Пример #1
0
    public static void Write(OutputModel outputModel, DatabasePlan databasePlan, PartitionPlan partitionPlan)
    {
        var s = $@"
namespace {databasePlan.Namespace};

public class {partitionPlan.QueryUnionsClassName} : Cosmogenesis.Core.DbQueryBase
{{
    protected virtual {databasePlan.Namespace}.{databasePlan.DbClassName} {databasePlan.DbClassName} {{ get; }} = default!;
    protected virtual {databasePlan.Namespace}.{partitionPlan.QueryBuilderClassName} {partitionPlan.QueryBuilderClassName} {{ get; }} = default!;

    /// <summary>Mocking constructor</summary>
    protected {partitionPlan.QueryUnionsClassName}() {{ }}

    internal protected {partitionPlan.QueryUnionsClassName}(
        {databasePlan.Namespace}.{databasePlan.DbClassName} {databasePlan.DbClassNameArgument},
        {databasePlan.Namespace}.{partitionPlan.QueryBuilderClassName} {partitionPlan.QueryBuilderClassNameArgument})
        : base(
            dbBase: {databasePlan.DbClassNameArgument},
            queryBuilder: {partitionPlan.QueryBuilderClassNameArgument})
    {{
        this.{databasePlan.DbClassName} = {databasePlan.DbClassNameArgument} ?? throw new System.ArgumentNullException(nameof({databasePlan.DbClassNameArgument}));
        this.{partitionPlan.QueryBuilderClassName} = {partitionPlan.QueryBuilderClassNameArgument} ?? throw new System.ArgumentNullException(nameof({partitionPlan.QueryBuilderClassNameArgument}));
    }}

{string.Concat(partitionPlan.Unions.Select(x => Query(databasePlan, partitionPlan, x)))}
}}
";

        outputModel.Context.AddSource($"partition_{partitionPlan.QueryUnionsClassName}.cs", s);
    }
Пример #2
0
    static string Unions(DatabasePlan databasePlan, PartitionPlan partitionPlan) =>
    partitionPlan.Unions.Count == 0 ? "" : $@"
    {databasePlan.Namespace}.{partitionPlan.ReadOrThrowUnionsClassName}? unions;
    public virtual {databasePlan.Namespace}.{partitionPlan.ReadOrThrowUnionsClassName} Unions => this.unions ??= new(
        {databasePlan.DbClassNameArgument}: this.{databasePlan.DbClassName},
        partitionKey: this.PartitionKey);
";
    public static void Write(OutputModel outputModel, DatabasePlan databasePlan, PartitionPlan partitionPlan)
    {
        if (!partitionPlan.Documents.Any(x => x.IsMutable || x.IsTransient))
        {
            return;
        }

        var s = $@"
namespace {databasePlan.Namespace};

public class {partitionPlan.CreateOrReplaceClassName}
{{
    protected virtual {databasePlan.Namespace}.{partitionPlan.ClassName} {partitionPlan.ClassName} {{ get; }} = default!;

    /// <summary>Mocking constructor</summary>
    protected {partitionPlan.CreateOrReplaceClassName}() {{ }}

    internal protected {partitionPlan.CreateOrReplaceClassName}({databasePlan.Namespace}.{partitionPlan.ClassName} {partitionPlan.ClassNameArgument})
    {{
        this.{partitionPlan.ClassName} = {partitionPlan.ClassNameArgument} ?? throw new System.ArgumentNullException(nameof({partitionPlan.ClassNameArgument}));
    }}

{string.Concat(partitionPlan.Documents.Select(x => CreateOrReplace(partitionPlan, x)))}
}}
";

        outputModel.Context.AddSource($"partition_{partitionPlan.CreateOrReplaceClassName}.cs", s);
    }
    public static void Write(OutputModel outputModel, DatabasePlan databasePlan, PartitionPlan partitionPlan)
    {
        var s = $@"
namespace {databasePlan.Namespace};

public class {partitionPlan.QueryBuilderUnionsClassName} : Cosmogenesis.Core.DbQueryBuilderBase
{{
    /// <summary>Mocking constructor</summary>
    protected {partitionPlan.QueryBuilderUnionsClassName}() {{ }}

    internal protected {partitionPlan.QueryBuilderUnionsClassName}(
        {databasePlan.Namespace}.{databasePlan.DbClassName} {databasePlan.DbClassNameArgument},
        Microsoft.Azure.Cosmos.PartitionKey? partitionKey)
        : base(
            dbBase: {databasePlan.DbClassNameArgument},
            partitionKey: partitionKey)
    {{
    }}

{string.Concat(partitionPlan.Unions.Select(BuildQuery))}
}}
";

        outputModel.Context.AddSource($"partition_{partitionPlan.QueryBuilderUnionsClassName}.cs", s);
    }
