Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Added a method to initialize the MongoDB driver using a LINQPad query…

…, the query can then perform BsonClassMap and DiscriminatorConvention registration.

Signed-off-by: Gordon Burgett <gordon.burgett@gmail.com>
  • Loading branch information...
commit cb5f3dff627d8a56b4f414b6d154c11c0f8e9718 1 parent 9347c0b
Gordon authored July 05, 2012
1  LinqPad Mongo Driver.sln
@@ -11,6 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
11 11
 	ProjectSection(SolutionItems) = preProject
12 12
 		LinqPad Mongo Driver.vsmdi = LinqPad Mongo Driver.vsmdi
13 13
 		Local.testsettings = Local.testsettings
  14
+		README.txt = README.txt
14 15
 		TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings
15 16
 	EndProjectSection
16 17
 EndProject
BIN  LinqPad Mongo Driver.suo
Binary file not shown
159  LinqPad Mongo Driver/Comparers.cs
... ...
@@ -0,0 +1,159 @@
  1
+using System;
  2
+using System.Collections.Generic;
  3
+using System.Linq;
  4
+using System.Text;
  5
+
  6
+namespace GDSX.Externals.LinqPad.Driver
  7
+{
  8
+    public class DynamicComparer<T> : IComparer<T>
  9
+    {
  10
+        public Func<T, T, int> Comparer { get; private set; }
  11
+
  12
+        public DynamicComparer(Func<T, T, int> comparer)
  13
+        {
  14
+            this.Comparer = comparer;
  15
+        }
  16
+
  17
+        public int Compare(T x, T y)
  18
+        {
  19
+            return Comparer(x, y);
  20
+        }
  21
+    }
  22
+
  23
+    public class CollectionEqualityComparer<T> : IEqualityComparer<ICollection<T>>
  24
+    {
  25
+        public bool Equals(ICollection<T> x, ICollection<T> y)
  26
+        {
  27
+            //if one is null the other should be null or empty
  28
+            if (x == null)
  29
+            {
  30
+                return y == null || y.Count == 0;
  31
+            }
  32
+            if (y == null)
  33
+                return x.Count == 0;
  34
+
  35
+            //quick check - counts
  36
+            if (x.Count != y.Count)
  37
+                return false;
  38
+
  39
+            //deep check - y contains every element of x
  40
+            return x.All(y.Contains);
  41
+        }
  42
+
  43
+        public int GetHashCode(ICollection<T> obj)
  44
+        {
  45
+            if (obj == null)
  46
+                return 0;
  47
+
  48
+            return obj.Aggregate(397, (hash, o) => (hash * 397) ^ o.GetHashCode());
  49
+        }
  50
+    }
  51
+
  52
+    public class DictionaryEqualityComparer<T, U> : IEqualityComparer<IDictionary<T, U>>
  53
+    {
  54
+        /// <summary>
  55
+        /// Gets or sets the EqualityComparer used to compare the values of the dictionary
  56
+        /// </summary>
  57
+        public IEqualityComparer<U> ValueEqualityComparer { get; set; }
  58
+
  59
+        public bool Equals(IDictionary<T, U> x, IDictionary<T, U> y)
  60
+        {
  61
+            if (x == null)
  62
+            {
  63
+                return y == null || y.Count == 0;
  64
+            }
  65
+            if (y == null)
  66
+                return x.Count == 0;
  67
+
  68
+            if (y.Count != x.Count)
  69
+                return false;
  70
+
  71
+            foreach (KeyValuePair<T, U> pair in x)
  72
+            {
  73
+
  74
+                U yValue;
  75
+
  76
+                //TODO: add key equality comparer if we ever need it
  77
+                if (!y.ContainsKey(pair.Key))
  78
+                    return false;
  79
+                yValue = y[pair.Key];
  80
+
  81
+
  82
+                if (ValueEqualityComparer == null)
  83
+                {
  84
+                    if (!object.Equals(pair.Value, yValue))
  85
+                        return false;
  86
+                }
  87
+                else
  88
+                {
  89
+                    if (!ValueEqualityComparer.Equals(pair.Value, yValue))
  90
+                        return false;
  91
+                }
  92
+            }
  93
+
  94
+            return true;
  95
+        }
  96
+
  97
+        public int GetHashCode(IDictionary<T, U> obj)
  98
+        {
  99
+            if (obj == null)
  100
+                return 0;
  101
+
  102
+            return obj.Aggregate(397, (hash, pair) =>
  103
+            {
  104
+                hash = (hash * 397) ^ pair.Key.GetHashCode();
  105
+                hash = (hash * 397) ^ (ValueEqualityComparer == null ?
  106
+                    pair.Value.GetHashCode() :
  107
+                    ValueEqualityComparer.GetHashCode(pair.Value));
  108
+
  109
+                return hash;
  110
+            });
  111
+        }
  112
+    }
  113
+
  114
+    public class StringEqualityComparer : IEqualityComparer<string>
  115
+    {
  116
+        public bool Equals(string x, string y)
  117
+        {
  118
+            if (string.IsNullOrEmpty(x))
  119
+                return string.IsNullOrEmpty(y);
  120
+
  121
+            if (string.IsNullOrEmpty(y))
  122
+                return false;
  123
+
  124
+            return string.Equals(x, y);
  125
+        }
  126
+
  127
+        public int GetHashCode(string obj)
  128
+        {
  129
+            if (string.IsNullOrEmpty(obj))
  130
+                return 0;
  131
+
  132
+            return obj.GetHashCode();
  133
+        }
  134
+    }
  135
+
  136
+    /// <summary>
  137
+    /// Compares two assembly paths to see if they point to the same .dll file, in different locations.
  138
+    /// </summary>
  139
+    public class AssemblyPathEqualityComparer : IEqualityComparer<string>
  140
+    {
  141
+        public bool Equals(string x, string y)
  142
+        {
  143
+            return string.Equals(
  144
+                    System.IO.Path.GetFileName(x),
  145
+                    System.IO.Path.GetFileName(y)
  146
+                );
  147
+        }
  148
+
  149
+        public int GetHashCode(string obj)
  150
+        {
  151
+            string filename = System.IO.Path.GetFileName(obj);
  152
+            if(filename == null)
  153
+                return 0;
  154
+
  155
+            return filename.GetHashCode();
  156
+        }
  157
+    }
  158
+
  159
+}
99  LinqPad Mongo Driver/Connection Dialog/ConnectionDialog.Designer.cs
@@ -61,6 +61,14 @@ private void InitializeComponent()
61 61
             this.cancelToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
