Skip to content

Commit

Permalink
Used PostgresqlObjectName instead of DbObjectName to handle diff corr…
Browse files Browse the repository at this point in the history
…ectly
  • Loading branch information
oskardudycz committed Nov 21, 2023
1 parent a2d4924 commit 38f7226
Show file tree
Hide file tree
Showing 33 changed files with 229 additions and 174 deletions.
2 changes: 1 addition & 1 deletion docs/configuration/multitenancy.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ If you don't know the tenant upfront, you can create and apply changes dynamical
var tenant = await theStore.Tenancy.GetTenantAsync(tenantId);
await tenant.Database.ApplyAllConfiguredChangesToDatabaseAsync();
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/adding_custom_schema_objects.cs#L151-L154' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_manual_single_tenancy_apply_changes' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/adding_custom_schema_objects.cs#L151-L156' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_manual_single_tenancy_apply_changes' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

You can place this code somewhere in the tenant initialization code. For instance:
Expand Down
32 changes: 14 additions & 18 deletions docs/scenarios/using-sequence-for-unique-id.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class MatterId: FeatureSchemaBase
private readonly int _startFrom;
private readonly string _schema;

public MatterId(StoreOptions options, int startFrom) : base(nameof(MatterId), options.Advanced.Migrator)
public MatterId(StoreOptions options, int startFrom): base(nameof(MatterId), options.Advanced.Migrator)
{
_startFrom = startFrom;
_schema = options.DatabaseSchemaName;
Expand All @@ -26,11 +26,12 @@ public class MatterId: FeatureSchemaBase
protected override IEnumerable<ISchemaObject> schemaObjects()
{
// We return a sequence that starts from the value provided in the ctor
yield return new Sequence(new DbObjectName(_schema, $"mt_{nameof(MatterId).ToLowerInvariant()}"), _startFrom);
yield return new Sequence(new PostgresqlObjectName(_schema, $"mt_{nameof(MatterId).ToLowerInvariant()}"),
_startFrom);
}
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L17-L36' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-setup' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L15-L37' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-setup' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

This sequence yielding customization will be plugged into Marten via the store configuration
Expand All @@ -40,7 +41,7 @@ This sequence yielding customization will be plugged into Marten via the store c
```cs
storeOptions.Storage.Add(new MatterId(storeOptions, 10000));
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L43-L45' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-storesetup-1' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L44-L48' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-storesetup-1' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

and then executed against the database (generating & executing the DDL statements that create the required database objects):
Expand All @@ -50,7 +51,7 @@ and then executed against the database (generating & executing the DDL statement
```cs
await theStore.Storage.ApplyAllConfiguredChangesToDatabaseAsync();
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L48-L50' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-storesetup-2' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L51-L55' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-storesetup-2' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

We introduce a few types with `Guid` identifiers, whom we reference to our end users by numbers, encapsulated in the `Matter` field:
Expand All @@ -61,17 +62,20 @@ We introduce a few types with `Guid` identifiers, whom we reference to our end u
public class Contract
{
public Guid Id { get; set; }

public int Matter { get; set; }
// Other fields...
}

public class Inquiry
{
public Guid Id { get; set; }

public int Matter { get; set; }
// Other fields...
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L79-L92' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-setup-types' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L77-L95' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-setup-types' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Now, when creating and persisting such types, we first query the database for a new and unique running number. While we generate (or if wanted, let Marten generate) non-human-readable, system-internal identifiers for the created instances, we assign to them the newly generated and unique human-readable identifier:
Expand All @@ -85,24 +89,16 @@ await using var session = theStore.LightweightSession();
// Generate a new, unique identifier
var nextMatter = session.NextInSequence(matter);

var contract = new Contract
{
Id = Guid.NewGuid(),
Matter = nextMatter
};
var contract = new Contract { Id = Guid.NewGuid(), Matter = nextMatter };

var inquiry = new Inquiry
{
Id = Guid.NewGuid(),
Matter = nextMatter
};
var inquiry = new Inquiry { Id = Guid.NewGuid(), Matter = nextMatter };

session.Store(contract);
session.Store(inquiry);

await session.SaveChangesAsync();
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L52-L76' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-querymatter' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L57-L74' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-querymatter' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Lastly, we have an extension method (used above) as a shorthand for generating the SQL statement for a sequence value query:
Expand All @@ -119,5 +115,5 @@ public static class SessionExtensions
}
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L95-L104' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-setup-extensions' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/Examples/ScenarioUsingSequenceForUniqueId.cs#L98-L109' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_scenario-usingsequenceforuniqueid-setup-extensions' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
25 changes: 14 additions & 11 deletions docs/schema/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@ Not to worry though, Marten comes with a base class that makes it a bit simpler
<!-- snippet: sample_creating-a-fake-schema-feature -->
<a id='snippet-sample_creating-a-fake-schema-feature'></a>
```cs
public class FakeStorage : FeatureSchemaBase
public class FakeStorage: FeatureSchemaBase
{
private readonly StoreOptions _options;

public FakeStorage(StoreOptions options) : base("fake", options.Advanced.Migrator)
public FakeStorage(StoreOptions options): base("fake", options.Advanced.Migrator)
{
_options = options;
}

protected override IEnumerable<ISchemaObject> schemaObjects()
{
var table = new Table(new DbObjectName(_options.DatabaseSchemaName, "mt_fake_table"));
var table = new Table(new PostgresqlObjectName(_options.DatabaseSchemaName, "mt_fake_table"));
table.AddColumn("name", "varchar");

yield return table;
}
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DocumentDbTests/Configuration/ability_to_add_custom_storage_features.cs#L48-L67' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_creating-a-fake-schema-feature' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DocumentDbTests/Configuration/ability_to_add_custom_storage_features.cs#L49-L69' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_creating-a-fake-schema-feature' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Now, to actually apply this feature to your Marten applications, use this syntax:
Expand All @@ -44,20 +44,23 @@ var store = DocumentStore.For(_ =>
_.Storage.Add(new FakeStorage(_));
});
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DocumentDbTests/Configuration/ability_to_add_custom_storage_features.cs#L33-L44' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_adding-schema-feature' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DocumentDbTests/Configuration/ability_to_add_custom_storage_features.cs#L32-L45' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_adding-schema-feature' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Do note that when you use the `Add<T>()` syntax, Marten will pass along the current `StoreOptions` to the constructor function if there is a constructor with that signature. Otherwise, it uses the no-arg constructor.

While you *can* directly implement the `ISchemaObject` interface for something Marten doesn't already support. Marten provides an even easier extensibility mechanism to add custom database objects such as Postgres tables, functions and sequences using `StorageFeatures.ExtendedSchemaObjects` using [Weasel](https://github.com/JasperFx/weasel).
While you
*can* directly implement the `ISchemaObject` interface for something Marten doesn't already support. Marten provides an even easier extensibility mechanism to add custom database objects such as Postgres tables, functions and sequences using `StorageFeatures.ExtendedSchemaObjects` using [Weasel](https://github.com/JasperFx/weasel).

::: warning
Marten will apply **Schema Feature Extensions** automatically when you call `ApplyAllConfiguredChangesToDatabaseAsync` for:
Marten will apply **Schema Feature Extensions
** automatically when you call `ApplyAllConfiguredChangesToDatabaseAsync` for:

* single schema configuration,
* [multi-tenancy per database](/configuration/multitenancy) with tenants known upfront.

But it **won't apply them** for multi-tenancy per database with **unknown** tenants. If you cannot predict them, read the guidance on [dynamically applying changes to tenants databases](/configuration/multitenancy#dynamically-applying-changes-to-tenants-databases).
But it **won't apply them** for multi-tenancy per database with **unknown
** tenants. If you cannot predict them, read the guidance on [dynamically applying changes to tenants databases](/configuration/multitenancy#dynamically-applying-changes-to-tenants-databases).
:::

## Table
Expand Down Expand Up @@ -94,7 +97,7 @@ StoreOptions(opts =>
opts.RegisterDocumentType<Target>();

// Create a user defined function to act as a ternary operator similar to SQL Server
var function = new Function(new DbObjectName("public", "iif"), @"
var function = new Function(new PostgresqlObjectName("public", "iif"), @"
create or replace function iif(
condition boolean, -- if condition
true_result anyelement, -- then
Expand All @@ -109,7 +112,7 @@ $f$ language sql immutable;

await theStore.Storage.ApplyAllConfiguredChangesToDatabaseAsync();
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/adding_custom_schema_objects.cs#L190-L212' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_customschemafunction' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/adding_custom_schema_objects.cs#L192-L214' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_customschemafunction' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## Sequence
Expand All @@ -131,7 +134,7 @@ StoreOptions(opts =>

await theStore.Storage.ApplyAllConfiguredChangesToDatabaseAsync();
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/adding_custom_schema_objects.cs#L226-L240' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_customschemasequence' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/adding_custom_schema_objects.cs#L228-L242' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_customschemasequence' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## Extension
Expand Down
3 changes: 1 addition & 2 deletions src/CoreTests/DocumentCleanerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace CoreTests;

public class DocumentCleanerTests : OneOffConfigurationsContext
public class DocumentCleanerTests: OneOffConfigurationsContext
{
private IDocumentCleaner theCleaner => theStore.Advanced.Clean;

Expand Down Expand Up @@ -224,6 +224,5 @@ int GetSequenceCount(IDocumentStore store)
await theStore.Advanced.Clean.CompletelyRemoveAllAsync();

GetSequenceCount(theStore).ShouldBe(0);

}
}
4 changes: 3 additions & 1 deletion src/CoreTests/adding_custom_schema_objects.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,10 @@ public async Task enable_an_extension_with_multitenancy_with_tenants_upfront_thr
});

#region sample_manual_single_tenancy_apply_changes

var tenant = await theStore.Tenancy.GetTenantAsync(tenantId);
await tenant.Database.ApplyAllConfiguredChangesToDatabaseAsync();

#endregion

await using var sessionNext = theStore.QuerySession(tenantId);
Expand Down Expand Up @@ -194,7 +196,7 @@ public async Task create_a_function()
opts.RegisterDocumentType<Target>();

// Create a user defined function to act as a ternary operator similar to SQL Server
var function = new Function(new DbObjectName("public", "iif"), @"
var function = new Function(new PostgresqlObjectName("public", "iif"), @"
create or replace function iif(
condition boolean, -- if condition
true_result anyelement, -- then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
using Marten.Testing.Harness;
using Weasel.Core;
using Weasel.Core.Migrations;
using Weasel.Postgresql;
using Weasel.Postgresql.Tables;
using Xunit;

namespace DocumentDbTests.Bugs;

public class Bug_2523_using_query_on_custom_storage_table : BugIntegrationContext
public class Bug_2523_using_query_on_custom_storage_table: BugIntegrationContext
{
[Fact]
public async Task WhenCustomTableIsUsedInABatchWithOtherDocumentResetAllShouldWork()
Expand All @@ -27,25 +28,26 @@ public async Task WhenCustomTableIsUsedInABatchWithOtherDocumentResetAllShouldWo

await using var session = store.LightweightSession();
session.QueueSqlCommand(CustomTableStorage.InsertSql, Guid.NewGuid().ToString());
session.Insert(new User{FirstName = "John", LastName = "Doe"});
session.Insert(new User { FirstName = "John", LastName = "Doe" });
await session.SaveChangesAsync();

await store.Advanced.ResetAllData();
}
}

public class CustomTableStorage : FeatureSchemaBase
public class CustomTableStorage: FeatureSchemaBase
{
private const string TableName = "mt_custom_table";
public const string InsertSql = $"insert into bugs.{TableName}(id) values(?)";

private readonly StoreOptions _options;

public CustomTableStorage(StoreOptions options) : base("custom_table", options.Advanced.Migrator) => _options = options;
public CustomTableStorage(StoreOptions options): base("custom_table", options.Advanced.Migrator) =>
_options = options;

protected override IEnumerable<ISchemaObject> schemaObjects()
{
var table = new Table(new DbObjectName("bugs", TableName));
var table = new Table(new PostgresqlObjectName("bugs", TableName));
table.AddColumn<string>("id").AsPrimaryKey();
yield return table;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,29 +98,29 @@ internal class spaceAfterTableNameSchema: testSchema
{
protected override IEnumerable<ISchemaObject> SchemaObjects()
{
var table = new Table(new DbObjectName(SchemaConstants.DefaultSchema,"test_space_after"));
var table = new Table(new PostgresqlObjectName(SchemaConstants.DefaultSchema, "test_space_after"));
table.AddColumn("space_after ", "int");
return new List<ISchemaObject> {table};
return new List<ISchemaObject> { table };
}
}

internal class spaceBeforeTableNameSchema: testSchema
{
protected override IEnumerable<ISchemaObject> SchemaObjects()
{
var table = new Table(new DbObjectName(SchemaConstants.DefaultSchema,"test_space_before"));
var table = new Table(new PostgresqlObjectName(SchemaConstants.DefaultSchema, "test_space_before"));
table.AddColumn(" space_before", "int");
return new List<ISchemaObject> {table};
return new List<ISchemaObject> { table };
}
}

internal class spaceInNameSchema: testSchema
{
protected override IEnumerable<ISchemaObject> SchemaObjects()
{
var table = new Table(new DbObjectName(SchemaConstants.DefaultSchema,"test_space_in"));
var table = new Table(new PostgresqlObjectName(SchemaConstants.DefaultSchema, "test_space_in"));
table.AddColumn("space inname", "int");
return new List<ISchemaObject> {table};
return new List<ISchemaObject> { table };
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ public class Bug_1338_Validate_Null_ForeignKeyDefinition_ReferenceDocumenType: B
[Fact]
public void StorageFeatures_AllActiveFeatures_Should_Not_Throw_With_ExternalForeignKeyDefinitions()
{
theStore.StorageFeatures.AllActiveFeatures(theStore.Tenancy.Default.Database).All(x => x != null).ShouldBeTrue();
theStore.StorageFeatures.AllActiveFeatures(theStore.Tenancy.Default.Database).All(x => x != null)
.ShouldBeTrue();
}

public async Task InitializeAsync()
{
var table = new Table(new DbObjectName(SchemaName, "external_table"));
var table = new Table(new PostgresqlObjectName(SchemaName, "external_table"));
table.AddColumn("id", "integer").AsPrimaryKey();

await using var dbConn = new NpgsqlConnection(ConnectionSource.ConnectionString);
Expand All @@ -40,7 +41,6 @@ public async Task InitializeAsync()
}, false);

await theStore.Advanced.Clean.DeleteDocumentsByTypeAsync(typeof(ClassWithExternalForeignKey));

}

public Task DisposeAsync()
Expand All @@ -60,10 +60,9 @@ public async Task UnitOfWork_GetTypeDependencies_Should_Not_Throw_With_ExternalF
// and finally, the function that we want to regression test"
// UnitOfWork.GetTypeDependencies(ClassWithExternalForeignKey)
await using var session = theStore.LightweightSession();
session.Insert(new ClassWithExternalForeignKey {Id = 1, ForeignId = 1});
session.Insert(new ClassWithExternalForeignKey { Id = 1, ForeignId = 1 });
await session.SaveChangesAsync();
}

}

public class ClassWithExternalForeignKey
Expand Down
Loading

0 comments on commit 38f7226

Please sign in to comment.