Пример #5
0
    static string Unions(DatabasePlan databasePlan, PartitionPlan partitionPlan) =>
    partitionPlan.Unions.Count == 0 ? "" : $@"
    {databasePlan.Namespace}.{partitionPlan.QueryUnionsClassName}? unions;
    public virtual {databasePlan.Namespace}.{partitionPlan.QueryUnionsClassName} Unions => this.unions ??= new(
        {databasePlan.DbClassNameArgument}: this.{databasePlan.DbClassName},
        {partitionPlan.QueryBuilderClassNameArgument}: this.{partitionPlan.QueryBuilderClassName});
";
Пример #6
0
    public static void Write(OutputModel outputModel, DatabasePlan databasePlan, PartitionPlan partitionPlan)
    {
        var s = $@"
namespace {databasePlan.Namespace};

public class {partitionPlan.QueryBuilderClassName} : Cosmogenesis.Core.DbQueryBuilderBase
{{
    protected virtual {databasePlan.Namespace}.{databasePlan.DbClassName} {databasePlan.DbClassName} {{ get; }} = default!;
    
    /// <summary>Mocking constructor</summary>
    protected {partitionPlan.QueryBuilderClassName}() {{ }}

    internal protected {partitionPlan.QueryBuilderClassName}(
        {databasePlan.Namespace}.{databasePlan.DbClassName} {databasePlan.DbClassNameArgument},
        Microsoft.Azure.Cosmos.PartitionKey? partitionKey)
        : base(
            dbBase: {databasePlan.DbClassNameArgument},
            partitionKey: partitionKey)
    {{
        {databasePlan.DbClassName} = {databasePlan.DbClassNameArgument} ?? throw new System.ArgumentNullException(nameof({databasePlan.DbClassNameArgument}));
    }}

{string.Concat(partitionPlan.Documents.Select(BuildQuery))}
{Unions(databasePlan, partitionPlan)}
}}
";

        if (partitionPlan.Unions.Any())
        {
            QueryBuilderUnionsWriter.Write(outputModel, databasePlan, partitionPlan);
        }

        outputModel.Context.AddSource($"partition_{partitionPlan.QueryBuilderClassName}.cs", s);
    }
Пример #7
0
    static string Query(DatabasePlan databasePlan, PartitionPlan partitionPlan, UnionPlan unionPlan) => $@"
    /// <summary>
    /// Build and execute a query filtered to {unionPlan.CommonName} documents.
    /// {unionPlan.CommonName} is a union of: {string.Join(", ", unionPlan.Documents.Select(x => x.ClassName))}
    /// <see cref=""https://github.com/Azure/azure-cosmos-dotnet-v3/blob/bb72ba5786d99d928b4774e16810f2655029e8a2/Microsoft.Azure.Cosmos/src/Linq/CosmosLinqExtensions.cs"" />
    /// </summary>
    public virtual System.Collections.Generic.IAsyncEnumerable<T> {unionPlan.CommonName.Pluralize()}<T>(
        System.Func<System.Linq.IQueryable<{unionPlan.FullCommonTypeName}>, System.Linq.IQueryable<T>> createQuery,
        System.Threading.CancellationToken cancellationToken = default)
        => this.{databasePlan.DbClassName}
            .ExecuteQueryAsync(
                query: createQuery(this.{partitionPlan.QueryBuilderClassName}.Unions.{unionPlan.CommonName.Pluralize()}()),
                cancellationToken: cancellationToken);

    /// <summary>
    /// Execute a query filtered to {unionPlan.CommonName} documents.
    /// {unionPlan.CommonName} is a union of: {string.Join(", ", unionPlan.Documents.Select(x => x.ClassName))}
    /// </summary>
    public virtual System.Collections.Generic.IAsyncEnumerable<{unionPlan.FullCommonTypeName}> {unionPlan.CommonName.Pluralize()}(
        System.Threading.CancellationToken cancellationToken = default)
        => this.{databasePlan.DbClassName}
            .ExecuteQueryAsync(
                query: this.{partitionPlan.QueryBuilderClassName}.Unions.{unionPlan.CommonName.Pluralize()}(),
                cancellationToken: cancellationToken);
