static MemberDeclarationSyntax MethodDeclarationSyntax(SqModelMeta sqModelMeta, string name, bool?pkFilter) { var setter = SyntaxFactory.IdentifierName("s"); ExpressionSyntax chain = setter; foreach (var metaProperty in sqModelMeta.Properties.Where(p => pkFilter.HasValue? p.IsPrimaryKey == pkFilter.Value : !p.IsIdentity)) { var col = setter.MemberAccess(nameof(IDataMapSetter <object, object> .Target)) .MemberAccess(metaProperty.Column.First().ColumnName); ExpressionSyntax prop = setter.MemberAccess(nameof(IDataMapSetter <object, object> .Source)) .MemberAccess(metaProperty.Name); if (metaProperty.CastType != null) { prop = SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName(metaProperty.Type), prop); } chain = chain.MemberAccess("Set").Invoke(col, prop); } var methodDeclarationSyntax = SyntaxFactory .MethodDeclaration(SyntaxFactory.ParseTypeName(nameof(IRecordSetterNext)), name) .WithModifiers(Modifiers(SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword)) .AddParameterListParameters(FuncParameter("s", $"{nameof(IDataMapSetter<object, object>)}<{sqModelMeta.Properties.First().Column.First().TableRef.TableTypeName},{sqModelMeta.Name}>")) .WithBody(SyntaxFactory.Block(SyntaxFactory.ReturnStatement(chain))); return(methodDeclarationSyntax); }
public static IEnumerable <MemberDeclarationSyntax> GenerateGetColumns(SqModelMeta meta) { return(meta.Properties.First() .Column.Select(tableColumn => { var arrayItems = meta.Properties.Select(p => p.Column.First()) .Select(p => SyntaxFactory.IdentifierName("table").MemberAccess(p.ColumnName)); var arrayType = SyntaxFactory.ArrayType( SyntaxFactory.IdentifierName(nameof(TableColumn)), new SyntaxList <ArrayRankSpecifierSyntax>(new[] { SyntaxFactory.ArrayRankSpecifier(SyntaxFactory.Token(SyntaxKind.OpenBracketToken), new SeparatedSyntaxList <ExpressionSyntax>(), SyntaxFactory.Token(SyntaxKind.CloseBracketToken)) })); var array = SyntaxFactory.ArrayCreationExpression( arrayType, SyntaxFactory.InitializerExpression(SyntaxKind.ArrayInitializerExpression, new SeparatedSyntaxList <ExpressionSyntax>().AddRange(arrayItems)) ); return SyntaxFactory .MethodDeclaration(arrayType, MethodNameGetColumns) .WithModifiers(Modifiers(SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword)) .AddParameterListParameters(FuncParameter("table", tableColumn.TableRef.TableTypeName)) .WithBody(SyntaxFactory.Block(SyntaxFactory.ReturnStatement( array ))); })); }
public static IEnumerable <MemberDeclarationSyntax> GenerateStaticFactory(SqModelMeta meta) { return(meta.Properties.First() .Column.Select(tableColumn => SyntaxFactory .MethodDeclaration(SyntaxFactory.ParseTypeName(meta.Name), MethodNameRead) .WithModifiers(Modifiers(SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword)) .AddParameterListParameters(FuncParameter("record", nameof(ISqDataRecordReader))) .AddParameterListParameters(FuncParameter("table", tableColumn.TableRef.TableTypeName)) .WithBody(SyntaxFactory.Block(SyntaxFactory.ReturnStatement( SyntaxFactory.ObjectCreationExpression(SyntaxFactory.Token(SyntaxKind.NewKeyword), SyntaxFactory.ParseTypeName(meta.Name), ArgumentList(meta.Properties.Select(p => { ExpressionSyntax invocation = MemberAccess("table", p.Column.First().ColumnName) .MemberAccess("Read") .Invoke(SyntaxFactory.ParseName("record")); if (p.CastType != null) { invocation = SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName(p.CastType), invocation); } return new NamedArgument(p.Name.FirstToLower(), invocation); }) .ToArray()), null)))))); }
public static MemberDeclarationSyntax[] Constructors(SqModelMeta meta) { var constructor = SyntaxFactory.ConstructorDeclaration(meta.Name) .WithModifiers(Modifiers(SyntaxKind.PublicKeyword)) .AddParameterListParameters(meta.Properties.Select(p => FuncParameter(p.Name.FirstToLower(), p.FinalType)).ToArray()) .WithBody(SyntaxFactory.Block(GenerateConstructorAssignments(meta))); return(new MemberDeclarationSyntax[] { constructor }); }
public static CompilationUnitSyntax Generate(SqModelMeta meta, string defaultNamespace, string existingFilePath, out bool existing) { CompilationUnitSyntax result; ClassDeclarationSyntax?existingClass = null; existing = false; if (File.Exists(existingFilePath)) { existing = true; var tClass = CSharpSyntaxTree.ParseText(File.ReadAllText(existingFilePath)); existingClass = tClass.GetRoot() .DescendantNodes() .OfType <ClassDeclarationSyntax>() .FirstOrDefault(cd => cd.Identifier.ValueText == meta.Name); } if (existingClass != null) { result = existingClass.FindParentOrDefault <CompilationUnitSyntax>() ?? throw new SqExpressCodeGenException($"Could not find compilation unit in \"{existingFilePath}\""); result = result.ReplaceNode(existingClass, GenerateClass(meta, existingClass)); } else { var namespaces = new[] { nameof(System), nameof(SqExpress), $"{nameof(SqExpress)}.{nameof(SqExpress.QueryBuilders)}.{nameof(SqExpress.QueryBuilders.RecordSetter)}" } .Concat(meta.Properties.SelectMany(p => p.Column) .Select(c => c.TableRef.TableTypeNameSpace) .Where(n => n != defaultNamespace)) .Distinct() .ToList(); result = SyntaxFactory.CompilationUnit() .AddUsings(namespaces.Select(n => SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(n))).ToArray()) .AddMembers(SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName(defaultNamespace)) .AddMembers(GenerateClass(meta, null))); } return(result.NormalizeWhitespace()); }
public static MemberDeclarationSyntax[] GenerateMapping(SqModelMeta meta) { var pkCount = meta.Properties.Count(i => i.IsPrimaryKey); if (pkCount > 0 && pkCount < meta.Properties.Count) { return(new [] { MethodDeclarationSyntax(meta, MethodNameGetMapping, null), MethodDeclarationSyntax(meta, MethodNameGetUpdateKeyMapping, true), MethodDeclarationSyntax(meta, MethodNameGetUpdateMapping, false) }); } else { return(new [] { MethodDeclarationSyntax(meta, MethodNameGetMapping, null) }); }
public static IEnumerable <MemberDeclarationSyntax> Properties(SqModelMeta meta, IReadOnlyDictionary <string, SyntaxList <AttributeListSyntax> >?oldAttributes) { return(meta.Properties.Select(p => { var res = SyntaxFactory.PropertyDeclaration( SyntaxFactory.ParseTypeName(p.FinalType), p.Name) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) .AddAccessorListAccessors( SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) ); if (oldAttributes != null && oldAttributes.TryGetValue(p.Name, out var attributeList)) { res = res.WithAttributeLists(attributeList); } return res; })); }
public static MemberDeclarationSyntax[] GenerateMapping(SqModelMeta meta, SqModelTableRef tableRef) { if (!HasUpdater(tableRef)) { return(Array.Empty <MemberDeclarationSyntax>()); } if (meta.HasPk()) { return(new [] { MethodDeclarationSyntax(meta, tableRef, MethodNameGetMapping, null), MethodDeclarationSyntax(meta, tableRef, MethodNameGetUpdateKeyMapping, true), MethodDeclarationSyntax(meta, tableRef, MethodNameGetUpdateMapping, false) }); } else { return(new [] { MethodDeclarationSyntax(meta, tableRef, MethodNameGetMapping, null) }); }
private static ClassDeclarationSyntax GenerateClass(SqModelMeta meta, ClassDeclarationSyntax?existingClass) { ClassDeclarationSyntax result; MemberDeclarationSyntax[]? oldMembers = null; Dictionary <string, SyntaxList <AttributeListSyntax> >?oldAttributes = null; if (existingClass != null) { result = existingClass; oldMembers = result.DescendantNodes() .OfType <MemberDeclarationSyntax>() .Where(md => { if (md is ConstructorDeclarationSyntax) { return(false); } if (md is IncompleteMemberSyntax) { return(false); } if (md is PropertyDeclarationSyntax p) { if (meta.Properties.Any(mp => mp.Name == p.Identifier.ValueText)) { if (p.AttributeLists.Count > 0) { oldAttributes ??= new Dictionary <string, SyntaxList <AttributeListSyntax> >(); oldAttributes.Add(p.Identifier.ValueText, p.AttributeLists); } return(false); } } if (md is MethodDeclarationSyntax method) { var name = method.Identifier.ValueText; if (name.StartsWith("With") || AllMethods.Contains(name)) { return(false); } } return(true); }) .ToArray(); result = result.RemoveNodes(result.DescendantNodes().OfType <MemberDeclarationSyntax>(), SyntaxRemoveOptions.KeepNoTrivia) !; } else { result = SyntaxFactory.ClassDeclaration(meta.Name) .WithModifiers(Modifiers(SyntaxKind.PublicKeyword)); } result = result .AddMembers(Constructors(meta) .Concat(GenerateStaticFactory(meta)) .Concat(Properties(meta, oldAttributes)) .Concat(GenerateGetColumns(meta)) .Concat(GenerateMapping(meta)) .Concat(GenerateWithModifiers(meta)) .ToArray()); if (oldMembers != null && oldMembers.Length > 0) { result = result.AddMembers(oldMembers); } return(result); }
private static IEnumerable <Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax> GenerateConstructorAssignments(SqModelMeta meta) { return(meta.Properties.Select(p => SyntaxFactory.ExpressionStatement(AssignmentThis(p.Name, SyntaxFactory.IdentifierName(p.Name.FirstToLower()))))); }
public static CompilationUnitSyntax Generate(SqModelMeta meta, string defaultNamespace, string existingFilePath, bool rwClasses, ModelType modelType, IFileSystem fileSystem, out bool existing) { CompilationUnitSyntax result; TypeDeclarationSyntax?existingClass = null; existing = false; if (fileSystem.FileExists(existingFilePath)) { existing = true; var tClass = CSharpSyntaxTree.ParseText(fileSystem.ReadAllText(existingFilePath)); existingClass = tClass.GetRoot() .DescendantNodes() .OfType <TypeDeclarationSyntax>() .FirstOrDefault(cd => cd.Identifier.ValueText == meta.Name); } var namespaces = new[] { nameof(System), nameof(SqExpress), $"{nameof(SqExpress)}.{nameof(SqExpress.QueryBuilders)}.{nameof(SqExpress.QueryBuilders.RecordSetter)}" } .Concat(meta.Properties.SelectMany(p => p.Column) .Select(c => c.TableRef.TableTypeNameSpace) .Where(n => n != defaultNamespace)) .Distinct() .ToList(); if (rwClasses || ExtractTableRefs(meta).Any(tr => tr.BaseTypeKindTag == BaseTypeKindTag.DerivedTableBase)) { namespaces.Add($"{nameof(SqExpress)}.{nameof(SqExpress.Syntax)}.{nameof(SqExpress.Syntax.Names)}"); namespaces.Add($"{nameof(System)}.{nameof(System.Collections)}.{nameof(System.Collections.Generic)}"); } if (existingClass != null) { result = existingClass.FindParentOrDefault <CompilationUnitSyntax>() ?? throw new SqExpressCodeGenException($"Could not find compilation unit in \"{existingFilePath}\""); foreach (var usingDirectiveSyntax in result.Usings) { var existingUsing = usingDirectiveSyntax.Name.ToFullString(); var index = namespaces.IndexOf(existingUsing); if (index >= 0) { namespaces.RemoveAt(index); } } if (namespaces.Count > 0) { result = result.AddUsings(namespaces .Select(n => SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(n))) .ToArray()); } var oldClass = existingClass; if (oldClass is ClassDeclarationSyntax classDeclaration && modelType == ModelType.Record) { oldClass = SyntaxFactory.RecordDeclaration(classDeclaration.AttributeLists, classDeclaration.Modifiers, SyntaxFactory.Token(SyntaxKind.RecordKeyword), classDeclaration.Identifier, classDeclaration.TypeParameterList, null, classDeclaration.BaseList, classDeclaration.ConstraintClauses, SyntaxFactory.Token(SyntaxKind.OpenBraceToken), classDeclaration.Members, SyntaxFactory.Token(SyntaxKind.CloseBraceToken), SyntaxFactory.Token(SyntaxKind.None)); } result = result.ReplaceNode(existingClass, GenerateClass(meta, rwClasses, modelType, oldClass)); } else { result = SyntaxFactory.CompilationUnit() .AddUsings(namespaces.Select(n => SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(n))).ToArray()) .AddMembers(SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName(defaultNamespace)) .AddMembers(GenerateClass(meta, rwClasses, modelType, null))); } return(result.NormalizeWhitespace()); }
public static IEnumerable <MemberDeclarationSyntax> GenerateMapping(SqModelMeta meta) { return(ExtractTableRefs(meta).SelectMany(tr => GenerateMapping(meta, tr))); }
public static IEnumerable <MemberDeclarationSyntax> GenerateOrdinalStaticFactory(SqModelMeta meta) { return(ExtractTableRefs(meta).Select(tableRef => SyntaxFactory .MethodDeclaration(SyntaxFactory.ParseTypeName(meta.Name), MethodNameReadOrdinal) .WithModifiers(Modifiers(SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword)) .AddParameterListParameters(FuncParameter("record", nameof(ISqDataRecordReader))) .AddParameterListParameters(FuncParameter("table", ExtractTableTypeName(meta, tableRef))) .AddParameterListParameters(FuncParameter("offset", "int")) .WithBody(SyntaxFactory.Block(SyntaxFactory.ReturnStatement( SyntaxFactory.ObjectCreationExpression(SyntaxFactory.Token(SyntaxKind.NewKeyword), SyntaxFactory.ParseTypeName(meta.Name), ArgumentList(meta.Properties.Select((p, index) => { ExpressionSyntax invocation = MemberAccess("table", p.Column.First().ColumnName) .MemberAccess("Read") .Invoke( SyntaxFactory.ParseName("record"), index == 0 ? SyntaxFactory.IdentifierName("offset") : SyntaxFactory.BinaryExpression(SyntaxKind.AddExpression, SyntaxFactory.IdentifierName("offset"), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(index)))); if (p.CastType != null) { invocation = SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName(p.CastType), invocation); } return new NamedArgument(p.Name.FirstToLower(), invocation); }) .ToArray()), null)))))); }
private static TypeDeclarationSyntax GenerateClass(SqModelMeta meta, bool rwClasses, ModelType modelType, TypeDeclarationSyntax?existingClass) { TypeDeclarationSyntax result; MemberDeclarationSyntax[]? oldMembers = null; Dictionary <string, SyntaxList <AttributeListSyntax> >?oldAttributes = null; if (existingClass != null) { result = existingClass; oldMembers = result.Members .Where(md => { if (md is ConstructorDeclarationSyntax) { return(false); } if (md is IncompleteMemberSyntax) { return(false); } if (md is PropertyDeclarationSyntax p) { if (meta.Properties.Any(mp => mp.Name == p.Identifier.ValueText)) { if (p.AttributeLists.Count > 0) { oldAttributes ??= new Dictionary <string, SyntaxList <AttributeListSyntax> >(); oldAttributes.Add(p.Identifier.ValueText, p.AttributeLists); } return(false); } } if (md is MethodDeclarationSyntax method) { var name = method.Identifier.ValueText; if (name.StartsWith("With") || AllMethods.Contains(name) || name.StartsWith(MethodNameGetReader + "For") || name.StartsWith(MethodNameGetUpdater + "For")) { return(false); } } if (md is ClassDeclarationSyntax classDeclaration) { var name = classDeclaration.Identifier.ValueText; if (name == meta.Name + ReaderClassSuffix || name.StartsWith(meta.Name + ReaderClassSuffix + "For")) { return(false); } if (name == meta.Name + UpdaterClassSuffix || name.StartsWith(meta.Name + UpdaterClassSuffix + "For")) { return(false); } } return(true); }) .ToArray(); result = result.RemoveNodes(result.DescendantNodes().OfType <MemberDeclarationSyntax>(), SyntaxRemoveOptions.KeepNoTrivia) !; } else { result = (modelType == ModelType.Record ? (TypeDeclarationSyntax)SyntaxFactory .RecordDeclaration(SyntaxFactory.Token(SyntaxKind.RecordKeyword), meta.Name) .WithOpenBraceToken(SyntaxFactory.Token(SyntaxKind.OpenBraceToken)) .WithCloseBraceToken(SyntaxFactory.Token(SyntaxKind.CloseBraceToken)) : SyntaxFactory.ClassDeclaration(meta.Name)) .WithModifiers(existingClass?.Modifiers ?? Modifiers(SyntaxKind.PublicKeyword)); } result = result .AddMembers(Constructors(meta) .Concat(GenerateStaticFactory(meta)) .Concat(rwClasses ? GenerateOrdinalStaticFactory(meta) : Array.Empty <MemberDeclarationSyntax>()) .Concat(Properties(meta, oldAttributes)) .Concat(modelType == ModelType.ImmutableClass ? GenerateWithModifiers(meta) : Array.Empty <MemberDeclarationSyntax>()) .Concat(GenerateGetColumns(meta)) .Concat(GenerateMapping(meta)) .Concat(rwClasses ? GenerateReaderClass(meta): Array.Empty <MemberDeclarationSyntax>()) .Concat(rwClasses ? GenerateWriterClass(meta) : Array.Empty <MemberDeclarationSyntax>()) .ToArray()); if (oldMembers != null && oldMembers.Length > 0) { result = result.AddMembers(oldMembers); } return(result); }