62 62
             this.additionalOptionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
63 63
             this.additionalOptionsToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
  64
+            this.initializationToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
  65
+            this.noQueryLoadedToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
  66
+            this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
  67
+            this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
  68
+            this.reloadFromDiskToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
  69
+            this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
  70
+            this.loadQueryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
  71
+            this.createShellQueryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
64 72
             ((System.ComponentModel.ISupportInitialize)(this.dgCollectionTypes)).BeginInit();
65 73
             this.tableLayoutPanel1.SuspendLayout();
66 74
             this.panel1.SuspendLayout();
@@ -363,42 +371,43 @@ private void InitializeComponent()
363 371
             // loadToolStripMenuItem
364 372
             // 
365 373
             this.loadToolStripMenuItem.Name = "loadToolStripMenuItem";
366  
-            this.loadToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
  374
+            this.loadToolStripMenuItem.Size = new System.Drawing.Size(110, 22);
367 375
             this.loadToolStripMenuItem.Text = "Import";
368 376
             this.loadToolStripMenuItem.Click += new System.EventHandler(this.loadToolStripMenuItem_Click);
369 377
             // 
370 378
             // exportToolStripMenuItem
371 379
             // 
372 380
             this.exportToolStripMenuItem.Name = "exportToolStripMenuItem";
373  
-            this.exportToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
  381
+            this.exportToolStripMenuItem.Size = new System.Drawing.Size(110, 22);
374 382
             this.exportToolStripMenuItem.Text = "Export";
375 383
             this.exportToolStripMenuItem.Click += new System.EventHandler(this.exportToolStripMenuItem_Click);
376 384
             // 
377 385
             // clearToolStripMenuItem
378 386
             // 
379 387
             this.clearToolStripMenuItem.Name = "clearToolStripMenuItem";
380  
-            this.clearToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
  388
+            this.clearToolStripMenuItem.Size = new System.Drawing.Size(110, 22);
381 389
             this.clearToolStripMenuItem.Text = "Clear";
382 390
             this.clearToolStripMenuItem.Click += new System.EventHandler(this.clearToolStripMenuItem_Click);
383 391
             // 
384 392
             // saveToolStripMenuItem
385 393
             // 
386 394
             this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
387  
-            this.saveToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
  395
+            this.saveToolStripMenuItem.Size = new System.Drawing.Size(110, 22);
388 396
             this.saveToolStripMenuItem.Text = "Save";
389 397
             this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveToolStripMenuItem_Click);
390 398
             // 
391 399
             // cancelToolStripMenuItem
392 400
             // 
393 401
             this.cancelToolStripMenuItem.Name = "cancelToolStripMenuItem";
394  
-            this.cancelToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
  402
+            this.cancelToolStripMenuItem.Size = new System.Drawing.Size(110, 22);
395 403
             this.cancelToolStripMenuItem.Text = "Cancel";
396 404
             this.cancelToolStripMenuItem.Click += new System.EventHandler(this.cancelToolStripMenuItem_Click);
397 405
             // 
398 406
             // additionalOptionsToolStripMenuItem
399 407
             // 
400 408
             this.additionalOptionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
401  
-            this.additionalOptionsToolStripMenuItem1});
  409
+            this.additionalOptionsToolStripMenuItem1,
  410
+            this.initializationToolStripMenuItem});
402 411
             this.additionalOptionsToolStripMenuItem.Name = "additionalOptionsToolStripMenuItem";
403 412
             this.additionalOptionsToolStripMenuItem.Size = new System.Drawing.Size(119, 20);
404 413
             this.additionalOptionsToolStripMenuItem.Text = "Additional Options";
@@ -410,6 +419,76 @@ private void InitializeComponent()
410 419
             this.additionalOptionsToolStripMenuItem1.Text = "Additional Options";
411 420
             this.additionalOptionsToolStripMenuItem1.Click += new System.EventHandler(this.additionalOptionsToolStripMenuItem1_Click);
412 421
             // 
  422
+            // initializationToolStripMenuItem
  423
+            // 
  424
+            this.initializationToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
  425
+            this.noQueryLoadedToolStripMenuItem,
  426
+            this.toolStripSeparator1,
  427
+            this.loadQueryToolStripMenuItem,
  428
+            this.createShellQueryToolStripMenuItem});
  429
+            this.initializationToolStripMenuItem.Name = "initializationToolStripMenuItem";
  430
+            this.initializationToolStripMenuItem.Size = new System.Drawing.Size(174, 22);
  431
+            this.initializationToolStripMenuItem.Text = "Initialization";
  432
+            // 
  433
+            // noQueryLoadedToolStripMenuItem
  434
+            // 
  435
+            this.noQueryLoadedToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
  436
+            this.viewToolStripMenuItem,
  437
+            this.removeToolStripMenuItem,
  438
+            this.reloadFromDiskToolStripMenuItem});
  439