";
Пример #8
0
    public static void Write(OutputModel outputModel, DatabasePlan databasePlan, PartitionPlan partitionPlan)
    {
        var s = $@"
namespace {databasePlan.Namespace};

public class {partitionPlan.ReadClassName}
{{
    protected virtual {databasePlan.Namespace}.{databasePlan.DbClassName} {databasePlan.DbClassName} {{ get; }} = default!;
    protected virtual Microsoft.Azure.Cosmos.PartitionKey PartitionKey {{ get; }} = default!;

    /// <summary>Mocking constructor</summary>
    protected {partitionPlan.ReadClassName}() {{ }}

    internal protected {partitionPlan.ReadClassName}(
        {databasePlan.Namespace}.{databasePlan.DbClassName} {databasePlan.DbClassNameArgument},
        Microsoft.Azure.Cosmos.PartitionKey partitionKey)
    {{
        this.{databasePlan.DbClassName} = {databasePlan.DbClassNameArgument} ?? throw new System.ArgumentNullException(nameof({databasePlan.DbClassNameArgument}));
        this.PartitionKey = partitionKey;
    }}

{string.Concat(partitionPlan.Documents.Select(x => Read(databasePlan, x)))}
{Unions(databasePlan, partitionPlan)}
}}
";

        if (partitionPlan.Unions.Count > 0)
        {
            ReadUnionsWriter.Write(outputModel, databasePlan, partitionPlan);
        }

        outputModel.Context.AddSource($"partition_{partitionPlan.ReadClassName}.cs", s);
    }
Пример #9
0
    static string Create(PartitionPlan partitionPlan, DocumentPlan documentPlan) => $@"
    /// <summary>
    /// Try to create a {documentPlan.ClassName}.
    /// </summary>
    /// <exception cref=""Cosmogenesis.Core.DbOverloadedException"" />
    /// <exception cref=""Cosmogenesis.Core.DbUnknownStatusCodeException"" />
    public virtual System.Threading.Tasks.Task<Cosmogenesis.Core.CreateResult<{documentPlan.FullTypeName}>> {documentPlan.ClassName}Async({documentPlan.PropertiesByName.Values.Where(x => !partitionPlan.GetPkPlan.ArgumentByPropertyName.ContainsKey(x.PropertyName)).AsInputParameters()}) => 
        this.{partitionPlan.ClassName}.CreateAsync({documentPlan.ClassNameArgument}: new {documentPlan.FullTypeName} {{ {partitionPlan.AsSettersFromDocumentPlanAndPartitionClass(documentPlan)} }});
";
Пример #10
0
    static string ReadOrCreate(PartitionPlan partitionPlan, DocumentPlan documentPlan) => $@"
    /// <summary>
    /// Read a {documentPlan.ClassName} document, or create it if it does not yet exist.
    /// </summary>
    /// <exception cref=""Cosmogenesis.Core.DbOverloadedException"" />
    /// <exception cref=""Cosmogenesis.Core.DbUnknownStatusCodeException"" />
    public virtual System.Threading.Tasks.Task<Cosmogenesis.Core.ReadOrCreateResult<{documentPlan.FullTypeName}>> {documentPlan.ClassName}Async({new[] { "bool tryCreateFirst", documentPlan.PropertiesByName.Values.Where(x => !partitionPlan.GetPkPlan.ArgumentByPropertyName.ContainsKey(x.PropertyName)).AsInputParameters() }.JoinNonEmpty()}) => 
        this.{partitionPlan.ClassName}.ReadOrCreateAsync({documentPlan.ClassNameArgument}: new {documentPlan.FullTypeName} {{ {partitionPlan.AsSettersFromDocumentPlanAndPartitionClass(documentPlan)} }}, tryCreateFirst: tryCreateFirst);
";
Пример #11
0
    static string CreateOrReplace(DatabasePlan databasePlan, PartitionPlan partitionPlan) =>
    !partitionPlan.Documents.Any(x => x.IsTransient || x.IsMutable)
        ? ""
        : $@"
        {partitionPlan.CreateOrReplaceClassName}? createOrReplace;
    /// <summary>
    /// Methods to create or replace (unconditionally overwrite) documents.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.CreateOrReplaceClassName} CreateOrReplace => this.createOrReplace ??= new(this);
";
Пример #12
0
    static string PkClass(PartitionPlan partitionPlan) =>
    partitionPlan.GetPkPlan.Arguments.Count == 0
        ? "" :
    $@"
    internal protected struct PkData
    {{
        {string.Concat(partitionPlan.GetPkPlan.Arguments.Select(PkClassProperty))}
    }}

    internal protected virtual PkData PartitionKeyData {{ get; }}
