Beispiel #1
0
        public DocumentTable(DocumentMapping mapping) : base(mapping.Table)
        {
            var pgIdType = TypeMappings.GetPgType(mapping.IdMember.GetMemberType());

            AddPrimaryKey(new TableColumn("id", pgIdType));

            AddColumn("data", "jsonb", "NOT NULL");

            AddColumn <LastModifiedColumn>();
            AddColumn <VersionColumn>();
            AddColumn <DotNetTypeColumn>();

            foreach (var field in mapping.DuplicatedFields)
            {
                AddColumn(new DuplicatedFieldColumn(field));
            }

            if (mapping.IsHierarchy())
            {
                AddColumn(new DocumentTypeColumn(mapping));
            }

            if (mapping.DeleteStyle == DeleteStyle.SoftDelete)
            {
                AddColumn <DeletedColumn>();
                AddColumn <DeletedAtColumn>();
            }

            Indexes.AddRange(mapping.Indexes);
            ForeignKeys.AddRange(mapping.ForeignKeys);
        }
        public UpsertFunction(DocumentMapping mapping, DbObjectName identifier = null, bool disableConcurrency = false) : base(identifier ?? mapping.UpsertFunction)
        {
            _disableConcurrency = disableConcurrency;
            if (mapping == null)
            {
                throw new ArgumentNullException(nameof(mapping));
            }

            _tableName = mapping.Table;


            var table = new DocumentTable(mapping);

            if (table.PrimaryKeys.Count > 1)
            {
                _primaryKeyConstraintName = mapping.Table.Name + "_pkey";
            }
            else
            {
                _primaryKeyConstraintName = "pk_" + mapping.Table.Name;
            }



            var idType   = mapping.IdMember.GetMemberType();
            var pgIdType = TypeMappings.GetPgType(idType);

            Arguments.Add(new UpsertArgument
            {
                Arg          = "docId",
                PostgresType = pgIdType,
                Column       = "id",
                Members      = new[] { mapping.IdMember }
            });

            Arguments.Add(new DocJsonBodyArgument());

            Arguments.AddRange(mapping.DuplicatedFields.Select(x => x.UpsertArgument));

            Arguments.Add(new VersionArgument());

            Arguments.Add(new DotNetTypeArgument());

            if (mapping.IsHierarchy())
            {
                Arguments.Add(new DocTypeArgument());
            }

            if (mapping.UseOptimisticConcurrency)
            {
                Arguments.Add(new CurrentVersionArgument());
            }

            if (mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                Arguments.Add(new TenantIdArgument());
                _tenantWhereClause    = $"{_tableName.QualifiedName}.{TenantIdColumn.Name} = {TenantIdArgument.ArgName}";
                _andTenantWhereClause = $" and {_tenantWhereClause}";
            }
        }
        // TODO -- just inject the type alias and simplify the operation classes
        private void buildOperationMethod(GeneratedType type, DocumentOperations operations, string methodName)
        {
            var operationType = (GeneratedType)typeof(DocumentOperations).GetProperty(methodName).GetValue(operations);
            var method        = type.MethodFor(methodName);

            if (_mapping.IsHierarchy())
            {
                method.Frames
                .Code($@"
return new Marten.Generated.{operationType.TypeName}
(
    {{0}}, Identity({{0}}),
    {{1}}.Versions.ForType<{_mapping.DocumentType.FullNameInCode()},
    {_mapping.IdType.FullNameInCode()}>(),
    {{2}}
);"
                      , new Use(_mapping.DocumentType), Use.Type <IMartenSession>(), Use.Type <DocumentMapping>());
            }
            else
            {
                method.Frames
                .Code($@"
return new Marten.Generated.{operationType.TypeName}
(
    {{0}}, Identity({{0}}),
    {{1}}.Versions.ForType<{_mapping.DocumentType.FullNameInCode()},
    {_mapping.IdType.FullNameInCode()}>()
);"
                      , new Use(_mapping.DocumentType), Use.Type <IMartenSession>());
            }
        }
        public static DocumentProvider <T> FromPreBuiltTypes <T>(Assembly assembly, DocumentMapping mapping)
        {
            var queryOnly = assembly.ExportedTypes.FirstOrDefault(x =>
                                                                  x.Name == DocumentStorageBuilder.DeriveTypeName(mapping, StorageStyle.QueryOnly));

            var lightweight = assembly.ExportedTypes.FirstOrDefault(x =>
                                                                    x.Name == DocumentStorageBuilder.DeriveTypeName(mapping, StorageStyle.Lightweight));

            var identityMap = assembly.ExportedTypes.FirstOrDefault(x =>
                                                                    x.Name == DocumentStorageBuilder.DeriveTypeName(mapping, StorageStyle.IdentityMap));

            var dirtyTracking = assembly.ExportedTypes.FirstOrDefault(x =>
                                                                      x.Name == DocumentStorageBuilder.DeriveTypeName(mapping, StorageStyle.DirtyTracking));

            var bulkWriterType =
                assembly.ExportedTypes.FirstOrDefault(x => x.Name == new BulkLoaderBuilder(mapping).TypeName);

            var slot = new DocumentProvider <T>
            {
                QueryOnly     = (IDocumentStorage <T>)Activator.CreateInstance(queryOnly, mapping),
                Lightweight   = (IDocumentStorage <T>)Activator.CreateInstance(lightweight, mapping),
                IdentityMap   = (IDocumentStorage <T>)Activator.CreateInstance(identityMap, mapping),
                DirtyTracking = (IDocumentStorage <T>)Activator.CreateInstance(dirtyTracking, mapping),
            };

            slot.BulkLoader = mapping.IsHierarchy()
                ? (IBulkLoader <T>)Activator.CreateInstance(bulkWriterType, slot.QueryOnly, mapping)
                : (IBulkLoader <T>)Activator.CreateInstance(bulkWriterType, slot.QueryOnly);


            return(slot);
        }
        public static void DeserializeAsync(this FramesCollection frames, DocumentMapping mapping, int index)
        {
            var documentType = mapping.DocumentType;
            var document     = new Variable(documentType, DocumentVariableName);

            if (!mapping.IsHierarchy())
            {
                frames.Code($@"
{documentType.FullNameInCode()} document;
BLOCK:using (var json = reader.GetTextReader({index}))
document = _serializer.FromJson<{documentType.FullNameInCode()}>(json);
END
").Creates(document);
            }
            else
            {
                frames.CodeAsync($@"
{documentType.FullNameInCode()} document;
var typeAlias = await reader.GetFieldValueAsync<string>({index + 1}, {{0}}).ConfigureAwait(false);
BLOCK:using (var json = reader.GetTextReader({index}))
document = ({documentType.FullNameInCode()}) _serializer.FromJson(_mapping.TypeFor(typeAlias), json);
END
", Use.Type <CancellationToken>()).Creates(document);
            }
        }
Beispiel #6
0
        public DocumentTable(DocumentMapping mapping) : base(mapping.TableName)
        {
            // validate to ensure document has an Identity field or property
            mapping.CompileAndValidate();

            _mapping = mapping;

            foreach (var index in mapping.IgnoredIndexes)
            {
                IgnoredIndexes.Add(index);
            }

            var idColumn = new IdColumn(mapping);

            AddColumn(idColumn).AsPrimaryKey();

            if (mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                AddColumn(mapping.Metadata.TenantId).AsPrimaryKey();

                Indexes.Add(new DocumentIndex(mapping, TenantIdColumn.Name));
            }

            AddColumn <DataColumn>();

            AddIfActive(_mapping.Metadata.LastModified);
            AddIfActive(_mapping.Metadata.Version);
            AddIfActive(_mapping.Metadata.DotNetType);

            AddIfActive(_mapping.Metadata.CorrelationId);
            AddIfActive(_mapping.Metadata.CausationId);
            AddIfActive(_mapping.Metadata.LastModifiedBy);
            AddIfActive(_mapping.Metadata.Headers);

            foreach (var field in mapping.DuplicatedFields.Where(x => !x.OnlyForSearching))
            {
                AddColumn(new DuplicatedFieldColumn(field));
            }

            if (mapping.IsHierarchy())
            {
                Indexes.Add(new DocumentIndex(_mapping, SchemaConstants.DocumentTypeColumn));
                AddColumn(_mapping.Metadata.DocumentType);
            }

            if (mapping.DeleteStyle == DeleteStyle.SoftDelete)
            {
                AddColumn(_mapping.Metadata.IsSoftDeleted);
                Indexes.Add(new DocumentIndex(mapping, SchemaConstants.DeletedColumn));

                AddColumn(_mapping.Metadata.SoftDeletedAt);
            }

            Indexes.AddRange(mapping.Indexes);
            ForeignKeys.AddRange(mapping.ForeignKeys);
        }
Beispiel #7
0
        public DocumentTable(DocumentMapping mapping) : base(mapping.TableName)
        {
            // validate to ensure document has an Identity field or property
            mapping.Validate();

            _mapping = mapping;

            var idColumn = new IdColumn(mapping);

            if (mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                AddPrimaryKeys(new List <TableColumn> {
                    idColumn, mapping.Metadata.TenantId
                });

                Indexes.Add(new IndexDefinition(mapping, TenantIdColumn.Name));
            }
            else
            {
                AddPrimaryKey(idColumn);
            }

            AddColumn <DataColumn>();

            AddIfActive(_mapping.Metadata.LastModified);
            AddIfActive(_mapping.Metadata.Version);
            AddIfActive(_mapping.Metadata.DotNetType);

            AddIfActive(_mapping.Metadata.CorrelationId);
            AddIfActive(_mapping.Metadata.CausationId);
            AddIfActive(_mapping.Metadata.LastModifiedBy);
            AddIfActive(_mapping.Metadata.Headers);

            foreach (var field in mapping.DuplicatedFields)
            {
                AddColumn(new DuplicatedFieldColumn(field));
            }

            if (mapping.IsHierarchy())
            {
                Indexes.Add(new IndexDefinition(_mapping, SchemaConstants.DocumentTypeColumn));
                AddColumn(_mapping.Metadata.DocumentType);
            }

            if (mapping.DeleteStyle == DeleteStyle.SoftDelete)
            {
                AddColumn(_mapping.Metadata.IsSoftDeleted);
                Indexes.Add(new IndexDefinition(mapping, SchemaConstants.DeletedColumn));

                AddColumn(_mapping.Metadata.SoftDeletedAt);
            }

            Indexes.AddRange(mapping.Indexes);
            ForeignKeys.AddRange(mapping.ForeignKeys);
        }
        public DocumentProvider <T> Generate <T>()
        {
            var assembly = new GeneratedAssembly(new GenerationRules("Marten.Generated"));

            var operations = new DocumentOperations(assembly, _mapping, _options);

            assembly.Namespaces.Add(typeof(CommandExtensions).Namespace);
            assembly.Namespaces.Add(typeof(TenantIdArgument).Namespace);
            assembly.Namespaces.Add(typeof(NpgsqlCommand).Namespace);


            var queryOnly = new DocumentStorageBuilder(_mapping, StorageStyle.QueryOnly, x => x.QueryOnlySelector)
                            .Build(assembly, operations);

            var lightweight = new DocumentStorageBuilder(_mapping, StorageStyle.Lightweight, x => x.LightweightSelector)
                              .Build(assembly, operations);

            var identityMap = new DocumentStorageBuilder(_mapping, StorageStyle.IdentityMap, x => x.IdentityMapSelector)
                              .Build(assembly, operations);

            var dirtyTracking = new DocumentStorageBuilder(_mapping, StorageStyle.DirtyTracking, x => x.DirtyCheckingSelector)
                                .Build(assembly, operations);

            var bulkWriterType = new BulkLoaderBuilder(_mapping).BuildType(assembly);

            var compiler = new AssemblyGenerator();

            compiler.ReferenceAssembly(typeof(IDocumentStorage <>).Assembly);
            compiler.ReferenceAssembly(typeof(T).Assembly);

            compiler.Compile(assembly);

            var slot = new DocumentProvider <T>
            {
                QueryOnly     = (IDocumentStorage <T>)Activator.CreateInstance(queryOnly.CompiledType, _mapping),
                Lightweight   = (IDocumentStorage <T>)Activator.CreateInstance(lightweight.CompiledType, _mapping),
                IdentityMap   = (IDocumentStorage <T>)Activator.CreateInstance(identityMap.CompiledType, _mapping),
                DirtyTracking = (IDocumentStorage <T>)Activator.CreateInstance(dirtyTracking.CompiledType, _mapping),

                Operations        = operations,
                QueryOnlyType     = queryOnly,
                LightweightType   = lightweight,
                IdentityMapType   = identityMap,
                DirtyTrackingType = dirtyTracking
            };

            slot.BulkLoader = _mapping.IsHierarchy()
                ? (IBulkLoader <T>)Activator.CreateInstance(bulkWriterType.CompiledType, slot.QueryOnly, _mapping)
                : (IBulkLoader <T>)Activator.CreateInstance(bulkWriterType.CompiledType, slot.QueryOnly);

            slot.BulkLoaderType = bulkWriterType;

            return(slot);
        }
Beispiel #9
0
        public DocumentTable(DocumentMapping mapping) : base(mapping.Table)
        {
            // validate to ensure document has an Identity field or property
            mapping.Validate();

            var pgIdType   = TypeMappings.GetPgType(mapping.IdMember.GetMemberType());
            var pgTextType = TypeMappings.GetPgType(string.Empty.GetType());

            var idColumn = new TableColumn("id", pgIdType);

            if (mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                AddPrimaryKeys(new List <TableColumn>
                {
                    idColumn,
                    new TenantIdColumn()
                });

                Indexes.Add(new IndexDefinition(mapping, TenantIdColumn.Name));
            }
            else
            {
                AddPrimaryKey(idColumn);
            }

            AddColumn("data", "jsonb", "NOT NULL");

            AddColumn <LastModifiedColumn>();
            AddColumn <VersionColumn>();
            AddColumn <DotNetTypeColumn>();

            foreach (var field in mapping.DuplicatedFields)
            {
                AddColumn(new DuplicatedFieldColumn(field));
            }

            if (mapping.IsHierarchy())
            {
                AddColumn(new DocumentTypeColumn(mapping));
            }

            if (mapping.DeleteStyle == DeleteStyle.SoftDelete)
            {
                AddColumn <DeletedColumn>();
                Indexes.Add(new IndexDefinition(mapping, DocumentMapping.DeletedColumn));
                AddColumn <DeletedAtColumn>();
            }


            Indexes.AddRange(mapping.Indexes);
            ForeignKeys.AddRange(mapping.ForeignKeys);
        }
        public GeneratedType BuildType(GeneratedAssembly assembly)
        {
            var upsertFunction = _mapping.Schema.Upsert;


            var arguments = orderArgumentsForBulkWriting(upsertFunction);

            var columns = arguments.Select(x => $"\\\"{x.Column}\\\"").Join(", ");

            var type = assembly.AddType(TypeName,
                                        typeof(BulkLoader <,>).MakeGenericType(_mapping.DocumentType, _mapping.IdType));

            if (_mapping.IsHierarchy())
            {
                type.AllInjectedFields.Add(new InjectedField(typeof(DocumentMapping), "mapping"));
            }

            type.MethodFor("MainLoaderSql")
            .Frames
            .ReturnNewStringConstant("MAIN_LOADER_SQL",
                                     $"COPY {_mapping.TableName.QualifiedName}({columns}) FROM STDIN BINARY");

            type.MethodFor("TempLoaderSql").Frames
            .ReturnNewStringConstant("TEMP_LOADER_SQL", $"COPY {_tempTable}({columns}) FROM STDIN BINARY");

            type.MethodFor(nameof(CopyNewDocumentsFromTempTable))
            .Frames.ReturnNewStringConstant("COPY_NEW_DOCUMENTS_SQL", CopyNewDocumentsFromTempTable());

            type.MethodFor(nameof(OverwriteDuplicatesFromTempTable))
            .Frames.ReturnNewStringConstant("OVERWRITE_SQL", OverwriteDuplicatesFromTempTable());

            type.MethodFor(nameof(CreateTempTableForCopying))
            .Frames.ReturnNewStringConstant("CREATE_TEMP_TABLE_FOR_COPYING_SQL",
                                            CreateTempTableForCopying().Replace("\"", "\\\""));

            var load = type.MethodFor("LoadRow");

            foreach (var argument in arguments)
            {
                argument.GenerateBulkWriterCode(type, load, _mapping);
            }

            var loadAsync = type.MethodFor("LoadRowAsync");

            foreach (var argument in arguments)
            {
                argument.GenerateBulkWriterCodeAsync(type, loadAsync, _mapping);
            }

            return(type);
        }
Beispiel #11
0
        public UpsertFunction(DocumentMapping mapping) : base(mapping.UpsertFunction)
        {
            if (mapping == null)
            {
                throw new ArgumentNullException(nameof(mapping));
            }

            _tableName = mapping.Table;
            _primaryKeyConstraintName = "pk_" + mapping.Table.Name;

            var idType   = mapping.IdMember.GetMemberType();
            var pgIdType = TypeMappings.GetPgType(idType);

            Arguments.Add(new UpsertArgument
            {
                Arg          = "docId",
                PostgresType = pgIdType,
                Column       = "id",
                Members      = new[] { mapping.IdMember }
            });

            Arguments.Add(new DocJsonBodyArgument());

            Arguments.AddRange(mapping.DuplicatedFields.Select(x => x.UpsertArgument));

            Arguments.Add(new VersionArgument());

            Arguments.Add(new DotNetTypeArgument());

            if (mapping.IsHierarchy())
            {
                Arguments.Add(new DocTypeArgument());
            }

            if (mapping.UseOptimisticConcurrency)
            {
                Arguments.Add(new CurrentVersionArgument());
            }

            if (mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                Arguments.Add(new TenantIdArgument());
            }
        }
        public GeneratedType BuildType(GeneratedAssembly assembly)
        {
            var baseType = typeof(StorageOperation <,>).MakeGenericType(_mapping.DocumentType, _mapping.IdType);
            var type     = assembly.AddType(ClassName, baseType);

            if (_mapping.IsHierarchy())
            {
                type.AllInjectedFields.Add(new InjectedField(typeof(DocumentMapping), "mapping"));
            }

            type.MethodFor("Role").Frames.Return(Constant.ForEnum(_role));
            type.MethodFor("DbType").Frames.Return(Constant.ForEnum(TypeMappings.ToDbType(_mapping.IdType)));
            type.MethodFor("CommandText").Frames.Return(Constant.ForString(CommandText));

            buildConfigureMethod(type);

            buildPostprocessingMethods(type);

            return(type);
        }
Beispiel #13
0
        public GeneratedType BuildType(GeneratedAssembly assembly)
        {
            var upsertFunction = _mapping.Schema.Upsert;


            var arguments = orderArgumentsForBulkWriting(upsertFunction);

            var columns = arguments.Select(x => $"\\\"{x.Column}\\\"").Join(", ");

            var type = assembly.AddType($"{_mapping.DocumentType.Name.Sanitize()}BulkLoader",
                                        typeof(BulkLoader <,>).MakeGenericType(_mapping.DocumentType, _mapping.IdType));

            if (_mapping.IsHierarchy())
            {
                type.AllInjectedFields.Add(new InjectedField(typeof(DocumentMapping), "mapping"));
            }

            type.MethodFor("MainLoaderSql").Frames
            .Return($"COPY {_mapping.TableName.QualifiedName}({columns}) FROM STDIN BINARY");

            type.MethodFor("TempLoaderSql").Frames
            .Return($"COPY {_tempTable}({columns}) FROM STDIN BINARY");

            type.MethodFor(nameof(CopyNewDocumentsFromTempTable))
            .Frames.Return(CopyNewDocumentsFromTempTable());

            type.MethodFor(nameof(OverwriteDuplicatesFromTempTable))
            .Frames.Return(OverwriteDuplicatesFromTempTable());

            type.MethodFor(nameof(CreateTempTableForCopying))
            .Frames.Return(CreateTempTableForCopying().Replace("\"", "\\\""));

            var load = type.MethodFor("LoadRow");

            foreach (var argument in arguments)
            {
                argument.GenerateBulkWriterCode(type, load, _mapping);
            }

            return(type);
        }
        public static void DeserializeDocumentAsync(this FramesCollection frames, DocumentMapping mapping, int index)
        {
            var documentType = mapping.DocumentType;
            var document     = new Variable(documentType, DocumentVariableName);

            if (!mapping.IsHierarchy())
            {
                frames.Code($@"
{documentType.FullNameInCode()} document;
document = _serializer.FromJson<{documentType.FullNameInCode()}>(reader, {index});
").Creates(document);
            }
            else
            {
                frames.CodeAsync($@"
{documentType.FullNameInCode()} document;
var typeAlias = await reader.GetFieldValueAsync<string>({index + 1}, {{0}});
document = ({documentType.FullNameInCode()}) (await _serializer.FromJsonAsync(_mapping.TypeFor(typeAlias), reader, {index}, {{0}}));
", Use.Type <CancellationToken>()).Creates(document);
            }
        }
Beispiel #15
0
        public GeneratedType BuildType(GeneratedAssembly assembly)
        {
            var upsertFunction = new UpsertFunction(_mapping);


            var arguments = upsertFunction.OrderedArguments().Where(x => !(x is CurrentVersionArgument)).ToArray();
            var columns   = arguments.Select(x => $"\\\"{x.Column}\\\"").Join(", ");

            var type = assembly.AddType($"{_mapping.DocumentType.Name.Sanitize()}BulkLoader",
                                        typeof(BulkLoader <,>).MakeGenericType(_mapping.DocumentType, _mapping.IdType));

            if (_mapping.IsHierarchy())
            {
                type.AllInjectedFields.Add(new InjectedField(typeof(DocumentMapping), "mapping"));
            }

            type.MethodFor("MainLoaderSql").Frames
            .Return($"COPY {_mapping.Table.QualifiedName}({columns}) FROM STDIN BINARY");

            type.MethodFor("TempLoaderSql").Frames
            .Return($"COPY {_tempTable}({columns}) FROM STDIN BINARY");

            type.MethodFor(nameof(CopyNewDocumentsFromTempTable))
            .Frames.Return(CopyNewDocumentsFromTempTable());

            type.MethodFor(nameof(OverwriteDuplicatesFromTempTable))
            .Frames.Return(OverwriteDuplicatesFromTempTable());

            type.MethodFor(nameof(CreateTempTableForCopying))
            .Frames.Return(CreateTempTableForCopying().Replace("\"", "\\\""));

            var load = type.MethodFor("LoadRow");

            for (int i = 0; i < arguments.Length; i++)
            {
                arguments[i].GenerateBulkWriterCode(type, load, _mapping);
            }

            return(type);
        }
Beispiel #16
0
        private void writeReturnOfOperation(GeneratedMethod method, GeneratedType operationType)
        {
            var assembly = method.ParentType.ParentAssembly;

            var tenantDeclaration = "";

            if (_mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                tenantDeclaration = ", tenant";
            }


            if (_mapping.IsHierarchy())
            {
                method.Frames
                .Code($@"
return new {assembly.Namespace}.{operationType.TypeName}
(
    {{0}}, Identity({{0}}),
    {{1}}.Versions.ForType<{_mapping.DocumentType.FullNameInCode()}, {_mapping.IdType.FullNameInCode()}>(),
    {{2}}
    {tenantDeclaration}
);"
                      , new Use(_mapping.DocumentType), Use.Type <IMartenSession>(), Use.Type <DocumentMapping>());
            }
            else
            {
                method.Frames
                .Code($@"
return new {assembly.Namespace}.{operationType.TypeName}
(
    {{0}}, Identity({{0}}),
    {{1}}.Versions.ForType<{_mapping.DocumentType.FullNameInCode()}, {_mapping.IdType.FullNameInCode()}>(),
    {{2}}
    {tenantDeclaration}
);"
                      , new Use(_mapping.DocumentType), Use.Type <IMartenSession>(), Use.Type <DocumentMapping>());
            }
        }
Beispiel #17
0
        public GeneratedType BuildType(GeneratedAssembly assembly)
        {
            var typeName = $"{_style}{_mapping.DocumentType.Name.Sanitize()}Selector";


            var baseType = determineBaseType();

            var type          = assembly.AddType(typeName, baseType);
            var interfaceType = typeof(ISelector <>).MakeGenericType(_mapping.DocumentType);

            type.Implements(interfaceType);

            var sync  = type.MethodFor("Resolve");
            var async = type.MethodFor("ResolveAsync");

            var versionPosition = _mapping.IsHierarchy() ? 3 : 2;

            switch (_style)
            {
            case StorageStyle.QueryOnly:
                sync.Frames.Deserialize(_mapping);
                async.Frames.DeserializeAsync(_mapping);
                break;

            case StorageStyle.IdentityMap:
                sync.Frames.GetId(_mapping);
                async.Frames.GetIdAsync(_mapping);

                sync.Frames.CheckExistingFirst();
                async.Frames.CheckExistingFirst();

                sync.Frames.Deserialize(_mapping);
                async.Frames.DeserializeAsync(_mapping);

                sync.Frames.MarkAsLoaded();
                async.Frames.MarkAsLoaded();

                sync.Frames.StoreVersion(false, _mapping, versionPosition);
                async.Frames.StoreVersion(true, _mapping, versionPosition);

                sync.Frames.StoreInIdentityMap(_mapping);
                async.Frames.StoreInIdentityMap(_mapping);

                break;

            case StorageStyle.DirtyTracking:
                sync.Frames.GetId(_mapping);
                async.Frames.GetIdAsync(_mapping);

                sync.Frames.CheckExistingFirst();
                async.Frames.CheckExistingFirst();

                sync.Frames.Deserialize(_mapping);
                async.Frames.DeserializeAsync(_mapping);

                sync.Frames.MarkAsLoaded();
                async.Frames.MarkAsLoaded();

                sync.Frames.StoreVersion(false, _mapping, versionPosition);
                async.Frames.StoreVersion(true, _mapping, versionPosition);

                sync.Frames.StoreInIdentityMap(_mapping);
                async.Frames.StoreInIdentityMap(_mapping);

                sync.Frames.StoreTracker();
                async.Frames.StoreTracker();

                break;

            case StorageStyle.Lightweight:
                sync.Frames.GetId(_mapping);
                async.Frames.GetIdAsync(_mapping);

                sync.Frames.Deserialize(_mapping);
                async.Frames.DeserializeAsync(_mapping);

                sync.Frames.MarkAsLoaded();
                async.Frames.MarkAsLoaded();


                sync.Frames.StoreVersion(false, _mapping, versionPosition);
                async.Frames.StoreVersion(true, _mapping, versionPosition);

                break;

            default:
                throw new InvalidOperationException();
            }


            sync.Frames.Return(_mapping.DocumentType);
            if (_style == StorageStyle.QueryOnly && !_mapping.IsHierarchy())
            {
                async.Frames.Code("return Task.FromResult(document);");
            }
            else
            {
                async.Frames.Return(_mapping.DocumentType);
            }

            return(type);
        }
Beispiel #18
0
        public UpsertFunction(DocumentMapping mapping, DbObjectName identifier = null, bool disableConcurrency = false) : base(identifier ?? mapping.UpsertFunction)
        {
            _mapping            = mapping;
            _disableConcurrency = disableConcurrency;
            if (mapping == null)
            {
                throw new ArgumentNullException(nameof(mapping));
            }

            _tableName = mapping.TableName;

            var table = new DocumentTable(mapping);

            _primaryKeyConstraintName = table.PrimaryKeyName;

            var idType   = mapping.IdMember.GetMemberType();
            var pgIdType = PostgresqlProvider.Instance.GetDatabaseType(idType, mapping.EnumStorage);

            Arguments.Add(new UpsertArgument
            {
                Arg          = "docId",
                PostgresType = pgIdType,
                Column       = "id",
                Members      = new[] { mapping.IdMember }
            });

            Arguments.Add(new DocJsonBodyArgument());

            Arguments.AddRange(mapping.DuplicatedFields.Where(x => !x.OnlyForSearching).Select(x => x.UpsertArgument));

            // These two arguments need to be added this way
            if (mapping.Metadata.Version.Enabled)
            {
                Arguments.Add(new VersionArgument());
            }
            if (mapping.Metadata.DotNetType.Enabled)
            {
                Arguments.Add(new DotNetTypeArgument());
            }

            AddIfActive(mapping.Metadata.CorrelationId);
            AddIfActive(mapping.Metadata.CausationId);
            AddIfActive(mapping.Metadata.LastModifiedBy);
            AddIfActive(mapping.Metadata.Headers);


            if (mapping.IsHierarchy())
            {
                Arguments.Add(new DocTypeArgument());
            }

            if (mapping.UseOptimisticConcurrency)
            {
                Arguments.Add(new CurrentVersionArgument());
            }

            if (mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                Arguments.Add(new TenantIdArgument());
                _tenantWhereClause    = $"{_tableName.QualifiedName}.{TenantIdColumn.Name} = {TenantIdArgument.ArgName}";
                _andTenantWhereClause = $" and {_tenantWhereClause}";
            }
        }
        public DocumentProvider <T> Generate <T>()
        {
            var assembly = new GeneratedAssembly(new GenerationRules("Marten.Generated"));

            var operations = new DocumentOperations(assembly, _mapping, _options);

            assembly.Namespaces.Add(typeof(CommandExtensions).Namespace);
            assembly.Namespaces.Add(typeof(TenantIdArgument).Namespace);
            assembly.Namespaces.Add(typeof(NpgsqlCommand).Namespace);


            var queryOnly = new DocumentStorageBuilder(_mapping, StorageStyle.QueryOnly, x => x.QueryOnlySelector)
                            .Build(assembly, operations);

            var lightweight = new DocumentStorageBuilder(_mapping, StorageStyle.Lightweight, x => x.LightweightSelector)
                              .Build(assembly, operations);

            var identityMap = new DocumentStorageBuilder(_mapping, StorageStyle.IdentityMap, x => x.IdentityMapSelector)
                              .Build(assembly, operations);

            var dirtyTracking = new DocumentStorageBuilder(_mapping, StorageStyle.DirtyTracking, x => x.DirtyCheckingSelector)
                                .Build(assembly, operations);

            var bulkWriterType = new BulkLoaderBuilder(_mapping).BuildType(assembly);

            var compiler = new AssemblyGenerator();

            compiler.ReferenceAssembly(typeof(IDocumentStorage <>).Assembly);
            compiler.ReferenceAssembly(typeof(T).Assembly);

            try
            {
                compiler.Compile(assembly);
            }
            catch (Exception e)
            {
                if (e.Message.Contains("is inaccessible due to its protection level"))
                {
                    throw new InvalidOperationException($"Requested document type '{_mapping.DocumentType.FullNameInCode()}' must be either scoped as 'public' or the assembly holding it must use the {nameof(InternalsVisibleToAttribute)} pointing to 'Marten.Generated'", e);
                }

                throw;
            }

            var slot = new DocumentProvider <T>
            {
                QueryOnly     = (IDocumentStorage <T>)Activator.CreateInstance(queryOnly.CompiledType, _mapping),
                Lightweight   = (IDocumentStorage <T>)Activator.CreateInstance(lightweight.CompiledType, _mapping),
                IdentityMap   = (IDocumentStorage <T>)Activator.CreateInstance(identityMap.CompiledType, _mapping),
                DirtyTracking = (IDocumentStorage <T>)Activator.CreateInstance(dirtyTracking.CompiledType, _mapping),

                Operations        = operations,
                QueryOnlyType     = queryOnly,
                LightweightType   = lightweight,
                IdentityMapType   = identityMap,
                DirtyTrackingType = dirtyTracking
            };

            slot.BulkLoader = _mapping.IsHierarchy()
                ? (IBulkLoader <T>)Activator.CreateInstance(bulkWriterType.CompiledType, slot.QueryOnly, _mapping)
                : (IBulkLoader <T>)Activator.CreateInstance(bulkWriterType.CompiledType, slot.QueryOnly);

            slot.BulkLoaderType = bulkWriterType;

            return(slot);
        }
Beispiel #20
0
        public GeneratedType BuildType(GeneratedAssembly assembly)
        {
            var typeName = $"{_style}{_mapping.DocumentType.Name}Selector";


            var baseType = determineBaseType();

            var type          = assembly.AddType(typeName, baseType);
            var interfaceType = typeof(ISelector <>).MakeGenericType(_mapping.DocumentType);

            type.Implements(interfaceType);

            var sync  = type.MethodFor("Resolve");
            var async = type.MethodFor("ResolveAsync");

            var versionPosition = _mapping.IsHierarchy() ? 3 : 2;

            switch (_style)
            {
            case StorageStyle.QueryOnly:
                sync.Frames.Deserialize(_mapping);
                async.Frames.DeserializeAsync(_mapping);
                break;

            case StorageStyle.IdentityMap:

                sync.Frames.Deserialize(_mapping);
                async.Frames.DeserializeAsync(_mapping);

                sync.Frames.GetId(_mapping);
                async.Frames.GetIdAsync(_mapping);


                sync.Frames.StoreVersion(false, _mapping, versionPosition);
                async.Frames.StoreVersion(true, _mapping, versionPosition);

                sync.Frames.StoreInIdentityMap(_mapping);
                async.Frames.StoreInIdentityMap(_mapping);

                break;

            case StorageStyle.DirtyTracking:

                sync.Frames.Deserialize(_mapping);
                async.Frames.DeserializeAsync(_mapping);

                sync.Frames.GetId(_mapping);
                async.Frames.GetIdAsync(_mapping);


                sync.Frames.StoreVersion(false, _mapping, versionPosition);
                async.Frames.StoreVersion(true, _mapping, versionPosition);

                // TODO -- this needs to be a little different
                sync.Frames.StoreInIdentityMap(_mapping);
                async.Frames.StoreInIdentityMap(_mapping);

                break;

            case StorageStyle.Lightweight:
                sync.Frames.Deserialize(_mapping);
                async.Frames.DeserializeAsync(_mapping);

                sync.Frames.GetId(_mapping);
                async.Frames.GetIdAsync(_mapping);

                sync.Frames.StoreVersion(false, _mapping, versionPosition);
                async.Frames.StoreVersion(true, _mapping, versionPosition);

                break;

            default:
                throw new NotImplementedException("Not yet supporting dirty checking");
            }


            sync.Frames.Return(_mapping.DocumentType);
            if (_style == StorageStyle.QueryOnly && !_mapping.IsHierarchy())
            {
                async.Frames.Code("return Task.FromResult(document);");
            }
            else
            {
                async.Frames.Return(_mapping.DocumentType);
            }

            return(type);
        }
Beispiel #21
0
        public UpsertFunction(DocumentMapping mapping, DbObjectName identifier = null, bool disableConcurrency = false) : base(identifier ?? mapping.UpsertFunction)
        {
            _mapping            = mapping;
            _disableConcurrency = disableConcurrency;
            if (mapping == null)
            {
                throw new ArgumentNullException(nameof(mapping));
            }

            _tableName = mapping.TableName;

            // TODO -- it'd be nice to not need this here.
            var table = new DocumentTable(mapping);

            if (table.PrimaryKeys.Count > 1)
            {
                _primaryKeyConstraintName = mapping.TableName.Name + "_pkey";
            }
            else
            {
                _primaryKeyConstraintName = "pk_" + mapping.TableName.Name;
            }

            var idType   = mapping.IdMember.GetMemberType();
            var pgIdType = TypeMappings.GetPgType(idType, mapping.EnumStorage);

            Arguments.Add(new UpsertArgument
            {
                Arg          = "docId",
                PostgresType = pgIdType,
                Column       = "id",
                Members      = new[] { mapping.IdMember }
            });

            Arguments.Add(new DocJsonBodyArgument());

            Arguments.AddRange(mapping.DuplicatedFields.Select(x => x.UpsertArgument));

            // TODO -- see the columns below
            if (mapping.Metadata.Version.Enabled)
            {
                Arguments.Add(new VersionArgument());
            }

            if (mapping.Metadata.DotNetType.Enabled)
            {
                Arguments.Add(new DotNetTypeArgument());
            }

            AddIfActive(mapping.Metadata.CorrelationId);
            AddIfActive(mapping.Metadata.CausationId);
            AddIfActive(mapping.Metadata.LastModifiedBy);
            AddIfActive(mapping.Metadata.Headers);


            if (mapping.IsHierarchy())
            {
                Arguments.Add(new DocTypeArgument());
            }

            if (mapping.UseOptimisticConcurrency)
            {
                Arguments.Add(new CurrentVersionArgument());
            }

            if (mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                Arguments.Add(new TenantIdArgument());
                _tenantWhereClause    = $"{_tableName.QualifiedName}.{TenantIdColumn.Name} = {TenantIdArgument.ArgName}";
                _andTenantWhereClause = $" and {_tenantWhereClause}";
            }
        }