+            this.noQueryLoadedToolStripMenuItem.Name = "noQueryLoadedToolStripMenuItem";
  440
+            this.noQueryLoadedToolStripMenuItem.Size = new System.Drawing.Size(171, 22);
  441
+            this.noQueryLoadedToolStripMenuItem.Text = "No Query Loaded";
  442
+            this.noQueryLoadedToolStripMenuItem.ToolTipText = "The currently loaded Query";
  443
+            // 
  444
+            // viewToolStripMenuItem
  445
+            // 
  446
+            this.viewToolStripMenuItem.Name = "viewToolStripMenuItem";
  447
+            this.viewToolStripMenuItem.Size = new System.Drawing.Size(117, 22);
  448
+            this.viewToolStripMenuItem.Text = "View";
  449
+            this.viewToolStripMenuItem.ToolTipText = "View the query in LinqPad (or whatever you have configured to view .linq files)";
  450
+            this.viewToolStripMenuItem.Click += new System.EventHandler(this.viewToolStripMenuItem_Click);
  451
+            // 
  452
+            // removeToolStripMenuItem
  453
+            // 
  454
+            this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";
  455
+            this.removeToolStripMenuItem.Size = new System.Drawing.Size(117, 22);
  456
+            this.removeToolStripMenuItem.Text = "Remove";
  457
+            this.removeToolStripMenuItem.ToolTipText = "Remove the initialization query from the connection properties.  It will no longe" +
  458
+    "r be run before any queries are executed.";
  459
+            this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click);
  460
+            // 
  461
+            // reloadFromDiskToolStripMenuItem
  462
+            // 
  463
+            this.reloadFromDiskToolStripMenuItem.Name = "reloadFromDiskToolStripMenuItem";
  464
+            this.reloadFromDiskToolStripMenuItem.Size = new System.Drawing.Size(117, 22);
  465
+            this.reloadFromDiskToolStripMenuItem.Text = "Validate";
  466
+            this.reloadFromDiskToolStripMenuItem.ToolTipText = "Reloads the query from disk and validates it.";
  467
+            this.reloadFromDiskToolStripMenuItem.Click += new System.EventHandler(this.reloadFromDiskToolStripMenuItem_Click);
  468
+            // 
  469
+            // toolStripSeparator1
  470
+            // 
  471
+            this.toolStripSeparator1.Name = "toolStripSeparator1";
  472
+            this.toolStripSeparator1.Size = new System.Drawing.Size(168, 6);
  473
+            // 
  474
+            // loadQueryToolStripMenuItem
  475
+            // 
  476
+            this.loadQueryToolStripMenuItem.Name = "loadQueryToolStripMenuItem";
  477
+            this.loadQueryToolStripMenuItem.Size = new System.Drawing.Size(171, 22);
  478
+            this.loadQueryToolStripMenuItem.Text = "Load New Query";
  479
+            this.loadQueryToolStripMenuItem.ToolTipText = "Click to load a LinqPad query that will be executed to initialize the Mongo Drive" +
  480
+    "r";
  481
+            this.loadQueryToolStripMenuItem.Click += new System.EventHandler(this.loadQueryToolStripMenuItem_Click);
  482
+            // 
  483
+            // createShellQueryToolStripMenuItem
  484
+            // 
  485
+            this.createShellQueryToolStripMenuItem.Name = "createShellQueryToolStripMenuItem";
  486
+            this.createShellQueryToolStripMenuItem.Size = new System.Drawing.Size(171, 22);
  487
+            this.createShellQueryToolStripMenuItem.Text = "Create Shell Query";
  488
+            this.createShellQueryToolStripMenuItem.ToolTipText = "Click to create a Shell for a query that can be used to initialize the Mongo driv" +
  489
+    "er";
  490
+            this.createShellQueryToolStripMenuItem.Click += new System.EventHandler(this.createShellQueryToolStripMenuItem_Click);
  491
+            // 
413 492
             // ConnectionDialog
414 493
             // 
415 494
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -472,5 +551,13 @@ private void InitializeComponent()
472 551
         private System.Windows.Forms.ToolStripMenuItem cancelToolStripMenuItem;
473 552
         private System.Windows.Forms.ToolStripMenuItem additionalOptionsToolStripMenuItem;
474 553
         private System.Windows.Forms.ToolStripMenuItem additionalOptionsToolStripMenuItem1;
  554
+        private System.Windows.Forms.ToolStripMenuItem initializationToolStripMenuItem;
  555
+        private System.Windows.Forms.ToolStripMenuItem loadQueryToolStripMenuItem;
  556
+        private System.Windows.Forms.ToolStripMenuItem createShellQueryToolStripMenuItem;
  557
+        private System.Windows.Forms.ToolStripMenuItem noQueryLoadedToolStripMenuItem;
  558
+        private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
  559
+        private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem;
  560
+        private System.Windows.Forms.ToolStripMenuItem viewToolStripMenuItem;
  561
+        private System.Windows.Forms.ToolStripMenuItem reloadFromDiskToolStripMenuItem;
475 562
     }
476 563
 }
340  LinqPad Mongo Driver/Connection Dialog/ConnectionDialog.cs
... ...
@@ -1,15 +1,15 @@
1 1
 using System;
  2
+using System.CodeDom.Compiler;
2 3
 using System.Collections.Generic;
3  
-using System.ComponentModel;
4  
-using System.Data;
5  
-using System.Drawing;
  4
+using System.Diagnostics;
6 5
 using System.IO;
7 6
 using System.Linq;
8 7
 using System.Reflection;
9 8
 using System.Text;
10 9
 using System.Windows.Forms;
  10
+using System.Xml;
11 11
 using System.Xml.Linq;
12  
-using MongoDB.Bson;
  12
+using Microsoft.CSharp;
13 13
 using MongoDB.Bson.Serialization;