";
Пример #13
0
    static string ReadMany(DatabasePlan databasePlan, PartitionPlan partitionPlan) =>
    !partitionPlan.Documents.Any(x => x.GetIdPlan.Arguments.Count > 0)
        ? ""
        : $@"
        {partitionPlan.ReadManyClassName}? readMany;
    /// <summary>
    /// Methods to read multiple documents at once, though not necessarily in a single operation.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.ReadManyClassName} ReadMany => this.readMany ??= new(
        {databasePlan.DbClassNameArgument}: {databasePlan.DbClassName}, 
        partitionKey: this.PartitionKey);
";
Пример #14
0
    static string CreateOrReplace(PartitionPlan partitionPlan, DocumentPlan documentPlan) =>
    !documentPlan.IsTransient && !documentPlan.IsMutable
        ? ""
        : $@"
    /// <summary>
    /// Create or replace (unconditionally overwrite) a {documentPlan.ClassName}.
    /// </summary>
    /// <exception cref=""Cosmogenesis.Core.DbOverloadedException"" />
    /// <exception cref=""Cosmogenesis.Core.DbUnknownStatusCodeException"" />
    public virtual System.Threading.Tasks.Task<Cosmogenesis.Core.CreateOrReplaceResult<{documentPlan.FullTypeName}>> {documentPlan.ClassName}Async({documentPlan.PropertiesByName.Values.Where(x => !partitionPlan.GetPkPlan.ArgumentByPropertyName.ContainsKey(x.PropertyName)).AsInputParameters()}) => 
        this.{partitionPlan.ClassName}.CreateOrReplaceAsync(new {documentPlan.FullTypeName} {{ {partitionPlan.AsSettersFromDocumentPlanAndPartitionClass(documentPlan)} }});
";
Пример #15
0
    static string Delete(DatabasePlan databasePlan, PartitionPlan partitionPlan, DocumentPlan documentPlan) =>
    !documentPlan.IsTransient
        ? ""
        : $@"
    /// <summary>
    /// Queue a {documentPlan.ClassName} for deletion in the batch
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.BatchClassName} Delete({documentPlan.FullTypeName} {documentPlan.ClassNameArgument})
    {{
        this.DeleteCore(item: {documentPlan.ClassNameArgument});
        return this;
    }}
";
Пример #16
0
    static string Replace(DatabasePlan databasePlan, PartitionPlan partitionPlan, DocumentPlan documentPlan) =>
    !documentPlan.IsMutable
        ? ""
        : $@"
    /// <summary>
    /// Queue a {documentPlan.ClassName} for replacement in the batch
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.BatchClassName} Replace({documentPlan.FullTypeName} {documentPlan.ClassNameArgument})
    {{    
        this.ReplaceCore(item: {documentPlan.ClassNameArgument}, type: {documentPlan.ConstDocType});
        return this;
    }}
";
Пример #17
0
    public static string AsSettersFromDocumentPlanAndPartitionClass(this PartitionPlan partitionPlan, DocumentPlan documentPlan)
    {
        var setters = documentPlan
                      .PropertiesByName
                      .Values
                      .Where(x => !partitionPlan.GetPkPlan.ArgumentByPropertyName.ContainsKey(x.PropertyName))
                      .Select(x => $"{x.PropertyName} = {x.ArgumentName}");
        var key = partitionPlan
                  .GetPkPlan
                  .Arguments
                  .Select(x => $"{x.PropertyName} = this.{partitionPlan.ClassName}.PartitionKeyData.{x.PropertyName}");

        return(setters.Concat(key).JoinNonEmpty());
    }
Пример #18
0
    static string ReadOrCreate(PartitionPlan partitionPlan, DocumentPlan documentPlan) => $@"
    /// <summary>
    /// Read a {documentPlan.ClassName} document, or create it if it does not yet exist.
    /// .id must be set if there is no stable id generator defined
    /// .pk, .CreationDate and .Type are set automatically
    /// </summary>
    /// <exception cref=""Cosmogenesis.Core.DbOverloadedException"" />
    /// <exception cref=""Cosmogenesis.Core.DbUnknownStatusCodeException"" />
    internal protected virtual System.Threading.Tasks.Task<Cosmogenesis.Core.ReadOrCreateResult<{documentPlan.FullTypeName}>> ReadOrCreateAsync(bool tryCreateFirst, {documentPlan.FullTypeName} {documentPlan.ClassNameArgument})
    {{
        {DocumentModelWriter.CreateAndCheckPkAndId(partitionPlan, documentPlan, documentPlan.ClassNameArgument)}
        return this.ReadOrCreateItemAsync(item: {documentPlan.ClassNameArgument}, type: {documentPlan.ConstDocType}, tryCreateFirst: tryCreateFirst);
    }}
