Fix problems with overlong directory names: phase #1
[mono.git] / mcs / class / System.Data / System.Data / CustomDataClassGenerator.cs
1 //
2 // Mono.Data.CustomDataClassGenerator
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // (C)2004 Novell Inc.
8 //
9 // API notes are the bottom of the source.
10 //
11 // This class is standalone testable (even under MS.NET) when compiled with
12 // -d:DATACLASS_GENERATOR_STANDALONE .
13 //
14
15 //
16 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
17 //
18 // Permission is hereby granted, free of charge, to any person obtaining
19 // a copy of this software and associated documentation files (the
20 // "Software"), to deal in the Software without restriction, including
21 // without limitation the rights to use, copy, modify, merge, publish,
22 // distribute, sublicense, and/or sell copies of the Software, and to
23 // permit persons to whom the Software is furnished to do so, subject to
24 // the following conditions:
25 // 
26 // The above copyright notice and this permission notice shall be
27 // included in all copies or substantial portions of the Software.
28 // 
29 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 //
37 using System;
38 using System.Xml;
39 using System.Data;
40 using System.Collections;
41 using System.CodeDom;
42 using System.Globalization;
43 using System.Text;
44 using System.CodeDom.Compiler;
45 using System.ComponentModel;
46 using System.Runtime.Serialization;
47 using System.Xml.Schema;
48 using System.Xml.Serialization;
49
50 // only for Driver
51 using Microsoft.CSharp;
52 using System.IO;
53
54 namespace System.Data
55 {
56
57 #if DATACLASS_GENERATOR_STANDALONE
58         public class Driver
59         {
60                 public static void Main (string [] args)
61                 {
62                         try {
63                                 if (args.Length < 1) {
64                                         Console.WriteLine ("mono dsgentest.exe filename");
65                                         return;
66                                 }
67
68                                 DataSet ds = new DataSet ();
69                                 ds.ReadXml (args [0]);
70                                 ICodeGenerator gen = new CSharpCodeProvider ().CreateGenerator ();
71
72                                 CodeNamespace cns = new CodeNamespace ("MyNamespace");
73                                 TextWriter tw = new StreamWriter (Path.ChangeExtension (args [0], ".ms.cs"), false, Encoding.Default);
74                                 TypedDataSetGenerator.Generate (ds, cns, gen);
75                                 gen.GenerateCodeFromNamespace (cns, tw, null);
76                                 tw.Close ();
77
78                                 cns = new CodeNamespace ("MyNamespace");
79                                 tw = new StreamWriter (Path.ChangeExtension (args [0], ".mono.cs"), false, Encoding.Default);
80                                 CustomDataClassGenerator.CreateDataSetClasses (ds, cns, gen, null);
81                                 gen.GenerateCodeFromNamespace (cns, tw, null);
82                                 tw.Close ();
83                         } catch (Exception ex) {
84                                 Console.WriteLine (ex);
85                         }
86                 }
87         }
88 #endif
89
90 #if DATACLASS_GENERATOR_STANDALONE
91         public class CustomDataClassGenerator
92 #else
93         internal class CustomDataClassGenerator
94 #endif
95         {
96                 public static void CreateDataSetClasses (DataSet ds,
97                         CodeNamespace cns, ICodeGenerator gen,
98                         ClassGeneratorOptions options)
99                 {
100                         new Generator (ds, cns, gen, options).Run ();
101                 }
102
103                 public static string MakeSafeName (string name, ICodeGenerator codeGen)
104                 {
105                         if (name == null || codeGen == null)
106                                 throw new NullReferenceException ();
107
108                         name = codeGen.CreateValidIdentifier (name);
109
110                         if (name.Length == 0)
111                                 return "_";
112
113                         StringBuilder sb = null;
114                         if (!Char.IsLetter (name, 0) && name [0] != '_') {
115                                 sb = new StringBuilder ();
116                                 sb.Append ('_');
117                         }
118
119                         int start = 0;
120                         for (int i = 0; i < name.Length; i++) {
121                                 if (!Char.IsLetterOrDigit (name, i)) {
122                                         if (sb == null)
123                                                 sb = new StringBuilder ();
124                                         sb.Append (name, start, i - start);
125                                         sb.Append ('_');
126                                         start = i + 1;
127                                 }
128                         }
129
130                         if (sb != null) {
131                                 sb.Append (name, start, name.Length - start);
132                                 return sb.ToString ();
133                         }
134                         else
135                                 return name;
136                 }
137         }
138
139 #if DATACLASS_GENERATOR_STANDALONE
140         public delegate string CodeNamingMethod (string source, ICodeGenerator gen);
141 #else
142         internal delegate string CodeNamingMethod (string source, ICodeGenerator gen);
143 #endif
144
145 #if DATACLASS_GENERATOR_STANDALONE
146         public class ClassGeneratorOptions
147 #else
148         internal class ClassGeneratorOptions
149 #endif
150         {
151                 public bool MakeClassesInsideDataSet = true; // default = MS compatible
152
153                 public CodeNamingMethod CreateDataSetName;
154                 public CodeNamingMethod CreateTableTypeName;
155                 public CodeNamingMethod CreateTableMemberName;
156                 public CodeNamingMethod CreateTableColumnName;
157                 public CodeNamingMethod CreateColumnName;
158                 public CodeNamingMethod CreateRowName;
159                 public CodeNamingMethod CreateRelationName;
160                 public CodeNamingMethod CreateTableDelegateName;
161                 public CodeNamingMethod CreateEventArgsName;
162
163                 internal string DataSetName (string source, ICodeGenerator gen)
164                 {
165                         if (CreateDataSetName != null)
166                                 return CreateDataSetName (source, gen);
167                         else
168                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
169                 }
170
171                 internal string TableTypeName (string source, ICodeGenerator gen)
172                 {
173                         if (CreateTableTypeName != null)
174                                 return CreateTableTypeName (source, gen);
175                         else
176                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "DataTable";
177                 }
178
179                 internal string TableMemberName (string source, ICodeGenerator gen)
180                 {
181                         if (CreateTableMemberName != null)
182                                 return CreateTableMemberName (source, gen);
183                         else
184                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
185                 }
186
187                 internal string TableColName (string source, ICodeGenerator gen)
188                 {
189                         if (CreateTableColumnName != null)
190                                 return CreateTableColumnName (source, gen);
191                         else
192                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
193                 }
194
195                 internal string TableDelegateName (string source, ICodeGenerator gen)
196                 {
197                         if (CreateTableDelegateName != null)
198                                 return CreateTableDelegateName (source, gen);
199                         else
200                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "RowChangedEventHandler";
201                 }
202
203                 internal string EventArgsName (string source, ICodeGenerator gen)
204                 {
205                         if (CreateEventArgsName != null)
206                                 return CreateEventArgsName (source, gen);
207                         else
208                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "RowChangedEventArgs";
209                 }
210
211                 internal string ColumnName (string source, ICodeGenerator gen)
212                 {
213                         if (CreateColumnName != null)
214                                 return CreateColumnName (source, gen);
215                         else
216                                 return CustomDataClassGenerator.MakeSafeName (source, gen);
217                 }
218
219                 internal string RowName (string source, ICodeGenerator gen)
220                 {
221                         if (CreateRowName != null)
222                                 return CreateRowName (source, gen);
223                         else
224                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "Row";
225                 }
226
227                 internal string RelationName (string source, ICodeGenerator gen)
228                 {
229                         if (CreateRelationName != null)
230                                 return CreateRelationName (source, gen);
231                         else
232                                 return CustomDataClassGenerator.MakeSafeName (source, gen) + "Relation";
233                 }
234         }
235
236         internal class Generator
237         {
238                 static ClassGeneratorOptions DefaultOptions = new ClassGeneratorOptions ();
239
240                 DataSet ds;
241                 CodeNamespace cns;
242                 ClassGeneratorOptions opts;
243                 ICodeGenerator gen;
244
245                 CodeTypeDeclaration dsType;
246
247                 public Generator (DataSet ds, CodeNamespace cns, ICodeGenerator gen, ClassGeneratorOptions options)
248                 {
249                         this.ds = ds;
250                         this.cns = cns;
251                         this.gen = gen;
252                         this.opts = options;
253
254                         if (opts == null)
255                                 opts = DefaultOptions;
256                 }
257
258                 public void Run ()
259                 {
260                         // using decls
261                         cns.Imports.Add (new CodeNamespaceImport ("System"));
262                         cns.Imports.Add (new CodeNamespaceImport ("System.Collections"));
263                         cns.Imports.Add (new CodeNamespaceImport ("System.ComponentModel"));
264                         cns.Imports.Add (new CodeNamespaceImport ("System.Data"));
265                         cns.Imports.Add (new CodeNamespaceImport ("System.Runtime.Serialization"));
266                         cns.Imports.Add (new CodeNamespaceImport ("System.Xml"));
267
268
269                         CodeTypeDeclaration dsType = GenerateDataSetType ();
270                         cns.Types.Add (dsType);
271                         foreach (DataTable dt in ds.Tables) {
272                                 // 1. table types ([foo]DataTable)
273                                 // 2. row types ([foo]Row)
274                                 // 3. delegates ([foo]RowChangedEventHandler)
275                                 // 4. eventargs ([foo]RowChangeEventArgs)
276
277                                 CodeTypeDeclaration dtType = GenerateDataTableType (dt);
278
279                                 CodeTypeDeclaration dtRow = GenerateDataRowType (dt);
280
281                                 CodeTypeDelegate dtDelegate = new CodeTypeDelegate (opts.TableDelegateName (dt.TableName, gen));
282                                 dtDelegate.Parameters.Add (Param (typeof (object), "o"));
283                                 dtDelegate.Parameters.Add (Param (opts.EventArgsName (dt.TableName, gen), "e"));
284
285                                 CodeTypeDeclaration dtEventType = GenerateEventType (dt);
286
287                                 // Add types to either DataSet or CodeNamespace
288                                 if (opts.MakeClassesInsideDataSet) {
289                                         dsType.Members.Add (dtType);
290                                         dsType.Members.Add (dtRow);
291                                         dsType.Members.Add (dtDelegate);
292                                         dsType.Members.Add (dtEventType);
293                                 }
294                                 else {
295                                         cns.Types.Add (dtType);
296                                         cns.Types.Add (dtRow);
297                                         cns.Types.Add (dtDelegate);
298                                         cns.Types.Add (dtEventType);
299                                 }
300                         }
301                 }
302
303                 private CodeThisReferenceExpression This ()
304                 {
305                         return new CodeThisReferenceExpression ();
306                 }
307
308                 private CodeBaseReferenceExpression Base ()
309                 {
310                         return new CodeBaseReferenceExpression ();
311                 }
312
313                 private CodePrimitiveExpression Const (object value)
314                 {
315                         return new CodePrimitiveExpression (value);
316                 }
317
318                 private CodeTypeReference TypeRef (Type t)
319                 {
320                         return new CodeTypeReference (t);
321                 }
322
323                 private CodeTypeReference TypeRef (string name)
324                 {
325                         return new CodeTypeReference (name);
326                 }
327
328                 private CodeParameterDeclarationExpression Param (string t, string name)
329                 {
330                         return new CodeParameterDeclarationExpression (t, name);
331                 }
332
333                 private CodeParameterDeclarationExpression Param (Type t, string name)
334                 {
335                         return new CodeParameterDeclarationExpression (t, name);
336                 }
337
338                 private CodeParameterDeclarationExpression Param (CodeTypeReference t, string name)
339                 {
340                         return new CodeParameterDeclarationExpression (t, name);
341                 }
342
343                 private CodeArgumentReferenceExpression ParamRef (string name)
344                 {
345                         return new CodeArgumentReferenceExpression (name);
346                 }
347
348                 private CodeCastExpression Cast (string t, CodeExpression exp)
349                 {
350                         return new CodeCastExpression (t, exp);
351                 }
352
353                 private CodeCastExpression Cast (Type t, CodeExpression exp)
354                 {
355                         return new CodeCastExpression (t, exp);
356                 }
357
358                 private CodeCastExpression Cast (CodeTypeReference t, CodeExpression exp)
359                 {
360                         return new CodeCastExpression (t, exp);
361                 }
362
363                 private CodeExpression New (Type t, params CodeExpression [] parameters)
364                 {
365                         return new CodeObjectCreateExpression (t, parameters);
366                 }
367
368                 private CodeExpression New (string t, params CodeExpression [] parameters)
369                 {
370                         return new CodeObjectCreateExpression (TypeRef (t), parameters);
371                 }
372
373                 private CodeExpression NewArray (Type t, params CodeExpression [] parameters)
374                 {
375                         return new CodeArrayCreateExpression (t, parameters);
376                 }
377
378                 private CodeVariableReferenceExpression Local (string name)
379                 {
380                         return new CodeVariableReferenceExpression (name);
381                 }
382
383                 private CodeFieldReferenceExpression FieldRef (string name)
384                 {
385                         return new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), name);
386                 }
387
388                 private CodeFieldReferenceExpression FieldRef (CodeExpression exp, string name)
389                 {
390                         return new CodeFieldReferenceExpression (exp, name);
391                 }
392
393                 private CodePropertyReferenceExpression PropRef (string name)
394                 {
395                         return new CodePropertyReferenceExpression (new CodeThisReferenceExpression (), name);
396                 }
397
398                 private CodePropertyReferenceExpression PropRef (CodeExpression target, string name)
399                 {
400                         return new CodePropertyReferenceExpression (target, name);
401                 }
402
403                 private CodeIndexerExpression IndexerRef (CodeExpression target, CodeExpression parameters)
404                 {
405                         return new CodeIndexerExpression (target, parameters);
406                 }
407
408                 private CodeIndexerExpression IndexerRef (CodeExpression param)
409                 {
410                         return new CodeIndexerExpression (new CodeThisReferenceExpression (), param);
411                 }
412
413                 private CodeEventReferenceExpression EventRef (string name)
414                 {
415                         return new CodeEventReferenceExpression (new CodeThisReferenceExpression (), name);
416                 }
417
418                 private CodeEventReferenceExpression EventRef (CodeExpression target, string name)
419                 {
420                         return new CodeEventReferenceExpression (target, name);
421                 }
422
423                 private CodeMethodInvokeExpression MethodInvoke (string name, params CodeExpression [] parameters)
424                 {
425                         return new CodeMethodInvokeExpression (new CodeThisReferenceExpression (), name, parameters);
426                 }
427
428                 private CodeMethodInvokeExpression MethodInvoke (CodeExpression target, string name, params CodeExpression [] parameters)
429                 {
430                         return new CodeMethodInvokeExpression (target, name, parameters);
431                 }
432
433                 // note that this is "Identity" equality comparison
434                 private CodeBinaryOperatorExpression Equals (CodeExpression exp1, CodeExpression exp2)
435                 {
436                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.IdentityEquality, exp2);
437                 }
438
439                 private CodeBinaryOperatorExpression Inequals (CodeExpression exp1, CodeExpression exp2)
440                 {
441                         return new CodeBinaryOperatorExpression (exp1, CodeBinaryOperatorType.IdentityInequality, exp2);
442                 }
443
444                 private CodeTypeReferenceExpression TypeRefExp (Type t)
445                 {
446                         return new CodeTypeReferenceExpression (t);
447                 }
448
449
450                 private CodeExpressionStatement Eval (CodeExpression exp)
451                 {
452                         return new CodeExpressionStatement (exp);
453                 }
454
455                 private CodeAssignStatement Let (CodeExpression exp, CodeExpression value)
456                 {
457                         return new CodeAssignStatement (exp, value);
458                 }
459
460                 private CodeMethodReturnStatement Return (CodeExpression exp)
461                 {
462                         return new CodeMethodReturnStatement (exp);
463                 }
464
465                 private CodeVariableDeclarationStatement VarDecl (Type t,
466                         string name, CodeExpression init)
467                 {
468                         return new CodeVariableDeclarationStatement (t, name, init);
469                 }
470
471                 private CodeVariableDeclarationStatement VarDecl (string t,
472                         string name, CodeExpression init)
473                 {
474                         return new CodeVariableDeclarationStatement (t, name, init);
475                 }
476
477                 private CodeCommentStatement Comment (string comment)
478                 {
479                         return new CodeCommentStatement (comment);
480                 }
481
482                 private CodeThrowExceptionStatement Throw (CodeExpression exp)
483                 {
484                         return new CodeThrowExceptionStatement (exp);
485                 }
486
487 #region DataSet class
488
489                 private CodeTypeDeclaration GenerateDataSetType ()
490                 {
491                         // Type
492                         dsType = new CodeTypeDeclaration (opts.DataSetName (ds.DataSetName, gen));
493                         dsType.BaseTypes.Add (TypeRef (typeof (DataSet)));
494                         dsType.BaseTypes.Add (TypeRef (typeof (IXmlSerializable)));
495
496                         // .ctor()
497                         dsType.Members.Add (CreateDataSetDefaultCtor ());
498                         // runtime serialization .ctor()
499                         dsType.Members.Add (CreateDataSetSerializationCtor ());
500
501                         // Clone()
502                         dsType.Members.Add (CreateDataSetCloneMethod (dsType));
503
504 // FIXME: I keep these methods out of the generated source right now.
505 // It should be added after runtime serialization was implemented.
506 /*
507                         // ShouldSerializeTables()
508                         dsType.Members.Add (CreateDataSetShouldSerializeTables ());
509
510                         // ShouldSerializeRelations()
511                         dsType.Members.Add (CreateDataSetShouldSerializeRelations ());
512
513                         // ReadXmlSerializable()
514                         dsType.Members.Add (CreateDataSetReadXmlSerializable ());
515 */
516
517                         // GetSchemaSerializable()
518                         dsType.Members.Add (CreateDataSetGetSchemaSerializable ());
519
520                         dsType.Members.Add (CreateDataSetGetSchema ());
521                         dsType.Members.Add (CreateDataSetInitializeClass ());
522                         dsType.Members.Add (CreateDataSetInitializeFields ());
523                         dsType.Members.Add (CreateDataSetSchemaChanged ());
524
525                         // table class and members
526                         foreach (DataTable table in ds.Tables)
527                                 CreateDataSetTableMembers (dsType, table);
528                         // relation class and members
529                         foreach (DataRelation rel in ds.Relations)
530                                 CreateDataSetRelationMembers (dsType, rel);
531
532                         return dsType;
533                 }
534
535                 // Code:
536                 // public Foo ()
537                 // {
538                 //   InitializeClass();
539                 //   CollectionChangeEventHandler handler = new CollectionChangeEventHandler (SchemaChanged);
540                 //   Tables.CollectionChanged += handler;
541                 //   Relations.CollectionChanged += handler;
542                 // }
543                 private CodeConstructor CreateDataSetDefaultCtor ()
544                 {
545                         CodeConstructor ctor = new CodeConstructor ();
546                         ctor.Attributes = MemberAttributes.Public;
547                         // Code: InitializeClass().
548                         ctor.Statements.Add (Eval (MethodInvoke ("InitializeClass")));
549
550                         // Code: CollectionChangedEventHandler handler = new CollectionChangeEventHandler (SchemeChanged);
551                         CodeVariableDeclarationStatement stmt2 = 
552                                 VarDecl (
553                                         typeof (CollectionChangeEventHandler), 
554                                         "handler", 
555                                         New (typeof (CollectionChangeEventHandler), FieldRef ("SchemaChanged")));
556                         ctor.Statements.Add (stmt2);
557
558                         // Code: Tables.CollectionChanged += handler;
559                         ctor.Statements.Add (
560                                 new CodeAttachEventStatement (
561                                         EventRef (
562                                                 PropRef ("Tables"), 
563                                                 "CollectionChanged"),
564                                         Local ("handler")));
565
566                         // Code: Relations.CollectionChanged += handler;
567                         ctor.Statements.Add (
568                                 new CodeAttachEventStatement (
569                                         EventRef (
570                                                 PropRef ("Relations"), 
571                                                 "CollectionChanged"), 
572                                         Local ("handler")));
573
574                         return ctor;
575                 }
576
577                 // TODO: implement
578
579                 // Code:
580                 // protected Foo (SerializationInfo info, StreamingContext ctx)
581                 // {
582                 //   throw new NotImplementedException ();
583                 // }
584                 private CodeConstructor CreateDataSetSerializationCtor ()
585                 {
586                         CodeConstructor ctor = new CodeConstructor ();
587                         ctor.Attributes = MemberAttributes.Family;
588                         ctor.Parameters.Add (Param (typeof (SerializationInfo), "info"));
589                         ctor.Parameters.Add (Param (typeof (StreamingContext), "ctx"));
590
591                         // Code: 
592                         //  // TODO: implement
593                         //  throw new NotImplementedException ();
594                         ctor.Statements.Add (Comment ("TODO: implement"));
595                         ctor.Statements.Add (Throw (New (typeof (NotImplementedException))));
596
597                         return ctor;
598                 }
599
600                 // Code:
601                 //  public override DataSet Clone()
602                 //  {
603                 //    [foo] set = ([foo]) base.Clone ();
604                 //    set.InitializeFields ();
605                 //    return set;
606                 //  }
607                 private CodeMemberMethod CreateDataSetCloneMethod (CodeTypeDeclaration dsType)
608                 {
609                         CodeMemberMethod m = new CodeMemberMethod ();
610                         m.ReturnType = TypeRef (typeof (DataSet));
611                         m.Attributes = MemberAttributes.Public | MemberAttributes.Override;
612                         m.Name = "Clone";
613                         // Code: [foo] set = ([foo]) base.Clone ();
614                         CodeVariableReferenceExpression set = Local ("set");
615                         m.Statements.Add (VarDecl (
616                                         dsType.Name,
617                                         "set", 
618                                         Cast (
619                                                 dsType.Name,
620                                                 MethodInvoke (Base (), "Clone"))));
621                         m.Statements.Add (Eval (MethodInvoke (set, "InitializeFields")));
622                         m.Statements.Add (Return (set));
623                         return m;
624                 }
625
626                 // Code:
627                 // protected override bool ShouldSerializeTables ()
628                 // {
629                 //   return true; // it should be false
630                 // }
631                 private CodeMemberMethod CreateDataSetShouldSerializeTables ()
632                 {
633                         CodeMemberMethod m = new CodeMemberMethod ();
634                         m.Name = "ShouldSerializeTables";
635                         m.ReturnType = TypeRef (typeof (bool));
636                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
637                         // FIXME: set "false" after serialization .ctor() implementation
638                         m.Statements.Add (Return (Const (true)));
639                         return m;
640                 }
641
642                 // Code:
643                 // protected override bool ShouldSerializeRelations ()
644                 // {
645                 //   return true; // it should be false
646                 // }
647                 private CodeMemberMethod CreateDataSetShouldSerializeRelations ()
648                 {
649                         CodeMemberMethod m = new CodeMemberMethod ();
650                         m.Name = "ShouldSerializeRelations";
651                         m.ReturnType = TypeRef (typeof (bool));
652                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
653                         // FIXME: set "false" after serialization .ctor() implementation
654                         m.Statements.Add (Return (Const (true)));
655                         return m;
656                 }
657
658                 // Code:
659                 // protected override void ReadXmlSerializable()
660                 // {
661                 //   // TODO: implement
662                 //   throw new NotImplementedException ();
663                 // }
664                 private CodeMemberMethod CreateDataSetReadXmlSerializable ()
665                 {
666                         CodeMemberMethod method = new CodeMemberMethod ();
667                         method.Name = "ReadXmlSerializable";
668                         method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
669                         method.Parameters.Add (Param (TypeRef (typeof (XmlReader)), "reader"));
670                         // TODO: implemnet
671                         method.Statements.Add (Comment ("TODO: implement"));
672                         // Hey, how can I specify the constructor to invoke chained ctor with an empty parameter list!?
673                         method.Statements.Add (Throw (New (typeof (NotImplementedException))));
674                         return method;
675                 }
676
677                 private CodeMemberMethod CreateDataSetGetSchema ()
678                 {
679                         CodeMemberMethod m = new CodeMemberMethod ();
680                         m.PrivateImplementationType = TypeRef (typeof (IXmlSerializable));
681                         m.Name = "GetSchema";
682                         m.ReturnType = TypeRef (typeof (XmlSchema));
683                         m.Statements.Add (Return (MethodInvoke ("GetSchemaSerializable")));
684
685                         return m;
686                 }
687
688                 private CodeMemberMethod CreateDataSetGetSchemaSerializable ()
689                 {
690                         CodeMemberMethod m = new CodeMemberMethod ();
691                         m.Attributes = MemberAttributes.Family | 
692                                 MemberAttributes.Override;
693                         m.Name = "GetSchemaSerializable";
694                         m.ReturnType = TypeRef (typeof (XmlSchema));
695
696                         m.Statements.Add (VarDecl (typeof (StringWriter), "sw",
697                                 New (typeof (StringWriter))));
698                         m.Statements.Add (Eval (MethodInvoke ("WriteXmlSchema", Local ("sw"))));
699                         m.Statements.Add (Return (MethodInvoke (
700                                 TypeRefExp (typeof (XmlSchema)),
701                                 "Read",
702                                 New (typeof (XmlTextReader),
703                                         New (typeof (StringReader),
704                                                 MethodInvoke (Local ("sw"),
705                                                         "ToString"))),
706                                 Const (null))));
707
708                         return m;
709                 }
710
711                 private CodeMemberMethod CreateDataSetInitializeClass ()
712                 {
713                         CodeMemberMethod m = new CodeMemberMethod ();
714                         m.Name = "InitializeClass";
715                         m.Attributes = MemberAttributes.Assembly;
716
717                         // dataset properties
718                         m.Statements.Add (Let (PropRef ("DataSetName"), Const (ds.DataSetName)));
719                         m.Statements.Add (Let (PropRef ("Prefix"), Const (ds.Prefix)));
720                         m.Statements.Add (Let (PropRef ("Namespace"), Const (ds.Namespace)));
721                         m.Statements.Add (Let (PropRef ("Locale"), New (typeof (CultureInfo), Const (ds.Locale.Name))));
722                         m.Statements.Add (Let (PropRef ("CaseSensitive"), Const (ds.CaseSensitive)));
723                         m.Statements.Add (Let (PropRef ("EnforceConstraints"), Const (ds.EnforceConstraints)));
724
725                         // table
726                         foreach (DataTable dt in ds.Tables) {
727                                 string tableFieldName = "__table" + opts.TableMemberName (dt.TableName, gen);
728                                 string tableTypeName = opts.TableTypeName (dt.TableName, gen);
729                                 m.Statements.Add (Let (FieldRef (tableFieldName), New (tableTypeName)));
730                                 m.Statements.Add (Eval (MethodInvoke (PropRef ("Tables"), "Add", FieldRef (tableFieldName))));
731                         }
732
733                         bool fkcExists = false;
734                         bool ucExists = false;
735                         // First the UniqueConstraints
736                         foreach (DataTable dt in ds.Tables) {
737                                 string tname = "__table" + opts.TableMemberName (dt.TableName, gen);
738                                 foreach (Constraint c in dt.Constraints) {
739                                         UniqueConstraint uc = c as UniqueConstraint;
740                                         if (uc != null) {
741                                                 if (!ucExists) {
742                                                         m.Statements.Add (VarDecl (typeof (UniqueConstraint), "uc", null));
743                                                         ucExists = true;
744                                                 }
745                                                 CreateUniqueKeyStatements (m, uc, tname);
746                                         }
747                                 }
748                         }
749                         // Then the ForeignKeyConstraints
750                         foreach (DataTable dt in ds.Tables) {
751                                 string tname = "__table" + opts.TableMemberName (dt.TableName, gen);
752                                 foreach (Constraint c in dt.Constraints) {
753                                         ForeignKeyConstraint fkc = c as ForeignKeyConstraint;
754                                         if (fkc != null) {
755                                                 if (!fkcExists) {
756                                                         m.Statements.Add (VarDecl (typeof (ForeignKeyConstraint), "fkc", null));
757                                                         fkcExists = true;
758                                                 }
759                                                 string rtname = "__table" + opts.TableMemberName (fkc.RelatedTable.TableName, gen);
760                                                 CreateForeignKeyStatements (m, fkc, tname, rtname);
761                                         }
762                                 }
763                         }
764                         // What if other cases? dunno. Just ignore ;-)
765                         foreach (DataRelation rel in ds.Relations) {
766                                 string relName = opts.RelationName (rel.RelationName, gen);
767                                 ArrayList pcols = new ArrayList ();
768                                 foreach (DataColumn pcol in rel.ParentColumns)
769                                         pcols.Add (IndexerRef (PropRef (FieldRef ("__table" + opts.TableMemberName (rel.ParentTable.TableName, gen)), "Columns"), Const (pcol.ColumnName)));
770
771                                 ArrayList ccols = new ArrayList ();
772                                 foreach (DataColumn ccol in rel.ChildColumns)
773                                         ccols.Add (IndexerRef (PropRef (FieldRef ("__table" + opts.TableMemberName (rel.ChildTable.TableName, gen)), "Columns"), Const (ccol.ColumnName)));
774
775                                 // relation field
776                                 string fieldName = "__relation" + relName;
777                                 m.Statements.Add (Let (FieldRef (fieldName), New (typeof (DataRelation),
778                                         Const (rel.RelationName),
779                                         NewArray (typeof (DataColumn), pcols.ToArray (typeof (CodeExpression)) as CodeExpression []),
780                                         NewArray (typeof (DataColumn), ccols.ToArray (typeof (CodeExpression)) as CodeExpression []),
781                                         Const (false)
782                                         )));
783                                 m.Statements.Add (Let (PropRef (FieldRef (fieldName), "Nested"), Const (rel.Nested)));
784                                 m.Statements.Add (MethodInvoke (PropRef ("Relations"), "Add", FieldRef (fieldName)));
785                         }
786
787                         return m;
788                 }
789
790                 private void CreateUniqueKeyStatements (CodeMemberMethod m, UniqueConstraint uc, string tableField)
791                 {
792                         ArrayList al = new ArrayList ();
793                         foreach (DataColumn col in uc.Columns)
794                                 al.Add (IndexerRef (PropRef (FieldRef (tableField), "Columns"), Const (col.ColumnName)));
795
796                         m.Statements.Add (Let (Local ("uc"), New (
797                                 typeof (UniqueConstraint),
798                                 Const (uc.ConstraintName),
799                                 NewArray (
800                                         typeof (DataColumn),
801                                         al.ToArray (typeof (CodeExpression)) as CodeExpression []),
802                                 Const (uc.IsPrimaryKey))));
803                         m.Statements.Add (MethodInvoke (PropRef (FieldRef (tableField), "Constraints"), "Add", Local ("uc")));
804                 }
805
806                 private void CreateForeignKeyStatements (CodeMemberMethod m,ForeignKeyConstraint fkc, string tableField, string rtableField)
807                 {
808                         ArrayList pcols = new ArrayList ();
809                         foreach (DataColumn col in fkc.RelatedColumns)
810                                 pcols.Add (IndexerRef (PropRef (FieldRef (rtableField), "Columns"), Const (col.ColumnName)));
811
812                         ArrayList ccols = new ArrayList ();
813                         foreach (DataColumn col in fkc.Columns)
814                                 ccols.Add (IndexerRef (PropRef (FieldRef (tableField), "Columns"), Const (col.ColumnName)));
815
816                         m.Statements.Add (Let (Local ("fkc"), New (
817                                 typeof (ForeignKeyConstraint),
818                                 Const (fkc.ConstraintName),
819                                 NewArray (
820                                         typeof (DataColumn),
821                                         pcols.ToArray (typeof (CodeExpression)) as CodeExpression []),
822                                 NewArray (
823                                         typeof (DataColumn),
824                                         ccols.ToArray (typeof (CodeExpression)) as CodeExpression []))));
825
826                         m.Statements.Add (Let (
827                                 PropRef (Local ("fkc"), "AcceptRejectRule"),
828                                 FieldRef (TypeRefExp (typeof (AcceptRejectRule)), Enum.GetName (typeof (AcceptRejectRule), fkc.AcceptRejectRule))));
829                         m.Statements.Add (Let (
830                                 PropRef (Local ("fkc"), "DeleteRule"),
831                                 FieldRef (TypeRefExp (typeof (Rule)), Enum.GetName (typeof (Rule), fkc.DeleteRule))));
832                         m.Statements.Add (Let (
833                                 PropRef (Local ("fkc"), "UpdateRule"),
834                                 FieldRef (TypeRefExp (typeof (Rule)), Enum.GetName (typeof (Rule), fkc.UpdateRule))));
835
836                         m.Statements.Add (MethodInvoke (PropRef (FieldRef (tableField), "Constraints"), "Add", Local ("fkc")));
837                 }
838
839                 private CodeMemberMethod CreateDataSetInitializeFields ()
840                 {
841                         CodeMemberMethod m = new CodeMemberMethod ();
842                         m.Attributes = MemberAttributes.Assembly;
843                         m.Name = "InitializeFields";
844
845                         foreach (DataTable dt in ds.Tables)
846                                 m.Statements.Add (Eval (MethodInvoke (FieldRef ("__table" + opts.TableMemberName (dt.TableName, gen)), "InitializeFields")));
847
848                         foreach (DataRelation rel in ds.Relations)
849                                 m.Statements.Add (Let (FieldRef ("__relation" + opts.RelationName (rel.RelationName, gen)), IndexerRef (PropRef ("Relations"), Const (rel.RelationName))));
850
851                         return m;
852                 }
853
854                 private CodeMemberMethod CreateDataSetSchemaChanged ()
855                 {
856                         CodeMemberMethod m = new CodeMemberMethod ();
857                         m.Name = "SchemaChanged";
858                         m.Parameters.Add (Param (typeof (object), "sender"));
859                         m.Parameters.Add (Param (typeof (CollectionChangeEventArgs), "e"));
860
861                         m.Statements.Add (
862                                 new CodeConditionStatement (
863                                         Equals (
864                                                 PropRef (ParamRef ("e"), "Action"),
865                                                 FieldRef (TypeRefExp (typeof (CollectionChangeAction)), "Remove")),
866                                         new CodeStatement [] { Eval (MethodInvoke ("InitializeFields")) },
867                                         new CodeStatement [] {}));
868                         return m;
869                 }
870
871                 private void CreateDataSetTableMembers (CodeTypeDeclaration dsType, DataTable table)
872                 {
873                         string tableTypeName = opts.TableTypeName (table.TableName, gen);
874                         string tableVarName = opts.TableMemberName (table.TableName, gen);
875
876                         CodeMemberField privTable = new CodeMemberField ();
877                         privTable.Type = TypeRef (tableTypeName);
878                         privTable.Name = "__table" + tableVarName;
879                         dsType.Members.Add (privTable);
880
881                         CodeMemberProperty pubTable = new CodeMemberProperty ();
882                         pubTable.Type = TypeRef (tableTypeName);
883                         pubTable.Attributes = MemberAttributes.Public;
884                         pubTable.Name = tableVarName;
885                         pubTable.HasSet = false;
886                         // Code: return __table[foo];
887                         pubTable.GetStatements.Add (Return (FieldRef ("__table" + tableVarName)));
888
889                         dsType.Members.Add (pubTable);
890
891                 }
892
893                 private void CreateDataSetRelationMembers (CodeTypeDeclaration dsType, DataRelation relation)
894                 {
895                         string relName = opts.RelationName (relation.RelationName, gen);
896                         string fieldName = "__relation" + relName;
897
898                         CodeMemberField field = new CodeMemberField ();
899                         field.Type = TypeRef (typeof (DataRelation));
900                         field.Name = fieldName;
901                         dsType.Members.Add (field);
902
903                         // This is not supported in MS.NET
904                         CodeMemberProperty prop = new CodeMemberProperty ();
905                         prop.Type = TypeRef (typeof (DataRelation));
906                         prop.Attributes = MemberAttributes.Public;
907                         prop.Name = relName;
908                         prop.HasSet = false;
909                         // Code: return __relation[foo_bar];
910                         prop.GetStatements.Add (Return (FieldRef (fieldName)));
911                         dsType.Members.Add (prop);
912                 }
913
914 #endregion
915
916
917
918 #region DataTable class
919
920                 private CodeTypeDeclaration GenerateDataTableType (DataTable dt)
921                 {
922                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
923                         t.Name = opts.TableTypeName (dt.TableName, gen);
924                         t.BaseTypes.Add (TypeRef (typeof (DataTable)));
925                         t.BaseTypes.Add (TypeRef (typeof (IEnumerable)));
926
927                         t.Members.Add (CreateTableCtor1 (dt));
928                         t.Members.Add (CreateTableCtor2 (dt));
929
930                         t.Members.Add (CreateTableCount (dt));
931                         t.Members.Add (CreateTableIndexer (dt));
932
933                         t.Members.Add (CreateTableInitializeClass (dt));
934                         t.Members.Add (CreateTableInitializeFields (dt));
935
936                         t.Members.Add (CreateTableGetEnumerator (dt));
937                         t.Members.Add (CreateTableClone (dt));
938                         t.Members.Add (CreateTableCreateInstance (dt));
939
940                         t.Members.Add (CreateTableAddRow1 (dt));
941                         t.Members.Add (CreateTableAddRow2 (dt));
942                         t.Members.Add (CreateTableNewRow (dt));
943                         t.Members.Add (CreateTableNewRowFromBuilder (dt));
944                         t.Members.Add (CreateTableRemoveRow (dt));
945                         t.Members.Add (CreateTableGetRowType (dt));
946
947                         t.Members.Add (CreateTableEventStarter (dt, "Changing"));
948                         t.Members.Add (CreateTableEventStarter (dt, "Changed"));
949                         t.Members.Add (CreateTableEventStarter (dt, "Deleting"));
950                         t.Members.Add (CreateTableEventStarter (dt, "Deleted"));
951
952                         // events
953                         t.Members.Add (CreateTableEvent (dt, "RowChanging"));
954                         t.Members.Add (CreateTableEvent (dt, "RowChanged"));
955                         t.Members.Add (CreateTableEvent (dt, "RowDeleting"));
956                         t.Members.Add (CreateTableEvent (dt, "RowDeleted"));
957
958                         // column members
959                         foreach (DataColumn col in dt.Columns) {
960                                 t.Members.Add (CreateTableColumnField (dt, col));
961                                 t.Members.Add (CreateTableColumnProperty (dt, col));
962                         }
963
964                         return t;
965                 }
966
967                 // Code:
968                 //  internal [foo]DataTable () : base ("[foo]")
969                 //  {
970                 //    InitializeClass ();
971                 //  }
972                 private CodeConstructor CreateTableCtor1 (DataTable dt)
973                 {
974                         CodeConstructor c = new CodeConstructor ();
975                         c.Attributes = MemberAttributes.Assembly;
976                         c.BaseConstructorArgs.Add (Const (dt.TableName));
977                         c.Statements.Add (Eval (MethodInvoke ("InitializeClass")));
978                         c.Statements.Add (Eval (MethodInvoke ("InitializeFields")));
979                         return c;
980                 }
981
982                 // Code:
983                 //  internal [foo]DataTable (DataTable table) : base (table.TableName)
984                 //  {
985                 //    // TODO: implement
986                 //    throw new NotImplementedException ();
987                 //  }
988                 private CodeConstructor CreateTableCtor2 (DataTable dt)
989                 {
990                         CodeConstructor c = new CodeConstructor ();
991                         c.Attributes = MemberAttributes.Assembly;
992                         c.Parameters.Add (Param (typeof (DataTable), "table"));
993                         c.BaseConstructorArgs.Add (PropRef (ParamRef ("table"), "TableName"));
994                         // TODO: implement
995                         c.Statements.Add (Comment ("TODO: implement"));
996                         c.Statements.Add (Throw (New (typeof (NotImplementedException))));
997                         return c;
998                 }
999
1000                 private CodeMemberMethod CreateTableInitializeClass (DataTable dt)
1001                 {
1002                         CodeMemberMethod m = new CodeMemberMethod ();
1003                         m.Name = "InitializeClass";
1004                         foreach (DataColumn col in dt.Columns) {
1005                                 m.Statements.Add (Eval (MethodInvoke (
1006                                         PropRef ("Columns"),
1007                                         "Add",
1008                                         New (typeof (DataColumn),
1009                                                 Const (col.ColumnName),
1010                                                 new CodeTypeOfExpression (col.DataType)
1011                                                 ))));
1012                         }
1013                         return m;
1014                 }
1015
1016                 private CodeMemberMethod CreateTableInitializeFields (DataTable dt)
1017                 {
1018                         CodeMemberMethod m = new CodeMemberMethod ();
1019                         m.Name = "InitializeFields";
1020                         m.Attributes = MemberAttributes.Assembly;
1021
1022                         string colRef;
1023                         foreach (DataColumn col in dt.Columns) {
1024                                 colRef = String.Format("__column{0}", opts.TableColName (col.ColumnName, gen));
1025
1026                                 m.Statements.Add (Let (FieldRef (colRef), IndexerRef (PropRef ("Columns"), Const (col.ColumnName))));
1027                                 if (!col.AllowDBNull)
1028                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AllowDBNull"), Const (col.AllowDBNull)));
1029                                 if (col.DefaultValue != null && col.DefaultValue.GetType() != typeof(System.DBNull))
1030                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "DefaultValue"), Const (col.DefaultValue)));
1031                                 if (col.AutoIncrement)
1032                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrement"), Const (col.AutoIncrement)));
1033                                 if (col.AutoIncrementSeed != 0)
1034                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrementSeed"), Const (col.AutoIncrementSeed)));
1035                                 if (col.AutoIncrementStep != 1)
1036                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "AutoIncrementStep"), Const (col.AutoIncrementStep)));
1037                                 if (col.ReadOnly)
1038                                         m.Statements.Add (Let (FieldRef (PropRef (colRef), "ReadOnly"), Const (col.ReadOnly)));
1039                         }
1040                         return m;
1041                 }
1042
1043                 private CodeMemberMethod CreateTableClone (DataTable dt)
1044                 {
1045                         CodeMemberMethod m = new CodeMemberMethod ();
1046                         m.Name = "Clone";
1047                         m.Attributes = MemberAttributes.Public | MemberAttributes.Override;
1048                         m.ReturnType = TypeRef (typeof (DataTable));
1049                         string typeName = opts.TableTypeName (dt.TableName, gen);
1050                         m.Statements.Add (
1051                                 VarDecl (typeName, "t", Cast (typeName, MethodInvoke (Base (), "Clone"))));
1052                         m.Statements.Add (Eval (MethodInvoke (Local ("t"), "InitializeFields")));
1053                         m.Statements.Add (Return (Local ("t")));
1054                         return m;
1055                 }
1056
1057                 private CodeMemberMethod CreateTableGetEnumerator (DataTable dt)
1058                 {
1059                         CodeMemberMethod m = new CodeMemberMethod ();
1060                         m.Name = "GetEnumerator";
1061                         m.Attributes = MemberAttributes.Public;
1062                         m.ReturnType = TypeRef (typeof (IEnumerator));
1063                         m.Statements.Add (Return (MethodInvoke (PropRef ("Rows"), "GetEnumerator")));
1064                         return m;
1065                 }
1066
1067                 private CodeMemberMethod CreateTableCreateInstance (DataTable dt)
1068                 {
1069                         CodeMemberMethod m = new CodeMemberMethod ();
1070                         m.Name = "CreateInstance";
1071                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1072                         m.ReturnType = TypeRef (typeof (DataTable));
1073                         m.Statements.Add (Return (New (opts.TableTypeName (dt.TableName, gen))));
1074                         return m;
1075                 }
1076
1077                 private CodeMemberField CreateTableColumnField (DataTable dt, DataColumn col)
1078                 {
1079                         CodeMemberField f = new CodeMemberField ();
1080                         f.Name = "__column" + opts.ColumnName (col.ColumnName, gen);
1081                         f.Type = TypeRef (typeof (DataColumn));
1082                         return f;
1083                 }
1084
1085                 private CodeMemberProperty CreateTableColumnProperty (DataTable dt, DataColumn col)
1086                 {
1087                         string name = opts.ColumnName (col.ColumnName, gen);
1088                         CodeMemberProperty p = new CodeMemberProperty ();
1089                         p.Name = name + "Column";
1090                         p.Attributes = MemberAttributes.Assembly;
1091                         p.Type = TypeRef (typeof (DataColumn));
1092                         p.HasSet = false;
1093                         p.GetStatements.Add (Return (FieldRef ("__column" + name)));
1094                         return p;
1095                 }
1096
1097                 private CodeMemberProperty CreateTableCount (DataTable dt)
1098                 {
1099                         CodeMemberProperty p = new CodeMemberProperty ();
1100                         p.Name = "Count";
1101                         p.Attributes = MemberAttributes.Public;
1102                         p.Type = TypeRef (typeof (int));
1103                         p.HasSet = false;
1104                         p.GetStatements.Add (Return (PropRef (PropRef ("Rows"), "Count")));
1105                         return p;
1106                 }
1107
1108                 private CodeMemberProperty CreateTableIndexer (DataTable dt)
1109                 {
1110                         string rowName = opts.RowName (dt.TableName, gen);
1111                         CodeMemberProperty ix = new CodeMemberProperty ();
1112                         ix.Name = "Item"; // indexer
1113                         ix.Attributes = MemberAttributes.Public;
1114                         ix.Type = TypeRef (rowName);
1115                         ix.Parameters.Add (Param (typeof (int), "i"));
1116                         ix.HasSet = false;
1117                         ix.GetStatements.Add (Return (Cast (rowName, IndexerRef (PropRef ("Rows"), ParamRef ("i")))));
1118                         return ix;
1119                 }
1120
1121                 private CodeMemberMethod CreateTableAddRow1 (DataTable dt)
1122                 {
1123                         CodeMemberMethod m = new CodeMemberMethod ();
1124                         string rowType = opts.RowName (dt.TableName, gen);
1125                         m.Name = "Add" + rowType;
1126                         m.Attributes = MemberAttributes.Public;
1127                         m.Parameters.Add (Param (TypeRef (rowType), "row"));
1128                         m.Statements.Add (Eval (MethodInvoke (PropRef ("Rows"), "Add", ParamRef ("row"))));
1129                         return m;
1130                 }
1131
1132                 private CodeMemberMethod CreateTableAddRow2 (DataTable dt)
1133                 {
1134                         CodeMemberMethod m = new CodeMemberMethod ();
1135                         string rowType = opts.RowName (dt.TableName, gen);
1136                         m.Name = "Add" + rowType;
1137                         m.ReturnType = TypeRef (rowType);
1138                         m.Attributes = MemberAttributes.Public;
1139
1140                         m.Statements.Add (VarDecl (rowType, "row", MethodInvoke ("New" + rowType)));
1141
1142                         foreach (DataColumn col in dt.Columns) {
1143                                 if (col.ColumnMapping == MappingType.Hidden) {
1144                                         foreach (DataRelation r in dt.DataSet.Relations) {
1145                                                 if (r.ChildTable == dt) {
1146                                                         // parameter
1147                                                         string paramType = opts.RowName (r.ParentTable.TableName, gen);
1148                                                         string paramName = paramType;
1149                                                         m.Parameters.Add (Param (paramType, paramName));
1150                                                         // CODE: SetParentRow (fooRow, DataSet.Relations ["foo_bar"]);
1151                                                         m.Statements.Add (Eval (MethodInvoke (Local ("row"), "SetParentRow", ParamRef (paramName), IndexerRef (PropRef (PropRef ("DataSet"), "Relations"), Const (r.RelationName)))));
1152                                                         break;
1153                                                 }
1154                                         }
1155                                 }
1156                                 else {
1157                                         // parameter
1158                                         string paramName = opts.ColumnName (col.ColumnName, gen);
1159                                         m.Parameters.Add (Param (col.DataType, paramName));
1160                                         // row ["foo"] = foo;
1161                                         m.Statements.Add (Let (IndexerRef (Local ("row"), Const (paramName)), ParamRef (paramName)));
1162                                 }
1163                         }
1164
1165                         // Rows.Add (row);
1166                         m.Statements.Add (MethodInvoke (PropRef ("Rows"), "Add", Local ("row")));
1167                         m.Statements.Add (Return (Local ("row")));
1168
1169                         return m;
1170                 }
1171
1172                 private CodeMemberMethod CreateTableNewRow (DataTable dt)
1173                 {
1174                         CodeMemberMethod m = new CodeMemberMethod ();
1175                         string rowType = opts.RowName (dt.TableName, gen);
1176                         m.Name = "New" + rowType;
1177                         m.ReturnType = TypeRef (rowType);
1178                         m.Attributes = MemberAttributes.Public;
1179                         m.Statements.Add (Return (Cast (rowType, MethodInvoke ("NewRow"))));
1180                         return m;
1181                 }
1182
1183                 private CodeMemberMethod CreateTableNewRowFromBuilder (DataTable dt)
1184                 {
1185                         CodeMemberMethod m = new CodeMemberMethod ();
1186                         m.Name = "NewRowFromBuilder";
1187                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1188                         m.ReturnType = TypeRef (typeof (DataRow));
1189                         m.Parameters.Add (Param (typeof (DataRowBuilder), "builder"));
1190                         m.Statements.Add (Return (New (opts.RowName (dt.TableName, gen), ParamRef ("builder"))));
1191                         return m;
1192                 }
1193
1194                 private CodeMemberMethod CreateTableRemoveRow (DataTable dt)
1195                 {
1196                         CodeMemberMethod m = new CodeMemberMethod ();
1197                         string rowType = opts.RowName (dt.TableName, gen);
1198                         m.Name = "Remove" + rowType;
1199                         m.Attributes = MemberAttributes.Public;
1200                         m.Parameters.Add (Param (TypeRef (rowType), "row"));
1201                         m.Statements.Add (Eval (MethodInvoke (PropRef ("Rows"), "Remove", ParamRef ("row"))));
1202                         return m;
1203                 }
1204
1205                 private CodeMemberMethod CreateTableGetRowType (DataTable dt)
1206                 {
1207                         CodeMemberMethod m = new CodeMemberMethod ();
1208                         m.Name = "GetRowType";
1209                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1210                         m.ReturnType = TypeRef (typeof (Type));
1211                         m.Statements.Add (Return (new CodeTypeOfExpression (opts.RowName (dt.TableName, gen))));
1212                         return m;
1213                 }
1214
1215                 private CodeMemberMethod CreateTableEventStarter (DataTable dt, string type)
1216                 {
1217                         CodeMemberMethod m = new CodeMemberMethod ();
1218                         m.Name = "OnRow" + type;
1219                         m.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1220                         m.Parameters.Add (Param (typeof (DataRowChangeEventArgs), "e"));
1221
1222                         m.Statements.Add (Eval (MethodInvoke (
1223                                         Base (),
1224                                         m.Name,
1225                                         ParamRef ("e"))));
1226                         string eventName = opts.TableMemberName (dt.TableName, gen) + "Row" + type;
1227                         CodeStatement trueStmt = Eval (
1228                                 MethodInvoke (
1229                                         eventName,
1230                                         This (),
1231                                         New (
1232                                                 opts.EventArgsName (dt.TableName, gen),
1233                                                 Cast (opts.RowName (dt.TableName, gen), PropRef (ParamRef ("e"), "Row")),
1234                                                 PropRef (ParamRef ("e"), "Action"))));
1235
1236                         m.Statements.Add (
1237                                 new CodeConditionStatement (
1238                                         Inequals (EventRef (eventName), Const (null)),
1239                                         new CodeStatement [] {trueStmt},
1240                                         new CodeStatement [] {}));
1241
1242                         return m;
1243                 }
1244
1245                 private CodeMemberEvent CreateTableEvent (DataTable dt, string nameSuffix)
1246                 {
1247                         CodeMemberEvent cme = new CodeMemberEvent ();
1248                         cme.Attributes = MemberAttributes.Public;
1249                         cme.Name = opts.TableMemberName (dt.TableName, gen) + nameSuffix;
1250                         cme.Type = TypeRef (opts.TableDelegateName (dt.TableName, gen));
1251                         return cme;
1252                 }
1253
1254 #endregion
1255
1256
1257
1258 #region Row class
1259
1260                 public CodeTypeDeclaration GenerateDataRowType (DataTable dt)
1261                 {
1262                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1263                         t.Name = opts.RowName (dt.TableName, gen);
1264                         t.BaseTypes.Add (TypeRef (typeof (DataRow)));
1265
1266                         t.Members.Add (CreateRowCtor (dt));
1267
1268                         t.Members.Add (CreateRowTableField (dt));
1269
1270                         foreach (DataColumn col in dt.Columns) {
1271                                 if (col.ColumnMapping != MappingType.Hidden) {
1272                                         t.Members.Add (CreateRowColumnProperty (dt, col));
1273                                         t.Members.Add (CreateRowColumnIsNull (dt, col));
1274                                         t.Members.Add (CreateRowColumnSetNull (dt, col));
1275                                 }
1276                         }
1277
1278                         foreach (DataRelation rel in dt.ParentRelations)
1279                                 t.Members.Add (CreateRowParentRowProperty (dt, rel));
1280                         foreach (DataRelation rel in dt.ChildRelations)
1281                                 t.Members.Add (CreateRowGetChildRows (dt, rel));
1282
1283                         return t;
1284                 }
1285
1286                 private CodeConstructor CreateRowCtor (DataTable dt)
1287                 {
1288                         CodeConstructor c = new CodeConstructor ();
1289                         c.Attributes = MemberAttributes.Assembly;
1290                         c.Parameters.Add (Param (typeof (DataRowBuilder), "builder"));
1291                         c.BaseConstructorArgs.Add (ParamRef ("builder"));
1292                         c.Statements.Add (Let (FieldRef ("table"), Cast (
1293                                 opts.TableTypeName (dt.TableName, gen),
1294                                 PropRef ("Table"))));
1295                         return c;
1296                 }
1297
1298                 private CodeMemberField CreateRowTableField (DataTable dt)
1299                 {
1300                         CodeMemberField f = new CodeMemberField ();
1301                         f.Name = "table";
1302                         f.Type = TypeRef (opts.TableTypeName (dt.TableName, gen));
1303                         return f;
1304                 }
1305
1306                 private CodeMemberProperty CreateRowColumnProperty (DataTable dt, DataColumn col)
1307                 {
1308                         CodeMemberProperty p = new CodeMemberProperty ();
1309                         p.Name = opts.ColumnName (col.ColumnName, gen);
1310                         p.Type = TypeRef (col.DataType);
1311                         p.Attributes = MemberAttributes.Public;
1312
1313                         // This part should be better than MS code output.
1314                         // Code:
1315                         //  object ret = this [col];
1316                         //  if (ret == DBNull.Value)
1317                         //    throw new StrongTypingException ()
1318                         //  else
1319                         //    return (type) ret;
1320                         p.GetStatements.Add (VarDecl (typeof (object), "ret",
1321                                 IndexerRef (PropRef 
1322                                         (PropRef ("table"), 
1323                                         opts.TableColName (col.ColumnName, gen) + "Column"))));
1324                         p.GetStatements.Add (new CodeConditionStatement (
1325                                 Equals (
1326                                         Local ("ret"),
1327                                         PropRef (TypeRefExp (typeof (DBNull)), "Value")),
1328                                 new CodeStatement [] {
1329                                         Throw (New (typeof (StrongTypingException), Const ("Cannot get strong typed value since it is DB null."), Const (null))) },
1330                                 new CodeStatement [] {
1331                                         Return (Cast (col.DataType, Local ("ret"))) }));
1332
1333                         p.SetStatements.Add (Let (IndexerRef (PropRef (PropRef ("table"), opts.TableColName (col.ColumnName, gen) + "Column")), new CodePropertySetValueReferenceExpression ()));
1334
1335                         return p;
1336                 }
1337
1338                 private CodeMemberMethod CreateRowColumnIsNull (DataTable dt, DataColumn col)
1339                 {
1340                         CodeMemberMethod m = new CodeMemberMethod ();
1341                         m.Name = "Is" + opts.ColumnName (col.ColumnName, gen) + "Null";
1342                         m.Attributes = MemberAttributes.Public;
1343                         m.ReturnType = TypeRef (typeof (bool));
1344                         m.Statements.Add (Return (MethodInvoke (
1345                                 "IsNull",
1346                                 // table[foo].[bar]Column
1347                                 PropRef (
1348                                         PropRef ("table"), 
1349                                         opts.TableColName (col.ColumnName, gen) + "Column"))));
1350                         return m;
1351                 }
1352
1353                 private CodeMemberMethod CreateRowColumnSetNull (DataTable dt, DataColumn col)
1354                 {
1355                         CodeMemberMethod m = new CodeMemberMethod ();
1356                         m.Name = "Set" + opts.ColumnName (col.ColumnName, gen) + "Null";
1357                         m.Attributes = MemberAttributes.Public;
1358                         m.Statements.Add (Let (IndexerRef (
1359                                 PropRef (
1360                                         PropRef ("table"), 
1361                                         opts.TableColName (col.ColumnName, gen) + "Column")),
1362                                 PropRef (TypeRefExp (typeof (DBNull)), "Value")));
1363
1364                         return m;
1365                 }
1366
1367                 private CodeMemberProperty CreateRowParentRowProperty (DataTable dt, DataRelation rel)
1368                 {
1369                         CodeMemberProperty p = new CodeMemberProperty ();
1370                         p.Name = opts.TableMemberName (rel.ParentTable.TableName, gen) + "Row" +
1371                                 (rel.ParentTable.TableName == rel.ChildTable.TableName ? "Parent" : String.Empty);
1372                         p.Attributes = MemberAttributes.Public;
1373                         p.Type = TypeRef (opts.RowName (rel.ParentTable.TableName, gen));
1374                         p.GetStatements.Add (Return (Cast (p.Type, MethodInvoke (
1375                                 "GetParentRow",
1376                                 IndexerRef (
1377                                         PropRef (
1378                                                 PropRef (
1379                                                         PropRef ("Table"),
1380                                                         "DataSet"),
1381                                                 "Relations"),
1382                                         Const (rel.RelationName))))));
1383                         p.SetStatements.Add (Eval (MethodInvoke (
1384                                 "SetParentRow",
1385                                 new CodePropertySetValueReferenceExpression (),
1386                                 IndexerRef (
1387                                         PropRef (
1388                                                 PropRef (
1389                                                         PropRef ("Table"),
1390                                                         "DataSet"),
1391                                                 "Relations"),
1392                                         Const (rel.RelationName)))));
1393
1394                         return p;
1395                 }
1396
1397                 private CodeMemberMethod CreateRowGetChildRows (DataTable dt, DataRelation rel)
1398                 {
1399                         CodeMemberMethod m = new CodeMemberMethod ();
1400                         m.Name = "Get" + opts.TableMemberName (rel.ChildTable.TableName, gen) + "Rows";
1401                         m.Attributes = MemberAttributes.Public;
1402                         m.ReturnType = new CodeTypeReference (opts.RowName (rel.ChildTable.TableName, gen), 1);
1403                         m.Statements.Add (Return (Cast (m.ReturnType, MethodInvoke (
1404                                 "GetChildRows",
1405                                 IndexerRef (
1406                                         PropRef (
1407                                                 PropRef (
1408                                                         PropRef ("Table"),
1409                                                         "DataSet"),
1410                                                 "Relations"),
1411                                         Const (rel.RelationName))))));
1412                         return m;
1413                 }
1414
1415 #endregion
1416
1417
1418 #region Event class
1419
1420                 // Code:
1421                 //  public class [foo]ChangeEventArgs : EventArgs
1422                 //  {
1423                 //    private [foo]Row row;
1424                 //    private DataRowAction action;
1425                 //    (.ctor())
1426                 //    (Row)
1427                 //    (Action)
1428                 //  }
1429                 private CodeTypeDeclaration GenerateEventType (DataTable dt)
1430                 {
1431                         CodeTypeDeclaration t = new CodeTypeDeclaration ();
1432                         t.Name = opts.EventArgsName (dt.TableName, gen);
1433                         t.BaseTypes.Add (TypeRef (typeof (EventArgs)));
1434                         t.Attributes = MemberAttributes.Public;
1435
1436                         t.Members.Add (
1437                                 new CodeMemberField (
1438                                         TypeRef (opts.RowName (dt.TableName, gen)),
1439                                         "row"));
1440                         t.Members.Add (
1441                                 new CodeMemberField (
1442                                         TypeRef (typeof (DataRowAction)), "action"));
1443                         t.Members.Add (CreateEventCtor (dt));
1444
1445                         t.Members.Add (CreateEventRow (dt));
1446
1447                         t.Members.Add (CreateEventAction (dt));
1448
1449                         return t;
1450                 }
1451
1452                 // Code:
1453                 //  public [foo]RowChangeEventArgs ([foo]Row r, DataRowAction a)
1454                 //  {
1455                 //    row = r;
1456                 //    action = a;
1457                 //  }
1458                 private CodeConstructor CreateEventCtor (DataTable dt)
1459                 {
1460                         CodeConstructor c = new CodeConstructor ();
1461                         c.Attributes = MemberAttributes.Public;
1462                         c.Parameters.Add (Param (TypeRef (opts.RowName (dt.TableName, gen)), "r"));
1463                         c.Parameters.Add (Param (TypeRef (typeof (DataRowAction)), "a"));
1464                         c.Statements.Add (Let (FieldRef ("row"), ParamRef ("r")));
1465                         c.Statements.Add (Let (FieldRef ("action"), ParamRef ("a")));
1466
1467                         return c;
1468                 }
1469
1470                 // Code:
1471                 //  public [foo]Row Row {
1472                 //   get { return row; }
1473                 // }
1474                 private CodeMemberProperty CreateEventRow (DataTable dt)
1475                 {
1476                         CodeMemberProperty p = new CodeMemberProperty ();
1477                         p.Name = "Row";
1478                         p.Attributes = MemberAttributes.Public | MemberAttributes.Final;
1479                         p.Type = TypeRef (opts.RowName (dt.TableName, gen));
1480                         p.HasSet = false;
1481                         p.GetStatements.Add (Return (FieldRef ("row")));
1482                         return p;
1483                 }
1484
1485                 // Code:
1486                 //  public DataRowAction Action {
1487                 //   get { return action; }
1488                 // }
1489                 private CodeMemberProperty CreateEventAction (DataTable dt)
1490                 {
1491                         CodeMemberProperty p = new CodeMemberProperty ();
1492                         p.Name = "Action";
1493                         p.Attributes = MemberAttributes.Public | MemberAttributes.Final;
1494                         p.Type = TypeRef (typeof (DataRowAction));
1495                         p.HasSet = false;
1496                         p.GetStatements.Add (Return (FieldRef ("action")));
1497                         return p;
1498                 }
1499
1500 #endregion
1501
1502         }
1503 }
1504
1505
1506 /* =========================================================
1507
1508
1509 MonoDataSetGenerator API notes
1510
1511
1512 ** generator API:
1513         CreateDataSetClasses (
1514                 DataSet ds,
1515                 CodeNamespace cns,
1516                 ICodeGenerator gen,
1517                 GeneratorOptions options)
1518
1519 ** classes:
1520
1521 *** Code naming method delegate
1522
1523         public delegate string CodeNamingMethod (string sourceName);
1524
1525         It is used in CodeGeneratorOptions (describled immediately below).
1526
1527
1528
1529 *** Generator Options
1530
1531         public bool MakeClassesInsideDataSet
1532                 indicates whether classes and delegates other than DataSet
1533                 itself are "contained" in the DataSet class or not.
1534
1535         public CodeNamingMethod CreateDataSetName;
1536         public CodeNamingMethod CreateTableTypeName;
1537         public CodeNamingMethod CreateTableMemberName;
1538         public CodeNamingMethod CreateColumnName;
1539         public CodeNamingMethod CreateRowName;
1540         public CodeNamingMethod CreateRelationName;
1541         public CodeNamingMethod CreateTableDelegateName;
1542         public CodeNamingMethod CreateEventArgsName;
1543                 Custom methods each of that returns type or member name.
1544
1545                 By default, they are set as to useTypedDataSetGenerator.
1546                 CreateIdName() with modifications listed as below:
1547
1548                 DataSetName: as is
1549                 TableTypeName: "DataTable" suffix
1550                 TableMemberName: as is
1551                 ColumnName: as is
1552                 RowName: "Row" suffix
1553                 RelationName: (TBD; maybe had better have another delegate type)
1554                 DelegateName: "RowChangedEventHandler" suffix
1555                 EventArgsName: "RowChangedEventArgs" suffix
1556
1557 ** Auto Generated classes
1558
1559 1. Custom DataSet class 
1560
1561         class name = dataset name, encoded by options.CreateDataSetName().
1562
1563 *** .ctor
1564
1565         public default .ctor()
1566                 "initialize" class.
1567                 set custom delegate on Tables.CollectionChanged
1568                 set custom delegate on Relations.CollectionChanged
1569
1570         runtime serialization .ctor()
1571                 TBD
1572
1573 *** public members
1574
1575         data tables: [foo]DataTable foo { return this.table[foo]; }
1576
1577         Clone()
1578                 init variables on new dataset.
1579
1580 *** protected members
1581
1582         ShouldSerializeTables()
1583                 returns false, while default DataSet returns true.
1584         ShouldSerializeRelations()
1585                 returns false, while default DataSet returns true.
1586
1587         ReadXmlSerializable() ... similar to runtime serialization
1588                 TBD
1589
1590         GetSchemaSerializable()
1591                 Write its schema to temporary MemoryStream
1592                 Read XML schema from the stream
1593
1594 *** internal members
1595
1596         "init variables"
1597                 set member fields (tables, relations)
1598                 call members' "init variables"
1599
1600         "init class"
1601                 set DataSetName, Prefix, Namespace, Locale, CaseSensitive, EnforceConstraints
1602                 for each table
1603                         allocate table[foo] 
1604                         Tables.Add() 
1605                         create FKC: new FKC([rel], new DataColumn [] {table[foo].[keyColumnName]Column}, new DataColumn [] {table[child].[childColName]Column}
1606                 fill Rule properties.
1607                 allocate relation[rel] and fill Nested, then Relations.Add()
1608
1609 *** private members
1610
1611         data tables: [foo]DataTable table[foo];
1612
1613         data relations: DataRelation relation[rel];
1614
1615         ShouldSerialize[foo]
1616
1617
1618
1619 2. Custom DataTable classes for each DataTable
1620
1621         This class is created under the dataset.
1622
1623 *** internal members
1624
1625         .ctor() : base("[foo]")
1626                 initialize class
1627
1628         .ctor(DataTable)
1629                 wtf?
1630
1631         DataColumn [bar]Column { return column[bar]; }
1632
1633         "init variables"()
1634                 fill each column fields
1635
1636 *** public members
1637
1638         int Count { rowcount }
1639
1640         this [int index] { row [i]; }
1641
1642         event [foo]RowChangedEventHandler [foo]RowChanged
1643         event [foo]RowChangedEventHandler [foo]RowChanging
1644         event [foo]RowChangedEventHandler [foo]RowDeleted
1645         event [foo]RowChangedEventHandler [foo]RowDeleting
1646
1647         void Add[foo]Row ([foo]Row row) { Rows.Add (row); }
1648
1649         [foo]Row Add[foo]Row ([columnType] [columnName])
1650                 create new [foo]row.
1651                 set members
1652                 Rows.Add ()
1653                 // where
1654                 //      non-relation-children are just created as column type
1655                 //      relation-children are typeof fooRow[]
1656
1657         GetEnumerator() { Rows.GetEnumerator (); }
1658
1659         override DataTable Clone()
1660                 "init variables"
1661
1662         [foo]Row New[foo]Row()
1663
1664         void Remove[foo]Row([foo]Row)
1665
1666         //for each ChildRelations
1667         [bar]Row [] Get[foo_bar]Rows ()
1668
1669 *** protected members
1670
1671         override DataTable CreateInstance() { return new }
1672
1673         override DataRow NewRowFromBuilder(DataRowBuilder)
1674
1675         override Type GetRowType()
1676
1677         override void OnRowChanged(DataRowChangedEventArgs)
1678                 base.()
1679                 check this event [foo]RowChanged.
1680
1681         override void OnRowChanging(DataRowChangedEventArgs)
1682         override void OnRowDeleted(DataRowChangedEventArgs)
1683         override void OnRowDeleting(DataRowChangedEventArgs)
1684         ... as well
1685
1686 *** private members
1687
1688         "initialize class"
1689                 for each columns {
1690                         column[bar] = new DataColumn (...);
1691                         Columns.Add()
1692                 }
1693
1694         DataColumn [bar]Column
1695
1696 3. Custom DataRow classses
1697
1698 *** public members
1699
1700         for simple members:
1701
1702                 [bar_type] [bar] {
1703                         get { try { } catch { throw StrongTypingException(); }
1704                         set { this [[foo]Table.[bar]Column] = value; }
1705
1706                 bool Is[bar]Null ()
1707                         IsNull ([foo]Table.[bar]Column);
1708
1709                 void Set[bar]Null ()
1710
1711         if the table is parent of some relations
1712
1713                 public [child]Row [] Get[child]Rows()
1714
1715 *** internal members
1716
1717         .ctor(DataRowBuilder) : base.()
1718                 table[foo] = Table;
1719
1720 *** private members
1721
1722         [foo]DataTable table[foo]
1723
1724
1725 4. Custom DataRowChangeEvent classes
1726
1727 *** private members
1728
1729         [foo]Row eventRow
1730         DataRowAction eventAction
1731
1732 *** public members
1733
1734         .ctor([foo]Row row, DataRowAction action)
1735
1736         [foo]Row Row
1737
1738         DataRowAction Action
1739
1740
1741
1742 5. public Table RowChangedEventHandler delegates
1743
1744         [foo]RowChangedEventHandler(object, [foo]RowChangedEvent e)
1745
1746
1747 ======================================================== */