14 14
 using MongoDB.Driver;
15 15
 
@@ -19,6 +19,8 @@ public partial class ConnectionDialog : Form
19 19
     {
20 20
         private ConnectionProperties mConnection;
21 21
         private ConnectionAdditionalOptions mAdditionalOptions;
  22
+        private LinqPadQuery mInitializationQuery;
  23
+
22 24
         private readonly bool mIsNewConnection;
23 25
 
24 26
         private bool mCloseAlreadyValidated = false;
@@ -33,7 +35,7 @@ public partial class ConnectionDialog : Form
33 35
 
34 36
         private Dictionary<string, List<CollectionTypeMapping>> mDatabases = new Dictionary<string, List<CollectionTypeMapping>>();
35 37
 
36  
-        private IXElementSerializer<ConnectionProperties> connectionPropertiesSerializer = new ConnectionPropertiesSerializer();
  38
+        private readonly IXElementSerializer<ConnectionProperties> connectionPropertiesSerializer = new ConnectionPropertiesSerializer();
37 39
 
38 40
         public ConnectionDialog(ConnectionProperties props, bool isNewConnection, Func<string, Assembly> loadSafely)
39 41
         {
@@ -45,6 +47,8 @@ public ConnectionDialog(ConnectionProperties props, bool isNewConnection, Func<s
45 47
 
46 48
             InitializeComponent();
47 49
 
  50
+            this.SetLoadedQueryName(null);
  51
+
48 52
             if (!this.mIsNewConnection)
49 53
                 this.LoadFrom(props);
50 54
             else
@@ -136,28 +140,6 @@ public void LoadTypes()
136 140
                 this.dgCollectionTypes.DataSource = null;
137 141
         }
138 142
 
139  
-        //// issues a query to the DB to see if there's some type info there.
140  
-        //// Wastes DB hits for most of our usage
141  
-        //private Type TryGetTypeForCollection(MongoDatabase db, string collectionName, ILookup<string, Type> typeLookup)
142  
-        //{
143  
-            
144  
-        //    var ret = db.Eval(string.Format("db['{0}'].findOne({{}}, {{'_t':1}})", collectionName));
145  
-        //    BsonElement typeElement;
146  
-        //    try
147  
-        //    {
148  
-        //        if (ret.AsBsonDocument.TryGetElement("_t", out typeElement))
149  
-        //        {
150  
-        //            string type1 = typeElement.Value.AsBsonArray.First().AsString;
151  
-        //            return typeLookup[type1].SingleOrDefault();
152  
-        //        }
153  
-        //    }catch(Exception ex)
154  
-        //    {
155  
-        //        //leave it as default
156  
-        //    }
157  
-
158  
-        //    return default(Type);
159  
-        //}
160  
-
161 143
         #region event handlers
162 144
         private void ConnectionDialog_FormClosing(object sender, FormClosingEventArgs e)
163 145
         {
@@ -357,6 +339,9 @@ private void btnImport_Click(object sender, EventArgs e)
357 339
             {
358 340
                 using (var chooser = new OpenFileDialog())
359 341
                 {
  342
+                    chooser.DefaultExt = ".xml";
  343
+                    chooser.Filter = "Xml Files|*.xml|All Files|*.*";
  344
+
360 345
                     var result = chooser.ShowDialog();
361 346
 
362 347
                     if (result == System.Windows.Forms.DialogResult.OK)
@@ -422,13 +407,255 @@ private void cancelToolStripMenuItem_Click(object sender, EventArgs e)
422 407
             this.btnCancel_Click(sender, e);
423 408
         }
424 409
 
  410
+        private void createShellQueryToolStripMenuItem_Click(object sender, EventArgs e)
  411
+        {
  412
+            var props = new ConnectionProperties();
  413
+            this.Populate(props);
  414
+
  415
+            string contents = this.CreateShellQuery(props);
  416
+            using (var chooser = new SaveFileDialog())
  417
+            {
  418
+                chooser.AddExtension = true;
  419
+                chooser.DefaultExt = ".linq";
  420
+                chooser.Filter = "LinqPad Queries|*.linq|All Files|*.*";
  421
+
  422
+                DialogResult result = chooser.ShowDialog();
  423
+                if (result == DialogResult.OK)
  424
+                {
  425
+                    using (StreamWriter writer = new StreamWriter(chooser.OpenFile()))
  426
+                    {
  427
+                        writer.Write(contents);
  428
+                    }
  429
+
  430
+                    this.ViewLocation(chooser.FileName);
  431
+                }
  432
+            }
  433
+        }
  434
+
  435
+        private void loadQueryToolStripMenuItem_Click(object sender, EventArgs e)
  436
+        {
  437
+            LinqPadQuery query;
  438
+            using (var chooser = new OpenFileDialog())
  439
+            {
  440
+                chooser.DefaultExt = ".linq";
  441
+                chooser.Filter = "LinqPad Queries|*.linq|All Files|*.*";
  442
+
  443
+                DialogResult result = chooser.ShowDialog();
  444
+                if (result == DialogResult.OK)
  445
+                {
  446
+                    query = LinqPadQuery.CreateFrom(chooser.FileName);
  447
+                }
  448
+                else
  449
+                {
  450
+                    return;
  451
+                }
  452
+            }
  453
+
  454
+            var props = new ConnectionProperties();
  455
+            this.Populate(props);
  456
+            List<string> errors = ValidateLinqQuery(query, props);
  457
+            if (errors.Count == 0)
  458
+            {
  459
+                this.mInitializationQuery = query;
  460
+                this.SetLoadedQueryName(Path.GetFileName(this.mInitializationQuery.Location));
  461
+            }
  462
+            else
  463
+            {
  464
+                DisplayErrors(errors);
  465
+            }
  466
+        }
  467
+
  468
+
  469
+        private void viewToolStripMenuItem_Click(object sender, EventArgs e)
  470
+        {
  471
+            if (this.mInitializationQuery == null)
  472
+            {
  473
+                MessageBox.Show("No query loaded");
  474
+                return;
  475
+            }
  476
+            if (!File.Exists(this.mInitializationQuery.Location))
  477
+            {
  478
+                MessageBox.Show(string.Format("File {0} no longer exists", this.mInitializationQuery.Location));
  479
+                return;
  480
+            }
  481
+
  482
+            ViewLocation(this.mInitializationQuery.Location);
  483
+        }
  484
+
  485
+        private void removeToolStripMenuItem_Click(object sender, EventArgs e)
  486
+        {
  487
+            this.mInitializationQuery = null;
  488
+            this.SetLoadedQueryName(null);
  489
+        }
  490
+
  491
+        private void reloadFromDiskToolStripMenuItem_Click(object sender, EventArgs e)
  492
+        {
  493
+            if (this.mInitializationQuery == null)
  494
+                return;
  495
+            if(!File.Exists(this.mInitializationQuery.Location))
  496
+            {
  497
+                MessageBox.Show(string.Format("Query '{0}' no longer exists", this.mInitializationQuery.Location));
  498
+                return;
  499
+            }
  500
+
  501
+            ConnectionProperties props = new ConnectionProperties();
  502
+            this.Populate(props);
  503
+            
  504
+            LinqPadQuery query = LinqPadQuery.CreateFrom(this.mInitializationQuery.Location);
  505
+            List<string> errors = this.ValidateLinqQuery(query, props);
  506
+            if(errors.Count != 0)
  507
+            {
  508
+                MessageBox.Show("Loaded query has errors: \r\n" +
  509
+                    string.Join("\r\n", errors));
  510
+                return;
  511
+            }
  512
+
  513
+            this.mInitializationQuery = query;
  514
+            this.SetLoadedQueryName(Path.GetFileName(this.mInitializationQuery.Location));
  515
+        }
  516
+
425 517
         #endregion
426 518
 
  519
+
  520
+        private void SetLoadedQueryName(string text)
  521
+        {
  522
+            if (text == null)
  523
+            {
  524
+                this.noQueryLoadedToolStripMenuItem.Text = "No Query Loaded";
  525
+                foreach (var dropDownItem in this.noQueryLoadedToolStripMenuItem.DropDownItems.Cast<ToolStripItem>())
  526
+                {
  527
+                    dropDownItem.Visible = false;
  528
+                }
  529
+            }
  530
+            else
  531
+            {
  532
+                this.noQueryLoadedToolStripMenuItem.Text = text;
  533
+                foreach (var dropDownItem in this.noQueryLoadedToolStripMenuItem.DropDownItems.Cast<ToolStripItem>())
  534
+                {
  535
+                    dropDownItem.Visible = true;
  536
+                }
  537
+            }
  538
+        }
  539
+
  540
+        private string CreateShellQuery(ConnectionProperties props)
  541
+        {
  542
+            var driver = new MongoDynamicDataContextDriver();
  543
+
  544
+            //build the query XDocument
  545
+            var doc = new XDocument();
  546
+            var query = new XElement("Query");
  547
+            doc.Add(query);
  548
+            query.SetAttributeValue("Kind", "Program");
  549
+            query.SetElementValue("Reference", Path.Combine(driver.GetDriverFolder(), "LinqPadMongoDriver.dll"));
  550
+            foreach (string loc in props.AssemblyLocations)
  551
+            {
  552
+                var el = new XElement("Reference");
  553
+                el.SetValue(loc);
  554
+                query.Add(el);
  555
+            }
  556
+            foreach (string ns in MongoDynamicDataContextDriver.GetNamespacesToAdd(props)
  557
+                .Concat(new[]
  558
+                    {
  559
+                        "System",
  560
+                        "GDSX.Externals.LinqPad.Driver"
  561
+                    }))
  562
+            {
  563
+                var el = new XElement("Namespace");
  564
+                el.SetValue(ns);
  565
+                query.Add(el);
  566
+            }
  567
+
  568
+            StringBuilder sb = new StringBuilder();
  569
+            using (var writer = XmlWriter.Create(sb, new XmlWriterSettings{OmitXmlDeclaration = true}))
  570
+                doc.Save(writer);
  571
+
  572
+            sb.AppendLine();
  573
+
  574
+
  575
+            var ass = Assembly.GetExecutingAssembly();
  576
+            using (var stream = ass.GetManifestResourceStream("GDSX.Externals.LinqPad.Driver.ShellInitQuery.linq"))
  577
+            {
  578
+                if (stream == null)
  579
+                    throw new Exception("Could not find static code files");
  580
+                using (var reader = new StreamReader(stream))
  581
+                    sb.Append(reader.ReadToEnd());
  582
+            }
  583
+
  584
+            return sb.ToString();
  585
+        }
  586
+
  587
+
  588
+
  589
+        private List<string> ValidateLinqQuery(LinqPadQuery query, ConnectionProperties props)
  590
+        {
  591
+            List<string> errors = new List<string>();
  592
+
  593
+            StringBuilder sb = new StringBuilder();
  594
+            foreach (var ns in query.Namespaces)
  595
+            {
  596
+                sb.Append("using ").Append(ns).AppendLine(";");
  597
+            }
  598
+            sb.AppendFormat(@"
  599
+public class TestQuery
  600
+{{
  601
+    public TestQuery()
  602
+    {{
  603
+
  604
+    }}
  605
+
  606
+    {0}
  607
+}}", query.Query);
  608
+
  609
+            var driver = new MongoDynamicDataContextDriver();
  610
+            CompilerResults results;
  611
+            using (var codeProvider = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } }))
  612
+            {
  613
+                var assemblyNames = new HashSet<string>(query.References, new AssemblyPathEqualityComparer());
  614
+
  615
+                //add additional assemblies which may or may not have been overridden
  616
+                assemblyNames.AddRange("System.dll System.Core.dll".Split());
  617
+                assemblyNames.Add(Path.Combine(driver.GetDriverFolder(), "MongoDB.Driver.dll"));
  618
+                assemblyNames.Add(Path.Combine(driver.GetDriverFolder(), "MongoDB.Bson.dll"));
  619
+
  620
+                var options = new CompilerParameters(assemblyNames.ToArray());
  621
+                options.GenerateInMemory = true;
  622
+
  623
+                results = codeProvider.CompileAssemblyFromSource(options, sb.ToString());
  624
+            }
  625
+            if (results.Errors.Count > 0)
  626
+            {
  627
+                errors.AddRange(results.Errors.Cast<CompilerError>().Select(x => x.ToString()));
  628
+
  629
+                return errors;
  630
+            }
  631
+
  632
+            Type compiledType = results.CompiledAssembly.GetType("TestQuery");
  633
+            object instance = Activator.CreateInstance(compiledType);
  634
+            MethodInfo initMethod = compiledType.GetMethod("Initialize", new[] { typeof(ConnectionProperties) });
  635
+            if (initMethod == null)
  636
+            {
  637
+                errors.Add(string.Format("The query must contain a method called Initialize that takes one parameter of type {0}", typeof(ConnectionProperties)));
  638
+                return errors;
  639
+            }
  640
+
  641
+
  642
+            return errors;
  643
+        }
  644
+
  645
+        private void ViewLocation(string path)
  646
+        {
  647
+            System.Diagnostics.Process p = new Process();
  648
+            p.StartInfo.FileName = path;
  649
+            p.Start();
  650
+        }
  651
+
427 652
         /// <summary>
428 653
         /// populates the connection properties with the values in the form
429 654
         /// </summary>
430  
-        private void Populate(ConnectionProperties props)
  655
+        private List<string> Populate(ConnectionProperties props, bool doValidate = false)
431 656
         {
  657
+            List<string> errors = new List<string>();
  658
+
432 659
             props.ConnectionString = this.txtConnectionString.Text.Trim();
433 660
 
434 661
             props.AssemblyLocations = new HashSet<string>();
@@ -453,6 +680,14 @@ private void Populate(ConnectionProperties props)
453 680
                 props.CustomSerializers.Add(pair.Key.ToString(), pair.Value.ToString());
454 681
 
455 682
             props.AdditionalOptions = this.mAdditionalOptions;
  683
+
  684
+            if(this.mInitializationQuery != null && doValidate)
  685
+            {
  686
+                errors.AddRange(ValidateLinqQuery(this.mInitializationQuery, props));
  687
+            }
  688
+            props.InitializationQuery = this.mInitializationQuery;
  689
+
  690
+            return errors;
456 691
         }
457 692
         
458 693
         /// <summary>
@@ -520,6 +755,12 @@ private void LoadFrom(ConnectionProperties props)
520 755
 
521 756
             this.mAdditionalOptions = props.AdditionalOptions;
522 757
 
  758
+            this.mInitializationQuery = props.InitializationQuery;
  759
+            if(this.mInitializationQuery != null)
  760
+            {
  761
+                this.SetLoadedQueryName(Path.GetFileName(this.mInitializationQuery.Location));
  762
+            }
  763
+
523 764
             UpdateLoadedAssemblies();
524 765
         }
525 766
 
@@ -562,10 +803,26 @@ private bool DoCancel()
562 803
         /// <returns>true if the data successfully saved, false if the form should stay open</returns>
563 804
         private bool DoSave()
564 805
         {
565  
-            this.Populate(this.mConnection);
  806
+            List<string> errors = this.Populate(this.mConnection, true);
566 807
 
567  
-            this.DialogResult = System.Windows.Forms.DialogResult.OK;
568  
-            return true;
  808
+            if(errors.Count == 0)
  809
+            {
  810
+                this.DialogResult = System.Windows.Forms.DialogResult.OK;
  811
+                return true;
  812
+            }
  813
+            else
  814
+            {
  815
+                DisplayErrors(errors);
  816
+                return false;
  817
+            }
  818
+        }
  819
+
  820
+        private void DisplayErrors(List<string> errors)
  821
+        {
  822
+            var result = MessageBox.Show("There are errors with your settings: \r\n" +
  823
+                       String.Join("\r\n", errors),
  824
+                       "Invalid Settings",
  825
+                       MessageBoxButtons.OK);
569 826
         }
570 827
 
571 828
         //Updates the loaded assemblies view and the type tree view
@@ -742,31 +999,16 @@ public override string ToString()
742 999
             }