";
Пример #19
0
    static string Partition(PartitionPlan partitionPlan) => $@"
    public class {partitionPlan.BatchHandlersClassName}
    {{
        /// <summary>Mocking constructor</summary>
        protected {partitionPlan.BatchHandlersClassName}() {{ }}

        public {partitionPlan.BatchHandlersClassName}({partitionPlan.Documents.OrderBy(x => x.ClassName).Select(ConstructorArg).JoinNonEmpty()})
        {{
{string.Concat(partitionPlan.Documents.Select(AssignArg))}
        }}

{string.Concat(partitionPlan.Documents.Select(Handler))}
    }}
    
    public virtual {partitionPlan.BatchHandlersClassName}? {partitionPlan.Name} {{ get; }}
";
Пример #20
0
    static string CreateOrReplace(PartitionPlan partitionPlan, DocumentPlan documentPlan) =>
    !documentPlan.IsMutable && !documentPlan.IsTransient
        ? ""
        : $@"
    /// <summary>
    /// Create or replace (unconditionally overwrite) a {documentPlan.ClassName}.
    /// .id must be set if there is no stable id generator defined
    /// .pk, .CreationDate and .Type are set automatically
    /// </summary>
    /// <exception cref=""Cosmogenesis.Core.DbOverloadedException"" />
    /// <exception cref=""Cosmogenesis.Core.DbUnknownStatusCodeException"" />
    internal protected virtual System.Threading.Tasks.Task<Cosmogenesis.Core.CreateOrReplaceResult<{documentPlan.FullTypeName}>> CreateOrReplaceAsync({documentPlan.FullTypeName} {documentPlan.ClassNameArgument})
    {{
        {DocumentModelWriter.CreateAndCheckPkAndId(partitionPlan, documentPlan, documentPlan.ClassNameArgument)}
        return this.CreateOrReplaceItemAsync(item: {documentPlan.ClassNameArgument}, type: {documentPlan.ConstDocType});
    }}
";
Пример #21
0
    static string Create(DatabasePlan databasePlan, PartitionPlan partitionPlan, DocumentPlan documentPlan) => $@"
    /// <summary>
    /// Queue a {documentPlan.ClassName} for creation in the batch
    /// </summary>
    protected virtual {databasePlan.Namespace}.{partitionPlan.BatchClassName} Create({documentPlan.FullTypeName} {documentPlan.ClassNameArgument})
    {{
        {DocumentModelWriter.CreateAndCheckPkAndId(partitionPlan, documentPlan, documentPlan.ClassNameArgument)}
        this.CreateCore(item: {documentPlan.ClassNameArgument}, type: {documentPlan.ConstDocType});
        return this;
    }}

    /// <summary>
    /// Queue a {documentPlan.ClassName} for creation in the batch
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.BatchClassName} Create{documentPlan.ClassName}({documentPlan.PropertiesByName.Values.Where(x => !partitionPlan.GetPkPlan.ArgumentByPropertyName.ContainsKey(x.PropertyName)).AsInputParameters()}) =>
        this.Create({documentPlan.ClassNameArgument}: new {documentPlan.FullTypeName} {{ {partitionPlan.AsSettersFromDocumentPlanAndPartitionClass(documentPlan)} }});
";
Пример #22
0
    public static string CreateAndCheckPkAndId(PartitionPlan partitionPlan, DocumentPlan documentPlan, string paramTypeName) => $@"
        if ({paramTypeName} is null)
        {{
            throw new System.ArgumentNullException(nameof({paramTypeName}));
        }}
        var calculatedPk = {partitionPlan.GetPkPlan.FullMethodName}({partitionPlan.GetPkPlan.DocumentToParametersMapping(paramTypeName)});
        var calculatedId = Cosmogenesis.Core.DbDocHelper.GetValidId({documentPlan.GetIdPlan.FullMethodName}({documentPlan.GetIdPlan.DocumentToParametersMapping(paramTypeName)}));
        if ({paramTypeName}.id is null)
        {{
            {paramTypeName}.id = calculatedId ?? throw new System.InvalidOperationException(""The generated document id cannot be null"");
        }}
        else if ({paramTypeName}.id != calculatedId) 
        {{
            throw new System.InvalidOperationException(""The document .id property does not match the calculated document id"");
        }}
        if ({paramTypeName}.pk is null)
        {{
            {paramTypeName}.pk = calculatedPk ?? throw new System.InvalidOperationException(""The generated partition key cannot be null"");
        }}
        else if ({paramTypeName}.pk != calculatedPk)
        {{
            throw new System.InvalidOperationException(""The document .pk property does not match the calculated document partition key"");
        }}
