static void Initialize(OutputModel outputModel, ClassModel?classModel, OutputPlan outputPlan, DbAttributeModel dbAttribute) { var name = dbAttribute.Name ?? ""; var symbol = classModel?.ClassSymbol as ISymbol ?? outputModel.Compilation.Assembly; if (outputPlan.DatabasePlansByName.TryGetValue(name, out var plan)) { if (dbAttribute.Namespace.NullIfEmpty() is not null && dbAttribute.Namespace != plan.Namespace) { if (plan.IsDefaultNamespace) { plan.IsDefaultNamespace = false; plan.Namespace = dbAttribute.Namespace !; plan.ClassModel = classModel; } else { outputModel.Report(Diagnostics.Errors.DbMultipleNamespace, symbol); } } } else { plan = new DatabasePlan { Namespace = dbAttribute.Namespace.NullIfEmpty() !, Name = name, ClassModel = classModel, DbClassName = name.WithSuffix(Suffixes.Database), PartitionsClassName = name.WithSuffix(Suffixes.Partitions), QueryBuilderClassName = name.WithSuffix(Suffixes.QueryBuilder), QueryBuilderUnionsClassName = name.WithSuffix(Suffixes.QueryBuilderUnions), QueryClassName = name.WithSuffix(Suffixes.Query), QueryUnionsClassName = name.WithSuffix(Suffixes.QueryUnions), ReadClassName = name.WithSuffix(Suffixes.Read), SerializerClassName = name.WithSuffix(Suffixes.Serializer), ConverterClassName = name.WithSuffix(Suffixes.Converter), TypesClassName = name.WithSuffix(Suffixes.Types), BatchHandlersClassName = name.WithSuffix(Suffixes.BatchHandlers), ChangeFeedProcessorClassName = name.WithSuffix(Suffixes.ChangeFeedProcessor) }; plan.BatchHandlersArgumentName = plan.BatchHandlersClassName.ToArgumentName(); plan.IsDefaultNamespace = plan.Namespace is null; plan.Namespace ??= classModel?.ClassSymbol.ContainingNamespace?.ToDisplayString() ?? outputModel.Compilation.Assembly.Name.NullIfEmpty() ?? "Cosmogenesis.Generated"; plan.DbClassNameArgument = plan.DbClassName.ToArgumentName(); plan.QueryBuilderClassNameArgument = plan.QueryBuilderClassName.ToArgumentName(); outputModel.ValidateNames( symbol, plan.Name, plan.DbClassName, plan.PartitionsClassName, plan.QueryBuilderClassName, plan.QueryClassName, plan.ReadClassName, plan.SerializerClassName, plan.ConverterClassName, plan.TypesClassName, plan.BatchHandlersClassName, plan.ChangeFeedProcessorClassName, plan.QueryBuilderUnionsClassName, plan.QueryUnionsClassName); outputModel.ValidateIdentifiers( symbol, plan.BatchHandlersArgumentName, plan.DbClassNameArgument, plan.QueryBuilderClassNameArgument); plan.Namespace.ValidateNamespace(outputModel, symbol); outputPlan.DatabasePlansByName[name] = plan; } if (classModel is not null) { outputPlan.DatabasePlansByClass[classModel].Add(plan); } } }
static void AddPartitionDefinition(OutputModel outputModel, DatabasePlan databasePlan, MethodModel methodModel, string name) { if (databasePlan.PartitionPlansByName.TryGetValue(name, out var partitionPlan)) { if (!SymbolEqualityComparer.Default.Equals(partitionPlan.GetPkModel.MethodSymbol, methodModel.MethodSymbol)) { outputModel.Report(Diagnostics.Errors.PartitionAlreadyDefined, methodModel.MethodSymbol); } } else { partitionPlan = new PartitionPlan { Name = name, PluralName = name.Pluralize(), ClassName = name.WithSuffix(Suffixes.Partition), BatchHandlersClassName = name.WithSuffix(Suffixes.BatchHandlers), CreateOrReplaceClassName = name.WithSuffix(Suffixes.CreateOrReplace), ReadClassName = name.WithSuffix(Suffixes.Read), ReadOrThrowClassName = name.WithSuffix(Suffixes.ReadOrThrow), ReadManyClassName = name.WithSuffix(Suffixes.ReadMany), ReadUnionsClassName = name.WithSuffix(Suffixes.ReadUnions), ReadOrThrowUnionsClassName = name.WithSuffix(Suffixes.ReadOrThrowUnions), ReadManyUnionsClassName = name.WithSuffix(Suffixes.ReadManyUnions), QueryBuilderClassName = name.WithSuffix(Suffixes.QueryBuilder), QueryBuilderUnionsClassName = name.WithSuffix(Suffixes.QueryBuilderUnions), QueryClassName = name.WithSuffix(Suffixes.Query), QueryUnionsClassName = name.WithSuffix(Suffixes.QueryUnions), ReadOrCreateClassName = name.WithSuffix(Suffixes.ReadOrCreate), CreateClassName = name.WithSuffix(Suffixes.Create), BatchClassName = name.WithSuffix(Suffixes.Batch), GetPkModel = methodModel }; partitionPlan.BatchHandlersClassNameArgument = partitionPlan.BatchHandlersClassName.ToArgumentName(); partitionPlan.ClassNameArgument = partitionPlan.ClassName.ToArgumentName(); databasePlan.PartitionPlansByName[name] = partitionPlan; partitionPlan.QueryBuilderClassNameArgument = partitionPlan.QueryBuilderClassName.ToArgumentName(); outputModel.ValidateNames( methodModel.MethodSymbol, partitionPlan.Name, partitionPlan.PluralName, partitionPlan.ClassName, partitionPlan.BatchHandlersClassName, partitionPlan.CreateOrReplaceClassName, partitionPlan.ReadClassName, partitionPlan.ReadOrThrowClassName, partitionPlan.ReadManyClassName, partitionPlan.QueryBuilderClassName, partitionPlan.QueryClassName, partitionPlan.ReadOrCreateClassName, partitionPlan.CreateClassName, partitionPlan.BatchClassName, partitionPlan.QueryBuilderUnionsClassName, partitionPlan.QueryUnionsClassName, partitionPlan.ReadManyUnionsClassName, partitionPlan.ReadOrThrowUnionsClassName, partitionPlan.ReadUnionsClassName); outputModel.ValidateIdentifiers( methodModel.MethodSymbol, partitionPlan.ClassNameArgument, partitionPlan.BatchHandlersClassNameArgument, partitionPlan.QueryBuilderClassNameArgument); } }
public static void AddDocuments(OutputModel outputModel, OutputPlan outputPlan) { outputModel.CancellationToken.ThrowIfCancellationRequested(); if (!outputModel.CanGenerate) { return; } foreach (var kvp in outputPlan.DatabasePlansByClass) { var classModel = kvp.Key; var databasePlans = kvp.Value; if (classModel.IsDbDoc && !classModel.ClassSymbol.IsAbstract) { if (databasePlans.Count == 0) { outputModel.Report(Diagnostics.Errors.NoDatabase, classModel.ClassSymbol); } else if (classModel.PartitionAttribute is null) { outputModel.Report(Diagnostics.Warnings.DbDocWithoutPartition, classModel.ClassSymbol, classModel.ClassSymbol.Name); } else { if (!classModel.ClassSymbol.Constructors.Any(x => x.Parameters.IsDefaultOrEmpty && x.DeclaredAccessibility.IsAccessible())) { outputModel.Report(Diagnostics.Errors.ParameterlessConstructor, classModel.ClassSymbol); } var implicitGetIds = classModel.Methods .Where(x => x.MethodSymbol.Name == "GetId") .Where(x => x.MethodSymbol.IsStatic) .Where(x => x.MethodSymbol.ReturnType.SpecialType == SpecialType.System_String) .Where(x => x.MethodSymbol.DeclaredAccessibility.IsAccessible()) .ToList(); if (implicitGetIds.Count == 0) { outputModel.Report(Diagnostics.Errors.NoGetId, classModel.ClassSymbol); } else if (implicitGetIds.Count > 1) { outputModel.Report(Diagnostics.Errors.MultipleGetId, classModel.ClassSymbol); } else { var getId = implicitGetIds[0]; var partitionName = classModel.PartitionAttribute.Name; var name = classModel.ClassSymbol.Name.WithoutSuffix(Suffixes.Doc).WithoutSuffix(Suffixes.Document); var type = classModel.DocTypeAttribute?.Name.NullIfEmpty() ?? name; type.ValidateDocType(outputModel, classModel.ClassSymbol); foreach (var databasePlan in databasePlans) { if (!databasePlan.PartitionPlansByName.TryGetValue(partitionName, out var partitionPlan)) { outputModel.Report(Diagnostics.Errors.NoGetPk, classModel.ClassSymbol); } else { var documentPlan = new DocumentPlan { DocType = type, FullTypeName = classModel.ClassSymbol.ToDisplayString(), ClassModel = classModel, IsMutable = classModel.MutableAttribute is not null, IsTransient = classModel.TransientAttribute is not null, ClassName = name, ClassNameArgument = name.ToArgumentName(), PluralName = name.Pluralize(), ConstDocType = $"{databasePlan.Namespace}.{databasePlan.TypesClassName}.{partitionPlan.ClassName}.{name}", GetIdPlan = new GetPkIdPlan { FullMethodName = $"{getId.MethodSymbol.ContainingType.ToDisplayString()}.{getId.MethodSymbol.Name}", Arguments = getId .MethodSymbol .Parameters .Select(x => new GetPkIdPlan.Argument { ArgumentName = x.Name.ToArgumentName(), FullTypeName = x.Type.ToDisplayString() }) .ToList() } }; partitionPlan.Documents.Add(documentPlan); outputModel.ValidateNames( classModel.ClassSymbol, documentPlan.ClassName, documentPlan.PluralName); outputModel.ValidateIdentifiers( classModel.ClassSymbol, documentPlan.ClassNameArgument); PropertyPlanBuilder.AddProperties(outputModel, classModel, documentPlan); documentPlan.GetIdPlan = GetPkIdPlanBuilder.Build(outputModel, getId.MethodSymbol, documentPlan.PropertiesByName, documentPlan.PropertiesByArgumentName); if (partitionPlan.GetPkPlan is null) { partitionPlan.GetPkPlan = GetPkIdPlanBuilder.Build(outputModel, partitionPlan.GetPkModel.MethodSymbol, documentPlan.PropertiesByName, documentPlan.PropertiesByArgumentName); } else { foreach (var arg in partitionPlan.GetPkPlan.Arguments) { if (arg.PropertyName is not null && !documentPlan.PropertiesByName.ContainsKey(arg.PropertyName)) { outputModel.Report(Diagnostics.Errors.PropertyResolvePkIdConsistency, partitionPlan.GetPkModel.MethodSymbol, arg.ArgumentName, arg.PropertyName); } } } } } } } } } } }