743 1000
         }
744 1001
 
  1002
+        
745 1003
     }
746 1004
     
747  
-    
748  
-    class DynamicComparer<T> : IComparer<T>
749  
-    {
750  
-        public Func<T, T, int> Comparer { get; private set; }
751 1005
 
752  
-        public DynamicComparer(Func<T, T, int> comparer)
753  
-        {
754  
-            this.Comparer = comparer;
755  
-        }
756  
-
757  
-        public int Compare(T x, T y)
758  
-        {
759  
-            return Comparer(x, y);
760  
-        }
761  
-    }
762 1006
 
763 1007
     static class Extensions
764 1008
     {
765  
-        public static SortedSet<T> AddRange<T>(this SortedSet<T> set, IEnumerable<T> values)
  1009
+        public static T AddRange<T,U>(this T set, IEnumerable<U> values) where T : ISet<U>
766 1010
         {
767  
-            foreach (T val in values)
768  
-                set.Add(val);
769  
-
  1011
+            set.UnionWith(values);
770 1012
             return set;
771 1013
         }
772 1014
 
136  LinqPad Mongo Driver/ConnectionProperties.cs
@@ -31,6 +31,8 @@ public class ConnectionProperties
31 31
         public Dictionary<string, string> CustomSerializers { get; set; }
32 32
 
33 33
         public ConnectionAdditionalOptions AdditionalOptions { get; set; }
  34
+
  35
+        public LinqPadQuery InitializationQuery { get; set; }
34 36
         
35 37
         public ConnectionProperties()
36 38
         {
@@ -230,122 +232,6 @@ public ConnectionAdditionalOptions Clone()
230 232
         }
231 233
     }