";
Пример #23
0
 static string PkClassSetter(PartitionPlan partitionPlan) => partitionPlan.GetPkPlan.Arguments.Count == 0 ? "" : "this.PartitionKeyData = pkData;";
Пример #24
0
 static string ConstructorKeyParameter(PartitionPlan partitionPlan) =>
 partitionPlan.GetPkPlan.Arguments.Count == 0 ?
 "" : $@"
     in PkData pkData";
Пример #25
0
    public static void Write(OutputModel outputModel, DatabasePlan databasePlan, PartitionPlan partitionPlan)
    {
        var s = $@"
namespace {databasePlan.Namespace};

public class {partitionPlan.BatchClassName} : Cosmogenesis.Core.DbBatchBase
{{
    protected virtual {databasePlan.Namespace}.{partitionPlan.ClassName} {partitionPlan.ClassName} {{ get; }} = default!;

    /// <summary>Mocking constructor</summary>
    protected {partitionPlan.BatchClassName}() {{ }}

    internal protected {partitionPlan.BatchClassName}(
        Microsoft.Azure.Cosmos.TransactionalBatch transactionalBatch,
        string partitionKey,
        bool validateStateBeforeSave,
        {databasePlan.Namespace}.{partitionPlan.ClassName} {partitionPlan.ClassNameArgument})
        : base(
            transactionalBatch: transactionalBatch,
            partitionKey: partitionKey,
            serializer: {databasePlan.Namespace}.{databasePlan.SerializerClassName}.Instance,
            validateStateBeforeSave: validateStateBeforeSave)
    {{
        this.{partitionPlan.ClassName} = {partitionPlan.ClassNameArgument} ?? throw new System.ArgumentNullException(nameof({partitionPlan.ClassNameArgument}));
    }}

    /// <summary>
    /// Queue a document for creation in the batch.
    /// Throws InvalidOperationException if the DbDoc does not belong in the partition.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.BatchClassName} CheckAndCreate(Cosmogenesis.Core.DbDoc dbDoc) => dbDoc switch
    {{
{string.Concat(partitionPlan.Documents.Select(CheckedCreate))}
        null => throw new System.ArgumentNullException(nameof(dbDoc)),
        _ => throw new System.InvalidOperationException($""{{dbDoc.GetType().Name}} is not a type stored in this partition"")
    }};

    /// <summary>
    /// Tries to queue a document for creation in the batch.
    /// Returns true if queued, or false if the document does not belong in the partition.
    /// </summary>
    public virtual bool TryCheckAndCreate(Cosmogenesis.Core.DbDoc dbDoc) => dbDoc switch
    {{
{string.Concat(partitionPlan.Documents.Select(CheckedCreate))}
        null => throw new System.ArgumentNullException(nameof(dbDoc)),
        _ => ({databasePlan.Namespace}.{partitionPlan.BatchClassName}?)null
    }} != null;

    /// <summary>
    /// Queue a document for creation or replacement in the batch.
    /// Throws InvalidOperationException if the DbDoc does not belong in the partition or is not mutable.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.BatchClassName} CheckAndCreateOrReplace(Cosmogenesis.Core.DbDoc dbDoc) => dbDoc switch
    {{
{string.Concat(partitionPlan.Documents.Where(x => x.IsMutable || x.IsTransient).Select(CheckedCreateOrReplace))}
        null => throw new System.ArgumentNullException(nameof(dbDoc)),
        _ => throw new System.InvalidOperationException($""{{dbDoc.GetType().Name}} is not a mutable type in this partition"")
    }};

    /// <summary>
    /// Tries to queue a document for creation or replacement in the batch.
    /// Returns true if queued, or false if the document does not belong in the partition or is not mutable.
    /// </summary>
    public virtual bool TryCheckAndCreateOrReplace(Cosmogenesis.Core.DbDoc dbDoc) => dbDoc switch
    {{
{string.Concat(partitionPlan.Documents.Where(x => x.IsMutable || x.IsTransient).Select(CheckedCreateOrReplace))}
        null => throw new System.ArgumentNullException(nameof(dbDoc)),
        _ => ({databasePlan.Namespace}.{partitionPlan.BatchClassName}?)null
    }} != null;

    /// <summary>
    /// Queue a document for replacement in the batch.
    /// Throws InvalidOperationException if the DbDoc does not belong in the partition or is not mutable.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.BatchClassName} CheckAndReplace(Cosmogenesis.Core.DbDoc dbDoc) => dbDoc switch
    {{
        {string.Concat(partitionPlan.Documents.Where(x => x.IsMutable).Select(CheckedReplace))}
        null => throw new System.ArgumentNullException(nameof(dbDoc)),
        _ => throw new System.InvalidOperationException($""{{dbDoc.GetType().Name}} is not a mutable type in this partition"")
    }};

    /// <summary>
    /// Tries to queue a document for replacement in the batch.
    /// Returns true if queued, or false if the document does not belong in the partition or is not mutable.
    /// </summary>
    public virtual bool TryCheckAndReplace(Cosmogenesis.Core.DbDoc dbDoc) => dbDoc switch
    {{
        {string.Concat(partitionPlan.Documents.Where(x => x.IsMutable).Select(CheckedReplace))}
        null => throw new System.ArgumentNullException(nameof(dbDoc)),
        _ => ({databasePlan.Namespace}.{partitionPlan.BatchClassName}?)null
    }} != null;

    /// <summary>
    /// Queue a document for deletion in the batch.
    /// Throws InvalidOperationException if the DbDoc does not belong in the partition or is not transient.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.BatchClassName} CheckAndDelete(Cosmogenesis.Core.DbDoc dbDoc) => dbDoc switch
    {{
        {string.Concat(partitionPlan.Documents.Where(x => x.IsTransient).Select(CheckedDelete))}
        null => throw new System.ArgumentNullException(nameof(dbDoc)),
        _ => throw new System.InvalidOperationException($""{{dbDoc.GetType().Name}} is not a transient type in this partition"")
    }};

    /// <summary>
    /// Tries to queue a document for deletion in the batch.
    /// Returns true if queued, or false if the document does not belong in the partition or is not transient.
    /// </summary>
    public virtual bool TryCheckAndDelete(Cosmogenesis.Core.DbDoc dbDoc) => dbDoc switch
    {{
        {string.Concat(partitionPlan.Documents.Where(x => x.IsTransient).Select(CheckedDelete))}
        null => throw new System.ArgumentNullException(nameof(dbDoc)),
        _ => ({databasePlan.Namespace}.{partitionPlan.BatchClassName}?)null
    }} != null;

{string.Concat(partitionPlan.Documents.Select(x => Create(databasePlan, partitionPlan, x)))}
{string.Concat(partitionPlan.Documents.Select(x => CreateOrReplace(databasePlan, partitionPlan, x)))}
{string.Concat(partitionPlan.Documents.Select(x => Replace(databasePlan, partitionPlan, x)))}
{string.Concat(partitionPlan.Documents.Select(x => Delete(databasePlan, partitionPlan, x)))}
}}
";

        outputModel.Context.AddSource($"partition_{partitionPlan.BatchClassName}.cs", s);
    }
