5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne
\r
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
\r
8 // of this software and associated documentation files (the "Software"), to deal
\r
9 // in the Software without restriction, including without limitation the rights
\r
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
\r
11 // copies of the Software, and to permit persons to whom the Software is
\r
12 // furnished to do so, subject to the following conditions:
\r
14 // The above copyright notice and this permission notice shall be included in
\r
15 // all copies or substantial portions of the Software.
\r
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
\r
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
\r
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
\r
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
\r
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
\r
27 using System.Collections.Generic;
\r
28 using System.Globalization;
\r
31 using DbLinq.Factory;
\r
32 using DbLinq.Schema;
\r
33 using DbLinq.Schema.Dbml;
\r
35 using DbLinq.Vendor;
\r
36 using DbMetal.Schema;
\r
40 namespace DbMetal.Generator.Implementation
\r
45 class Processor : IProcessor
\r
47 private TextWriter log;
\r
51 public TextWriter Log
\r
53 get { return log ?? Console.Out; }
\r
57 SchemaLoaderFactory.Log = value;
\r
61 public ISchemaLoaderFactory SchemaLoaderFactory { get; set; }
\r
65 //for DbMetal for want to log to console
\r
66 //for VisualMetal we want to log to log4net
\r
67 //Logger = ObjectFactory.Get<ILogger>();
\r
68 SchemaLoaderFactory = ObjectFactory.Get<ISchemaLoaderFactory>();
\r
71 public void Process(string[] args)
\r
73 var parameters = new Parameters { Log = Log };
\r
75 if (args.Length == 0)
\r
76 PrintUsage(parameters);
\r
80 parameters.WriteHeader();
\r
84 parameters.Parse(args);
\r
88 Output.WriteErrorLine(Log, e.Message);
\r
89 PrintUsage(parameters);
\r
93 if (parameters.Help)
\r
95 PrintUsage(parameters);
\r
99 ProcessSchema(parameters);
\r
101 if (parameters.ReadLineAtExit)
\r
103 // '-readLineAtExit' flag: useful when running from Visual Studio
\r
109 private void ProcessSchema(Parameters parameters)
\r
113 // we always need a factory, even if generating from a DBML file, because we need a namespace
\r
114 ISchemaLoader schemaLoader;
\r
115 // then we load the schema
\r
116 var dbSchema = ReadSchema(parameters, out schemaLoader);
\r
117 // the we write it (to DBML or code)
\r
118 WriteSchema(dbSchema, schemaLoader, parameters);
\r
120 catch (Exception ex)
\r
122 string assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
\r
123 Output.WriteErrorLine(Log, assemblyName + " failed:" + ex);
\r
127 protected void WriteSchema(Database dbSchema, ISchemaLoader schemaLoader, Parameters parameters)
\r
129 if (parameters.Dbml != null)
\r
131 //we are supposed to write out a DBML file and exit
\r
132 parameters.Write("<<< Writing file '{0}'", parameters.Dbml);
\r
133 using (Stream dbmlFile = File.Create(parameters.Dbml))
\r
135 DbmlSerializer.Write(dbmlFile, dbSchema);
\r
140 if (!parameters.Schema)
\r
141 RemoveSchemaFromTables(dbSchema);
\r
143 // extract filename from output filename, database schema or schema name
\r
144 string filename = parameters.Code;
\r
145 if (string.IsNullOrEmpty(filename) && !string.IsNullOrEmpty(parameters.Database))
\r
146 filename = parameters.Database.Replace("\"", "");
\r
147 if (string.IsNullOrEmpty(filename))
\r
148 filename = dbSchema.Name;
\r
150 // TODO: move such check to runtime.
\r
151 schemaLoader.CheckNamesSafety(dbSchema);
\r
153 parameters.Write("<<< writing C# classes in file '{0}'", filename);
\r
154 GenerateCode(parameters, dbSchema, schemaLoader, filename);
\r
159 protected void RemoveSchemaFromTables(Database schema)
\r
161 foreach (var table in schema.Table)
\r
163 string[] nameAndSchema = table.Name.Split('.');
\r
164 table.Name = nameAndSchema[nameAndSchema.Length - 1];
\r
168 public virtual IEnumerable<ICodeGenerator> EnumerateCodeGenerators()
\r
170 foreach (var codeGeneratorType in ObjectFactory.Current.GetImplementations(typeof(ICodeGenerator)))
\r
172 yield return (ICodeGenerator)ObjectFactory.Current.Get(codeGeneratorType);
\r
176 protected virtual ICodeGenerator FindCodeGeneratorByLanguage(string languageCode)
\r
178 return (from codeGenerator in EnumerateCodeGenerators()
\r
179 where codeGenerator.LanguageCode == languageCode
\r
180 select codeGenerator).SingleOrDefault();
\r
183 protected virtual ICodeGenerator FindCodeGeneratorByExtension(string extension)
\r
185 return EnumerateCodeGenerators().SingleOrDefault(gen => gen.Extension == extension);
\r
188 public virtual ICodeGenerator FindCodeGenerator(Parameters parameters, string filename)
\r
190 if (!string.IsNullOrEmpty(parameters.Language))
\r
191 return FindCodeGeneratorByLanguage(parameters.Language);
\r
192 return FindCodeGeneratorByExtension(Path.GetExtension(filename));
\r
195 public void GenerateCode(Parameters parameters, Database dbSchema, ISchemaLoader schemaLoader, string filename)
\r
197 ICodeGenerator codeGenerator = FindCodeGenerator(parameters, filename);
\r
198 if (codeGenerator == null)
\r
199 throw new ArgumentException("Please specify either a /language or a /code file");
\r
201 if (string.IsNullOrEmpty(filename))
\r
202 filename = dbSchema.Class;
\r
203 if (String.IsNullOrEmpty(Path.GetExtension(filename)))
\r
204 filename += codeGenerator.Extension;
\r
206 using (var streamWriter = new StreamWriter(filename))
\r
208 var generationContext = new GenerationContext(parameters, schemaLoader);
\r
209 codeGenerator.Write(streamWriter, dbSchema, generationContext);
\r
213 public Database ReadSchema(Parameters parameters, out ISchemaLoader schemaLoader)
\r
216 var nameAliases = NameAliasesLoader.Load(parameters.Aliases);
\r
217 if (parameters.SchemaXmlFile == null) // read schema from DB
\r
219 schemaLoader = SchemaLoaderFactory.Load(parameters);
\r
221 parameters.Write(">>> Reading schema from {0} database", schemaLoader.Vendor.VendorName);
\r
222 dbSchema = schemaLoader.Load(parameters.Database, nameAliases,
\r
223 new NameFormat(parameters.Pluralize, GetCase(parameters), new CultureInfo(parameters.Culture)),
\r
224 parameters.Sprocs, parameters.Namespace, parameters.Namespace);
\r
225 dbSchema.Provider = parameters.Provider;
\r
226 dbSchema.Tables.Sort(new LambdaComparer<Table>((x, y) => (x.Type.Name.CompareTo(y.Type.Name))));
\r
227 foreach (var table in dbSchema.Tables)
\r
228 table.Type.Columns.Sort(new LambdaComparer<Column>((x, y) => (x.Member.CompareTo(y.Member))));
\r
229 dbSchema.Functions.Sort(new LambdaComparer<Function>((x, y) => (x.Method.CompareTo(y.Method))));
\r
230 //SchemaPostprocess.PostProcess_DB(dbSchema);
\r
234 dbSchema = ReadSchema(parameters, parameters.SchemaXmlFile);
\r
235 schemaLoader = SchemaLoaderFactory.Load(dbSchema.Provider);
\r
238 if (schemaLoader == null)
\r
239 throw new ApplicationException("Please provide -Provider=MySql (or Oracle, OracleODP, PostgreSql, Sqlite - see app.config for provider listing)");
\r
244 public Database ReadSchema(Parameters parameters, string filename)
\r
246 parameters.Write(">>> Reading schema from DBML file '{0}'", filename);
\r
247 using (Stream dbmlFile = File.OpenRead(filename))
\r
249 return DbmlSerializer.Read(dbmlFile);
\r
253 private void PrintUsage(Parameters parameters)
\r
255 parameters.WriteHelp();
\r
258 private Case GetCase(Parameters parameters)
\r
260 if (String.IsNullOrEmpty(parameters.Case))
\r
261 return Case.PascalCase;
\r
263 switch (parameters.Case.ToLowerInvariant())
\r
268 return Case.camelCase;
\r
270 return Case.PascalCase;
\r
272 return Case.NetCase;
\r