232 234
 
233  
-    #region Equality
234  
-    public class CollectionEqualityComparer<T> : IEqualityComparer<ICollection<T>>
235  
-    {
236  
-        public bool Equals(ICollection<T> x, ICollection<T> y)
237  
-        {
238  
-            //if one is null the other should be null or empty
239  
-            if(x == null)
240  
-            {
241  
-                return y == null || y.Count == 0;
242  
-            }
243  
-            if (y == null)
244  
-                return x.Count == 0;
245  
-
246  
-            //quick check - counts
247  
-            if (x.Count != y.Count)
248  
-                return false;
249  
-
250  
-            //deep check - y contains every element of x
251  
-            return x.All(y.Contains);
252  
-        }
253  
-
254  
-        public int GetHashCode(ICollection<T> obj)
255  
-        {
256  
-            if (obj == null)
257  
-                return 0;
258  
-
259  
-            return obj.Aggregate(397, (hash, o) => (hash * 397) ^ o.GetHashCode());
260  
-        }
261  
-    }
262  
-
263  
-    public class DictionaryEqualityComparer<T, U> : IEqualityComparer<IDictionary<T, U>>
264  
-    {
265  
-        /// <summary>
266  
-        /// Gets or sets the EqualityComparer used to compare the values of the dictionary
267  
-        /// </summary>
268  
-        public IEqualityComparer<U> ValueEqualityComparer { get; set; }
269  
-
270  
-        public bool Equals(IDictionary<T, U> x, IDictionary<T, U> y)
271  
-        {
272  
-            if (x == null)
273  
-            {
274  
-                return y == null || y.Count == 0;
275  
-            }
276  
-            if (y == null)
277  
-                return x.Count == 0;
278  
-
279  
-            if (y.Count != x.Count)
280  
-                return false;
281  
-
282  
-            foreach (KeyValuePair<T, U> pair in x)
283  
-            {
284  
-
285  
-                U yValue;
286  
-                
287  
-                //TODO: add key equality comparer if we ever need it
288  
-                if (!y.ContainsKey(pair.Key))
289  
-                    return false;
290  
-                yValue = y[pair.Key];
291  
-                
292  
-
293  
-                if (ValueEqualityComparer == null)
294  
-                {
295  
-                    if (!object.Equals(pair.Value, yValue))
296  
-                        return false;
297  
-                }
298  
-                else
299  
-                {
300  
-                    if (!ValueEqualityComparer.Equals(pair.Value, yValue))
301  
-                        return false;
302  
-                }
303  
-            }
304  
-
305  
-            return true;
306  
-        }
307  
-
308  
-        public int GetHashCode(IDictionary<T, U> obj)
309  
-        {
310  
-            if (obj == null)
311  
-                return 0;
312  
-
313  
-            return obj.Aggregate(397, (hash, pair) =>
314  
-                {
315  
-                    hash = (hash * 397) ^ pair.Key.GetHashCode();
316  
-                    hash = (hash * 397) ^ (ValueEqualityComparer == null ? 
317  
-                        pair.Value.GetHashCode() :
318  
-                        ValueEqualityComparer.GetHashCode(pair.Value));
319  
-
320  
-                    return hash;
321  
-                });
322  
-        }
323  
-    }
324  
-
325  
-    public class StringEqualityComparer : IEqualityComparer<string>
326  
-    {
327  
-        public bool Equals(string x, string y)
328  
-        {
329  
-            if (string.IsNullOrEmpty(x))
330  
-                return string.IsNullOrEmpty(y);
331  
-
332  
-            if (string.IsNullOrEmpty(y))
333  
-                return false;
334  
-
335  
-            return string.Equals(x, y);
336  
-        }
337  
-
338  
-        public int GetHashCode(string obj)
339  
-        {
340  
-            if (string.IsNullOrEmpty(obj))
341  
-                return 0;
342  
-
343  
-            return obj.GetHashCode();
344  
-        }
345  
-    }
346  
-
347  
-    #endregion
348  
-
349 235
     #region Serialization