Пример #26
0
    static string PartitionTypes(PartitionPlan partitionPlan) => $@"
    public static class {partitionPlan.ClassName}
    {{
{string.Concat(partitionPlan.Documents.Select(Type))}
    }}
";
Пример #27
0
    public static void Write(OutputModel outputModel, DatabasePlan databasePlan, PartitionPlan partitionPlan)
    {
        var s = $@"
namespace {databasePlan.Namespace};

public class {partitionPlan.ClassName} : Cosmogenesis.Core.DbPartitionBase
{{
    protected virtual {databasePlan.Namespace}.{databasePlan.DbClassName} {databasePlan.DbClassName} {{ get; }} = default!;

    {PkClass(partitionPlan)}

    /// <summary>Mocking constructor</summary>
    protected {partitionPlan.ClassName}() {{ }}

    internal protected {partitionPlan.ClassName}(
        {new[] { ConstructorClassParameter(databasePlan), ConstructorKeyParameter(partitionPlan) }.Where(x => !string.IsNullOrEmpty(x)).JoinNonEmpty()})
        : base(
            db: {databasePlan.DbClassNameArgument},
            partitionKey: {partitionPlan.GetPkPlan.FullMethodName}({partitionPlan.GetPkPlan.DocumentToParametersMapping("pkData")}),
            serializer: {databasePlan.Namespace}.{databasePlan.SerializerClassName}.Instance)
    {{
        this.{databasePlan.DbClassName} = {databasePlan.DbClassNameArgument} ?? throw new System.ArgumentNullException(nameof({databasePlan.DbClassNameArgument}));
        {PkClassSetter(partitionPlan)}
    }}

    {databasePlan.Namespace}.{partitionPlan.QueryBuilderClassName}? queryBuilder;
    /// <summary>
    /// Methods to build queries for later execution.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.QueryBuilderClassName} QueryBuilder => this.queryBuilder ??= new(
        {databasePlan.DbClassNameArgument}: this.{databasePlan.DbClassName},
        partitionKey: this.PartitionKey);

    {databasePlan.Namespace}.{partitionPlan.QueryClassName}? query;
    /// <summary>
    /// Methods to execute queries.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.QueryClassName} Query => this.query ??= new(
        {databasePlan.DbClassNameArgument}: this.{databasePlan.DbClassName},
        {partitionPlan.QueryBuilderClassNameArgument}: this.QueryBuilder);

    /// <summary>
    /// A batch of operations to be executed atomically (or not at all) within a {partitionPlan.Name} in the {databasePlan.Name} database.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.BatchClassName} CreateBatch() => new(
        transactionalBatch: this.CreateBatchForPartition(),
        partitionKey: this.PartitionKeyString,
        validateStateBeforeSave: this.{databasePlan.DbClassName}.ValidateStateBeforeSave,
        {partitionPlan.ClassNameArgument}: this);

    {databasePlan.Namespace}.{partitionPlan.ReadClassName}? read;
    /// <summary>
    /// Methods to read documents.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.ReadClassName} Read => this.read ??= new(
        {databasePlan.DbClassNameArgument}: this.{databasePlan.DbClassName}, 
        partitionKey: this.PartitionKey);

    {databasePlan.Namespace}.{partitionPlan.ReadOrThrowClassName}? readOrThrow;
    /// <summary>
    /// Methods to read documents, or throw DbConflictException is they are not found.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.ReadOrThrowClassName} ReadOrThrow => this.readOrThrow ??= new(
        {databasePlan.DbClassNameArgument}: this.{databasePlan.DbClassName}, 
        partitionKey: this.PartitionKey);

    {databasePlan.Namespace}.{partitionPlan.CreateClassName}? create;
    /// <summary>
    /// Methods to create documents.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.CreateClassName} Create => this.create ??= new(this);

    {databasePlan.Namespace}.{partitionPlan.ReadOrCreateClassName}? readOrCreate;
    /// <summary>
    /// Methods to read documents, or create them if they did not yet exist.
    /// </summary>
    public virtual {databasePlan.Namespace}.{partitionPlan.ReadOrCreateClassName} ReadOrCreate => this.readOrCreate ??= new(this);

