/// <summary> /// loads the saved connection properties into the form /// </summary> private void LoadFrom(ConnectionProperties props) { this.txtConnectionString.Text = props.ConnectionString; this.LoadedAssemblies = props.AssemblyLocations.ToDictionary(loc => loc, loc => { if (!File.Exists(loc)) { return(null); } else { return(this.loadSafely(loc)); } }); this.LoadedTypes.Clear(); this.LoadedTypes.AddRange(MongoDynamicDataContextDriver.CommonTypes.Values); var badAssemblies = new HashSet <Assembly>(); this.LoadedTypes.AddRange(this.LoadedAssemblies.Values.Where(x => x != null) .SelectMany(ass => { try { return(ass.GetExportedTypes()); } catch (Exception) { badAssemblies.Add(ass); return(Enumerable.Empty <Type>()); } })); foreach (var badAssembly in badAssemblies) { var key = this.LoadedAssemblies.First(x => x.Value == badAssembly).Key; this.LoadedAssemblies[key] = null; } this.mDatabases = new Dictionary <string, HashSet <CollectionTypeMapping> >(); foreach (var pair in props.CollectionTypeMappings) { this.mDatabases[pair.Key] = new HashSet <CollectionTypeMapping>(pair.Value); } this.cbDatabases.Items.Clear(); this.cbDatabases.Items.AddRange(this.mDatabases.Keys.Cast <object>().ToArray()); string db = this.mDatabases.Keys.FirstOrDefault(); this.cbDatabases.SelectedItem = db; if (db != null) { this.dgCollectionTypes.DataSource = this.mDatabases[db].Select(m => new TypeMappingWrapper(m)).ToList(); } else { this.dgCollectionTypes.DataSource = null; } if (props.SelectedDatabase != null) { this.cbDatabases.SelectedIndex = this.cbDatabases.Items.IndexOf(props.SelectedDatabase); } this.lbCustomSerializers.Items.Clear(); this.SerializerMappings.Clear(); if (props.CustomSerializers != null) { foreach (var pair in props.CustomSerializers) { var keyType = this.LoadedTypes.FirstOrDefault(x => string.Equals(pair.Key, x.FullName)); var valType = this.LoadedTypes.FirstOrDefault(x => string.Equals(pair.Value, x.FullName)); if (keyType != null && valType != null) { this.SerializerMappings[keyType] = valType; } } } this.lbCustomSerializers.Items.AddRange(this.SerializerMappings.Select(pair => new SerializerMappingWrapper { Type = pair.Key, Serializer = pair.Value }).Cast <object>().ToArray()); this.mAdditionalOptions = props.AdditionalOptions; this.mInitializationQuery = props.InitializationQuery; if (this.mInitializationQuery != null) { this.SetLoadedQueryName(Path.GetFileName(this.mInitializationQuery.Location)); } UpdateLoadedAssemblies(); }
private List <string> ValidateLinqQuery(LinqPadQuery query, ConnectionProperties props) { List <string> errors = new List <string>(); StringBuilder sb = new StringBuilder(); foreach (var ns in query.Namespaces) { sb.Append("using ").Append(ns).AppendLine(";"); } sb.AppendFormat(@" public class TestQuery {{ public TestQuery() {{ }} {0} }}", query.Query); var driver = new MongoDynamicDataContextDriver(); CompilerResults results; using (var codeProvider = new CSharpCodeProvider(new Dictionary <string, string>() { { "CompilerVersion", "v4.0" } })) { var assemblyNames = new HashSet <string>(query.References, new AssemblyPathEqualityComparer()); //add additional assemblies which may or may not have been overridden assemblyNames.AddRange("System.dll System.Core.dll".Split()); assemblyNames.Add(Path.Combine(driver.GetDriverFolder(), "MongoDB.Driver.dll")); assemblyNames.Add(Path.Combine(driver.GetDriverFolder(), "MongoDB.Bson.dll")); assemblyNames.Add(Path.Combine(driver.GetDriverFolder(), "LinqPadMongoDriver.dll")); var options = new CompilerParameters(assemblyNames.ToArray()); options.GenerateInMemory = true; results = codeProvider.CompileAssemblyFromSource(options, sb.ToString()); } if (results.Errors.Count > 0) { errors.AddRange(results.Errors.Cast <CompilerError>().Select(x => x.ToString())); return(errors); } Type compiledType = results.CompiledAssembly.GetType("TestQuery"); object instance = Activator.CreateInstance(compiledType); MethodInfo initMethod = compiledType.GetMethod("Initialize", new[] { typeof(ConnectionProperties) }); if (initMethod == null) { errors.Add(string.Format("The query must contain a method called Initialize that takes one parameter of type {0}", typeof(ConnectionProperties))); return(errors); } return(errors); }
private void clearToolStripMenuItem_Click(object sender, EventArgs e) { this.mConnection = new ConnectionProperties(); this.LoadFrom(this.mConnection); }
/// <summary> /// Gets the additional namespaces that should be imported for queries using this driver /// </summary> /// <param name="cxInfo">the serialized connection properties.</param> /// <returns>The namespaces that should be imported as strings</returns> public override IEnumerable <string> GetNamespacesToAdd(IConnectionInfo cxInfo) { ConnectionProperties props = propsSerializer.Deserialize(cxInfo.DriverData); return(GetNamespacesToAdd(props)); }
/// <summary> /// Generates the Dynamic Driver class as a string of code to be compiled. /// </summary> /// <param name="props">The deserialized Connection Properties</param> /// <param name="assemblies">The already-loaded assemblies.</param> /// <param name="nameSpace">The namespace of the driver class</param> /// <param name="typeName">The name of the driver class</param> /// <returns>The Driver class as a string of C# code</returns> public string GenerateDynamicCode(ConnectionProperties props, List <Assembly> assemblies, string nameSpace, string typeName) { var writer = new StringWriter(); // write namespace and opening brace if (!string.IsNullOrEmpty(nameSpace)) { writer.Write("namespace "); writer.WriteLine(nameSpace); writer.WriteLine("{"); } // write using directives writer.WriteLine( @"using System.Linq; using MongoDB.Driver; using MongoDB.Driver.Linq; using System.IO; using System; using GDSX.Externals.LinqPad.Driver; "); // write type declaration writer.WriteLine(string.Format("public class {0}\n{{", typeName)); writer.WriteLine(string.Format("\tpublic {0}(MongoServer mongo)\n\t{{", typeName)); writer.WriteLine( @" this.mongo = mongo; } private readonly MongoServer mongo; public TextWriter SqlTabWriter { get; set; } "); if (props.InitializationQuery != null) { writer.WriteLine( @" private CustomInitQuery mCustomInitializer; public CustomInitQuery CustomInitializer { get { return this.mCustomInitializer; } } public void DoCustomInit(ConnectionProperties props) { if(mCustomInitializer == null) { mCustomInitializer = new CustomInitQuery(); mCustomInitializer.Initialize(props); } } "); } writer.WriteLine(string.Format( "\tpublic String ConnectionString {{ get {{ return \"{0}\"; }} }}\n", props.ConnectionString)); string db = props.SelectedDatabase; writer.WriteLine(string.Format( "\tpublic String DatabaseName {{ get {{ return \"{0}\"; }} }}\n", db)); writer.WriteLine(string.Format( "\tpublic MongoDatabase db {{ get {{ return this.mongo.GetDatabase(\"{0}\"); }} }}\n", db)); HashSet <string> names = new HashSet <string>(); List <string> initializations = new List <string>(); foreach (var collection in props.CollectionTypeMappings[db]) { var name = collection.CollectionName; Type type = null; if (!string.IsNullOrEmpty(collection.CollectionType) && !string.IsNullOrEmpty(name)) { type = this.TryLoadType(assemblies, collection.CollectionType); } var pluralizedName = DoPluralize(name); if (type == null) { //writer.WriteLine(string.Format( // "\tpublic MongoCollection {1}Collection {{ get {{ return this.db.GetCollection(\"{0}\"); }} }}\r\n" + // "\tpublic IQueryable<{2}> {1} {{ get {{ return this.{1}Collection.AsQueryable<{2}>().Select(x => x); }} }}", name, pluralizedName, typeof(BsonDocument).FullName)); } else { names.Add(pluralizedName); //Select(x => x) to get around bug in mongo query provider writer.WriteLine(string.Format( "\tprivate Interceptor<{0}> m{2};\r\n" + "\tpublic IQueryable<{0}> {2} {{ get {{ return this.m{2}.AsQueryable<{0}>().Select(x => x); }} }}\n", type.FullName, name, pluralizedName)); //generate initialization strings initializations.Add(string.Format("\t\tthis.m{2} = new Interceptor<{0}>(this.db.GetCollection<{0}>(\"{1}\"), this.SqlTabWriter);", type.FullName, name, pluralizedName)); if (props.AdditionalOptions.AllowSaveForAllTypes || props.AdditionalOptions.ExplicitSaveAllowedTypes.Contains(type.ToString())) { initializations.Add(string.Format("\t\tthis.m{0}.AllowSave = true;", pluralizedName)); } writer.WriteLine(string.Format( "\tpublic Interceptor<{0}> {2}Collection {{ get {{ return this.m{2}; }} }}\n", type.FullName, name, pluralizedName)); } } writer.WriteLine( @" /// <summary> /// Submits all changes to queried objects by calling Save on the objects given by /// <see cref=""ToUpdate""/> /// </summary> public void SubmitChanges() { int modified = 0;"); foreach (string name in names) { writer.WriteLine(string.Format("\t\tmodified += this.m{0}.SubmitChanges();", name)); } writer.WriteLine( @" if (modified == 0 && !TrackChanges){ Console.WriteLine(""No changes were submitted. Did you mean to turn on TrackChanges?""); } }"); writer.WriteLine( @" private bool mTrackChanges = false; /// <summary> /// If true, changes made to collection objects will be tracked and can be updated /// using SubmitChanges. Defaults to off to avoid unnecessary serialization. /// </summary> public bool TrackChanges { get { return mTrackChanges; } set { mTrackChanges = value; "); foreach (string name in names) { writer.WriteLine(string.Format("\t\t\tthis.m{0}.TrackChanges = value;", name)); } writer.WriteLine( @" } }"); writer.WriteLine( @" public void InitCollections() {"); foreach (string init in initializations) { writer.WriteLine(init); } writer.WriteLine("\t}"); // write type closing brace writer.WriteLine("}"); // write namespace closing brace if (!string.IsNullOrEmpty(nameSpace)) { writer.WriteLine("}"); } return(writer.ToString()); }
/// <summary> /// Builds the Schema tree for display to the user /// </summary> /// <param name="props">The deserialized Connection Properties</param> /// <param name="assemblies">The already-loaded assemblies.</param> /// <returns>A tree of ExplorerItem objects which is shown to the user in LinqPad's UI</returns> public List <ExplorerItem> BuildSchema(ConnectionProperties props, List <Assembly> assemblies) { List <ExplorerItem> ret = new List <ExplorerItem>(); List <ExplorerItem> UntypedCollections = new List <ExplorerItem>(); List <ExplorerItem> TypedCollections = new List <ExplorerItem>(); ret.Add(new ExplorerItem("db", ExplorerItemKind.QueryableObject, ExplorerIcon.LinkedDatabase)); foreach (var ctm in props.CollectionTypeMappings[props.SelectedDatabase]) { ExplorerItem coll = null; Type type = null; if (!string.IsNullOrEmpty(ctm.CollectionType)) { type = this.TryLoadType(assemblies, ctm.CollectionType); } if (type != null) { var name = DoPluralize(ctm.CollectionName); coll = new ExplorerItem(name, ExplorerItemKind.QueryableObject, ExplorerIcon.Table) { IsEnumerable = true, DragText = name, ToolTipText = String.Format("Queryable of {0}", type.Name) }; foreach (PropertyInfo info in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { //ignore BSON ignored properties if (info.GetCustomAttributes(typeof(BsonIgnoreAttribute), true).Any()) { continue; } if (coll.Children == null) { coll.Children = new List <ExplorerItem>(); } coll.Children.Add(new ExplorerItem(info.Name, ExplorerItemKind.Property, ExplorerIcon.Column)); } ret.Add(coll); var tColl = new ExplorerItem(name + "Collection", ExplorerItemKind.CollectionLink, ExplorerIcon.View) { IsEnumerable = true, DragText = name + "Collection", ToolTipText = String.Format("MongoCollection of {0}", type.Name) }; tColl.Children = coll.Children; TypedCollections.Add(tColl); } else { UntypedCollections.Add(new ExplorerItem(ctm.CollectionName, ExplorerItemKind.Category, ExplorerIcon.Blank)); } } if (TypedCollections.Count > 0) { var item = new ExplorerItem("Collections", ExplorerItemKind.Category, ExplorerIcon.Box); item.Children = TypedCollections; ret.Add(item); } if (UntypedCollections.Count > 0) { var item = new ExplorerItem("Untyped Collections", ExplorerItemKind.Category, ExplorerIcon.Box); item.Children = UntypedCollections; ret.Add(item); } if (ret.Count == 0) { throw new Exception("No databases mapped to types"); } return(ret); }