350 236
 
351 237
     public interface IXElementSerializer<T>
@@ -400,7 +286,7 @@ public class ConnectionPropertiesSerializer : IXElementSerializer<ConnectionProp
400 286
     {
401 287
         private readonly IXElementSerializer<CollectionTypeMapping> ctmSerializer = new CollectionTypeMappingSerializer();
402 288
         private readonly IXElementSerializer<ConnectionAdditionalOptions> additionalOptionsSerializer = new XElementSerializer<ConnectionAdditionalOptions>(); 
403  
-
  289
+        private readonly IXElementSerializer<LinqPadQuery> linqPadQuerySerializer = new LinqPadQuerySerializer(); 
404 290
 
405 291
         public void Serialize(XElement root, ConnectionProperties obj)
406 292
         {
@@ -463,6 +349,15 @@ public void Serialize(XElement root, ConnectionProperties obj)
463 349
                 this.additionalOptionsSerializer.Serialize(additionalOptions, obj.AdditionalOptions);
464 350
                 root.Add(additionalOptions);
465 351
             }
  352
+
  353
+            //Initialization Query
  354
+            if(obj.InitializationQuery != null)
  355
+            {
  356
+                var query = new XElement("InitializationQuery");
  357
+                this.linqPadQuerySerializer.Serialize(query, obj.InitializationQuery);
  358
+                root.Add(query);
  359
+            }
  360
+
466 361
         }