{ReadMany(databasePlan, partitionPlan)}
{CreateOrReplace(databasePlan, partitionPlan)}
{string.Concat(partitionPlan.Documents.Select(x => Create(partitionPlan, x)))}
{string.Concat(partitionPlan.Documents.Select(x => CreateOrReplace(partitionPlan, x)))}
{string.Concat(partitionPlan.Documents.Select(x => ReadOrCreate(partitionPlan, x)))}
{string.Concat(partitionPlan.Documents.Select(ReplaceIfMutable))}
{string.Concat(partitionPlan.Documents.Select(DeleteIfTransient))}
}}
";

        outputModel.Context.AddSource($"partition_{partitionPlan.ClassName}.cs", s);

        BatchWriter.Write(outputModel, databasePlan, partitionPlan);
        CreateWriter.Write(outputModel, databasePlan, partitionPlan);
        ReadOrCreateWriter.Write(outputModel, databasePlan, partitionPlan);
        CreateOrReplaceWriter.Write(outputModel, databasePlan, partitionPlan);
        ReadWriter.Write(outputModel, databasePlan, partitionPlan);
        ReadOrThrowWriter.Write(outputModel, databasePlan, partitionPlan);
        ReadManyWriter.Write(outputModel, databasePlan, partitionPlan);
        QueryBuilderWriter.Write(outputModel, databasePlan, partitionPlan);
        QueryWriter.Write(outputModel, databasePlan, partitionPlan);
    }
Пример #28
0
    static string Partition(DatabasePlan databasePlan, PartitionPlan partitionPlan) => $@"
    public virtual {databasePlan.Namespace}.{partitionPlan.ClassName} {partitionPlan.Name}({partitionPlan.GetPkPlan.AsInputParameters()}) =>
        new({new[] { CreateClassParameter(databasePlan), CreateKeyParameter(partitionPlan) }.JoinNonEmpty()});
";
Пример #29
0
    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);
        }
    }
Пример #30
0
 static string CreateKeyParameter(PartitionPlan partitionPlan) =>
 partitionPlan.GetPkPlan.Arguments.Count == 0 ?
 "" : $@"
         pkData: new() {{ {partitionPlan.GetPkPlan.AsSettersFromParameters()} }}";