public static void Register(List <string> helperAssemblies, bool force = false) { try { var ctr = TinyIoCContainer.Current; //kludge if (force == true) { ctr.Dispose(); } else if (false)//TinyIoCContainer.Current.CanResolve<IWrapperClassMaker>()) { //_VSOutputWindow.Write("Already registered\n"); return; } List <Assembly> assemblies = new List <Assembly>(); if (helperAssemblies != null) { foreach (var ass in helperAssemblies) { try { assemblies.Add(Assembly.LoadFrom(ass)); } catch (Exception ex) { QfConsole.WriteLine($@"Error loading assembly {ass}\n{ex}"); } } } assemblies.Add(Assembly.GetExecutingAssembly()); var then = new DateTime(); // First in wins TinyIoCContainer.Current.AutoRegister(assemblies, DuplicateImplementationActions.RegisterSingle); var now = new DateTime(); QfConsole.WriteLine($@"{assemblies.Count} assemblies registered in { (now - then).TotalMilliseconds}ms"); // IProvider, for instance, has multiple implementations. To resolve we use the provider name on the connection string, // which must correspond to the fully qualified name of the implementation. ie. QueryFirst.Providers.SqlClient for SqlServer } catch (Exception ex) { QfConsole.WriteLine(ex.ToString()); } }
public static void Main(string[] args) { // parse args var startupOptions = DefineAndParseOptions(args); // check we have a file (should never be empty because if nothing provided we take the current directory.) if (!string.IsNullOrEmpty(startupOptions.SourcePath) && !File.Exists(startupOptions.SourcePath) && !Directory.Exists(startupOptions.SourcePath)) { QfConsole.WriteLine($@"The file or directory {startupOptions.SourcePath} does not exist. Exiting..."); return; } // fetch config query/project/install var configFileReader = new ConfigFileReader(); var projectConfig = configFileReader.GetProjectConfig(startupOptions.SourcePath); var installConfig = configFileReader.GetInstallConfig(); var projectType = new ProjectType().DetectProjectType(); // build config project-install var configBuilder = new ConfigBuilder(); var outerConfig = configBuilder.Resolve2Configs(projectConfig, configBuilder.GetInstallConfigForProjectType(installConfig, projectType)); // register types RegisterTypes.Register(outerConfig.HelperAssemblies); // New Config if (startupOptions.CreateConfig.GetValueOrDefault()) { var fileToCreate = Path.Join(Environment.CurrentDirectory, "qfconfig.json"); if (File.Exists(fileToCreate)) { Console.WriteLine($"QueryFirst: {fileToCreate} exists already. Skipping."); } File.WriteAllText(fileToCreate, $@"{{ ""defaultConnection"": ""Server = localhost\\SQLEXPRESS; Database = NORTHWND; Trusted_Connection = True; "", ""provider"": ""System.Data.SqlClient"", ""namespace"": ""MyNamespaceForCodeGeneration"" }} " ); } // New Runtime Connection if (startupOptions.CreateRuntimeConnection.GetValueOrDefault()) { var fileToCreate = Path.Join(Environment.CurrentDirectory, "QfRuntimeConnection.cs"); if (File.Exists(fileToCreate)) { Console.WriteLine($"QueryFirst: {fileToCreate} exists already. Skipping."); } File.WriteAllText(fileToCreate, $@"using Microsoft.Data.SqlClient; using System.Data; class QfRuntimeConnection {{ public static IDbConnection GetConnection() {{ return new SqlConnection(""Server=localhost\\SQLEXPRESS;Database=NORTHWND;Trusted_Connection=True;""); }} }} " ); } // New query if (!string.IsNullOrEmpty(startupOptions.NewQueryName)) { if (!startupOptions.NewQueryName.EndsWith(".sql")) { startupOptions.NewQueryName = startupOptions.NewQueryName + ".sql"; } if (File.Exists(startupOptions.NewQueryName)) { Console.WriteLine($"QueryFirst: {startupOptions.NewQueryName} exists already. Exiting"); return; } File.WriteAllText(startupOptions.NewQueryName, @"/* .sql query managed by QueryFirst */ -- designTime - put parameter declarations and design time initialization here -- endDesignTime" ); return; } // C'est pas beau. If we've created a file or shown help, we'll do nothing else... if (startupOptions.CreateConfig.GetValueOrDefault() || startupOptions.CreateRuntimeConnection.GetValueOrDefault() || !string.IsNullOrEmpty(startupOptions.NewQueryName) || startupOptions.DidShowHelp ) { return; } // Process one file if (File.Exists(startupOptions.SourcePath)) { if (startupOptions.Watch) { // watch for changes or renaming of the specified file. (VS renames a temp file after deleting the original file) using (FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(startupOptions.SourcePath), Path.GetFileName(startupOptions.SourcePath))) { watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; watcher.Changed += (source, e) => { try { var conductor = new Conductor().BuildUp(); conductor.ProcessOneQuery(startupOptions.SourcePath, outerConfig); } catch (Exception ex) { Console.Write(ex.TellMeEverything()); } }; //watcher.Deleted += OnChanged; watcher.Renamed += (source, e) => { try { var conductor = new Conductor().BuildUp(); conductor.ProcessOneQuery(startupOptions.SourcePath, outerConfig); } catch (Exception ex) { Console.Write(ex.TellMeEverything()); } }; watcher.EnableRaisingEvents = true; Console.WriteLine("Press 'q' to stop watching."); while (Console.Read() != 'q') { ; } } } else { var conductor = new Conductor().BuildUp(); conductor.ProcessOneQuery(startupOptions.SourcePath, outerConfig); } } // Process a folder if (Directory.Exists(startupOptions.SourcePath)) { if (startupOptions.Watch) { // watch for changes or renaming of .sql files in the specified folder. using (FileSystemWatcher watcher = new FileSystemWatcher(startupOptions.SourcePath, "*.sql")) { watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; watcher.IncludeSubdirectories = true; watcher.Changed += (source, e) => { try { if (e.FullPath.ToLower().EndsWith(".sql")) { var conductor = new Conductor().BuildUp(); conductor.ProcessOneQuery(e.FullPath, outerConfig); } } catch (Exception ex) { Console.Write(ex.TellMeEverything()); } }; //watcher.Deleted += OnChanged; watcher.Renamed += (source, e) => { try { if (e.FullPath.ToLower().EndsWith(".sql")) { var conductor = new Conductor().BuildUp(); conductor.ProcessOneQuery(e.FullPath, outerConfig); } } catch (Exception ex) { Console.Write(ex.TellMeEverything()); } }; watcher.EnableRaisingEvents = true; Console.WriteLine($"Press 'q' to stop watching in ${startupOptions.SourcePath}"); while (Console.Read() != 'q') { ; } } } else { ProcessDirectory(startupOptions.SourcePath, outerConfig); } if (keepOpen) { Console.ReadKey(); } } }
public void ProcessOneQuery(string sourcePath, QfConfigModel outerConfig) { try { _state = new State(); ProcessUpToStep4(sourcePath, outerConfig, ref _state); // We have the config, we can instantiate our provider... if (_tiny.CanResolve <IProvider>(_state._3Config.Provider)) { _provider = _tiny.Resolve <IProvider>(_state._3Config.Provider); } else { QfConsole.WriteLine(@"After resolving the config, we have no provider\n"); } if (string.IsNullOrEmpty(_state._3Config.DefaultConnection)) { QfConsole.WriteLine(@"No design time connection string. You need to create qfconfig.json beside or above your query or put --QfDefaultConnection=myConnectionString somewhere in your query file. See the Readme section at https://marketplace.visualstudio.com/items?itemName=bbsimonbb.QueryFirst "); return; // nothing to be done } if (!_tiny.CanResolve <IProvider>(_state._3Config.Provider)) { QfConsole.WriteLine(string.Format( @"No Implementation of IProvider for providerName {0}. The query {1} may not run and the wrapper has not been regenerated.\n", _state._3Config.Provider, _state._1BaseName )); return; } // assign some names new _4ExtractNamesFromUserPartialClass().Go(_state); // Scaffold inserts and updates _tiny.Resolve <_5ScaffoldUpdateOrInsert>().Go(ref _state); if (_state._2InitialQueryText != _state._5QueryAfterScaffolding) { } // Execute query try { new _6FindUndeclaredParameters(_provider).Go(ref _state, out string outputMessage); // if message returned, write it to output. if (!string.IsNullOrEmpty(outputMessage)) { QfConsole.WriteLine(outputMessage); } // if undeclared params were found, modify the original .sql if (!string.IsNullOrEmpty(_state._6NewParamDeclarations)) { QfTextFileWriter.WriteFile(new QfTextFile() { Filename = _state._1SourceQueryFullPath, FileContents = _state._6QueryWithParamsAdded }); } new _7RunQueryAndGetResultSchema(new AdoSchemaFetcher(), _provider).Go(ref _state); new _8ParseOrFindDeclaredParams(_provider).Go(ref _state); } catch (Exception ex) { StringBuilder bldr = new StringBuilder(); bldr.AppendLine("Error running query."); bldr.AppendLine(); bldr.AppendLine("/*The last attempt to run this query failed with the following error. This class is no longer synced with the query"); bldr.AppendLine("You can compile the class by deleting this error information, but it will likely generate runtime errors."); bldr.AppendLine("-----------------------------------------------------------"); bldr.AppendLine(ex.Message); bldr.AppendLine("-----------------------------------------------------------"); bldr.AppendLine(ex.StackTrace); bldr.AppendLine("*/"); File.AppendAllText(_state._1GeneratedClassFullFilename, bldr.ToString()); throw; } // dump state for reproducing issues #if DEBUG using (var ms = new MemoryStream()) { var ser = new DataContractJsonSerializer(typeof(State)); ser.WriteObject(ms, _state); byte[] json = ms.ToArray(); ms.Close(); File.WriteAllText(_state._1CurrDir + "qfDumpState.json", Encoding.UTF8.GetString(json, 0, json.Length)); } #endif var code = new CSharpFrameworkGenerator().Generate(_state); //File.WriteAllText(ctx.GeneratedClassFullFilename, Code.ToString()); QfTextFileWriter.WriteFile(code); QfConsole.WriteLine("QueryFirst generated wrapper class for " + _state._1BaseName + ".sql" + Environment.NewLine); } catch (Exception ex) { QfConsole.WriteLine(ex.TellMeEverything()); } }