467 362
 
468 363
         public ConnectionProperties Deserialize(XElement root)
@@ -527,6 +422,13 @@ public ConnectionProperties Deserialize(XElement root)
527 422
                 obj.AdditionalOptions = this.additionalOptionsSerializer.Deserialize(xElement);
528 423
             }
529 424
 
  425
+            //Initialization query
  426
+            xElement = root.Element("InitializationQuery");
  427
+            if (xElement != null)
  428
+            {
  429
+                obj.InitializationQuery = this.linqPadQuerySerializer.Deserialize(xElement);
  430
+            }
  431
+
530 432
             return obj;
531 433
         }
532 434
 
5  LinqPad Mongo Driver/LinqPad Mongo Driver.csproj
@@ -49,7 +49,7 @@
49 49
     </Reference>
50 50
     <Reference Include="Microsoft.Pex.Framework, Version=0.94.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
51 51
     <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
52  
-    <Reference Include="MongoDB.Bson, Version=1.4.0.4468, Culture=neutral, PublicKeyToken=f686731cfb9cc103, processorArchitecture=MSIL">
  52
+    <Reference Include="MongoDB.Bson, Version=1.4.2.4500, Culture=neutral, PublicKeyToken=f686731cfb9cc103, processorArchitecture=MSIL">
53 53
       <SpecificVersion>False</SpecificVersion>
54 54
       <HintPath>lib\MongoDB.Bson.dll</HintPath>
55 55
     </Reference>
@@ -71,6 +71,7 @@
71 71
   </ItemGroup>
72 72
   <ItemGroup>
73 73
     <Compile Include="BsonValueMemberProvider.cs" />
  74
+    <Compile Include="Comparers.cs" />
74 75
     <Compile Include="Connection Dialog\AdditionalOptions.cs">
75 76
       <SubType>Form</SubType>
76 77
     </Compile>
@@ -96,6 +97,7 @@
96 97
     <Compile Include="Connection Dialog\CustomSerializerSelector.Designer.cs">
97 98
       <DependentUpon>CustomSerializerSelector.cs</DependentUpon>
98 99
     </Compile>
  100
+    <EmbeddedResource Include="ShellInitQuery.linq" />
99 101
     <EmbeddedResource Include="Connection Dialog\AdditionalOptions.resx">
100 102
       <DependentUpon>AdditionalOptions.cs</DependentUpon>
101 103
     </EmbeddedResource>
@@ -103,6 +105,7 @@
103 105
       <DependentUpon>SingleTypeSelector.cs</DependentUpon>
104 106
     </EmbeddedResource>
105 107
     <EmbeddedResource Include="InterceptorCollection.cs" />
  108
+    <Compile Include="LinqPadQuery.cs" />
106 109
     <Compile Include="MongoDynamicDataContextDriver.cs" />
107 110
     <Compile Include="Properties\AssemblyInfo.cs" />
108 111
     <EmbeddedResource Include="Connection Dialog\CustomSerializerSelector.resx">
173  LinqPad Mongo Driver/LinqPadQuery.cs
... ...
@@ -0,0 +1,173 @@
  1
+using System;
  2
+using System.Collections.Generic;
  3
+using System.IO;
  4
+using System.Linq;
  5
+using System.Text;
  6
+using System.Windows.Forms;
  7
+using System.Xml;
  8
+using System.Xml.Linq;
  9
+
  10
+namespace GDSX.Externals.LinqPad.Driver
  11
+{
  12
+    public class LinqPadQuery
  13
+    {
  14
+        public XDocument ConnectionInfo { get; set; }
  15
+
  16
+        public String Query { get; set; }
  17
+
  18
+        public String Location { get; set; }
  19
+
  20
+        public IEnumerable<string> References
  21
+        {
  22
+            get
  23
+            {
  24
+                if (this.ConnectionInfo == null || this.ConnectionInfo.Root == null)
  25
+                    return Enumerable.Empty<string>();
  26
+
  27
+                return this.ConnectionInfo.Root.Elements("Reference").Select(x => x.Value);
  28
+            }
  29
+        }
  30
+
  31
+        public IEnumerable<string> Namespaces
  32
+        {
  33
+            get
  34
+            {
  35
+                if (this.ConnectionInfo == null || this.ConnectionInfo.Root == null)
  36
+                    return Enumerable.Empty<string>();
  37
+
  38
+                return this.ConnectionInfo.Root.Elements("Namespace").Select(x => x.Value);
  39
+            }
  40
+        }
  41
+
  42
+        public LinqPadQuery()
  43
+        {
  44
+        
  45
+        }
  46
+
  47
+        public LinqPadQuery(XDocument connectionInfo, string query)
  48
+        {
  49
+            this.ConnectionInfo = connectionInfo;
  50
+            this.Query = query;
  51
+        }
  52
+
  53
+        public static LinqPadQuery CreateFrom(string path)
  54
+        {
  55
+            LinqPadQuery retval = CreateFrom(File.ReadAllBytes(path));
  56
+            retval.Location = path;
  57
+            return retval;
  58
+        }
  59
+
  60
+        public static LinqPadQuery CreateFrom(byte[] bytes)
  61
+        {
  62
+            XDocument doc;
  63
+            string query;
  64
+            using (var memStream = new MemoryStream(bytes))
  65
+            {
  66
+                using (var reader = new XmlTextReader(memStream))