diff --git a/docker-compose.yml b/docker-compose.yml index 3be2661b68..3257fa7e7b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,4 +8,5 @@ services: POSTGRES_PASSWORD: postgres POSTGRES_USER: postgres POSTGRES_DB: marten_testing + NAMEDATALEN: 100 diff --git a/src/AspNetCoreWithMarten/Samples/ByNestedClosure/Startup.cs b/src/AspNetCoreWithMarten/Samples/ByNestedClosure/Startup.cs index e5d4674044..d9e34bfc1d 100644 --- a/src/AspNetCoreWithMarten/Samples/ByNestedClosure/Startup.cs +++ b/src/AspNetCoreWithMarten/Samples/ByNestedClosure/Startup.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Weasel.Postgresql; namespace AspNetCoreWithMarten.Samples.ByNestedClosure { diff --git a/src/AspNetCoreWithMarten/Samples/ByStoreOptions/Startup.cs b/src/AspNetCoreWithMarten/Samples/ByStoreOptions/Startup.cs index afaf70bd7c..65fb3eb48c 100644 --- a/src/AspNetCoreWithMarten/Samples/ByStoreOptions/Startup.cs +++ b/src/AspNetCoreWithMarten/Samples/ByStoreOptions/Startup.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Weasel.Postgresql; namespace AspNetCoreWithMarten.Samples.ByStoreOptions { diff --git a/src/AspNetCoreWithMarten/Samples/ConfiguringSessionCreation/Startup.cs b/src/AspNetCoreWithMarten/Samples/ConfiguringSessionCreation/Startup.cs index f1f35034df..ef1c16354c 100644 --- a/src/AspNetCoreWithMarten/Samples/ConfiguringSessionCreation/Startup.cs +++ b/src/AspNetCoreWithMarten/Samples/ConfiguringSessionCreation/Startup.cs @@ -1,17 +1,14 @@ -using System; using System.Data; using Marten; -using Marten.Services; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Npgsql; +using Weasel.Postgresql; namespace AspNetCoreWithMarten.Samples.ConfiguringSessionCreation { - #region sample_CustomSessionFactory + public class CustomSessionFactory: ISessionFactory { private readonly IDocumentStore _store; @@ -37,35 +34,37 @@ public IDocumentSession OpenSession() return _store.LightweightSession(IsolationLevel.Serializable); } } + #endregion sample_CustomSessionFactory #region sample_AddMartenWithCustomSessionCreation + public class Startup { - public IConfiguration Configuration { get; } - public IHostEnvironment Hosting { get; } - public Startup(IConfiguration configuration, IHostEnvironment hosting) { Configuration = configuration; Hosting = hosting; } + public IConfiguration Configuration { get; } + public IHostEnvironment Hosting { get; } + public void ConfigureServices(IServiceCollection services) { var connectionString = Configuration.GetConnectionString("postgres"); services.AddMarten(opts => - { - opts.Connection(connectionString); - - // Use the more permissive schema auto create behavior - // while in development - if (Hosting.IsDevelopment()) { - opts.AutoCreateSchemaObjects = AutoCreate.All; - } - }) + opts.Connection(connectionString); + + // Use the more permissive schema auto create behavior + // while in development + if (Hosting.IsDevelopment()) + { + opts.AutoCreateSchemaObjects = AutoCreate.All; + } + }) // Chained helper to replace the built in // session factory behavior @@ -74,5 +73,6 @@ public void ConfigureServices(IServiceCollection services) // And other methods we don't care about here... } + #endregion sample_AddMartenWithCustomSessionCreation } diff --git a/src/AspNetCoreWithMarten/Samples/PerScopeSessionCreation/Startup.cs b/src/AspNetCoreWithMarten/Samples/PerScopeSessionCreation/Startup.cs index 0995d58c9d..3e92c2ef52 100644 --- a/src/AspNetCoreWithMarten/Samples/PerScopeSessionCreation/Startup.cs +++ b/src/AspNetCoreWithMarten/Samples/PerScopeSessionCreation/Startup.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Npgsql; +using Weasel.Postgresql; namespace AspNetCoreWithMarten.Samples.PerScopeSessionCreation { diff --git a/src/AspNetCoreWithMarten/Startup.cs b/src/AspNetCoreWithMarten/Startup.cs index 9c5e750f02..106fa99e51 100644 --- a/src/AspNetCoreWithMarten/Startup.cs +++ b/src/AspNetCoreWithMarten/Startup.cs @@ -1,19 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Marten; -using Marten.Events.Daemon.Resiliency; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Weasel.Postgresql; namespace AspNetCoreWithMarten { #region sample_StartupConfigureServices + public class Startup { public IConfiguration Configuration { get; } @@ -46,6 +43,7 @@ public void ConfigureServices(IServiceCollection services) } // and other methods we don't care about right now... + #endregion sample_StartupConfigureServices // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/src/CommandLineRunner/Program.cs b/src/CommandLineRunner/Program.cs index 656db4352f..bf0d5fa403 100644 --- a/src/CommandLineRunner/Program.cs +++ b/src/CommandLineRunner/Program.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Marten; using Marten.AsyncDaemon.Testing; @@ -9,6 +6,7 @@ using Marten.Testing.Harness; using Microsoft.Extensions.Hosting; using Oakton; +using Weasel.Postgresql; namespace CommandLineRunner { @@ -19,8 +17,9 @@ public static Task Main(string[] args) return CreateHostBuilder(args).RunOaktonCommands(args); } - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) + public static IHostBuilder CreateHostBuilder(string[] args) + { + return Host.CreateDefaultBuilder(args) .ConfigureServices((hostContext, services) => { services.AddMarten(opts => @@ -34,5 +33,6 @@ public static IHostBuilder CreateHostBuilder(string[] args) => opts.Events.Projections.Add(new DistanceProjection(), ProjectionLifecycle.Async); }); }); + } } } diff --git a/src/EventPublisher/Program.cs b/src/EventPublisher/Program.cs index f13715d04f..49a6729d9b 100644 --- a/src/EventPublisher/Program.cs +++ b/src/EventPublisher/Program.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using System.Timers; using Baseline.Dates; using Marten; using Marten.AsyncDaemon.Testing.TestingSupport; using Marten.Testing.Harness; +using Weasel.Postgresql; namespace EventPublisher { diff --git a/src/EventSourceWorker/Program.cs b/src/EventSourceWorker/Program.cs index 5c8172c3a1..165ce82e3c 100644 --- a/src/EventSourceWorker/Program.cs +++ b/src/EventSourceWorker/Program.cs @@ -1,13 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Marten; using Marten.AsyncDaemon.Testing.TestingSupport; using Marten.Events.Daemon.Resiliency; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Weasel.Postgresql; namespace EventSourceWorker { diff --git a/src/Marten.AsyncDaemon.Testing/HighWaterDetectorTests.cs b/src/Marten.AsyncDaemon.Testing/HighWaterDetectorTests.cs index db318bd56c..3423ef59f8 100644 --- a/src/Marten.AsyncDaemon.Testing/HighWaterDetectorTests.cs +++ b/src/Marten.AsyncDaemon.Testing/HighWaterDetectorTests.cs @@ -5,6 +5,7 @@ using Marten.AsyncDaemon.Testing.TestingSupport; using Marten.Events; using Marten.Events.Daemon.HighWater; +using Weasel.Postgresql; using Marten.Services; using Marten.Util; using NpgsqlTypes; diff --git a/src/Marten.CommandLine.Testing/ApplyThenAssertSmokeTests.cs b/src/Marten.CommandLine.Testing/ApplyThenAssertSmokeTests.cs new file mode 100644 index 0000000000..9e24eb0b8d --- /dev/null +++ b/src/Marten.CommandLine.Testing/ApplyThenAssertSmokeTests.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using Marten.CommandLine.Commands; +using Marten.Testing.Documents; +using Marten.Testing.Harness; +using Microsoft.Extensions.Hosting; +using Xunit; + +namespace Marten.CommandLine.Testing +{ + public class ApplyThenAssertSmokeTests + { + [Fact] + public async Task do_it_all() + { + var options = new StoreOptions(); + options.Connection(ConnectionSource.ConnectionString); + options.Schema.For(); + options.Schema.For(); + + await new DocumentStore(options).Advanced.Clean.CompletelyRemoveAllAsync(); + + await new ApplyCommand().Execute(new MartenInput + { + HostBuilder = new HostBuilder().ConfigureServices(x => x.AddMarten(options)) + }); + + await new AssertCommand().Execute(new MartenInput + { + HostBuilder = new HostBuilder().ConfigureServices(x => x.AddMarten(options)) + }); + } + } +} diff --git a/src/Marten.CommandLine.Testing/AssemblyInfo.cs b/src/Marten.CommandLine.Testing/AssemblyInfo.cs new file mode 100644 index 0000000000..63bf3d35db --- /dev/null +++ b/src/Marten.CommandLine.Testing/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using Xunit; +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/src/Marten.CommandLine.Testing/DumpCommandSmokeTests.cs b/src/Marten.CommandLine.Testing/DumpCommandSmokeTests.cs index 26047a6992..f1c1fd8a0a 100644 --- a/src/Marten.CommandLine.Testing/DumpCommandSmokeTests.cs +++ b/src/Marten.CommandLine.Testing/DumpCommandSmokeTests.cs @@ -1,5 +1,6 @@ using System.IO; using System.Threading; +using System.Threading.Tasks; using Baseline; using Marten.CommandLine.Commands.Dump; using Marten.Testing.Documents; @@ -12,7 +13,7 @@ namespace Marten.CommandLine.Testing public class DumpCommandSmokeTests { [Fact] - public void can_clean_repeatedly_for_directory() + public async Task can_clean_repeatedly_for_directory() { var options = new StoreOptions(); options.Connection(ConnectionSource.ConnectionString); @@ -27,15 +28,15 @@ public void can_clean_repeatedly_for_directory() }; - new DumpCommand().Execute(input); + await new DumpCommand().Execute(input); Thread.Sleep(100); // Let the file system calm down input.HostBuilder = new HostBuilder().ConfigureServices(x => x.AddMarten(options)); - new DumpCommand().Execute(input); + await new DumpCommand().Execute(input); } [Fact] - public void can_clean_repeatedly_for_file() + public async Task can_clean_repeatedly_for_file() { var options = new StoreOptions(); options.Connection(ConnectionSource.ConnectionString); @@ -52,11 +53,11 @@ public void can_clean_repeatedly_for_file() }; - new DumpCommand().Execute(input); + await new DumpCommand().Execute(input); Thread.Sleep(100); // Let the file system calm down input.HostBuilder = new HostBuilder().ConfigureServices(x => x.AddMarten(options)); - new DumpCommand().Execute(input); + await new DumpCommand().Execute(input); } } } diff --git a/src/Marten.CommandLine.Testing/PatchCommandSmokeTests.cs b/src/Marten.CommandLine.Testing/PatchCommandSmokeTests.cs new file mode 100644 index 0000000000..95cbf37e2a --- /dev/null +++ b/src/Marten.CommandLine.Testing/PatchCommandSmokeTests.cs @@ -0,0 +1,35 @@ +using System.IO; +using System.Reflection.Metadata; +using System.Threading.Tasks; +using Baseline; +using Marten.CommandLine.Commands.Patch; +using Marten.Testing.Documents; +using Marten.Testing.Harness; +using Microsoft.Extensions.Hosting; +using Xunit; + +namespace Marten.CommandLine.Testing +{ + public class PatchCommandSmokeTests + { + + [Fact] + public async Task can_write_both_files() + { + var options = new StoreOptions(); + options.Connection(ConnectionSource.ConnectionString); + options.Schema.For(); + options.Schema.For(); + + var input = new PatchInput() + { + HostBuilder = new HostBuilder().ConfigureServices(x => x.AddMarten(options)), + FileName = Path.GetTempPath().AppendPath("dump1.sql"), + + + }; + + await new PatchCommand().Execute(input); + } + } +} diff --git a/src/Marten.CommandLine/Commands/ApplyCommand.cs b/src/Marten.CommandLine/Commands/ApplyCommand.cs index 587a97bb40..c616163e3f 100644 --- a/src/Marten.CommandLine/Commands/ApplyCommand.cs +++ b/src/Marten.CommandLine/Commands/ApplyCommand.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Oakton; namespace Marten.CommandLine.Commands @@ -6,11 +7,11 @@ namespace Marten.CommandLine.Commands [Description("Applies all outstanding changes to the database based on the current configuration", Name = "marten-apply")] public class ApplyCommand: MartenCommand { - protected override bool execute(IDocumentStore store, MartenInput input) + protected override async Task execute(IDocumentStore store, MartenInput input) { try { - store.Schema.ApplyAllConfiguredChangesToDatabase(); + await store.Schema.ApplyAllConfiguredChangesToDatabase(); input.WriteLine(ConsoleColor.Green, "Successfully applied outstanding database changes"); return true; diff --git a/src/Marten.CommandLine/Commands/AssertCommand.cs b/src/Marten.CommandLine/Commands/AssertCommand.cs index ee8ac46e2a..995b309b0c 100644 --- a/src/Marten.CommandLine/Commands/AssertCommand.cs +++ b/src/Marten.CommandLine/Commands/AssertCommand.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Marten.Exceptions; using Marten.Schema; using Oakton; @@ -8,11 +9,11 @@ namespace Marten.CommandLine.Commands [Description("Assert that the existing database matches the current Marten configuration", Name = "marten-assert")] public class AssertCommand: MartenCommand { - protected override bool execute(IDocumentStore store, MartenInput input) + protected override async Task execute(IDocumentStore store, MartenInput input) { try { - store.Schema.AssertDatabaseMatchesConfiguration(); + await store.Schema.AssertDatabaseMatchesConfiguration(); input.WriteLine(ConsoleColor.Green, "No database differences detected."); diff --git a/src/Marten.CommandLine/Commands/Dump/DumpCommand.cs b/src/Marten.CommandLine/Commands/Dump/DumpCommand.cs index 24e8ce9aa4..6e2b6684a5 100644 --- a/src/Marten.CommandLine/Commands/Dump/DumpCommand.cs +++ b/src/Marten.CommandLine/Commands/Dump/DumpCommand.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Threading.Tasks; using Baseline; using Oakton; @@ -14,12 +15,12 @@ public DumpCommand() .Arguments(x => x.FileName); } - protected override bool execute(IDocumentStore store, DumpInput input) + protected override Task execute(IDocumentStore store, DumpInput input) { if (input.ByTypeFlag) { input.WriteLine("Writing DDL files to " + input.FileName); - store.Schema.WriteDDLByType(input.FileName, input.TransactionalScriptFlag); + store.Schema.WriteDatabaseCreationScriptByType(input.FileName); // You only need to clean out the existing folder when dumping // by type @@ -41,10 +42,10 @@ protected override bool execute(IDocumentStore store, DumpInput input) - store.Schema.WriteDDL(input.FileName, input.TransactionalScriptFlag); + store.Schema.WriteDatabaseCreationScriptFile(input.FileName); } - return true; + return Task.FromResult(true); } } } diff --git a/src/Marten.CommandLine/Commands/Patch/PatchCommand.cs b/src/Marten.CommandLine/Commands/Patch/PatchCommand.cs index e591821c79..18b81fa238 100644 --- a/src/Marten.CommandLine/Commands/Patch/PatchCommand.cs +++ b/src/Marten.CommandLine/Commands/Patch/PatchCommand.cs @@ -1,7 +1,9 @@ using System; +using System.Threading.Tasks; +using Baseline; using Marten.Exceptions; -using Marten.Schema; using Oakton; +using Weasel.Postgresql; namespace Marten.CommandLine.Commands.Patch { @@ -15,11 +17,11 @@ public PatchCommand() Usage("Write the patch and matching drop file").Arguments(x => x.FileName); } - protected override bool execute(IDocumentStore store, PatchInput input) + protected override async Task execute(IDocumentStore store, PatchInput input) { try { - store.Schema.AssertDatabaseMatchesConfiguration(); + await store.Schema.AssertDatabaseMatchesConfiguration(); input.WriteLine(ConsoleColor.Green, "No differences were detected between the Marten configuration and the database"); @@ -27,15 +29,20 @@ protected override bool execute(IDocumentStore store, PatchInput input) } catch (SchemaValidationException) { - var patch = store.Schema.ToPatch(input.SchemaFlag, withAutoCreateAll: true); + var patch = await store.Schema.CreateMigration(); input.WriteLine(ConsoleColor.Green, "Wrote a patch file to " + input.FileName); - patch.WriteUpdateFile(input.FileName, input.TransactionalScriptFlag); - var dropFile = input.DropFlag ?? SchemaPatch.ToDropFileName(input.FileName); + var rules = store.Options.As().Advanced.DdlRules; + rules.IsTransactional = input.TransactionalScriptFlag; + + rules.WriteTemplatedFile(input.FileName, (r, w) => patch.WriteAllUpdates(w, r, AutoCreate.CreateOrUpdate)); + + var dropFile = input.DropFlag ?? SchemaMigration.ToDropFileName(input.FileName); input.WriteLine(ConsoleColor.Green, "Wrote the drop file to " + dropFile); - patch.WriteRollbackFile(dropFile, input.TransactionalScriptFlag); + + rules.WriteTemplatedFile(input.FileName, (r, w) => patch.WriteAllRollbacks(w, r)); return true; } diff --git a/src/Marten.CommandLine/Commands/Patch/PatchInput.cs b/src/Marten.CommandLine/Commands/Patch/PatchInput.cs index 453690b50f..5125729fc9 100644 --- a/src/Marten.CommandLine/Commands/Patch/PatchInput.cs +++ b/src/Marten.CommandLine/Commands/Patch/PatchInput.cs @@ -7,8 +7,6 @@ public class PatchInput: MartenInput [Description("File (or folder) location to write the DDL file")] public string FileName { get; set; } - [Description("Opt into also writing out any missing schema creation scripts")] - public bool SchemaFlag { get; set; } [Description("Override the location of the drop file")] public string DropFlag { get; set; } diff --git a/src/Marten.CommandLine/MartenCommand.cs b/src/Marten.CommandLine/MartenCommand.cs index 048666c971..71933a01ec 100644 --- a/src/Marten.CommandLine/MartenCommand.cs +++ b/src/Marten.CommandLine/MartenCommand.cs @@ -1,21 +1,18 @@ +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Oakton; namespace Marten.CommandLine { - public abstract class MartenCommand: OaktonCommand where T : MartenInput + public abstract class MartenCommand: OaktonAsyncCommand where T : MartenInput { - public override bool Execute(T input) + public override async Task Execute(T input) { try { - using (var host = input.BuildHost()) - { - using (var store = host.Services.GetRequiredService()) - { - return execute(store, input); - } - } + using var host = input.BuildHost(); + var store = host.Services.GetRequiredService(); + return await execute(store, input); } finally { @@ -23,6 +20,6 @@ public override bool Execute(T input) } } - protected abstract bool execute(IDocumentStore store, T input); + protected abstract Task execute(IDocumentStore store, T input); } } diff --git a/src/Marten.NodaTime.Testing/Acceptance/noda_time_acceptance.cs b/src/Marten.NodaTime.Testing/Acceptance/noda_time_acceptance.cs index 870591ec0d..d72b484b76 100644 --- a/src/Marten.NodaTime.Testing/Acceptance/noda_time_acceptance.cs +++ b/src/Marten.NodaTime.Testing/Acceptance/noda_time_acceptance.cs @@ -10,6 +10,7 @@ using Marten.Testing.Harness; using NodaTime; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.NodaTime.Testing.Acceptance diff --git a/src/Marten.Schema.Testing/ApplyAllConfiguredChangesToDatabaseTests.cs b/src/Marten.Schema.Testing/ApplyAllConfiguredChangesToDatabaseTests.cs index ae27e0e6f9..7c5ac06e19 100644 --- a/src/Marten.Schema.Testing/ApplyAllConfiguredChangesToDatabaseTests.cs +++ b/src/Marten.Schema.Testing/ApplyAllConfiguredChangesToDatabaseTests.cs @@ -1,5 +1,7 @@ +using System.Threading.Tasks; using Marten.Schema.Testing.Documents; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing @@ -7,7 +9,7 @@ namespace Marten.Schema.Testing public class ApplyAllConfiguredChangesToDatabaseTests : IntegrationContext { [Fact] - public void can_apply_schema_changes_independent_of_store_options_auto_create() + public async Task can_apply_schema_changes_independent_of_store_options_auto_create() { StoreOptions(_ => { @@ -16,16 +18,16 @@ public void can_apply_schema_changes_independent_of_store_options_auto_create() _.AutoCreateSchemaObjects = AutoCreate.None; }); - // should not throw SchemaValidationException - Should.NotThrow(() => + + await Should.NotThrowAsync(async () => { - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - theStore.Schema.AssertDatabaseMatchesConfiguration(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.AssertDatabaseMatchesConfiguration(); }); } [Fact] - public void can_apply_schema_changes_with_create_options_independent_of_store_options_auto_create() + public async Task can_apply_schema_changes_with_create_options_independent_of_store_options_auto_create() { StoreOptions(_ => { @@ -34,11 +36,10 @@ public void can_apply_schema_changes_with_create_options_independent_of_store_op _.AutoCreateSchemaObjects = AutoCreate.None; }); - // should not throw SchemaValidationException - Should.NotThrow(() => + await Should.NotThrowAsync(async () => { - theStore.Schema.ApplyAllConfiguredChangesToDatabase(AutoCreate.All); - theStore.Schema.AssertDatabaseMatchesConfiguration(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(AutoCreate.All); + await theStore.Schema.AssertDatabaseMatchesConfiguration(); }); } diff --git a/src/Marten.Schema.Testing/Bugs/Bug_145_table_getting_erroneously_regenerated_Tests.cs b/src/Marten.Schema.Testing/Bugs/Bug_145_table_getting_erroneously_regenerated_Tests.cs index 670bf15e39..47b94710cf 100644 --- a/src/Marten.Schema.Testing/Bugs/Bug_145_table_getting_erroneously_regenerated_Tests.cs +++ b/src/Marten.Schema.Testing/Bugs/Bug_145_table_getting_erroneously_regenerated_Tests.cs @@ -2,6 +2,9 @@ using System.IO; using Baseline; using Marten.Storage; +using Shouldly; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Schema.Testing.Bugs @@ -29,17 +32,9 @@ public void does_not_regenerate_the_login_table() var mapping = theStore.Storage.MappingFor(typeof(Login)); var configured = new DocumentTable(mapping.As()); - if (!existing.Equals(configured)) - { - var writer = new StringWriter(); - writer.WriteLine("Expected:"); - configured.Write(theStore.Schema.DdlRules, writer); - writer.WriteLine(); - writer.WriteLine("But from the database, was:"); - existing.Write(theStore.Schema.DdlRules, writer); - - throw new Exception(writer.ToString()); - } + var delta = new TableDelta(configured, existing); + delta.Difference.ShouldBe(SchemaPatchDifference.None); + } } diff --git a/src/Marten.Schema.Testing/DbObjectsTests.cs b/src/Marten.Schema.Testing/DbObjectsTests.cs index 0e78d2859c..aa869cf04c 100644 --- a/src/Marten.Schema.Testing/DbObjectsTests.cs +++ b/src/Marten.Schema.Testing/DbObjectsTests.cs @@ -1,5 +1,7 @@ using System.Linq; +using System.Threading.Tasks; using Baseline; +using Weasel.Postgresql; using Marten.Schema.Testing.Documents; using Shouldly; using Xunit; @@ -9,36 +11,9 @@ namespace Marten.Schema.Testing [Collection("dbobjects")] public class DbObjectsTests : IntegrationContext { - [Fact] - public void can_fetch_indexes_for_a_table_in_public() - { - var store1 = StoreOptions(_ => - { - _.DatabaseSchemaName = "other"; - _.Schema.For().Duplicate(x => x.UserName).Duplicate(x => x.Internal); - }).As(); - - store1.Tenancy.Default.EnsureStorageExists(typeof(User)); - - var store2 = StoreOptions(_ => - { - _.DatabaseSchemaName = Marten.StoreOptions.DefaultDatabaseSchemaName; - _.Schema.For().Duplicate(x => x.UserName).Duplicate(x => x.FirstName); - }).As(); - - store2.Tenancy.Default.EnsureStorageExists(typeof(User)); - - var indices = store2.Tenancy.Default.DbObjects.AllIndexes(); - - indices.Any(x => Equals(x.Table, store1.Storage.MappingFor(typeof(User)).TableName)) - .ShouldBeFalse(); - - indices.Any(x => Equals(x.Table, store2.Storage.MappingFor(typeof(User)).TableName)) - .ShouldBeTrue(); - } [Fact] - public void can_fetch_the_function_ddl() + public async Task can_fetch_the_function_ddl() { var store1 = StoreOptions(_ => { @@ -50,9 +25,9 @@ public void can_fetch_the_function_ddl() var upsert = store1.Storage.MappingFor(typeof(User)).As().UpsertFunction; - var functionBody = store1.Tenancy.Default.DbObjects.DefinitionForFunction(upsert); + var functionBody = await store1.Tenancy.Default.DefinitionForFunction(upsert); - functionBody.Body.ShouldContain( "mt_doc_user"); + functionBody.Body().ShouldContain( "mt_doc_user"); } } diff --git a/src/Marten.Schema.Testing/DocumentCleanerTests.cs b/src/Marten.Schema.Testing/DocumentCleanerTests.cs index 011d06f800..e321596f21 100644 --- a/src/Marten.Schema.Testing/DocumentCleanerTests.cs +++ b/src/Marten.Schema.Testing/DocumentCleanerTests.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using Baseline; using Marten.Schema.Testing.Documents; using Shouldly; @@ -27,7 +28,7 @@ public void clean_table() theSession.SaveChanges(); theSession.Dispose(); - theCleaner.DeleteDocumentsFor(typeof(Target)); + theCleaner.DeleteDocumentsByType(typeof(Target)); using (var session = theStore.QuerySession()) { @@ -59,7 +60,7 @@ public void delete_all_documents() } [Fact] - public void completely_remove_document_type() + public async Task completely_remove_document_type() { theSession.Store(new Target { Number = 1 }); theSession.Store(new Target { Number = 2 }); @@ -69,37 +70,35 @@ public void completely_remove_document_type() var tableName = theStore.Storage.MappingFor(typeof(Target)).TableName; - theStore.Tenancy.Default.DbObjects.DocumentTables().Contains(tableName) + (await theStore.Tenancy.Default.DocumentTables()).Contains(tableName) .ShouldBeTrue(); theCleaner.CompletelyRemove(typeof(Target)); - theStore.Tenancy.Default.DbObjects.DocumentTables().Contains(tableName) + (await theStore.Tenancy.Default.DocumentTables()).Contains(tableName) .ShouldBeFalse(); } [Fact] - public void completely_remove_document_removes_the_upsert_command_too() + public async Task completely_remove_document_removes_the_upsert_command_too() { theSession.Store(new Target { Number = 1 }); theSession.Store(new Target { Number = 2 }); - theSession.SaveChanges(); - - var dbObjects = theStore.Tenancy.Default.DbObjects; + await theSession.SaveChangesAsync(); var upsertName = theStore.Storage.MappingFor(typeof(Target)).As().UpsertFunction; - dbObjects.Functions().ShouldContain(upsertName); + (await theStore.Tenancy.Default.Functions()).ShouldContain(upsertName); theCleaner.CompletelyRemove(typeof(Target)); - dbObjects.Functions().Contains(upsertName) - .ShouldBeFalse(); + (await theStore.Tenancy.Default.Functions()).ShouldNotContain(upsertName); + } [Fact] - public void completely_remove_everything() + public async Task completely_remove_everything() { theSession.Store(new Target { Number = 1 }); theSession.Store(new Target { Number = 2 }); @@ -107,15 +106,16 @@ public void completely_remove_everything() theSession.Store(new Company()); theSession.Store(new Issue()); - theSession.SaveChanges(); + await theSession.SaveChangesAsync(); theSession.Dispose(); - theCleaner.CompletelyRemoveAll(); - - var dbObjects = theStore.Tenancy.Default.DbObjects; + await theCleaner.CompletelyRemoveAllAsync(); + var tables = await theStore.Tenancy.Default.DocumentTables(); + tables.ShouldBeEmpty(); - ShouldBeEmpty(dbObjects.DocumentTables()); - ShouldBeEmpty(dbObjects.Functions().Where(x => x.Name != "mt_immutable_timestamp" || x.Name != "mt_immutable_timestamptz").ToArray()); + var functions = await theStore.Tenancy.Default.Functions(); + functions.Where(x => x.Name != "mt_immutable_timestamp" || x.Name != "mt_immutable_timestamptz") + .ShouldBeEmpty(); } [Fact] @@ -132,6 +132,21 @@ public void delete_all_event_data() theSession.Events.FetchStream(streamId).ShouldBeEmpty(); } + + [Fact] + public async Task delete_all_event_data_async() + { + var streamId = Guid.NewGuid(); + theSession.Events.StartStream(streamId, new QuestStarted()); + + await theSession.SaveChangesAsync(); + + await theCleaner.DeleteAllEventDataAsync(); + + theSession.Events.QueryRawEventDataOnly().ShouldBeEmpty(); + (await theSession.Events.FetchStreamAsync(streamId)).ShouldBeEmpty(); + } + private static void ShouldBeEmpty(T[] documentTables) { var stillInDatabase = string.Join(",", documentTables); @@ -165,24 +180,46 @@ public void delete_except_types() } [Fact] - public void CanCleanSequences() + public async Task delete_except_types_async() + { + theSession.Store(new Target { Number = 1 }); + theSession.Store(new Target { Number = 2 }); + theSession.Store(new User()); + theSession.Store(new Company()); + theSession.Store(new Issue()); + + await theSession.SaveChangesAsync(); + theSession.Dispose(); + + await theCleaner.DeleteDocumentsExceptAsync(typeof(Target), typeof(User)); + + using var session = theStore.OpenSession(); + // Not cleaned off + session.Query().Count().ShouldBe(2); + session.Query().Count().ShouldBe(1); + + // Should be cleaned off + session.Query().Count().ShouldBe(0); + session.Query().Count().ShouldBe(0); + } + + [Fact] + public async Task CanCleanSequences() { StoreOptions(opts => { opts.Events.AddEventType(typeof(MembersJoined)); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); var allSchemas = theStore.Storage.AllSchemaNames(); int GetSequenceCount(IDocumentStore store) { - using (var session = store.QuerySession()) - { - return session.Query(@"select count(*) from information_schema.sequences s + using var session = store.QuerySession(); + return session.Query(@"select count(*) from information_schema.sequences s where s.sequence_name like ? and s.sequence_schema = any(?);", "mt_%", allSchemas).First(); - } } GetSequenceCount(theStore).ShouldBeGreaterThan(0); diff --git a/src/Marten.Schema.Testing/DocumentMappingTests.cs b/src/Marten.Schema.Testing/DocumentMappingTests.cs index 25e61e6356..fecbfc7981 100644 --- a/src/Marten.Schema.Testing/DocumentMappingTests.cs +++ b/src/Marten.Schema.Testing/DocumentMappingTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using Baseline; using LamarCodeGeneration; using Marten.Linq.Fields; @@ -14,6 +15,8 @@ using Marten.Testing.Harness; using NpgsqlTypes; using Shouldly; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Schema.Testing @@ -337,19 +340,17 @@ public void find_field_for_immediate_property_that_is_not_duplicated() } [Fact] - public void generate_a_table_to_the_database_with_duplicated_field() + public async Task generate_a_table_to_the_database_with_duplicated_field() { - using (var store = DocumentStore.For(ConnectionSource.ConnectionString)) - { - store.Advanced.Clean.CompletelyRemove(typeof(User)); + using var store = DocumentStore.For(ConnectionSource.ConnectionString); + store.Advanced.Clean.CompletelyRemove(typeof(User)); - var mapping = store.Storage.MappingFor(typeof(User)).As(); - mapping.DuplicateField(nameof(User.FirstName)); + var mapping = store.Storage.MappingFor(typeof(User)).As(); + mapping.DuplicateField(nameof(User.FirstName)); - store.Tenancy.Default.EnsureStorageExists(typeof(User)); + store.Tenancy.Default.EnsureStorageExists(typeof(User)); - store.Tenancy.Default.DbObjects.DocumentTables().ShouldContain(mapping.TableName.QualifiedName); - } + (await store.Tenancy.Default.DocumentTables()).Select(x => x.QualifiedName).ShouldContain(mapping.TableName.QualifiedName); } [Fact] @@ -505,11 +506,11 @@ public void picks_up_marten_attribute_on_document_type() public void picks_up_marten_ginindexed_attribute_on_document_type() { var mapping = DocumentMapping.For(); - var indexDefinition = mapping.Indexes.Cast().Single(x => x.Columns.First() == "data"); + var indexDefinition = mapping.Indexes.Cast().Single(x => x.Columns.First() == "data"); indexDefinition.Method.ShouldBe(IndexMethod.gin); var mappingSub = DocumentMapping.For(); - indexDefinition = mappingSub.Indexes.Cast().Single(x => x.Columns.First() == "data"); + indexDefinition = mappingSub.Indexes.Cast().Single(x => x.Columns.First() == "data"); indexDefinition.Method.ShouldBe(IndexMethod.gin); } @@ -570,7 +571,7 @@ public void to_table_columns_with_duplicated_fields() var table = new DocumentTable(mapping); - table.Select(x => x.Name) + table.Columns.Select(x => x.Name) .ShouldHaveTheSameElementsAs("id", "data", SchemaConstants.LastModifiedColumn, SchemaConstants.VersionColumn, SchemaConstants.DotNetTypeColumn, "first_name"); } @@ -583,7 +584,7 @@ public void to_table_columns_with_subclasses() var table = new DocumentTable(mapping); - var typeColumn = table.Last(); + var typeColumn = table.Columns.Last(); typeColumn.Name.ShouldBe(SchemaConstants.DocumentTypeColumn); typeColumn.Type.ShouldBe("varchar"); } @@ -593,7 +594,7 @@ public void to_table_without_subclasses_and_no_duplicated_fields() { var mapping = DocumentMapping.For(); var table = new DocumentTable(mapping); - table.Select(x => x.Name) + table.Columns.Select(x => x.Name) .ShouldHaveTheSameElementsAs("id", "data", SchemaConstants.LastModifiedColumn, SchemaConstants.VersionColumn, SchemaConstants.DotNetTypeColumn); } @@ -751,7 +752,7 @@ public void add_the_tenant_id_column_when_it_is_conjoined_tenancy() mapping.TenancyStyle = TenancyStyle.Conjoined; var table = new DocumentTable(mapping); - table.Any(x => x is TenantIdColumn).ShouldBeTrue(); + table.Columns.Any(x => x is TenantIdColumn).ShouldBeTrue(); } [Fact] diff --git a/src/Marten.Schema.Testing/DocumentMapping_schema_patch_foreign_key_writing.cs b/src/Marten.Schema.Testing/DocumentMapping_schema_patch_foreign_key_writing.cs deleted file mode 100644 index 06db1fa37e..0000000000 --- a/src/Marten.Schema.Testing/DocumentMapping_schema_patch_foreign_key_writing.cs +++ /dev/null @@ -1,427 +0,0 @@ -using Marten.Schema.Testing.Documents; -using Marten.Testing.Harness; -using Marten.Util; -using Xunit; - -namespace Marten.Schema.Testing -{ - public class DocumentMapping_schema_patch_foreign_key_writing: IntegrationContext - { - [Fact] - public void can_update_foreignkeys_todocuments_with_cascade_delete_that_were_added() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = true); - })) - { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = false); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldContain("DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES public.mt_doc_user (id);", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain(@"DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - patch.RollbackDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES mt_doc_user(id) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - [Fact] - public void can_update_foreignkeys_todocuments_without_cascade_delete_that_were_added() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = false); - })) - { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = true); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldContain("DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES public.mt_doc_user (id) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain(@"DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - patch.RollbackDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES mt_doc_user(id);", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - [Fact] - public void can_create_and_drop_foreignkeys_toexternaltable_that_were_added() - { - CreateNonMartenTable(); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(i => i.BugId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = true); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_bug_id_fkey FOREIGN KEY (bug_id) - REFERENCES bugtracker.bugs (bugid) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - [Fact] - public void can_update_foreignkeys_toexternaltable_with_cascade_delete_that_were_added() - { - CreateNonMartenTable(); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(i => i.BugId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = true); - })) - { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(i => i.BugId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = false); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldContain("DROP CONSTRAINT mt_doc_issue_bug_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_bug_id_fkey FOREIGN KEY (bug_id) - REFERENCES bugtracker.bugs (bugid)", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain(@"DROP CONSTRAINT mt_doc_issue_bug_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - patch.RollbackDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_bug_id_fkey FOREIGN KEY (bug_id) - REFERENCES bugtracker.bugs(bugid) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - [Fact] - public void can_update_foreignkeys_toexternaltable_without_cascade_delete_that_were_added() - { - CreateNonMartenTable(); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(i => i.BugId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = false); - })) - { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - - using (var store = DocumentStore.For(_ => - { - _.AutoCreateSchemaObjects = AutoCreate.All; - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(i => i.BugId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = true); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldContain("DROP CONSTRAINT mt_doc_issue_bug_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_bug_id_fkey FOREIGN KEY (bug_id) - REFERENCES bugtracker.bugs (bugid) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain(@"DROP CONSTRAINT mt_doc_issue_bug_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - patch.RollbackDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_bug_id_fkey FOREIGN KEY (bug_id) - REFERENCES bugtracker.bugs(bugid);", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - [Fact] - public void can_add_foreignkeys_toexternaltable_and_delete_that_were_added_asdocument_and_does_not_exist() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - CreateNonMartenTable(); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = false); - })) - { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - - using (var store = DocumentStore.For(_ => - { - _.AutoCreateSchemaObjects = AutoCreate.All; - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(i => i.BugId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = true); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldContain("DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_bug_id_fkey FOREIGN KEY (bug_id) - REFERENCES bugtracker.bugs (bugid) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain(@"DROP CONSTRAINT mt_doc_issue_bug_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES mt_doc_user(id);", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - [Fact] - public void can_add_foreignkeys_todocuments_and_delete_that_were_added_asexternaltable_and_does_not_exist() - { - theStore.Advanced.Clean.CompletelyRemoveAll(); - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - CreateNonMartenTable(); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(i => i.BugId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = false); - })) - { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - - using (var store = DocumentStore.For(_ => - { - _.AutoCreateSchemaObjects = AutoCreate.All; - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = true); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldContain("DROP CONSTRAINT mt_doc_issue_bug_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES public.mt_doc_user (id) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain(@"DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - patch.RollbackDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_bug_id_fkey FOREIGN KEY (bug_id) - REFERENCES bugtracker.bugs(bugid);", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - [Fact] - public void can_add_foreignkeys_toexternaltable_and_keep_that_were_added_asdocument_and_exists() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - CreateNonMartenTable(); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = false); - })) - { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - - using (var store = DocumentStore.For(_ => - { - _.AutoCreateSchemaObjects = AutoCreate.All; - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = false); - _.Schema.For().ForeignKey(i => i.BugId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = true); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldNotContain("DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_bug_id_fkey FOREIGN KEY (bug_id) - REFERENCES bugtracker.bugs (bugid) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain(@"DROP CONSTRAINT mt_doc_issue_bug_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldNotContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES mt_doc_user(id);", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - [Fact] - public void can_add_foreignkeys_todocuments_and_keep_that_were_added_asexternaltable_and_exists() - { - theStore.Advanced.Clean.CompletelyRemoveAll(); - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - CreateNonMartenTable(); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(i => i.BugId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = false); - })) - { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - - using (var store = DocumentStore.For(_ => - { - _.AutoCreateSchemaObjects = AutoCreate.All; - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(i => i.BugId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = false); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = true); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldNotContain("DROP CONSTRAINT mt_doc_issue_bug_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES public.mt_doc_user (id) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain(@"DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - patch.RollbackDDL.ShouldNotContain(@"ADD CONSTRAINT mt_doc_issue_bug_id_fkey FOREIGN KEY (assignee_id) - REFERENCES bugtracker.bugs(bugid);", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - [Fact] - public void can_replace_foreignkeys_from_todocuments_to_asexternaltable() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - CreateNonMartenTable(); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = false); - })) - { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - - using (var store = DocumentStore.For(_ => - { - _.AutoCreateSchemaObjects = AutoCreate.All; - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(i => i.AssigneeId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = true); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldContain("DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES bugtracker.bugs (bugid) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain("DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES mt_doc_user(id);", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - [Fact] - public void can_replace_foreignkeys_from_asexternaltable_to_todocuments() - { - theStore.Advanced.Clean.CompletelyRemoveAll(); - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - CreateNonMartenTable(); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(i => i.AssigneeId, "bugtracker", "bugs", "bugid", fkd => fkd.CascadeDeletes = false); - })) - { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - - using (var store = DocumentStore.For(_ => - { - _.AutoCreateSchemaObjects = AutoCreate.All; - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = true); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldContain("DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES public.mt_doc_user (id) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain("DROP CONSTRAINT mt_doc_issue_assignee_id_fkey;", StringComparisonOption.NormalizeWhitespaces); - - patch.RollbackDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES bugtracker.bugs(bugid);", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - private void CreateNonMartenTable() - { - using (var sesion = theStore.OpenSession()) - { - sesion.Connection.RunSql(@"CREATE SCHEMA IF NOT EXISTS bugtracker;"); - sesion.Connection.RunSql( - @"CREATE TABLE IF NOT EXISTS bugtracker.bugs ( - bugid uuid CONSTRAINT pk_mt_streams PRIMARY KEY, - name varchar(100) NULL - )"); - } - } - - } -} diff --git a/src/Marten.Schema.Testing/DocumentMapping_schema_patch_writing.cs b/src/Marten.Schema.Testing/DocumentMapping_schema_patch_writing.cs deleted file mode 100644 index f7891a4bbe..0000000000 --- a/src/Marten.Schema.Testing/DocumentMapping_schema_patch_writing.cs +++ /dev/null @@ -1,242 +0,0 @@ -using System; -using Marten.Schema.Testing.Documents; -using Marten.Testing.Harness; -using Shouldly; -using Xunit; - -namespace Marten.Schema.Testing -{ - public class DocumentMapping_schema_patch_writing: IntegrationContext - { - [Fact] - public void creates_the_table_in_update_ddl_if_all_new() - { - StoreOptions(_ => - { - _.Schema.For(); - }); - - var patch = theStore.Schema.ToPatch(); - - patch.UpdateDDL.ShouldContain($"CREATE TABLE public.mt_doc_user"); - patch.UpdateDDL.ShouldContain($"CREATE OR REPLACE FUNCTION public.mt_upsert_user(doc JSONB, docDotNetType varchar, docId uuid, docVersion uuid) RETURNS UUID LANGUAGE plpgsql SECURITY INVOKER AS $function$"); - } - - [Fact] - public void drops_the_table_in_rollback_if_all_new() - { - var schemaName = StoreOptions(_ => - { - _.Schema.For(); - }); - - var patch = theStore.Schema.ToPatch(); - - patch.RollbackDDL.ShouldContain($"drop table if exists public.mt_doc_user cascade;"); - } - - [Fact] - public void drops_the_table_in_rollback_if_all_new_different_schema() - { - StoreOptions(_ => - { - _.Schema.For(); - _.DatabaseSchemaName = "other"; - }); - - var patch = theStore.Schema.ToPatch(); - - patch.RollbackDDL.ShouldContain("drop table if exists other.mt_doc_user cascade;"); - } - - [Fact] - public void does_not_drop_the_table_if_it_all_exists() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - - var patch = theStore.Schema.ToPatch(); - - patch.RollbackDDL.ShouldNotContain("drop table if exists public.mt_doc_user cascade;"); - } - - [Fact] - public void can_drop_added_columns_in_document_storage() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().Duplicate(x => x.UserName); - })) - { - var patch = store.Schema.ToPatch(); - - patch.RollbackDDL.ShouldContain("alter table if exists public.mt_doc_user drop column if exists user_name;"); - } - } - - [Fact] - public void can_drop_indexes_that_were_added() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().Index(x => x.UserName); - })) - { - var patch = store.Schema.ToPatch(); - - patch.RollbackDDL.ShouldContain("drop index concurrently if exists public.mt_doc_user_idx_user_name;"); - } - } - - [Fact] - public void can_revert_indexes_that_changed() - { - StoreOptions(_ => - { - _.Schema.For() - .Duplicate(x => x.UserName, configure: i => i.Method = IndexMethod.btree); - }); - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For() - .Duplicate(x => x.UserName, configure: i => i.Method = IndexMethod.hash); - })) - { - var patch = store.Schema.ToPatch(); - - patch.RollbackDDL.ShouldContain("drop index"); - - patch.RollbackDDL.ShouldContain("CREATE INDEX mt_doc_user_idx_user_name"); - } - } - - [Fact] - public void can_revert_indexes_that_changed_in_non_public_schema() - { - StoreOptions(_ => - { - _.DatabaseSchemaName = "other"; - _.Schema.For() - .Duplicate(x => x.UserName, configure: i => i.Method = IndexMethod.btree); - }); - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - - using (var store = DocumentStore.For(_ => - { - _.DatabaseSchemaName = "other"; - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For() - .Duplicate(x => x.UserName, configure: i => i.Method = IndexMethod.hash); - })) - { - var patch = store.Schema.ToPatch(); - - patch.RollbackDDL.ShouldContain("drop index other.mt_doc_user_idx_user_name;"); - - patch.RollbackDDL.ShouldContain("CREATE INDEX mt_doc_user_idx_user_name ON other.mt_doc_user USING btree (user_name);"); - } - } - - [Fact] - public void can_create_and_drop_foreignkeys_todocuments_that_were_added() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = true); - })) - { - var patch = store.Schema.ToPatch(); - - patch.UpdateDDL.ShouldContain(@"ADD CONSTRAINT mt_doc_issue_assignee_id_fkey FOREIGN KEY (assignee_id) - REFERENCES public.mt_doc_user (id) - ON DELETE CASCADE;", StringComparisonOption.NormalizeWhitespaces); - - store.Schema.ApplyAllConfiguredChangesToDatabase(); - } - } - - [Fact] - public void for_document_with_int_id_when_schema_patch_applied_then_does_not_show_more_changes() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(IntDoc)); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For(); - })) - { - Should.NotThrow(() => - { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - - store.Schema.AssertDatabaseMatchesConfiguration(); - }); - } - } - - [Fact] - public void can_create_duplicate_field_with_null_constraint() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(Target)); - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().Duplicate(x => x.NullableDateTime); - })) - { - var patch = store.Schema.ToPatch(); - SpecificationExtensions.ShouldContain(patch.UpdateDDL, "alter table public.mt_doc_target add column nullable_date_time timestamp without time zone NULL"); - } - } - - [Fact] - public void can_create_duplicate_field_with_not_null_constraint() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(Target)); - - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().Duplicate(x => x.Date, notNull: true); - })) - { - var patch = store.Schema.ToPatch(); - SpecificationExtensions.ShouldContain(patch.UpdateDDL, "alter table public.mt_doc_target add column date timestamp without time zone NOT NULL"); - } - } - - [Fact] - public void can_create_duplicate_field_with_not_null_constraint_using_duplicate_field_attribute() - { - using (var store = DocumentStore.For(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For(); - })) - { - var patch = store.Schema.ToPatch(); - SpecificationExtensions.ShouldContain(patch.UpdateDDL, "non_nullable_duplicate_field timestamp without time zone NOT NULL"); - } - } - - } - - public class NonNullableDuplicateFieldTest - { - public Guid Id { get; set; } - [DuplicateField(NotNull = true)] - public DateTime NonNullableDuplicateField { get; set; } - } -} diff --git a/src/Marten.Schema.Testing/DocumentSchemaOnOtherSchemaTests.cs b/src/Marten.Schema.Testing/DocumentSchemaOnOtherSchemaTests.cs index 694ca453d8..28e6b6dc42 100644 --- a/src/Marten.Schema.Testing/DocumentSchemaOnOtherSchemaTests.cs +++ b/src/Marten.Schema.Testing/DocumentSchemaOnOtherSchemaTests.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using Baseline; using Marten.Events; using Marten.Exceptions; @@ -32,7 +33,7 @@ public void generate_ddl() - var sql = theSchema.ToDDL(); + var sql = theSchema.ToDatabaseScript(); sql.ShouldContain("CREATE OR REPLACE FUNCTION other.mt_upsert_user"); sql.ShouldContain("CREATE OR REPLACE FUNCTION other.mt_upsert_issue"); @@ -48,7 +49,7 @@ public void do_not_write_event_sql_if_the_event_graph_is_not_active() { theStore.Events.IsActive(null).ShouldBeFalse(); - theSchema.ToDDL().ShouldNotContain("other.mt_streams"); + theSchema.ToDatabaseScript().ShouldNotContain("other.mt_streams"); } [Fact] @@ -57,22 +58,22 @@ public void do_write_the_event_sql_if_the_event_graph_is_active() theStore.Events.AddEventType(typeof(MembersJoined)); theStore.Events.IsActive(null).ShouldBeTrue(); - theSchema.ToDDL().ShouldContain("other.mt_streams"); + theSchema.ToDatabaseScript().ShouldContain("other.mt_streams"); } [Fact] - public void builds_schema_objects_on_the_fly_as_needed() + public async Task builds_schema_objects_on_the_fly_as_needed() { theStore.Tenancy.Default.StorageFor().ShouldNotBeNull(); theStore.Tenancy.Default.StorageFor().ShouldNotBeNull(); theStore.Tenancy.Default.StorageFor().ShouldNotBeNull(); - var tables = theStore.Tenancy.Default.DbObjects.SchemaTables(); + var tables = (await theStore.Tenancy.Default.SchemaTables()).Select(x => x.QualifiedName).ToArray(); tables.ShouldContain("other.mt_doc_user"); tables.ShouldContain("other.mt_doc_issue"); tables.ShouldContain("other.mt_doc_company"); - var functions = theStore.Tenancy.Default.DbObjects.Functions(); + var functions = (await theStore.Tenancy.Default.Functions()).Select(x => x.QualifiedName).ToArray(); functions.ShouldContain("other.mt_upsert_user"); functions.ShouldContain("other.mt_upsert_issue"); functions.ShouldContain("other.mt_upsert_company"); @@ -146,7 +147,7 @@ public void can_write_ddl_by_type_with_schema_creation() _.Connection(ConnectionSource.ConnectionString); })) { - store.Schema.WriteDDLByType(_binAllsql); + store.Schema.WriteDatabaseCreationScriptByType(_binAllsql); } string filename = _binAllsql.AppendPath("all.sql"); @@ -181,7 +182,7 @@ public void write_ddl_by_type_generates_the_all_sql_script() store.Options.Storage.MappingFor(typeof(User)) .DatabaseSchemaName.ShouldBe("other"); - store.Schema.WriteDDLByType(_binAllsql); + store.Schema.WriteDatabaseCreationScriptByType(_binAllsql); } @@ -214,7 +215,7 @@ public void write_ddl_by_type_with_no_events() })) { store.Events.IsActive(null).ShouldBeFalse(); - store.Schema.WriteDDLByType(_binAllsql); + store.Schema.WriteDatabaseCreationScriptByType(_binAllsql); } var fileSystem = new FileSystem(); @@ -237,7 +238,7 @@ public void write_ddl_by_type_with_events() })) { store.Events.IsActive(null).ShouldBeTrue(); - store.Schema.WriteDDLByType(_binAllsql); + store.Schema.WriteDatabaseCreationScriptByType(_binAllsql); } var fileSystem = new FileSystem(); @@ -263,7 +264,7 @@ public void fixing_bug_343_double_export_of_events() })) { store.Events.IsActive(null).ShouldBeTrue(); - store.Schema.WriteDDLByType(_binAllsql); + store.Schema.WriteDatabaseCreationScriptByType(_binAllsql); } var fileSystem = new FileSystem(); diff --git a/src/Marten.Schema.Testing/DocumentSchemaTests.cs b/src/Marten.Schema.Testing/DocumentSchemaTests.cs index 9277baa4e7..4bfd299206 100644 --- a/src/Marten.Schema.Testing/DocumentSchemaTests.cs +++ b/src/Marten.Schema.Testing/DocumentSchemaTests.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using System.Threading.Tasks; using Baseline; using Marten.Events; using Marten.Internal.Storage; @@ -8,12 +9,12 @@ using Marten.Schema.Testing.Hierarchies; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; -using Issue = Marten.Schema.Testing.Documents.Issue; namespace Marten.Schema.Testing { - public class DocumentSchemaTests : IntegrationContext + public class DocumentSchemaTests: IntegrationContext { private readonly string _binAllsql = AppContext.BaseDirectory.AppendPath("bin", "allsql"); private readonly string _binAllsql2 = AppContext.BaseDirectory.AppendPath("bin", "allsql2"); @@ -61,7 +62,7 @@ public void can_resolve_document_storage_for_subclass() }); theStore.Tenancy.Default.StorageFor() - .ShouldBeOfType>(); + .ShouldBeOfType>(); } [Fact] @@ -85,15 +86,15 @@ public void generate_ddl() theStore.Tenancy.Default.StorageFor(); theStore.Tenancy.Default.EnsureStorageExists(typeof(IntDoc)); - var sql = theStore.Schema.ToDDL(); + var sql = theStore.Schema.ToDatabaseScript(); - SpecificationExtensions.ShouldContain(sql, "CREATE OR REPLACE FUNCTION public.mt_get_next_hi"); - SpecificationExtensions.ShouldContain(sql, "CREATE OR REPLACE FUNCTION public.mt_upsert_user"); - SpecificationExtensions.ShouldContain(sql, "CREATE OR REPLACE FUNCTION public.mt_upsert_issue"); - SpecificationExtensions.ShouldContain(sql, "CREATE OR REPLACE FUNCTION public.mt_upsert_company"); - SpecificationExtensions.ShouldContain(sql, "CREATE TABLE public.mt_doc_user"); - SpecificationExtensions.ShouldContain(sql, "CREATE TABLE public.mt_doc_issue"); - SpecificationExtensions.ShouldContain(sql, "CREATE TABLE public.mt_doc_company"); + sql.ShouldContain("CREATE OR REPLACE FUNCTION public.mt_get_next_hi"); + sql.ShouldContain("CREATE OR REPLACE FUNCTION public.mt_upsert_user"); + sql.ShouldContain("CREATE OR REPLACE FUNCTION public.mt_upsert_issue"); + sql.ShouldContain("CREATE OR REPLACE FUNCTION public.mt_upsert_company"); + sql.ShouldContain("CREATE TABLE public.mt_doc_user"); + sql.ShouldContain("CREATE TABLE public.mt_doc_issue"); + sql.ShouldContain("CREATE TABLE public.mt_doc_company"); } [Fact] @@ -104,12 +105,12 @@ public void generate_the_ddl_with_the_event_store() _.Events.AddEventType(typeof(MembersDeparted)); }); - var sql = theStore.Schema.ToDDL(); + var sql = theStore.Schema.ToDatabaseScript(); - sql.ShouldContain($"CREATE TABLE public.mt_streams"); + sql.ShouldContain("CREATE TABLE public.mt_streams"); // Crude way of checking that it should only be dumped once - sql.IndexOf($"CREATE TABLE public.mt_streams").ShouldBe(sql.LastIndexOf($"CREATE TABLE public.mt_streams")); + sql.IndexOf("CREATE TABLE public.mt_streams").ShouldBe(sql.LastIndexOf("CREATE TABLE public.mt_streams")); } [Fact] @@ -120,7 +121,7 @@ public void do_not_write_event_sql_if_the_event_graph_is_not_active() theStore.Events.IsActive(null).ShouldBeFalse(); - theStore.Schema.ToDDL().ShouldNotContain( "public.mt_streams"); + theStore.Schema.ToDatabaseScript().ShouldNotContain("public.mt_streams"); } [Fact] @@ -129,22 +130,22 @@ public void do_write_the_event_sql_if_the_event_graph_is_active() theStore.Events.AddEventType(typeof(MembersJoined)); theStore.Events.IsActive(null).ShouldBeTrue(); - theStore.Schema.ToDDL().ShouldContain("public.mt_streams"); + theStore.Schema.ToDatabaseScript().ShouldContain("public.mt_streams"); } [Fact] - public void builds_schema_objects_on_the_fly_as_needed() + public async Task builds_schema_objects_on_the_fly_as_needed() { theStore.Tenancy.Default.StorageFor().ShouldNotBeNull(); theStore.Tenancy.Default.StorageFor().ShouldNotBeNull(); theStore.Tenancy.Default.StorageFor().ShouldNotBeNull(); - var tables = theStore.Tenancy.Default.DbObjects.SchemaTables(); + var tables = (await theStore.Tenancy.Default.SchemaTables()).Select(x => x.QualifiedName).ToArray(); tables.ShouldContain("public.mt_doc_user"); tables.ShouldContain("public.mt_doc_issue"); tables.ShouldContain("public.mt_doc_company"); - var functions = theStore.Tenancy.Default.DbObjects.Functions(); + var functions = (await theStore.Tenancy.Default.Functions()).Select(x => x.QualifiedName).ToArray(); functions.ShouldContain("public.mt_upsert_user"); functions.ShouldContain("public.mt_upsert_issue"); functions.ShouldContain("public.mt_upsert_company"); @@ -163,7 +164,7 @@ public void can_write_ddl_by_type_smoke_test() _.Connection(ConnectionSource.ConnectionString); })) { - store.Schema.WriteDDLByType(_binAllsql); + store.Schema.WriteDatabaseCreationScriptByType(_binAllsql); } var fileSystem = new FileSystem(); @@ -174,13 +175,12 @@ public void can_write_ddl_by_type_smoke_test() var actuals = files.Select(Path.GetFileName).Where(x => x != "all.sql").OrderBy(x => x); actuals - .ShouldHaveTheSameElementsAs("company.sql", "issue.sql", "system_functions.sql", "transforms.sql", "user.sql"); - - + .ShouldHaveTheSameElementsAs("company.sql", "issue.sql", "system_functions.sql", "transforms.sql", + "user.sql"); } [Fact] - public void can_write_patch_by_type_smoke_test() + public async Task can_write_patch_by_type_smoke_test() { using (var store = DocumentStore.For(_ => { @@ -194,16 +194,15 @@ public void can_write_patch_by_type_smoke_test() store.Advanced.Clean.CompletelyRemoveAll(); - store.Schema.WritePatchByType(_binAllsql2); + await store.Schema.WriteMigrationFileByType(_binAllsql2); } var fileSystem = new FileSystem(); var files = fileSystem.FindFiles(_binAllsql2, FileSet.Shallow("*.sql")).ToArray(); files.Select(Path.GetFileName).Where(x => x != "all.sql").OrderBy(x => x) - .ShouldHaveTheSameElementsAs("company.sql", "issue.sql", "system_functions.sql", "transforms.sql", "user.sql"); - - + .ShouldHaveTheSameElementsAs("company.sql", "issue.sql", "system_functions.sql", "transforms.sql", + "user.sql"); } [Fact] @@ -222,7 +221,7 @@ public void write_ddl_by_type_generates_the_all_sql_script() _.Transforms.LoadFile("get_fullname.js"); })) { - store.Schema.WriteDDLByType(_binAllsql); + store.Schema.WriteDatabaseCreationScriptByType(_binAllsql); } var filename = _binAllsql.AppendPath("all.sql"); @@ -234,8 +233,6 @@ public void write_ddl_by_type_generates_the_all_sql_script() lines.ShouldContain("\\i issue.sql"); lines.ShouldContain("\\i eventstore.sql"); lines.ShouldContain("\\i transforms.sql"); - - } [Fact] @@ -254,14 +251,15 @@ public void writes_transform_function() _.Transforms.LoadFile("get_fullname.js"); })) { - store.Schema.WriteDDLByType(_binAllsql); + store.Schema.WriteDatabaseCreationScriptByType(_binAllsql); } var file = _binAllsql.AppendPath("transforms.sql"); var lines = new FileSystem().ReadStringFromFile(file).ReadLines().ToArray(); - lines.ShouldContain("CREATE OR REPLACE FUNCTION public.mt_transform_get_fullname(doc JSONB) RETURNS JSONB AS $$"); + lines.ShouldContain( + "CREATE OR REPLACE FUNCTION public.mt_transform_get_fullname(doc JSONB) RETURNS JSONB AS $$"); } [Fact] @@ -277,7 +275,7 @@ public void write_ddl_by_type_with_no_events() })) { store.Events.IsActive(null).ShouldBeFalse(); - store.Schema.WriteDDLByType(_binAllsql); + store.Schema.WriteDatabaseCreationScriptByType(_binAllsql); } var fileSystem = new FileSystem(); @@ -300,7 +298,7 @@ public void can_write_ddl_by_type_with_no_database_connection() })) { store.Events.IsActive(null).ShouldBeFalse(); - store.Schema.WriteDDLByType(_binAllsql); + store.Schema.WriteDatabaseCreationScriptByType(_binAllsql); } var fileSystem = new FileSystem(); @@ -323,7 +321,7 @@ public void write_ddl_by_type_with_events() })) { store.Events.IsActive(null).ShouldBeTrue(); - store.Schema.WriteDDLByType(_binAllsql); + store.Schema.WriteDatabaseCreationScriptByType(_binAllsql); } var fileSystem = new FileSystem(); @@ -348,21 +346,21 @@ public void resolve_storage_for_event_type() theStore.Tenancy.Default.StorageFor().ShouldBeOfType>() .DocumentType.ShouldBe(typeof(RaceStarted)); } - } [Collection("DefaultSchema")] - public class DocumentSchemaWithOverridenSchemaTests : IntegrationContext + public class DocumentSchemaWithOverridenSchemaTests: IntegrationContext { - private readonly string _sql; - private readonly DbObjectName[] _tables; private readonly DbObjectName[] _functions; private readonly IDocumentSchema _schema; + private readonly string _sql; + private readonly DbObjectName[] _tables; public DocumentSchemaWithOverridenSchemaTests() { #region sample_override_schema_per_table + StoreOptions(_ => { _.Storage.MappingFor(typeof(User)).DatabaseSchemaName = "other"; @@ -371,12 +369,13 @@ public DocumentSchemaWithOverridenSchemaTests() _.Storage.MappingFor(typeof(IntDoc)); // this will tell marten to use the default 'public' schema name. - _.DatabaseSchemaName = Marten.StoreOptions.DefaultDatabaseSchemaName; + _.DatabaseSchemaName = DbObjectName.DefaultDatabaseSchemaName; }); + #endregion sample_override_schema_per_table _schema = theStore.Schema; - _sql = _schema.ToDDL(); + _sql = _schema.ToDatabaseScript(); using (var session = theStore.OpenSession()) { @@ -386,14 +385,11 @@ public DocumentSchemaWithOverridenSchemaTests() session.SaveChanges(); } - _tables = theStore.Tenancy.Default.DbObjects.SchemaTables(); - _functions = theStore.Tenancy.Default.DbObjects.Functions(); + _tables = theStore.Tenancy.Default.SchemaTables().GetAwaiter().GetResult().ToArray(); + _functions = theStore.Tenancy.Default.Functions().GetAwaiter().GetResult().ToArray(); } - - - [Fact] public void include_the_hilo_table_by_default() { @@ -513,20 +509,23 @@ public void the_company_should_be_stored() } } - public class DocumentSchemaWithOverridenDefaultSchemaAndEventsTests : IntegrationContext + public class DocumentSchemaWithOverridenDefaultSchemaAndEventsTests: IntegrationContext { - private readonly string _sql; - private readonly DbObjectName[] _tables; private readonly DbObjectName[] _functions; private readonly IDocumentSchema _schema; + private readonly string _sql; + private readonly DbObjectName[] _tables; public DocumentSchemaWithOverridenDefaultSchemaAndEventsTests() { StoreOptions(_ => { #region sample_override_schema_name + _.DatabaseSchemaName = "other"; + #endregion sample_override_schema_name + _.Storage.MappingFor(typeof(User)).DatabaseSchemaName = "yet_another"; _.Storage.MappingFor(typeof(Issue)).DatabaseSchemaName = "overriden"; _.Storage.MappingFor(typeof(Company)); @@ -535,7 +534,7 @@ public DocumentSchemaWithOverridenDefaultSchemaAndEventsTests() _schema = theStore.Schema; - _sql = _schema.ToDDL(); + _sql = _schema.ToDatabaseScript(); using (var session = theStore.OpenSession()) { @@ -545,8 +544,8 @@ public DocumentSchemaWithOverridenDefaultSchemaAndEventsTests() session.SaveChanges(); } - _tables = theStore.Tenancy.Default.DbObjects.SchemaTables(); - _functions = theStore.Tenancy.Default.DbObjects.Functions(); + _tables = theStore.Tenancy.Default.SchemaTables().GetAwaiter().GetResult().ToArray(); + _functions = theStore.Tenancy.Default.Functions().GetAwaiter().GetResult().ToArray(); } @@ -554,7 +553,7 @@ public DocumentSchemaWithOverridenDefaultSchemaAndEventsTests() public void do_write_the_event_sql_if_the_event_graph_is_active() { theStore.Events.IsActive(null).ShouldBeTrue(); - SpecificationExtensions.ShouldContain(_schema.ToDDL(), "other.mt_streams"); + _schema.ToDatabaseScript().ShouldContain("other.mt_streams"); } @@ -579,7 +578,7 @@ public void then_the_company_function_should_be_generated_in_the_default_schema( [Fact] public void then_the_user_table_should_be_generated_in_the_default_schema() { - SpecificationExtensions.ShouldContain(_sql, "CREATE TABLE yet_another.mt_doc_user"); + _sql.ShouldContain("CREATE TABLE yet_another.mt_doc_user"); } [Fact] diff --git a/src/Marten.Schema.Testing/EventStoreSchemaV3ToV4Tests.cs b/src/Marten.Schema.Testing/EventStoreSchemaV3ToV4Tests.cs index 9eb1f559ff..0dfdccbc62 100644 --- a/src/Marten.Schema.Testing/EventStoreSchemaV3ToV4Tests.cs +++ b/src/Marten.Schema.Testing/EventStoreSchemaV3ToV4Tests.cs @@ -1,8 +1,9 @@ using System; +using System.Threading.Tasks; using Marten.Events; using Marten.Exceptions; +using Weasel.Postgresql; using Marten.Testing.Harness; -using Marten.Util; using Npgsql; using Shouldly; using Xunit; @@ -12,7 +13,7 @@ namespace Marten.Schema.Testing public class EventStoreSchemaV3ToV4Tests : IntegrationContext { [Fact] - public void can_create_patch_for_event_store_schema_changes() + public async Task can_create_patch_for_event_store_schema_changes() { var store1 = Store(AutoCreate.All); store1.Tenancy.Default.EnsureStorageExists(typeof(StreamAction)); @@ -22,37 +23,37 @@ public void can_create_patch_for_event_store_schema_changes() // create another store and check if the schema can be be auto updated using var store2 = Store(AutoCreate.CreateOrUpdate); - var sql = store2.Schema.ToPatch().UpdateDDL; + var sql = (await store2.Schema.CreateMigration()).UpdateSql; sql.ShouldContain($"alter table {_schemaName}.mt_events alter column version type bigint", Case.Insensitive); sql.ShouldContain($"alter table {_schemaName}.mt_streams alter column version type bigint", Case.Insensitive); sql.ShouldContain($"drop function if exists {_schemaName}.mt_append_event", Case.Insensitive); } [Fact] - public void can_auto_update_event_store_schema_changes() + public async Task can_auto_update_event_store_schema_changes() { using var store1 = Store(AutoCreate.All); - store1.Schema.ApplyAllConfiguredChangesToDatabase(); + await store1.Schema.ApplyAllConfiguredChangesToDatabase(); SimulateEventStoreV3Schema(); // create another store and check if the schema can be be auto updated using var store2 = Store(AutoCreate.CreateOrUpdate); - Should.Throw(() => + await Should.ThrowAsync(async () => { - store2.Schema.AssertDatabaseMatchesConfiguration(); + await store2.Schema.AssertDatabaseMatchesConfiguration(); }); - Should.NotThrow(() => + await Should.NotThrowAsync(async () => { - store2.Schema.ApplyAllConfiguredChangesToDatabase(); - store2.Schema.AssertDatabaseMatchesConfiguration(); + await store2.Schema.ApplyAllConfiguredChangesToDatabase(); + await store2.Schema.AssertDatabaseMatchesConfiguration(); }); } [Fact] - public void should_not_have_v3_to_v4_patches_on_v4_schema() + public async Task should_not_have_v3_to_v4_patches_on_v4_schema() { using var store1 = Store(AutoCreate.All); store1.Tenancy.Default.EnsureStorageExists(typeof(StreamAction)); @@ -60,7 +61,7 @@ public void should_not_have_v3_to_v4_patches_on_v4_schema() // create another store and check if no v3 to v4 patches are generated using var store2 = Store(AutoCreate.CreateOrUpdate); - var sql = store2.Schema.ToPatch().UpdateDDL; + var sql = (await store2.Schema.CreateMigration()).UpdateSql; sql.ShouldNotContain($"alter table {_schemaName}.mt_events alter column version type bigint", Case.Insensitive); sql.ShouldNotContain($"alter table {_schemaName}.mt_streams alter column version type bigint", Case.Insensitive); sql.ShouldNotContain($"drop function if exists {_schemaName}.mt_append_event", Case.Insensitive); diff --git a/src/Marten.Schema.Testing/ForeignKeyDefinitionTests.cs b/src/Marten.Schema.Testing/ForeignKeyDefinitionTests.cs deleted file mode 100644 index 01de15caf0..0000000000 --- a/src/Marten.Schema.Testing/ForeignKeyDefinitionTests.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System; -using Marten.Schema.Testing.Documents; -using Marten.Storage; -using Shouldly; -using Xunit; - -namespace Marten.Schema.Testing -{ - public class ForeignKeyDefinitionTests - { - private readonly DocumentMapping _userMapping = DocumentMapping.For(); - private readonly DocumentMapping _issueMapping = DocumentMapping.For(); - - [Fact] - public void default_key_name() - { - new ForeignKeyDefinition("user_id", _issueMapping, _userMapping).KeyName.ShouldBe("mt_doc_issue_user_id_fkey"); - } - - [Fact] - public void generate_ddl() - { - var expected = string.Join(Environment.NewLine, - "ALTER TABLE public.mt_doc_issue", - "ADD CONSTRAINT mt_doc_issue_user_id_fkey FOREIGN KEY (user_id)", - "REFERENCES public.mt_doc_user (id);"); - - new ForeignKeyDefinition("user_id", _issueMapping, _userMapping).ToDDL() - .ShouldBe(expected); - } - - [Fact] - public void generate_ddl_with_cascade() - { - var expected = string.Join(Environment.NewLine, - "ALTER TABLE public.mt_doc_issue", - "ADD CONSTRAINT mt_doc_issue_user_id_fkey FOREIGN KEY (user_id)", - "REFERENCES public.mt_doc_user (id)", - "ON DELETE CASCADE;"); - - new ForeignKeyDefinition("user_id", _issueMapping, _userMapping) - { CascadeDeletes = true } - .ToDDL() - .ShouldBe(expected); - } - - [Fact] - public void generate_ddl_on_other_schema() - { - var issueMappingOtherSchema = DocumentMapping.For("schema1"); - var userMappingOtherSchema = DocumentMapping.For("schema2"); - - var expected = string.Join(Environment.NewLine, - "ALTER TABLE schema1.mt_doc_issue", - "ADD CONSTRAINT mt_doc_issue_user_id_fkey FOREIGN KEY (user_id)", - "REFERENCES schema2.mt_doc_user (id);"); - - new ForeignKeyDefinition("user_id", issueMappingOtherSchema, userMappingOtherSchema).ToDDL() - .ShouldBe(expected); - } - - [Fact] - public void generate_ddl_on_other_schema_with_cascade() - { - var issueMappingOtherSchema = DocumentMapping.For("schema1"); - var userMappingOtherSchema = DocumentMapping.For("schema2"); - - var expected = string.Join(Environment.NewLine, - "ALTER TABLE schema1.mt_doc_issue", - "ADD CONSTRAINT mt_doc_issue_user_id_fkey FOREIGN KEY (user_id)", - "REFERENCES schema2.mt_doc_user (id)", - "ON DELETE CASCADE;"); - - new ForeignKeyDefinition("user_id", issueMappingOtherSchema, userMappingOtherSchema) {CascadeDeletes = true} - .ToDDL() - .ShouldBe(expected);; - } - - [Fact] - public void generate_ddl_with_tenancy_conjoined() - { - _userMapping.TenancyStyle = TenancyStyle.Conjoined; - _issueMapping.TenancyStyle = TenancyStyle.Conjoined; - var expected = string.Join(Environment.NewLine, - "ALTER TABLE public.mt_doc_issue", - "ADD CONSTRAINT mt_doc_issue_user_id_tenant_id_fkey FOREIGN KEY (user_id, tenant_id)", - "REFERENCES public.mt_doc_user (id, tenant_id);"); - - new ForeignKeyDefinition("user_id", _issueMapping, _userMapping) - .ToDDL() - .ShouldBe(expected); - } - } - - public class ExternalForeignKeyDefinitionTests - { - private readonly DocumentMapping _userMapping = DocumentMapping.For(); - - [Fact] - public void generate_ddl_without_cascade() - { - var expected = string.Join(Environment.NewLine, - "ALTER TABLE public.mt_doc_user", - "ADD CONSTRAINT mt_doc_user_user_id_fkey FOREIGN KEY (user_id)", - "REFERENCES external_schema.external_table (external_id);"); - - new ExternalForeignKeyDefinition("user_id", _userMapping, - "external_schema", "external_table", "external_id") - .ToDDL() - .ShouldBe(expected); - } - - [Fact] - public void generate_ddl_with_cascade() - { - var expected = string.Join(Environment.NewLine, - "ALTER TABLE public.mt_doc_user", - "ADD CONSTRAINT mt_doc_user_user_id_fkey FOREIGN KEY (user_id)", - "REFERENCES external_schema.external_table (external_id)", - "ON DELETE CASCADE;"); - - new ExternalForeignKeyDefinition("user_id", _userMapping, - "external_schema", "external_table", "external_id") {CascadeDeletes = true} - .ToDDL() - .ShouldBe(expected); - } - - [Fact] - public void generate_ddl_with_tenancy_conjoined() - { - _userMapping.TenancyStyle = TenancyStyle.Conjoined; - var expected = string.Join(Environment.NewLine, - "ALTER TABLE public.mt_doc_user", - "ADD CONSTRAINT mt_doc_user_user_id_fkey FOREIGN KEY (user_id)", - "REFERENCES external_schema.external_table (external_id);"); - - new ExternalForeignKeyDefinition("user_id", _userMapping, - "external_schema", "external_table", "external_id") - .ToDDL() - .ShouldBe(expected); - } - } -} diff --git a/src/Marten.Schema.Testing/Hierarchies/end_to_end_document_hierarchy_usage_Tests.cs b/src/Marten.Schema.Testing/Hierarchies/end_to_end_document_hierarchy_usage_Tests.cs index 0e18b63c84..96d96e3556 100644 --- a/src/Marten.Schema.Testing/Hierarchies/end_to_end_document_hierarchy_usage_Tests.cs +++ b/src/Marten.Schema.Testing/Hierarchies/end_to_end_document_hierarchy_usage_Tests.cs @@ -185,7 +185,7 @@ public query_through_mixed_population_Tests() [Fact] public void clean_by_subclass_only_deletes_the_one_subclass() { - theStore.Advanced.Clean.DeleteDocumentsFor(typeof(AdminUser)); + theStore.Advanced.Clean.DeleteDocumentsByType(typeof(AdminUser)); theSession.Query().Any().ShouldBeTrue(); theSession.Query().Any().ShouldBeTrue(); diff --git a/src/Marten.Schema.Testing/Hierarchies/generating_code_and_sql_for_hierarchy_smoke_Tests.cs b/src/Marten.Schema.Testing/Hierarchies/generating_code_and_sql_for_hierarchy_smoke_Tests.cs index 3f5cfb5e24..82fb37a483 100644 --- a/src/Marten.Schema.Testing/Hierarchies/generating_code_and_sql_for_hierarchy_smoke_Tests.cs +++ b/src/Marten.Schema.Testing/Hierarchies/generating_code_and_sql_for_hierarchy_smoke_Tests.cs @@ -2,6 +2,7 @@ using System.Linq; using Marten.Storage; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing.Hierarchies @@ -23,7 +24,7 @@ public void can_generate_upsert_function_for_95() { var writer = new StringWriter(); - new UpsertFunction(theHierarchy).Write(new DdlRules(), writer); + new UpsertFunction(theHierarchy).WriteCreateStatement(new DdlRules(), writer); var sql = writer.ToString(); @@ -35,7 +36,7 @@ public void can_generate_upsert_function_with_security_definer() { var writer = new StringWriter(); - new UpsertFunction(theHierarchy).Write(new DdlRules + new UpsertFunction(theHierarchy).WriteCreateStatement(new DdlRules { UpsertRights = SecurityRights.Definer }, writer); @@ -50,7 +51,7 @@ public void can_generate_upsert_function_for_94() { var writer = new StringWriter(); - new UpsertFunction(theHierarchy).Write(new DdlRules(), writer); + new UpsertFunction(theHierarchy).WriteCreateStatement(new DdlRules(), writer); var sql = writer.ToString(); @@ -63,7 +64,7 @@ public void can_generate_upsert_function_for_95_with_optimistic_concurrency() var writer = new StringWriter(); theHierarchy.UseOptimisticConcurrency = true; - new UpsertFunction(theHierarchy).Write(new DdlRules(), writer); + new UpsertFunction(theHierarchy).WriteCreateStatement(new DdlRules(), writer); var sql = writer.ToString(); @@ -76,7 +77,7 @@ public void can_generate_upsert_function_for_94_with_optimistic_concurrency() var writer = new StringWriter(); theHierarchy.UseOptimisticConcurrency = true; - new UpsertFunction(theHierarchy).Write(new DdlRules(), writer); + new UpsertFunction(theHierarchy).WriteCreateStatement(new DdlRules(), writer); var sql = writer.ToString(); @@ -100,7 +101,7 @@ public generating_code_and_sql_for_hierarchy_smoke_Tests_on_other_database_schem public void contains_index_for_documenttype_column() { var table = new DocumentTable(theHierarchy); - table.Indexes.Any(x => x.IndexName == $"mt_doc_squad_idx_{SchemaConstants.DocumentTypeColumn}").ShouldBeTrue(); + table.Indexes.Any(x => x.Name == $"mt_doc_squad_idx_{SchemaConstants.DocumentTypeColumn}").ShouldBeTrue(); } [Fact] @@ -108,7 +109,7 @@ public void can_generate_upsert_function_for_95() { var writer = new StringWriter(); - new UpsertFunction(theHierarchy).Write(new DdlRules(), writer); + new UpsertFunction(theHierarchy).WriteCreateStatement(new DdlRules(), writer); var sql = writer.ToString(); @@ -120,7 +121,7 @@ public void can_generate_upsert_function_for_94() { var writer = new StringWriter(); - new UpsertFunction(theHierarchy).Write(new DdlRules(), writer); + new UpsertFunction(theHierarchy).WriteCreateStatement(new DdlRules(), writer); var sql = writer.ToString(); diff --git a/src/Marten.Schema.Testing/Identity/Sequences/Bug_1404_Hilo_concurrent_update_failure.cs b/src/Marten.Schema.Testing/Identity/Sequences/Bug_1404_Hilo_concurrent_update_failure.cs index 239241d1c1..ff3dec4203 100644 --- a/src/Marten.Schema.Testing/Identity/Sequences/Bug_1404_Hilo_concurrent_update_failure.cs +++ b/src/Marten.Schema.Testing/Identity/Sequences/Bug_1404_Hilo_concurrent_update_failure.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Marten.Schema.Testing.Documents; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing.Identity.Sequences diff --git a/src/Marten.Schema.Testing/Identity/Sequences/Bug_255_Hilo_table_being_erroneously_recreated.cs b/src/Marten.Schema.Testing/Identity/Sequences/Bug_255_Hilo_table_being_erroneously_recreated.cs index 646f17be21..5dd3461494 100644 --- a/src/Marten.Schema.Testing/Identity/Sequences/Bug_255_Hilo_table_being_erroneously_recreated.cs +++ b/src/Marten.Schema.Testing/Identity/Sequences/Bug_255_Hilo_table_being_erroneously_recreated.cs @@ -5,6 +5,7 @@ using Marten.Schema.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing.Identity.Sequences diff --git a/src/Marten.Schema.Testing/Identity/Sequences/HiLoSequenceTests.cs b/src/Marten.Schema.Testing/Identity/Sequences/HiLoSequenceTests.cs index 08c6067a78..f3beff2e3a 100644 --- a/src/Marten.Schema.Testing/Identity/Sequences/HiLoSequenceTests.cs +++ b/src/Marten.Schema.Testing/Identity/Sequences/HiLoSequenceTests.cs @@ -44,34 +44,34 @@ public void should_advance_initial_case() } [Fact] - public void advance_to_next_hi_from_initial_state() + public async Task advance_to_next_hi_from_initial_state() { - theSequence.AdvanceToNextHi(); + await theSequence.AdvanceToNextHi(); theSequence.CurrentLo.ShouldBe(1); theSequence.CurrentHi.ShouldBe(0); } [Fact] - public void advance_to_next_hi_several_times() + public async Task advance_to_next_hi_several_times() { - theSequence.AdvanceToNextHi(); + await theSequence.AdvanceToNextHi(); - theSequence.AdvanceToNextHi(); + await theSequence.AdvanceToNextHi(); theSequence.CurrentHi.ShouldBe(1); - theSequence.AdvanceToNextHi(); + await theSequence.AdvanceToNextHi(); theSequence.CurrentHi.ShouldBe(2); - theSequence.AdvanceToNextHi(); + await theSequence.AdvanceToNextHi(); theSequence.CurrentHi.ShouldBe(3); } [Fact] - public void advance_value_from_initial_state() + public async Task advance_value_from_initial_state() { // Gotta do this at least once - theSequence.AdvanceToNextHi(); + await theSequence.AdvanceToNextHi(); theSequence.AdvanceValue().ShouldBe(1); theSequence.AdvanceValue().ShouldBe(2); diff --git a/src/Marten.Schema.Testing/Identity/Sequences/SequenceFactoryTests.cs b/src/Marten.Schema.Testing/Identity/Sequences/SequenceFactoryTests.cs index abc855f0cc..d37340d5d2 100644 --- a/src/Marten.Schema.Testing/Identity/Sequences/SequenceFactoryTests.cs +++ b/src/Marten.Schema.Testing/Identity/Sequences/SequenceFactoryTests.cs @@ -1,4 +1,6 @@ -using Marten.Schema.Identity.Sequences; +using System.Linq; +using System.Threading.Tasks; +using Marten.Schema.Identity.Sequences; using Marten.Schema.Testing.Documents; using Shouldly; using Xunit; @@ -19,15 +21,15 @@ public SequenceFactoryTests() } [Fact] - public void can_create_table_on_fly_if_necessary() + public async Task can_create_table_on_fly_if_necessary() { - theStore.Tenancy.Default.DbObjects.Functions().ShouldContain("public.mt_get_next_hi"); + (await theStore.Tenancy.Default.Functions()).Select(x => x.QualifiedName).ShouldContain("public.mt_get_next_hi"); } [Fact] - public void can_create_function_on_fly_if_necessary() + public async Task can_create_function_on_fly_if_necessary() { - theStore.Tenancy.Default.DbObjects.Functions().ShouldContain("public.mt_get_next_hi"); + (await theStore.Tenancy.Default.Functions()).Select(x => x.QualifiedName).ShouldContain("public.mt_get_next_hi"); } @@ -45,15 +47,15 @@ public SequenceFactoryOnOtherDatabaseSchemaTests() } [Fact] - public void can_create_table_on_fly_if_necessary() + public async Task can_create_table_on_fly_if_necessary() { - theStore.Tenancy.Default.DbObjects.SchemaTables().ShouldContain("seq_other.mt_hilo"); + (await theStore.Tenancy.Default.SchemaTables()).Select(x => x.QualifiedName).ShouldContain("seq_other.mt_hilo"); } [Fact] - public void can_create_function_on_fly_if_necessary() + public async Task can_create_function_on_fly_if_necessary() { - theStore.Tenancy.Default.DbObjects.Functions().ShouldContain("seq_other.mt_get_next_hi"); + (await theStore.Tenancy.Default.Functions()).Select(x => x.QualifiedName).ShouldContain("seq_other.mt_get_next_hi"); } } } diff --git a/src/Marten.Schema.Testing/Identity/Sequences/hilo_configuration_overrides.cs b/src/Marten.Schema.Testing/Identity/Sequences/hilo_configuration_overrides.cs index 5ad2f032c5..18c72908b7 100644 --- a/src/Marten.Schema.Testing/Identity/Sequences/hilo_configuration_overrides.cs +++ b/src/Marten.Schema.Testing/Identity/Sequences/hilo_configuration_overrides.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using Baseline; using Marten.Schema.Identity; using Marten.Schema.Identity.Sequences; @@ -12,7 +13,7 @@ namespace Marten.Schema.Testing.Identity.Sequences public class hilo_configuration_overrides { [Fact] - public void can_establish_the_hilo_starting_point() + public async Task can_establish_the_hilo_starting_point() { #region sample_ResetHiloSequenceFloor var store = DocumentStore.For(opts => @@ -23,7 +24,7 @@ public void can_establish_the_hilo_starting_point() // Resets the minimum Id number for the IntDoc document // type to 2500 - store.Tenancy.Default.ResetHiloSequenceFloor(2500); + await store.Tenancy.Default.ResetHiloSequenceFloor(2500); #endregion sample_ResetHiloSequenceFloor using (var session = store.OpenSession()) diff --git a/src/Marten.Schema.Testing/IndexDefinitionTests.cs b/src/Marten.Schema.Testing/IndexDefinitionTests.cs deleted file mode 100644 index 587888c043..0000000000 --- a/src/Marten.Schema.Testing/IndexDefinitionTests.cs +++ /dev/null @@ -1,278 +0,0 @@ -using Marten.Schema.Testing.Documents; -using Shouldly; -using Xunit; - -namespace Marten.Schema.Testing -{ - public class IndexDefinitionTests - { - private readonly DocumentMapping mapping = DocumentMapping.For(); - private readonly DocumentMapping mappingOhterSchema = DocumentMapping.For("other"); - - [Fact] - public void default_index_name_with_one_column() - { - new IndexDefinition(mapping, "long").IndexName.ShouldBe("mt_doc_target_idx_long"); - } - - [Fact] - public void default_index_name_with_multiple_columns() - { - new IndexDefinition(mapping, "foo", "bar").IndexName.ShouldBe("mt_doc_target_idx_foo_bar"); - } - - [Fact] - public void default_method_is_btree() - { - new IndexDefinition(mapping, "foo").Method.ShouldBe(IndexMethod.btree); - } - - [Fact] - public void default_sort_order_is_asc() - { - new IndexDefinition(mapping, "foo").SortOrder.ShouldBe(SortOrder.Asc); - } - - [Fact] - public void default_unique_is_false() - { - new IndexDefinition(mapping, "foo").IsUnique.ShouldBeFalse(); - } - - [Fact] - public void default_concurrent_is_false() - { - new IndexDefinition(mapping, "foo").IsConcurrent.ShouldBeFalse(); - } - - [Fact] - public void default_modifier_is_null() - { - SpecificationExtensions.ShouldBeNull(new IndexDefinition(mapping, "foo").Modifier); - } - - [Fact] - public void generate_ddl_for_single_column_all_defaults() - { - new IndexDefinition(mapping, "foo").ToDDL() - .ShouldBe("CREATE INDEX mt_doc_target_idx_foo ON public.mt_doc_target (\"foo\");"); - } - - [Fact] - public void generate_ddl_other_database_schema_for_single_column_all_defaults() - { - new IndexDefinition(mappingOhterSchema, "foo").ToDDL() - .ShouldBe("CREATE INDEX mt_doc_target_idx_foo ON other.mt_doc_target (\"foo\");"); - } - - [Fact] - public void generate_ddl_for_custom_index_name() - { - var definition = new IndexDefinition(mapping, "foo"); - definition.IndexName = "bar"; - - definition.ToDDL() - .ShouldBe("CREATE INDEX mt_bar ON public.mt_doc_target (\"foo\");"); - } - - [Fact] - public void generate_ddl_for_descending_sort_order() - { - var definition = new IndexDefinition(mapping, "foo"); - definition.SortOrder = SortOrder.Desc; - - definition.ToDDL() - .ShouldBe("CREATE INDEX mt_doc_target_idx_foo ON public.mt_doc_target (\"foo\" DESC);"); - } - - [InlineData(IndexMethod.btree, true)] - [InlineData(IndexMethod.gin, false)] - [InlineData(IndexMethod.brin, false)] - [InlineData(IndexMethod.gist, false)] - [InlineData(IndexMethod.hash, false)] - [Theory] - public void sort_order_only_applied_for_btree_index(IndexMethod method, bool shouldUseSort) - { - var definition = new IndexDefinition(mapping, "foo"); - definition.Method = method; - definition.SortOrder = SortOrder.Desc; - - var ddl = definition.ToDDL(); - - if (shouldUseSort) - { - ddl.ShouldEndWith(" DESC);"); - } - else - { - ddl.ShouldNotEndWith(" DESC);"); - } - } - - [Fact] - public void generate_ddl_for_single_column_unique() - { - var definition = new IndexDefinition(mapping, "foo"); - definition.IsUnique = true; - - definition.ToDDL() - .ShouldBe("CREATE UNIQUE INDEX mt_doc_target_idx_foo ON public.mt_doc_target (\"foo\");"); - } - - [Fact] - public void generate_ddl_other_database_schema_for_single_column_unique() - { - var definition = new IndexDefinition(mappingOhterSchema, "foo"); - definition.IsUnique = true; - - definition.ToDDL() - .ShouldBe("CREATE UNIQUE INDEX mt_doc_target_idx_foo ON other.mt_doc_target (\"foo\");"); - } - - [Fact] - public void generate_ddl_with_modifier() - { - var definition = new IndexDefinition(mapping, "foo"); - definition.IsUnique = true; - definition.Modifier = "WITH (fillfactor = 70)"; - - definition.ToDDL() - .ShouldBe("CREATE UNIQUE INDEX mt_doc_target_idx_foo ON public.mt_doc_target (\"foo\") WITH (fillfactor = 70);"); - } - - [Fact] - public void generate_ddl_other_database_schema_with_modifier() - { - var definition = new IndexDefinition(mappingOhterSchema, "foo"); - definition.IsUnique = true; - definition.Modifier = "WITH (fillfactor = 70)"; - - definition.ToDDL() - .ShouldBe("CREATE UNIQUE INDEX mt_doc_target_idx_foo ON other.mt_doc_target (\"foo\") WITH (fillfactor = 70);"); - } - - [Fact] - public void generate_ddl_for_concurrent_index() - { - var definition = new IndexDefinition(mapping, "foo"); - definition.IsConcurrent = true; - - definition.ToDDL() - .ShouldBe("CREATE INDEX CONCURRENTLY mt_doc_target_idx_foo ON public.mt_doc_target (\"foo\");"); - } - - [Fact] - public void generate_ddl_other_database_schema_for_concurrent_index() - { - var definition = new IndexDefinition(mappingOhterSchema, "foo"); - definition.IsConcurrent = true; - - definition.ToDDL() - .ShouldBe("CREATE INDEX CONCURRENTLY mt_doc_target_idx_foo ON other.mt_doc_target (\"foo\");"); - } - - [Fact] - public void generate_ddl_for_concurrent_unique_index() - { - var definition = new IndexDefinition(mapping, "foo"); - definition.IsConcurrent = true; - definition.IsUnique = true; - - definition.ToDDL() - .ShouldBe("CREATE UNIQUE INDEX CONCURRENTLY mt_doc_target_idx_foo ON public.mt_doc_target (\"foo\");"); - } - - [Fact] - public void generate_ddl_other_database_schema_for_concurrent_unique_index() - { - var definition = new IndexDefinition(mappingOhterSchema, "foo"); - definition.IsConcurrent = true; - definition.IsUnique = true; - - definition.ToDDL() - .ShouldBe("CREATE UNIQUE INDEX CONCURRENTLY mt_doc_target_idx_foo ON other.mt_doc_target (\"foo\");"); - } - - [Fact] - public void generate_ddl_for_gin_index() - { - var definition = new IndexDefinition(mapping, "foo"); - definition.Method = IndexMethod.gin; - - definition.ToDDL() - .ShouldBe("CREATE INDEX mt_doc_target_idx_foo ON public.mt_doc_target USING gin (\"foo\");"); - } - - [Fact] - public void generate_ddl_other_database_schema_for_gin_index() - { - var definition = new IndexDefinition(mappingOhterSchema, "foo"); - definition.Method = IndexMethod.gin; - - definition.ToDDL() - .ShouldBe("CREATE INDEX mt_doc_target_idx_foo ON other.mt_doc_target USING gin (\"foo\");"); - } - - [Fact] - public void generate_ddl_for_gin_with_jsonb_path_ops_index() - { - var definition = new IndexDefinition(mapping, "foo"); - definition.Method = IndexMethod.gin; - definition.Expression = "? jsonb_path_ops"; - - definition.ToDDL() - .ShouldBe("CREATE INDEX mt_doc_target_idx_foo ON public.mt_doc_target USING gin (\"foo\" jsonb_path_ops);"); - } - - [Fact] - public void generate_ddl_other_database_schema_for_gin_with_jsonb_path_ops_index() - { - var definition = new IndexDefinition(mappingOhterSchema, "foo"); - definition.Method = IndexMethod.gin; - definition.Expression = "? jsonb_path_ops"; - - definition.ToDDL() - .ShouldBe("CREATE INDEX mt_doc_target_idx_foo ON other.mt_doc_target USING gin (\"foo\" jsonb_path_ops);"); - } - - [Fact] - public void generate_ddl_for_gist_index() - { - var definition = new IndexDefinition(mapping, "foo"); - definition.Method = IndexMethod.gist; - - definition.ToDDL() - .ShouldBe("CREATE INDEX mt_doc_target_idx_foo ON public.mt_doc_target USING gist (\"foo\");"); - } - - [Fact] - public void generate_ddl_other_database_schema_for_gist_index() - { - var definition = new IndexDefinition(mappingOhterSchema, "foo"); - definition.Method = IndexMethod.gist; - - definition.ToDDL() - .ShouldBe("CREATE INDEX mt_doc_target_idx_foo ON other.mt_doc_target USING gist (\"foo\");"); - } - - [Fact] - public void generate_ddl_for_hash_index() - { - var definition = new IndexDefinition(mapping, "foo"); - definition.Method = IndexMethod.hash; - - definition.ToDDL() - .ShouldBe("CREATE INDEX mt_doc_target_idx_foo ON public.mt_doc_target USING hash (\"foo\");"); - } - - [Fact] - public void generate_ddl_on_other_database_schema_for_hash_index() - { - var definition = new IndexDefinition(mappingOhterSchema, "foo"); - definition.Method = IndexMethod.hash; - - definition.ToDDL() - .ShouldBe("CREATE INDEX mt_doc_target_idx_foo ON other.mt_doc_target USING hash (\"foo\");"); - } - } -} diff --git a/src/Marten.Schema.Testing/IntegrationContext.cs b/src/Marten.Schema.Testing/IntegrationContext.cs index 084b056410..0a9f3e22f6 100644 --- a/src/Marten.Schema.Testing/IntegrationContext.cs +++ b/src/Marten.Schema.Testing/IntegrationContext.cs @@ -1,23 +1,16 @@ using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using Baseline; -using Marten.Services; using Marten.Testing.Harness; -using Xunit; using Xunit.Abstractions; +using Weasel.Postgresql; namespace Marten.Schema.Testing { - - - public abstract class IntegrationContext : IDisposable + public abstract class IntegrationContext: IDisposable { protected ITestOutputHelper _output; - private DocumentStore _store; private IDocumentSession _session; + private DocumentStore _store; protected IntegrationContext(ITestOutputHelper output = null) { @@ -30,7 +23,6 @@ protected IntegrationContext(ITestOutputHelper output = null) protected bool EnableCommandLogging { get; set; } - protected DocumentStore theStore { get @@ -44,6 +36,26 @@ protected DocumentStore theStore } } + protected IDocumentSession theSession + { + get + { + if (_session == null) + { + _session = buildSession(); + } + + return _session; + } + } + + public DocumentTracking DocumentTracking { get; set; } = DocumentTracking.None; + + public virtual void Dispose() + { + _store?.Dispose(); + } + protected void UseDefaultSchema() { StoreOptions(x => x.DatabaseSchemaName = "public"); @@ -73,14 +85,13 @@ protected DocumentStore StoreOptions(Action configure) } /// - /// This creates an all new DocumentStore without - /// cleaning the schema + /// This creates an all new DocumentStore without + /// cleaning the schema /// /// /// protected DocumentStore SeparateStore(Action configure) { - var store = DocumentStore.For(opts => { opts.NameDataLength = 100; @@ -99,31 +110,9 @@ protected DocumentStore SeparateStore(Action configure) return store; } - protected IDocumentSession theSession - { - get - { - if (_session == null) - { - _session = buildSession(); - } - - return _session; - } - } - - public DocumentTracking DocumentTracking { get; set; } = DocumentTracking.None; - protected IDocumentSession buildSession() { return theStore.OpenSession(DocumentTracking); } - - public virtual void Dispose() - { - _store?.Dispose(); - } } - - } diff --git a/src/Marten.Schema.Testing/ProductionModeSchemeCreationTests.cs b/src/Marten.Schema.Testing/ProductionModeSchemeCreationTests.cs index b13acd909b..1cfee1ef61 100644 --- a/src/Marten.Schema.Testing/ProductionModeSchemeCreationTests.cs +++ b/src/Marten.Schema.Testing/ProductionModeSchemeCreationTests.cs @@ -1,6 +1,7 @@ using System.Linq; using Marten.Schema.Testing.Documents; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing diff --git a/src/Marten.Schema.Testing/SchemaPatchTester.cs b/src/Marten.Schema.Testing/SchemaPatchTester.cs deleted file mode 100644 index 86e12e05d4..0000000000 --- a/src/Marten.Schema.Testing/SchemaPatchTester.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.IO; -using Marten.Storage; -using Shouldly; -using Xunit; - -namespace Marten.Schema.Testing -{ - public class SchemaPatchTester - { - [Fact] - public void translates_the_file_name() - { - SchemaPatch.ToDropFileName("update.sql").ShouldBe("update.drop.sql"); - SchemaPatch.ToDropFileName("1.update.sql").ShouldBe("1.update.drop.sql"); - SchemaPatch.ToDropFileName("folder\\1.update.sql").ShouldBe("folder\\1.update.drop.sql"); - } - - [Fact] - public void write_transactional_script_with_no_role() - { - var rules = new DdlRules(); - SpecificationExtensions.ShouldBeNull(rules.Role); - - var patch = new SchemaPatch(rules); - - var writer = new StringWriter(); - - patch.WriteScript(writer, w => - { - w.WriteLine("Hello."); - }); - - SpecificationExtensions.ShouldNotContain(writer.ToString(), "SET ROLE"); - SpecificationExtensions.ShouldNotContain(writer.ToString(), "RESET ROLE;"); - } - - [Fact] - public void write_transactional_script_with_a_role() - { - var rules = new DdlRules(); - rules.Role = "OCD_DBA"; - - var patch = new SchemaPatch(rules); - - var writer = new StringWriter(); - - patch.WriteScript(writer, w => - { - w.WriteLine("Hello."); - }); - - SpecificationExtensions.ShouldContain(writer.ToString(), "SET ROLE OCD_DBA;"); - SpecificationExtensions.ShouldContain(writer.ToString(), "RESET ROLE;"); - } - - [Fact] - public void difference_is_none_by_default() - { - new SchemaPatch(new DdlRules()).Difference.ShouldBe(SchemaPatchDifference.None); - } - - [Fact] - public void invalid_wins_over_all_else() - { - var patch = new SchemaPatch(new DdlRules()); - var table1 = new Table(new DbObjectName("public", "sometable1")); - var table2 = new Table(new DbObjectName("public", "sometable2")); - var table3 = new Table(new DbObjectName("public", "sometable3")); - var table4 = new Table(new DbObjectName("public", "sometable4")); - - patch.Log(table1, SchemaPatchDifference.Invalid); - patch.Log(table2, SchemaPatchDifference.Create); - patch.Log(table3, SchemaPatchDifference.None); - patch.Log(table4, SchemaPatchDifference.Update); - - patch.Difference.ShouldBe(SchemaPatchDifference.Invalid); - } - - - - - - - - [Fact] - public void update_is_second_in_priority() - { - var patch = new SchemaPatch(new DdlRules()); - var table1 = new Table(new DbObjectName("public", "sometable1")); - var table2 = new Table(new DbObjectName("public", "sometable2")); - var table3 = new Table(new DbObjectName("public", "sometable3")); - var table4 = new Table(new DbObjectName("public", "sometable4")); - - //patch.Log(table1, SchemaPatchDifference.Invalid); - patch.Log(table2, SchemaPatchDifference.Create); - patch.Log(table3, SchemaPatchDifference.None); - patch.Log(table4, SchemaPatchDifference.Update); - - patch.Difference.ShouldBe(SchemaPatchDifference.Update); - } - - [Fact] - public void create_takes_precedence_over_none() - { - var patch = new SchemaPatch(new DdlRules()); - var table1 = new Table(new DbObjectName("public", "sometable1")); - var table2 = new Table(new DbObjectName("public", "sometable2")); - var table3 = new Table(new DbObjectName("public", "sometable3")); - var table4 = new Table(new DbObjectName("public", "sometable4")); - - //patch.Log(table1, SchemaPatchDifference.Invalid); - patch.Log(table2, SchemaPatchDifference.Create); - patch.Log(table3, SchemaPatchDifference.None); - //patch.Log(table4, SchemaPatchDifference.Update); - - patch.Difference.ShouldBe(SchemaPatchDifference.Create); - } - - [Fact] - public void return_none_if_no_changes_detected() - { - var patch = new SchemaPatch(new DdlRules()); - var table1 = new Table(new DbObjectName("public", "sometable1")); - var table2 = new Table(new DbObjectName("public", "sometable2")); - var table3 = new Table(new DbObjectName("public", "sometable3")); - var table4 = new Table(new DbObjectName("public", "sometable4")); - - patch.Log(table1, SchemaPatchDifference.None); - patch.Log(table2, SchemaPatchDifference.None); - patch.Log(table3, SchemaPatchDifference.None); - patch.Log(table4, SchemaPatchDifference.None); - - patch.Difference.ShouldBe(SchemaPatchDifference.None); - } - - [Theory] - [InlineData(SchemaPatchDifference.Invalid, AutoCreate.CreateOnly)] - [InlineData(SchemaPatchDifference.Update, AutoCreate.CreateOnly)] - [InlineData(SchemaPatchDifference.Invalid, AutoCreate.CreateOrUpdate)] - public void should_throw_exception_on_assertion(SchemaPatchDifference difference, AutoCreate autoCreate) - { - var patch = new SchemaPatch(new DdlRules()); - var table1 = new Table(new DbObjectName("public", "sometable1")); - patch.Log(table1, difference); - - Exception.ShouldBeThrownBy(() => - { - patch.AssertPatchingIsValid(autoCreate); - }); - } - - [Theory] - [InlineData(SchemaPatchDifference.Create, AutoCreate.CreateOnly)] - [InlineData(SchemaPatchDifference.Create, AutoCreate.CreateOrUpdate)] - [InlineData(SchemaPatchDifference.Create, AutoCreate.All)] - [InlineData(SchemaPatchDifference.Invalid, AutoCreate.All)] // drop and replace - [InlineData(SchemaPatchDifference.Update, AutoCreate.CreateOrUpdate)] - public void should_not_throw_exception_on_assertion(SchemaPatchDifference difference, AutoCreate autoCreate) - { - var patch = new SchemaPatch(new DdlRules()); - var table1 = new Table(new DbObjectName("public", "sometable1")); - patch.Log(table1, difference); - - patch.AssertPatchingIsValid(autoCreate); - } - } -} diff --git a/src/Marten.Schema.Testing/SpecificationExtensions.cs b/src/Marten.Schema.Testing/SpecificationExtensions.cs index efc66e79a3..4a8f3f0ae8 100644 --- a/src/Marten.Schema.Testing/SpecificationExtensions.cs +++ b/src/Marten.Schema.Testing/SpecificationExtensions.cs @@ -6,6 +6,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Baseline; +using Weasel.Postgresql; using Newtonsoft.Json.Linq; using Shouldly; diff --git a/src/Marten.Schema.Testing/Storage/DocumentTableTester.cs b/src/Marten.Schema.Testing/Storage/DocumentTableTester.cs index ec69c0b94c..257f00bab5 100644 --- a/src/Marten.Schema.Testing/Storage/DocumentTableTester.cs +++ b/src/Marten.Schema.Testing/Storage/DocumentTableTester.cs @@ -1,15 +1,17 @@ using System; using System.IO; using System.Linq; +using System.Threading.Tasks; using Baseline; using Marten.Exceptions; using Marten.Internal.CodeGeneration; +using Weasel.Postgresql; using Marten.Schema.Testing.Documents; using Marten.Storage; using Marten.Testing.Harness; -using Marten.Util; using Npgsql; using Shouldly; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Schema.Testing.Storage @@ -47,7 +49,7 @@ private void writeTable(Table table = null) table = table ?? theTable; var writer = new StringWriter(); - table.Write(new DdlRules(), writer); + table.WriteCreateStatement(new DdlRules(), writer); var sql = writer.ToString(); @@ -77,32 +79,30 @@ private void removeColumn(string name) _conn.CreateCommand(sql).ExecuteNonQuery(); } - private void writeAndApplyPatch(AutoCreate autoCreate, DocumentTable table) + private async Task writeAndApplyPatch(AutoCreate autoCreate, DocumentTable table) { - var patch = new SchemaPatch(new DdlRules()); + var migration = await SchemaMigration.Determine(_conn, new ISchemaObject[] {table}); - patch.Apply(_conn, autoCreate, new ISchemaObject[] {table}); - var updateDDL = patch.UpdateDDL; - - if (!string.IsNullOrEmpty(updateDDL)) + if (migration.Difference != SchemaPatchDifference.None) { - _conn.CreateCommand(updateDDL).ExecuteNonQuery(); + await migration.ApplyAll(_conn, new DdlRules(), autoCreate); } + } [Theory] [InlineData(SchemaConstants.DotNetTypeColumn)] [InlineData(SchemaConstants.LastModifiedColumn)] [InlineData(SchemaConstants.VersionColumn)] - public void can_migrate_missing_metadata_column(string columnName) + public async Task can_migrate_missing_metadata_column(string columnName) { writeTable(); removeColumn(columnName); - writeAndApplyPatch(AutoCreate.CreateOrUpdate, theTable); + await writeAndApplyPatch(AutoCreate.CreateOrUpdate, theTable); - var theActual = theTable.FetchExisting(_conn); + var theActual = await theTable.FetchExisting(_conn); theActual.HasColumn(columnName); } @@ -110,7 +110,7 @@ public void can_migrate_missing_metadata_column(string columnName) [Fact] public void basic_columns() { - theTable.Select(x => x.Name) + theTable.Columns.Select(x => x.Name) .ShouldHaveTheSameElementsAs( "id", "data", @@ -120,15 +120,15 @@ public void basic_columns() } [Fact] - public void can_create_with_indexes() + public async Task can_create_with_indexes() { theMapping.Index(x => x.UserName); theMapping.Index(x => x.FirstName); writeTable(); - var existing = theTable.FetchExisting(_conn); - existing.ActualIndices.Count.ShouldBe(2); + var existing = await theTable.FetchExisting(_conn); + existing.Indexes.Count.ShouldBe(2); } [Fact] @@ -150,63 +150,49 @@ public void can_do_substitutions() } [Fact] - public void can_migrate_missing_duplicated_fields() + public async Task can_migrate_missing_duplicated_fields() { writeTable(); theMapping.Duplicate(x => x.FirstName); var newTable = new DocumentTable(theMapping); - writeAndApplyPatch(AutoCreate.CreateOrUpdate, newTable); + await writeAndApplyPatch(AutoCreate.CreateOrUpdate, newTable); - var theActual = theTable.FetchExisting(_conn); + var theActual = await theTable.FetchExisting(_conn); theActual.HasColumn("first_name"); } [Fact] - public void can_migrate_missing_hierarchical_columns() + public async Task can_migrate_missing_hierarchical_columns() { writeTable(); theMapping.SubClasses.Add(typeof(SuperUser)); var newTable = new DocumentTable(theMapping); - writeAndApplyPatch(AutoCreate.CreateOrUpdate, newTable); + await writeAndApplyPatch(AutoCreate.CreateOrUpdate, newTable); - var theActual = theTable.FetchExisting(_conn); + var theActual = await theTable.FetchExisting(_conn); theActual.HasColumn(SchemaConstants.DocumentTypeColumn); } [Fact] - public void can_migrate_missing_soft_deleted_columns() + public async Task can_migrate_missing_soft_deleted_columns() { writeTable(); theMapping.DeleteStyle = DeleteStyle.SoftDelete; var newTable = new DocumentTable(theMapping); - writeAndApplyPatch(AutoCreate.CreateOrUpdate, newTable); + await writeAndApplyPatch(AutoCreate.CreateOrUpdate, newTable); - var theActual = theTable.FetchExisting(_conn); + var theActual = await theTable.FetchExisting(_conn); theActual.HasColumn(SchemaConstants.DeletedColumn); theActual.HasColumn(SchemaConstants.DeletedAtColumn); } - [Fact] - public void can_spot_an_extra_index() - { - theMapping.Index(x => x.UserName); - - writeTable(); - - theMapping.Index(x => x.FirstName); - var table = new DocumentTable(theMapping); - var delta = table.FetchDelta(_conn); - - delta.IndexChanges.Count.ShouldBe(1); - delta.IndexRollbacks.Count.ShouldBe(1); - } [Fact] public void can_write_the_basic_table() @@ -228,18 +214,6 @@ public void duplicated_fields() theTable.HasColumn("last_name").ShouldBeTrue(); } - [Fact] - public void equivalency_negative_column_type_changed() - { - var users = DocumentMapping.For(); - var table1 = new DocumentTable(users); - var table2 = new DocumentTable(users); - - table2.ReplaceOrAddColumn(table2.PrimaryKey.Name, "int", table2.PrimaryKey.Directive); - - table2.ShouldNotBe(table1); - } - [Fact] public void equivalency_negative_different_numbers_of_columns() { @@ -259,47 +233,13 @@ public void equivalency_positive() var table1 = new DocumentTable(users); var table2 = new DocumentTable(users); - table2.ShouldBe(table1); - table1.ShouldBe(table2); - table1.ShouldNotBeSameAs(table2); - } - - - [Fact] - public void equivalency_with_the_postgres_synonym_issue() - { - // This was meant to address GH-127 - - var users = DocumentMapping.For(); - users.DuplicateField("FirstName"); - - var table1 = new DocumentTable(users); - var table2 = new DocumentTable(users); - - table1.ReplaceOrAddColumn("first_name", "varchar"); - table2.ReplaceOrAddColumn("first_name", "character varying"); - - table1.Equals(table2).ShouldBeTrue(); - table2.Equals(table1).ShouldBeTrue(); - - table1.ReplaceOrAddColumn("first_name", "character varying"); - table2.ReplaceOrAddColumn("first_name", "varchar"); - - table1.Equals(table2).ShouldBeTrue(); - table2.Equals(table1).ShouldBeTrue(); + var delta = new TableDelta(table1, table2); + delta.Difference.ShouldBe(SchemaPatchDifference.None); - table1.ReplaceOrAddColumn("first_name", "character varying"); - table2.ReplaceOrAddColumn("first_name", "character varying"); + } - table1.Equals(table2).ShouldBeTrue(); - table2.Equals(table1).ShouldBeTrue(); - table1.ReplaceOrAddColumn("first_name", "varchar"); - table2.ReplaceOrAddColumn("first_name", "varchar"); - table1.Equals(table2).ShouldBeTrue(); - table2.Equals(table1).ShouldBeTrue(); - } [Fact] public void hierarchical() @@ -309,19 +249,6 @@ public void hierarchical() theTable.HasColumn(SchemaConstants.DocumentTypeColumn); } - [Fact] - public void matches_on_indexes() - { - theMapping.Index(x => x.UserName); - theMapping.Index(x => x.FirstName); - - writeTable(); - - var delta = theTable.FetchDelta(_conn); - - delta.IndexChanges.Any().ShouldBeFalse(); - delta.IndexRollbacks.Any().ShouldBeFalse(); - } [Fact] public void soft_deleted() @@ -329,7 +256,7 @@ public void soft_deleted() theMapping.DeleteStyle = DeleteStyle.SoftDelete; theTable.HasColumn(SchemaConstants.DeletedColumn); - Assert.Contains(theTable.Indexes, x => x.IndexName == $"mt_doc_user_idx_{SchemaConstants.DeletedColumn}"); + Assert.Contains(theTable.Indexes, x => x.Name == $"mt_doc_user_idx_{SchemaConstants.DeletedColumn}"); theTable.HasColumn(SchemaConstants.DeletedAtColumn); } @@ -343,7 +270,7 @@ public void write_ddl_in_create_if_not_exists_mode() TableCreation = CreationStyle.CreateIfNotExists }; - var ddl = table.ToDDL(rules); + var ddl = table.ToCreateSql(rules); ddl.ShouldNotContain("DROP TABLE IF EXISTS public.mt_doc_user CASCADE;"); ddl.ShouldContain("CREATE TABLE IF NOT EXISTS public.mt_doc_user"); @@ -359,7 +286,7 @@ public void write_ddl_in_default_drop_then_create_mode() TableCreation = CreationStyle.DropThenCreate }; - var ddl = table.ToDDL(rules); + var ddl = table.ToCreateSql(rules); ddl.ShouldContain("DROP TABLE IF EXISTS public.mt_doc_user CASCADE;"); ddl.ShouldContain("CREATE TABLE public.mt_doc_user"); diff --git a/src/Marten.Schema.Testing/Storage/FunctionBodyTests.cs b/src/Marten.Schema.Testing/Storage/FunctionBodyTests.cs deleted file mode 100644 index 2b1798b9f8..0000000000 --- a/src/Marten.Schema.Testing/Storage/FunctionBodyTests.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Marten.Storage; -using Shouldly; -using Xunit; - -namespace Marten.Schema.Testing.Storage -{ - public class FunctionBodyTests - { - private string theFunctionBody = @" -CREATE OR REPLACE FUNCTION public.mt_upsert_target( - doc jsonb, - docdotnettype character varying, - docid uuid, - docversion uuid) - RETURNS uuid AS -$BODY$ -DECLARE - final_version uuid; -BEGIN -INSERT INTO public.mt_doc_target (""data"", ""mt_dotnet_type"", ""id"", ""mt_version"", mt_last_modified) VALUES (doc, docDotNetType, docId, docVersion, transaction_timestamp()) - ON CONFLICT ON CONSTRAINT pk_mt_doc_target - DO UPDATE SET ""data"" = doc, ""mt_dotnet_type"" = docDotNetType, ""mt_version"" = docVersion, mt_last_modified = transaction_timestamp(); - - SELECT mt_version FROM public.mt_doc_target into final_version WHERE id = docId; - RETURN final_version; -END; -$BODY$ - -"; - - [Fact] - public void derive_the_function_signature_from_the_body() - { - - - var func = new FunctionBody(new DbObjectName("public", "mt_upsert_target"), new string[0], theFunctionBody); - - func.Signature().ShouldBe("public.mt_upsert_target(jsonb, character varying, uuid, uuid)"); - } - - [Fact] - public void do_substitutions() - { - var func = new FunctionBody(new DbObjectName("public", "mt_upsert_target"), new string[0], theFunctionBody); - - func.BuildTemplate($"*{DdlRules.SCHEMA}*").ShouldBe("*public*"); - func.BuildTemplate($"*{DdlRules.FUNCTION}*").ShouldBe("*mt_upsert_target*"); - func.BuildTemplate($"*{DdlRules.SIGNATURE}*").ShouldBe($"*{func.Signature()}*"); - } - } -} \ No newline at end of file diff --git a/src/Marten.Schema.Testing/Storage/ScenarioUsingSequenceForUniqueId.cs b/src/Marten.Schema.Testing/Storage/ScenarioUsingSequenceForUniqueId.cs index b2f30d6bd2..382e955d54 100644 --- a/src/Marten.Schema.Testing/Storage/ScenarioUsingSequenceForUniqueId.cs +++ b/src/Marten.Schema.Testing/Storage/ScenarioUsingSequenceForUniqueId.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Marten.Storage; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing.Storage @@ -15,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) + public MatterId(StoreOptions options, int startFrom) : base(nameof(MatterId)) { _startFrom = startFrom; _schema = options.DatabaseSchemaName; @@ -30,7 +32,7 @@ protected override IEnumerable schemaObjects() #endregion sample_scenario-usingsequenceforuniqueid-setup [Fact] - public void ScenarioUsingSequenceForUniqueIdScenario() + public async Task ScenarioUsingSequenceForUniqueIdScenario() { StoreOptions(storeOptions => { @@ -40,7 +42,7 @@ public void ScenarioUsingSequenceForUniqueIdScenario() }); #region sample_scenario-usingsequenceforuniqueid-storesetup-2 - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); #endregion sample_scenario-usingsequenceforuniqueid-storesetup-2 #region sample_scenario-usingsequenceforuniqueid-querymatter diff --git a/src/Marten.Schema.Testing/Storage/SequenceCustomization.cs b/src/Marten.Schema.Testing/Storage/SequenceCustomization.cs deleted file mode 100644 index de089f7ffc..0000000000 --- a/src/Marten.Schema.Testing/Storage/SequenceCustomization.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Marten.Storage; -using Xunit; - -namespace Marten.Schema.Testing.Storage -{ - public class SequenceCustomization : IntegrationContext - { - public class SequenceWithStart : FeatureSchemaBase - { - private readonly string schema; - - public SequenceWithStart(StoreOptions options) : base(nameof(SequenceWithStart), options) - { - schema = options.DatabaseSchemaName; - } - - protected override IEnumerable schemaObjects() - { - yield return new Sequence(new DbObjectName(schema, $"mt_{nameof(SequenceWithStart).ToLowerInvariant()}"), 1337); - } - } - - [Fact] - public void CanRegisterSequenceWithStartAttribute() - { - StoreOptions(_ => - { - _.Storage.Add(); - }); - - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - - using (var session = theStore.OpenSession()) - { - var value = session.Query("select nextval(?)", - $"{theStore.Options.DatabaseSchemaName}.mt_{nameof(SequenceWithStart).ToLowerInvariant()}").First(); - - Assert.Equal(1337, value); - } - } - - } -} diff --git a/src/Marten.Schema.Testing/Storage/SequenceTester.cs b/src/Marten.Schema.Testing/Storage/SequenceTester.cs deleted file mode 100644 index f59d5314f2..0000000000 --- a/src/Marten.Schema.Testing/Storage/SequenceTester.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.IO; -using Marten.Storage; -using Marten.Testing.Harness; -using Marten.Util; -using Npgsql; -using Shouldly; -using Xunit; - -namespace Marten.Schema.Testing.Storage -{ - [Collection("testbed")] - public class SequenceTester : IDisposable - { - private readonly NpgsqlConnection _conn; - private readonly Sequence theSequence = new Sequence(new DbObjectName("testbed", "mysequence")); - - public SequenceTester() - { - _conn = new NpgsqlConnection(ConnectionSource.ConnectionString); - _conn.Open(); - - _conn.CreateCommand("drop schema if exists testbed cascade;create schema testbed") - .ExecuteNonQuery(); - } - - public void Dispose() - { - _conn.Close(); - _conn.Dispose(); - } - - [Fact] - public void can_create_sequence_without_blowing_up() - { - var writer = new StringWriter(); - theSequence.Write(new DdlRules(), writer); - - _conn.CreateCommand(writer.ToString()).ExecuteNonQuery(); - } - - - [Fact] - public void determine_that_it_is_missing() - { - var patch = new SchemaPatch(new DdlRules()); - patch.Apply(_conn, AutoCreate.All, theSequence); - - patch.Difference.ShouldBe(SchemaPatchDifference.Create); - } - - [Fact] - public void determine_that_it_is_already_there() - { - can_create_sequence_without_blowing_up(); - - var patch = new SchemaPatch(new DdlRules()); - patch.Apply(_conn, AutoCreate.All, theSequence); - - patch.Difference.ShouldBe(SchemaPatchDifference.None); - } - } -} diff --git a/src/Marten.Schema.Testing/Storage/TableDeltaTests.cs b/src/Marten.Schema.Testing/Storage/TableDeltaTests.cs deleted file mode 100644 index d504266814..0000000000 --- a/src/Marten.Schema.Testing/Storage/TableDeltaTests.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System.Linq; -using Marten.Schema.Testing.Documents; -using Marten.Storage; -using Shouldly; -using Xunit; - -namespace Marten.Schema.Testing.Storage -{ - public class TableDeltaTests - { - public static TheoryData TypeToSynonymsMappings = new TheoryData() - { - { "character varying", "varchar" }, - { "bool", "boolean" }, - { "integer","int" }, - { "integer[]", "int[]" }, - { "numeric", "decimal" }, - { "timestamp without time zone", "timestamp" }, - { "timestamp with time zone", "timestamptz" } - }; - - [Fact] - public void perfect_match() - { - var users = DocumentMapping.For(); - var actual = new DocumentTable(users); - var expected = new DocumentTable(users); - - var diff = new TableDelta(expected, actual); - diff.Matches.ShouldBeTrue(); - } - - [Fact] - public void can_match_up_on_columns() - { - var users = DocumentMapping.For(); - var actual = new DocumentTable(users); - var expected = new DocumentTable(users); - - var diff = new TableDelta(expected, actual); - - diff.Matched.OrderBy(x => x.Name).Select(x => x.Name) - .ShouldHaveTheSameElementsAs("data", "id", SchemaConstants.DotNetTypeColumn, SchemaConstants.LastModifiedColumn, SchemaConstants.VersionColumn); - } - - [Theory] - [MemberData(nameof(TypeToSynonymsMappings))] - public void can_match_up_on_columns_with_synonyms(string type, string synonym) - { - var users = DocumentMapping.For(); - var actual = new DocumentTable(users); - var expected = new DocumentTable(users); - - var actualTableColumnWithType = new TableColumn("new", type); - var expectedTableColumnWithSynonym = new TableColumn("new", synonym); - - var actualTableColumnWithSynonym = new TableColumn("newer", synonym); - var expectedTableColumnWithType = new TableColumn("newer", type); - - actual.AddColumn(actualTableColumnWithType); - actual.AddColumn(actualTableColumnWithSynonym); - - expected.AddColumn(expectedTableColumnWithType); - expected.AddColumn(expectedTableColumnWithSynonym); - - var diff = new TableDelta(expected, actual); - - diff.Matched.OrderBy(x => x.Name).Select(x => x.Name) - .ShouldContain("new", "newer"); - } - - [Fact] - public void not_matching_with_missing_columns() - { - var users = DocumentMapping.For(); - var actual = new DocumentTable(users); - var expected = new DocumentTable(users); - - var tableColumn = new TableColumn("new", "varchar"); - expected.AddColumn(tableColumn); - - var diff = new TableDelta(expected, actual); - diff.Matches.ShouldBeFalse(); - - diff.Missing.Single().ShouldBe(tableColumn); - diff.Extras.Any().ShouldBeFalse(); - diff.Different.Any().ShouldBeFalse(); - } - - [Fact] - public void not_matching_with_extra_columns() - { - var users = DocumentMapping.For(); - var actual = new DocumentTable(users); - var expected = new DocumentTable(users); - - var tableColumn = new TableColumn("new", "varchar"); - actual.AddColumn(tableColumn); - - var diff = new TableDelta(expected, actual); - - diff.Matches.ShouldBeFalse(); - diff.Extras.Single().ShouldBe(tableColumn); - } - - [Fact] - public void not_matching_with_columns_of_same_name_that_are_different() - { - var users = DocumentMapping.For(); - var actual = new DocumentTable(users); - var expected = new DocumentTable(users); - - actual.ReplaceOrAddColumn("id", "int"); - - var diff = new TableDelta(expected, actual); - diff.Matches.ShouldBeFalse(); - - diff.Different.Single().Name.ShouldBe("id"); - } - } -} diff --git a/src/Marten.Schema.Testing/Storage/TableTester.cs b/src/Marten.Schema.Testing/Storage/TableTester.cs deleted file mode 100644 index 35d1ab332f..0000000000 --- a/src/Marten.Schema.Testing/Storage/TableTester.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using Baseline; -using Marten.Storage; -using Marten.Testing.Harness; -using Marten.Util; -using Npgsql; -using Shouldly; -using Xunit; - -namespace Marten.Schema.Testing.Storage -{ - [Collection("testbed")] - public class TableTester : IDisposable - { - private readonly NpgsqlConnection _conn; - private readonly Table theTable; - - public TableTester() - { - _conn = new NpgsqlConnection(ConnectionSource.ConnectionString); - _conn.Open(); - - _conn.CreateCommand("drop schema if exists testbed cascade;create schema testbed") - .ExecuteNonQuery(); - - - theTable = new Table(new DbObjectName("testbed", "table1")); - theTable.AddPrimaryKey(new TableColumn("id", "uuid")); - - theTable.AddColumn("name", "text"); - theTable.AddColumn("number", "int"); - theTable.AddColumn("rownum", "serial"); - } - - public void Dispose() - { - _conn.Close(); - _conn.Dispose(); - } - - private void writeTable() - { - var writer = new StringWriter(); - theTable.Write(new DdlRules(), writer); - - var sql = writer.ToString(); - - try - { - _conn.CreateCommand(sql).ExecuteNonQuery(); - } - catch (Exception) - { - Console.WriteLine(sql); - throw; - } - } - - private bool tableExists() - { - var sql = "select count(*) from pg_stat_user_tables where relname = 'table1' and schemaname = 'testbed'"; - - var count = _conn.CreateCommand(sql).ExecuteScalar().As(); - return count == 1; - } - - [Fact] - public void can_write_the_initial_table() - { - writeTable(); - - tableExists().ShouldBeTrue(); - - _conn.CreateCommand("insert into testbed.table1 (id, name, number) values (:id, 'Jeremy', 42)") - .With("id", Guid.NewGuid()).ExecuteNonQuery(); - - _conn.CreateCommand("select count(*) from testbed.table1") - .ExecuteScalar().As().ShouldBe(1); - } - - [Fact] - public void can_recognize_when_the_existing_table_does_not_exist() - { - tableExists().ShouldBeFalse(); - - SpecificationExtensions.ShouldBeNull(theTable.FetchExisting(_conn)); - } - - [Fact] - public void can_fetch_the_existing_table() - { - writeTable(); - tableExists().ShouldBeTrue(); - - var existing = theTable.FetchExisting(_conn); - - SpecificationExtensions.ShouldNotBeNull(existing); - - existing.PrimaryKey.Name.ShouldBe("id"); - existing.Select(x => x.Name).ShouldHaveTheSameElementsAs("id", "name", "number", "rownum"); - } - - - - [Fact] - public void perfect_match() - { - writeTable(); - - var diff = theTable.FetchDelta(_conn); - SpecificationExtensions.ShouldNotBeNull(diff); - diff.Matched.Select(x => x.Name).ShouldHaveTheSameElementsAs("id", "name", "number", "rownum"); - diff.Missing.Length.ShouldBe(0); - diff.Extras.Length.ShouldBe(0); - diff.Different.Length.ShouldBe(0); - - diff.Matches.ShouldBeTrue(); - } - - [Fact] - public void not_matching_with_missing_columns() - { - writeTable(); - - theTable.AddColumn("newcol", "text"); - - var diff = theTable.FetchDelta(_conn); - diff.Matches.ShouldBeFalse(); - - diff.Missing.Single().Name.ShouldBe("newcol"); - diff.Extras.Any().ShouldBeFalse(); - diff.Different.Any().ShouldBeFalse(); - } - - [Fact] - public void not_matching_with_extra_columns() - { - var tableColumn = new TableColumn("new", "varchar"); - theTable.AddColumn(tableColumn); - - writeTable(); - - theTable.RemoveColumn("new"); - - - var diff = theTable.FetchDelta(_conn); - - diff.Matches.ShouldBeFalse(); - diff.Extras.Single().ShouldBe(tableColumn); - } - - [Fact] - public void not_matching_with_columns_of_same_name_that_are_different() - { - writeTable(); - theTable.ColumnFor("id").Type = "int"; - - var diff = theTable.FetchDelta(_conn); - diff.Matches.ShouldBeFalse(); - - diff.Different.Single().Name.ShouldBe("id"); - } - - [Fact] - public void matching_with_columns_same_name_and_synonymn_of_type() - { - //e.g. serial is an int - writeTable(); - - var existing = theTable.FetchExisting(_conn); - existing.Columns.First(c => c.Name == "rownum").Type.ShouldBe("integer"); - - var diff = theTable.FetchDelta(_conn); - diff.Matches.ShouldBeTrue(); - } - - - - - } -} diff --git a/src/Marten.Schema.Testing/Storage/UpsertFunctionTester.cs b/src/Marten.Schema.Testing/Storage/UpsertFunctionTester.cs deleted file mode 100644 index a94b4a9d86..0000000000 --- a/src/Marten.Schema.Testing/Storage/UpsertFunctionTester.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.IO; -using Baseline; -using Marten.Schema.Testing.Documents; -using Marten.Storage; -using Marten.Testing.Harness; -using Marten.Util; -using Npgsql; -using Shouldly; -using Xunit; - -namespace Marten.Schema.Testing.Storage -{ - [Collection("UpsertFunction")] - public class UpsertFunctionTester : IDisposable - { - private readonly NpgsqlConnection _conn; - private readonly DocumentMapping theMapping; - - public UpsertFunctionTester() - { - _conn = new NpgsqlConnection(ConnectionSource.ConnectionString); - _conn.Open(); - - _conn.CreateCommand("drop schema if exists testbed cascade;create schema testbed") - .ExecuteNonQuery(); - - theMapping = DocumentMapping.For(); - theMapping.DatabaseSchemaName = "testbed"; - - // write the initial table - writeTable(); - } - - private void writeTable() - { - var table = new DocumentTable(theMapping); - - var patch = new SchemaPatch(new DdlRules()); - - var cmd = _conn.CreateCommand(); - var builder = new CommandBuilder(cmd); - - table.ConfigureQueryCommand(builder); - cmd.CommandText = builder.ToString(); - - try - { - using (var reader = cmd.ExecuteReader()) - { - table.CreatePatch(reader, patch, AutoCreate.All); - } - - _conn.CreateCommand(patch.UpdateDDL).ExecuteNonQuery(); - } - catch (Exception) - { - Console.WriteLine(builder.ToString()); - throw; - } - } - - private void writeFunction() - { - var writer = new StringWriter(); - var function = new UpsertFunction(theMapping); - function.Write(new DdlRules(), writer); - - var sql = writer.ToString(); - - try - { - _conn.CreateCommand(sql).ExecuteNonQuery(); - } - catch (Exception) - { - Console.WriteLine(sql); - throw; - } - } - - private bool functionExists() - { - var function = new UpsertFunction(theMapping); - var sql = $@" -select count(*) -from pg_proc JOIN pg_namespace as ns ON pg_proc.pronamespace = ns.oid -where ns.nspname = 'testbed' and pg_proc.proname = '{function.Identifier.Name}';"; - - var count = _conn.CreateCommand(sql).ExecuteScalar().As(); - return count == 1; - } - - public void Dispose() - { - _conn.Close(); - _conn.Dispose(); - } - - [Fact] - public void can_create_the_initial_function() - { - functionExists().ShouldBeFalse(); - writeFunction(); - functionExists().ShouldBeTrue(); - } - - [Fact] - public void detect_when_the_function_is_missing() - { - var function = new UpsertFunction(theMapping); - - var delta = function.FetchDelta(_conn, new DdlRules()); - - SpecificationExtensions.ShouldBeNull(delta); - } - - [Fact] - public void detect_that_there_are_no_changes() - { - writeFunction(); - - var function = new UpsertFunction(theMapping); - - var delta = function.FetchDelta(_conn, new DdlRules()); - delta.AllNew.ShouldBeFalse(); - delta.HasChanged.ShouldBeFalse(); - } - - [Fact] - public void detect_that_the_function_has_changed() - { - writeFunction(); - - theMapping.Duplicate(x => x.FirstName); - writeTable(); - - var function = new UpsertFunction(theMapping); - - var delta = function.FetchDelta(_conn, new DdlRules()); - - delta.AllNew.ShouldBeFalse(); - delta.HasChanged.ShouldBeTrue(); - } - - [Fact] - public void restore_previous_function_in_rollback() - { - writeFunction(); - - theMapping.Duplicate(x => x.FirstName); - writeTable(); - - var function = new UpsertFunction(theMapping); - - var ddlRules = new DdlRules(); - var delta = function.FetchDelta(_conn, ddlRules); - - var patch = new SchemaPatch(ddlRules); - delta.WritePatch(patch); - - SpecificationExtensions.ShouldContain(patch.RollbackDDL, delta.Actual.Body); - } - } -} diff --git a/src/Marten.Schema.Testing/Storage/creating_diffs_when_system_columns_are_missing.cs b/src/Marten.Schema.Testing/Storage/creating_diffs_when_system_columns_are_missing.cs index 6143384870..925b1c21cb 100644 --- a/src/Marten.Schema.Testing/Storage/creating_diffs_when_system_columns_are_missing.cs +++ b/src/Marten.Schema.Testing/Storage/creating_diffs_when_system_columns_are_missing.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Threading.Tasks; using Baseline; using Marten.Schema.Testing.Documents; using Marten.Storage; @@ -12,73 +13,73 @@ namespace Marten.Schema.Testing.Storage public class creating_diffs_when_system_columns_are_missing : IntegrationContext { [Fact] - public void can_fill_in_the_version_column() + public async Task can_fill_in_the_version_column() { var mapping = theStore.Storage.MappingFor(typeof(User)); var table = new DocumentTable(mapping.As()); table.RemoveColumn(SchemaConstants.VersionColumn); var writer = new StringWriter(); - table.Write(theStore.Schema.DdlRules, writer); + table.WriteCreateStatement(theStore.Schema.DdlRules, writer); using (var conn = theStore.Tenancy.Default.OpenConnection()) { var cmd = new NpgsqlCommand(writer.ToString()); - conn.Execute(cmd); + await conn.ExecuteAsync(cmd); } theStore.Tenancy.Default.ResetSchemaExistenceChecks(); theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - var actual = theStore.Tenancy.Default.DbObjects.ExistingTableFor(typeof(User)); + var actual = await theStore.Tenancy.Default.ExistingTableFor(typeof(User)); actual.HasColumn(SchemaConstants.VersionColumn).ShouldBeTrue(); } [Fact] - public void can_fill_in_the_dotnettype_column() + public async Task can_fill_in_the_dotnettype_column() { var mapping = theStore.Storage.MappingFor(typeof(User)); var table = new DocumentTable(mapping.As()); table.RemoveColumn(SchemaConstants.DotNetTypeColumn); var writer = new StringWriter(); - table.Write(theStore.Schema.DdlRules, writer); + table.WriteCreateStatement(theStore.Schema.DdlRules, writer); using (var conn = theStore.Tenancy.Default.OpenConnection()) { var cmd = new NpgsqlCommand(writer.ToString()); - conn.Execute(cmd); + await conn.ExecuteAsync(cmd); } theStore.Tenancy.Default.ResetSchemaExistenceChecks(); theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - var actual = theStore.Tenancy.Default.DbObjects.ExistingTableFor(typeof(User)); + var actual = await theStore.Tenancy.Default.ExistingTableFor(typeof(User)); actual.HasColumn(SchemaConstants.DotNetTypeColumn).ShouldBeTrue(); } [Fact] - public void can_fill_in_the_lastmodified_column() + public async Task can_fill_in_the_lastmodified_column() { var mapping = theStore.Storage.MappingFor(typeof(User)); var table = new DocumentTable(mapping.As()); table.RemoveColumn(SchemaConstants.LastModifiedColumn); var writer = new StringWriter(); - table.Write(theStore.Schema.DdlRules, writer); + table.WriteCreateStatement(theStore.Schema.DdlRules, writer); var cmd = new NpgsqlCommand(writer.ToString()); using (var conn = theStore.Tenancy.Default.OpenConnection()) { - conn.Execute(cmd); + await conn.ExecuteAsync(cmd); } theStore.Tenancy.Default.ResetSchemaExistenceChecks(); theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - var actual = theStore.Tenancy.Default.DbObjects.ExistingTableFor(typeof(User)); + var actual = await theStore.Tenancy.Default.ExistingTableFor(typeof(User)); actual.HasColumn(SchemaConstants.LastModifiedColumn).ShouldBeTrue(); } diff --git a/src/Marten.Schema.Testing/Storage/using_custom_ddl_rules_smoke_tests.cs b/src/Marten.Schema.Testing/Storage/using_custom_ddl_rules_smoke_tests.cs index 6799e0ff2e..8a8b6bf495 100644 --- a/src/Marten.Schema.Testing/Storage/using_custom_ddl_rules_smoke_tests.cs +++ b/src/Marten.Schema.Testing/Storage/using_custom_ddl_rules_smoke_tests.cs @@ -1,4 +1,5 @@ using Marten.Schema.Testing.Documents; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing.Storage diff --git a/src/Marten.Schema.Testing/Storage/when_deriving_the_table_definition_from_the_database_schema_Tests.cs b/src/Marten.Schema.Testing/Storage/when_deriving_the_table_definition_from_the_database_schema_Tests.cs index b548df9ad4..0400e92311 100644 --- a/src/Marten.Schema.Testing/Storage/when_deriving_the_table_definition_from_the_database_schema_Tests.cs +++ b/src/Marten.Schema.Testing/Storage/when_deriving_the_table_definition_from_the_database_schema_Tests.cs @@ -38,22 +38,23 @@ public void it_maps_the_table_name() [Fact] public void it_finds_the_primary_key() { - theDerivedTable.PrimaryKey.ShouldNotBeNull(); - theDerivedTable.PrimaryKey.Name.ShouldBe("id"); + theDerivedTable.PrimaryKeyColumns.Single() + .ShouldBe("id"); } [Fact] public void it_has_all_the_columns() { - theDerivedTable.Select(x => x.Name).ShouldHaveTheSameElementsAs("id", "data", SchemaConstants.LastModifiedColumn, SchemaConstants.VersionColumn, SchemaConstants.DotNetTypeColumn, "user_name"); + theDerivedTable.Columns.Select(x => x.Name).ShouldHaveTheSameElementsAs("id", "data", SchemaConstants.LastModifiedColumn, SchemaConstants.VersionColumn, SchemaConstants.DotNetTypeColumn, "user_name"); } [Fact] public void it_can_map_the_database_type() { - theDerivedTable.PrimaryKey.Type.ShouldBe("uuid"); - theDerivedTable.Column("data").Type.ShouldBe("jsonb"); - theDerivedTable.Column("user_name").Type.ShouldBe("varchar"); + theDerivedTable.Columns + .Single(x => x.IsPrimaryKey).Type.ShouldBe("uuid"); + theDerivedTable.ColumnFor("data").Type.ShouldBe("jsonb"); + theDerivedTable.ColumnFor("user_name").Type.ShouldBe("varchar"); } } diff --git a/src/Marten.Schema.Testing/Storage/when_generating_a_table_for_soft_deletes.cs b/src/Marten.Schema.Testing/Storage/when_generating_a_table_for_soft_deletes.cs index e198ec5d5a..c22fe3b1e6 100644 --- a/src/Marten.Schema.Testing/Storage/when_generating_a_table_for_soft_deletes.cs +++ b/src/Marten.Schema.Testing/Storage/when_generating_a_table_for_soft_deletes.cs @@ -1,7 +1,10 @@ using System.Linq; +using System.Threading.Tasks; using Marten.Schema.Testing.Documents; using Marten.Storage; using Shouldly; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Schema.Testing.Storage @@ -24,26 +27,26 @@ public when_generating_a_table_for_soft_deletes() [Fact] public void has_a_column_for_the_deleted_mark() { - var column = theTable.Column(SchemaConstants.DeletedColumn); - column.Directive.ShouldBe("DEFAULT FALSE"); + var column = theTable.ColumnFor(SchemaConstants.DeletedColumn); + column.DefaultExpression.ShouldBe("FALSE"); column.Type.ShouldBe("boolean"); } [Fact] public void has_a_column_for_the_deleted_at_mark() { - var column = theTable.Column(SchemaConstants.DeletedAtColumn); - column.Directive.ShouldBe("NULL"); + var column = theTable.ColumnFor(SchemaConstants.DeletedAtColumn); + column.AllowNulls.ShouldBeTrue(); column.Type.ShouldBe("timestamp with time zone"); } [Fact] - public void can_generate_the_patch() + public async Task can_generate_the_patch() { using (var store1 = SeparateStore(x=> x.AutoCreateSchemaObjects = AutoCreate.All)) { - store1.BulkInsert(new User [] {new User {UserName = "foo"}, new User { UserName = "bar" } }); + await store1.BulkInsertAsync(new User [] {new User {UserName = "foo"}, new User { UserName = "bar" } }); } using (var store2 = SeparateStore(_ => @@ -59,7 +62,7 @@ public void can_generate_the_patch() } - var table = store2.Tenancy.Default.DbObjects.ExistingTableFor(typeof(User)); + var table = await store2.Tenancy.Default.ExistingTableFor(typeof(User)); table.HasColumn(SchemaConstants.DeletedColumn).ShouldBeTrue(); table.HasColumn(SchemaConstants.DeletedAtColumn).ShouldBeTrue(); @@ -67,14 +70,14 @@ public void can_generate_the_patch() } [Fact] - public void can_generate_the_patch_with_camel_casing() + public async Task can_generate_the_patch_with_camel_casing() { using (var store1 = StoreOptions(_ => { _.UseDefaultSerialization(EnumStorage.AsString, Casing.CamelCase); })) { - store1.BulkInsert(new User[] { new User { UserName = "foo" }, new User { UserName = "bar" } }); + await store1.BulkInsertAsync(new User[] { new User { UserName = "foo" }, new User { UserName = "bar" } }); } using (var store2 = SeparateStore(_ => @@ -91,7 +94,7 @@ public void can_generate_the_patch_with_camel_casing() } - var table = store2.Tenancy.Default.DbObjects.ExistingTableFor(typeof(User)); + var table = await store2.Tenancy.Default.ExistingTableFor(typeof(User)); table.HasColumn(SchemaConstants.DeletedColumn).ShouldBeTrue(); table.HasColumn(SchemaConstants.DeletedAtColumn).ShouldBeTrue(); diff --git a/src/Marten.Schema.Testing/Storage/will_build_a_new_database_table_if_definition_changes_Tests.cs b/src/Marten.Schema.Testing/Storage/will_build_a_new_database_table_if_definition_changes_Tests.cs index 1519a64e64..70d376334e 100644 --- a/src/Marten.Schema.Testing/Storage/will_build_a_new_database_table_if_definition_changes_Tests.cs +++ b/src/Marten.Schema.Testing/Storage/will_build_a_new_database_table_if_definition_changes_Tests.cs @@ -1,6 +1,9 @@ -using Marten.Schema.Testing.Documents; +using System.Linq; +using System.Threading.Tasks; +using Marten.Schema.Testing.Documents; using Marten.Storage; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing.Storage @@ -10,7 +13,7 @@ public class will_build_a_new_database_table_if_definition_changes_Tests : Integ { [Fact] - public void will_build_the_new_table_if_the_configured_table_does_not_match_the_existing_table() + public async Task will_build_the_new_table_if_the_configured_table_does_not_match_the_existing_table() { DocumentTable table1; DocumentTable table2; @@ -18,57 +21,23 @@ public void will_build_the_new_table_if_the_configured_table_does_not_match_the_ theStore.Tenancy.Default.StorageFor(); - theStore.Tenancy.Default.DbObjects.DocumentTables().ShouldContain($"public.mt_doc_user"); + (await theStore.Tenancy.Default.DocumentTables()).Select(x => x.QualifiedName).ShouldContain($"public.mt_doc_user"); table1 = theStore.TableSchema(typeof(User)); - table1.ShouldNotContain(x => x.Name == "user_name"); + table1.Columns.ShouldNotContain(x => x.Name == "user_name"); var store = SeparateStore(opts => opts.Schema.For().Duplicate(x => x.UserName)); store.Tenancy.Default.StorageFor(); - store.Tenancy.Default.DbObjects.DocumentTables().ShouldContain($"public.mt_doc_user"); + (await store.Tenancy.Default.DocumentTables()).Select(x => x.QualifiedName).ShouldContain($"public.mt_doc_user"); table2 = store.TableSchema(typeof(User)); table2.ShouldNotBe(table1); - ShouldBeNullExtensions.ShouldNotBeNull(table2.Column("user_name")); + ShouldBeNullExtensions.ShouldNotBeNull(table2.ColumnFor("user_name")); } - [Fact] - public void will_build_the_new_table_if_the_configured_table_does_not_match_the_existing_table_on_other_schema() - { - DocumentTable table1; - DocumentTable table2; - - StoreOptions(_ => _.DatabaseSchemaName = "other"); - - theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - - theStore.Tenancy.Default.DbObjects.DocumentTables().ShouldContain("other.mt_doc_user"); - - table1 = theStore.TableSchema(typeof(User)); - table1.ShouldNotContain(x => x.Name == "user_name"); - - - var store2 = SeparateStore(_ => - { - _.DatabaseSchemaName = "other"; - _.Schema.For().Duplicate(x => x.UserName); - _.AutoCreateSchemaObjects = AutoCreate.All; - }); - - store2.Tenancy.Default.EnsureStorageExists(typeof(User)); - - store2.Tenancy.Default.DbObjects.DocumentTables().ShouldContain("other.mt_doc_user"); - - table2 = store2.TableSchema(typeof(User)); - - - table2.ShouldNotBe(table1); - - ShouldBeNullExtensions.ShouldNotBeNull(table2.Column("user_name")); - } } } diff --git a/src/Marten.Schema.Testing/Storage/will_name_nested_class_documents_appropriately.cs b/src/Marten.Schema.Testing/Storage/will_name_nested_class_documents_appropriately.cs index db14edf019..b8ea14582c 100644 --- a/src/Marten.Schema.Testing/Storage/will_name_nested_class_documents_appropriately.cs +++ b/src/Marten.Schema.Testing/Storage/will_name_nested_class_documents_appropriately.cs @@ -1,4 +1,6 @@ using System; +using System.Linq; +using System.Threading.Tasks; using Marten.Storage; using Shouldly; using Xunit; @@ -8,7 +10,7 @@ namespace Marten.Schema.Testing.Storage public class will_name_nested_class_documents_appropriately : IntegrationContext { [Fact] - public void will_name_nested_class_table_with_containing_class_name_prefix() + public async Task will_name_nested_class_table_with_containing_class_name_prefix() { DocumentTable table1; DocumentTable table2; @@ -17,7 +19,7 @@ public void will_name_nested_class_table_with_containing_class_name_prefix() theStore.Tenancy.Default.StorageFor(); theStore.Tenancy.Default.StorageFor(); - var documentTables = theStore.Tenancy.Default.DbObjects.DocumentTables(); + var documentTables = (await theStore.Tenancy.Default.DocumentTables()).Select(x => x.QualifiedName).ToArray(); documentTables.ShouldContain("public.mt_doc_foo_document"); documentTables.ShouldContain("public.mt_doc_bar_document"); @@ -33,7 +35,7 @@ public void will_name_nested_class_table_with_containing_class_name_prefix() } [Fact] - public void will_name_nested_class_table_with_containing_class_name_prefix_on_other_database_schema() + public async Task will_name_nested_class_table_with_containing_class_name_prefix_on_other_database_schema() { DocumentTable table1; DocumentTable table2; @@ -43,7 +45,7 @@ public void will_name_nested_class_table_with_containing_class_name_prefix_on_ot theStore.Tenancy.Default.StorageFor(); theStore.Tenancy.Default.StorageFor(); - var documentTables = theStore.Tenancy.Default.DbObjects.DocumentTables(); + var documentTables = (await theStore.Tenancy.Default.DocumentTables()).Select(x => x.QualifiedName).ToArray(); documentTables.ShouldContain("other.mt_doc_foo_document"); documentTables.ShouldContain("other.mt_doc_bar_document"); diff --git a/src/Marten.Schema.Testing/SystemFunctionTests.cs b/src/Marten.Schema.Testing/SystemFunctionTests.cs index 4e4845a76e..098a8f02bb 100644 --- a/src/Marten.Schema.Testing/SystemFunctionTests.cs +++ b/src/Marten.Schema.Testing/SystemFunctionTests.cs @@ -1,4 +1,6 @@ -using Marten.Storage; +using System.Threading.Tasks; +using Weasel.Postgresql; +using Marten.Storage; using Marten.Util; using Npgsql; using Xunit; @@ -8,22 +10,22 @@ namespace Marten.Schema.Testing public class SystemFunctionTests : IntegrationContext { [Fact] - public void generate_schema_objects_if_necessary() + public async Task generate_schema_objects_if_necessary() { using (var conn = theStore.Tenancy.Default.OpenConnection()) { var cmd = new NpgsqlCommand("drop function if exists public.mt_immutable_timestamptz(text)"); - conn.Execute(cmd); + await conn.ExecuteAsync(cmd); } - theStore.Tenancy.Default.DbObjects.DefinitionForFunction(new DbObjectName("public", "mt_immutable_timestamtzp")) + (await theStore.Tenancy.Default.DefinitionForFunction(new DbObjectName("public", "mt_immutable_timestamtzp"))) .ShouldBeNull(); theStore.Tenancy.Default.ResetSchemaExistenceChecks(); theStore.Tenancy.Default.EnsureStorageExists(typeof(SystemFunctions)); - theStore.Tenancy.Default.DbObjects.DefinitionForFunction(new DbObjectName("public", "mt_immutable_timestamptz")) + (await theStore.Tenancy.Default.DefinitionForFunction(new DbObjectName("public", "mt_immutable_timestamptz"))) .ShouldNotBeNull(); } diff --git a/src/Marten.Schema.Testing/TableNameTests.cs b/src/Marten.Schema.Testing/TableNameTests.cs index 57c3d9a9e2..58ceac7976 100644 --- a/src/Marten.Schema.Testing/TableNameTests.cs +++ b/src/Marten.Schema.Testing/TableNameTests.cs @@ -1,4 +1,5 @@ -using Shouldly; +using Weasel.Postgresql; +using Shouldly; using Xunit; namespace Marten.Schema.Testing @@ -28,4 +29,4 @@ public void can_parse_without_schema() table.QualifiedName.ShouldBe("public.mt_doc_user"); } } -} \ No newline at end of file +} diff --git a/src/Marten.Schema.Testing/TestingDocumentStore.cs b/src/Marten.Schema.Testing/TestingDocumentStore.cs index e8910d6914..6db26e3d8a 100644 --- a/src/Marten.Schema.Testing/TestingDocumentStore.cs +++ b/src/Marten.Schema.Testing/TestingDocumentStore.cs @@ -1,5 +1,6 @@ using System; using Baseline; +using Weasel.Postgresql; using Marten.Testing.Harness; using Npgsql; using Xunit.Abstractions; @@ -50,7 +51,7 @@ public static DocumentStore DefaultSchema(ITestOutputHelper output = null) { if (output != null) _.Logger(new TestOutputMartenLogger(output)); - _.DatabaseSchemaName = StoreOptions.DefaultDatabaseSchemaName; + _.DatabaseSchemaName = DbObjectName.DefaultDatabaseSchemaName; }); return store; } @@ -63,7 +64,7 @@ public override void Dispose() { var schemaName = Options.DatabaseSchemaName; - if (schemaName != StoreOptions.DefaultDatabaseSchemaName) + if (schemaName != DbObjectName.DefaultDatabaseSchemaName) { var sql = $"DROP SCHEMA {schemaName} CASCADE;"; var cmd = new NpgsqlCommand(sql); diff --git a/src/Marten.Schema.Testing/WritePatch_smoke_tests.cs b/src/Marten.Schema.Testing/WritePatch_smoke_tests.cs index c221f333a6..f00084c27e 100644 --- a/src/Marten.Schema.Testing/WritePatch_smoke_tests.cs +++ b/src/Marten.Schema.Testing/WritePatch_smoke_tests.cs @@ -1,15 +1,17 @@ using System; +using System.Threading.Tasks; using Baseline; using Marten.Exceptions; using Marten.Schema.Testing.Documents; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing { public class WritePatch_smoke_tests : IntegrationContext { - private void configure() + private async Task configure() { #region sample_configure-document-types-upfront var store = DocumentStore.For(_ => @@ -27,21 +29,21 @@ private void configure() #endregion sample_configure-document-types-upfront #region sample_WritePatch - store.Schema.WritePatch("1.initial.sql"); + await store.Schema.WriteMigrationFile("1.initial.sql"); #endregion sample_WritePatch #region sample_ApplyAllConfiguredChangesToDatabase - store.Schema.ApplyAllConfiguredChangesToDatabase(); + await store.Schema.ApplyAllConfiguredChangesToDatabase(); #endregion sample_ApplyAllConfiguredChangesToDatabase #region sample_AssertDatabaseMatchesConfiguration - store.Schema.AssertDatabaseMatchesConfiguration(); + await store.Schema.AssertDatabaseMatchesConfiguration(); #endregion sample_AssertDatabaseMatchesConfiguration store.Dispose(); } [Fact(Skip = "flakey on ci")] - public void can_create_patch_for_a_single_document_type() + public async Task can_create_patch_for_a_single_document_type() { StoreOptions(_ => { @@ -50,28 +52,28 @@ public void can_create_patch_for_a_single_document_type() _.Schema.For(); }); - var patch = theStore.Schema.ToPatch(typeof(User)); + var patch = await theStore.Schema.CreateMigration(typeof(User)); - SpecificationExtensions.ShouldContain(patch.UpdateDDL, "CREATE OR REPLACE FUNCTION public.mt_upsert_user"); - SpecificationExtensions.ShouldContain(patch.UpdateDDL, "CREATE TABLE public.mt_doc_user"); - SpecificationExtensions.ShouldContain(patch.RollbackDDL, "drop table if exists public.mt_doc_user cascade;"); + patch.UpdateSql.ShouldContain("CREATE OR REPLACE FUNCTION public.mt_upsert_user"); + patch.UpdateSql.ShouldContain("CREATE TABLE public.mt_doc_user"); + patch.RollbackSql.ShouldContain("drop table if exists public.mt_doc_user cascade;"); var file = AppContext.BaseDirectory.AppendPath("bin", "update_users.sql"); - patch.WriteUpdateFile(file); + new DdlRules().WriteTemplatedFile(file, (r, w) => patch.WriteAllUpdates(w, r, AutoCreate.CreateOrUpdate)); var text = new FileSystem().ReadStringFromFile(file); - SpecificationExtensions.ShouldContain(text, "DO LANGUAGE plpgsql $tran$"); - SpecificationExtensions.ShouldContain(text, "$tran$;"); + text.ShouldContain("DO LANGUAGE plpgsql $tran$"); + text.ShouldContain("$tran$;"); } [Fact(Skip = "flakey on ci")] - public void can_do_schema_validation_negative_case_with_detected_changes() + public async Task can_do_schema_validation_negative_case_with_detected_changes() { theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); theStore.Tenancy.Default.EnsureStorageExists(typeof(Target)); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); using (var store = DocumentStore.For(_ => { @@ -80,32 +82,37 @@ public void can_do_schema_validation_negative_case_with_detected_changes() _.Schema.For(); })) { - SpecificationExtensions.ShouldContain(Exception.ShouldBeThrownBy( - () => { store.Schema.AssertDatabaseMatchesConfiguration(); }).Message, "user_name"); + var ex = await Exception.ShouldBeThrownByAsync(async + () => + { + await store.Schema.AssertDatabaseMatchesConfiguration(); + }); + + + + ex.Message.ShouldContain("user_name"); } } [Fact(Skip = "flakey on ci")] - public void can_do_schema_validation_with_no_detected_changes() + public async Task can_do_schema_validation_with_no_detected_changes() { theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); theStore.Tenancy.Default.EnsureStorageExists(typeof(Target)); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - using (var store = DocumentStore.For(_ => + using var store = DocumentStore.For(_ => { _.Connection(ConnectionSource.ConnectionString); _.Schema.For(); _.Schema.For(); - })) - { - store.Schema.AssertDatabaseMatchesConfiguration(); - } + }); + await store.Schema.AssertDatabaseMatchesConfiguration(); } [Fact] // -- flakey on ci - public void can_do_schema_validation_with_no_detected_changes_on_event_store() + public async Task can_do_schema_validation_with_no_detected_changes_on_event_store() { /* var system = new FileSystem(); @@ -128,22 +135,20 @@ public void can_do_schema_validation_with_no_detected_changes_on_event_store() _.Events.AddEventType(typeof(MembersJoined)); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - - using (var store = DocumentStore.For(_ => + using var store = DocumentStore.For(_ => { _.Connection(ConnectionSource.ConnectionString); _.Events.AddEventType(typeof(MembersJoined)); - })) - { - store.Schema.AssertDatabaseMatchesConfiguration(); - } + }); + + await store.Schema.AssertDatabaseMatchesConfiguration(); } [Fact(Skip = "flakey on ci")] - public void writes_both_the_update_and_rollback_files() + public async Task writes_both_the_update_and_rollback_files() { StoreOptions(_ => { @@ -165,7 +170,7 @@ public void writes_both_the_update_and_rollback_files() #region sample_write-patch // Write the patch SQL file to the @"bin\patches" directory - theStore.Schema.WritePatch(directory.AppendPath("1.initial.sql")); + await theStore.Schema.WriteMigrationFile(directory.AppendPath("1.initial.sql")); #endregion sample_write-patch fileSystem.FileExists(directory.AppendPath("1.initial.sql")); @@ -173,7 +178,7 @@ public void writes_both_the_update_and_rollback_files() } [Fact(Skip = "flakey on ci")] - public void writepatch_writes_patch_schema_when_autocreate_none() + public async Task writepatch_writes_patch_schema_when_autocreate_none() { StoreOptions(_ => { @@ -189,7 +194,7 @@ public void writepatch_writes_patch_schema_when_autocreate_none() #region sample_write-patch // Write the patch SQL file to the @"bin\patches" directory - theStore.Schema.WritePatch(directory.AppendPath("1.initial.sql")); + await theStore.Schema.WriteMigrationFile(directory.AppendPath("1.initial.sql")); #endregion sample_write-patch fileSystem.FileExists(directory.AppendPath("1.initial.sql")); @@ -197,7 +202,7 @@ public void writepatch_writes_patch_schema_when_autocreate_none() var patchSql = fileSystem.ReadStringFromFile(directory.AppendPath("1.initial.sql")); - SpecificationExtensions.ShouldContain(patchSql, "CREATE TABLE public.mt_doc_user"); + patchSql.ShouldContain("CREATE TABLE public.mt_doc_user"); } } diff --git a/src/Marten.Schema.Testing/add_origin_Tests.cs b/src/Marten.Schema.Testing/add_origin_Tests.cs index a173fddf7d..0478326460 100644 --- a/src/Marten.Schema.Testing/add_origin_Tests.cs +++ b/src/Marten.Schema.Testing/add_origin_Tests.cs @@ -1,4 +1,5 @@ -using Marten.Schema.Testing.Documents; +using Weasel.Postgresql; +using Marten.Schema.Testing.Documents; using Marten.Testing.Harness; using Marten.Util; using Xunit; diff --git a/src/Marten.Schema.Testing/auto_create_mode_Tests.cs b/src/Marten.Schema.Testing/auto_create_mode_Tests.cs index 083ff9b923..6db90312e0 100644 --- a/src/Marten.Schema.Testing/auto_create_mode_Tests.cs +++ b/src/Marten.Schema.Testing/auto_create_mode_Tests.cs @@ -2,6 +2,7 @@ using Marten.Schema.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing @@ -70,12 +71,11 @@ public void cannot_add_fields_if_mode_is_create_only() _.Schema.For().Duplicate(x => x.FirstName); })) { - var ex = Should.Throw(() => + var ex = Should.Throw(() => { store2.Tenancy.Default.EnsureStorageExists(typeof(User)); }); - ex.Message.ShouldBe($"Marten cannot apply updates in CreateOnly mode to existing items public.mt_doc_user, public.mt_upsert_user, public.mt_insert_user, public.mt_update_user"); } } diff --git a/src/Marten.Schema.Testing/auto_create_schema_should_ensure_storage_only_once.cs b/src/Marten.Schema.Testing/auto_create_schema_should_ensure_storage_only_once.cs index 921d17f17c..c921eb51ee 100644 --- a/src/Marten.Schema.Testing/auto_create_schema_should_ensure_storage_only_once.cs +++ b/src/Marten.Schema.Testing/auto_create_schema_should_ensure_storage_only_once.cs @@ -1,7 +1,7 @@ using System; -using System.Linq; using Marten.Schema.Testing.Identity.Sequences; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing diff --git a/src/Marten.Schema.Testing/configuring_foreign_key_fields_Tests.cs b/src/Marten.Schema.Testing/configuring_foreign_key_fields_Tests.cs index 1ca4fded5e..70a52d0533 100644 --- a/src/Marten.Schema.Testing/configuring_foreign_key_fields_Tests.cs +++ b/src/Marten.Schema.Testing/configuring_foreign_key_fields_Tests.cs @@ -15,7 +15,7 @@ public void should_get_foreign_key_from_attribute() theStore.Storage.MappingFor(typeof(Issue)) .As() .ForeignKeys - .ShouldContain(x => x.ColumnName == "user_id"); + .ShouldContain(x => x.ColumnNames[0] == "user_id"); } [Fact] @@ -32,7 +32,7 @@ public void should_get_foreign_key_from_registry() store.Storage.MappingFor(typeof(Issue)) .As() .ForeignKeys - .ShouldContain(x => x.ColumnName == "other_user_id"); + .ShouldContain(x => x.ColumnNames[0] == "other_user_id"); } [Fact] @@ -41,7 +41,7 @@ public void should_allow_self_reference() theStore.Storage.MappingFor(typeof(Employee)) .As() .ForeignKeys - .ShouldContain(x => x.ColumnName == "manager_id"); + .ShouldContain(x => x.ColumnNames[0] == "manager_id"); } [Fact] @@ -60,7 +60,7 @@ public void should_allow_foreign_key_on_id_field() store.Storage.MappingFor(typeof(FooExtra)) .As() .ForeignKeys - .ShouldContain(x => x.ColumnName == "foo_id"); + .ShouldContain(x => x.ColumnNames[0] == "foo_id"); } #region sample_issue-with-fk-attribute diff --git a/src/Marten.Schema.Testing/configuring_last_modified_index_Tests.cs b/src/Marten.Schema.Testing/configuring_last_modified_index_Tests.cs index e8ad410b42..456c7c4f59 100644 --- a/src/Marten.Schema.Testing/configuring_last_modified_index_Tests.cs +++ b/src/Marten.Schema.Testing/configuring_last_modified_index_Tests.cs @@ -1,5 +1,6 @@ using System.Linq; using Shouldly; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Schema.Testing @@ -10,7 +11,7 @@ public class configuring_last_modified_index_Tests public void creates_btree_index_for_mt_last_modified() { var mapping = DocumentMapping.For(); - var indexDefinition = mapping.Indexes.Cast().Single(x => x.Columns.First() == SchemaConstants.LastModifiedColumn); + var indexDefinition = mapping.Indexes.Cast().Single(x => x.Columns.First() == SchemaConstants.LastModifiedColumn); indexDefinition.Method.ShouldBe(IndexMethod.btree); } diff --git a/src/Marten.Schema.Testing/configuring_searchable_fields_Tests.cs b/src/Marten.Schema.Testing/configuring_searchable_fields_Tests.cs index 0d78f5d126..9b9f8aed08 100644 --- a/src/Marten.Schema.Testing/configuring_searchable_fields_Tests.cs +++ b/src/Marten.Schema.Testing/configuring_searchable_fields_Tests.cs @@ -3,6 +3,7 @@ using Baseline; using Marten.Util; using Shouldly; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Schema.Testing @@ -23,7 +24,7 @@ public void use_the_default_pg_type_for_the_member_type_if_not_overridden() public void creates_btree_index_for_the_member() { var mapping = DocumentMapping.For(); - var indexDefinition = mapping.Indexes.Cast().Single(x => x.Columns.First() == "Name".ToTableAlias()); + var indexDefinition = mapping.Indexes.Cast().Single(x => x.Columns.First() == "Name".ToTableAlias()); indexDefinition.Method.ShouldBe(IndexMethod.btree); } @@ -32,7 +33,7 @@ public void creates_btree_index_for_the_member() public void can_override_index_type_and_name_on_the_attribute() { var mapping = DocumentMapping.For(); - var indexDefinition = (IndexDefinition)mapping.Indexes.Single(x => x.IndexName == "mt_idx_foo"); + var indexDefinition = (DocumentIndex)mapping.Indexes.Single(x => x.Name == "idx_foo"); indexDefinition.Method.ShouldBe(IndexMethod.hash); } @@ -41,7 +42,7 @@ public void can_override_index_type_and_name_on_the_attribute() public void can_override_index_sort_order_on_the_attribute() { var mapping = DocumentMapping.For(); - var indexDefinition = mapping.Indexes.Cast().Single(x => x.Columns.First() == "YetAnotherName".ToTableAlias()); + var indexDefinition = mapping.Indexes.Cast().Single(x => x.Columns.First() == "YetAnotherName".ToTableAlias()); indexDefinition.SortOrder.ShouldBe(SortOrder.Desc); } diff --git a/src/Marten.Schema.Testing/create_database_Tests.cs b/src/Marten.Schema.Testing/create_database_Tests.cs index 8311b9f864..7b693c57a9 100644 --- a/src/Marten.Schema.Testing/create_database_Tests.cs +++ b/src/Marten.Schema.Testing/create_database_Tests.cs @@ -1,7 +1,10 @@ using System; +using System.Threading.Tasks; using Marten.Schema.Testing.Documents; using Marten.Testing.Harness; using Npgsql; +using Shouldly; +using Weasel.Postgresql; using Xunit; using Xunit.Sdk; @@ -10,7 +13,7 @@ namespace Marten.Schema.Testing public class create_database_Tests : IDisposable { [Fact] - public void can_create_new_database_when_one_does_not_exist_for_default_tenant() + public async Task can_create_new_database_when_one_does_not_exist_for_default_tenant() { var cstring = ConnectionSource.ConnectionString; @@ -21,9 +24,9 @@ public void can_create_new_database_when_one_does_not_exist_for_default_tenant() _.Connection(dbToCreateConnectionString); })) { - Assert.Throws(() => + await Should.ThrowAsync(async () => { - store1.Schema.ApplyAllConfiguredChangesToDatabase(); + await store1.Schema.ApplyAllConfiguredChangesToDatabase(); }); } @@ -52,8 +55,8 @@ public void can_create_new_database_when_one_does_not_exist_for_default_tenant() #endregion sample_marten_create_database })) { - store.Schema.ApplyAllConfiguredChangesToDatabase(); - store.Schema.AssertDatabaseMatchesConfiguration(); + await store.Schema.ApplyAllConfiguredChangesToDatabase(); + await store.Schema.AssertDatabaseMatchesConfiguration(); Assert.True(dbCreated); } } diff --git a/src/Marten.Schema.Testing/creating_a_full_patch.cs b/src/Marten.Schema.Testing/creating_a_full_patch.cs index a16639667f..b5251f4a1b 100644 --- a/src/Marten.Schema.Testing/creating_a_full_patch.cs +++ b/src/Marten.Schema.Testing/creating_a_full_patch.cs @@ -1,5 +1,7 @@ -using Marten.Schema.Testing.Documents; +using System.Threading.Tasks; +using Marten.Schema.Testing.Documents; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Schema.Testing @@ -8,7 +10,7 @@ namespace Marten.Schema.Testing public class creating_a_full_patch : IntegrationContext { [Fact] - public void patch_for_multiple_tables() + public async Task patch_for_multiple_tables() { theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); theStore.Tenancy.Default.EnsureStorageExists(typeof(Target)); @@ -24,7 +26,7 @@ public void patch_for_multiple_tables() _.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate; })) { - var patch = store2.Schema.ToPatch().UpdateDDL; + var patch = (await store2.Schema.CreateMigration()).UpdateSql; // don't patch Target and Company because they don't change patch.ShouldNotContain("mt_doc_company"); @@ -38,26 +40,6 @@ public void patch_for_multiple_tables() } } - [Fact] - public void base_patch_should_drop_system_functions_correctly() - { - - using (var store2 = StoreOptions(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Events.AddEventType(typeof(IssueAssigned)); - })) - { - var patch = store2.Schema.ToPatch(); - - patch.RollbackDDL.ShouldContain($"drop function if exists public.mt_immutable_timestamp(text) cascade;"); - patch.RollbackDDL.ShouldContain($"drop function if exists public.mt_immutable_timestamptz(text) cascade;"); - patch.RollbackDDL.ShouldContain($"DROP FUNCTION IF EXISTS public.mt_transform_patch_doc(JSONB, JSONB);"); - - patch.RollbackDDL.ShouldContain($"drop function if exists public.mt_mark_event_progression(varchar, bigint) cascade;"); - } - } - public creating_a_full_patch() { } diff --git a/src/Marten.Schema.Testing/ddl_generation_with_templates.cs b/src/Marten.Schema.Testing/ddl_generation_with_templates.cs index de33c2849b..cc20e41f3d 100644 --- a/src/Marten.Schema.Testing/ddl_generation_with_templates.cs +++ b/src/Marten.Schema.Testing/ddl_generation_with_templates.cs @@ -31,7 +31,7 @@ public ddl_generation_with_templates() [Fact] public void use_the_default_template_if_it_exists() { - var ddl = theStore.Schema.ToDDL(); + var ddl = theStore.Schema.ToDatabaseScript(); ddl.ShouldContain($"Default for public.mt_doc_user"); ddl.ShouldContain($"Default for public.mt_upsert_user"); } @@ -44,7 +44,7 @@ public void use_an_overridden_template_if_it_exists() -- Blue for public.mt_upsert_bluedoc */ - var ddl = theStore.Schema.ToDDL(); + var ddl = theStore.Schema.ToDatabaseScript(); ddl.ShouldContain($"Blue for public.mt_doc_bluedoc"); ddl.ShouldContain($"Blue for public.mt_upsert_bluedoc"); } diff --git a/src/Marten.Schema.Testing/do_not_overwrite_tables_with_searchable_fields_Tests.cs b/src/Marten.Schema.Testing/do_not_overwrite_tables_with_searchable_fields_Tests.cs index b01fa09158..6a538af5b9 100644 --- a/src/Marten.Schema.Testing/do_not_overwrite_tables_with_searchable_fields_Tests.cs +++ b/src/Marten.Schema.Testing/do_not_overwrite_tables_with_searchable_fields_Tests.cs @@ -5,6 +5,9 @@ using Marten.Schema.Testing.Documents; using Marten.Services; using Marten.Storage; +using Shouldly; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Schema.Testing @@ -24,18 +27,9 @@ private void searchable(Expression> expression) var configured = new DocumentTable(theStore.Storage.MappingFor(typeof(Target)).As()); - if (!existing.Equals(configured)) - { - - var writer = new StringWriter(); - writer.WriteLine("Expected:"); - configured.Write(theStore.Schema.DdlRules, writer); - writer.WriteLine(); - writer.WriteLine("But from the database, was:"); - existing.Write(theStore.Schema.DdlRules, writer); + var delta = new TableDelta(configured, existing); + delta.Difference.ShouldBe(SchemaPatchDifference.None); - throw new Exception(writer.ToString()); - } } [Fact] diff --git a/src/Marten.Schema.Testing/table_regeneration_with_new_searchable_fields_Tests.cs b/src/Marten.Schema.Testing/table_regeneration_with_new_searchable_fields_Tests.cs index 9d22e202b2..11877856e7 100644 --- a/src/Marten.Schema.Testing/table_regeneration_with_new_searchable_fields_Tests.cs +++ b/src/Marten.Schema.Testing/table_regeneration_with_new_searchable_fields_Tests.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Linq; +using Weasel.Postgresql; using Marten.Schema.Testing.Documents; using Marten.Testing.Harness; -using Marten.Util; using Shouldly; using Xunit; diff --git a/src/Marten.Storyteller/Fixtures/EventStore/EventStoreFixture.cs b/src/Marten.Storyteller/Fixtures/EventStore/EventStoreFixture.cs index 18e7b79f68..a914c21a6e 100644 --- a/src/Marten.Storyteller/Fixtures/EventStore/EventStoreFixture.cs +++ b/src/Marten.Storyteller/Fixtures/EventStore/EventStoreFixture.cs @@ -2,11 +2,10 @@ using System.Collections.Generic; using System.Linq; using Baseline; -using Marten.Testing; +using Weasel.Postgresql; using Marten.Testing.Events; using Marten.Testing.Events.Projections; using Marten.Testing.Harness; -using Marten.Util; using NpgsqlTypes; using StoryTeller; using StoryTeller.Grammars.Tables; diff --git a/src/Marten.Storyteller/Fixtures/EventStore/InlineAggregationFixture.cs b/src/Marten.Storyteller/Fixtures/EventStore/InlineAggregationFixture.cs index f870c0bd63..bfc37b999a 100644 --- a/src/Marten.Storyteller/Fixtures/EventStore/InlineAggregationFixture.cs +++ b/src/Marten.Storyteller/Fixtures/EventStore/InlineAggregationFixture.cs @@ -2,12 +2,12 @@ using System.Collections.Generic; using System.Diagnostics; using Baseline; -using Marten.Testing; using Marten.Testing.Events; using Marten.Testing.Events.Projections; using Marten.Testing.Harness; using StoryTeller; using StoryTeller.Grammars; +using Weasel.Postgresql; namespace Marten.Storyteller.Fixtures.EventStore { diff --git a/src/Marten.Testing/Acceptance/computed_indexes.cs b/src/Marten.Testing/Acceptance/computed_indexes.cs index 7dddaa0563..b9c7c09379 100644 --- a/src/Marten.Testing/Acceptance/computed_indexes.cs +++ b/src/Marten.Testing/Acceptance/computed_indexes.cs @@ -1,11 +1,13 @@ using System; using System.Linq; using System.Linq.Expressions; -using Marten.Exceptions; +using System.Threading.Tasks; +using Baseline; using Marten.Schema; using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Testing.Acceptance @@ -41,24 +43,22 @@ public void example() } [Fact] - public void smoke_test() + public async Task smoke_test() { StoreOptions(_ => _.Schema.For().Index(x => x.Number)); var data = Target.GenerateRandomData(100).ToArray(); - theStore.BulkInsert(data.ToArray()); + await theStore.BulkInsertAsync(data.ToArray()); - theStore.Tenancy.Default.DbObjects.AllIndexes().Select(x => x.Name) - .ShouldContain("mt_doc_target_idx_number"); + var table = await theStore.Tenancy.Default.ExistingTableFor(typeof(Target)); + table.HasIndex("mt_doc_target_idx_number").ShouldBeTrue(); - using (var session = theStore.QuerySession()) - { - var cmd = session.Query().Where(x => x.Number == 3) - .ToCommand(); + using var session = theStore.QuerySession(); + var cmd = session.Query().Where(x => x.Number == 3) + .ToCommand(); - session.Query().Where(x => x.Number == data.First().Number) - .Select(x => x.Id).ToList().ShouldContain(data.First().Id); - } + session.Query().Where(x => x.Number == data.First().Number) + .Select(x => x.Id).ToList().ShouldContain(data.First().Id); } [Fact] @@ -93,7 +93,7 @@ public void specify_a_different_mechanism_to_customize_the_index() x.Casing = ComputedIndex.Casings.Lower; // Override the index name if you want - x.IndexName = "mt_my_name"; + x.Name = "mt_my_name"; // Toggle whether or not the index is concurrent // Default is false @@ -109,7 +109,7 @@ public void specify_a_different_mechanism_to_customize_the_index() x.TenancyScope = Schema.Indexing.Unique.TenancyScope.PerTenant; // Partial index by supplying a condition - x.Where = "(data ->> 'Number')::int > 10"; + x.Predicate = "(data ->> 'Number')::int > 10"; }); // For B-tree indexes, it's also possible to change @@ -123,49 +123,10 @@ public void specify_a_different_mechanism_to_customize_the_index() #endregion sample_customizing-calculated-index } - [Fact] - public void specifying_an_index_type_should_create_the_index_with_that_type() - { - StoreOptions(_ => _.Schema.For().Index(x => x.Number, x => - { - x.Method = IndexMethod.brin; - })); - - var data = Target.GenerateRandomData(100).ToArray(); - theStore.BulkInsert(data.ToArray()); - - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Where(x => x.Name == "mt_doc_target_idx_number") - .Select(x => x.DDL.ToLower()) - .First(); - - SpecificationExtensions.ShouldContain(ddl, "mt_doc_target_idx_number on"); - SpecificationExtensions.ShouldContain(ddl, "mt_doc_target using brin"); - } - - [Fact] - public void create_index_with_sort_order() - { - StoreOptions(_ => _.Schema.For().Index(x => x.Number, x => - { - x.SortOrder = SortOrder.Desc; - })); - - var data = Target.GenerateRandomData(100).ToArray(); - theStore.BulkInsert(data.ToArray()); - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Where(x => x.Name == "mt_doc_target_idx_number") - .Select(x => x.DDL.ToLower()) - .First(); - - SpecificationExtensions.ShouldContain(ddl, "mt_doc_target_idx_number on"); - SpecificationExtensions.ShouldContain(ddl, "mt_doc_target"); - ddl.ShouldEndWith(" DESC)", Case.Insensitive); - } [Fact] - public void create_multi_property_index() + public async Task create_multi_property_index() { StoreOptions(_ => { @@ -178,20 +139,19 @@ public void create_multi_property_index() }); var data = Target.GenerateRandomData(100).ToArray(); - theStore.BulkInsert(data.ToArray()); + await theStore.BulkInsertAsync(data.ToArray()); + + var table = await theStore.Tenancy.Default.ExistingTableFor(typeof(Target)); + var index = table.IndexFor("mt_doc_target_idx_user_idflag").As(); + + index.DDL.ShouldBe("CREATE INDEX mt_doc_target_idx_user_idflag ON acceptance.mt_doc_target USING btree ((((data ->> 'UserId'::text))::uuid), (((data ->> 'Flag'::text))::boolean));"); - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Single(x => x.Name == "mt_doc_target_idx_user_idflag") - .DDL - .ToLower(); - SpecificationExtensions.ShouldContain(ddl, "index mt_doc_target_idx_user_idflag"); - SpecificationExtensions.ShouldContain(ddl, "((((data ->> 'userid'::text))::uuid), (((data ->> 'flag'::text))::boolean))"); } [Fact] - public void create_multi_property_string_index_with_casing() + public async Task create_multi_property_string_index_with_casing() { StoreOptions(_ => { @@ -204,69 +164,14 @@ public void create_multi_property_string_index_with_casing() }); var data = Target.GenerateRandomData(100).ToArray(); - theStore.BulkInsert(data.ToArray()); - - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Single(x => x.Name == "mt_doc_target_idx_stringstring_field") - .DDL - .ToLower(); - - SpecificationExtensions.ShouldContain(ddl, "index mt_doc_target_idx_stringstring_field"); - - SpecificationExtensions.ShouldContain(ddl, "(upper((data ->> 'string'::text)), upper((data ->> 'stringfield'::text)))"); - } - - [Fact] - public void create_multi_property_type_index_with_casing() - { - StoreOptions(_ => - { - var columns = new Expression>[] - { - x => x.String, - x => x.Long, - x => x.OtherGuid - }; - _.Schema.For().Index(columns, c => - { - c.Casing = ComputedIndex.Casings.Upper; - c.IsUnique = true; - }); - }); + await theStore.BulkInsertAsync(data.ToArray()); - var guid = Guid.NewGuid(); - using (var session = theStore.LightweightSession()) - { - var item = new Target - { - String = "string value", - Long = 123, - OtherGuid = guid - }; - session.Store(item); - session.SaveChanges(); - } + var table = await theStore.Tenancy.Default.ExistingTableFor(typeof(Target)); + var index = table.IndexFor("mt_doc_target_idx_stringstring_field").ShouldBeOfType(); - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Single(x => x.Name == "mt_doc_target_uidx_stringlongother_guid") - .DDL - .ToLower(); + index.DDL.ShouldBe("CREATE INDEX mt_doc_target_idx_stringstring_field ON acceptance.mt_doc_target USING btree (upper((data ->> 'String'::text)), upper((data ->> 'StringField'::text)));"); - SpecificationExtensions.ShouldContain(ddl, "index mt_doc_target_uidx_stringlongother_guid"); - SpecificationExtensions.ShouldContain(ddl, "(upper((data ->> 'string'::text)), (((data ->> 'long'::text))::bigint), (((data ->> 'otherguid'::text))::uuid))"); - using (var session = theStore.LightweightSession()) - { - var item = new Target - { - String = "String Value", - Long = 123, - OtherGuid = guid - }; - session.Store(item); - var exception = Assert.Throws(() => session.SaveChanges()); - Assert.Contains("duplicate key value violates unique constraint", exception.ToString()); - } } [Fact] @@ -280,64 +185,15 @@ public void creating_index_using_date_should_work() var data = Target.GenerateRandomData(100).ToArray(); theStore.BulkInsert(data.ToArray()); - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Where(x => x.Name == "mt_doc_target_idx_date") - .Select(x => x.DDL.ToLower()) - .First(); - - SpecificationExtensions.ShouldContain(ddl, "mt_doc_target_idx_date on"); - SpecificationExtensions.ShouldContain(ddl, "mt_doc_target_idx_date"); } - [Fact] - public void create_unique_index_on_string_with_mixed_casing() - { - StoreOptions(_ => _.Schema.For().Index(x => x.String, x => - { - x.IsUnique = true; - })); - - var testString = "MiXeD cAsE sTrInG"; - - using (var session = theStore.LightweightSession()) - { - var item = Target.GenerateRandomData(1).First(); - item.String = testString; - session.Store(item); - session.SaveChanges(); - } - - theStore.Tenancy.Default.DbObjects.AllIndexes().Select(x => x.Name) - .ShouldContain("mt_doc_target_uidx_string"); - - using (var session = theStore.LightweightSession()) - { - var item = Target.GenerateRandomData(1).First(); - - item.String = testString.ToLower(); - - // Inserting the same string but all lowercase should be OK - session.Store(item); - session.SaveChanges(); - - var item2 = Target.GenerateRandomData(1).First(); - - item2.String = testString; - - // Inserting the same original string should throw - session.Store(item2); - - Exception.ShouldBeThrownBy(() => session.SaveChanges()); - - } - } [Fact] - public void create_index_with_custom_name() + public async Task create_index_with_custom_name() { StoreOptions(_ => _.Schema.For().Index(x => x.String, x => { - x.IndexName = "banana_index_created_by_nigel"; + x.Name = "mt_banana_index_created_by_nigel"; })); var testString = "MiXeD cAsE sTrInG"; @@ -347,73 +203,17 @@ public void create_index_with_custom_name() var item = Target.GenerateRandomData(1).First(); item.String = testString; session.Store(item); - session.SaveChanges(); + await session.SaveChangesAsync(); } - theStore.Tenancy.Default.DbObjects.AllIndexes().Select(x => x.Name) - .ShouldContain("mt_banana_index_created_by_nigel"); - } - - [Fact] - public void create_index_with_where_clause() - { - StoreOptions(_ => _.Schema.For().Index(x => x.String, x => - { - x.Where = "(data ->> 'Number')::int > 10"; - })); - - var testString = "MiXeD cAsE sTrInG"; - - using (var session = theStore.LightweightSession()) - { - var item = Target.GenerateRandomData(1).First(); - item.String = testString; - session.Store(item); - session.SaveChanges(); - } + (await theStore.Tenancy.Default.ExistingTableFor(typeof(Target))) + .HasIndex("mt_banana_index_created_by_nigel"); - SpecificationExtensions.ShouldContain(theStore.Tenancy.Default.DbObjects.AllIndexes() - .Where(x => x.Name == "mt_doc_target_idx_string") - .Select(x => x.DDL), x => x.Contains("WHERE (((data ->> 'Number'::text))::integer > 10)")); } - [Fact] - public void create_unique_index_with_lower_case_constraint() - { - StoreOptions(_ => _.Schema.For().Index(x => x.String, x => - { - x.IsUnique = true; - x.Casing = ComputedIndex.Casings.Lower; - })); - - var testString = "MiXeD cAsE sTrInG"; - - using (var session = theStore.LightweightSession()) - { - var item = Target.GenerateRandomData(1).First(); - item.String = testString; - session.Store(item); - session.SaveChanges(); - } - - theStore.Tenancy.Default.DbObjects.AllIndexes().Select(x => x.Name) - .ShouldContain("mt_doc_target_uidx_string"); - - using (var session = theStore.LightweightSession()) - { - var item = Target.GenerateRandomData(1).First(); - - item.String = testString.ToUpper(); - - // Inserting the same string but all uppercase should throw because - // the index is stored with lowcased value - session.Store(item); - Exception.ShouldBeThrownBy(() => session.SaveChanges()); - } - } [Fact] - public void patch_if_missing() + public async Task patch_if_missing() { using (var store1 = SeparateStore()) { @@ -428,34 +228,9 @@ public void patch_if_missing() _.Schema.For().Index(x => x.Number); })) { - var patch = store2.Schema.ToPatch(); - - SpecificationExtensions.ShouldContain(patch.UpdateDDL, "mt_doc_target_idx_number"); - } - } - - [Fact] - public void no_patch_if_not_missing() - { - using (var store1 = StoreOptions(_ => - { - _.Schema.For().Index(x => x.Number); - })) - { - store1.Advanced.Clean.CompletelyRemoveAll(); - - store1.Tenancy.Default.EnsureStorageExists(typeof(Target)); - } - - using (var store2 = SeparateStore(_ => - { - _.Connection(ConnectionSource.ConnectionString); - _.Schema.For().Index(x => x.Number); - })) - { - var patch = store2.Schema.ToPatch(typeof(Target)); + var patch = await store2.Schema.CreateMigration(); - SpecificationExtensions.ShouldNotContain(patch.UpdateDDL, "mt_doc_target_idx_number"); + patch.UpdateSql.ShouldContain( "mt_doc_target_idx_number", Case.Insensitive); } } diff --git a/src/Marten.Testing/Acceptance/document_transforms.cs b/src/Marten.Testing/Acceptance/document_transforms.cs index 3afccd0cee..616065a77a 100644 --- a/src/Marten.Testing/Acceptance/document_transforms.cs +++ b/src/Marten.Testing/Acceptance/document_transforms.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; @@ -70,10 +71,10 @@ private static void transform_example(IDocumentStore store) #endregion sample_transform_example [Fact] //-- Unreliable on CI - public void use_transform_in_production_mode() + public async Task use_transform_in_production_mode() { theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); theStore.Transform.All("default_username"); diff --git a/src/Marten.Testing/Acceptance/duplicated_field.cs b/src/Marten.Testing/Acceptance/duplicated_field.cs index 55316461b2..7eea230acc 100644 --- a/src/Marten.Testing/Acceptance/duplicated_field.cs +++ b/src/Marten.Testing/Acceptance/duplicated_field.cs @@ -4,6 +4,7 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Acceptance diff --git a/src/Marten.Testing/Acceptance/foreign_keys.cs b/src/Marten.Testing/Acceptance/foreign_keys.cs index 761c5d411f..d3aa429ac7 100644 --- a/src/Marten.Testing/Acceptance/foreign_keys.cs +++ b/src/Marten.Testing/Acceptance/foreign_keys.cs @@ -2,6 +2,8 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Testing.Acceptance @@ -11,7 +13,7 @@ public class foreign_keys: IntegrationContext [Fact] public void can_insert_document_with_null_value_of_foreign_key() { - ConfigureForeignKeyWithCascadingDeletes(false); + ConfigureForeignKeyWithCascadingDeletes(CascadeAction.Restrict); var issue = new Issue(); @@ -21,7 +23,7 @@ public void can_insert_document_with_null_value_of_foreign_key() [Fact] public void can_insert_document_with_existing_value_of_foreign_key() { - ConfigureForeignKeyWithCascadingDeletes(false); + ConfigureForeignKeyWithCascadingDeletes(CascadeAction.Restrict); var user = new User(); using (var session = theStore.OpenSession()) @@ -38,7 +40,7 @@ public void can_insert_document_with_existing_value_of_foreign_key() [Fact] public void cannot_insert_document_with_non_existing_value_of_foreign_key() { - ConfigureForeignKeyWithCascadingDeletes(false); + ConfigureForeignKeyWithCascadingDeletes(CascadeAction.Restrict); var issue = new Issue { AssigneeId = Guid.NewGuid() }; @@ -55,7 +57,7 @@ public void cannot_insert_document_with_non_existing_value_of_foreign_key() [Fact] public void can_update_document_with_existing_value_of_foreign_key_to_other_existing_value() { - ConfigureForeignKeyWithCascadingDeletes(false); + ConfigureForeignKeyWithCascadingDeletes(CascadeAction.Restrict); var user = new User(); var otherUser = new User(); @@ -76,7 +78,7 @@ public void can_update_document_with_existing_value_of_foreign_key_to_other_exis [Fact] public void can_update_document_with_existing_value_of_foreign_key_to_null() { - ConfigureForeignKeyWithCascadingDeletes(false); + ConfigureForeignKeyWithCascadingDeletes(CascadeAction.Restrict); var user = new User(); var otherUser = new User(); @@ -97,7 +99,7 @@ public void can_update_document_with_existing_value_of_foreign_key_to_null() [Fact] public void cannot_update_document_with_existing_value_of_foreign_key_to_not_existing() { - ConfigureForeignKeyWithCascadingDeletes(false); + ConfigureForeignKeyWithCascadingDeletes(CascadeAction.Restrict); var user = new User(); var otherUser = new User(); @@ -125,7 +127,7 @@ public void cannot_update_document_with_existing_value_of_foreign_key_to_not_exi [Fact] public void can_delete_document_with_foreign_key() { - ConfigureForeignKeyWithCascadingDeletes(true); + ConfigureForeignKeyWithCascadingDeletes(CascadeAction.Cascade); var user = new User(); var issue = new Issue { AssigneeId = user.Id }; @@ -153,7 +155,7 @@ public void can_delete_document_with_foreign_key() [Fact] public void can_delete_document_that_is_referenced_by_foreignkey_with_cascadedeletes_from_other_document() { - ConfigureForeignKeyWithCascadingDeletes(true); + ConfigureForeignKeyWithCascadingDeletes(CascadeAction.Cascade); var user = new User(); var issue = new Issue { AssigneeId = user.Id }; @@ -181,7 +183,7 @@ public void can_delete_document_that_is_referenced_by_foreignkey_with_cascadedel [Fact] public void cannot_delete_document_that_is_referenced_by_foreignkey_without_cascadedeletes_from_other_document() { - ConfigureForeignKeyWithCascadingDeletes(false); + ConfigureForeignKeyWithCascadingDeletes(CascadeAction.Restrict); var user = new User(); var issue = new Issue { AssigneeId = user.Id }; @@ -209,11 +211,11 @@ public void cannot_delete_document_that_is_referenced_by_foreignkey_without_casc } } - private void ConfigureForeignKeyWithCascadingDeletes(bool hasCascadeDeletes) + private void ConfigureForeignKeyWithCascadingDeletes(CascadeAction onDelete) { StoreOptions(options => { - options.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = hasCascadeDeletes); + options.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.OnDelete = onDelete); }); theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); } diff --git a/src/Marten.Testing/Acceptance/full_text_index.cs b/src/Marten.Testing/Acceptance/full_text_index.cs index 56793d61a2..73b584078e 100644 --- a/src/Marten.Testing/Acceptance/full_text_index.cs +++ b/src/Marten.Testing/Acceptance/full_text_index.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Marten.Schema; using Marten.Storage; using Marten.Testing.Documents; @@ -126,7 +127,7 @@ public void using_a_single_property_full_text_index_through_store_options_with_c _.Schema.For().FullTextIndex( index => { - index.IndexName = "mt_custom_italian_user_fts_idx"; + index.Name = "mt_custom_italian_user_fts_idx"; index.RegConfig = "italian"; }, d => d.FirstName); @@ -158,7 +159,7 @@ public void using_multiple_properties_full_text_index_through_store_options_with _.Schema.For().FullTextIndex( index => { - index.IndexName = "mt_custom_italian_user_fts_idx"; + index.Name = "mt_custom_italian_user_fts_idx"; index.RegConfig = "italian"; }, d => d.FirstName, d => d.LastName); @@ -496,91 +497,19 @@ private void should_search_using_a_single_property_full_text_index_through_attri } [PgVersionTargetedFact(MinimumVersion = "10.0")] - public void creating_a_full_text_index_should_create_the_index_on_the_table() + public async Task creating_a_full_text_index_should_create_the_index_on_the_table() { StoreOptions(_ => _.Schema.For().FullTextIndex()); var data = Target.GenerateRandomData(100).ToArray(); - theStore.BulkInsert(data); - - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Where(x => x.Name == "mt_doc_target_idx_fts") - .Select(x => x.DDL.ToLower()) - .First(); - - SpecificationExtensions.ShouldContain(ddl, "create index mt_doc_target_idx_fts"); - SpecificationExtensions.ShouldContain(ddl, "on fulltext.mt_doc_target"); - SpecificationExtensions.ShouldContain(ddl, "to_tsvector"); - } - - [PgVersionTargetedFact(MinimumVersion = "10.0")] - public void not_specifying_an_index_name_should_generate_default_index_name() - { - StoreOptions(_ => _.Schema.For().FullTextIndex()); - var data = Target.GenerateRandomData(100).ToArray(); - theStore.BulkInsert(data); - - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Select(x => x.DDL.ToLower()) - .First(); - - SpecificationExtensions.ShouldContain(ddl, "mt_doc_target_idx_fts"); - } - - [PgVersionTargetedFact(MinimumVersion = "10.0")] - public void specifying_an_index_name_without_marten_prefix_should_prepend_prefix() - { - StoreOptions(_ => _.Schema.For().FullTextIndex(configure: x => x.IndexName = "doesnt_have_prefix")); - var data = Target.GenerateRandomData(100).ToArray(); - theStore.BulkInsert(data); - - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Select(x => x.DDL) - .First(); - - SpecificationExtensions.ShouldContain(ddl, "mt_doesnt_have_prefix"); - } + await theStore.BulkInsertAsync(data); - [PgVersionTargetedFact(MinimumVersion = "10.0")] - public void specifying_an_index_name_with_mixed_case_should_result_in_lower_case_name() - { - StoreOptions(_ => _.Schema.For().FullTextIndex(configure: x => x.IndexName = "Doesnt_Have_PreFix")); - var data = Target.GenerateRandomData(100).ToArray(); - theStore.BulkInsert(data); - - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Select(x => x.DDL) - .First(); - - SpecificationExtensions.ShouldContain(ddl, "mt_doesnt_have_prefix"); - } - - [PgVersionTargetedFact(MinimumVersion = "10.0")] - public void specifying_an_index_name_with_marten_prefix_remains_unchanged() - { - StoreOptions(_ => _.Schema.For().FullTextIndex(configure: x => x.IndexName = "mt_i_have_prefix")); - var data = Target.GenerateRandomData(100).ToArray(); - theStore.BulkInsert(data); - - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Select(x => x.DDL) - .First(); - - SpecificationExtensions.ShouldContain(ddl, "mt_i_have_prefix"); - } - - [PgVersionTargetedFact(MinimumVersion = "10.0")] - public void specifying_an_index_name_with_marten_prefix_and_mixed_case_results_in_lowercase_name() - { - StoreOptions(_ => _.Schema.For().FullTextIndex(configure: x => x.IndexName = "mT_I_hAve_preFIX")); - var data = Target.GenerateRandomData(100).ToArray(); - theStore.BulkInsert(data); + var table = await theStore.Tenancy.Default.ExistingTableFor(typeof(Target)); + var index = table.IndexFor("mt_doc_target_idx_fts"); + index.ShouldNotBeNull(); - var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() - .Select(x => x.DDL) - .First(); + index.ToDDL(table).ShouldContain("to_tsvector", StringComparisonOption.Default); - SpecificationExtensions.ShouldContain(ddl, "mt_i_have_prefix"); } [PgVersionTargetedFact(MinimumVersion = "10.0")] @@ -640,7 +569,7 @@ public void creating_a_full_text_index_with_custom_data_configuration_and_custom { index.DataConfig = DataConfig; index.RegConfig = RegConfig; - index.IndexName = IndexName; + index.Name = IndexName; })); var data = Target.GenerateRandomData(100).ToArray(); @@ -648,7 +577,7 @@ public void creating_a_full_text_index_with_custom_data_configuration_and_custom theStore.Storage .ShouldContainIndexDefinitionFor( - indexName: $"mt_{IndexName}", + indexName: IndexName, regConfig: RegConfig, dataConfig: DataConfig ); @@ -693,7 +622,7 @@ public void creating_a_full_text_index_with_multiple_members_and_custom_configur StoreOptions(_ => _.Schema.For().FullTextIndex( index => { - index.IndexName = IndexName; + index.Name = IndexName; index.RegConfig = RegConfig; }, d => d.AnotherString)); @@ -703,7 +632,7 @@ public void creating_a_full_text_index_with_multiple_members_and_custom_configur theStore.Storage .ShouldContainIndexDefinitionFor( - indexName: $"mt_{IndexName}", + indexName: IndexName, regConfig: RegConfig, dataConfig: $"((data ->> '{nameof(Target.AnotherString)}'))" ); @@ -837,7 +766,7 @@ public void using_multiple_properties_full_text_index_through_attribute_with_cus } [PgVersionTargetedFact(MinimumVersion = "10.0")] - public void wholedoc_fts_index_comparison_works() + public async Task wholedoc_fts_index_comparison_works() { StoreOptions(_ => { @@ -845,16 +774,16 @@ public void wholedoc_fts_index_comparison_works() }); // Apply changes - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); // Look at updates after that - var patch = theStore.Schema.ToPatch(); + var patch = await theStore.Schema.CreateMigration(); - Assert.DoesNotContain("drop index fulltext.mt_doc_user_idx_fts", patch.UpdateDDL); + Assert.DoesNotContain("drop index fulltext.mt_doc_user_idx_fts", patch.UpdateSql); } [PgVersionTargetedFact(MinimumVersion = "10.0")] - public void fts_index_comparison_must_take_into_account_automatic_cast() + public async Task fts_index_comparison_must_take_into_account_automatic_cast() { StoreOptions(_ => { @@ -863,16 +792,16 @@ public void fts_index_comparison_must_take_into_account_automatic_cast() }); // Apply changes - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); // Look at updates after that - var patch = theStore.Schema.ToPatch(); + var patch = await theStore.Schema.CreateMigration(); - Assert.DoesNotContain("drop index fulltext.mt_doc_company_idx_fts", patch.UpdateDDL); + Assert.DoesNotContain("drop index fulltext.mt_doc_company_idx_fts", patch.UpdateSql); } [PgVersionTargetedFact(MinimumVersion = "10.0")] - public void multifield_fts_index_comparison_must_take_into_account_automatic_cast() + public async Task multifield_fts_index_comparison_must_take_into_account_automatic_cast() { StoreOptions(_ => { @@ -881,16 +810,16 @@ public void multifield_fts_index_comparison_must_take_into_account_automatic_cas }); // Apply changes - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); // Look at updates after that - var patch = theStore.Schema.ToPatch(); + var patch = await theStore.Schema.CreateMigration(); - Assert.DoesNotContain("drop index fulltext.mt_doc_user_idx_fts", patch.UpdateDDL); + Assert.DoesNotContain("drop index fulltext.mt_doc_user_idx_fts", patch.UpdateSql); } [PgVersionTargetedFact(MinimumVersion = "10.0")] - public void modified_fts_index_comparison_must_generate_drop() + public async Task modified_fts_index_comparison_must_generate_drop() { StoreOptions(_ => { @@ -899,7 +828,7 @@ public void modified_fts_index_comparison_must_generate_drop() }); // Apply changes - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); // Change indexed fields var store = DocumentStore.For(_ => @@ -912,9 +841,9 @@ public void modified_fts_index_comparison_must_generate_drop() }); // Look at updates after that - var patch = store.Schema.ToPatch(); + var patch = await store.Schema.CreateMigration(); - Assert.Contains("drop index fulltext.mt_doc_user_idx_fts", patch.UpdateDDL); + Assert.Contains("drop index concurrently if exists fulltext.mt_doc_user_idx_fts", patch.UpdateSql); } } @@ -928,12 +857,14 @@ public static void ShouldContainIndexDefinitionFor( string regConfig = "english", string dataConfig = null) { - var ddl = storage.MappingFor(typeof(TDocument)).Indexes - .Where(x => x.IndexName == indexName) - .Select(x => x.ToDDL()) + var documentMapping = storage.MappingFor(typeof(TDocument)); + var table = new DocumentTable(documentMapping); + var ddl = documentMapping.Indexes + .Where(x => x.Name == indexName) + .Select(x => x.ToDDL(table)) .FirstOrDefault(); - SpecificationExtensions.ShouldNotBeNull(ddl); + ddl.ShouldNotBeNull(); SpecificationExtensions.ShouldContain(ddl, $"CREATE INDEX {indexName}"); SpecificationExtensions.ShouldContain(ddl, $"ON {tableName}"); diff --git a/src/Marten.Testing/Acceptance/multi_tenancy.cs b/src/Marten.Testing/Acceptance/multi_tenancy.cs index ed5e0e8bf6..6bae39801b 100644 --- a/src/Marten.Testing/Acceptance/multi_tenancy.cs +++ b/src/Marten.Testing/Acceptance/multi_tenancy.cs @@ -7,6 +7,8 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; using Xunit; using Xunit.Abstractions; @@ -161,17 +163,17 @@ public async Task composite_key_correctly_used_for_upsert_concurrency_check() } [Fact] - public void can_add_same_primary_key_to_multiple_tenant() + public async Task can_add_same_primary_key_to_multiple_tenant() { var guid = Guid.NewGuid(); theStore.Tenancy.Default.EnsureStorageExists(typeof(Target)); - var existing = theStore.Tenancy.Default.DbObjects.ExistingTableFor(typeof(Target)); + var existing = await theStore.Tenancy.Default.ExistingTableFor(typeof(Target)); var mapping = theStore.Options.Storage.MappingFor(typeof(Target)); var expected = new DocumentTable(mapping); var delta = new TableDelta(expected, existing); - delta.Matches.ShouldBeTrue(); + delta.Difference.ShouldBe(SchemaPatchDifference.None); using (var session = theStore.OpenSession("123")) { @@ -179,7 +181,7 @@ public void can_add_same_primary_key_to_multiple_tenant() target.Id = guid; target.String = "123"; session.ForTenant("123").Store(target); - session.SaveChanges(); + await session.SaveChangesAsync(); } using (var session = theStore.OpenSession("abc")) @@ -188,20 +190,20 @@ public void can_add_same_primary_key_to_multiple_tenant() target.Id = guid; target.String = "abc"; session.ForTenant("abc").Store(target); - session.SaveChanges(); + await session.SaveChangesAsync(); } using (var session = theStore.OpenSession("123")) { var target = session.Load(guid); - SpecificationExtensions.ShouldNotBeNull(target); + target.ShouldNotBeNull(); target.String.ShouldBe("123"); } using (var session = theStore.OpenSession("abc")) { var target = session.Load(guid); - SpecificationExtensions.ShouldNotBeNull(target); + target.ShouldNotBeNull(); target.String.ShouldBe("abc"); } } diff --git a/src/Marten.Testing/Acceptance/npgsql_multiplexing.cs b/src/Marten.Testing/Acceptance/npgsql_multiplexing.cs index 7a9437fb14..d32ca7ea3e 100644 --- a/src/Marten.Testing/Acceptance/npgsql_multiplexing.cs +++ b/src/Marten.Testing/Acceptance/npgsql_multiplexing.cs @@ -11,14 +11,17 @@ public class npgsql_multiplexing : IntegrationContext { private readonly string _connectionMultiplexed = $"{ConnectionSource.ConnectionString};multiplexing=true"; - [Fact(Skip= "Failing - Issue #1646")] + [Fact] public async Task can_insert_documents() { using var store = DocumentStore.For(options => { options.Connection(_connectionMultiplexed); + options.DatabaseSchemaName = "multiplex"; }); + await store.Advanced.Clean.CompletelyRemoveAsync(typeof(Target)); + await using (var session = store.OpenSession()) { session.Insert(Target.GenerateRandomData(99).ToArray()); @@ -27,7 +30,7 @@ public async Task can_insert_documents() await using (var query = store.QuerySession()) { - query.Query().Count().ShouldBe(99); + (await query.Query().CountAsync()).ShouldBe(99); } } diff --git a/src/Marten.Testing/Acceptance/patching_api.cs b/src/Marten.Testing/Acceptance/patching_api.cs index 6634e8846e..581d790ee0 100644 --- a/src/Marten.Testing/Acceptance/patching_api.cs +++ b/src/Marten.Testing/Acceptance/patching_api.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; -using Marten.Linq; +using System.Threading.Tasks; using Marten.Linq.Filters; using Marten.Patching; -using Marten.Services; using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Acceptance @@ -24,13 +24,13 @@ public patching_api() : base("patching_api") } [Fact] - public void can_use_patch_api_when_autocreate_is_none() + public async Task can_use_patch_api_when_autocreate_is_none() { - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); var entity = Target.Random(); theSession.Store(entity); - theSession.SaveChanges(); + await theSession.SaveChangesAsync(); @@ -40,10 +40,11 @@ public void can_use_patch_api_when_autocreate_is_none() o.UseDefaultSerialization(EnumStorage.AsString); o.AutoCreateSchemaObjects = AutoCreate.None; }); + using (var session = store.LightweightSession()) { session.Patch(entity.Id).Set(t => t.String, "foo"); - session.SaveChanges(); + await session.SaveChangesAsync(); } } @@ -773,52 +774,48 @@ public void delete_property_from_many_documents() } [Fact] - public void bug_611_duplicate_field_is_updated_by_set_operation() + public async Task bug_611_duplicate_field_is_updated_by_set_operation() { var mapping = theStore.Storage.MappingFor(typeof(Target)); var field = mapping.DuplicateField("String"); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); var entity = Target.Random(); theSession.Store(entity); - theSession.SaveChanges(); + await theSession.SaveChangesAsync(); var newval = new string(entity.String.Reverse().ToArray()); theSession.Patch(entity.Id).Set(t => t.String, newval); - theSession.SaveChanges(); + await theSession.SaveChangesAsync(); - using (var command = theSession.Connection.CreateCommand()) - { - command.CommandText = $"select count(*) from {mapping.TableName.QualifiedName} " + - $"where data->>'String' = '{newval}' and {field.ColumnName} = '{newval}'"; - var count = (long)(command.ExecuteScalar() ?? 0); - count.ShouldBe(1); - } + using var command = theSession.Connection.CreateCommand(); + command.CommandText = $"select count(*) from {mapping.TableName.QualifiedName} " + + $"where data->>'String' = '{newval}' and {field.ColumnName} = '{newval}'"; + var count = (long)(command.ExecuteScalar() ?? 0); + count.ShouldBe(1); } [Fact] - public void bug_611_duplicate_field_is_updated_by_set_operation_with_multiple_duplicates_smoke_test() + public async Task bug_611_duplicate_field_is_updated_by_set_operation_with_multiple_duplicates_smoke_test() { var mapping = theStore.Storage.MappingFor(typeof(Target)); var field = mapping.DuplicateField("String"); var field2 = mapping.DuplicateField(nameof(Target.Number)); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); var entity = Target.Random(); theSession.Store(entity); - theSession.SaveChanges(); + await theSession.SaveChangesAsync(); var newval = new string(entity.String.Reverse().ToArray()); theSession.Patch(entity.Id).Set(t => t.String, newval); - theSession.SaveChanges(); + await theSession.SaveChangesAsync(); - using (var command = theSession.Connection.CreateCommand()) - { - command.CommandText = $"select count(*) from {mapping.TableName.QualifiedName} " + - $"where data->>'String' = '{newval}' and {field.ColumnName} = '{newval}'"; - var count = (long)(command.ExecuteScalar() ?? 0); - count.ShouldBe(1); - } + using var command = theSession.Connection.CreateCommand(); + command.CommandText = $"select count(*) from {mapping.TableName.QualifiedName} " + + $"where data->>'String' = '{newval}' and {field.ColumnName} = '{newval}'"; + var count = (long)(command.ExecuteScalar() ?? 0); + count.ShouldBe(1); } } diff --git a/src/Marten.Testing/Acceptance/soft_deletes.cs b/src/Marten.Testing/Acceptance/soft_deletes.cs index e59b3fe36d..4ca6b7b615 100644 --- a/src/Marten.Testing/Acceptance/soft_deletes.cs +++ b/src/Marten.Testing/Acceptance/soft_deletes.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Marten.Linq.SoftDeletes; using Marten.Metadata; +using Weasel.Postgresql; using Marten.Testing.CoreFunctionality; using Marten.Testing.Documents; using Marten.Testing.Harness; diff --git a/src/Marten.Testing/AssemblyInfo.cs b/src/Marten.Testing/AssemblyInfo.cs index eda3b8102d..63bf3d35db 100644 --- a/src/Marten.Testing/AssemblyInfo.cs +++ b/src/Marten.Testing/AssemblyInfo.cs @@ -1,2 +1,2 @@ using Xunit; -[assembly: CollectionBehavior(DisableTestParallelization = false)] +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/src/Marten.Testing/Bugs/Bug_1002_new_duplicate_field_write_patch_syntax_error.cs b/src/Marten.Testing/Bugs/Bug_1002_new_duplicate_field_write_patch_syntax_error.cs index 094ab478a4..7e9b337fd6 100644 --- a/src/Marten.Testing/Bugs/Bug_1002_new_duplicate_field_write_patch_syntax_error.cs +++ b/src/Marten.Testing/Bugs/Bug_1002_new_duplicate_field_write_patch_syntax_error.cs @@ -1,4 +1,6 @@ +using System.Threading.Tasks; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs @@ -6,7 +8,7 @@ namespace Marten.Testing.Bugs public class Bug_1002_new_duplicate_field_write_patch_syntax_error: BugIntegrationContext { [Fact] - public void update_patch_should_not_contain_double_semicolon() + public async Task update_patch_should_not_contain_double_semicolon() { StoreOptions(_ => { @@ -15,7 +17,7 @@ public void update_patch_should_not_contain_double_semicolon() _.Schema.For(); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); var store = SeparateStore(_ => { @@ -24,7 +26,7 @@ public void update_patch_should_not_contain_double_semicolon() .Duplicate(x => x.Name); // add a new duplicate column }); - store.Schema.ToPatch().UpdateDDL.ShouldNotContain(";;"); + (await store.Schema.CreateMigration()).UpdateSql.ShouldNotContain(";;"); } } diff --git a/src/Marten.Testing/Bugs/Bug_1018_multi_key_unique_index_schema_update_assert_failure.cs b/src/Marten.Testing/Bugs/Bug_1018_multi_key_unique_index_schema_update_assert_failure.cs index 15c6b3adf2..e0c77ebb44 100644 --- a/src/Marten.Testing/Bugs/Bug_1018_multi_key_unique_index_schema_update_assert_failure.cs +++ b/src/Marten.Testing/Bugs/Bug_1018_multi_key_unique_index_schema_update_assert_failure.cs @@ -1,6 +1,8 @@ using System; +using System.Threading.Tasks; using Marten.Schema; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs @@ -15,7 +17,7 @@ public class Doc_1018 public class Bug_1018_multi_key_unique_index_schema_update_assert_failure: BugIntegrationContext { [Fact] - public void check_database_matches_configuration_with_multi_key_unique_index() + public async Task check_database_matches_configuration_with_multi_key_unique_index() { StoreOptions(_ => { @@ -26,8 +28,8 @@ public void check_database_matches_configuration_with_multi_key_unique_index() .UniqueIndex(UniqueIndexType.DuplicatedField, x => x.Field1, x => x.Field2); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - theStore.Schema.AssertDatabaseMatchesConfiguration(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.AssertDatabaseMatchesConfiguration(); } } diff --git a/src/Marten.Testing/Bugs/Bug_1043_do_not_drop_unchanged_index.cs b/src/Marten.Testing/Bugs/Bug_1043_do_not_drop_unchanged_index.cs deleted file mode 100644 index 2342e57f91..0000000000 --- a/src/Marten.Testing/Bugs/Bug_1043_do_not_drop_unchanged_index.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Marten.Schema; -using Marten.Storage; -using Marten.Testing.Harness; -using Xunit; - -namespace Marten.Testing.Bugs -{ - public class Bug_1043_do_not_drop_unchanged_index: BugIntegrationContext - { - [Fact] - public void do_not_drop_unchanged_index() - { - StoreOptions(_ => - { - _.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate; - _.Advanced.DdlRules.TableCreation = CreationStyle.CreateIfNotExists; - _.Schema.For().Index(x => x.Name, x => - { - x.IndexName = "Test_Index"; - x.IsUnique = true; - x.Casing = ComputedIndex.Casings.Lower; - x.IsConcurrent = true; - }); - }); - - using (var session = theStore.OpenSession()) - { - session.Insert(new Bug1043.Thing - { - Id = "test/1", - Name = "A Thing", - Count = 1 - }); - - session.SaveChanges(); - } - - var mapping = DocumentMapping.For(); - mapping.DatabaseSchemaName = SchemaName; - mapping.Index(x => x.Name, x => - { - x.IndexName = "Test_Index"; - x.IsUnique = true; - x.Casing = ComputedIndex.Casings.Lower; - x.IsConcurrent = true; - - }); - var docTable = new DocumentTable(mapping); - - using (var connection = new Npgsql.NpgsqlConnection(ConnectionSource.ConnectionString)) - { - connection.Open(); - - var diff = docTable.FetchDelta(connection); - - Assert.NotNull(diff); - Assert.Equal(0, diff.IndexChanges.Count); - Assert.Equal(0, diff.IndexRollbacks.Count); - } - } - - } -} - -namespace Bug1043 -{ - public class Thing - { - public string Id { get; set; } - public string Name { get; set; } - public int Count { get; set; } - } -} diff --git a/src/Marten.Testing/Bugs/Bug_1151_assert_database_matches_configuration_exception.cs b/src/Marten.Testing/Bugs/Bug_1151_assert_database_matches_configuration_exception.cs index b41ec61379..8fc9804c05 100644 --- a/src/Marten.Testing/Bugs/Bug_1151_assert_database_matches_configuration_exception.cs +++ b/src/Marten.Testing/Bugs/Bug_1151_assert_database_matches_configuration_exception.cs @@ -1,4 +1,6 @@ +using System.Threading.Tasks; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs @@ -6,7 +8,7 @@ namespace Marten.Testing.Bugs public class Bug_1151_assert_db_matches_config_exception: BugIntegrationContext { [Fact] - public void check_assert_db_matches_config_for_doc_with_pg_keyword_prop() + public async Task check_assert_db_matches_config_for_doc_with_pg_keyword_prop() { StoreOptions(_ => { @@ -15,8 +17,8 @@ public void check_assert_db_matches_config_for_doc_with_pg_keyword_prop() .Duplicate(c => c.Trim); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - theStore.Schema.AssertDatabaseMatchesConfiguration(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.AssertDatabaseMatchesConfiguration(); } } diff --git a/src/Marten.Testing/Bugs/Bug_1155_null_duplicate_fields.cs b/src/Marten.Testing/Bugs/Bug_1155_null_duplicate_fields.cs index c76fce22cb..c578b09549 100644 --- a/src/Marten.Testing/Bugs/Bug_1155_null_duplicate_fields.cs +++ b/src/Marten.Testing/Bugs/Bug_1155_null_duplicate_fields.cs @@ -2,6 +2,7 @@ using Marten.Services; using Marten.Testing.Documents; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs diff --git a/src/Marten.Testing/Bugs/Bug_1173_patch_typenamehandling_bug.cs b/src/Marten.Testing/Bugs/Bug_1173_patch_typenamehandling_bug.cs index 0ba1cfa802..ebff7ec635 100644 --- a/src/Marten.Testing/Bugs/Bug_1173_patch_typenamehandling_bug.cs +++ b/src/Marten.Testing/Bugs/Bug_1173_patch_typenamehandling_bug.cs @@ -1,5 +1,6 @@ using Marten.Services; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs @@ -28,7 +29,7 @@ public void can_support_typenamehandling() config.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects; }); _.Serializer(serializer); - _.AutoCreateSchemaObjects = Marten.AutoCreate.All; + _.AutoCreateSchemaObjects = AutoCreate.All; })) { using (var session = store.OpenSession()) diff --git a/src/Marten.Testing/Bugs/Bug_1258_cannot_derive_updates_for_objects.cs b/src/Marten.Testing/Bugs/Bug_1258_cannot_derive_updates_for_objects.cs index c60532fa04..9ce63fac93 100644 --- a/src/Marten.Testing/Bugs/Bug_1258_cannot_derive_updates_for_objects.cs +++ b/src/Marten.Testing/Bugs/Bug_1258_cannot_derive_updates_for_objects.cs @@ -4,6 +4,7 @@ using Marten.Testing.Harness; using Npgsql; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs diff --git a/src/Marten.Testing/Bugs/Bug_127_do_not_recreate_a_table_with_duplicated_string_field_Tests.cs b/src/Marten.Testing/Bugs/Bug_127_do_not_recreate_a_table_with_duplicated_string_field_Tests.cs index bf8979139f..a49e6a32d9 100644 --- a/src/Marten.Testing/Bugs/Bug_127_do_not_recreate_a_table_with_duplicated_string_field_Tests.cs +++ b/src/Marten.Testing/Bugs/Bug_127_do_not_recreate_a_table_with_duplicated_string_field_Tests.cs @@ -3,6 +3,7 @@ using Marten.Schema; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs diff --git a/src/Marten.Testing/Bugs/Bug_1308_get_dependent_types_should_not_return_null.cs b/src/Marten.Testing/Bugs/Bug_1308_get_dependent_types_should_not_return_null.cs deleted file mode 100644 index 82b6949df2..0000000000 --- a/src/Marten.Testing/Bugs/Bug_1308_get_dependent_types_should_not_return_null.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Linq; -using Marten.Schema; -using Marten.Storage; -using Shouldly; -using Xunit; - -namespace Marten.Testing.Bugs -{ - public class Bug_1308_get_dependent_types_should_not_return_null - { - [Fact] - public void documentmapping_dependenttypes_should_not_include_nulls() - { - var docMap = new DocumentMapping(typeof(BugTestClass), new StoreOptions()); - docMap.ForeignKeys.Add(new ExternalForeignKeyDefinition("test_column", docMap, "test_schema", "test_table", "test_column_2")); - - docMap.Schema.DependentTypes().Any(t => t == null).ShouldBeFalse(); - } - - public class BugTestClass - { - public Guid Id; - } - } -} diff --git a/src/Marten.Testing/Bugs/Bug_1325_Any_with_contains_on_IList_of_string.cs b/src/Marten.Testing/Bugs/Bug_1325_Any_with_contains_on_IList_of_string.cs index 317af4e4b2..7f44132ddb 100644 --- a/src/Marten.Testing/Bugs/Bug_1325_Any_with_contains_on_IList_of_string.cs +++ b/src/Marten.Testing/Bugs/Bug_1325_Any_with_contains_on_IList_of_string.cs @@ -9,13 +9,6 @@ namespace Marten.Testing.Bugs { public class Bug_1325_Any_with_contains_on_IList_of_string: IntegrationContext { - public class DocWithLists - { - public Guid Id { get; set; } - - public IList Names { get; set; } = new List(); - } - [Fact] public void can_do_any_with_contains_against_IList() { @@ -74,4 +67,11 @@ public Bug_1325_Any_with_contains_on_IList_of_string(DefaultStoreFixture fixture { } } + + public class DocWithLists + { + public Guid Id { get; set; } + + public IList Names { get; set; } = new List(); + } } diff --git a/src/Marten.Testing/Bugs/Bug_1429_fk_ordering_problems.cs b/src/Marten.Testing/Bugs/Bug_1429_fk_ordering_problems.cs index b5bb58272a..59d652602c 100644 --- a/src/Marten.Testing/Bugs/Bug_1429_fk_ordering_problems.cs +++ b/src/Marten.Testing/Bugs/Bug_1429_fk_ordering_problems.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; using Xunit.Abstractions; diff --git a/src/Marten.Testing/Bugs/Bug_1473_warn_about_custom_value_types_in_linq.cs b/src/Marten.Testing/Bugs/Bug_1473_warn_about_custom_value_types_in_linq.cs index 020b3d2b9a..5d19feba47 100644 --- a/src/Marten.Testing/Bugs/Bug_1473_warn_about_custom_value_types_in_linq.cs +++ b/src/Marten.Testing/Bugs/Bug_1473_warn_about_custom_value_types_in_linq.cs @@ -12,17 +12,6 @@ public Bug_1473_warn_about_custom_value_types_in_linq(DefaultStoreFixture fixtur { } - public class MyClass - { - public string Id { get; set; } - public CustomObject CustomObject { get; set; } - } - - public class CustomObject - { - public string Name { get; set; } - } - [Fact] public void get_a_descriptive_exception_message() { @@ -34,4 +23,15 @@ public void get_a_descriptive_exception_message() ex.Message.ShouldBe("Marten cannot support custom value types in Linq expression. Please query on either simple properties of the value type, or register a custom IFieldSource for this value type."); } } + + public class MyClass + { + public string Id { get; set; } + public CustomObject CustomObject { get; set; } + } + + public class CustomObject + { + public string Name { get; set; } + } } diff --git a/src/Marten.Testing/Bugs/Bug_1563_user_friendly_warning_about_public_type.cs b/src/Marten.Testing/Bugs/Bug_1563_user_friendly_warning_about_public_type.cs index c63a76119e..6f625e4506 100644 --- a/src/Marten.Testing/Bugs/Bug_1563_user_friendly_warning_about_public_type.cs +++ b/src/Marten.Testing/Bugs/Bug_1563_user_friendly_warning_about_public_type.cs @@ -1,4 +1,6 @@ using System; +using Marten.Events.Projections; +using Marten.Schema; using Marten.Testing.Harness; using Xunit; @@ -6,6 +8,7 @@ namespace Marten.Testing.Bugs { public class Bug_1563_user_friendly_warning_about_public_type : BugIntegrationContext { + [DocumentAlias("internal_doc")] internal class InternalDoc { public Guid Id { get; set; } @@ -15,6 +18,7 @@ internal class InternalDoc public void good_error_on_non_public_type() { var expectedMessage = "Requested document type 'Marten.Testing.Bugs.Bug_1563_user_friendly_warning_about_public_type.InternalDoc' must be either scoped as 'public' or the assembly holding it must use the InternalsVisibleToAttribute pointing to 'Marten.Generated'"; + var ex = Exception.ShouldBeThrownBy(() => { var doc = new InternalDoc(); diff --git a/src/Marten.Testing/Bugs/Bug_1703_Equality_Not_Symmetric.cs b/src/Marten.Testing/Bugs/Bug_1703_Equality_Not_Symmetric.cs index 83fbbfcf16..c68fa3533c 100644 --- a/src/Marten.Testing/Bugs/Bug_1703_Equality_Not_Symmetric.cs +++ b/src/Marten.Testing/Bugs/Bug_1703_Equality_Not_Symmetric.cs @@ -13,7 +13,7 @@ public sealed class Bug_1703_Equality_Not_Symmetric: IntegrationContext public Bug_1703_Equality_Not_Symmetric(DefaultStoreFixture fixture) : base(fixture) { } - + [Fact] public void string_equality_equals_operator_should_be_symmetric() { @@ -33,7 +33,7 @@ public void string_equality_equals_operator_should_be_symmetric() .ToList() .Count .ShouldBe(1); - + session.Query() .Where(x => theString == x.String ) .ToList() @@ -50,7 +50,7 @@ public async Task string_equality_equals_should_be_symmetric() using (var session = theStore.OpenSession()) { session.Insert(random); - session.SaveChanges(); + await session.SaveChangesAsync(); } using (var session = theStore.QuerySession()) @@ -61,7 +61,7 @@ public async Task string_equality_equals_should_be_symmetric() .ToList() .Count .ShouldBe(1); - + session.Query() .Where(x => theString.Equals(x.String)) .ToList() @@ -70,8 +70,8 @@ public async Task string_equality_equals_should_be_symmetric() } } - - + + [Fact] public async Task string_equality_equals_ignoring_case_should_be_symmetric() { @@ -80,12 +80,12 @@ public async Task string_equality_equals_ignoring_case_should_be_symmetric() using (var session = theStore.OpenSession()) { session.Insert(random); - session.SaveChanges(); + await session.SaveChangesAsync(); } using (var session = theStore.QuerySession()) { - + session.Query() .Where(x => x.String.Equals(theString, StringComparison.InvariantCultureIgnoreCase)) .ToList() @@ -97,10 +97,10 @@ public async Task string_equality_equals_ignoring_case_should_be_symmetric() .ToList() .Count .ShouldBe(1); - + } } - + [Fact] public async Task object_equality_equals_should_be_symmetric() { @@ -109,7 +109,7 @@ public async Task object_equality_equals_should_be_symmetric() using (var session = theStore.OpenSession()) { session.Insert(random); - session.SaveChanges(); + await session.SaveChangesAsync(); } using (var session = theStore.QuerySession()) @@ -120,7 +120,7 @@ public async Task object_equality_equals_should_be_symmetric() .ToList() .Count .ShouldBe(1); - + session.Query() .Where(x => theNumber.Equals(x.Number)) .ToList() @@ -128,7 +128,7 @@ public async Task object_equality_equals_should_be_symmetric() .ShouldBe(1); } } - + [Fact] public async Task object_equality_equals_operator_should_be_symmetric() { @@ -137,7 +137,7 @@ public async Task object_equality_equals_operator_should_be_symmetric() using (var session = theStore.OpenSession()) { session.Insert(random); - session.SaveChanges(); + await session.SaveChangesAsync(); } using (var session = theStore.QuerySession()) @@ -148,7 +148,7 @@ public async Task object_equality_equals_operator_should_be_symmetric() .ToList() .Count .ShouldBe(1); - + session.Query() .Where(x => theNumber == x.Number) .ToList() @@ -157,4 +157,4 @@ public async Task object_equality_equals_operator_should_be_symmetric() } } } -} \ No newline at end of file +} diff --git a/src/Marten.Testing/Bugs/Bug_1710_selecting_to_anonymous_type_with_numbers_using_jil.cs b/src/Marten.Testing/Bugs/Bug_1710_selecting_to_anonymous_type_with_numbers_using_jil.cs index cfac528865..5961c70924 100644 --- a/src/Marten.Testing/Bugs/Bug_1710_selecting_to_anonymous_type_with_numbers_using_jil.cs +++ b/src/Marten.Testing/Bugs/Bug_1710_selecting_to_anonymous_type_with_numbers_using_jil.cs @@ -1,6 +1,8 @@ using System; using System.Linq; using System.Threading.Tasks; +using Marten.Events.Projections; +using Marten.Schema; using Marten.Testing.Harness; using Shouldly; using Xunit; @@ -34,6 +36,7 @@ public async Task select_to_anonymous_type() custom.Number.ShouldBe(myDoc.Number); } + [DocumentAlias("mydoc")] public class MyDoc { public Guid Id { get; set; } diff --git a/src/Marten.Testing/Bugs/Bug_1779_null_comparison_to_foreign_key_column_not_generating_is_null.cs b/src/Marten.Testing/Bugs/Bug_1779_null_comparison_to_foreign_key_column_not_generating_is_null.cs index bd2762135a..82bbd1cb87 100644 --- a/src/Marten.Testing/Bugs/Bug_1779_null_comparison_to_foreign_key_column_not_generating_is_null.cs +++ b/src/Marten.Testing/Bugs/Bug_1779_null_comparison_to_foreign_key_column_not_generating_is_null.cs @@ -1,13 +1,11 @@ using System; using System.Linq; using System.Threading.Tasks; - using Bug1779; - using Marten.Testing.Harness; using Shouldly; - +using Weasel.Postgresql; using Xunit; using Xunit.Abstractions; diff --git a/src/Marten.Testing/Bugs/Bug_336_completely_remove_crosses_schema_lines.cs b/src/Marten.Testing/Bugs/Bug_336_completely_remove_crosses_schema_lines.cs index f51f82a20c..bb29518db1 100644 --- a/src/Marten.Testing/Bugs/Bug_336_completely_remove_crosses_schema_lines.cs +++ b/src/Marten.Testing/Bugs/Bug_336_completely_remove_crosses_schema_lines.cs @@ -1,7 +1,9 @@ using System.Linq; +using System.Threading.Tasks; using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs @@ -9,12 +11,12 @@ namespace Marten.Testing.Bugs public class Bug_336_completely_remove_crosses_schema_lines : BugIntegrationContext { [Fact] - public void do_not_remove_items_out_of_the_main_schema() + public async Task do_not_remove_items_out_of_the_main_schema() { var store1 = theStore; - store1.BulkInsert(Target.GenerateRandomData(5).ToArray()); - store1.BulkInsert(new[] { new User() }); - store1.Tenancy.Default.DbObjects.DocumentTables().Any().ShouldBeTrue(); + await store1.BulkInsertAsync(Target.GenerateRandomData(5).ToArray()); + await store1.BulkInsertAsync(new[] { new User() }); + (await store1.Tenancy.Default.DocumentTables()).Any().ShouldBeTrue(); var store2 = SeparateStore(_ => { @@ -22,13 +24,13 @@ public void do_not_remove_items_out_of_the_main_schema() _.DatabaseSchemaName = "other_bug"; }); - store2.BulkInsert(Target.GenerateRandomData(5).ToArray()); - store2.BulkInsert(new[] { new User() }); - store2.Tenancy.Default.DbObjects.DocumentTables().Any().ShouldBeTrue(); + await store2.BulkInsertAsync(Target.GenerateRandomData(5).ToArray()); + await store2.BulkInsertAsync(new[] { new User() }); + (await store2.Tenancy.Default.DocumentTables()).Any().ShouldBeTrue(); store1.Advanced.Clean.CompletelyRemoveAll(); - store1.Tenancy.Default.DbObjects.DocumentTables().Any().ShouldBeFalse(); - store2.Tenancy.Default.DbObjects.DocumentTables().Any().ShouldBeTrue(); + (await store1.Tenancy.Default.DocumentTables()).Any().ShouldBeFalse(); + (await store2.Tenancy.Default.DocumentTables()).Any().ShouldBeTrue(); } } } diff --git a/src/Marten.Testing/Bugs/Bug_431_not_patching_with_the_doc_type_column.cs b/src/Marten.Testing/Bugs/Bug_431_not_patching_with_the_doc_type_column.cs index a4f06cfd4d..deaca28c48 100644 --- a/src/Marten.Testing/Bugs/Bug_431_not_patching_with_the_doc_type_column.cs +++ b/src/Marten.Testing/Bugs/Bug_431_not_patching_with_the_doc_type_column.cs @@ -1,5 +1,7 @@ +using System.Threading.Tasks; using Marten.Testing.Documents; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs @@ -7,7 +9,7 @@ namespace Marten.Testing.Bugs public class Bug_431_not_patching_with_the_doc_type_column : BugIntegrationContext { [Fact] - public void should_add_a_missing_doc_type_column_in_patch() + public async Task should_add_a_missing_doc_type_column_in_patch() { StoreOptions(_ => { @@ -22,13 +24,15 @@ public void should_add_a_missing_doc_type_column_in_patch() var store2 = SeparateStore(_ => { - _.AutoCreateSchemaObjects = AutoCreate.All; + _.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate; _.Schema.For().AddSubClass(); }); - var patch = store2.Schema.ToPatch(); + await store2.Schema.ApplyAllConfiguredChangesToDatabase(); + await store2.Schema.AssertDatabaseMatchesConfiguration(); + + - patch.UpdateDDL.ShouldContain("alter table bugs.mt_doc_user add column mt_doc_type varchar DEFAULT \'BASE\'"); } } } diff --git a/src/Marten.Testing/Bugs/Bug_432_querying_with_UTC_times_with_offset.cs b/src/Marten.Testing/Bugs/Bug_432_querying_with_UTC_times_with_offset.cs index 3718be71c1..6e9e241a2e 100644 --- a/src/Marten.Testing/Bugs/Bug_432_querying_with_UTC_times_with_offset.cs +++ b/src/Marten.Testing/Bugs/Bug_432_querying_with_UTC_times_with_offset.cs @@ -2,6 +2,7 @@ using System.Linq; using Baseline; using Baseline.Dates; +using Weasel.Postgresql; using Marten.Testing.Harness; using Marten.Util; using Shouldly; diff --git a/src/Marten.Testing/Bugs/Bug_479_select_datetime_fields.cs b/src/Marten.Testing/Bugs/Bug_479_select_datetime_fields.cs index 33eefc0949..43e01d3600 100644 --- a/src/Marten.Testing/Bugs/Bug_479_select_datetime_fields.cs +++ b/src/Marten.Testing/Bugs/Bug_479_select_datetime_fields.cs @@ -3,6 +3,7 @@ using Baseline.Dates; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs diff --git a/src/Marten.Testing/Bugs/Bug_495_concurrent_check_by_not_first_loading_from_the_session.cs b/src/Marten.Testing/Bugs/Bug_495_concurrent_check_by_not_first_loading_from_the_session.cs index 46d373051a..54be68adb3 100644 --- a/src/Marten.Testing/Bugs/Bug_495_concurrent_check_by_not_first_loading_from_the_session.cs +++ b/src/Marten.Testing/Bugs/Bug_495_concurrent_check_by_not_first_loading_from_the_session.cs @@ -9,7 +9,7 @@ namespace Marten.Testing.Bugs { public class Bug_495_concurrent_check_by_not_first_loading_from_the_session: BugIntegrationContext { - [UseOptimisticConcurrency] + [UseOptimisticConcurrency][DocumentAlias("foo")] public class Foo { public string Id { get; set; } diff --git a/src/Marten.Testing/Bugs/Bug_550_schema_diff_with_precision.cs b/src/Marten.Testing/Bugs/Bug_550_schema_diff_with_precision.cs index f6b18f182d..152859ff0a 100644 --- a/src/Marten.Testing/Bugs/Bug_550_schema_diff_with_precision.cs +++ b/src/Marten.Testing/Bugs/Bug_550_schema_diff_with_precision.cs @@ -1,7 +1,8 @@ using System; -using Marten.Storage; +using System.Threading.Tasks; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs @@ -10,7 +11,7 @@ public class Bug_550_schema_diff_with_precision: BugIntegrationContext { [Fact] - public void can_handle_the_explicit_precision() + public async Task can_handle_the_explicit_precision() { // Configure a doc StoreOptions(_ => @@ -18,7 +19,7 @@ public void can_handle_the_explicit_precision() _.Schema.For().Duplicate(x => x.Name, "character varying (100)"); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); var store = SeparateStore(_ => { @@ -26,7 +27,7 @@ public void can_handle_the_explicit_precision() _.Schema.For().Duplicate(x => x.Name, "character varying (100)"); }); - var patch = store.Schema.ToPatch(typeof(DocWithPrecision)); + var patch = await store.Schema.CreateMigration(typeof(DocWithPrecision)); patch.Difference.ShouldBe(SchemaPatchDifference.None); } diff --git a/src/Marten.Testing/Bugs/Bug_553_ForeignKey_attribute_is_not_creating_an_index.cs b/src/Marten.Testing/Bugs/Bug_553_ForeignKey_attribute_is_not_creating_an_index.cs index 5afcd1cb25..3a86c70e4a 100644 --- a/src/Marten.Testing/Bugs/Bug_553_ForeignKey_attribute_is_not_creating_an_index.cs +++ b/src/Marten.Testing/Bugs/Bug_553_ForeignKey_attribute_is_not_creating_an_index.cs @@ -1,4 +1,6 @@ using System; +using System.Linq; +using System.Threading.Tasks; using Marten.Schema; using Marten.Testing.Documents; using Marten.Testing.Harness; @@ -10,12 +12,12 @@ namespace Marten.Testing.Bugs public class Bug_553_ForeignKey_attribute_is_not_creating_an_index: IntegrationContext { [Fact] - public void should_create_an_index_for_the_fk() + public async Task should_create_an_index_for_the_fk() { theStore.Tenancy.Default.EnsureStorageExists(typeof(DocWithFK)); - var table = theStore.Tenancy.Default.DbObjects.ExistingTableFor(typeof(DocWithFK)); - table.ActualIndices.ContainsKey("mt_doc_docwithfk_idx_user_id").ShouldBeTrue(); + var table = await theStore.Tenancy.Default.ExistingTableFor(typeof(DocWithFK)); + table.Indexes.Any(x => x.Name == "mt_doc_docwithfk_idx_user_id").ShouldBeTrue(); } public Bug_553_ForeignKey_attribute_is_not_creating_an_index(DefaultStoreFixture fixture) : base(fixture) diff --git a/src/Marten.Testing/Bugs/Bug_571_defensive_check_for_IEnumerable_of_T_in_Store.cs b/src/Marten.Testing/Bugs/Bug_571_defensive_check_for_IEnumerable_of_T_in_Store.cs index 54c8f96c88..f1229d42f1 100644 --- a/src/Marten.Testing/Bugs/Bug_571_defensive_check_for_IEnumerable_of_T_in_Store.cs +++ b/src/Marten.Testing/Bugs/Bug_571_defensive_check_for_IEnumerable_of_T_in_Store.cs @@ -19,25 +19,25 @@ public void not_too_tight_in_the_validation() } } - public class DocHolder: IEnumerable + public Bug_571_defensive_check_for_IEnumerable_of_T_in_Store(DefaultStoreFixture fixture) : base(fixture) { - public Guid Id; + } + } - private readonly IList _users = new List(); + public class DocHolder: IEnumerable + { + public Guid Id; - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + private readonly IList _users = new List(); - public IEnumerator GetEnumerator() - { - return _users.GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); } - public Bug_571_defensive_check_for_IEnumerable_of_T_in_Store(DefaultStoreFixture fixture) : base(fixture) + public IEnumerator GetEnumerator() { + return _users.GetEnumerator(); } } } diff --git a/src/Marten.Testing/Bugs/Bug_582_and_592_Skip_and_Take_in_compiled_queries.cs b/src/Marten.Testing/Bugs/Bug_582_and_592_Skip_and_Take_in_compiled_queries.cs index ee25a511dd..88303311c7 100644 --- a/src/Marten.Testing/Bugs/Bug_582_and_592_Skip_and_Take_in_compiled_queries.cs +++ b/src/Marten.Testing/Bugs/Bug_582_and_592_Skip_and_Take_in_compiled_queries.cs @@ -6,6 +6,7 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs diff --git a/src/Marten.Testing/Bugs/Bug_590_add_FK_later.cs b/src/Marten.Testing/Bugs/Bug_590_add_FK_later.cs deleted file mode 100644 index ae3ec47dc2..0000000000 --- a/src/Marten.Testing/Bugs/Bug_590_add_FK_later.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Linq; -using Marten.Testing.Documents; -using Marten.Testing.Harness; -using Shouldly; -using Xunit; - -namespace Marten.Testing.Bugs -{ - public class Bug_590_add_FK_later : BugIntegrationContext - { - [Fact] - public void should_add_a_new_FK_to_the_database() - { - theStore.Tenancy.Default.EnsureStorageExists(typeof(UserHolder)); - - var store = SeparateStore(_ => - { - _.Schema.For().ForeignKey(x => x.UserId); - }); - - store.Tenancy.Default.EnsureStorageExists(typeof(UserHolder)); - - store.Tenancy.Default.DbObjects - .AllForeignKeys() - .Any(x => x.Name == "mt_doc_userholder_user_id_fkey") - .ShouldBeTrue(); - } - } - - public class UserHolder - { - public Guid Id; - - public Guid UserId { get; set; } - } -} diff --git a/src/Marten.Testing/Bugs/Bug_593_patch_doc_function_should_be_built_in_designated_schema.cs b/src/Marten.Testing/Bugs/Bug_593_patch_doc_function_should_be_built_in_designated_schema.cs index 299cc23d45..f6fafc7855 100644 --- a/src/Marten.Testing/Bugs/Bug_593_patch_doc_function_should_be_built_in_designated_schema.cs +++ b/src/Marten.Testing/Bugs/Bug_593_patch_doc_function_should_be_built_in_designated_schema.cs @@ -1,4 +1,6 @@ using System.Linq; +using System.Threading.Tasks; +using Weasel.Postgresql; using Marten.Schema; using Marten.Testing.Harness; using Shouldly; @@ -9,14 +11,14 @@ namespace Marten.Testing.Bugs public class Bug_593_patch_doc_function_should_be_built_in_designated_schema: BugIntegrationContext { [Fact] - public void should_stick_the_patch_doc_function_in_the_right_schema() + public async Task should_stick_the_patch_doc_function_in_the_right_schema() { StoreOptions(_ => _.DatabaseSchemaName = "other"); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); var expected = new DbObjectName("other", "mt_transform_patch_doc"); - theStore.Tenancy.Default.DbObjects.Functions().Contains(expected).ShouldBeTrue(); + (await theStore.Tenancy.Default.Functions()).Contains(expected).ShouldBeTrue(); } } diff --git a/src/Marten.Testing/Bugs/Bug_605_unary_expressions_in_where_clause_of_compiled_query.cs b/src/Marten.Testing/Bugs/Bug_605_unary_expressions_in_where_clause_of_compiled_query.cs index 38d5f92c3b..d4e46db2f3 100644 --- a/src/Marten.Testing/Bugs/Bug_605_unary_expressions_in_where_clause_of_compiled_query.cs +++ b/src/Marten.Testing/Bugs/Bug_605_unary_expressions_in_where_clause_of_compiled_query.cs @@ -6,6 +6,7 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs diff --git a/src/Marten.Testing/Bugs/Bug_620_alias_bool.cs b/src/Marten.Testing/Bugs/Bug_620_alias_bool.cs index fe4cd8948d..580b20be10 100644 --- a/src/Marten.Testing/Bugs/Bug_620_alias_bool.cs +++ b/src/Marten.Testing/Bugs/Bug_620_alias_bool.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Marten.Schema; using Marten.Testing.Documents; using Marten.Testing.Harness; @@ -9,13 +10,13 @@ namespace Marten.Testing.Bugs public class Bug_620_alias_bool : BugIntegrationContext { [Fact] - public void can_canonicize_bool() + public async Task can_canonicize_bool() { using (var store1 = SeparateStore()) { store1.Tenancy.Default.EnsureStorageExists(typeof(DocWithBool)); - store1.Schema.ApplyAllConfiguredChangesToDatabase(); + await store1.Schema.ApplyAllConfiguredChangesToDatabase(); } using (var store2 = SeparateStore(_ => @@ -23,7 +24,7 @@ public void can_canonicize_bool() _.Schema.For(); })) { - store2.Schema.AssertDatabaseMatchesConfiguration(); + await store2.Schema.AssertDatabaseMatchesConfiguration(); } } } diff --git a/src/Marten.Testing/Bugs/Bug_628_fk_from_doc_to_itself.cs b/src/Marten.Testing/Bugs/Bug_628_fk_from_doc_to_itself.cs index 1044eb79fe..a66f02c38c 100644 --- a/src/Marten.Testing/Bugs/Bug_628_fk_from_doc_to_itself.cs +++ b/src/Marten.Testing/Bugs/Bug_628_fk_from_doc_to_itself.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Marten.Testing.Harness; using Xunit; @@ -14,14 +15,14 @@ public class Category } [Fact] - public void can_reference_itself_as_an_fk() + public async Task can_reference_itself_as_an_fk() { StoreOptions(_ => { _.Schema.For().ForeignKey(x => x.ParentId); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); } } diff --git a/src/Marten.Testing/Bugs/Bug_772_index_wrapping_column_does_not_match_DDL.cs b/src/Marten.Testing/Bugs/Bug_772_index_wrapping_column_does_not_match_DDL.cs index 008d9351c2..2c2da63ce1 100644 --- a/src/Marten.Testing/Bugs/Bug_772_index_wrapping_column_does_not_match_DDL.cs +++ b/src/Marten.Testing/Bugs/Bug_772_index_wrapping_column_does_not_match_DDL.cs @@ -1,6 +1,8 @@ +using System.Threading.Tasks; using Marten.Schema; using Marten.Testing.Documents; using Marten.Testing.Harness; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Testing.Bugs @@ -8,7 +10,7 @@ namespace Marten.Testing.Bugs public class Bug_772_index_wrapping_column_does_not_match_DDL: BugIntegrationContext { [Fact] // Control - public void index_with_no_expression_should_match_DDL() + public async Task index_with_no_expression_should_match_DDL() { StoreOptions(_ => { @@ -16,12 +18,12 @@ public void index_with_no_expression_should_match_DDL() .Duplicate(c => c.Name); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - theStore.Schema.AssertDatabaseMatchesConfiguration(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.AssertDatabaseMatchesConfiguration(); } [Fact] // Control - public void index_with_expression_not_wrapping_column_should_match_DDL() + public async Task index_with_expression_not_wrapping_column_should_match_DDL() { StoreOptions(_ => { @@ -33,12 +35,12 @@ public void index_with_expression_not_wrapping_column_should_match_DDL() }); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - theStore.Schema.AssertDatabaseMatchesConfiguration(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.AssertDatabaseMatchesConfiguration(); } [Fact] // Experiment, passed - public void index_with_expression_wrapping_column_should_match_DDL_if_DDL_not_reformatted() + public async Task index_with_expression_wrapping_column_should_match_DDL_if_DDL_not_reformatted() { StoreOptions(_ => { @@ -47,34 +49,15 @@ public void index_with_expression_wrapping_column_should_match_DDL_if_DDL_not_re { // The DDL for this expression is not reformatted, // and so the index definition matches the DDL. - id.Expression = "lower((?)::text)"; - id.IndexName = id.IndexName + "_lower"; - }); - }); - - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - theStore.Schema.AssertDatabaseMatchesConfiguration(); - } - - //[Fact] // Experiment, failed - public void index_with_expression_wrapping_column_should_match_DDL() - { - StoreOptions(_ => - { - _.Schema.For() - .Duplicate(c => c.Name, configure: id => - { - // The DDL for this expression is reformatted, - // and so I'm not certain there is a simple - // way to get the formats to match. id.Expression = "lower(?)"; - id.IndexName = id.IndexName + "_lower"; + id.Name = id.Name + "_lower"; }); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - theStore.Schema.AssertDatabaseMatchesConfiguration(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.AssertDatabaseMatchesConfiguration(); } + } } diff --git a/src/Marten.Testing/Bugs/Bug_837_missing_func_mt_immutable_timestamp_when_initializing_with_new_Schema.cs b/src/Marten.Testing/Bugs/Bug_837_missing_func_mt_immutable_timestamp_when_initializing_with_new_Schema.cs index 1446d9f405..a3bf8e5a73 100644 --- a/src/Marten.Testing/Bugs/Bug_837_missing_func_mt_immutable_timestamp_when_initializing_with_new_Schema.cs +++ b/src/Marten.Testing/Bugs/Bug_837_missing_func_mt_immutable_timestamp_when_initializing_with_new_Schema.cs @@ -2,6 +2,7 @@ using System.Linq; using Marten.Testing.Documents; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs diff --git a/src/Marten.Testing/Bugs/Bug_899_operations_out_of_order_when_types_use_inheritance.cs b/src/Marten.Testing/Bugs/Bug_899_operations_out_of_order_when_types_use_inheritance.cs index 8b92175831..8e267d1f35 100644 --- a/src/Marten.Testing/Bugs/Bug_899_operations_out_of_order_when_types_use_inheritance.cs +++ b/src/Marten.Testing/Bugs/Bug_899_operations_out_of_order_when_types_use_inheritance.cs @@ -18,7 +18,7 @@ public void performs_soft_delete_then_store_operations_in_order() .Index(x => x.DocumentId, x => { x.IsUnique = true; - x.Where = "mt_deleted = false"; + x.Predicate = "mt_deleted = false"; })); var docId = Guid.Parse("96d41d29-02a5-4c19-b019-034eb2cf964e"); diff --git a/src/Marten.Testing/Bugs/Bug_902_generic_type_documents.cs b/src/Marten.Testing/Bugs/Bug_902_generic_type_documents.cs index a3541254a9..d91a649c87 100644 --- a/src/Marten.Testing/Bugs/Bug_902_generic_type_documents.cs +++ b/src/Marten.Testing/Bugs/Bug_902_generic_type_documents.cs @@ -8,13 +8,6 @@ namespace Marten.Testing.Bugs { public class Bug_902_generic_type_documents: IntegrationContext { - public class MartenStoredState - { - public Guid Id = Guid.NewGuid(); - - public T Value { get; set; } - } - [Fact] public void can_create_object_name() { @@ -40,4 +33,11 @@ public Bug_902_generic_type_documents(DefaultStoreFixture fixture) : base(fixtur { } } + + public class MartenStoredState + { + public Guid Id = Guid.NewGuid(); + + public T Value { get; set; } + } } diff --git a/src/Marten.Testing/Bugs/Bug_957_duplicating_a_string_array.cs b/src/Marten.Testing/Bugs/Bug_957_duplicating_a_string_array.cs index 952dfdc334..02c5f4d70e 100644 --- a/src/Marten.Testing/Bugs/Bug_957_duplicating_a_string_array.cs +++ b/src/Marten.Testing/Bugs/Bug_957_duplicating_a_string_array.cs @@ -1,5 +1,6 @@ using System; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs diff --git a/src/Marten.Testing/Bugs/Bug_960_drop_index_concurrently_pg_error.cs b/src/Marten.Testing/Bugs/Bug_960_drop_index_concurrently_pg_error.cs index f4998ec8b2..52ce850412 100644 --- a/src/Marten.Testing/Bugs/Bug_960_drop_index_concurrently_pg_error.cs +++ b/src/Marten.Testing/Bugs/Bug_960_drop_index_concurrently_pg_error.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs diff --git a/src/Marten.Testing/Bugs/Bug_961_custom_identity_field_with_fk.cs b/src/Marten.Testing/Bugs/Bug_961_custom_identity_field_with_fk.cs index 951d909ea1..805270b820 100644 --- a/src/Marten.Testing/Bugs/Bug_961_custom_identity_field_with_fk.cs +++ b/src/Marten.Testing/Bugs/Bug_961_custom_identity_field_with_fk.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Marten.Testing.Harness; using Xunit; @@ -18,7 +19,7 @@ public class Document } [Fact] - public void can_build_the_fk_correctly() + public async Task can_build_the_fk_correctly() { StoreOptions(_ => { @@ -27,7 +28,7 @@ public void can_build_the_fk_correctly() _.Schema.For().ForeignKey(a => a.TargetId); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); } } diff --git a/src/Marten.Testing/Bugs/Bug_983_autocreate_none_is_disabling_schema_validation.cs b/src/Marten.Testing/Bugs/Bug_983_autocreate_none_is_disabling_schema_validation.cs index 8b2a757518..b05ade894f 100644 --- a/src/Marten.Testing/Bugs/Bug_983_autocreate_none_is_disabling_schema_validation.cs +++ b/src/Marten.Testing/Bugs/Bug_983_autocreate_none_is_disabling_schema_validation.cs @@ -1,6 +1,7 @@ +using System.Threading.Tasks; using Marten.Exceptions; -using Marten.Schema; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Bugs @@ -13,7 +14,7 @@ public class Document } [Fact] - public void should_be_validating_the_new_doc_does_not_exist() + public async Task should_be_validating_the_new_doc_does_not_exist() { StoreOptions(cfg => { @@ -22,9 +23,9 @@ public void should_be_validating_the_new_doc_does_not_exist() cfg.AutoCreateSchemaObjects = AutoCreate.None; }); - Exception.ShouldBeThrownBy(() => + await Exception.ShouldBeThrownByAsync(() => { - theStore.Schema.AssertDatabaseMatchesConfiguration(); + return theStore.Schema.AssertDatabaseMatchesConfiguration(); }); } diff --git a/src/Marten.Testing/Bugs/Bug_PR_1412_spaces_in_table_name_cause_schema_patch_to_fail.cs b/src/Marten.Testing/Bugs/Bug_PR_1412_spaces_in_table_name_cause_schema_patch_to_fail.cs index 6e0354933b..2280e5e323 100644 --- a/src/Marten.Testing/Bugs/Bug_PR_1412_spaces_in_table_name_cause_schema_patch_to_fail.cs +++ b/src/Marten.Testing/Bugs/Bug_PR_1412_spaces_in_table_name_cause_schema_patch_to_fail.cs @@ -1,20 +1,65 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; -using Marten.Schema; +using System.Threading.Tasks; using Marten.Storage; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Testing.Bugs { - public class Bug_PR_1412_spaces_in_table_name_cause_schema_patch_to_fail : BugIntegrationContext + public class Bug_PR_1412_spaces_in_table_name_cause_schema_patch_to_fail: BugIntegrationContext { + [Fact] + public async Task space_after_table_name_does_not_cause_exception_on_update() + { + StoreOptions(_ => + { + _.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate; + _.Storage.Add(new spaceAfterTableNameSchema()); + }); + await Should.NotThrowAsync(async () => + { + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.AssertDatabaseMatchesConfiguration(); + }); + } + + [Fact] + public async Task space_before_table_name_does_not_cause_exception_on_update() + { + StoreOptions(_ => + { + _.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate; + _.Storage.Add(new spaceBeforeTableNameSchema()); + }); + await Should.NotThrowAsync(async () => + { + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.AssertDatabaseMatchesConfiguration(); + }); + } + + [Fact] + public async Task space_in_table_name_does_not_cause_exception_on_update() + { + StoreOptions(_ => + { + _.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate; + _.Storage.Add(new spaceInNameSchema()); + }); + await Should.NotThrowAsync(async () => + { + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.AssertDatabaseMatchesConfiguration(); + }); + } - internal class testSchema : IFeatureSchema + internal class testSchema: IFeatureSchema { public ISchemaObject[] Objects => SchemaObjects().ToArray(); @@ -27,22 +72,21 @@ public IEnumerable DependentTypes() return new List(); } - public bool IsActive(StoreOptions options) + public void WritePermissions(DdlRules rules, TextWriter writer) { - return true; + // No permissions! } - public void WritePermissions(DdlRules rules, StringWriter writer) + public bool IsActive(StoreOptions options) { - // No permissions! + return true; } protected virtual IEnumerable SchemaObjects() { - List objects = new List(); + var objects = new List(); return objects; } - } internal class spaceAfterTableNameSchema: testSchema @@ -51,78 +95,28 @@ protected override IEnumerable SchemaObjects() { var table = new Table(new DbObjectName("test_space_after")); table.AddColumn("space_after ", "int"); - return new List - { - table - }; + return new List {table}; } } - [Fact] - public void space_after_table_name_does_not_cause_exception_on_update() - { - StoreOptions(_ => - { - _.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate; - _.Storage.Add(new spaceAfterTableNameSchema()); - }); - Should.NotThrow(() => - { - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - theStore.Schema.AssertDatabaseMatchesConfiguration(); - }); - } + internal class spaceBeforeTableNameSchema: testSchema { protected override IEnumerable SchemaObjects() { var table = new Table(new DbObjectName("test_space_before")); table.AddColumn(" space_before", "int"); - return new List - { - table - }; + return new List {table}; } } - [Fact] - public void space_before_table_name_does_not_cause_exception_on_update() - { - StoreOptions(_ => - { - _.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate; - _.Storage.Add(new spaceBeforeTableNameSchema()); - }); - Should.NotThrow(() => - { - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - theStore.Schema.AssertDatabaseMatchesConfiguration(); - }); - } + internal class spaceInNameSchema: testSchema { protected override IEnumerable SchemaObjects() { var table = new Table(new DbObjectName("test_space_in")); table.AddColumn("space inname", "int"); - return new List - { - table - }; + return new List {table}; } } - [Fact] - public void space_in_table_name_does_not_cause_exception_on_update() - { - StoreOptions(_ => - { - _.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate; - _.Storage.Add(new spaceInNameSchema()); - }); - Should.NotThrow(() => - { - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - theStore.Schema.AssertDatabaseMatchesConfiguration(); - }); - } - } } diff --git a/src/Marten.Testing/Bugs/ability_to_persist_generic_types.cs b/src/Marten.Testing/Bugs/ability_to_persist_generic_types.cs index 03ad8614f3..02a32a42f9 100644 --- a/src/Marten.Testing/Bugs/ability_to_persist_generic_types.cs +++ b/src/Marten.Testing/Bugs/ability_to_persist_generic_types.cs @@ -1,4 +1,5 @@ using System; +using Marten.Schema; using Marten.Testing.Harness; using Xunit; @@ -50,6 +51,7 @@ public void can_persist_and_load_generic_types() doc2.ShouldNotBeNull(); } + [DocumentAlias("nested_generic")] public class NestedGenericTypeToPersist { public Guid Id = Guid.NewGuid(); diff --git a/src/Marten.Testing/Bugs/bug_1338_Validate_Null_ForeignKeyDefinition_ReferenceDocumenType.cs b/src/Marten.Testing/Bugs/bug_1338_Validate_Null_ForeignKeyDefinition_ReferenceDocumenType.cs index a0c3f1c255..9f6ea7c0cf 100644 --- a/src/Marten.Testing/Bugs/bug_1338_Validate_Null_ForeignKeyDefinition_ReferenceDocumenType.cs +++ b/src/Marten.Testing/Bugs/bug_1338_Validate_Null_ForeignKeyDefinition_ReferenceDocumenType.cs @@ -1,18 +1,16 @@ -using System; using System.Collections.Generic; using System.Linq; -using Marten.Schema; using Marten.Storage; -using Marten.Testing.Documents; using Marten.Testing.Harness; -using Marten.Util; using Npgsql; using Shouldly; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Testing.Bugs { - public class Bug_1338_Validate_Null_ForeignKeyDefinition_ReferenceDocumenType : BugIntegrationContext + public class Bug_1338_Validate_Null_ForeignKeyDefinition_ReferenceDocumenType: BugIntegrationContext { [Fact] public void StorageFeatures_AllActiveFeatures_Should_Not_Throw_With_ExternalForeignKeyDefinitions() @@ -21,8 +19,9 @@ public void StorageFeatures_AllActiveFeatures_Should_Not_Throw_With_ExternalFore StoreOptions(_ => { - _.Schema.For().ForeignKey(x => x.ForeignId, _.DatabaseSchemaName, "external_table", "id"); - }); + _.Schema.For() + .ForeignKey(x => x.ForeignId, _.DatabaseSchemaName, "external_table", "id"); + }); theStore.Storage.AllActiveFeatures(theStore.Tenancy.Default).All(x => x != null).ShouldBeTrue(); } @@ -33,9 +32,10 @@ public void UnitOfWork_GetTypeDependencies_Should_Not_Throw_With_ExternalForeign CreateExternalTableForTesting(); StoreOptions(_ => - { - _.Schema.For().ForeignKey(x => x.ForeignId, _.DatabaseSchemaName, "external_table", "id"); - }); + { + _.Schema.For() + .ForeignKey(x => x.ForeignId, _.DatabaseSchemaName, "external_table", "id"); + }); // Inserting a new document will force a call to: // UnitOfWork.ApplyChanges() @@ -46,21 +46,21 @@ public void UnitOfWork_GetTypeDependencies_Should_Not_Throw_With_ExternalForeign // UnitOfWork.GetTypeDependencies(ClassWithExternalForeignKey) using (var session = theStore.LightweightSession()) { - session.Insert(new ClassWithExternalForeignKey{Id = 1, ForeignId = 1}); + session.Insert(new ClassWithExternalForeignKey {Id = 1, ForeignId = 1}); session.SaveChanges(); } } private void CreateExternalTableForTesting() { - string createSchema = $"create schema if not exists {SchemaName}"; - string dropSql = $"DROP TABLE IF EXISTS {SchemaName}.external_table CASCADE;"; - string createSql = -$@"CREATE TABLE {SchemaName}.external_table ( + var createSchema = $"create schema if not exists {SchemaName}"; + var dropSql = $"DROP TABLE IF EXISTS {SchemaName}.external_table CASCADE;"; + var createSql = + $@"CREATE TABLE {SchemaName}.external_table ( id integer, CONSTRAINT ""external_table_pkey"" PRIMARY KEY (id) );"; - string insertSql = $"INSERT INTO {SchemaName}.external_table VALUES (1);"; + var insertSql = $"INSERT INTO {SchemaName}.external_table VALUES (1);"; using (var dbConn = new NpgsqlConnection(ConnectionSource.ConnectionString)) { @@ -85,15 +85,17 @@ private void CreateExternalTableForTesting() } } } - } public class FakeExternalTable: FeatureSchemaBase { - public FakeExternalTable(StoreOptions options) : base("fake_external_table", options) + public FakeExternalTable(StoreOptions options): base("fake_external_table") { + Options = options; } + public StoreOptions Options { get; } + protected override IEnumerable schemaObjects() { var table = new Table(new DbObjectName(Options.DatabaseSchemaName, "external_table")); diff --git a/src/Marten.Testing/CoreFunctionality/DdlRulesTester.cs b/src/Marten.Testing/CoreFunctionality/DdlRulesTester.cs deleted file mode 100644 index 2a0c466ee0..0000000000 --- a/src/Marten.Testing/CoreFunctionality/DdlRulesTester.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Marten.Testing.Harness; -using Shouldly; -using Xunit; - -namespace Marten.Testing.CoreFunctionality -{ - public class DdlRulesTester - { - - - [Fact] - public void role_is_null_by_default() - { - SpecificationExtensions.ShouldBeNull(new DdlRules().Role); - } - - [Fact] - public void table_creation_is_drop_then_create_by_default() - { - new DdlRules().TableCreation.ShouldBe(CreationStyle.DropThenCreate); - } - - [Fact] - public void upsert_rights_are_by_invoker_by_default() - { - new DdlRules().UpsertRights.ShouldBe(SecurityRights.Invoker); - } - } -} diff --git a/src/Marten.Testing/CoreFunctionality/MartenRegistryTests.cs b/src/Marten.Testing/CoreFunctionality/MartenRegistryTests.cs index 83061a07f6..e099abb31e 100644 --- a/src/Marten.Testing/CoreFunctionality/MartenRegistryTests.cs +++ b/src/Marten.Testing/CoreFunctionality/MartenRegistryTests.cs @@ -7,6 +7,7 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Testing.CoreFunctionality @@ -23,9 +24,9 @@ public MartenRegistryTests() : base("registry") _.Schema.For() .Duplicate(x => x.Name).Duplicate(x => x.OtherName, configure: x => { - x.IndexName = "mt_special"; + x.Name = "mt_special"; }) - .GinIndexJsonData(x => x.IndexName = "my_gin_index") + .GinIndexJsonData(x => x.Name = "my_gin_index") .IndexLastModified(x => x.IsConcurrent = true) .SoftDeletedWithIndex(x => x.Method = IndexMethod.brin); @@ -62,7 +63,7 @@ public void searchable_field_is_also_indexed() var mapping = theStorage.MappingFor(typeof (Organization)).As(); var index = mapping.IndexesFor("name").Single(); - index.IndexName.ShouldBe("mt_doc_martenregistrytests_organization_idx_name"); + index.Name.ShouldBe("mt_doc_martenregistrytests_organization_idx_name"); index.Columns.ShouldHaveTheSameElementsAs("name"); } @@ -73,7 +74,7 @@ public void can_customize_the_index_on_a_searchable_field() var mapping = theStorage.MappingFor(typeof(Organization)).As(); var index = mapping.IndexesFor("other_name").Single(); - index.IndexName.ShouldBe("mt_special"); + index.Name.ShouldBe("mt_special"); index.Columns.ShouldHaveTheSameElementsAs("other_name"); } @@ -84,9 +85,9 @@ public void can_set_up_gin_index_on_json_data() var index = mapping.IndexesFor("data").Single(); - index.IndexName.ShouldBe("mt_my_gin_index"); + index.Name.ShouldBe("my_gin_index"); index.Method.ShouldBe(IndexMethod.gin); - index.Expression.ShouldBe("? jsonb_path_ops"); + index.Expression.ShouldBe("(? jsonb_path_ops)"); } [Fact] @@ -113,7 +114,10 @@ public void mt_deleted_at_index_is_added() var index = mapping.IndexesFor(SchemaConstants.DeletedAtColumn).Single(); - index.Modifier.ShouldBe("WHERE mt_deleted"); + var ddl = index.ToDDL(new DocumentTable(mapping)); + ddl + .ShouldContain("WHERE (mt_deleted)", Case.Insensitive); + index.Method.ShouldBe(IndexMethod.brin); } diff --git a/src/Marten.Testing/CoreFunctionality/StoreOptionsTests.cs b/src/Marten.Testing/CoreFunctionality/StoreOptionsTests.cs index bb28e8a045..dec8a92892 100644 --- a/src/Marten.Testing/CoreFunctionality/StoreOptionsTests.cs +++ b/src/Marten.Testing/CoreFunctionality/StoreOptionsTests.cs @@ -1,16 +1,11 @@ using System; using System.Linq; using Marten.Exceptions; -using Marten.Linq; -using Marten.Schema; -using Marten.Schema.Identity; -using Marten.Services; using Marten.Storage; using Marten.Testing.Documents; using Marten.Testing.Harness; -using Npgsql; -using NpgsqlTypes; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.CoreFunctionality @@ -39,8 +34,7 @@ public void add_document_types() options.Connection(ConnectionSource.ConnectionString); options.RegisterDocumentType(); options.RegisterDocumentType(typeof(Company)); - options.RegisterDocumentTypes(new Type[] {typeof(Target), typeof(Issue)}); - + options.RegisterDocumentTypes(new[] {typeof(Target), typeof(Issue)}); }); store.Options.Storage.AllDocumentMappings.OrderBy(x => x.DocumentType.Name) @@ -74,18 +68,22 @@ public void can_overwrite_the_logger() public void using_console_logger() { #region sample_plugging-in-marten-logger + var store = DocumentStore.For(_ => { _.Logger(new ConsoleMartenLogger()); }); + #endregion sample_plugging-in-marten-logger #region sample_plugging-in-session-logger + using (var session = store.OpenSession()) { // Replace the logger for only this one session session.Logger = new RecordingLogger(); } + #endregion sample_plugging-in-session-logger } @@ -254,7 +252,8 @@ public void enum_storage_should_not_change_when_duplicated_field_enum_storage_wa } [Fact] - public void duplicated_field_enum_storage_after_it_had_value_assigned_should_not_change_when_enum_storage_was_updated() + public void + duplicated_field_enum_storage_after_it_had_value_assigned_should_not_change_when_enum_storage_was_updated() { var storeOptions = new StoreOptions(); storeOptions.UseDefaultSerialization(EnumStorage.AsInteger); @@ -275,12 +274,14 @@ public void duplicated_field_enum_storage_after_it_had_value_assigned_should_not public void set_the_maximum_name_length() { #region sample_setting-name-data-length + var store = DocumentStore.For(_ => { // If you have overridden NAMEDATALEN in your // Postgresql database to 100 _.NameDataLength = 100; }); + #endregion sample_setting-name-data-length } } diff --git a/src/Marten.Testing/CoreFunctionality/TypeMappingsTests.cs b/src/Marten.Testing/CoreFunctionality/TypeMappingsTests.cs deleted file mode 100644 index 0f842725cb..0000000000 --- a/src/Marten.Testing/CoreFunctionality/TypeMappingsTests.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using Marten.Util; -using Npgsql; -using Npgsql.TypeHandlers; -using Npgsql.TypeMapping; -using NpgsqlTypes; -using Shouldly; -using Xunit; - -namespace Marten.Testing.CoreFunctionality -{ - public class TypeMappingsTests - { - [Fact] - public void execute_to_db_type_as_int() - { - TypeMappings.ToDbType(typeof(int)).ShouldBe(NpgsqlDbType.Integer); - TypeMappings.ToDbType(typeof(int?)).ShouldBe(NpgsqlDbType.Integer); - } - - [Fact] - public void execute_to_db_custom_mappings_resolve() - { - NpgsqlConnection.GlobalTypeMapper.AddMapping(new NpgsqlTypeMappingBuilder - { - PgTypeName = "varchar", - NpgsqlDbType = NpgsqlDbType.Varchar, - ClrTypes = new[] { typeof(MappedTarget) }, - TypeHandlerFactory = new TextHandlerFactory() - }.Build()); - - TypeMappings.ToDbType(typeof(MappedTarget)).ShouldBe(NpgsqlDbType.Varchar); - ShouldThrowExtensions.ShouldThrow(() => TypeMappings.ToDbType(typeof(UnmappedTarget))); - } - - - [Fact] - public void execute_get_pg_type_default_mappings_resolve() - { - TypeMappings.GetPgType(typeof(long), EnumStorage.AsString).ShouldBe("bigint"); - TypeMappings.GetPgType(typeof(DateTime), EnumStorage.AsString).ShouldBe("timestamp without time zone"); - } - - [Fact] - public void execute_get_pg_type_custom_mappings_resolve_or_default_to_jsonb() - { - NpgsqlConnection.GlobalTypeMapper.MapComposite("varchar"); - - TypeMappings.GetPgType(typeof(MappedTarget), EnumStorage.AsString).ShouldBe("varchar"); - TypeMappings.GetPgType(typeof(UnmappedTarget), EnumStorage.AsString).ShouldBe("jsonb"); - } - - [Fact] - public void execute_has_type_mapping_resolves_custom_types() - { - NpgsqlConnection.GlobalTypeMapper.MapComposite("varchar"); - - TypeMappings.HasTypeMapping(typeof(MappedTarget)).ShouldBeTrue(); - TypeMappings.HasTypeMapping(typeof(UnmappedTarget)).ShouldBeFalse(); - } - - public class MappedTarget { } - public class UnmappedTarget { } - - [Fact] - public void canonicizesql_supports_tabs_as_whitespace() - { - var noTabsCanonized = - "\r\nDECLARE\r\n final_version uuid;\r\nBEGIN\r\nINSERT INTO table(\"data\", \"mt_dotnet_type\", \"id\", \"mt_version\", mt_last_modified) VALUES (doc, docDotNetType, docId, docVersion, transaction_timestamp())\r\n ON CONFLICT ON CONSTRAINT pk_table\r\n DO UPDATE SET \"data\" = doc, \"mt_dotnet_type\" = docDotNetType, \"mt_version\" = docVersion, mt_last_modified = transaction_timestamp();\r\n\r\n SELECT mt_version FROM table into final_version WHERE id = docId;\r\n RETURN final_version;\r\nEND;\r\n" - .CanonicizeSql(); - var tabsCanonized = - "\r\nDECLARE\r\n\tfinal_version uuid;\r\nBEGIN\r\n\tINSERT INTO table(\"data\", \"mt_dotnet_type\", \"id\", \"mt_version\", mt_last_modified)\r\n\tVALUES (doc, docDotNetType, docId, docVersion, transaction_timestamp())\r\n\t\tON CONFLICT ON CONSTRAINT pk_table\r\n\t\t\tDO UPDATE SET \"data\" = doc, \"mt_dotnet_type\" = docDotNetType, \"mt_version\" = docVersion, mt_last_modified = transaction_timestamp();\r\n\r\n\tSELECT mt_version FROM table into final_version WHERE id = docId;\r\n\r\n\tRETURN final_version;\r\nEND;\r\n" - .CanonicizeSql(); - noTabsCanonized.ShouldBe(tabsCanonized); - } - - [Fact] - public void replaces_multiple_spaces_with_new_string() - { - var inputString = "Darth Maroon the First"; - var expectedString = "Darth Maroon the First"; - inputString.ReplaceMultiSpace(" ").ShouldBe(expectedString); - } - - [Fact] - public void table_columns_should_match_raw_types() - { - var serialAsInt = new Marten.Storage.TableColumn("id", "serial"); - serialAsInt.Equals(new Marten.Storage.TableColumn("id", "int")); - - var varchararrAsArray = new Marten.Storage.TableColumn("comments", "varchar[]"); - varchararrAsArray.Equals(new Marten.Storage.TableColumn("comments", "array")); - - var charactervaryingAsArray = new Marten.Storage.TableColumn("comments", "character varying[]"); - charactervaryingAsArray.Equals(new Marten.Storage.TableColumn("comments", "array")); - - var textarrayAsArray = new Marten.Storage.TableColumn("comments", "text[]"); - charactervaryingAsArray.Equals(new Marten.Storage.TableColumn("comments", "array")); - } - } -} diff --git a/src/Marten.Testing/CoreFunctionality/Using_Global_DocumentSessionListener_Tests.cs b/src/Marten.Testing/CoreFunctionality/Using_Global_DocumentSessionListener_Tests.cs index 270ea629c3..cf53e760a0 100644 --- a/src/Marten.Testing/CoreFunctionality/Using_Global_DocumentSessionListener_Tests.cs +++ b/src/Marten.Testing/CoreFunctionality/Using_Global_DocumentSessionListener_Tests.cs @@ -7,6 +7,7 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.CoreFunctionality diff --git a/src/Marten.Testing/CoreFunctionality/Using_Local_DocumentSessionListener_Tests.cs b/src/Marten.Testing/CoreFunctionality/Using_Local_DocumentSessionListener_Tests.cs index 0b7de84a48..3052e271a5 100644 --- a/src/Marten.Testing/CoreFunctionality/Using_Local_DocumentSessionListener_Tests.cs +++ b/src/Marten.Testing/CoreFunctionality/Using_Local_DocumentSessionListener_Tests.cs @@ -5,6 +5,7 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.CoreFunctionality diff --git a/src/Marten.Testing/CoreFunctionality/ability_to_add_custom_storage_features.cs b/src/Marten.Testing/CoreFunctionality/ability_to_add_custom_storage_features.cs index fa0deffe48..8ea4bb4833 100644 --- a/src/Marten.Testing/CoreFunctionality/ability_to_add_custom_storage_features.cs +++ b/src/Marten.Testing/CoreFunctionality/ability_to_add_custom_storage_features.cs @@ -1,9 +1,11 @@ using System.Collections.Generic; using System.Linq; -using Marten.Schema; +using System.Threading.Tasks; using Marten.Storage; +using Weasel.Postgresql; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql.Tables; using Xunit; namespace Marten.Testing.CoreFunctionality @@ -11,15 +13,15 @@ namespace Marten.Testing.CoreFunctionality public class ability_to_add_custom_storage_features : IntegrationContext { [Fact] - public void can_register_a_custom_feature() + public async Task can_register_a_custom_feature() { StoreOptions(_ => { _.Storage.Add(); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - theStore.Tenancy.Default.DbObjects.SchemaTables().Any(x => x.Name == "mt_fake_table") + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + (await theStore.Tenancy.Default.SchemaTables()).Any(x => x.Name == "mt_fake_table") .ShouldBeTrue(); } @@ -47,13 +49,16 @@ public ability_to_add_custom_storage_features(DefaultStoreFixture fixture) : bas #region sample_creating-a-fake-schema-feature public class FakeStorage : FeatureSchemaBase { - public FakeStorage(StoreOptions options) : base("fake", options) + private readonly StoreOptions _options; + + public FakeStorage(StoreOptions options) : base("fake") { + _options = options; } protected override IEnumerable schemaObjects() { - var table = new Table(new DbObjectName(Options.DatabaseSchemaName, "mt_fake_table")); + var table = new Table(new DbObjectName(_options.DatabaseSchemaName, "mt_fake_table")); table.AddColumn("name", "varchar"); yield return table; diff --git a/src/Marten.Testing/CoreFunctionality/ability_to_use_an_existing_connection_and_transaction.cs b/src/Marten.Testing/CoreFunctionality/ability_to_use_an_existing_connection_and_transaction.cs index 2581fb9940..e5ec802949 100644 --- a/src/Marten.Testing/CoreFunctionality/ability_to_use_an_existing_connection_and_transaction.cs +++ b/src/Marten.Testing/CoreFunctionality/ability_to_use_an_existing_connection_and_transaction.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Threading.Tasks; using System.Transactions; +using Weasel.Postgresql; using Marten.Services; using Marten.Testing.Documents; using Marten.Testing.Harness; diff --git a/src/Marten.Testing/CoreFunctionality/bulk_loading_Tests.cs b/src/Marten.Testing/CoreFunctionality/bulk_loading_Tests.cs index 0c484ed165..972083f766 100644 --- a/src/Marten.Testing/CoreFunctionality/bulk_loading_Tests.cs +++ b/src/Marten.Testing/CoreFunctionality/bulk_loading_Tests.cs @@ -1,4 +1,5 @@ using System.Linq; +using Weasel.Postgresql; using Marten.Services; using Marten.Testing.Documents; using Marten.Testing.Harness; diff --git a/src/Marten.Testing/CoreFunctionality/bulk_loading_async_Tests.cs b/src/Marten.Testing/CoreFunctionality/bulk_loading_async_Tests.cs index 6917acd2b8..f3376eeb01 100644 --- a/src/Marten.Testing/CoreFunctionality/bulk_loading_async_Tests.cs +++ b/src/Marten.Testing/CoreFunctionality/bulk_loading_async_Tests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using Weasel.Postgresql; using Marten.Services; using Marten.Testing.Documents; using Marten.Testing.Harness; diff --git a/src/Marten.Testing/CoreFunctionality/document_session_persist_and_load_single_documents_Tests.cs b/src/Marten.Testing/CoreFunctionality/document_session_persist_and_load_single_documents_Tests.cs index 2a8447219e..917f588180 100644 --- a/src/Marten.Testing/CoreFunctionality/document_session_persist_and_load_single_documents_Tests.cs +++ b/src/Marten.Testing/CoreFunctionality/document_session_persist_and_load_single_documents_Tests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Baseline; +using Weasel.Postgresql; using Marten.Services; using Marten.Testing.Documents; using Marten.Testing.Harness; diff --git a/src/Marten.Testing/CoreFunctionality/document_session_sort_large_operation_bundle_Tests.cs b/src/Marten.Testing/CoreFunctionality/document_session_sort_large_operation_bundle_Tests.cs index bc28d022e2..07851b9f6f 100644 --- a/src/Marten.Testing/CoreFunctionality/document_session_sort_large_operation_bundle_Tests.cs +++ b/src/Marten.Testing/CoreFunctionality/document_session_sort_large_operation_bundle_Tests.cs @@ -1,4 +1,5 @@ using System; +using Marten.Schema; using Marten.Testing.Harness; using Xunit; @@ -75,6 +76,7 @@ public void save_large_bundle_of_operations() } } + [DocumentAlias("testmodel1")] public class TestModel1 { public Guid Id { get; set; } @@ -84,12 +86,14 @@ public class TestModel1 public int Mode { get; set; } } + [DocumentAlias("testmodel2")] public class TestModel2 { public Guid Id { get; set; } public string Content { get; set; } } + [DocumentAlias("testmodel3")] public class TestModel3 { public Guid Id { get; set; } @@ -100,7 +104,7 @@ public class TestModel3 public int Cond2 { get; set; } } - + [DocumentAlias("testmodel4")] public class TestModel4 { public Guid Id { get; set; } @@ -119,6 +123,7 @@ public class TestModel4 public string Mode { get; set; } } + [DocumentAlias("testmodel5")] public class TestModel5 { public Guid Id { get; set; } @@ -128,6 +133,7 @@ public class TestModel5 public int Stage { get; set; } } + [DocumentAlias("testmodel6")] public class TestModel6 { public Guid Id { get; set; } diff --git a/src/Marten.Testing/CoreFunctionality/query_session_Tests.cs b/src/Marten.Testing/CoreFunctionality/query_session_Tests.cs index 5d36c1ebf8..245f75ff3b 100644 --- a/src/Marten.Testing/CoreFunctionality/query_session_Tests.cs +++ b/src/Marten.Testing/CoreFunctionality/query_session_Tests.cs @@ -1,5 +1,6 @@ using System; using System.Data; +using Weasel.Postgresql; using Marten.Services; using Marten.Testing.Documents; using Marten.Testing.Harness; diff --git a/src/Marten.Testing/CoreFunctionality/streaming_json_results.cs b/src/Marten.Testing/CoreFunctionality/streaming_json_results.cs index cfeb11add3..8204c78e0d 100644 --- a/src/Marten.Testing/CoreFunctionality/streaming_json_results.cs +++ b/src/Marten.Testing/CoreFunctionality/streaming_json_results.cs @@ -27,7 +27,7 @@ private T deserialize(Stream stream) [Fact] public async Task stream_by_id_miss() { - theStore.Advanced.Clean.DeleteDocumentsFor(typeof(IntDoc)); + theStore.Advanced.Clean.DeleteDocumentsByType(typeof(IntDoc)); var stream = new MemoryStream(); var found = await theSession.Json.StreamById(1, stream); diff --git a/src/Marten.Testing/DevelopmentModeRegistry.cs b/src/Marten.Testing/DevelopmentModeRegistry.cs index 5d93bb0ffd..083126fab9 100644 --- a/src/Marten.Testing/DevelopmentModeRegistry.cs +++ b/src/Marten.Testing/DevelopmentModeRegistry.cs @@ -1,5 +1,5 @@ - using Lamar; +using Weasel.Postgresql; namespace Marten.Testing { diff --git a/src/Marten.Testing/Events/Aggregation/AggregationContext.cs b/src/Marten.Testing/Events/Aggregation/AggregationContext.cs index 34eafbb5f4..3e17d5966e 100644 --- a/src/Marten.Testing/Events/Aggregation/AggregationContext.cs +++ b/src/Marten.Testing/Events/Aggregation/AggregationContext.cs @@ -15,7 +15,7 @@ public class AggregationContext : IntegrationContext public AggregationContext(DefaultStoreFixture fixture) : base(fixture) { - theStore.Advanced.Clean.DeleteDocumentsFor(typeof(MyAggregate)); + theStore.Advanced.Clean.DeleteDocumentsByType(typeof(MyAggregate)); } public void UsingDefinition() where T : AggregateProjection, new() diff --git a/src/Marten.Testing/Events/Aggregation/when_using_inline_lambdas_to_define_the_projection.cs b/src/Marten.Testing/Events/Aggregation/when_using_inline_lambdas_to_define_the_projection.cs index 6599d10c69..b5a1301d5e 100644 --- a/src/Marten.Testing/Events/Aggregation/when_using_inline_lambdas_to_define_the_projection.cs +++ b/src/Marten.Testing/Events/Aggregation/when_using_inline_lambdas_to_define_the_projection.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Marten.Schema; using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; @@ -206,6 +207,7 @@ await InlineProject(x => } + [DocumentAlias("system_state")] public class SystemState { public Guid Id { get; set; } diff --git a/src/Marten.Testing/Events/Bugs/Bug_1019_event_type_not_found_bad_exception_message.cs b/src/Marten.Testing/Events/Bugs/Bug_1019_event_type_not_found_bad_exception_message.cs index db887f09af..6c159bddc0 100644 --- a/src/Marten.Testing/Events/Bugs/Bug_1019_event_type_not_found_bad_exception_message.cs +++ b/src/Marten.Testing/Events/Bugs/Bug_1019_event_type_not_found_bad_exception_message.cs @@ -1,5 +1,6 @@ using System; using Marten.Exceptions; +using Weasel.Postgresql; using Marten.Testing.Harness; using Marten.Util; using Xunit; diff --git a/src/Marten.Testing/Events/Bugs/Bug_1069_using_generic_event_types_because_why_not.cs b/src/Marten.Testing/Events/Bugs/Bug_1069_using_generic_event_types_because_why_not.cs index e0467d6505..245dbec613 100644 --- a/src/Marten.Testing/Events/Bugs/Bug_1069_using_generic_event_types_because_why_not.cs +++ b/src/Marten.Testing/Events/Bugs/Bug_1069_using_generic_event_types_because_why_not.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events.Bugs diff --git a/src/Marten.Testing/Events/Bugs/Bug_1679_use_inner_type_for_self_aggregate.cs b/src/Marten.Testing/Events/Bugs/Bug_1679_use_inner_type_for_self_aggregate.cs index 2eac443525..4c5e5617c6 100644 --- a/src/Marten.Testing/Events/Bugs/Bug_1679_use_inner_type_for_self_aggregate.cs +++ b/src/Marten.Testing/Events/Bugs/Bug_1679_use_inner_type_for_self_aggregate.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Marten.Events; +using Marten.Schema; using Marten.Testing.Events.Aggregation; using Marten.Testing.Harness; using Xunit; @@ -25,6 +26,7 @@ public async Task try_self_aggregate_with_inner_class() aggregate.ShouldNotBeNull(); } + [DocumentAlias("inner_aggregate")] public class InnerAggregate { public Guid Id { get; set; } diff --git a/src/Marten.Testing/Events/Bugs/Bug_443_erroneously_creating_the_event_tables_when_unnecessary.cs b/src/Marten.Testing/Events/Bugs/Bug_443_erroneously_creating_the_event_tables_when_unnecessary.cs index b5e3ebb1e7..8ac0999d3e 100644 --- a/src/Marten.Testing/Events/Bugs/Bug_443_erroneously_creating_the_event_tables_when_unnecessary.cs +++ b/src/Marten.Testing/Events/Bugs/Bug_443_erroneously_creating_the_event_tables_when_unnecessary.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using Baseline; using Marten.Testing.Documents; using Marten.Testing.Harness; @@ -11,13 +12,13 @@ namespace Marten.Testing.Events.Bugs public class Bug_443_erroneously_creating_the_event_tables_when_unnecessary: BugIntegrationContext { [Fact] - public void event_table_should_not_be_there_if_unused() + public async Task event_table_should_not_be_there_if_unused() { theStore.Tenancy.Default.EnsureStorageExists(typeof(User)); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - var tables = theStore.Tenancy.Default.DbObjects.SchemaTables(); + var tables = await theStore.Tenancy.Default.SchemaTables(); tables.Any(x => x.Name == "mt_events").ShouldBeFalse(); tables.Any(x => x.Name == "mt_streams").ShouldBeFalse(); @@ -26,19 +27,19 @@ public void event_table_should_not_be_there_if_unused() [Fact] public void event_tables_are_not_part_of_the_ddl() { - var ddl = theStore.Schema.ToDDL(); + var ddl = theStore.Schema.ToDatabaseScript(); SpecificationExtensions.ShouldNotContain(ddl, "mt_events"); SpecificationExtensions.ShouldNotContain(ddl, "mt_streams"); } [Fact] - public void not_part_of_the_patch() + public async Task not_part_of_the_patch() { - var patch = theStore.Schema.ToPatch(); + var patch = await theStore.Schema.CreateMigration(); - SpecificationExtensions.ShouldNotContain(patch.UpdateDDL, "mt_events"); - SpecificationExtensions.ShouldNotContain(patch.UpdateDDL, "mt_streams"); + SpecificationExtensions.ShouldNotContain(patch.UpdateSql, "mt_events"); + SpecificationExtensions.ShouldNotContain(patch.UpdateSql, "mt_streams"); } [Fact] @@ -48,7 +49,7 @@ public void not_part_of_the_by_type_dump() var fileSystem = new FileSystem(); fileSystem.CleanDirectory(directory); - theStore.Schema.WriteDDLByType(directory); + theStore.Schema.WriteDatabaseCreationScriptByType(directory); fileSystem.FindFiles(directory, FileSet.Shallow("*.sql")) .Any(x => x.EndsWith("mt_streams.sql")) diff --git a/src/Marten.Testing/Events/Bugs/Bug_499_event_store_objects_should_not_be_erroneously_in_the_patch.cs b/src/Marten.Testing/Events/Bugs/Bug_499_event_store_objects_should_not_be_erroneously_in_the_patch.cs index 059d7c4fbf..ff1090eb17 100644 --- a/src/Marten.Testing/Events/Bugs/Bug_499_event_store_objects_should_not_be_erroneously_in_the_patch.cs +++ b/src/Marten.Testing/Events/Bugs/Bug_499_event_store_objects_should_not_be_erroneously_in_the_patch.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using Marten.Testing.Documents; using Marten.Testing.Harness; using Xunit; @@ -7,14 +8,14 @@ namespace Marten.Testing.Events.Bugs public class Bug_499_event_store_objects_should_not_be_erroneously_in_the_patch: BugIntegrationContext { [Fact] - public void not_using_the_event_store_should_not_be_in_patch() + public async Task not_using_the_event_store_should_not_be_in_patch() { StoreOptions(_ => _.Schema.For()); - var patch = theStore.Schema.ToPatch(false); + var patch = await theStore.Schema.CreateMigration(); - patch.UpdateDDL.ShouldNotContain("mt_events"); - patch.UpdateDDL.ShouldNotContain("mt_streams"); + patch.UpdateSql.ShouldNotContain("mt_events"); + patch.UpdateSql.ShouldNotContain("mt_streams"); } } diff --git a/src/Marten.Testing/Events/EventProgressWriteTests.cs b/src/Marten.Testing/Events/EventProgressWriteTests.cs index 1793cb0465..6df30b6b6a 100644 --- a/src/Marten.Testing/Events/EventProgressWriteTests.cs +++ b/src/Marten.Testing/Events/EventProgressWriteTests.cs @@ -1,6 +1,7 @@ using Baseline; using Marten.Events; using Marten.Events.Operations; +using Weasel.Postgresql; using Marten.Testing.Harness; using Marten.Util; using Shouldly; diff --git a/src/Marten.Testing/Events/Projections/EventProjectionTests.cs b/src/Marten.Testing/Events/Projections/EventProjectionTests.cs index 33df7cc686..1103209f7d 100644 --- a/src/Marten.Testing/Events/Projections/EventProjectionTests.cs +++ b/src/Marten.Testing/Events/Projections/EventProjectionTests.cs @@ -16,7 +16,7 @@ public class EventProjectionTests : OneOffConfigurationsContext { public EventProjectionTests() : base("event_projections") { - theStore.Advanced.Clean.DeleteDocumentsFor(typeof(User)); + theStore.Advanced.Clean.DeleteDocumentsByType(typeof(User)); } protected void UseProjection() where T : EventProjection, new() diff --git a/src/Marten.Testing/Events/Projections/appending_events_and_storing.cs b/src/Marten.Testing/Events/Projections/appending_events_and_storing.cs index dd7e7010d3..3a43a35a41 100644 --- a/src/Marten.Testing/Events/Projections/appending_events_and_storing.cs +++ b/src/Marten.Testing/Events/Projections/appending_events_and_storing.cs @@ -8,6 +8,7 @@ using Marten.Storage; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events.Projections @@ -17,7 +18,7 @@ public class appending_events_and_storing: IntegrationContext [Theory] [InlineData(TenancyStyle.Single)] [InlineData(TenancyStyle.Conjoined)] - public void patch_inside_inline_projection_does_not_error_during_savechanges(TenancyStyle tenancyStyle) + public async Task patch_inside_inline_projection_does_not_error_during_savechanges(TenancyStyle tenancyStyle) { StoreOptions(_ => { @@ -27,7 +28,7 @@ public void patch_inside_inline_projection_does_not_error_during_savechanges(Ten _.Events.Projections.Add(new QuestPatchTestProjection()); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); var aggregateId = Guid.NewGuid(); var quest = new Quest @@ -41,9 +42,9 @@ public void patch_inside_inline_projection_does_not_error_during_savechanges(Ten }; theSession.Events.Append(aggregateId, quest, questStarted); - theSession.SaveChanges(); + await theSession.SaveChangesAsync(); - theSession.Events.FetchStreamState(aggregateId).Version.ShouldBe(2); + (await theSession.Events.FetchStreamStateAsync(aggregateId)).Version.ShouldBe(2); } public class QuestPatchTestProjection: IProjection diff --git a/src/Marten.Testing/Events/Projections/custom_transformation_of_events.cs b/src/Marten.Testing/Events/Projections/custom_transformation_of_events.cs index 1a6a6f575d..454cd59ca4 100644 --- a/src/Marten.Testing/Events/Projections/custom_transformation_of_events.cs +++ b/src/Marten.Testing/Events/Projections/custom_transformation_of_events.cs @@ -5,6 +5,7 @@ using Marten.Events.Projections; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events.Projections diff --git a/src/Marten.Testing/Events/Projections/inline_aggregation_by_stream_with_multiples.cs b/src/Marten.Testing/Events/Projections/inline_aggregation_by_stream_with_multiples.cs index b598abc64e..fe5a11a397 100644 --- a/src/Marten.Testing/Events/Projections/inline_aggregation_by_stream_with_multiples.cs +++ b/src/Marten.Testing/Events/Projections/inline_aggregation_by_stream_with_multiples.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; -using Marten.Services; using Marten.Storage; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events.Projections diff --git a/src/Marten.Testing/Events/Projections/inline_aggregation_with_base_view_class.cs b/src/Marten.Testing/Events/Projections/inline_aggregation_with_base_view_class.cs index 202a129f28..565f0d9b79 100644 --- a/src/Marten.Testing/Events/Projections/inline_aggregation_with_base_view_class.cs +++ b/src/Marten.Testing/Events/Projections/inline_aggregation_with_base_view_class.cs @@ -1,8 +1,8 @@ using System; using System.Linq; -using Marten.Services; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events.Projections diff --git a/src/Marten.Testing/Events/Projections/inline_aggregation_with_non_public_setter.cs b/src/Marten.Testing/Events/Projections/inline_aggregation_with_non_public_setter.cs index 9b64de607b..10d49f19d5 100644 --- a/src/Marten.Testing/Events/Projections/inline_aggregation_with_non_public_setter.cs +++ b/src/Marten.Testing/Events/Projections/inline_aggregation_with_non_public_setter.cs @@ -1,8 +1,8 @@ using System; using System.Linq; -using Marten.Services; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events.Projections diff --git a/src/Marten.Testing/Events/Projections/inline_aggregation_with_private_constructor.cs b/src/Marten.Testing/Events/Projections/inline_aggregation_with_private_constructor.cs index 2e8146dbc6..a2667e2fc1 100644 --- a/src/Marten.Testing/Events/Projections/inline_aggregation_with_private_constructor.cs +++ b/src/Marten.Testing/Events/Projections/inline_aggregation_with_private_constructor.cs @@ -1,8 +1,8 @@ using System; using System.Linq; -using Marten.Services; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events.Projections diff --git a/src/Marten.Testing/Events/Projections/inline_transformation_of_events.cs b/src/Marten.Testing/Events/Projections/inline_transformation_of_events.cs index ff0d589c85..27497e28b3 100644 --- a/src/Marten.Testing/Events/Projections/inline_transformation_of_events.cs +++ b/src/Marten.Testing/Events/Projections/inline_transformation_of_events.cs @@ -4,10 +4,10 @@ using Baseline; using Marten.Events; using Marten.Events.Projections; -using Marten.Services; using Marten.Storage; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events.Projections diff --git a/src/Marten.Testing/Events/appending_events_workflow_specs.cs b/src/Marten.Testing/Events/appending_events_workflow_specs.cs index 5ddc2983f0..69d5eca72e 100644 --- a/src/Marten.Testing/Events/appending_events_workflow_specs.cs +++ b/src/Marten.Testing/Events/appending_events_workflow_specs.cs @@ -12,11 +12,11 @@ using Marten.Internal; using Marten.Internal.Operations; using Marten.Internal.Sessions; +using Weasel.Postgresql; using Marten.Services; using Marten.Storage; using Marten.Testing.Events.Aggregation; using Marten.Testing.Harness; -using Marten.Util; using Shouldly; using Xunit; using Xunit.Abstractions; diff --git a/src/Marten.Testing/Events/delete_single_event_stream.cs b/src/Marten.Testing/Events/delete_single_event_stream.cs index 42c40f8a2e..198ab06f2c 100644 --- a/src/Marten.Testing/Events/delete_single_event_stream.cs +++ b/src/Marten.Testing/Events/delete_single_event_stream.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using Marten.Events; using Marten.Storage; using Marten.Testing.Harness; @@ -44,6 +45,40 @@ public void delete_stream_by_guid_id(TenancyStyle tenancyStyle) } } + [Theory] + [InlineData(TenancyStyle.Single)] + [InlineData(TenancyStyle.Conjoined)] + public async Task delete_stream_by_guid_id_async(TenancyStyle tenancyStyle) + { + StoreOptions(_ => _.Events.TenancyStyle = tenancyStyle); + + var stream1 = Guid.NewGuid(); + var stream2 = Guid.NewGuid(); + + using (var session = theStore.LightweightSession()) + { + var joined = new MembersJoined { Members = new[] { "Rand", "Matt", "Perrin", "Thom" } }; + var departed = new MembersDeparted { Members = new[] { "Thom" } }; + + session.Events.Append(stream1, joined, departed); + + var joined2 = new MembersJoined { Members = new[] { "Rand", "Matt", "Perrin", "Thom" } }; + var departed2 = new MembersDeparted { Members = new[] { "Thom" } }; + + session.Events.Append(stream2, joined2, departed2); + + await session.SaveChangesAsync(); + } + + await theStore.Advanced.Clean.DeleteSingleEventStreamAsync(stream1); + + using (var session = theStore.LightweightSession()) + { + session.Events.QueryAllRawEvents().ToList().All(x => x.StreamId == stream2) + .ShouldBeTrue(); + } + } + [Theory] [InlineData(TenancyStyle.Single)] [InlineData(TenancyStyle.Conjoined)] diff --git a/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_Tests.cs b/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_Tests.cs index 28f8373950..8bccbe51d7 100644 --- a/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_Tests.cs +++ b/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_Tests.cs @@ -7,6 +7,7 @@ using Marten.Testing.Events.Utils; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events diff --git a/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_with_non_typed_streams_Tests.cs b/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_with_non_typed_streams_Tests.cs index 549a7c5ca5..1fba4037c2 100644 --- a/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_with_non_typed_streams_Tests.cs +++ b/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_with_non_typed_streams_Tests.cs @@ -6,6 +6,7 @@ using Marten.Testing.Events.Projections; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events diff --git a/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_with_string_identifiers.cs b/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_with_string_identifiers.cs index 5023d918f8..5ef627d320 100644 --- a/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_with_string_identifiers.cs +++ b/src/Marten.Testing/Events/end_to_end_event_capture_and_fetching_the_stream_with_string_identifiers.cs @@ -4,9 +4,9 @@ using System.Threading.Tasks; using Baseline; using Marten.Events; -using Marten.Testing; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events diff --git a/src/Marten.Testing/Events/event_store_with_string_identifiers_for_stream.cs b/src/Marten.Testing/Events/event_store_with_string_identifiers_for_stream.cs index 070789d1b8..91bdb64824 100644 --- a/src/Marten.Testing/Events/event_store_with_string_identifiers_for_stream.cs +++ b/src/Marten.Testing/Events/event_store_with_string_identifiers_for_stream.cs @@ -30,8 +30,11 @@ public void use_string_id_if_as_string_identifiers() var table = new StreamsTable(events); - table.PrimaryKey.Type.ShouldBe("varchar"); - table.First().Name.ShouldBe("id"); + var pk = table.Columns.Single(x => x.IsPrimaryKey); + + pk.Type.ShouldBe("varchar"); + pk.Name.ShouldBe("id"); + table.Columns.First().Name.ShouldBe("id"); } [Fact] diff --git a/src/Marten.Testing/Events/patch_writing.cs b/src/Marten.Testing/Events/patch_writing.cs deleted file mode 100644 index 3f184e5c34..0000000000 --- a/src/Marten.Testing/Events/patch_writing.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Marten.Events; -using Marten.Testing.Harness; -using Xunit; - -namespace Marten.Testing.Events -{ - public class patch_writing: IntegrationContext - { - [Fact] - public void generate_the_patch_with_drop_if_does_not_exist() - { - var schemaName = StoreOptions(_ => - { - _.Events.AddEventType(typeof(MembersJoined)); - }); - - var patch = theStore.Schema.ToPatch(); - - patch.RollbackDDL.ShouldContain($"drop table if exists {schemaName}.mt_streams cascade;"); - } - - [Fact] - public void generate_the_patch_with_drop_if_does_not_exist_in_a_different_schema() - { - StoreOptions(_ => - { - _.Events.AddEventType(typeof(MembersJoined)); - _.Events.DatabaseSchemaName = "events"; - }); - - var patch = theStore.Schema.ToPatch(); - - patch.RollbackDDL.ShouldContain("drop table if exists events.mt_streams cascade;"); - } - - [Fact] - public void no_rollback_if_the_table_already_existed() - { - StoreOptions(_ => - { - _.Events.AddEventType(typeof(MembersJoined)); - }); - - theStore.Tenancy.Default.EnsureStorageExists(typeof(StreamAction)); - - var patch = theStore.Schema.ToPatch(); - - patch.RollbackDDL.ShouldNotContain("public.mt_streams"); - } - - public patch_writing(DefaultStoreFixture fixture) : base(fixture) - { - } - } -} diff --git a/src/Marten.Testing/Events/query_against_event_documents_Tests.cs b/src/Marten.Testing/Events/query_against_event_documents_Tests.cs index 4d87094a9a..8777c28b1c 100644 --- a/src/Marten.Testing/Events/query_against_event_documents_Tests.cs +++ b/src/Marten.Testing/Events/query_against_event_documents_Tests.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using Weasel.Postgresql; using Marten.Services; using Marten.Testing.Harness; using Marten.Util; diff --git a/src/Marten.Testing/Events/using_the_schema_objects_Tests.cs b/src/Marten.Testing/Events/using_the_schema_objects_Tests.cs index 480d430707..d4b06305cc 100644 --- a/src/Marten.Testing/Events/using_the_schema_objects_Tests.cs +++ b/src/Marten.Testing/Events/using_the_schema_objects_Tests.cs @@ -1,8 +1,11 @@ using System; +using System.Linq; +using System.Threading.Tasks; using Marten.Events; using Marten.Testing.Events.Projections; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Events @@ -50,7 +53,7 @@ public void can_build_schema_with_auto_create_none() } [Fact] - public void can_build_the_event_schema_objects_in_a_separted_schema() + public async Task can_build_the_event_schema_objects_in_a_separted_schema() { var store = StoreOptions(_ => { @@ -61,24 +64,24 @@ public void can_build_the_event_schema_objects_in_a_separted_schema() store.Tenancy.Default.EnsureStorageExists(typeof(StreamAction)); - var schemaTableNames = store.Tenancy.Default.DbObjects.SchemaTables(); + var schemaTableNames = (await store.Tenancy.Default.SchemaTables()).Select(x => x.QualifiedName).ToArray(); schemaTableNames.ShouldContain("event_store.mt_streams"); schemaTableNames.ShouldContain("event_store.mt_events"); } [Fact] - public void can_build_the_mt_stream_schema_objects() + public async Task can_build_the_mt_stream_schema_objects() { theStore.Tenancy.Default.EnsureStorageExists(typeof(StreamAction)); - var schemaTableNames = theStore.Tenancy.Default.DbObjects.SchemaTables(); + var schemaTableNames = (await theStore.Tenancy.Default.SchemaTables()).Select(x => x.QualifiedName).ToArray(); schemaTableNames.ShouldContain($"{SchemaName}.mt_streams"); schemaTableNames.ShouldContain($"{SchemaName}.mt_events"); schemaTableNames.ShouldContain($"{SchemaName}.mt_event_progression"); } [Fact] - public void can_build_the_mt_stream_schema_objects_in_different_database_schema() + public async Task can_build_the_mt_stream_schema_objects_in_different_database_schema() { var store = SeparateStore(_ => { @@ -87,7 +90,7 @@ public void can_build_the_mt_stream_schema_objects_in_different_database_schema( store.Tenancy.Default.EnsureStorageExists(typeof(StreamAction)); - var schemaTableNames = store.Tenancy.Default.DbObjects.SchemaTables(); + var schemaTableNames = (await store.Tenancy.Default.SchemaTables()).Select(x => x.QualifiedName).ToArray(); schemaTableNames.ShouldContain("other.mt_streams"); schemaTableNames.ShouldContain("other.mt_events"); schemaTableNames.ShouldContain("other.mt_event_progression"); diff --git a/src/Marten.Testing/Examples/ConfiguringDocumentStore.cs b/src/Marten.Testing/Examples/ConfiguringDocumentStore.cs index 068167864f..2a3c10320b 100644 --- a/src/Marten.Testing/Examples/ConfiguringDocumentStore.cs +++ b/src/Marten.Testing/Examples/ConfiguringDocumentStore.cs @@ -1,9 +1,9 @@ -using System; using System.Linq; using Marten.Services; using Marten.Testing.Documents; using Marten.Testing.Harness; using Newtonsoft.Json; +using Weasel.Postgresql; namespace Marten.Testing.Examples { diff --git a/src/Marten.Testing/Examples/DDLCustomization.cs b/src/Marten.Testing/Examples/DDLCustomization.cs index 250daaad7b..ccc639864f 100644 --- a/src/Marten.Testing/Examples/DDLCustomization.cs +++ b/src/Marten.Testing/Examples/DDLCustomization.cs @@ -1,4 +1,5 @@ using Marten.Testing.Documents; +using Weasel.Postgresql; namespace Marten.Testing.Examples { diff --git a/src/Marten.Testing/Examples/DocumentCleanerExamples.cs b/src/Marten.Testing/Examples/DocumentCleanerExamples.cs index afe2f5103a..a5396c7fd1 100644 --- a/src/Marten.Testing/Examples/DocumentCleanerExamples.cs +++ b/src/Marten.Testing/Examples/DocumentCleanerExamples.cs @@ -18,7 +18,7 @@ public void clean_out_documents(IDocumentStore store) store.Advanced.Clean.DeleteAllDocuments(); // Deletes all of the persisted User documents - store.Advanced.Clean.DeleteDocumentsFor(typeof(User)); + store.Advanced.Clean.DeleteDocumentsByType(typeof(User)); // For cases where you may want to keep some document types, // but eliminate everything else. This is here specifically to support diff --git a/src/Marten.Testing/Examples/ExportingDDL.cs b/src/Marten.Testing/Examples/ExportingDDL.cs index 114eb259f4..067b32c36e 100644 --- a/src/Marten.Testing/Examples/ExportingDDL.cs +++ b/src/Marten.Testing/Examples/ExportingDDL.cs @@ -21,15 +21,15 @@ public void export_ddl() }); // Export the SQL to a file - store.Schema.WriteDDL("my_database.sql"); + store.Schema.WriteDatabaseCreationScriptFile("my_database.sql"); // Or instead, write a separate sql script // to the named directory // for each type of document - store.Schema.WriteDDLByType("sql"); + store.Schema.WriteDatabaseCreationScriptByType("sql"); // or just see it - var sql = store.Schema.ToDDL(); + var sql = store.Schema.ToDatabaseScript(); Debug.WriteLine(sql); } diff --git a/src/Marten.Testing/Examples/ForeignKeyExamples.cs b/src/Marten.Testing/Examples/ForeignKeyExamples.cs index 18971f5b19..29b95235ed 100644 --- a/src/Marten.Testing/Examples/ForeignKeyExamples.cs +++ b/src/Marten.Testing/Examples/ForeignKeyExamples.cs @@ -1,4 +1,6 @@ using Marten.Testing.Documents; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; namespace Marten.Testing.Examples { @@ -45,9 +47,9 @@ public void cascade_deletes_with_config_func() { _.Connection("some database connection"); - _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.CascadeDeletes = true); + _.Schema.For().ForeignKey(x => x.AssigneeId, fkd => fkd.OnDelete = CascadeAction.Cascade); }); #endregion sample_cascade_deletes_with_config_func } } -} \ No newline at end of file +} diff --git a/src/Marten.Testing/Examples/MartenRegistryExamples.cs b/src/Marten.Testing/Examples/MartenRegistryExamples.cs index ceaf4aa78f..406e80f050 100644 --- a/src/Marten.Testing/Examples/MartenRegistryExamples.cs +++ b/src/Marten.Testing/Examples/MartenRegistryExamples.cs @@ -1,5 +1,6 @@ using Marten.Schema; using Marten.Testing.Documents; +using Weasel.Postgresql.Tables; namespace Marten.Testing.Examples { @@ -65,7 +66,7 @@ public static void Configure() // for FirstName options.Schema.For().Duplicate(x => x.FirstName, configure: idx => { - idx.IndexName = "idx_special"; + idx.Name = "idx_special"; idx.Method = IndexMethod.hash; }); diff --git a/src/Marten.Testing/Examples/Setting_Timestamp_on_all_changes_by_base_class_Tests.cs b/src/Marten.Testing/Examples/Setting_Timestamp_on_all_changes_by_base_class_Tests.cs index 2ddffe5eab..ff3971471b 100644 --- a/src/Marten.Testing/Examples/Setting_Timestamp_on_all_changes_by_base_class_Tests.cs +++ b/src/Marten.Testing/Examples/Setting_Timestamp_on_all_changes_by_base_class_Tests.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Baseline; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Examples diff --git a/src/Marten.Testing/Exceptions/known_exception_causes_dueto_pg9.cs b/src/Marten.Testing/Exceptions/known_exception_causes_dueto_pg9.cs index 09487f9e1e..226c722890 100644 --- a/src/Marten.Testing/Exceptions/known_exception_causes_dueto_pg9.cs +++ b/src/Marten.Testing/Exceptions/known_exception_causes_dueto_pg9.cs @@ -1,7 +1,9 @@ +using System.Diagnostics; using System.Linq; using Marten.Exceptions; using Marten.Testing.Documents; using Marten.Testing.Harness; +using Npgsql; using Shouldly; using Xunit; diff --git a/src/Marten.Testing/Harness/IntegrationContext.cs b/src/Marten.Testing/Harness/IntegrationContext.cs index ec8d98d4ef..059ffdeb84 100644 --- a/src/Marten.Testing/Harness/IntegrationContext.cs +++ b/src/Marten.Testing/Harness/IntegrationContext.cs @@ -1,7 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; -using Marten.Testing.Examples; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Harness diff --git a/src/Marten.Testing/Harness/OneOffConfigurationsContext.cs b/src/Marten.Testing/Harness/OneOffConfigurationsContext.cs index f945330710..b561952259 100644 --- a/src/Marten.Testing/Harness/OneOffConfigurationsContext.cs +++ b/src/Marten.Testing/Harness/OneOffConfigurationsContext.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; -using System.Threading; using Baseline; -using Marten.Testing.Events; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Harness diff --git a/src/Marten.Testing/Harness/SpecificationExtensions.cs b/src/Marten.Testing/Harness/SpecificationExtensions.cs index 33c52c02c0..64311ece61 100644 --- a/src/Marten.Testing/Harness/SpecificationExtensions.cs +++ b/src/Marten.Testing/Harness/SpecificationExtensions.cs @@ -6,6 +6,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Baseline; +using Weasel.Postgresql; using Marten.Schema; using Newtonsoft.Json.Linq; using Shouldly; diff --git a/src/Marten.Testing/Harness/StoreFixture.cs b/src/Marten.Testing/Harness/StoreFixture.cs index 1d2dc68c02..359b70159f 100644 --- a/src/Marten.Testing/Harness/StoreFixture.cs +++ b/src/Marten.Testing/Harness/StoreFixture.cs @@ -1,4 +1,5 @@ using System; +using Weasel.Postgresql; namespace Marten.Testing.Harness { @@ -16,7 +17,6 @@ protected StoreFixture(string schemaName) // Can be overridden Options.AutoCreateSchemaObjects = AutoCreate.All; - Options.NameDataLength = 100; } protected StoreOptions Options { get; } = new StoreOptions(); diff --git a/src/Marten.Testing/Internals/SqlGeneration/CommandParameterTests.cs b/src/Marten.Testing/Internals/SqlGeneration/CommandParameterTests.cs index 80e62a35ff..6a206ae61c 100644 --- a/src/Marten.Testing/Internals/SqlGeneration/CommandParameterTests.cs +++ b/src/Marten.Testing/Internals/SqlGeneration/CommandParameterTests.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Linq.Expressions; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; using Npgsql; using NpgsqlTypes; diff --git a/src/Marten.Testing/Linq/Bug_1061_string_enum_serialization_does_not_work_with_ginindexjsondata.cs b/src/Marten.Testing/Linq/Bug_1061_string_enum_serialization_does_not_work_with_ginindexjsondata.cs index 8609f0ccda..e40358d4bc 100644 --- a/src/Marten.Testing/Linq/Bug_1061_string_enum_serialization_does_not_work_with_ginindexjsondata.cs +++ b/src/Marten.Testing/Linq/Bug_1061_string_enum_serialization_does_not_work_with_ginindexjsondata.cs @@ -1,6 +1,8 @@ using System.Linq; +using System.Threading.Tasks; using Marten.Services; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Linq @@ -19,7 +21,7 @@ public enum Bug_1061_Enum public class Bug_1061_string_enum_serialization_does_not_work_with_ginindexjsondata: IntegrationContext { [Fact] - public void string_enum_serialization_does_not_work_with_ginindexjsondata() + public async Task string_enum_serialization_does_not_work_with_ginindexjsondata() { StoreOptions(_ => @@ -33,9 +35,9 @@ public void string_enum_serialization_does_not_work_with_ginindexjsondata() }); }); - theStore.Schema.ApplyAllConfiguredChangesToDatabase(); + await theStore.Schema.ApplyAllConfiguredChangesToDatabase(); - using (var store = DocumentStore.For(_ => + using var store = DocumentStore.For(_ => { _.Serializer(new JsonNetSerializer { @@ -47,18 +49,18 @@ public void string_enum_serialization_does_not_work_with_ginindexjsondata() { _.Expression = "to_tsvector('english', data::TEXT)"; }); - })) + }); + + using (var session = store.OpenSession()) { - using (var session = store.OpenSession()) - { - session.Store(new Bug_1061_Class { Id = "one", Enum = Bug_1061_Enum.One }); - session.SaveChanges(); - } - using (var session = store.OpenSession()) - { - var items = session.Query().Where(x => x.Enum == Bug_1061_Enum.One).ToList(); - Assert.Single(items); - } + session.Store(new Bug_1061_Class { Id = "one", Enum = Bug_1061_Enum.One }); + await session.SaveChangesAsync(); + } + + using (var session = store.OpenSession()) + { + var items = session.Query().Where(x => x.Enum == Bug_1061_Enum.One).ToList(); + Assert.Single(items); } } diff --git a/src/Marten.Testing/Linq/Compatibility/Support/LinqTestContext.cs b/src/Marten.Testing/Linq/Compatibility/Support/LinqTestContext.cs index 1a6b49e483..86c859e75c 100644 --- a/src/Marten.Testing/Linq/Compatibility/Support/LinqTestContext.cs +++ b/src/Marten.Testing/Linq/Compatibility/Support/LinqTestContext.cs @@ -4,6 +4,7 @@ using System.Linq.Expressions; using System.Threading.Tasks; using Baseline; +using Baseline.ImTools; using Marten.Testing.Documents; using Marten.Util; using Xunit; diff --git a/src/Marten.Testing/Linq/Fields/DuplicatedFieldTests.cs b/src/Marten.Testing/Linq/Fields/DuplicatedFieldTests.cs index 17c5c02db4..ff3a19ba32 100644 --- a/src/Marten.Testing/Linq/Fields/DuplicatedFieldTests.cs +++ b/src/Marten.Testing/Linq/Fields/DuplicatedFieldTests.cs @@ -6,6 +6,7 @@ using Marten.Testing.Documents; using NpgsqlTypes; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Linq.Fields diff --git a/src/Marten.Testing/Linq/Fields/FieldCollectionTests.cs b/src/Marten.Testing/Linq/Fields/FieldCollectionTests.cs index e2710aa1d7..db3222e17e 100644 --- a/src/Marten.Testing/Linq/Fields/FieldCollectionTests.cs +++ b/src/Marten.Testing/Linq/Fields/FieldCollectionTests.cs @@ -8,6 +8,7 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Linq.Fields diff --git a/src/Marten.Testing/Linq/Internals/StatementTests.cs b/src/Marten.Testing/Linq/Internals/StatementTests.cs index 6cb58931da..e526d1dc16 100644 --- a/src/Marten.Testing/Linq/Internals/StatementTests.cs +++ b/src/Marten.Testing/Linq/Internals/StatementTests.cs @@ -1,6 +1,7 @@ using Marten.Internal; using Marten.Linq.Fields; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; using NSubstitute; using Shouldly; diff --git a/src/Marten.Testing/Linq/SoftDeletes/DeletedBeforeParserTests.cs b/src/Marten.Testing/Linq/SoftDeletes/DeletedBeforeParserTests.cs index 70ea109d1a..0ba8a8928b 100644 --- a/src/Marten.Testing/Linq/SoftDeletes/DeletedBeforeParserTests.cs +++ b/src/Marten.Testing/Linq/SoftDeletes/DeletedBeforeParserTests.cs @@ -1,6 +1,7 @@ using System; using System.Linq.Expressions; using Marten.Linq.SoftDeletes; +using Weasel.Postgresql; using Marten.Schema; using Marten.Services; using Marten.Testing.Harness; diff --git a/src/Marten.Testing/Linq/SoftDeletes/DeletedSinceParserTests.cs b/src/Marten.Testing/Linq/SoftDeletes/DeletedSinceParserTests.cs index 9a4360f5bb..1c846e4438 100644 --- a/src/Marten.Testing/Linq/SoftDeletes/DeletedSinceParserTests.cs +++ b/src/Marten.Testing/Linq/SoftDeletes/DeletedSinceParserTests.cs @@ -1,6 +1,7 @@ using System; using System.Linq.Expressions; using Marten.Linq.SoftDeletes; +using Weasel.Postgresql; using Marten.Schema; using Marten.Services; using Marten.Testing.Harness; diff --git a/src/Marten.Testing/Linq/query_against_child_collections_integrated_Tests.cs b/src/Marten.Testing/Linq/query_against_child_collections_integrated_Tests.cs index d93e995bf8..3a709f682b 100644 --- a/src/Marten.Testing/Linq/query_against_child_collections_integrated_Tests.cs +++ b/src/Marten.Testing/Linq/query_against_child_collections_integrated_Tests.cs @@ -9,6 +9,7 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; using Xunit.Abstractions; @@ -287,18 +288,6 @@ private void buildAuthorData() theSession.SaveChanges(); } - public class Article - { - public Guid Id { get; set; } - public long Long { get; set; } - public string[] CategoryArray { get; set; } - public List CategoryList { get; set; } - public Guid[] AuthorArray { get; set; } - public List AuthorList { get; set; } - public Article ReferencedArticle { get; set; } - public bool Published { get; set; } - } - [Fact] public void query_string_array_intersects_array() { @@ -409,37 +398,6 @@ public void query_guid_list_intersects_array() res[0].Long.ShouldBe(5); } - public class DocWithArrays - { - public Guid Id { get; set; } - - public int[] Numbers { get; set; } - - public string[] Strings { get; set; } - - public DateTime[] Dates { get; set; } - } - - public class DocWithLists - { - public Guid Id { get; set; } - - public List Numbers { get; set; } - } - - public class DocWithLists2 - { - public Guid Id { get; set; } - - public IList Numbers { get; set; } - } - - public class DocWithLists3 - { - public Guid Id { get; set; } - - public IEnumerable Numbers { get; set; } - } [Fact] public void query_against_number_array() @@ -690,4 +648,48 @@ public void naked_any_hit_without_predicate() items.Count.ShouldBe(1); } } + + public class Article + { + public Guid Id { get; set; } + public long Long { get; set; } + public string[] CategoryArray { get; set; } + public List CategoryList { get; set; } + public Guid[] AuthorArray { get; set; } + public List AuthorList { get; set; } + public Article ReferencedArticle { get; set; } + public bool Published { get; set; } + } + + public class DocWithLists + { + public Guid Id { get; set; } + + public List Numbers { get; set; } + } + + public class DocWithLists2 + { + public Guid Id { get; set; } + + public IList Numbers { get; set; } + } + + public class DocWithLists3 + { + public Guid Id { get; set; } + + public IEnumerable Numbers { get; set; } + } + + public class DocWithArrays + { + public Guid Id { get; set; } + + public int[] Numbers { get; set; } + + public string[] Strings { get; set; } + + public DateTime[] Dates { get; set; } + } } diff --git a/src/Marten.Testing/Linq/query_for_sum_Tests.cs b/src/Marten.Testing/Linq/query_for_sum_Tests.cs index 1df5238fdd..4ff83382d5 100644 --- a/src/Marten.Testing/Linq/query_for_sum_Tests.cs +++ b/src/Marten.Testing/Linq/query_for_sum_Tests.cs @@ -3,6 +3,7 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Linq diff --git a/src/Marten.Testing/Linq/query_negating_predicate_with_binary_operator_tests.cs b/src/Marten.Testing/Linq/query_negating_predicate_with_binary_operator_tests.cs index 4d08d5e0e2..f9f545e420 100644 --- a/src/Marten.Testing/Linq/query_negating_predicate_with_binary_operator_tests.cs +++ b/src/Marten.Testing/Linq/query_negating_predicate_with_binary_operator_tests.cs @@ -8,13 +8,6 @@ namespace Marten.Testing.Linq { public class query_negating_predicate_with_binary_operator_tests : IntegrationContext { - public class Player - { - public Guid Id { get; set; } - public string Name { get; set; } - public int Level { get; set; } - } - [Fact] public void negating_predicate_with_an_and_operator_results_in_a_correct_query() { @@ -59,4 +52,11 @@ public query_negating_predicate_with_binary_operator_tests(DefaultStoreFixture f { } } + + public class Player + { + public Guid Id { get; set; } + public string Name { get; set; } + public int Level { get; set; } + } } diff --git a/src/Marten.Testing/Linq/query_with_enums_Tests.cs b/src/Marten.Testing/Linq/query_with_enums_Tests.cs index 6c77d0310f..b676529a8c 100644 --- a/src/Marten.Testing/Linq/query_with_enums_Tests.cs +++ b/src/Marten.Testing/Linq/query_with_enums_Tests.cs @@ -2,6 +2,7 @@ using Marten.Services; using Marten.Testing.Documents; using Marten.Testing.Harness; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Linq diff --git a/src/Marten.Testing/Linq/query_with_inheritance.cs b/src/Marten.Testing/Linq/query_with_inheritance.cs index e9ac6f4587..4b09fb281b 100644 --- a/src/Marten.Testing/Linq/query_with_inheritance.cs +++ b/src/Marten.Testing/Linq/query_with_inheritance.cs @@ -1,39 +1,53 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Marten.Schema; -using Marten.Services; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Linq { #region sample_smurfs-hierarchy + public interface ISmurf { string Ability { get; set; } Guid Id { get; set; } } - public class Smurf : ISmurf + + public class Smurf: ISmurf { public string Ability { get; set; } public Guid Id { get; set; } } - public interface IPapaSmurf : ISmurf{} - public class PapaSmurf : Smurf, IPapaSmurf{} - public class PapySmurf : Smurf, IPapaSmurf{} - public class BrainySmurf : PapaSmurf{ } + + public interface IPapaSmurf: ISmurf + { + } + + public class PapaSmurf: Smurf, IPapaSmurf + { + } + + public class PapySmurf: Smurf, IPapaSmurf + { + } + + public class BrainySmurf: PapaSmurf + { + } + #endregion sample_smurfs-hierarchy - public class query_with_inheritance_and_aliases : IntegrationContext + public class query_with_inheritance_and_aliases: IntegrationContext { - public query_with_inheritance_and_aliases(DefaultStoreFixture fixture) : base(fixture) + public query_with_inheritance_and_aliases(DefaultStoreFixture fixture): base(fixture) { StoreOptions(_ => { #region sample_add-subclass-hierarchy-with-aliases + _.Schema.For() .AddSubClassHierarchy( typeof(Smurf), @@ -42,6 +56,7 @@ public query_with_inheritance_and_aliases(DefaultStoreFixture fixture) : base(fi typeof(IPapaSmurf), typeof(BrainySmurf) ); + #endregion sample_add-subclass-hierarchy-with-aliases _.Connection(ConnectionSource.ConnectionString); @@ -54,9 +69,9 @@ public query_with_inheritance_and_aliases(DefaultStoreFixture fixture) : base(fi [Fact] public void get_all_subclasses_of_a_subclass() { - var smurf = new Smurf { Ability = "Follow the herd" }; - var papa = new PapaSmurf { Ability = "Lead" }; - var brainy = new BrainySmurf { Ability = "Invent" }; + var smurf = new Smurf {Ability = "Follow the herd"}; + var papa = new PapaSmurf {Ability = "Lead"}; + var brainy = new BrainySmurf {Ability = "Invent"}; theSession.Store(smurf, papa, brainy); theSession.SaveChanges(); @@ -65,15 +80,17 @@ public void get_all_subclasses_of_a_subclass() } } - public class query_with_inheritance : IntegrationContext + public class query_with_inheritance: IntegrationContext { #region sample_add-subclass-hierarchy - public query_with_inheritance(DefaultStoreFixture fixture) : base(fixture) + + public query_with_inheritance(DefaultStoreFixture fixture): base(fixture) { StoreOptions(_ => { _.Schema.For() - .AddSubClassHierarchy(typeof(Smurf), typeof(PapaSmurf), typeof(PapySmurf), typeof(IPapaSmurf), typeof(BrainySmurf)); + .AddSubClassHierarchy(typeof(Smurf), typeof(PapaSmurf), typeof(PapySmurf), typeof(IPapaSmurf), + typeof(BrainySmurf)); // Alternatively, you can use the following: // _.Schema.For().AddSubClassHierarchy(); @@ -88,16 +105,50 @@ public query_with_inheritance(DefaultStoreFixture fixture) : base(fixture) _.Schema.For().GinIndexJsonData(); }); } + #endregion sample_add-subclass-hierarchy + [Fact] + public void get_all_subclasses_of_an_interface_and_instantiate_them() + { + var smurf = new Smurf {Ability = "Follow the herd"}; + var papa = new PapaSmurf {Ability = "Lead"}; + var papy = new PapySmurf {Ability = "Lead"}; + var brainy = new BrainySmurf {Ability = "Invent"}; + theSession.Store(smurf, papa, brainy, papy); + + theSession.SaveChanges(); + + var list = theSession.Query().ToList(); + list.Count().ShouldBe(3); + list.Count(s => s.Ability == "Invent").ShouldBe(1); + } + + [Fact] + public async Task get_all_subclasses_of_an_interface_and_instantiate_them_async() + { + var smurf = new Smurf {Ability = "Follow the herd"}; + var papa = new PapaSmurf {Ability = "Lead"}; + var papy = new PapySmurf {Ability = "Lead"}; + var brainy = new BrainySmurf {Ability = "Invent"}; + theSession.Store(smurf, papa, brainy, papy); + + await theSession.SaveChangesAsync(); + + var list = await theSession.Query().ToListAsync(); + list.Count().ShouldBe(3); + list.Count(s => s.Ability == "Invent").ShouldBe(1); + } + #region sample_query-subclass-hierarchy + [Fact] public void get_all_subclasses_of_a_subclass() { var smurf = new Smurf {Ability = "Follow the herd"}; var papa = new PapaSmurf {Ability = "Lead"}; - var brainy = new BrainySmurf{Ability = "Invent"}; - theSession.Store(smurf,papa,brainy); + var brainy = new BrainySmurf {Ability = "Invent"}; + theSession.Store(smurf, papa, brainy); theSession.SaveChanges(); @@ -109,8 +160,8 @@ public void get_all_subclasses_of_a_subclass2() { var smurf = new Smurf {Ability = "Follow the herd"}; var papa = new PapaSmurf {Ability = "Lead"}; - var brainy = new BrainySmurf{Ability = "Invent"}; - theSession.Store(smurf,papa,brainy); + var brainy = new BrainySmurf {Ability = "Invent"}; + theSession.Store(smurf, papa, brainy); theSession.SaveChanges(); @@ -122,12 +173,12 @@ public void get_all_subclasses_of_a_subclass_with_where() { var smurf = new Smurf {Ability = "Follow the herd"}; var papa = new PapaSmurf {Ability = "Lead"}; - var brainy = new BrainySmurf{Ability = "Invent"}; - theSession.Store(smurf,papa,brainy); + var brainy = new BrainySmurf {Ability = "Invent"}; + theSession.Store(smurf, papa, brainy); theSession.SaveChanges(); - theSession.Query().Count(s=>s.Ability == "Invent").ShouldBe(1); + theSession.Query().Count(s => s.Ability == "Invent").ShouldBe(1); } [Fact] @@ -136,7 +187,8 @@ public void get_all_subclasses_of_a_subclass_with_where_with_camel_casing() StoreOptions(_ => { _.Schema.For() - .AddSubClassHierarchy(typeof(Smurf), typeof(PapaSmurf), typeof(PapySmurf), typeof(IPapaSmurf), typeof(BrainySmurf)); + .AddSubClassHierarchy(typeof(Smurf), typeof(PapaSmurf), typeof(PapySmurf), typeof(IPapaSmurf), + typeof(BrainySmurf)); // Alternatively, you can use the following: // _.Schema.For().AddSubClassHierarchy(); @@ -153,9 +205,9 @@ public void get_all_subclasses_of_a_subclass_with_where_with_camel_casing() }); - var smurf = new Smurf { Ability = "Follow the herd" }; - var papa = new PapaSmurf { Ability = "Lead" }; - var brainy = new BrainySmurf { Ability = "Invent" }; + var smurf = new Smurf {Ability = "Follow the herd"}; + var papa = new PapaSmurf {Ability = "Lead"}; + var brainy = new BrainySmurf {Ability = "Invent"}; theSession.Store(smurf, papa, brainy); theSession.SaveChanges(); @@ -167,49 +219,17 @@ public void get_all_subclasses_of_a_subclass_with_where_with_camel_casing() [Fact] public void get_all_subclasses_of_an_interface() { - var smurf = new Smurf { Ability = "Follow the herd" }; - var papa = new PapaSmurf { Ability = "Lead" }; - var papy = new PapySmurf { Ability = "Lead" }; - var brainy = new BrainySmurf { Ability = "Invent" }; + var smurf = new Smurf {Ability = "Follow the herd"}; + var papa = new PapaSmurf {Ability = "Lead"}; + var papy = new PapySmurf {Ability = "Lead"}; + var brainy = new BrainySmurf {Ability = "Invent"}; theSession.Store(smurf, papa, brainy, papy); theSession.SaveChanges(); theSession.Query().Count().ShouldBe(3); } - #endregion sample_query-subclass-hierarchy - - [Fact] - public void get_all_subclasses_of_an_interface_and_instantiate_them() - { - var smurf = new Smurf { Ability = "Follow the herd" }; - var papa = new PapaSmurf { Ability = "Lead" }; - var papy = new PapySmurf { Ability = "Lead" }; - var brainy = new BrainySmurf { Ability = "Invent" }; - theSession.Store(smurf, papa, brainy, papy); - - theSession.SaveChanges(); - - var list = theSession.Query().ToList(); - list.Count().ShouldBe(3); - list.Count(s => s.Ability == "Invent").ShouldBe(1); - } - - [Fact] - public async Task get_all_subclasses_of_an_interface_and_instantiate_them_async() - { - var smurf = new Smurf { Ability = "Follow the herd" }; - var papa = new PapaSmurf { Ability = "Lead" }; - var papy = new PapySmurf { Ability = "Lead" }; - var brainy = new BrainySmurf { Ability = "Invent" }; - theSession.Store(smurf, papa, brainy, papy); - - await theSession.SaveChangesAsync(); - - var list = await theSession.Query().ToListAsync(); - list.Count().ShouldBe(3); - list.Count(s => s.Ability == "Invent").ShouldBe(1); - } + #endregion sample_query-subclass-hierarchy } } diff --git a/src/Marten.Testing/Linq/query_with_is_in_generic_enumerable_Tests.cs b/src/Marten.Testing/Linq/query_with_is_in_generic_enumerable_Tests.cs index 4bedcbd3e7..373d08c8f7 100644 --- a/src/Marten.Testing/Linq/query_with_is_in_generic_enumerable_Tests.cs +++ b/src/Marten.Testing/Linq/query_with_is_in_generic_enumerable_Tests.cs @@ -49,16 +49,14 @@ public void can_query_against_number_in_List() .Select(x => x.Id).ShouldHaveTheSameElementsAs(doc2.Id); } - public class DocWithNumber - { - public Guid Id { get; set; } - public int Number { get; set; } - } - public query_with_is_in_generic_enumerable_Tests(DefaultStoreFixture fixture) : base(fixture) { } } - + public class DocWithNumber + { + public Guid Id { get; set; } + public int Number { get; set; } + } } diff --git a/src/Marten.Testing/Linq/query_with_select_many.cs b/src/Marten.Testing/Linq/query_with_select_many.cs index 5e7d7ca2a9..65e674ec5a 100644 --- a/src/Marten.Testing/Linq/query_with_select_many.cs +++ b/src/Marten.Testing/Linq/query_with_select_many.cs @@ -311,7 +311,7 @@ public void select_many_with_any() [Fact] public async Task select_many_with_any_async() { - theStore.Advanced.Clean.DeleteDocumentsFor(typeof(Target)); + theStore.Advanced.Clean.DeleteDocumentsByType(typeof(Target)); var product1 = new Product {Tags = new[] {"a", "b", "c"}}; var product2 = new Product {Tags = new[] {"b", "c", "d"}}; diff --git a/src/Marten.Testing/Linq/using_containment_operator_in_linq_Tests.cs b/src/Marten.Testing/Linq/using_containment_operator_in_linq_Tests.cs index 1e5b78ea25..1788198ad9 100644 --- a/src/Marten.Testing/Linq/using_containment_operator_in_linq_Tests.cs +++ b/src/Marten.Testing/Linq/using_containment_operator_in_linq_Tests.cs @@ -3,6 +3,7 @@ using Marten.Testing.Documents; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Linq diff --git a/src/Marten.Testing/Linq/using_custom_Linq_parser_plugins_Tests.cs b/src/Marten.Testing/Linq/using_custom_Linq_parser_plugins_Tests.cs index c948393b10..41e778e337 100644 --- a/src/Marten.Testing/Linq/using_custom_Linq_parser_plugins_Tests.cs +++ b/src/Marten.Testing/Linq/using_custom_Linq_parser_plugins_Tests.cs @@ -5,22 +5,21 @@ using System.Reflection; using Baseline; using Baseline.Reflection; -using Marten.Linq; using Marten.Linq.Fields; using Marten.Linq.Filters; using Marten.Linq.Parsing; using Marten.Linq.SqlGeneration; -using Marten.Schema; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Linq { - public class using_custom_Linq_parser_plugins_Tests { #region sample_using_custom_linq_parser + [Fact] public void query_with_custom_parser() { @@ -36,7 +35,6 @@ public void query_with_custom_parser() _.DatabaseSchemaName = "isblue"; })) { - store.Advanced.Clean.CompletelyRemoveAll(); @@ -56,13 +54,13 @@ public void query_with_custom_parser() using (var session = store.QuerySession()) { - session.Query().Count(x => CustomExtensions.IsBlue(x)) + session.Query().Count(x => x.IsBlue()) .ShouldBe(count); } } } - #endregion sample_using_custom_linq_parser + #endregion sample_using_custom_linq_parser } public class ColorTarget @@ -74,15 +72,18 @@ public class ColorTarget public static class CustomExtensions { #region sample_custom-extension-for-linq + public static bool IsBlue(this ColorTarget target) { return target.Color == "Blue"; } + #endregion sample_custom-extension-for-linq } #region sample_IsBlue - public class IsBlue : IMethodCallParser + + public class IsBlue: IMethodCallParser { private static readonly PropertyInfo _property = ReflectionHelper.GetProperty(x => x.Color); @@ -98,5 +99,6 @@ public ISqlFragment Parse(IFieldMapping mapping, ISerializer serializer, MethodC return new WhereFragment($"{locator} = 'Blue'"); } } + #endregion sample_IsBlue } diff --git a/src/Marten.Testing/Patching/can_build_the_patching_function.cs b/src/Marten.Testing/Patching/can_build_the_patching_function.cs index d961359a2c..e164c8b3a8 100644 --- a/src/Marten.Testing/Patching/can_build_the_patching_function.cs +++ b/src/Marten.Testing/Patching/can_build_the_patching_function.cs @@ -1,4 +1,5 @@ -using Marten.Testing.Harness; +using System.Threading.Tasks; +using Marten.Testing.Harness; using Shouldly; using Xunit; @@ -7,11 +8,11 @@ namespace Marten.Testing.Patching public class can_build_the_patching_function : IntegrationContext { [Fact] - public void does_not_blow_up() + public async Task does_not_blow_up() { var transform = theStore.Tenancy.Default.TransformFor("patch_doc"); - theStore.Tenancy.Default.DbObjects.Functions() + (await theStore.Tenancy.Default.Functions()) .ShouldContain(transform.Identifier); } diff --git a/src/Marten.Testing/Services/Includes/end_to_end_query_with_include_Tests.cs b/src/Marten.Testing/Services/Includes/end_to_end_query_with_include_Tests.cs index ddbb223263..a7337279fb 100644 --- a/src/Marten.Testing/Services/Includes/end_to_end_query_with_include_Tests.cs +++ b/src/Marten.Testing/Services/Includes/end_to_end_query_with_include_Tests.cs @@ -12,6 +12,7 @@ using Marten.Testing.Linq; using Marten.Util; using Shouldly; +using Weasel.Postgresql; using Xunit; using Xunit.Abstractions; using Issue = Marten.Testing.Documents.Issue; diff --git a/src/Marten.Testing/Storage/TenantTests.cs b/src/Marten.Testing/Storage/TenantTests.cs index 0bed21519c..f98530d609 100644 --- a/src/Marten.Testing/Storage/TenantTests.cs +++ b/src/Marten.Testing/Storage/TenantTests.cs @@ -2,6 +2,7 @@ using Marten.Storage; using Marten.Testing.Harness; using Shouldly; +using Weasel.Postgresql; using Xunit; namespace Marten.Testing.Storage diff --git a/src/Marten.Testing/Transforms/TransformFunctionTests.cs b/src/Marten.Testing/Transforms/TransformFunctionTests.cs index 7494c6a452..99328bdea2 100644 --- a/src/Marten.Testing/Transforms/TransformFunctionTests.cs +++ b/src/Marten.Testing/Transforms/TransformFunctionTests.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using Baseline; +using Weasel.Postgresql; using Marten.Schema; using Marten.Services; using Marten.Storage; diff --git a/src/Marten.Testing/Transforms/TransformFunction_ISchemaObjects_Implementation.cs b/src/Marten.Testing/Transforms/TransformFunction_ISchemaObjects_Implementation.cs index 25199eaaf1..43923e9afb 100644 --- a/src/Marten.Testing/Transforms/TransformFunction_ISchemaObjects_Implementation.cs +++ b/src/Marten.Testing/Transforms/TransformFunction_ISchemaObjects_Implementation.cs @@ -1,4 +1,5 @@ -using Marten.Schema; +using System.Threading.Tasks; +using Marten.Schema; using Marten.Testing.Harness; using Shouldly; using Xunit; @@ -16,16 +17,16 @@ public TransformFunction_ISchemaObjects_Implementation(DefaultStoreFixture fixtu } [Fact] - public void can_generate_when_the_transform_is_requested() + public async Task can_generate_when_the_transform_is_requested() { var transform = theStore.Tenancy.Default.TransformFor("get_fullname"); - theStore.Tenancy.Default.DbObjects.Functions() + (await theStore.Tenancy.Default.Functions()) .ShouldContain(transform.Identifier); } [Fact] - public void reset_still_makes_it_check_again() + public async Task reset_still_makes_it_check_again() { var transform = theStore.Tenancy.Default.TransformFor("get_fullname"); @@ -33,31 +34,29 @@ public void reset_still_makes_it_check_again() var transform2 = theStore.Tenancy.Default.TransformFor("get_fullname"); - theStore.Tenancy.Default.DbObjects.Functions() + (await theStore.Tenancy.Default.Functions()) .ShouldContain(transform2.Identifier); } [Fact] - public void regenerates_if_changed() + public async Task regenerates_if_changed() { var transform = theStore.Tenancy.Default.TransformFor("get_fullname"); - theStore.Tenancy.Default.DbObjects.Functions() + (await theStore.Tenancy.Default.Functions()) .ShouldContain(transform.Identifier); - using (var store2 = DocumentStore.For(_ => + using var store2 = DocumentStore.For(_ => { _.Connection(ConnectionSource.ConnectionString); _.Transforms.LoadJavascript("get_fullname", "module.exports = function(){return {};}"); - })) - { - var transform2 = store2.Tenancy.Default.TransformFor("get_fullname"); + }); + var transform2 = store2.Tenancy.Default.TransformFor("get_fullname"); - SpecificationExtensions.ShouldContain(store2.Tenancy.Default.DbObjects.DefinitionForFunction(transform2.Identifier) - .Body, transform2.Body); - } + (await store2.Tenancy.Default.DefinitionForFunction(transform2.Identifier)) + .Body().ShouldContain(transform2.Body, Case.Sensitive); } } } diff --git a/src/Marten.Testing/Util/CommandBuilderTests.cs b/src/Marten.Testing/Util/CommandBuilderTests.cs index 3c9803be44..e2a202d840 100644 --- a/src/Marten.Testing/Util/CommandBuilderTests.cs +++ b/src/Marten.Testing/Util/CommandBuilderTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Reflection; using System.Text; +using Weasel.Postgresql; using Marten.Testing.Documents; using Npgsql; using Xunit; @@ -13,27 +14,6 @@ namespace Marten.Testing.Util { public class CommandBuilderTests { - [Theory] - [InlineData("data", Casing.Default, "data -> 'Inner' ->> 'AnotherString'")] - [InlineData("d.data", Casing.CamelCase, "d.data -> 'inner' ->> 'anotherString'")] - [InlineData("string", Casing.SnakeCase, "string -> 'inner' ->> 'another_string'")] - public void build_json_string_locator(string column, Casing casing, string expected) - { - var members = new MemberInfo[] { ReflectionHelper.GetProperty(x => x.Inner), ReflectionHelper.GetProperty(x => x.AnotherString) }; - var locator = CommandBuilder.BuildJsonStringLocator(column, members, casing); - locator.ShouldBe(expected); - } - - [Theory] - [InlineData("data", Casing.Default, "data -> 'Inner' -> 'AnotherString'")] - [InlineData("d.data", Casing.CamelCase, "d.data -> 'inner' -> 'anotherString'")] - [InlineData("string", Casing.SnakeCase, "string -> 'inner' -> 'another_string'")] - public void build_json_object_locator(string column, Casing casing, string expected) - { - var members = new MemberInfo[] { ReflectionHelper.GetProperty(x => x.Inner), ReflectionHelper.GetProperty(x => x.AnotherString) }; - var locator = CommandBuilder.BuildJsonObjectLocator(column, members, casing); - locator.ShouldBe(expected); - } [Fact] public void append_parameters_with_one_at_the_end() diff --git a/src/Marten.Testing/Util/CommandExtensionsTests.cs b/src/Marten.Testing/Util/CommandExtensionsTests.cs index 66aa9cc43b..fec92074e1 100644 --- a/src/Marten.Testing/Util/CommandExtensionsTests.cs +++ b/src/Marten.Testing/Util/CommandExtensionsTests.cs @@ -1,4 +1,5 @@ -using Marten.Util; +using Weasel.Postgresql; +using Marten.Util; using Npgsql; using NpgsqlTypes; using Shouldly; diff --git a/src/Marten.Testing/Util/LambdaBuilderTester.cs b/src/Marten.Testing/Util/LambdaBuilderTester.cs deleted file mode 100644 index 8df2e14992..0000000000 --- a/src/Marten.Testing/Util/LambdaBuilderTester.cs +++ /dev/null @@ -1,170 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using Baseline.Reflection; -using Marten.Linq; -using Marten.Linq.Parsing; -using Marten.Testing.Documents; -using Marten.Testing.Harness; -using Marten.Util; -using Shouldly; -using Xunit; - -namespace Marten.Testing.Util -{ - public class LambdaBuilderTester - { - [Fact] - public void can_build_getter_for_property() - { - var target = new Target { Number = 5 }; - var prop = ReflectionHelper.GetProperty(x => x.Number); - - var getter = LambdaBuilder.GetProperty(prop); - - getter(target).ShouldBe(target.Number); - } - - public class GuyWithField - { - public Guid Id = Guid.NewGuid(); - } - - [Fact] - public void can_build_getter_for_field() - { - var guy = new GuyWithField(); - - var field = typeof(GuyWithField).GetField("Id"); - - var getter = LambdaBuilder.GetField(field); - - getter(guy).ShouldBe(guy.Id); - } - - [Fact] - public void can_build_setter_for_property() - { - var target = new Target { Number = 5 }; - var prop = ReflectionHelper.GetProperty(x => x.Number); - - var setter = LambdaBuilder.SetProperty(prop); - - setter(target, 11); - - target.Number.ShouldBe(11); - } - - [Fact] - public void can_build_setter_for_field() - { - var guy = new GuyWithField(); - - var field = typeof(GuyWithField).GetField("Id"); - - var setter = LambdaBuilder.SetField(field); - - var newGuid = Guid.NewGuid(); - - setter(guy, newGuid); - - guy.Id.ShouldBe(newGuid); - } - - [Fact] - public void can_build_getter_for_deep_expression() - { - Expression> expression = t => t.Inner.Number; - - var visitor = new FindMembers(); - visitor.Visit(expression); - - var members = visitor.Members.ToArray(); - - var getter = LambdaBuilder.Getter(EnumStorage.AsInteger, members); - - var target = Target.Random(true); - - getter(target).ShouldBe(target.Inner.Number); - } - - [Theory] - [InlineData(EnumStorage.AsInteger)] - [InlineData(EnumStorage.AsString)] - public void can_build_getter_for_enum_expression(EnumStorage enumStorage) - { - Expression> expression = t => t.Color; - var visitor = new FindMembers(); - visitor.Visit(expression); - - var members = visitor.Members.ToArray(); - var getter = LambdaBuilder.Getter(enumStorage, members); - - var target = new Target { Inner = new Target { Color = Colors.Blue } }; - getter(target).ShouldBe(target.Color); - } - - [Fact] - public void can_build_getter_for_deep_enum_expression_with_int_enum_storage() - { - canBuildGetterForDeepEnumExpression(EnumStorage.AsInteger); - } - - [Fact] - public void can_build_getter_for_deep_enum_expression_with_string_enum_storage() - { - canBuildGetterForDeepEnumExpression(EnumStorage.AsString); - } - - private static void canBuildGetterForDeepEnumExpression(EnumStorage enumStorage) - { - Expression> expression = t => t.Inner.Color; - var visitor = new FindMembers(); - visitor.Visit(expression); - - var members = visitor.Members.ToArray(); - var getter = LambdaBuilder.Getter(enumStorage, members); - var target = new Target { Inner = new Target { Color = Colors.Blue } }; - - getter(target).ShouldBeOfType(typeof(T)); - } - - [Fact] - public void can_build_getter_for_null_deep_expression() - { - Expression> expression = t => t.Inner.Number; - - var visitor = new FindMembers(); - visitor.Visit(expression); - - var members = visitor.Members.ToArray(); - - var getter = LambdaBuilder.Getter(EnumStorage.AsInteger, members); - - var target = Target.Random(false); - - getter(target).ShouldBe(default(int)); - } - - [Fact] - public void can_get_the_Enum_GetName_method() - { - SpecificationExtensions.ShouldNotBeNull(typeof(Enum).GetMethods(BindingFlags.Static | BindingFlags.Public).Single(mi => mi.Name == nameof(Enum.GetName) && !mi.IsGenericMethod)); - } - - [Fact] - public void can_set_a_private_id() - { - var member = ReflectionHelper.GetProperty(x => x.Id); - var setter = LambdaBuilder.Setter(member); - - var newGuid = Guid.NewGuid(); - var userWithPrivateId = new UserWithPrivateId(); - - setter(userWithPrivateId, newGuid); - - userWithPrivateId.Id.ShouldBe(newGuid); - } - } -} diff --git a/src/Marten.Testing/Util/NewTests.cs b/src/Marten.Testing/Util/NewTests.cs deleted file mode 100644 index f887e54f28..0000000000 --- a/src/Marten.Testing/Util/NewTests.cs +++ /dev/null @@ -1,263 +0,0 @@ -using Marten.Util; -using Shouldly; -using Xunit; - -namespace Marten.Testing.Util -{ - public class NewTests - { - [Fact] - public void can_create_intialized_instance_of_class_with_public_default_constructor() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeOfType(); - instance.IsInitialized.ShouldBeTrue(); - } - - [Fact] - public void can_create_intialized_instance_of_class_with_public_default_constructor_and_public_non_default_constructor() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeOfType(); - instance.IsInitialized.ShouldBeTrue(); - } - - [Fact] - public void can_create_intialized_instance_of_class_with_protected_default_constructor() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeOfType(); - instance.IsInitialized.ShouldBeTrue(); - } - - [Fact] - public void can_create_intialized_instance_of_class_with_protected_default_constructor_and_public_non_default_constructor() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeOfType(); - instance.IsInitialized.ShouldBeTrue(); - } - - [Fact] - public void can_create_intialized_instance_of_class_with_private_default_constructor() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeOfType(); - instance.IsInitialized.ShouldBeTrue(); - } - - [Fact] - public void can_create_not_intialized_instance_of_class_with_no_default_constructor() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeOfType(); - instance.IsInitialized.ShouldBeFalse(); - } - - [Fact] - public void can_create_intialized_instance_of_class_with_private_default_constructor_and_public_non_default_constructor() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeOfType(); - instance.IsInitialized.ShouldBeTrue(); - } - - [Fact] - public void can_create_intialized_instance_of_class_with_public_default_constructor_and_base_class_with_public_default_constructor() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeOfType(); - instance.IsInitialized.ShouldBeTrue(); - instance.IsInitializedInBaseClass.ShouldBeTrue(); - } - - [Fact] - public void can_create_intialized_instance_of_class_with_protected_default_constructor_and_base_class_with_public_default_constructor() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeOfType(); - instance.IsInitialized.ShouldBeTrue(); - instance.IsInitializedInBaseClass.ShouldBeTrue(); - } - - [Fact] - public void can_create_intialized_instance_of_class_with_private_default_constructor_and_base_class_with_public_default_constructor() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeOfType(); - instance.IsInitialized.ShouldBeTrue(); - instance.IsInitializedInBaseClass.ShouldBeTrue(); - } - - [Fact] - public void can_create__not_intialized_instance_of_class_with_no_default_constructor_and_base_class_with_public_default_constructor() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeOfType(); - instance.IsInitialized.ShouldBeFalse(); - instance.IsInitializedInBaseClass.ShouldBeFalse(); - } - - [Fact] - public void can_create_intialized_instance_of_string_and_returns_empty_string() - { - var instance = New.Instance(); - - instance.ShouldNotBeNull(); - instance.ShouldBeEmpty(); - } - } - - internal class ClassWithPublicDefaultConstructor - { - public bool IsInitialized = false; - - public ClassWithPublicDefaultConstructor() - { - IsInitialized = true; - } - } - - internal class ClassWithPublicDefaultConstructorAndPublicNonDefaultConstructor - { - public bool IsInitialized = false; - - public ClassWithPublicDefaultConstructorAndPublicNonDefaultConstructor() - { - IsInitialized = true; - } - - public ClassWithPublicDefaultConstructorAndPublicNonDefaultConstructor(string stringParam) - { - } - } - - internal class ClassWithProtectedDefaultConstructor - { - public bool IsInitialized = true; - - private ClassWithProtectedDefaultConstructor() - { - } - } - - internal class ClassWithNoDefaultConstructor - { - public bool IsInitialized = false; - - public ClassWithNoDefaultConstructor(string stringParam) - { - IsInitialized = true; - } - } - - internal class ClassWithProtectedDefaultConstructorAndPublicNonDefaultConstructor - { - public bool IsInitialized = false; - - private ClassWithProtectedDefaultConstructorAndPublicNonDefaultConstructor() - { - IsInitialized = true; - } - - public ClassWithProtectedDefaultConstructorAndPublicNonDefaultConstructor(string stringParam) - { - } - } - - internal class ClassWithPrivateDefaultConstructor - { - public bool IsInitialized = false; - - private ClassWithPrivateDefaultConstructor() - { - IsInitialized = true; - } - } - - internal class ClassWithPrivateDefaultConstructorAndPublicNonDefaultConstructor - { - public bool IsInitialized = false; - - private ClassWithPrivateDefaultConstructorAndPublicNonDefaultConstructor() - { - IsInitialized = true; - } - - public ClassWithPrivateDefaultConstructorAndPublicNonDefaultConstructor(string stringParam) - { - } - } - - internal class BaseClassWithPublicDefaultConstructor - { - public bool IsInitializedInBaseClass = false; - - public BaseClassWithPublicDefaultConstructor() - { - IsInitializedInBaseClass = true; - } - } - - internal class DerivedClassWithPublicDefaultConstructor: BaseClassWithPublicDefaultConstructor - { - public bool IsInitialized = false; - - public DerivedClassWithPublicDefaultConstructor() - { - IsInitialized = true; - } - } - - internal class DerivedClassWithProtectedDefaultConstructor: BaseClassWithPublicDefaultConstructor - { - public bool IsInitialized = false; - - private DerivedClassWithProtectedDefaultConstructor() - { - IsInitialized = true; - } - } - - internal class DerivedClassWithPrivateDefaultConstructor: BaseClassWithPublicDefaultConstructor - { - public bool IsInitialized = false; - - private DerivedClassWithPrivateDefaultConstructor() - { - IsInitialized = true; - } - } - - internal class DerivedClassWithNoDefaultConstructor: BaseClassWithPublicDefaultConstructor - { - public bool IsInitialized = false; - - private DerivedClassWithNoDefaultConstructor(string stringParam) - { - IsInitialized = true; - } - } -} diff --git a/src/Marten.Testing/performance_tuning.cs b/src/Marten.Testing/performance_tuning.cs index 1b01305ff0..d8071b8d12 100644 --- a/src/Marten.Testing/performance_tuning.cs +++ b/src/Marten.Testing/performance_tuning.cs @@ -6,6 +6,7 @@ using Jil; using Marten.Services; using Marten.Util; +using Weasel.Postgresql; namespace Marten.Testing { diff --git a/src/Marten/AdvancedOperations.cs b/src/Marten/AdvancedOperations.cs index 82a7ea3943..e9bc5af42c 100644 --- a/src/Marten/AdvancedOperations.cs +++ b/src/Marten/AdvancedOperations.cs @@ -11,7 +11,8 @@ using Marten.Internal.Sessions; using Marten.Linq.QueryHandlers; using Marten.Schema; -using Marten.Util; +using Weasel.Postgresql; + #nullable enable namespace Marten { @@ -33,9 +34,9 @@ internal AdvancedOperations(DocumentStore store) /// /// /// - public void ResetHiloSequenceFloor(long floor) + public Task ResetHiloSequenceFloor(long floor) { - _store.Tenancy.Default.ResetHiloSequenceFloor(floor); + return _store.Tenancy.Default.ResetHiloSequenceFloor(floor); } /// @@ -44,9 +45,9 @@ public void ResetHiloSequenceFloor(long floor) /// /// /// - public void ResetHiloSequenceFloor(string tenantId, long floor) + public Task ResetHiloSequenceFloor(string tenantId, long floor) { - _store.Tenancy[tenantId].ResetHiloSequenceFloor(floor); + return _store.Tenancy[tenantId].ResetHiloSequenceFloor(floor); } /// diff --git a/src/Marten/AutoCreate.cs b/src/Marten/AutoCreate.cs deleted file mode 100644 index 37f07c1315..0000000000 --- a/src/Marten/AutoCreate.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Marten -{ - public enum AutoCreate - { - /// - /// Will drop and recreate tables that do not match the Marten configuration or create new ones - /// - All, - - /// - /// Will never destroy existing tables. Attempts to add missing columns or missing tables - /// - CreateOrUpdate, - - /// - /// Will create missing schema objects at runtime, but will not update or remove existing schema objects - /// - CreateOnly, - - /// - /// Do not recreate, destroy, or update schema objects at runtime. Will throw exceptions if - /// the schema does not match the Marten configuration - /// - None - } -} diff --git a/src/Marten/CreationStyle.cs b/src/Marten/CreationStyle.cs deleted file mode 100644 index bc3e819ae2..0000000000 --- a/src/Marten/CreationStyle.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Marten -{ - public enum CreationStyle - { - /// - /// Export DDL by first issuing a DROP statement for a table, then the CREATE statement. This is the default - /// - DropThenCreate, - - /// - /// Export DDL for table creation by using a CREATE IF NOT EXISTS clause w/o a prior DROP statement - /// - CreateIfNotExists - } -} \ No newline at end of file diff --git a/src/Marten/DdlRules.cs b/src/Marten/DdlRules.cs deleted file mode 100644 index e9b510d339..0000000000 --- a/src/Marten/DdlRules.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.IO; -using Baseline; - -namespace Marten -{ - public class DdlRules - { - public static readonly string SCHEMA = "%SCHEMA%"; - public static readonly string TABLENAME = "%TABLENAME%"; - public static readonly string FUNCTION = "%FUNCTION%"; - public static readonly string SIGNATURE = "%SIGNATURE%"; - public static readonly string COLUMNS = "%COLUMNS%"; - public static readonly string NON_ID_COLUMNS = "%NON_ID_COLUMNS%"; - public static readonly string METADATA_COLUMNS = "%METADATA_COLUMNS%"; - - public readonly LightweightCache Templates - = new LightweightCache(name => new DdlTemplate(name)); - - /// - /// Alters the syntax used to create tables in DDL - /// - public CreationStyle TableCreation { get; set; } = CreationStyle.DropThenCreate; - - /// - /// Alters the user rights for the upsert functions in DDL - /// - public SecurityRights UpsertRights { get; set; } = SecurityRights.Invoker; - - /// - /// Option to use this database role during DDL scripts - /// - public string Role { get; set; } - - /// - /// Read [name].table and [name].function files from the named directory - /// to serve as templates for extra DDL (GRANT's probably) - /// - /// - public void ReadTemplates(string directory) - { - var system = new FileSystem(); - - system.FindFiles(directory, FileSet.Shallow("*.function")).Each(file => - { - var name = Path.GetFileNameWithoutExtension(file).ToLower(); - - Templates[name].FunctionCreation = system.ReadStringFromFile(file); - }); - - system.FindFiles(directory, FileSet.Shallow("*.table")).Each(file => - { - var name = Path.GetFileNameWithoutExtension(file).ToLower(); - - Templates[name].TableCreation = system.ReadStringFromFile(file); - }); - } - - /// - /// Read DDL templates from the application base directory - /// - public void ReadTemplates() - { - ReadTemplates(AppContext.BaseDirectory); - } - } - - public class DdlTemplate - { - private readonly string _name; - - public DdlTemplate(string name) - { - _name = name; - } - - public string TableCreation { get; set; } - public string FunctionCreation { get; set; } - } -} diff --git a/src/Marten/DocumentStore.cs b/src/Marten/DocumentStore.cs index 4d3aaf5f87..599b775ca6 100644 --- a/src/Marten/DocumentStore.cs +++ b/src/Marten/DocumentStore.cs @@ -49,7 +49,7 @@ public DocumentStore(StoreOptions options) databaseGenerator.CreateDatabases(Tenancy, options.CreateDatabases); } - Tenancy.Initialize(); + //Tenancy.Initialize(); Schema = Tenancy.Schema; diff --git a/src/Marten/Events/CodeGeneration/EventDocumentStorageGenerator.cs b/src/Marten/Events/CodeGeneration/EventDocumentStorageGenerator.cs index a53c013c81..3940338c0f 100644 --- a/src/Marten/Events/CodeGeneration/EventDocumentStorageGenerator.cs +++ b/src/Marten/Events/CodeGeneration/EventDocumentStorageGenerator.cs @@ -16,8 +16,8 @@ using Marten.Internal.CodeGeneration; using Marten.Storage; using Marten.Storage.Metadata; -using Marten.Util; using Npgsql; +using Weasel.Postgresql; namespace Marten.Events.CodeGeneration { diff --git a/src/Marten/Events/Daemon/EventTypeFilter.cs b/src/Marten/Events/Daemon/EventTypeFilter.cs index d76df8da2c..1d9db8740d 100644 --- a/src/Marten/Events/Daemon/EventTypeFilter.cs +++ b/src/Marten/Events/Daemon/EventTypeFilter.cs @@ -1,8 +1,8 @@ using System; using System.Linq; using Marten.Linq.SqlGeneration; -using Marten.Util; using NpgsqlTypes; +using Weasel.Postgresql; namespace Marten.Events.Daemon { diff --git a/src/Marten/Events/Daemon/HighWater/GapDetector.cs b/src/Marten/Events/Daemon/HighWater/GapDetector.cs index 2439e9748d..5be9cea3fc 100644 --- a/src/Marten/Events/Daemon/HighWater/GapDetector.cs +++ b/src/Marten/Events/Daemon/HighWater/GapDetector.cs @@ -2,8 +2,8 @@ using System.Threading; using System.Threading.Tasks; using Marten.Services; -using Marten.Util; using Npgsql; +using Weasel.Postgresql; namespace Marten.Events.Daemon.HighWater { diff --git a/src/Marten/Events/Daemon/HighWater/HighWaterDetector.cs b/src/Marten/Events/Daemon/HighWater/HighWaterDetector.cs index 16dc04bc96..c05988c418 100644 --- a/src/Marten/Events/Daemon/HighWater/HighWaterDetector.cs +++ b/src/Marten/Events/Daemon/HighWater/HighWaterDetector.cs @@ -2,8 +2,8 @@ using System.Threading; using System.Threading.Tasks; using Marten.Services; -using Marten.Util; using Npgsql; +using Weasel.Postgresql; namespace Marten.Events.Daemon.HighWater { diff --git a/src/Marten/Events/Daemon/HighWater/SafeSequenceFinder.cs b/src/Marten/Events/Daemon/HighWater/SafeSequenceFinder.cs index 390b2de96b..0840ccd660 100644 --- a/src/Marten/Events/Daemon/HighWater/SafeSequenceFinder.cs +++ b/src/Marten/Events/Daemon/HighWater/SafeSequenceFinder.cs @@ -3,8 +3,8 @@ using System.Threading; using System.Threading.Tasks; using Marten.Services; -using Marten.Util; using Npgsql; +using Weasel.Postgresql; namespace Marten.Events.Daemon.HighWater { diff --git a/src/Marten/Events/Daemon/HotColdCoordinator.cs b/src/Marten/Events/Daemon/HotColdCoordinator.cs index ec581bd5a9..b655ac1824 100644 --- a/src/Marten/Events/Daemon/HotColdCoordinator.cs +++ b/src/Marten/Events/Daemon/HotColdCoordinator.cs @@ -5,9 +5,9 @@ using System.Threading.Tasks; using System.Timers; using Baseline; +using Weasel.Postgresql; using Marten.Services; using Marten.Storage; -using Marten.Util; using Microsoft.Extensions.Logging; using Npgsql; using Timer = System.Timers.Timer; diff --git a/src/Marten/Events/Daemon/Progress/DeleteProjectionProgress.cs b/src/Marten/Events/Daemon/Progress/DeleteProjectionProgress.cs index a7fc08dcfa..33fb2e996a 100644 --- a/src/Marten/Events/Daemon/Progress/DeleteProjectionProgress.cs +++ b/src/Marten/Events/Daemon/Progress/DeleteProjectionProgress.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Marten.Internal; using Marten.Internal.Operations; +using Weasel.Postgresql; using Marten.Util; using NpgsqlTypes; @@ -20,7 +21,7 @@ public DeleteProjectionProgress(EventGraph events, string shardName) _events = events; _shardName = shardName; } - + public void ConfigureCommand(CommandBuilder builder, IMartenSession session) { var parameters = diff --git a/src/Marten/Events/Daemon/Progress/InsertProjectionProgress.cs b/src/Marten/Events/Daemon/Progress/InsertProjectionProgress.cs index bca980dfc7..ea08822bcd 100644 --- a/src/Marten/Events/Daemon/Progress/InsertProjectionProgress.cs +++ b/src/Marten/Events/Daemon/Progress/InsertProjectionProgress.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Marten.Internal; using Marten.Internal.Operations; +using Weasel.Postgresql; using Marten.Util; using NpgsqlTypes; diff --git a/src/Marten/Events/Daemon/Progress/ProjectionProgressStatement.cs b/src/Marten/Events/Daemon/Progress/ProjectionProgressStatement.cs index ac99702fc5..2550b97d96 100644 --- a/src/Marten/Events/Daemon/Progress/ProjectionProgressStatement.cs +++ b/src/Marten/Events/Daemon/Progress/ProjectionProgressStatement.cs @@ -1,5 +1,6 @@ using Baseline; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; using NpgsqlTypes; diff --git a/src/Marten/Events/Daemon/Progress/UpdateProjectionProgress.cs b/src/Marten/Events/Daemon/Progress/UpdateProjectionProgress.cs index 2b213acd2f..122492e0ae 100644 --- a/src/Marten/Events/Daemon/Progress/UpdateProjectionProgress.cs +++ b/src/Marten/Events/Daemon/Progress/UpdateProjectionProgress.cs @@ -6,6 +6,7 @@ using Marten.Exceptions; using Marten.Internal; using Marten.Internal.Operations; +using Weasel.Postgresql; using Marten.Util; using NpgsqlTypes; diff --git a/src/Marten/Events/Daemon/ProjectionUpdateBatch.cs b/src/Marten/Events/Daemon/ProjectionUpdateBatch.cs index 194f84cfd8..4b8fb4c5c2 100644 --- a/src/Marten/Events/Daemon/ProjectionUpdateBatch.cs +++ b/src/Marten/Events/Daemon/ProjectionUpdateBatch.cs @@ -7,6 +7,7 @@ using Marten.Internal; using Marten.Internal.Operations; using Marten.Internal.Sessions; +using Weasel.Postgresql; using Marten.Patching; using Marten.Services; using Marten.Util; diff --git a/src/Marten/Events/EventDocumentStorage.cs b/src/Marten/Events/EventDocumentStorage.cs index f287f460c6..7496b7d0ff 100644 --- a/src/Marten/Events/EventDocumentStorage.cs +++ b/src/Marten/Events/EventDocumentStorage.cs @@ -14,6 +14,7 @@ using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Schema; using Marten.Services; using Marten.Storage; @@ -64,6 +65,11 @@ public void TruncateDocumentStorage(ITenant tenant) tenant.RunSql($"truncate table {Events.DatabaseSchemaName}.mt_streams cascade"); } + public Task TruncateDocumentStorageAsync(ITenant tenant) + { + return tenant.RunSqlAsync($"truncate table {Events.DatabaseSchemaName}.mt_streams cascade"); + } + public EventGraph Events { get; } public TenancyStyle TenancyStyle { get; } diff --git a/src/Marten/Events/EventGraph.cs b/src/Marten/Events/EventGraph.cs index fbb8a047fb..dd2769fab5 100644 --- a/src/Marten/Events/EventGraph.cs +++ b/src/Marten/Events/EventGraph.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Baseline; +using Baseline.ImTools; using Marten.Events.Daemon; using Marten.Events.Operations; using Marten.Events.Projections; @@ -13,10 +14,11 @@ using Marten.Internal; using Marten.Internal.Operations; using Marten.Internal.Sessions; -using Marten.Schema; +using Weasel.Postgresql; using Marten.Schema.Identity; using Marten.Storage; using Marten.Util; +using Weasel.Postgresql.Functions; namespace Marten.Events { @@ -163,7 +165,7 @@ public void AddEventTypes(IEnumerable types) types.Each(AddEventType); } - public bool IsActive(StoreOptions options) => _events.Any() || Projections.Any() ; + internal bool IsActive(StoreOptions options) => _events.Any() || Projections.Any() ; /// /// Override the database schema name for event related tables. By default this @@ -223,7 +225,7 @@ ISchemaObject[] IFeatureSchema.Objects new EventProgressionTable(DatabaseSchemaName), sequence, new SystemFunction(DatabaseSchemaName, "mt_mark_event_progression", "varchar, bigint"), - new DropFunction(DatabaseSchemaName, "mt_append_event", appendEventFunctionArgs), + Function.ForRemoval(new DbObjectName(DatabaseSchemaName, "mt_append_event")) }; } } @@ -231,7 +233,7 @@ ISchemaObject[] IFeatureSchema.Objects Type IFeatureSchema.StorageType => typeof(EventGraph); string IFeatureSchema.Identifier { get; } = "eventstore"; - void IFeatureSchema.WritePermissions(DdlRules rules, StringWriter writer) + void IFeatureSchema.WritePermissions(DdlRules rules, TextWriter writer) { // Nothing } diff --git a/src/Marten/Events/EventMapping.cs b/src/Marten/Events/EventMapping.cs index 702af71dcc..ce7e70dc21 100644 --- a/src/Marten/Events/EventMapping.cs +++ b/src/Marten/Events/EventMapping.cs @@ -17,6 +17,7 @@ using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Schema; using Marten.Schema.Identity; using Marten.Services; @@ -123,7 +124,7 @@ public class EventMapping: EventMapping, IDocumentStorage where T : class public EventMapping(EventGraph parent) : base(parent, typeof(T)) { var schemaName = parent.DatabaseSchemaName; - _tableName = schemaName == StoreOptions.DefaultDatabaseSchemaName ? "mt_events" : $"{schemaName}.mt_events"; + _tableName = schemaName == DbObjectName.DefaultDatabaseSchemaName ? "mt_events" : $"{schemaName}.mt_events"; _idType = parent.StreamIdentity == StreamIdentity.AsGuid ? typeof(Guid) : typeof(string); } @@ -133,6 +134,11 @@ public void TruncateDocumentStorage(ITenant tenant) tenant.RunSql($"delete from table {_tableName} where type = '{Alias}'"); } + public Task TruncateDocumentStorageAsync(ITenant tenant) + { + return tenant.RunSqlAsync($"delete from table {_tableName} where type = '{Alias}'"); + } + public bool UseOptimisticConcurrency { get; } = false; public IOperationFragment DeleteFragment => throw new NotSupportedException(); public IOperationFragment HardDeleteFragment { get; } diff --git a/src/Marten/Events/EventQueryMapping.cs b/src/Marten/Events/EventQueryMapping.cs index 87d3fac7c3..cd104235f5 100644 --- a/src/Marten/Events/EventQueryMapping.cs +++ b/src/Marten/Events/EventQueryMapping.cs @@ -4,6 +4,7 @@ using Marten.Linq; using Marten.Linq.Fields; using Marten.Linq.Parsing; +using Weasel.Postgresql; using Marten.Schema; namespace Marten.Events diff --git a/src/Marten/Events/EventSequenceFetcher.cs b/src/Marten/Events/EventSequenceFetcher.cs index 42cee8ffe6..a1186b232e 100644 --- a/src/Marten/Events/EventSequenceFetcher.cs +++ b/src/Marten/Events/EventSequenceFetcher.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Marten.Internal; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Events diff --git a/src/Marten/Events/EventStatement.cs b/src/Marten/Events/EventStatement.cs index fbd9a79fdb..0d84dbf982 100644 --- a/src/Marten/Events/EventStatement.cs +++ b/src/Marten/Events/EventStatement.cs @@ -5,6 +5,7 @@ using Marten.Events.Daemon; using Marten.Linq.Filters; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Storage; using Marten.Util; diff --git a/src/Marten/Events/EventStore.cs b/src/Marten/Events/EventStore.cs index 89a19943ab..692b632de8 100644 --- a/src/Marten/Events/EventStore.cs +++ b/src/Marten/Events/EventStore.cs @@ -11,6 +11,7 @@ using Marten.Internal.Storage; using Marten.Linq; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Marten.Schema.Identity; using Marten.Storage; using Marten.Util; diff --git a/src/Marten/Events/Operations/AppendEventOperationBase.cs b/src/Marten/Events/Operations/AppendEventOperationBase.cs index 0c4c1bb31d..796d17b545 100644 --- a/src/Marten/Events/Operations/AppendEventOperationBase.cs +++ b/src/Marten/Events/Operations/AppendEventOperationBase.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Marten.Internal; using Marten.Internal.Operations; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Events.Operations diff --git a/src/Marten/Events/Operations/EstablishTombstoneStream.cs b/src/Marten/Events/Operations/EstablishTombstoneStream.cs index eae4ff526c..b344f99d62 100644 --- a/src/Marten/Events/Operations/EstablishTombstoneStream.cs +++ b/src/Marten/Events/Operations/EstablishTombstoneStream.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Marten.Internal; using Marten.Internal.Operations; +using Weasel.Postgresql; using Marten.Schema; using Marten.Storage; using Marten.Util; diff --git a/src/Marten/Events/Operations/EventProgressWrite.cs b/src/Marten/Events/Operations/EventProgressWrite.cs index 658be48a2c..bb5b38ad9a 100644 --- a/src/Marten/Events/Operations/EventProgressWrite.cs +++ b/src/Marten/Events/Operations/EventProgressWrite.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Marten.Internal; using Marten.Internal.Operations; +using Weasel.Postgresql; using Marten.Schema; using Marten.Util; using NpgsqlTypes; diff --git a/src/Marten/Events/Operations/InsertStreamBase.cs b/src/Marten/Events/Operations/InsertStreamBase.cs index 334bd294a0..9585263c78 100644 --- a/src/Marten/Events/Operations/InsertStreamBase.cs +++ b/src/Marten/Events/Operations/InsertStreamBase.cs @@ -3,9 +3,11 @@ using System.Data.Common; using System.Threading; using System.Threading.Tasks; +using Baseline.Exceptions; using Marten.Exceptions; using Marten.Internal; using Marten.Internal.Operations; +using Weasel.Postgresql; using Marten.Services; using Marten.Util; diff --git a/src/Marten/Events/Operations/UpdateStreamOperations.cs b/src/Marten/Events/Operations/UpdateStreamOperations.cs index e0a455d89c..74ce115569 100644 --- a/src/Marten/Events/Operations/UpdateStreamOperations.cs +++ b/src/Marten/Events/Operations/UpdateStreamOperations.cs @@ -6,6 +6,7 @@ using Marten.Exceptions; using Marten.Internal; using Marten.Internal.Operations; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Events.Operations diff --git a/src/Marten/Events/Projections/ProjectionCollection.cs b/src/Marten/Events/Projections/ProjectionCollection.cs index 8a37618350..9616c7feb3 100644 --- a/src/Marten/Events/Projections/ProjectionCollection.cs +++ b/src/Marten/Events/Projections/ProjectionCollection.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using Baseline; -using ImTools; +using Baseline.ImTools; using Marten.Events.Aggregation; using Marten.Events.Daemon; using Marten.Exceptions; diff --git a/src/Marten/Events/Querying/SingleEventQueryHandler.cs b/src/Marten/Events/Querying/SingleEventQueryHandler.cs index 0b6493d940..8184bedd3f 100644 --- a/src/Marten/Events/Querying/SingleEventQueryHandler.cs +++ b/src/Marten/Events/Querying/SingleEventQueryHandler.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Marten.Internal; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Events.Querying diff --git a/src/Marten/Events/Querying/StreamStateSelector.cs b/src/Marten/Events/Querying/StreamStateSelector.cs index 9a4d28d8e7..677051d5ba 100644 --- a/src/Marten/Events/Querying/StreamStateSelector.cs +++ b/src/Marten/Events/Querying/StreamStateSelector.cs @@ -4,6 +4,7 @@ using Baseline; using Marten.Internal; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Events.Querying diff --git a/src/Marten/Events/Schema/EventJsonDataColumn.cs b/src/Marten/Events/Schema/EventJsonDataColumn.cs index c647baf875..a92ba6fcc8 100644 --- a/src/Marten/Events/Schema/EventJsonDataColumn.cs +++ b/src/Marten/Events/Schema/EventJsonDataColumn.cs @@ -4,13 +4,15 @@ using Marten.Internal; using Marten.Storage; using NpgsqlTypes; +using Weasel.Postgresql.Tables; namespace Marten.Events.Schema { internal class EventJsonDataColumn: TableColumn, IEventTableColumn { - public EventJsonDataColumn() : base("data", "jsonb", "NOT NULL") + public EventJsonDataColumn() : base("data", "jsonb") { + AllowNulls = false; } public void GenerateSelectorCodeSync(GeneratedMethod method, EventGraph graph, int index) @@ -29,4 +31,4 @@ public void GenerateAppendCode(GeneratedMethod method, EventGraph graph, int ind method.Frames.Code($"parameters[{index}].Value = {{0}}.Serializer.ToJson({{1}}.{nameof(IEvent.Data)});", Use.Type(), Use.Type()); } } -} \ No newline at end of file +} diff --git a/src/Marten/Events/Schema/EventProgressionTable.cs b/src/Marten/Events/Schema/EventProgressionTable.cs index f18912be17..aed8425201 100644 --- a/src/Marten/Events/Schema/EventProgressionTable.cs +++ b/src/Marten/Events/Schema/EventProgressionTable.cs @@ -1,5 +1,7 @@ +using Weasel.Postgresql; using Marten.Schema; using Marten.Storage; +using Weasel.Postgresql.Tables; namespace Marten.Events.Schema { @@ -7,10 +9,12 @@ internal class EventProgressionTable: Table { public EventProgressionTable(string schemaName) : base(new DbObjectName(schemaName, "mt_event_progression")) { - AddPrimaryKey(new TableColumn("name", "varchar")); - AddColumn("last_seq_id", "bigint", "NULL"); - AddColumn("last_updated", "timestamp with time zone", "DEFAULT transaction_timestamp()") - .CanAdd = true; + AddColumn("name").AsPrimaryKey(); + AddColumn("last_seq_id", "bigint").AllowNulls(); + AddColumn("last_updated", "timestamp with time zone") + .DefaultValueByExpression("(transaction_timestamp())"); + + PrimaryKeyName = "pk_mt_event_progression"; } } } diff --git a/src/Marten/Events/Schema/EventTableColumn.cs b/src/Marten/Events/Schema/EventTableColumn.cs index 0973943014..7a029cf10e 100644 --- a/src/Marten/Events/Schema/EventTableColumn.cs +++ b/src/Marten/Events/Schema/EventTableColumn.cs @@ -10,6 +10,8 @@ using Marten.Util; using Npgsql; using NpgsqlTypes; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; namespace Marten.Events.Schema { @@ -53,4 +55,4 @@ public void GenerateAppendCode(GeneratedMethod method, EventGraph graph, int ind $"parameters[{index}].{nameof(NpgsqlParameter.Value)} = {{0}}.{_member.Name};", Use.Type()); } } -} \ No newline at end of file +} diff --git a/src/Marten/Events/Schema/EventTypeColumn.cs b/src/Marten/Events/Schema/EventTypeColumn.cs index 2e3f4eeff5..6c774b3e1a 100644 --- a/src/Marten/Events/Schema/EventTypeColumn.cs +++ b/src/Marten/Events/Schema/EventTypeColumn.cs @@ -2,13 +2,15 @@ using LamarCodeGeneration; using Marten.Internal.CodeGeneration; using Marten.Storage; +using Weasel.Postgresql.Tables; namespace Marten.Events.Schema { internal class EventTypeColumn: TableColumn, IEventTableColumn { - public EventTypeColumn() : base("type", "varchar(500)", "NOT NULL") + public EventTypeColumn() : base("type", "varchar(500)") { + AllowNulls = false; } public void GenerateSelectorCodeSync(GeneratedMethod method, EventGraph graph, int index) @@ -26,4 +28,4 @@ public void GenerateAppendCode(GeneratedMethod method, EventGraph graph, int ind method.SetParameterFromMember(index, x => x.EventTypeName); } } -} \ No newline at end of file +} diff --git a/src/Marten/Events/Schema/EventsTable.cs b/src/Marten/Events/Schema/EventsTable.cs index ddd238b65e..9daacaa23d 100644 --- a/src/Marten/Events/Schema/EventsTable.cs +++ b/src/Marten/Events/Schema/EventsTable.cs @@ -1,8 +1,11 @@ using System.Collections.Generic; using System.Linq; +using Weasel.Postgresql; using Marten.Schema; using Marten.Storage; using Marten.Storage.Metadata; +using Weasel.Postgresql.Tables; +using IndexDefinition = Weasel.Postgresql.Tables.IndexDefinition; namespace Marten.Events.Schema { @@ -11,19 +14,19 @@ internal class EventsTable: Table { public EventsTable(EventGraph events): base(new DbObjectName(events.DatabaseSchemaName, "mt_events")) { - AddPrimaryKey(new EventTableColumn("seq_id", x => x.Sequence)); - AddColumn(new EventTableColumn("id", x => x.Id) {Directive = "NOT NULL"}); + AddColumn(new EventTableColumn("seq_id", x => x.Sequence)).AsPrimaryKey(); + AddColumn(new EventTableColumn("id", x => x.Id)).NotNull(); AddColumn(new StreamIdColumn(events)); - AddColumn(new EventTableColumn("version", x => x.Version) {Directive = "NOT NULL"}); + + AddColumn(new EventTableColumn("version", x => x.Version)).NotNull(); AddColumn(); AddColumn(); - AddColumn(new EventTableColumn("timestamp", x => x.Timestamp) - { - Directive = "default (now()) NOT NULL", Type = "timestamptz" - }); + AddColumn(new EventTableColumn("timestamp", x => x.Timestamp)) + .NotNull().DefaultValueByString("(now())"); AddColumn(); - AddColumn(new DotNetTypeColumn {Directive = "NULL"}); + + AddColumn().AllowNulls(); AddIfActive(events.Metadata.CorrelationId); AddIfActive(events.Metadata.CausationId); @@ -31,17 +34,41 @@ public EventsTable(EventGraph events): base(new DbObjectName(events.DatabaseSche if (events.TenancyStyle == TenancyStyle.Conjoined) { - Constraints.Add( - $"FOREIGN KEY(stream_id, {TenantIdColumn.Name}) REFERENCES {events.DatabaseSchemaName}.mt_streams(id, {TenantIdColumn.Name})"); - Constraints.Add( - $"CONSTRAINT pk_mt_events_stream_and_version UNIQUE(stream_id, {TenantIdColumn.Name}, version)"); + ForeignKeys.Add(new ForeignKey("fkey_mt_events_stream_id_tenant_id") + { + ColumnNames = new string[]{"stream_id", TenantIdColumn.Name}, + LinkedNames = new string[]{"id", TenantIdColumn.Name}, + LinkedTable = new DbObjectName(events.DatabaseSchemaName, "mt_streams") + }); + + Indexes.Add(new IndexDefinition("pk_mt_events_stream_and_version") + { + IsUnique = true, + Columns = new string[]{"stream_id", TenantIdColumn.Name, "version"} + }); } else { - Constraints.Add("CONSTRAINT pk_mt_events_stream_and_version UNIQUE(stream_id, version)"); + ForeignKeys.Add(new ForeignKey("fkey_mt_events_stream_id") + { + ColumnNames = new string[]{"stream_id"}, + LinkedNames = new string[]{"id"}, + LinkedTable = new DbObjectName(events.DatabaseSchemaName, "mt_streams"), + OnDelete = CascadeAction.Cascade + }); + + Indexes.Add(new IndexDefinition("pk_mt_events_stream_and_version") + { + IsUnique = true, + Columns = new string[]{"stream_id", "version"} + }); } - Constraints.Add("CONSTRAINT pk_mt_events_id_unique UNIQUE(id)"); + Indexes.Add(new IndexDefinition("pk_mt_events_id_unique") + { + Columns = new string[]{"id"}, + IsUnique = true + }); } internal IList SelectColumns() diff --git a/src/Marten/Events/Schema/StreamIdColumn.cs b/src/Marten/Events/Schema/StreamIdColumn.cs index 780c193660..d528d0c632 100644 --- a/src/Marten/Events/Schema/StreamIdColumn.cs +++ b/src/Marten/Events/Schema/StreamIdColumn.cs @@ -1,6 +1,7 @@ using LamarCodeGeneration; using Marten.Internal.CodeGeneration; using Marten.Storage; +using Weasel.Postgresql.Tables; namespace Marten.Events.Schema { @@ -9,10 +10,6 @@ internal class StreamIdColumn: TableColumn, IEventTableColumn public StreamIdColumn(EventGraph graph) : base("stream_id", "varchar") { Type = graph.GetStreamIdDBType(); - Directive = graph.TenancyStyle != TenancyStyle.Conjoined - ? $"REFERENCES {graph.DatabaseSchemaName}.mt_streams ON DELETE CASCADE" - : null; - } public void GenerateSelectorCodeSync(GeneratedMethod method, EventGraph graph, int index) @@ -51,4 +48,4 @@ public void GenerateAppendCode(GeneratedMethod method, EventGraph graph, int ind } } } -} \ No newline at end of file +} diff --git a/src/Marten/Events/Schema/StreamsTable.cs b/src/Marten/Events/Schema/StreamsTable.cs index 1a83aa18bb..5418f3c41e 100644 --- a/src/Marten/Events/Schema/StreamsTable.cs +++ b/src/Marten/Events/Schema/StreamsTable.cs @@ -6,11 +6,13 @@ using LamarCodeGeneration; using Marten.Internal.CodeGeneration; using Marten.Linq.Parsing; +using Weasel.Postgresql; using Marten.Schema; using Marten.Storage; using Marten.Storage.Metadata; using Marten.Util; using NpgsqlTypes; +using Weasel.Postgresql.Tables; namespace Marten.Events.Schema { @@ -22,28 +24,23 @@ public StreamsTable(EventGraph events) : base(new DbObjectName(events.DatabaseSc ? new StreamTableColumn("id", x => x.Id) : new StreamTableColumn("id", x => x.Key); + AddColumn(idColumn).AsPrimaryKey(); + if (events.TenancyStyle == TenancyStyle.Conjoined) { - AddPrimaryKeys(new List - { - idColumn, - new TenantIdColumn() - }); - } - else - { - AddPrimaryKey(idColumn); + AddColumn().AsPrimaryKey(); } - AddColumn(new StreamTableColumn("type", x => x.AggregateTypeName) {Directive = "NULL"}); + AddColumn(new StreamTableColumn("type", x => x.AggregateTypeName)).AllowNulls(); - AddColumn(new StreamTableColumn("version", x => x.Version) {Directive = "NOT NULL"}); + AddColumn(new StreamTableColumn("version", x => x.Version)).AllowNulls(); AddColumn(new StreamTableColumn("timestamp", x => x.Timestamp) { Type = "timestamptz", - Directive = "default (now()) NOT NULL", - Writes = false + Writes = false, + AllowNulls = false, + DefaultExpression = "(now())" }); @@ -52,8 +49,8 @@ public StreamsTable(EventGraph events) : base(new DbObjectName(events.DatabaseSc AddColumn(new StreamTableColumn("created", x => x.Created) { - Directive = "default (now()) NOT NULL", Writes = false, Type = "timestamptz" - }); + Writes = false, Type = "timestamptz" + }).NotNull().DefaultValueByString("(now())"); if (events.TenancyStyle != TenancyStyle.Conjoined) { diff --git a/src/Marten/Events/TestSupport/ProjectionScenario.cs b/src/Marten/Events/TestSupport/ProjectionScenario.cs index d0d3de00e5..012c1ef9e3 100644 --- a/src/Marten/Events/TestSupport/ProjectionScenario.cs +++ b/src/Marten/Events/TestSupport/ProjectionScenario.cs @@ -67,7 +67,7 @@ internal async Task Execute() _store.Advanced.Clean.DeleteAllEventData(); foreach (var storageType in _store.Events.Projections.Projections.SelectMany(x => x.Options.StorageTypes)) - _store.Advanced.Clean.DeleteDocumentsFor(storageType); + await _store.Advanced.Clean.DeleteDocumentsByTypeAsync(storageType); } if (_store.Events.Projections.HasAnyAsyncProjections()) diff --git a/src/Marten/Exceptions/MartenCommandException.cs b/src/Marten/Exceptions/MartenCommandException.cs index c1be3aca49..6261c0abeb 100644 --- a/src/Marten/Exceptions/MartenCommandException.cs +++ b/src/Marten/Exceptions/MartenCommandException.cs @@ -38,7 +38,7 @@ protected static string ToMessage(NpgsqlCommand command, } - return $"Marten Command Failure:${Environment.NewLine}{prefix}{explanation}{command.CommandText}${Environment.NewLine}${Environment.NewLine}"; + return $"Marten Command Failure:${Environment.NewLine}{prefix}{explanation}{command?.CommandText}${Environment.NewLine}${Environment.NewLine}"; } /// diff --git a/src/Marten/Exceptions/MartenCommandExceptionFactory.cs b/src/Marten/Exceptions/MartenCommandExceptionFactory.cs index 5a1418e87c..b32d3f1f41 100644 --- a/src/Marten/Exceptions/MartenCommandExceptionFactory.cs +++ b/src/Marten/Exceptions/MartenCommandExceptionFactory.cs @@ -9,6 +9,7 @@ namespace Marten.Exceptions /// internal static class MartenCommandExceptionFactory { + [Obsolete("Replace with MartenExceptionTransformer")] internal static MartenCommandException Create ( NpgsqlCommand command, @@ -25,6 +26,9 @@ Exception innerException return new MartenCommandException(command, innerException); } + + + [Obsolete("Replace with MartenExceptionTransformer")] internal static bool TryToMapToMartenCommandNotSupportedException ( NpgsqlCommand command, diff --git a/src/Marten/Exceptions/MartenCommandNotSupportedException.cs b/src/Marten/Exceptions/MartenCommandNotSupportedException.cs index 9ccd6f9c0d..416b307614 100644 --- a/src/Marten/Exceptions/MartenCommandNotSupportedException.cs +++ b/src/Marten/Exceptions/MartenCommandNotSupportedException.cs @@ -1,5 +1,7 @@ using System; +using System.Linq; using System.Text.RegularExpressions; +using Baseline.Exceptions; using Npgsql; namespace Marten.Exceptions @@ -51,6 +53,28 @@ public MartenCommandNotSupportedException( } + internal class MartenCommandNotSupportedExceptionTransform: IExceptionTransform + { + public bool TryTransform(Exception original, out Exception transformed) + { + if (original is NpgsqlException e) + { + var knownCause = KnownNotSupportedExceptionCause.KnownCauses.FirstOrDefault(x => x.Matches(e)); + if (knownCause != null) + { + var command = e.ReadNpgsqlCommand(); + + transformed = new MartenCommandNotSupportedException(knownCause.Reason, command, e, knownCause.Description); + + return true; + } + } + + transformed = null; + return false; + } + } + internal sealed class KnownNotSupportedExceptionCause { private readonly Func match; diff --git a/src/Marten/Exceptions/MartenExceptionTransformer.cs b/src/Marten/Exceptions/MartenExceptionTransformer.cs new file mode 100644 index 0000000000..2febe8631c --- /dev/null +++ b/src/Marten/Exceptions/MartenExceptionTransformer.cs @@ -0,0 +1,51 @@ +using System; +using Baseline.Exceptions; +using Marten.Services; +using Npgsql; + +namespace Marten.Exceptions +{ + internal static class MartenExceptionTransformer + { + private static readonly ExceptionTransforms _transforms = new ExceptionTransforms(); + + internal static NpgsqlCommand ReadNpgsqlCommand(this Exception ex) + { + return ex.Data.Contains(nameof(NpgsqlCommand)) + ? (NpgsqlCommand) ex.Data[nameof(NpgsqlCommand)] + : null; + } + + static MartenExceptionTransformer() + { + _transforms.AddTransform(); + _transforms.AddTransform(); + + _transforms.IfExceptionIs() + .If(e => e.SqlState == PostgresErrorCodes.SerializationFailure) + .ThenTransformTo(e => throw new ConcurrentUpdateException(e)); + + _transforms.IfExceptionIs() + .TransformTo(e => + { + var command = e.ReadNpgsqlCommand(); + return new MartenCommandException(command, e); + }); + } + + internal static void WrapAndThrow(NpgsqlCommand command, Exception exception) + { + if (command != null) + { + exception.Data[nameof(NpgsqlCommand)] = command; + } + + _transforms.TransformAndThrow(exception); + } + + internal static void WrapAndThrow(Exception exception) + { + _transforms.TransformAndThrow(exception); + } + } +} diff --git a/src/Marten/FullTextIndexAttribute.cs b/src/Marten/FullTextIndexAttribute.cs index 9316345eb8..b55e278ae8 100644 --- a/src/Marten/FullTextIndexAttribute.cs +++ b/src/Marten/FullTextIndexAttribute.cs @@ -9,12 +9,13 @@ public class FullTextIndexAttribute: MartenAttribute { public override void Modify(DocumentMapping mapping) { - mapping.AddFullTextIndex(regConfig: RegConfig, (index) => { index.IndexName = IndexName; }); + mapping.AddFullTextIndex(regConfig: RegConfig, (index) => { index.Name = IndexName; }); } public override void Modify(DocumentMapping mapping, MemberInfo member) { - var membersGroupedByIndexName = member.DeclaringType.GetMembers() + var membersGroupedByIndexName = member.DeclaringType + .GetMembers() .Where(mi => mi.GetCustomAttributes().Any()) .Select(mi => new { @@ -22,8 +23,7 @@ public override void Modify(DocumentMapping mapping, MemberInfo member) IndexInformation = mi.GetCustomAttributes().First() }) .GroupBy(m => m.IndexInformation.IndexName ?? m.IndexInformation.RegConfig ?? m.Member.Name) - .Where(mg => mg.Any(m => m.Member == member)) - .Single(); + .Single(mg => mg.Any(m => m.Member == member)); mapping.AddFullTextIndex( membersGroupedByIndexName.Select(mg => new[] { mg.Member }).ToArray(), diff --git a/src/Marten/IReadOnlyStoreOptions.cs b/src/Marten/IReadOnlyStoreOptions.cs index 37439f2271..dbd8d5ea82 100644 --- a/src/Marten/IReadOnlyStoreOptions.cs +++ b/src/Marten/IReadOnlyStoreOptions.cs @@ -4,6 +4,8 @@ using Marten.Schema; using Marten.Storage; using Marten.Transforms; +using Weasel.Postgresql; + #nullable enable namespace Marten { diff --git a/src/Marten/ISerializer.cs b/src/Marten/ISerializer.cs index f9682889bc..17517f6d71 100644 --- a/src/Marten/ISerializer.cs +++ b/src/Marten/ISerializer.cs @@ -3,6 +3,8 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using Weasel.Postgresql; + #nullable enable namespace Marten { @@ -106,7 +108,7 @@ public interface ISerializer /// /// string ToJsonWithTypes(object document); - + /// /// Controls how the Linq Select() behavior needs to work in the database /// @@ -115,23 +117,6 @@ public interface ISerializer #endregion sample_ISerializer - /// - /// Governs how .Net Enum types are persisted - /// in the serialized JSON - /// - public enum EnumStorage - { - /// - /// Serialize Enum values as their integer value - /// - AsInteger, - - /// - /// Serialize Enum values as their string value - /// - AsString - } - /// /// Governs the JSON serialization behavior of how .Net /// member names are persisted in the JSON stored in diff --git a/src/Marten/Internal/CodeGeneration/BulkLoaderBuilder.cs b/src/Marten/Internal/CodeGeneration/BulkLoaderBuilder.cs index 12081c612e..d5fcaf0b01 100644 --- a/src/Marten/Internal/CodeGeneration/BulkLoaderBuilder.cs +++ b/src/Marten/Internal/CodeGeneration/BulkLoaderBuilder.cs @@ -85,8 +85,8 @@ public string CopyNewDocumentsFromTempTable() var table = _mapping.Schema.Table; var storageTable = table.Identifier.QualifiedName; - var columns = table.Where(x => x.Name != SchemaConstants.LastModifiedColumn).Select(x => $"\\\"{x.Name}\\\"").Join(", "); - var selectColumns = table.Where(x => x.Name != SchemaConstants.LastModifiedColumn).Select(x => $"{_tempTable}.\\\"{x.Name}\\\"").Join(", "); + var columns = table.Columns.Where(x => x.Name != SchemaConstants.LastModifiedColumn).Select(x => $"\\\"{x.Name}\\\"").Join(", "); + var selectColumns = table.Columns.Where(x => x.Name != SchemaConstants.LastModifiedColumn).Select(x => $"{_tempTable}.\\\"{x.Name}\\\"").Join(", "); return $"insert into {storageTable} ({columns}, {SchemaConstants.LastModifiedColumn}) (select {selectColumns}, transaction_timestamp() from {_tempTable} left join {storageTable} on {_tempTable}.id = {storageTable}.id where {storageTable}.id is null)"; } @@ -96,7 +96,7 @@ public string OverwriteDuplicatesFromTempTable() var table = _mapping.Schema.Table; var storageTable = table.Identifier.QualifiedName; - var updates = table.Where(x => x.Name != "id" && x.Name != SchemaConstants.LastModifiedColumn) + var updates = table.Columns.Where(x => x.Name != "id" && x.Name != SchemaConstants.LastModifiedColumn) .Select(x => $"{x.Name} = source.{x.Name}").Join(", "); return $@"update {storageTable} target SET {updates}, {SchemaConstants.LastModifiedColumn} = transaction_timestamp() FROM {_tempTable} source WHERE source.id = target.id"; diff --git a/src/Marten/Internal/CodeGeneration/DocumentFunctionOperationBuilder.cs b/src/Marten/Internal/CodeGeneration/DocumentFunctionOperationBuilder.cs index a20289fbb0..2d1a5448c9 100644 --- a/src/Marten/Internal/CodeGeneration/DocumentFunctionOperationBuilder.cs +++ b/src/Marten/Internal/CodeGeneration/DocumentFunctionOperationBuilder.cs @@ -11,7 +11,8 @@ using Marten.Internal.Operations; using Marten.Schema; using Marten.Storage; -using TypeMappings = Marten.Util.TypeMappings; +using Marten.Util; +using Weasel.Postgresql; namespace Marten.Internal.CodeGeneration { diff --git a/src/Marten/Internal/CodeGeneration/DocumentPersistenceBuilder.cs b/src/Marten/Internal/CodeGeneration/DocumentPersistenceBuilder.cs index df03e2fd16..abad436f6c 100644 --- a/src/Marten/Internal/CodeGeneration/DocumentPersistenceBuilder.cs +++ b/src/Marten/Internal/CodeGeneration/DocumentPersistenceBuilder.cs @@ -3,11 +3,13 @@ using LamarCodeGeneration; using LamarCompiler; using Marten.Internal.Storage; +using Weasel.Postgresql; using Marten.Schema; using Marten.Schema.Arguments; using Marten.Schema.BulkLoading; using Marten.Util; using Npgsql; +using CommandExtensions = Weasel.Postgresql.CommandExtensions; namespace Marten.Internal.CodeGeneration { diff --git a/src/Marten/Internal/CodeGeneration/FrameCollectionExtensions.cs b/src/Marten/Internal/CodeGeneration/FrameCollectionExtensions.cs index 1b02abcfff..54014b3491 100644 --- a/src/Marten/Internal/CodeGeneration/FrameCollectionExtensions.cs +++ b/src/Marten/Internal/CodeGeneration/FrameCollectionExtensions.cs @@ -4,12 +4,14 @@ using System.Reflection; using System.Threading; using Baseline; +using Baseline.Expressions; using LamarCodeGeneration; using LamarCodeGeneration.Frames; using LamarCodeGeneration.Model; -using Marten.Linq.Parsing; using Marten.Schema; using Marten.Util; +using Weasel.Postgresql; +using FindMembers = Marten.Linq.Parsing.FindMembers; namespace Marten.Internal.CodeGeneration { diff --git a/src/Marten/Internal/CompiledQueries/ClonedCompiledQuery.cs b/src/Marten/Internal/CompiledQueries/ClonedCompiledQuery.cs index aa11779917..b7e3875da6 100644 --- a/src/Marten/Internal/CompiledQueries/ClonedCompiledQuery.cs +++ b/src/Marten/Internal/CompiledQueries/ClonedCompiledQuery.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Marten.Linq; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Internal.CompiledQueries diff --git a/src/Marten/Internal/CompiledQueries/CompiledQuerySourceBuilder.cs b/src/Marten/Internal/CompiledQueries/CompiledQuerySourceBuilder.cs index 8c988fef7a..d7d7e10540 100644 --- a/src/Marten/Internal/CompiledQueries/CompiledQuerySourceBuilder.cs +++ b/src/Marten/Internal/CompiledQueries/CompiledQuerySourceBuilder.cs @@ -11,6 +11,7 @@ using Marten.Internal.Storage; using Marten.Linq.Includes; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Marten.Schema.Arguments; using Marten.Util; diff --git a/src/Marten/Internal/CompiledQueries/ComplexCompiledQuery.cs b/src/Marten/Internal/CompiledQueries/ComplexCompiledQuery.cs index f18c8eae3a..77a42b7dcc 100644 --- a/src/Marten/Internal/CompiledQueries/ComplexCompiledQuery.cs +++ b/src/Marten/Internal/CompiledQueries/ComplexCompiledQuery.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Internal.CompiledQueries diff --git a/src/Marten/Internal/CompiledQueries/QueryMember.cs b/src/Marten/Internal/CompiledQueries/QueryMember.cs index fa35ac48f1..b4dfc728e5 100644 --- a/src/Marten/Internal/CompiledQueries/QueryMember.cs +++ b/src/Marten/Internal/CompiledQueries/QueryMember.cs @@ -6,6 +6,7 @@ using Marten.Util; using Npgsql; using NpgsqlTypes; +using Weasel.Postgresql; namespace Marten.Internal.CompiledQueries { diff --git a/src/Marten/Internal/CompiledQueries/StatelessCompiledQuery.cs b/src/Marten/Internal/CompiledQueries/StatelessCompiledQuery.cs index bee089dd38..eacbdda83a 100644 --- a/src/Marten/Internal/CompiledQueries/StatelessCompiledQuery.cs +++ b/src/Marten/Internal/CompiledQueries/StatelessCompiledQuery.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Internal.CompiledQueries diff --git a/src/Marten/Internal/Operations/StorageOperation.cs b/src/Marten/Internal/Operations/StorageOperation.cs index 2aab1db9c1..0fa46b86c9 100644 --- a/src/Marten/Internal/Operations/StorageOperation.cs +++ b/src/Marten/Internal/Operations/StorageOperation.cs @@ -3,8 +3,10 @@ using System.Data.Common; using System.Threading; using System.Threading.Tasks; +using Baseline.Exceptions; using Marten.Exceptions; using Marten.Internal.DirtyTracking; +using Weasel.Postgresql; using Marten.Schema; using Marten.Schema.Identity; using Marten.Services; diff --git a/src/Marten/Internal/Operations/TruncateTable.cs b/src/Marten/Internal/Operations/TruncateTable.cs index 4371935071..f25e8fdd02 100644 --- a/src/Marten/Internal/Operations/TruncateTable.cs +++ b/src/Marten/Internal/Operations/TruncateTable.cs @@ -3,6 +3,7 @@ using System.Data.Common; using System.Threading; using System.Threading.Tasks; +using Weasel.Postgresql; using Marten.Schema; using Marten.Util; diff --git a/src/Marten/Internal/ProviderGraph.cs b/src/Marten/Internal/ProviderGraph.cs index 35511b1292..d8e08dee8d 100644 --- a/src/Marten/Internal/ProviderGraph.cs +++ b/src/Marten/Internal/ProviderGraph.cs @@ -1,5 +1,6 @@ using System; using Baseline; +using Baseline.ImTools; using LamarCodeGeneration; using Marten.Events; using Marten.Events.CodeGeneration; diff --git a/src/Marten/Internal/Storage/DocumentStorage.cs b/src/Marten/Internal/Storage/DocumentStorage.cs index 976649392b..54764df07f 100644 --- a/src/Marten/Internal/Storage/DocumentStorage.cs +++ b/src/Marten/Internal/Storage/DocumentStorage.cs @@ -14,6 +14,7 @@ using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Schema; using Marten.Services; using Marten.Storage; @@ -87,6 +88,12 @@ public void TruncateDocumentStorage(ITenant tenant) tenant.RunSql(sql); } + public Task TruncateDocumentStorageAsync(ITenant tenant) + { + var sql = "truncate {0} cascade".ToFormat(TableName.QualifiedName); + return tenant.RunSqlAsync(sql); + } + public void SetIdentity(T document, TId identity) { _setter(document, identity); diff --git a/src/Marten/Internal/Storage/IDocumentStorage.cs b/src/Marten/Internal/Storage/IDocumentStorage.cs index 1d31bcc81c..7f2619ac54 100644 --- a/src/Marten/Internal/Storage/IDocumentStorage.cs +++ b/src/Marten/Internal/Storage/IDocumentStorage.cs @@ -5,7 +5,7 @@ using Marten.Internal.Operations; using Marten.Linq.Fields; using Marten.Linq.SqlGeneration; -using Marten.Schema; +using Weasel.Postgresql; using Marten.Services; using Marten.Storage; using Npgsql; @@ -15,6 +15,7 @@ namespace Marten.Internal.Storage { public interface IDocumentStorage : ISelectClause { + Task TruncateDocumentStorageAsync(ITenant tenant); void TruncateDocumentStorage(ITenant tenant); Type SourceType { get; } @@ -35,6 +36,7 @@ public interface IDocumentStorage : ISelectClause Type DocumentType { get; } TenancyStyle TenancyStyle { get; } + } public interface IDocumentStorage : IDocumentStorage where T : notnull diff --git a/src/Marten/Internal/Storage/SubClassDocumentStorage.cs b/src/Marten/Internal/Storage/SubClassDocumentStorage.cs index d9e33d246f..0e781e8aeb 100644 --- a/src/Marten/Internal/Storage/SubClassDocumentStorage.cs +++ b/src/Marten/Internal/Storage/SubClassDocumentStorage.cs @@ -12,6 +12,7 @@ using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Schema; using Marten.Services; using Marten.Storage; @@ -46,6 +47,12 @@ public void TruncateDocumentStorage(ITenant tenant) $"delete from {_parent.TableName.QualifiedName} where {SchemaConstants.DocumentTypeColumn} = '{_mapping.Alias}'"); } + public Task TruncateDocumentStorageAsync(ITenant tenant) + { + return tenant.RunSqlAsync( + $"delete from {_parent.TableName.QualifiedName} where {SchemaConstants.DocumentTypeColumn} = '{_mapping.Alias}'"); + } + public TenancyStyle TenancyStyle => _parent.TenancyStyle; object IDocumentStorage.IdentityFor(T document) diff --git a/src/Marten/Internal/StorageCheckingProviderGraph.cs b/src/Marten/Internal/StorageCheckingProviderGraph.cs index 142eaa55d8..25a52e1ea8 100644 --- a/src/Marten/Internal/StorageCheckingProviderGraph.cs +++ b/src/Marten/Internal/StorageCheckingProviderGraph.cs @@ -1,5 +1,6 @@ using System; using Baseline; +using Baseline.ImTools; using Marten.Internal.CodeGeneration; using Marten.Storage; using Marten.Util; diff --git a/src/Marten/Internal/UnitOfWork.cs b/src/Marten/Internal/UnitOfWork.cs index 3aba6cc130..74133ca186 100644 --- a/src/Marten/Internal/UnitOfWork.cs +++ b/src/Marten/Internal/UnitOfWork.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Baseline; +using Baseline.ImTools; using Marten.Events; using Marten.Internal.Operations; using Marten.Patching; diff --git a/src/Marten/Internal/UpdateBatch.cs b/src/Marten/Internal/UpdateBatch.cs index 9a4f9e21af..57f4ed2b2e 100644 --- a/src/Marten/Internal/UpdateBatch.cs +++ b/src/Marten/Internal/UpdateBatch.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Baseline.Exceptions; using Marten.Internal.Operations; using Marten.Services; using Marten.Util; @@ -51,11 +52,7 @@ public void ApplyChanges(IMartenSession session) } catch (Exception e) { - Exception transformed = null; - - if (_operations.OfType().Any(x => x.TryTransform(e, out transformed))) - throw transformed; - throw; + _operations.OfType().TransformAndThrow(e); } throwExceptionsIfAny(); @@ -73,10 +70,7 @@ public async Task ApplyChangesAsync(IMartenSession session, CancellationToken to } catch (Exception e) { - Exception transformed = null; - if (_operations.OfType().Any(x => x.TryTransform(e, out transformed))) - throw transformed; - throw; + _operations.OfType().TransformAndThrow(e); } } else @@ -99,10 +93,7 @@ public async Task ApplyChangesAsync(IMartenSession session, CancellationToken to } catch (Exception e) { - Exception transformed = null; - if (operations.OfType().Any(x => x.TryTransform(e, out transformed))) - throw transformed; - throw; + _operations.OfType().TransformAndThrow(e); } count += session.Options.UpdateBatchSize; @@ -141,11 +132,7 @@ public static void ApplyCallbacks(IReadOnlyList operations, D } catch (Exception e) { - Exception transformed = null; - - if (operations.OfType().Any(x => x.TryTransform(e, out transformed))) - throw transformed; - throw; + operations.OfType().TransformAndThrow(e); } } @@ -161,11 +148,7 @@ public static void ApplyCallbacks(IReadOnlyList operations, D } catch (Exception e) { - Exception transformed = null; - - if (operations.OfType().Any(x => x.TryTransform(e, out transformed))) - throw transformed; - throw; + operations.OfType().TransformAndThrow(e); } } } @@ -185,13 +168,7 @@ public static async Task ApplyCallbacksAsync(IReadOnlyList op } catch (Exception e) { - Exception transformed = null; - - if (operations.OfType().Any(x => x.TryTransform(e, out transformed))) - { - throw transformed; - } - throw; + operations.OfType().TransformAndThrow(e); } } @@ -206,14 +183,7 @@ public static async Task ApplyCallbacksAsync(IReadOnlyList op } catch (Exception e) { - Exception transformed = null; - - if (operations.OfType().Any(x => x.TryTransform(e, out transformed))) - { - throw transformed; - } - - throw; + operations.OfType().TransformAndThrow(e); } } } diff --git a/src/Marten/Linq/Fields/ArrayField.cs b/src/Marten/Linq/Fields/ArrayField.cs index b290607b93..1dc7465cec 100644 --- a/src/Marten/Linq/Fields/ArrayField.cs +++ b/src/Marten/Linq/Fields/ArrayField.cs @@ -5,6 +5,7 @@ using Baseline; using LamarCodeGeneration.Util; using Marten.Util; +using Weasel.Postgresql; namespace Marten.Linq.Fields { diff --git a/src/Marten/Linq/Fields/DictionaryField.cs b/src/Marten/Linq/Fields/DictionaryField.cs index d8fe12314d..ac974a44ec 100644 --- a/src/Marten/Linq/Fields/DictionaryField.cs +++ b/src/Marten/Linq/Fields/DictionaryField.cs @@ -1,11 +1,13 @@ using System.Linq.Expressions; using System.Reflection; using Baseline; +using Baseline.ImTools; using Marten.Exceptions; using Marten.Linq.Filters; using Marten.Linq.SqlGeneration; using Marten.Services.BatchQuerying; using Marten.Util; +using Weasel.Postgresql; namespace Marten.Linq.Fields { diff --git a/src/Marten/Linq/Fields/DuplicatedField.cs b/src/Marten/Linq/Fields/DuplicatedField.cs index 2f01872112..3897062740 100644 --- a/src/Marten/Linq/Fields/DuplicatedField.cs +++ b/src/Marten/Linq/Fields/DuplicatedField.cs @@ -6,11 +6,13 @@ using Marten.Linq.Filters; using Marten.Linq.Parsing; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Schema; using Marten.Schema.Arguments; using Marten.Storage; using Marten.Util; using NpgsqlTypes; +using Weasel.Postgresql.Tables; namespace Marten.Linq.Fields { diff --git a/src/Marten/Linq/Fields/FieldBase.cs b/src/Marten/Linq/Fields/FieldBase.cs index e7bd0cbd12..bab51e407a 100644 --- a/src/Marten/Linq/Fields/FieldBase.cs +++ b/src/Marten/Linq/Fields/FieldBase.cs @@ -5,6 +5,7 @@ using Marten.Linq.Filters; using Marten.Linq.Parsing; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Fields diff --git a/src/Marten/Linq/Fields/FieldCollection.cs b/src/Marten/Linq/Fields/FieldCollection.cs index bb0aaaa255..ea2f13cb8f 100644 --- a/src/Marten/Linq/Fields/FieldCollection.cs +++ b/src/Marten/Linq/Fields/FieldCollection.cs @@ -6,11 +6,12 @@ using System.Linq.Expressions; using System.Reflection; using Baseline; - using Marten.Linq.Parsing; +using Marten.Linq.Parsing; using Marten.Linq.QueryHandlers; using Marten.Schema; using Marten.Util; - using ReflectionExtensions = LamarCodeGeneration.Util.ReflectionExtensions; +using Weasel.Postgresql; +using ReflectionExtensions = LamarCodeGeneration.Util.ReflectionExtensions; namespace Marten.Linq.Fields { diff --git a/src/Marten/Linq/Fields/IdField.cs b/src/Marten/Linq/Fields/IdField.cs index fac7f46fcc..4668a68af6 100644 --- a/src/Marten/Linq/Fields/IdField.cs +++ b/src/Marten/Linq/Fields/IdField.cs @@ -4,6 +4,7 @@ using Marten.Linq.Filters; using Marten.Linq.Parsing; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Fields diff --git a/src/Marten/Linq/Fields/NullableTypeField.cs b/src/Marten/Linq/Fields/NullableTypeField.cs index 5d16986afa..3cef2b6d8a 100644 --- a/src/Marten/Linq/Fields/NullableTypeField.cs +++ b/src/Marten/Linq/Fields/NullableTypeField.cs @@ -5,6 +5,7 @@ using Marten.Exceptions; using Marten.Linq.Filters; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Fields diff --git a/src/Marten/Linq/Fields/SimpleDataField.cs b/src/Marten/Linq/Fields/SimpleDataField.cs index bd4b8f795b..85cf0680f6 100644 --- a/src/Marten/Linq/Fields/SimpleDataField.cs +++ b/src/Marten/Linq/Fields/SimpleDataField.cs @@ -3,6 +3,7 @@ using System.Reflection; using Marten.Linq.Filters; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Fields diff --git a/src/Marten/Linq/Filters/BooleanFieldIsFalse.cs b/src/Marten/Linq/Filters/BooleanFieldIsFalse.cs index 7d36e5c735..3507ee39dc 100644 --- a/src/Marten/Linq/Filters/BooleanFieldIsFalse.cs +++ b/src/Marten/Linq/Filters/BooleanFieldIsFalse.cs @@ -1,5 +1,6 @@ using Marten.Linq.Fields; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Filters diff --git a/src/Marten/Linq/Filters/BooleanFieldIsTrue.cs b/src/Marten/Linq/Filters/BooleanFieldIsTrue.cs index c2b904d2db..d4ddc47f11 100644 --- a/src/Marten/Linq/Filters/BooleanFieldIsTrue.cs +++ b/src/Marten/Linq/Filters/BooleanFieldIsTrue.cs @@ -1,5 +1,6 @@ using Marten.Linq.Fields; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Filters diff --git a/src/Marten/Linq/Filters/ByIdFilter.cs b/src/Marten/Linq/Filters/ByIdFilter.cs index fcfb6220c9..f95c822d8e 100644 --- a/src/Marten/Linq/Filters/ByIdFilter.cs +++ b/src/Marten/Linq/Filters/ByIdFilter.cs @@ -1,5 +1,6 @@ using System; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; using NpgsqlTypes; diff --git a/src/Marten/Linq/Filters/CollectionIsEmpty.cs b/src/Marten/Linq/Filters/CollectionIsEmpty.cs index a29393427d..3bb0b4dd55 100644 --- a/src/Marten/Linq/Filters/CollectionIsEmpty.cs +++ b/src/Marten/Linq/Filters/CollectionIsEmpty.cs @@ -1,5 +1,6 @@ using Marten.Linq.Fields; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Filters diff --git a/src/Marten/Linq/Filters/CollectionIsNotEmpty.cs b/src/Marten/Linq/Filters/CollectionIsNotEmpty.cs index a1ea3c0137..7472dad702 100644 --- a/src/Marten/Linq/Filters/CollectionIsNotEmpty.cs +++ b/src/Marten/Linq/Filters/CollectionIsNotEmpty.cs @@ -1,5 +1,6 @@ using Marten.Linq.Fields; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Filters diff --git a/src/Marten/Linq/Filters/ComparisonFilter.cs b/src/Marten/Linq/Filters/ComparisonFilter.cs index 0c801e5cf6..b5c4a596e4 100644 --- a/src/Marten/Linq/Filters/ComparisonFilter.cs +++ b/src/Marten/Linq/Filters/ComparisonFilter.cs @@ -1,5 +1,6 @@ using Marten.Linq.Parsing; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Filters diff --git a/src/Marten/Linq/Filters/CompoundWhereFragment.cs b/src/Marten/Linq/Filters/CompoundWhereFragment.cs index ddfb8d8158..8912c9a445 100644 --- a/src/Marten/Linq/Filters/CompoundWhereFragment.cs +++ b/src/Marten/Linq/Filters/CompoundWhereFragment.cs @@ -2,6 +2,7 @@ using System.Linq; using Baseline; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Filters diff --git a/src/Marten/Linq/Filters/ContainmentWhereFragment.cs b/src/Marten/Linq/Filters/ContainmentWhereFragment.cs index e96e9e2b50..457204f137 100644 --- a/src/Marten/Linq/Filters/ContainmentWhereFragment.cs +++ b/src/Marten/Linq/Filters/ContainmentWhereFragment.cs @@ -6,6 +6,7 @@ using Baseline; using Marten.Linq.Parsing; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; using NpgsqlTypes; diff --git a/src/Marten/Linq/Filters/CurrentTenantFilter.cs b/src/Marten/Linq/Filters/CurrentTenantFilter.cs index 2e18f5708d..a9c969a2f2 100644 --- a/src/Marten/Linq/Filters/CurrentTenantFilter.cs +++ b/src/Marten/Linq/Filters/CurrentTenantFilter.cs @@ -1,4 +1,5 @@ using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Schema.Arguments; using Marten.Storage.Metadata; using Marten.Util; diff --git a/src/Marten/Linq/Filters/FullTextWhereFragment.cs b/src/Marten/Linq/Filters/FullTextWhereFragment.cs index 08ab3c7c59..d0a43f33bc 100644 --- a/src/Marten/Linq/Filters/FullTextWhereFragment.cs +++ b/src/Marten/Linq/Filters/FullTextWhereFragment.cs @@ -2,6 +2,7 @@ using Marten.Linq.Parsing; using Marten.Linq.Parsing.Methods; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Schema; using Marten.Util; diff --git a/src/Marten/Linq/Filters/IsNotNullFilter.cs b/src/Marten/Linq/Filters/IsNotNullFilter.cs index 717deb7fa1..a1fb77f9ad 100644 --- a/src/Marten/Linq/Filters/IsNotNullFilter.cs +++ b/src/Marten/Linq/Filters/IsNotNullFilter.cs @@ -1,5 +1,6 @@ using Marten.Linq.Fields; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Filters diff --git a/src/Marten/Linq/Filters/IsNullFilter.cs b/src/Marten/Linq/Filters/IsNullFilter.cs index bf41f0f858..952ece2812 100644 --- a/src/Marten/Linq/Filters/IsNullFilter.cs +++ b/src/Marten/Linq/Filters/IsNullFilter.cs @@ -1,5 +1,6 @@ using Marten.Linq.Fields; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Filters diff --git a/src/Marten/Linq/Filters/NotWhereFragment.cs b/src/Marten/Linq/Filters/NotWhereFragment.cs index 9aede96bde..917d9b24d9 100644 --- a/src/Marten/Linq/Filters/NotWhereFragment.cs +++ b/src/Marten/Linq/Filters/NotWhereFragment.cs @@ -1,4 +1,5 @@ using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Filters diff --git a/src/Marten/Linq/Filters/SpecificTenantFilter.cs b/src/Marten/Linq/Filters/SpecificTenantFilter.cs index 49c7d2e7dd..0ff90cc7b5 100644 --- a/src/Marten/Linq/Filters/SpecificTenantFilter.cs +++ b/src/Marten/Linq/Filters/SpecificTenantFilter.cs @@ -1,4 +1,5 @@ using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Storage; using Marten.Storage.Metadata; using Marten.Util; diff --git a/src/Marten/Linq/Filters/TenantIsOneOfWhereFragment.cs b/src/Marten/Linq/Filters/TenantIsOneOfWhereFragment.cs index ecd5c01c5f..dd9542a9eb 100644 --- a/src/Marten/Linq/Filters/TenantIsOneOfWhereFragment.cs +++ b/src/Marten/Linq/Filters/TenantIsOneOfWhereFragment.cs @@ -1,4 +1,5 @@ using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Storage; using Marten.Storage.Metadata; using Marten.Util; diff --git a/src/Marten/Linq/Filters/WhereFragment.cs b/src/Marten/Linq/Filters/WhereFragment.cs index 73818ca028..c3ec24e450 100644 --- a/src/Marten/Linq/Filters/WhereFragment.cs +++ b/src/Marten/Linq/Filters/WhereFragment.cs @@ -1,5 +1,7 @@ using System.Linq; +using Baseline; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Filters diff --git a/src/Marten/Linq/Filters/WhereInArray.cs b/src/Marten/Linq/Filters/WhereInArray.cs index 0dcb6db0fb..eb3a7117c1 100644 --- a/src/Marten/Linq/Filters/WhereInArray.cs +++ b/src/Marten/Linq/Filters/WhereInArray.cs @@ -1,5 +1,6 @@ using System.Linq.Expressions; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Filters diff --git a/src/Marten/Linq/Includes/InTempTableWhereFragment.cs b/src/Marten/Linq/Includes/InTempTableWhereFragment.cs index edc1b02e88..a7716761b5 100644 --- a/src/Marten/Linq/Includes/InTempTableWhereFragment.cs +++ b/src/Marten/Linq/Includes/InTempTableWhereFragment.cs @@ -1,4 +1,5 @@ using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Includes diff --git a/src/Marten/Linq/Includes/IncludeIdentitySelectorStatement.cs b/src/Marten/Linq/Includes/IncludeIdentitySelectorStatement.cs index ecd85b2be3..92f161faff 100644 --- a/src/Marten/Linq/Includes/IncludeIdentitySelectorStatement.cs +++ b/src/Marten/Linq/Includes/IncludeIdentitySelectorStatement.cs @@ -6,6 +6,7 @@ using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Includes diff --git a/src/Marten/Linq/Includes/IncludePlan.cs b/src/Marten/Linq/Includes/IncludePlan.cs index 0934a525a8..c6578d593e 100644 --- a/src/Marten/Linq/Includes/IncludePlan.cs +++ b/src/Marten/Linq/Includes/IncludePlan.cs @@ -4,6 +4,7 @@ using Marten.Linq.Fields; using Marten.Linq.Selectors; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Includes diff --git a/src/Marten/Linq/Includes/IncludeQueryHandler.cs b/src/Marten/Linq/Includes/IncludeQueryHandler.cs index 876a78ed42..dde8bdcc38 100644 --- a/src/Marten/Linq/Includes/IncludeQueryHandler.cs +++ b/src/Marten/Linq/Includes/IncludeQueryHandler.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Marten.Internal; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Includes diff --git a/src/Marten/Linq/MartenLinqQueryable.cs b/src/Marten/Linq/MartenLinqQueryable.cs index d9acafbec4..8d0c3b9b73 100644 --- a/src/Marten/Linq/MartenLinqQueryable.cs +++ b/src/Marten/Linq/MartenLinqQueryable.cs @@ -12,6 +12,7 @@ using Marten.Linq.Includes; using Marten.Linq.Parsing; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Marten.Services; using Marten.Transforms; using Marten.Util; diff --git a/src/Marten/Linq/Parsing/LinqHandlerBuilder.cs b/src/Marten/Linq/Parsing/LinqHandlerBuilder.cs index 710506d678..2ff86d9109 100644 --- a/src/Marten/Linq/Parsing/LinqHandlerBuilder.cs +++ b/src/Marten/Linq/Parsing/LinqHandlerBuilder.cs @@ -14,6 +14,7 @@ using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Transforms; using Marten.Util; using Npgsql; diff --git a/src/Marten/Linq/Parsing/Methods/IsNotOneOf.cs b/src/Marten/Linq/Parsing/Methods/IsNotOneOf.cs index 48422682ea..f768af1e22 100644 --- a/src/Marten/Linq/Parsing/Methods/IsNotOneOf.cs +++ b/src/Marten/Linq/Parsing/Methods/IsNotOneOf.cs @@ -5,6 +5,7 @@ using Marten.Linq.Fields; using Marten.Linq.Filters; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; using NpgsqlTypes; diff --git a/src/Marten/Linq/Parsing/Methods/IsOneOf.cs b/src/Marten/Linq/Parsing/Methods/IsOneOf.cs index 4b17ee8977..ede89c4641 100644 --- a/src/Marten/Linq/Parsing/Methods/IsOneOf.cs +++ b/src/Marten/Linq/Parsing/Methods/IsOneOf.cs @@ -5,6 +5,7 @@ using Marten.Linq.Fields; using Marten.Linq.Filters; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; using NpgsqlTypes; diff --git a/src/Marten/Linq/Parsing/Methods/SimpleEqualsParser.cs b/src/Marten/Linq/Parsing/Methods/SimpleEqualsParser.cs index 1dd0d02714..ad61426e1f 100644 --- a/src/Marten/Linq/Parsing/Methods/SimpleEqualsParser.cs +++ b/src/Marten/Linq/Parsing/Methods/SimpleEqualsParser.cs @@ -9,6 +9,7 @@ using Marten.Linq.SqlGeneration; using Marten.Schema; using Marten.Util; +using Weasel.Postgresql; namespace Marten.Linq.Parsing.Methods { diff --git a/src/Marten/Linq/Parsing/Methods/StringContains.cs b/src/Marten/Linq/Parsing/Methods/StringContains.cs index 890e2b371a..6c619d44da 100644 --- a/src/Marten/Linq/Parsing/Methods/StringContains.cs +++ b/src/Marten/Linq/Parsing/Methods/StringContains.cs @@ -23,7 +23,9 @@ private static MethodInfo[] GetContainsMethods() { typeof(string).GetMethod("Contains", new Type[] { typeof(string), typeof(StringComparison)}), ReflectionHelper.GetMethod(s => s.Contains(null)), +#if NET5_0 ReflectionHelper.GetMethod(s => s.Contains(null, StringComparison.CurrentCulture)) +#endif } .Where(m => m != null) .Distinct() diff --git a/src/Marten/Linq/Parsing/ModuloFragment.cs b/src/Marten/Linq/Parsing/ModuloFragment.cs index d3579bf7b6..6d40537e71 100644 --- a/src/Marten/Linq/Parsing/ModuloFragment.cs +++ b/src/Marten/Linq/Parsing/ModuloFragment.cs @@ -1,6 +1,7 @@ using System.Linq.Expressions; using Marten.Linq.Fields; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.Parsing diff --git a/src/Marten/Linq/QueryHandlers/IQueryHandler.cs b/src/Marten/Linq/QueryHandlers/IQueryHandler.cs index e53f0b3ebe..d6ff2d689d 100644 --- a/src/Marten/Linq/QueryHandlers/IQueryHandler.cs +++ b/src/Marten/Linq/QueryHandlers/IQueryHandler.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using Marten.Internal; +using Weasel.Postgresql; using Marten.Util; #nullable enable namespace Marten.Linq.QueryHandlers diff --git a/src/Marten/Linq/QueryHandlers/ListQueryHandler.cs b/src/Marten/Linq/QueryHandlers/ListQueryHandler.cs index 4a5a2284c6..4e6ca7775c 100644 --- a/src/Marten/Linq/QueryHandlers/ListQueryHandler.cs +++ b/src/Marten/Linq/QueryHandlers/ListQueryHandler.cs @@ -6,6 +6,7 @@ using Marten.Internal.CodeGeneration; using Marten.Linq.Selectors; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.QueryHandlers diff --git a/src/Marten/Linq/QueryHandlers/ListWithStatsQueryHandler.cs b/src/Marten/Linq/QueryHandlers/ListWithStatsQueryHandler.cs index 3465c6b330..7f5d214c39 100644 --- a/src/Marten/Linq/QueryHandlers/ListWithStatsQueryHandler.cs +++ b/src/Marten/Linq/QueryHandlers/ListWithStatsQueryHandler.cs @@ -6,6 +6,7 @@ using Marten.Internal.CodeGeneration; using Marten.Linq.Selectors; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.QueryHandlers diff --git a/src/Marten/Linq/QueryHandlers/LoadByIdArrayHandler.cs b/src/Marten/Linq/QueryHandlers/LoadByIdArrayHandler.cs index b83f9b1cc9..250ecd495f 100644 --- a/src/Marten/Linq/QueryHandlers/LoadByIdArrayHandler.cs +++ b/src/Marten/Linq/QueryHandlers/LoadByIdArrayHandler.cs @@ -6,6 +6,7 @@ using Marten.Internal.Storage; using Marten.Linq.Filters; using Marten.Linq.Selectors; +using Weasel.Postgresql; using Marten.Storage; using Marten.Util; #nullable enable diff --git a/src/Marten/Linq/QueryHandlers/LoadByIdHandler.cs b/src/Marten/Linq/QueryHandlers/LoadByIdHandler.cs index fb403c22a0..d77b87f646 100644 --- a/src/Marten/Linq/QueryHandlers/LoadByIdHandler.cs +++ b/src/Marten/Linq/QueryHandlers/LoadByIdHandler.cs @@ -5,6 +5,7 @@ using Marten.Internal.Storage; using Marten.Linq.Filters; using Marten.Linq.Selectors; +using Weasel.Postgresql; using Marten.Storage; using Marten.Util; diff --git a/src/Marten/Linq/QueryHandlers/OneResultHandler.cs b/src/Marten/Linq/QueryHandlers/OneResultHandler.cs index 61338803b9..ab64f65ff8 100644 --- a/src/Marten/Linq/QueryHandlers/OneResultHandler.cs +++ b/src/Marten/Linq/QueryHandlers/OneResultHandler.cs @@ -6,6 +6,7 @@ using Marten.Internal.CodeGeneration; using Marten.Linq.Selectors; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.QueryHandlers diff --git a/src/Marten/Linq/QueryHandlers/UserSuppliedQueryHandler.cs b/src/Marten/Linq/QueryHandlers/UserSuppliedQueryHandler.cs index 0b796ca723..1181ebd54c 100644 --- a/src/Marten/Linq/QueryHandlers/UserSuppliedQueryHandler.cs +++ b/src/Marten/Linq/QueryHandlers/UserSuppliedQueryHandler.cs @@ -5,9 +5,11 @@ using System.Threading; using System.Threading.Tasks; using Baseline; +using Baseline.Reflection; using Marten.Internal; using Marten.Linq.Selectors; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.QueryHandlers diff --git a/src/Marten/Linq/SqlGeneration/AnySelectClause.cs b/src/Marten/Linq/SqlGeneration/AnySelectClause.cs index a087267d7f..f0cf3711d3 100644 --- a/src/Marten/Linq/SqlGeneration/AnySelectClause.cs +++ b/src/Marten/Linq/SqlGeneration/AnySelectClause.cs @@ -5,6 +5,7 @@ using Marten.Internal; using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/CommandParameter.cs b/src/Marten/Linq/SqlGeneration/CommandParameter.cs index 6474eacdd3..7d2f233cf1 100644 --- a/src/Marten/Linq/SqlGeneration/CommandParameter.cs +++ b/src/Marten/Linq/SqlGeneration/CommandParameter.cs @@ -1,4 +1,5 @@ using System.Linq.Expressions; +using Weasel.Postgresql; using Marten.Util; using Npgsql; using NpgsqlTypes; diff --git a/src/Marten/Linq/SqlGeneration/ContainsIdSelectorStatement.cs b/src/Marten/Linq/SqlGeneration/ContainsIdSelectorStatement.cs index 71f8ebefe6..58c6b37980 100644 --- a/src/Marten/Linq/SqlGeneration/ContainsIdSelectorStatement.cs +++ b/src/Marten/Linq/SqlGeneration/ContainsIdSelectorStatement.cs @@ -1,5 +1,6 @@ using System.Linq.Expressions; using Marten.Internal; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/CountClause.cs b/src/Marten/Linq/SqlGeneration/CountClause.cs index 29a35f0fdd..83b8ca3f7a 100644 --- a/src/Marten/Linq/SqlGeneration/CountClause.cs +++ b/src/Marten/Linq/SqlGeneration/CountClause.cs @@ -5,6 +5,7 @@ using Marten.Internal; using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/CountComparisonStatement.cs b/src/Marten/Linq/SqlGeneration/CountComparisonStatement.cs index 3717ee2858..9202e089f2 100644 --- a/src/Marten/Linq/SqlGeneration/CountComparisonStatement.cs +++ b/src/Marten/Linq/SqlGeneration/CountComparisonStatement.cs @@ -2,6 +2,7 @@ using System.Linq.Expressions; using Marten.Internal; using Marten.Linq.Fields; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/CountStatement.cs b/src/Marten/Linq/SqlGeneration/CountStatement.cs index ece0963d4a..260d07fb0b 100644 --- a/src/Marten/Linq/SqlGeneration/CountStatement.cs +++ b/src/Marten/Linq/SqlGeneration/CountStatement.cs @@ -1,4 +1,5 @@ using System; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/DataSelectClause.cs b/src/Marten/Linq/SqlGeneration/DataSelectClause.cs index 9de8d921e5..6bc3103a4a 100644 --- a/src/Marten/Linq/SqlGeneration/DataSelectClause.cs +++ b/src/Marten/Linq/SqlGeneration/DataSelectClause.cs @@ -4,6 +4,7 @@ using Marten.Linq.Parsing; using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/FlattenerStatement.cs b/src/Marten/Linq/SqlGeneration/FlattenerStatement.cs index a662bba770..a028c6f766 100644 --- a/src/Marten/Linq/SqlGeneration/FlattenerStatement.cs +++ b/src/Marten/Linq/SqlGeneration/FlattenerStatement.cs @@ -1,6 +1,7 @@ using System; using Marten.Internal; using Marten.Linq.Fields; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/HardDelete.cs b/src/Marten/Linq/SqlGeneration/HardDelete.cs index f534a99e0a..7be2028604 100644 --- a/src/Marten/Linq/SqlGeneration/HardDelete.cs +++ b/src/Marten/Linq/SqlGeneration/HardDelete.cs @@ -1,5 +1,6 @@ using Marten.Internal.Operations; using Marten.Internal.Storage; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/ISelectClause.cs b/src/Marten/Linq/SqlGeneration/ISelectClause.cs index 7aa419eb14..046160104e 100644 --- a/src/Marten/Linq/SqlGeneration/ISelectClause.cs +++ b/src/Marten/Linq/SqlGeneration/ISelectClause.cs @@ -2,6 +2,7 @@ using Marten.Internal; using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; +using Weasel.Postgresql; using Marten.Util; #nullable enable namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/ISqlFragment.cs b/src/Marten/Linq/SqlGeneration/ISqlFragment.cs index befa1631b8..fb29c8d42c 100644 --- a/src/Marten/Linq/SqlGeneration/ISqlFragment.cs +++ b/src/Marten/Linq/SqlGeneration/ISqlFragment.cs @@ -2,6 +2,7 @@ using Marten.Linq.Filters; using Marten.Linq.Parsing; using Marten.Linq.Parsing.Methods; +using Weasel.Postgresql; using Marten.Util; using Npgsql; diff --git a/src/Marten/Linq/SqlGeneration/IdSelectorStatement.cs b/src/Marten/Linq/SqlGeneration/IdSelectorStatement.cs index e86671054c..33eec5f8c1 100644 --- a/src/Marten/Linq/SqlGeneration/IdSelectorStatement.cs +++ b/src/Marten/Linq/SqlGeneration/IdSelectorStatement.cs @@ -1,5 +1,6 @@ using Marten.Internal; using Marten.Linq.Fields; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/JsonSelectClause.cs b/src/Marten/Linq/SqlGeneration/JsonSelectClause.cs index 8ebef0c7f1..b18707f01a 100644 --- a/src/Marten/Linq/SqlGeneration/JsonSelectClause.cs +++ b/src/Marten/Linq/SqlGeneration/JsonSelectClause.cs @@ -8,6 +8,7 @@ using Marten.Internal; using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; +using Weasel.Postgresql; using Marten.Util; using Npgsql; using TypeExtensions = LamarCodeGeneration.Util.TypeExtensions; diff --git a/src/Marten/Linq/SqlGeneration/ScalarSelectClause.cs b/src/Marten/Linq/SqlGeneration/ScalarSelectClause.cs index b5e021eea6..6b609aa5c7 100644 --- a/src/Marten/Linq/SqlGeneration/ScalarSelectClause.cs +++ b/src/Marten/Linq/SqlGeneration/ScalarSelectClause.cs @@ -8,6 +8,7 @@ using Marten.Linq.Parsing; using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/ScalarSelectManyStatement.cs b/src/Marten/Linq/SqlGeneration/ScalarSelectManyStatement.cs index 2bbecfa7e4..68c1ddff23 100644 --- a/src/Marten/Linq/SqlGeneration/ScalarSelectManyStatement.cs +++ b/src/Marten/Linq/SqlGeneration/ScalarSelectManyStatement.cs @@ -1,4 +1,5 @@ using Marten.Util; +using Weasel.Postgresql; namespace Marten.Linq.SqlGeneration { diff --git a/src/Marten/Linq/SqlGeneration/ScalarStringSelectClause.cs b/src/Marten/Linq/SqlGeneration/ScalarStringSelectClause.cs index 92f739c4ac..a75d27d6d2 100644 --- a/src/Marten/Linq/SqlGeneration/ScalarStringSelectClause.cs +++ b/src/Marten/Linq/SqlGeneration/ScalarStringSelectClause.cs @@ -7,6 +7,7 @@ using Marten.Linq.Parsing; using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/SelectorStatement.cs b/src/Marten/Linq/SqlGeneration/SelectorStatement.cs index 09ca0ee7d0..259200faf2 100644 --- a/src/Marten/Linq/SqlGeneration/SelectorStatement.cs +++ b/src/Marten/Linq/SqlGeneration/SelectorStatement.cs @@ -7,6 +7,7 @@ using Marten.Linq.Parsing; using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/SoftDelete.cs b/src/Marten/Linq/SqlGeneration/SoftDelete.cs index 11a1700273..13dd2a6aee 100644 --- a/src/Marten/Linq/SqlGeneration/SoftDelete.cs +++ b/src/Marten/Linq/SqlGeneration/SoftDelete.cs @@ -1,5 +1,6 @@ using Marten.Internal.Operations; using Marten.Internal.Storage; +using Weasel.Postgresql; using Marten.Schema; using Marten.Util; diff --git a/src/Marten/Linq/SqlGeneration/Statement.cs b/src/Marten/Linq/SqlGeneration/Statement.cs index ba9ccec928..f9212cb210 100644 --- a/src/Marten/Linq/SqlGeneration/Statement.cs +++ b/src/Marten/Linq/SqlGeneration/Statement.cs @@ -5,6 +5,7 @@ using Marten.Linq.Fields; using Marten.Linq.Filters; using Marten.Linq.Parsing; +using Weasel.Postgresql; using Marten.Util; using Npgsql; using Remotion.Linq.Clauses; diff --git a/src/Marten/Linq/SqlGeneration/StatementOperation.cs b/src/Marten/Linq/SqlGeneration/StatementOperation.cs index 4df99ab042..2c2dba074c 100644 --- a/src/Marten/Linq/SqlGeneration/StatementOperation.cs +++ b/src/Marten/Linq/SqlGeneration/StatementOperation.cs @@ -10,6 +10,7 @@ using Marten.Internal.Sessions; using Marten.Internal.Storage; using Marten.Linq.Parsing; +using Weasel.Postgresql; using Marten.Util; using Remotion.Linq.Clauses; diff --git a/src/Marten/Linq/SqlGeneration/StatsSelectClause.cs b/src/Marten/Linq/SqlGeneration/StatsSelectClause.cs index 42b1c328d4..3a2b20f302 100644 --- a/src/Marten/Linq/SqlGeneration/StatsSelectClause.cs +++ b/src/Marten/Linq/SqlGeneration/StatsSelectClause.cs @@ -4,6 +4,7 @@ using Marten.Internal; using Marten.Linq.QueryHandlers; using Marten.Linq.Selectors; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/Linq/SqlGeneration/UnSoftDelete.cs b/src/Marten/Linq/SqlGeneration/UnSoftDelete.cs index cce2a90366..72635ab6b9 100644 --- a/src/Marten/Linq/SqlGeneration/UnSoftDelete.cs +++ b/src/Marten/Linq/SqlGeneration/UnSoftDelete.cs @@ -1,5 +1,6 @@ using Marten.Internal.Operations; using Marten.Internal.Storage; +using Weasel.Postgresql; using Marten.Schema; using Marten.Util; diff --git a/src/Marten/Linq/SqlGeneration/WhereInSubQuery.cs b/src/Marten/Linq/SqlGeneration/WhereInSubQuery.cs index 11b96c6914..81b10b9b4a 100644 --- a/src/Marten/Linq/SqlGeneration/WhereInSubQuery.cs +++ b/src/Marten/Linq/SqlGeneration/WhereInSubQuery.cs @@ -1,3 +1,4 @@ +using Weasel.Postgresql; using Marten.Util; namespace Marten.Linq.SqlGeneration diff --git a/src/Marten/LinqParsing.cs b/src/Marten/LinqParsing.cs index 1d31376059..7d7e716be5 100644 --- a/src/Marten/LinqParsing.cs +++ b/src/Marten/LinqParsing.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using Baseline.ImTools; using Baseline.Reflection; using Marten.Linq; using Marten.Linq.Fields; diff --git a/src/Marten/Marten.csproj b/src/Marten/Marten.csproj index f065ad0e6b..c3abcb0fa9 100644 --- a/src/Marten/Marten.csproj +++ b/src/Marten/Marten.csproj @@ -27,13 +27,14 @@ - + + @@ -51,4 +52,7 @@ + + + diff --git a/src/Marten/MartenRegistry.cs b/src/Marten/MartenRegistry.cs index a422911d4b..680cb38695 100644 --- a/src/Marten/MartenRegistry.cs +++ b/src/Marten/MartenRegistry.cs @@ -10,6 +10,9 @@ using Marten.Storage; using Marten.Storage.Metadata; using NpgsqlTypes; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; + #nullable enable namespace Marten { @@ -108,7 +111,7 @@ public DocumentMappingExpression DocumentAlias(string alias) [Obsolete( "Prefer Index() if you just want to optimize querying, or choose Duplicate() if you really want a duplicated field")] public DocumentMappingExpression Searchable(Expression> expression, string? pgType = null, - NpgsqlDbType? dbType = null, Action? configure = null) + NpgsqlDbType? dbType = null, Action? configure = null) { return Duplicate(expression, pgType, dbType, configure); } @@ -126,7 +129,7 @@ public DocumentMappingExpression Searchable(Expression> expre /// Optional, overrides the Npgsql DbType for any parameter usage of this property /// public DocumentMappingExpression Duplicate(Expression> expression, string? pgType = null, - NpgsqlDbType? dbType = null, Action? configure = null, bool notNull = false) + NpgsqlDbType? dbType = null, Action? configure = null, bool notNull = false) { _builder.Alter = mapping => { @@ -240,7 +243,7 @@ public DocumentMappingExpression UniqueIndex(UniqueIndexType indexType, strin /// /// /// - public DocumentMappingExpression IndexLastModified(Action? configure = null) + public DocumentMappingExpression IndexLastModified(Action? configure = null) { _builder.Alter = m => m.AddLastModifiedIndex(configure); @@ -295,8 +298,8 @@ public DocumentMappingExpression FullTextIndex(Action configur /// public DocumentMappingExpression ForeignKey( Expression> expression, - Action? foreignKeyConfiguration = null, - Action? indexConfiguration = null) + Action? foreignKeyConfiguration = null, + Action? indexConfiguration = null) { _builder.Alter = m => { @@ -306,7 +309,7 @@ public DocumentMappingExpression ForeignKey( var foreignKeyDefinition = m.AddForeignKey(visitor.Members.ToArray(), typeof(TReference)); foreignKeyConfiguration?.Invoke(foreignKeyDefinition); - var indexDefinition = m.AddIndex(foreignKeyDefinition.ColumnName); + var indexDefinition = m.AddIndex(foreignKeyDefinition.ColumnNames[0]); indexConfiguration?.Invoke(indexDefinition); }; @@ -315,21 +318,23 @@ public DocumentMappingExpression ForeignKey( public DocumentMappingExpression ForeignKey(Expression> expression, string schemaName, string tableName, string columnName, - Action? foreignKeyConfiguration = null) + Action? foreignKeyConfiguration = null) { _builder.Alter = m => { - var schemaName1 = schemaName; - schemaName1 ??= m.DatabaseSchemaName; - - var visitor = new FindMembers(); - visitor.Visit(expression); + var members = FindMembers.Determine(expression); - var duplicateField = m.DuplicateField(visitor.Members.ToArray()); + var duplicateField = m.DuplicateField(members); var foreignKey = - new ExternalForeignKeyDefinition(duplicateField.ColumnName, m, schemaName1, tableName, - columnName); + new ForeignKey($"{m.TableName.Name}_{duplicateField.ColumnName}_fkey") + { + LinkedTable = new DbObjectName(schemaName ?? m.DatabaseSchemaName, tableName), + ColumnNames = new[] {duplicateField.ColumnName}, + LinkedNames = new[] {columnName} + }; + + foreignKeyConfiguration?.Invoke(foreignKey); m.ForeignKeys.Add(foreignKey); }; @@ -388,7 +393,7 @@ public DocumentMappingExpression Identity(Expression> member) /// /// /// - public DocumentMappingExpression GinIndexJsonData(Action? configureIndex = null) + public DocumentMappingExpression GinIndexJsonData(Action? configureIndex = null) { _builder.Alter = mapping => { @@ -472,7 +477,7 @@ public DocumentMappingExpression SoftDeleted() return this; } - public DocumentMappingExpression SoftDeletedWithIndex(Action? configure = null) + public DocumentMappingExpression SoftDeletedWithIndex(Action? configure = null) { SoftDeleted(); _builder.Alter = m => m.AddDeletedAtIndex(configure); diff --git a/src/Marten/Patching/PatchOperation.cs b/src/Marten/Patching/PatchOperation.cs index ed69af0a21..3956722547 100644 --- a/src/Marten/Patching/PatchOperation.cs +++ b/src/Marten/Patching/PatchOperation.cs @@ -9,6 +9,7 @@ using Marten.Internal.Storage; using Marten.Linq; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Schema; using Marten.Schema.Identity; using Marten.Services; diff --git a/src/Marten/Schema/ActualForeignKey.cs b/src/Marten/Schema/ActualForeignKey.cs deleted file mode 100644 index e7e0d0b82f..0000000000 --- a/src/Marten/Schema/ActualForeignKey.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; - -namespace Marten.Schema -{ - public class ActualForeignKey - { - public DbObjectName Table { get; } - public string Name { get; } - public string DDL { get; } - - public bool DoesCascadeDeletes() - { - // NOTE: Use .IndexOf() so it's not effected by whitespace - return DDL.IndexOf("on delete cascade", StringComparison.OrdinalIgnoreCase) != -1; - } - - public ActualForeignKey(DbObjectName table, string name, string ddl) - { - Table = table; - Name = name; - DDL = ddl; - } - - public override string ToString() - { - return $"Table: {Table}, Name: {Name}, DDL: {DDL}"; - } - - protected bool Equals(ActualIndex other) - { - return string.Equals(Name, other.Name) && string.Equals(DDL, other.DDL); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - return false; - if (ReferenceEquals(this, obj)) - return true; - if (obj.GetType() != GetType()) - return false; - return Equals((ActualForeignKey)obj); - } - - public override int GetHashCode() - { - unchecked - { - return ((Name != null ? Name.GetHashCode() : 0) * 397) ^ (DDL != null ? DDL.GetHashCode() : 0); - } - } - } -} diff --git a/src/Marten/Schema/ActualIndex.cs b/src/Marten/Schema/ActualIndex.cs deleted file mode 100644 index 1e80931f85..0000000000 --- a/src/Marten/Schema/ActualIndex.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Marten.Schema -{ - public class ActualIndex - { - public DbObjectName Table { get; } - - public string Name { get; } - public string DDL { get; } - - public ActualIndex(DbObjectName table, string name, string ddl) - { - Table = table; - Name = name; - DDL = ddl.Replace(" ", " "); - } - - public override string ToString() - { - return $"Table: {Table}, Name: {Name}, DDL: {DDL}"; - } - - protected bool Equals(ActualIndex other) - { - return string.Equals(Name, other.Name) && string.Equals(DDL, other.DDL); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - return false; - if (ReferenceEquals(this, obj)) - return true; - if (obj.GetType() != GetType()) - return false; - return Equals((ActualIndex)obj); - } - - public override int GetHashCode() - { - unchecked - { - return ((Name != null ? Name.GetHashCode() : 0) * 397) ^ (DDL != null ? DDL.GetHashCode() : 0); - } - } - } -} diff --git a/src/Marten/Schema/Arguments/UpsertArgument.cs b/src/Marten/Schema/Arguments/UpsertArgument.cs index f696ffd5d3..0dbb00fd20 100644 --- a/src/Marten/Schema/Arguments/UpsertArgument.cs +++ b/src/Marten/Schema/Arguments/UpsertArgument.cs @@ -11,6 +11,7 @@ using Marten.Util; using Npgsql; using NpgsqlTypes; +using Weasel.Postgresql; namespace Marten.Schema.Arguments { diff --git a/src/Marten/Schema/ChildDocument.cs b/src/Marten/Schema/ChildDocument.cs index e74c5246e7..e1273bc9a2 100644 --- a/src/Marten/Schema/ChildDocument.cs +++ b/src/Marten/Schema/ChildDocument.cs @@ -3,6 +3,7 @@ using Marten.Linq; using Marten.Linq.Fields; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Storage; using Remotion.Linq; diff --git a/src/Marten/Schema/ComputedIndex.cs b/src/Marten/Schema/ComputedIndex.cs index 782b7c9b63..a45961de0b 100644 --- a/src/Marten/Schema/ComputedIndex.cs +++ b/src/Marten/Schema/ComputedIndex.cs @@ -1,17 +1,17 @@ +using System.Collections.Generic; using System.Linq; using System.Reflection; -using Baseline; using Marten.Schema.Indexing.Unique; -using Marten.Storage; +using Marten.Storage.Metadata; using Marten.Util; +using Weasel.Postgresql.Tables; namespace Marten.Schema { - public class ComputedIndex: IIndexDefinition + public class ComputedIndex : IndexDefinition { private readonly MemberInfo[][] _members; private readonly DocumentMapping _mapping; - private string _indexName; public ComputedIndex(DocumentMapping mapping, MemberInfo[] memberPath) : this(mapping, new[] { memberPath }) @@ -24,141 +24,75 @@ public ComputedIndex(DocumentMapping mapping, MemberInfo[][] members) _mapping = mapping; } - /// - /// Creates the index as UNIQUE - /// - public bool IsUnique { get; set; } + protected override string deriveIndexName() + { + var name = _mapping.TableName.Name; - /// - /// Specifies the index should be created in the background and not block/lock - /// - public bool IsConcurrent { get; set; } + name += IsUnique ? "_uidx_" : "_idx_"; - /// - /// Specify the name of the index explicity - /// - public string IndexName - { - get + foreach (var member in _members) { - if (_indexName.IsNotEmpty()) - { - return SchemaConstants.MartenPrefix + _indexName.ToLowerInvariant(); - } - - return GenerateIndexName(); + name += member.ToTableAlias(); } - set { _indexName = value; } - } - /// - /// Allows you to specify a where clause on the index - /// - public string Where { get; set; } + return name; + } /// /// Marks the column value as upper/lower casing /// public Casings Casing { get; set; } - /// - /// Specifies the type of index to create - /// - public IndexMethod Method { get; set; } = IndexMethod.btree; - - /// - /// Specifies the sort order of the index (only applicable to B-tree indexes) - /// - public SortOrder SortOrder { get; set; } = SortOrder.Asc; - /// /// Specifies the unique index is scoped to the tenant /// public TenancyScope TenancyScope { get; set; } - public string ToDDL() + public override string[] Columns { - var index = IsUnique ? "CREATE UNIQUE INDEX" : "CREATE INDEX"; - - if (IsConcurrent) + get { - index += " CONCURRENTLY"; + return buildColumns().ToArray(); } - - index += $" {IndexName} ON {_mapping.TableName.QualifiedName}"; - - if (Method != IndexMethod.btree) + set { - index += $" USING {Method}"; + // nothing } + } - var membersLocator = _members - .Select(m => - { - var field = _mapping.FieldFor(m); - var casing = Casing; - if (field.FieldType != typeof(string)) - { - // doesn't make sense to lower-case this particular member - casing = Casings.Default; - } - - var sql = field.TypedLocator.Replace("d.", ""); - switch (casing) - { - case Casings.Upper: - return $" upper({sql})"; - - case Casings.Lower: - return $" lower({sql})"; - - default: - return $" ({sql})"; - } - }) - .Join(","); - - var locator = $"{membersLocator}"; - - if (TenancyScope == TenancyScope.PerTenant) + private IEnumerable buildColumns() + { + foreach (var m in _members) { - locator = $"{locator}, tenant_id"; - } + var field = _mapping.FieldFor(m); + var casing = Casing; + if (field.FieldType != typeof(string)) + { + // doesn't make sense to lower-case this particular member + casing = Casings.Default; + } - index += " (" + locator + ")"; + var sql = field.TypedLocator.Replace("d.", ""); + switch (casing) + { + case Casings.Upper: + yield return $" upper({sql})"; + break; - // Only the B-tree index type supports modifying the sort order, and ascending is the default - if (Method == IndexMethod.btree && SortOrder == SortOrder.Desc) - { - index = index.Remove(index.Length - 1); - index += " DESC)"; - } + case Casings.Lower: + yield return $" lower({sql})"; + break; - if (Where.IsNotEmpty()) - { - index += $" WHERE ({Where})"; + default: + yield return $" ({sql})"; + break; + } } - return index + ";"; - } - - private string GenerateIndexName() - { - var name = _mapping.TableName.Name; - - name += IsUnique ? "_uidx_" : "_idx_"; - - foreach (var member in _members) + if (TenancyScope == TenancyScope.PerTenant) { - name += member.ToTableAlias(); + yield return TenantIdColumn.Name; } - - return name; - } - - public bool Matches(ActualIndex index) - { - return index != null; } public enum Casings diff --git a/src/Marten/Schema/DDLRunnerExtensions.cs b/src/Marten/Schema/DDLRunnerExtensions.cs deleted file mode 100644 index 69381a216f..0000000000 --- a/src/Marten/Schema/DDLRunnerExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Marten.Schema -{ - public static class DDLRunnerExtensions - { - public static void Drop(this IDDLRunner runner, object subject, DbObjectName table) - { - var sql = $"drop table if exists {table.QualifiedName} cascade;"; - runner.Apply(subject, sql); - } - - public static void RemoveColumn(this IDDLRunner runner, object subject, DbObjectName table, string columnName) - { - var sql = $"alter table if exists {table.QualifiedName} drop column if exists {columnName};"; - - runner.Apply(subject, sql); - } - } -} diff --git a/src/Marten/Schema/DatabaseGenerator.cs b/src/Marten/Schema/DatabaseGenerator.cs index 4130e5c8d2..0b146beecc 100644 --- a/src/Marten/Schema/DatabaseGenerator.cs +++ b/src/Marten/Schema/DatabaseGenerator.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Weasel.Postgresql; using Marten.Storage; using Marten.Util; using Npgsql; diff --git a/src/Marten/Schema/DatabaseSchemaGenerator.cs b/src/Marten/Schema/DatabaseSchemaGenerator.cs index e296ef17b8..baa0e5b0cb 100644 --- a/src/Marten/Schema/DatabaseSchemaGenerator.cs +++ b/src/Marten/Schema/DatabaseSchemaGenerator.cs @@ -3,12 +3,13 @@ using System.IO; using System.Linq; using Baseline; +using Weasel.Postgresql; using Marten.Services; using Marten.Storage; namespace Marten.Schema { - public class DatabaseSchemaGenerator + internal class DatabaseSchemaGenerator { private const string BeginScript = @"DO $$ BEGIN"; @@ -21,10 +22,7 @@ public class DatabaseSchemaGenerator public DatabaseSchemaGenerator(ITenant tenant) { - if (tenant == null) - throw new ArgumentNullException(nameof(tenant)); - - _tenant = tenant; + _tenant = tenant ?? throw new ArgumentNullException(nameof(tenant)); } public void Generate(StoreOptions options, string[] schemaNames) @@ -49,7 +47,7 @@ public static string GenerateScript(StoreOptions options, IEnumerable sc var names = schemaNames .Distinct() - .Where(name => name != StoreOptions.DefaultDatabaseSchemaName).ToList(); + .Where(name => name != DbObjectName.DefaultDatabaseSchemaName).ToList(); if (!names.Any()) return null; diff --git a/src/Marten/Schema/DbObjectName.cs b/src/Marten/Schema/DbObjectName.cs deleted file mode 100644 index 4c19840290..0000000000 --- a/src/Marten/Schema/DbObjectName.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; - -namespace Marten.Schema -{ - public class DbObjectName - { - public string OwnerName => Schema == StoreOptions.DefaultDatabaseSchemaName ? Name : QualifiedName; - - public string Schema { get; } - public string Name { get; } - public string QualifiedName { get; } - - /// - /// Create a DbObjectName with Schema = "public" - /// - /// - public DbObjectName(string name) : this("public", name) - { - } - - public DbObjectName(string schema, string name) - { - Schema = schema; - Name = name; - QualifiedName = $"{Schema}.{Name}"; - } - - public DbObjectName ToTempCopyTable() - { - return new DbObjectName(Schema, Name + "_temp"); - } - - public static DbObjectName Parse(string qualifiedName) - { - var parts = ParseQualifiedName(qualifiedName); - return new DbObjectName(parts[0], parts[1]); - } - - public override string ToString() - { - return QualifiedName; - } - - protected bool Equals(DbObjectName other) - { - return GetType() == other.GetType() && string.Equals(QualifiedName, other.QualifiedName, StringComparison.OrdinalIgnoreCase); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - return false; - if (ReferenceEquals(this, obj)) - return true; - if (obj.GetType() != this.GetType()) - return false; - return Equals((DbObjectName)obj); - } - - public override int GetHashCode() - { - unchecked - { - return GetType().GetHashCode() * 397 ^ (QualifiedName?.GetHashCode() ?? 0); - } - } - - protected static string[] ParseQualifiedName(string qualifiedName) - { - var parts = qualifiedName.Split('.'); - if (parts.Length == 1) - { - return new string[] { StoreOptions.DefaultDatabaseSchemaName, qualifiedName }; - } - - if (parts.Length != 2) - { - throw new InvalidOperationException( - $"Could not parse QualifiedName: '{qualifiedName}'. Number or parts should be 2s but is {parts.Length}"); - } - return parts; - } - } -} diff --git a/src/Marten/Schema/DbObjects.cs b/src/Marten/Schema/DbObjects.cs deleted file mode 100644 index 90aa413893..0000000000 --- a/src/Marten/Schema/DbObjects.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Common; -using System.Linq; -using Baseline; -using Marten.Storage; -using Marten.Util; - -namespace Marten.Schema -{ - public class DbObjects: IDbObjects - { - private readonly ITenant _tenant; - private readonly StorageFeatures _features; - - public DbObjects(ITenant tenant, StorageFeatures features) - { - _tenant = tenant; - _features = features; - } - - public DbObjectName[] DocumentTables() - { - return SchemaTables().Where(x => x.Name.StartsWith(SchemaConstants.TablePrefix)).ToArray(); - } - - private static DbObjectName Transform(DbDataReader r) - { - return new DbObjectName(r.GetString(0), r.GetString(1)); - } - - public DbObjectName[] Functions() - { - var sql = - "SELECT specific_schema, routine_name FROM information_schema.routines WHERE type_udt_name != 'trigger' and routine_name like ? and specific_schema = ANY(?);"; - - return - _tenant.Fetch(sql, Transform, SchemaConstants.MartenPrefix + "%", _features.AllSchemaNames()).ToArray(); - } - - public DbObjectName[] SchemaTables() - { - var sql = - "SELECT schemaname, relname FROM pg_stat_user_tables WHERE relname LIKE ? AND schemaname = ANY(?);"; - - var schemaNames = _features.AllSchemaNames(); - - var tablePattern = SchemaConstants.MartenPrefix + "%"; - var tables = _tenant.Fetch(sql, Transform, tablePattern, schemaNames).ToArray(); - - return tables; - } - - public bool TableExists(DbObjectName table) - { - var schemaTables = SchemaTables(); - return schemaTables.Contains(table); - } - - public IEnumerable AllIndexes() - { - var sql = @" -SELECT - U.usename AS user_name, - ns.nspname AS schema_name, - pg_catalog.textin(pg_catalog.regclassout(idx.indrelid :: REGCLASS)) AS table_name, - i.relname AS index_name, - pg_get_indexdef(i.oid) as ddl, - idx.indisunique AS is_unique, - idx.indisprimary AS is_primary, - am.amname AS index_type, - idx.indkey, - ARRAY( - SELECT pg_get_indexdef(idx.indexrelid, k + 1, TRUE) - FROM - generate_subscripts(idx.indkey, 1) AS k - ORDER BY k - ) AS index_keys, - (idx.indexprs IS NOT NULL) OR (idx.indkey::int[] @> array[0]) AS is_functional, - idx.indpred IS NOT NULL AS is_partial -FROM pg_index AS idx - JOIN pg_class AS i - ON i.oid = idx.indexrelid - JOIN pg_am AS am - ON i.relam = am.oid - JOIN pg_namespace AS NS ON i.relnamespace = NS.OID - JOIN pg_user AS U ON i.relowner = U.usesysid -WHERE -ns.nspname = ANY(?) AND -NOT nspname LIKE 'pg%' AND i.relname like 'mt_%'; -- Excluding system table -"; - - static ActualIndex Transform(DbDataReader r) => new ActualIndex(DbObjectName.Parse(r.GetString(2)), r.GetString(3), r.GetString(4)); - - var schemaNames = _features.AllSchemaNames(); - - return _tenant.Fetch(sql, Transform, (object)schemaNames); - } - - public IEnumerable IndexesFor(DbObjectName table) - { - return AllIndexes().Where(x => x.Table.Equals(table)).ToArray(); - } - - public FunctionBody DefinitionForFunction(DbObjectName function) - { - var sql = @" -SELECT pg_get_functiondef(pg_proc.oid) -FROM pg_proc JOIN pg_namespace as ns ON pg_proc.pronamespace = ns.oid WHERE ns.nspname = :schema and proname = :function; -SELECT format('DROP FUNCTION %s.%s(%s);' - ,n.nspname - ,p.proname - ,pg_get_function_identity_arguments(p.oid)) -FROM pg_proc p -LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace -WHERE p.proname = :function -AND n.nspname = :schema; -"; - - using (var conn = _tenant.CreateConnection()) - { - conn.Open(); - - try - { - var cmd = conn.CreateCommand().Sql(sql) - .With("schema", function.Schema) - .With("function", function.Name); - - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - return null; - - var definition = reader.GetString(0); - - reader.NextResult(); - - var drops = new List(); - while (reader.Read()) - { - drops.Add(reader.GetString(0)); - } - - return new FunctionBody(function, drops.ToArray(), definition); - } - } - finally - { - conn.Close(); - } - } - } - - public ForeignKeyConstraint[] AllForeignKeys() - { - Func reader = r => new ForeignKeyConstraint(r.GetString(0), r.GetString(1), r.GetString(2)); - - var sql = - "select constraint_name, constraint_schema, table_name from information_schema.table_constraints where constraint_name LIKE 'mt_%' and constraint_type = 'FOREIGN KEY'"; - - return _tenant.Fetch(sql, reader).ToArray(); - } - - public Table ExistingTableFor(Type type) - { - var mapping = _features.MappingFor(type).As(); - var expected = mapping.Schema.Table; - - using (var conn = _tenant.CreateConnection()) - { - conn.Open(); - - return expected.FetchExisting(conn); - } - } - - } -} diff --git a/src/Marten/Schema/DocumentCleaner.cs b/src/Marten/Schema/DocumentCleaner.cs index 47b5eb115e..b498f71205 100644 --- a/src/Marten/Schema/DocumentCleaner.cs +++ b/src/Marten/Schema/DocumentCleaner.cs @@ -1,10 +1,15 @@ using System; +using System.IO; using System.Linq; +using System.Threading.Tasks; using Baseline; +using Marten.Exceptions; using Marten.Internal; +using Weasel.Postgresql; using Marten.Services; using Marten.Storage; using Marten.Util; +using Npgsql; namespace Marten.Schema { @@ -17,7 +22,7 @@ public class DocumentCleaner: IDocumentCleaner ,pg_get_function_identity_arguments(p.oid)) FROM pg_proc p LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace -WHERE p.proname like 'mt_%' and n.nspname = ANY(?)"; +WHERE p.proname like 'mt_%' and n.nspname = ANY(:schemas)"; public static readonly string DropFunctionSql = @" SELECT format('DROP FUNCTION IF EXISTS %s.%s(%s);' @@ -29,11 +34,11 @@ FROM pg_proc p WHERE p.proname = '{0}' AND n.nspname = '{1}';"; - public static readonly string DropAllSequencesSql = @"SELECT format('DROP SEQUENCE %s.%s;' + public static readonly string DropAllSequencesSql = @"SELECT format('DROP SEQUENCE IF EXISTS %s.%s;' ,s.sequence_schema ,s.sequence_name) FROM information_schema.sequences s -WHERE s.sequence_name like 'mt_%' and s.sequence_schema = ANY(?);"; +WHERE s.sequence_name like 'mt_%' and s.sequence_schema = ANY(:schemas);"; private readonly StoreOptions _options; private readonly ITenant _tenant; @@ -46,25 +51,40 @@ public DocumentCleaner(StoreOptions options, ITenant tenant) public void DeleteAllDocuments() { - var dbObjects = new DbObjects(_tenant, _options.Storage); + DeleteAllDocumentsAsync().GetAwaiter().GetResult(); + } + + public async Task DeleteAllDocumentsAsync() + { + using var conn = _tenant.CreateConnection(); + await conn.OpenAsync(); - using (var conn = _tenant.OpenConnection(CommandRunnerMode.Transactional)) + var schemas = _options.Storage.AllSchemaNames(); + var tables = await conn.ExistingTables("mt_%", schemas); + + if (!tables.Any()) return; + + var builder = new CommandBuilder(); + foreach (var table in tables) { - dbObjects.DocumentTables().Each(tableName => - { - var sql = "truncate {0} cascade".ToFormat(tableName); - conn.Execute(sql); - }); - conn.Commit(); + builder.Append($"truncate {table} cascade;"); } + + await builder.ExecuteNonQueryAsync(conn); } - public void DeleteDocumentsFor(Type documentType) + public void DeleteDocumentsByType(Type documentType) { var storage = _options.Tenancy.Default.Providers.StorageFor(documentType); storage.TruncateDocumentStorage(_tenant); } + public Task DeleteDocumentsByTypeAsync(Type documentType) + { + var storage = _options.Tenancy.Default.Providers.StorageFor(documentType); + return storage.TruncateDocumentStorageAsync(_tenant); + } + public void DeleteDocumentsExcept(params Type[] documentTypes) { var documentMappings = _options.Storage.AllDocumentMappings.Where(x => !documentTypes.Contains(x.DocumentType)); @@ -75,6 +95,16 @@ public void DeleteDocumentsExcept(params Type[] documentTypes) } } + public async Task DeleteDocumentsExceptAsync(params Type[] documentTypes) + { + var documentMappings = _options.Storage.AllDocumentMappings.Where(x => !documentTypes.Contains(x.DocumentType)); + foreach (var mapping in documentMappings) + { + var storage = _options.Tenancy.Default.Providers.StorageFor(mapping.DocumentType); + await storage.TruncateDocumentStorageAsync(_tenant); + } + } + public void CompletelyRemove(Type documentType) { var mapping = _options.Storage.MappingFor(documentType); @@ -82,35 +112,107 @@ public void CompletelyRemove(Type documentType) { conn.Open(); - mapping.Schema.RemoveAllObjects(_options.Advanced.DdlRules, conn); + var writer = new StringWriter(); + foreach (var schemaObject in ((IFeatureSchema) mapping.Schema).Objects) + { + schemaObject.WriteDropStatement(_options.Advanced.DdlRules, writer); + } + + var sql = writer.ToString(); + var cmd = conn.CreateCommand(sql); + + try + { + cmd.ExecuteNonQuery(); + } + catch (Exception e) + { + MartenExceptionTransformer.WrapAndThrow(cmd, e); + } } } + public async Task CompletelyRemoveAsync(Type documentType) + { + var mapping = _options.Storage.MappingFor(documentType); + using var conn = _tenant.CreateConnection(); + await conn.OpenAsync(); + + var writer = new StringWriter(); + foreach (var schemaObject in ((IFeatureSchema) mapping.Schema).Objects) + { + schemaObject.WriteDropStatement(_options.Advanced.DdlRules, writer); + } + + var sql = writer.ToString(); + var cmd = conn.CreateCommand(sql); + + try + { + await cmd.ExecuteNonQueryAsync(); + } + catch (Exception e) + { + MartenExceptionTransformer.WrapAndThrow(cmd, e); + } + } + + public void CompletelyRemoveAll() { - var dbObjects = new DbObjects(_tenant, _options.Storage); + CompletelyRemoveAllAsync().GetAwaiter().GetResult(); + } + + public async Task CompletelyRemoveAllAsync() + { + using var conn = _tenant.CreateConnection(); + await conn.OpenAsync(); + var schemas = _options.Storage.AllSchemaNames(); + var tables = await conn.ExistingTables("mt_%", schemas); + + var builder = new CommandBuilder(); + - using (var connection = _tenant.OpenConnection(CommandRunnerMode.Transactional)) + foreach (var table in tables) { - var schemaTables = dbObjects.SchemaTables(); - schemaTables - .Each(tableName => { connection.Execute($"DROP TABLE IF EXISTS {tableName} CASCADE;"); }); + builder.Append($"DROP TABLE IF EXISTS {table} CASCADE;"); + } - var allSchemas = new object[] { _options.Storage.AllSchemaNames() }; + var functionDrops = await conn.CreateCommand(DropAllFunctionSql) + .With("schemas", schemas) + .FetchList(); + foreach (var functionDrop in functionDrops) + { + builder.Append(functionDrop); + } - var drops = connection.GetStringList(DropAllFunctionSql, allSchemas) - .Concat(connection.GetStringList(DropAllSequencesSql, allSchemas)); - drops.Each(drop => connection.Execute(drop)); - connection.Commit(); + var sequenceDrops = await conn.CreateCommand(DropAllSequencesSql) + .With("schemas", schemas) + .FetchList(); + foreach (var sequenceDrop in sequenceDrops) + { + builder.Append(sequenceDrop); + } - _tenant.ResetSchemaExistenceChecks(); + if (tables.Any() || functionDrops.Any() || sequenceDrops.Any()) + { + await builder.ExecuteNonQueryAsync(conn); } + + _tenant.ResetSchemaExistenceChecks(); } public void DeleteAllEventData() { using var connection = _tenant.OpenConnection(CommandRunnerMode.Transactional); - connection.Execute($@" + var deleteEventDataSql = toDeleteEventDataSql(); + connection.Execute(deleteEventDataSql); + connection.Commit(); + } + + private string toDeleteEventDataSql() + { + return $@" DO $$ BEGIN ALTER SEQUENCE IF EXISTS {_options.Events.DatabaseSchemaName}.mt_events_sequence RESTART WITH 1; IF EXISTS(SELECT * FROM information_schema.tables @@ -123,10 +225,21 @@ IF EXISTS(SELECT * FROM information_schema.tables WHERE table_name = 'mt_mark_event_progression' AND table_schema = '{_options.Events.DatabaseSchemaName}') THEN TRUNCATE TABLE {_options.Events.DatabaseSchemaName}.mt_mark_event_progression CASCADE; END IF; END; $$; -"); - connection.Commit(); - +"; + } + public async Task DeleteAllEventDataAsync() + { + using var connection = _tenant.CreateConnection(); + await connection.OpenAsync(); +#if NET5_0 + var tx = await connection.BeginTransactionAsync(); + #else + var tx = connection.BeginTransaction(); +#endif + var deleteEventDataSql = toDeleteEventDataSql(); + await connection.CreateCommand(deleteEventDataSql, tx).ExecuteNonQueryAsync(); + await tx.CommitAsync(); } public void DeleteSingleEventStream(Guid streamId) @@ -146,30 +259,69 @@ private void DeleteSingleEventStream(T streamId) throw new ArgumentException($"{nameof(streamId)} should be of type {_options.EventGraph.GetStreamIdType()}", nameof(streamId)); } - using (var conn = _tenant.CreateConnection()) + using var conn = _tenant.CreateConnection(); + var streamsWhere = "id = :id"; + var eventsWhere = "stream_id = :id"; + + if (_options.Events.TenancyStyle == TenancyStyle.Conjoined) { - var streamsWhere = "id = :id"; - var eventsWhere = "stream_id = :id"; + var tenantPart = $" AND tenant_id = :tenantId"; + streamsWhere += tenantPart; + eventsWhere += tenantPart; + } - if (_options.Events.TenancyStyle == TenancyStyle.Conjoined) - { - var tenantPart = $" AND tenant_id = :tenantId"; - streamsWhere += tenantPart; - eventsWhere += tenantPart; - } + var cmd = conn.CreateCommand().WithText($"delete from {_options.Events.DatabaseSchemaName}.mt_events where {eventsWhere};delete from {_options.Events.DatabaseSchemaName}.mt_streams where {streamsWhere}"); + cmd.AddNamedParameter("id", streamId); - var cmd = conn.CreateCommand().WithText($"delete from {_options.Events.DatabaseSchemaName}.mt_events where {eventsWhere};delete from {_options.Events.DatabaseSchemaName}.mt_streams where {streamsWhere}"); - cmd.AddNamedParameter("id", streamId); + if (_options.Events.TenancyStyle == TenancyStyle.Conjoined) + { + cmd.AddNamedParameter("tenantId", _tenant.TenantId); + } - if (_options.Events.TenancyStyle == TenancyStyle.Conjoined) - { - cmd.AddNamedParameter("tenantId", _tenant.TenantId); - } + conn.Open(); - conn.Open(); + cmd.ExecuteNonQuery(); + } + + public Task DeleteSingleEventStreamAsync(Guid streamId) + { + return DeleteSingleEventStreamAsync(streamId); + } - cmd.ExecuteNonQuery(); + public Task DeleteSingleEventStreamAsync(string streamId) + { + return DeleteSingleEventStreamAsync(streamId); + } + + private async Task DeleteSingleEventStreamAsync(T streamId) + { + if (typeof(T) != _options.EventGraph.GetStreamIdType()) + { + throw new ArgumentException($"{nameof(streamId)} should be of type {_options.EventGraph.GetStreamIdType()}", nameof(streamId)); + } + + using var conn = _tenant.CreateConnection(); + var streamsWhere = "id = :id"; + var eventsWhere = "stream_id = :id"; + + if (_options.Events.TenancyStyle == TenancyStyle.Conjoined) + { + var tenantPart = $" AND tenant_id = :tenantId"; + streamsWhere += tenantPart; + eventsWhere += tenantPart; } + + var cmd = conn.CreateCommand().WithText($"delete from {_options.Events.DatabaseSchemaName}.mt_events where {eventsWhere};delete from {_options.Events.DatabaseSchemaName}.mt_streams where {streamsWhere}"); + cmd.AddNamedParameter("id", streamId); + + if (_options.Events.TenancyStyle == TenancyStyle.Conjoined) + { + cmd.AddNamedParameter("tenantId", _tenant.TenantId); + } + + await conn.OpenAsync(); + + await cmd.ExecuteNonQueryAsync(); } } } diff --git a/src/Marten/Schema/DocumentForeignKey.cs b/src/Marten/Schema/DocumentForeignKey.cs new file mode 100644 index 0000000000..dacd22133c --- /dev/null +++ b/src/Marten/Schema/DocumentForeignKey.cs @@ -0,0 +1,45 @@ +using System; +using System.Text; +using Baseline; +using Marten.Storage; +using Marten.Storage.Metadata; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; + +namespace Marten.Schema +{ + public class DocumentForeignKey : ForeignKey + { + private static string toKeyName(DocumentMapping parent, DocumentMapping reference, string columnName) + { + return $"{parent.TableName.Name}_{columnName}{(parent.TenancyStyle == TenancyStyle.Conjoined && reference?.TenancyStyle == TenancyStyle.Conjoined ? "_tenant_id" : "")}_fkey"; + } + + public DocumentForeignKey( + string columnName, + DocumentMapping parent, + DocumentMapping reference + ) : base(toKeyName(parent, reference, columnName)) + { + ReferenceDocumentType = reference.DocumentType; + + LinkedTable = reference.TableName; + + if (parent.TenancyStyle == TenancyStyle.Conjoined && reference?.TenancyStyle == TenancyStyle.Conjoined) + { + ColumnNames = new[] {columnName, TenantIdColumn.Name}; + LinkedNames = new[] {"id", TenantIdColumn.Name}; + } + else + { + ColumnNames = new[] {columnName}; + LinkedNames = new[] {"id"}; + } + } + + public Type ReferenceDocumentType { get; } + } + + + +} diff --git a/src/Marten/Schema/DocumentIndex.cs b/src/Marten/Schema/DocumentIndex.cs new file mode 100644 index 0000000000..5b252aabff --- /dev/null +++ b/src/Marten/Schema/DocumentIndex.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Baseline; +using Marten.Schema.Indexing.Unique; +using Marten.Storage.Metadata; +using Weasel.Postgresql.Tables; + +namespace Marten.Schema +{ + public class DocumentIndex : IndexDefinition + { + private readonly DocumentMapping _parent; + private readonly string[] _columns; + + public DocumentIndex(DocumentMapping parent, params string[] columns) + { + _parent = parent; + _columns = columns; + } + + public override string ToString() + { + return $"DocumentIndex for {_parent.DocumentType} on columns {Columns.Join(", ")}"; + } + + public TenancyScope TenancyScope { get; set; } = TenancyScope.Global; + + public override string[] Columns + { + get + { + if (TenancyScope == TenancyScope.Global) + { + return _columns; + } + + return _columns.Concat(new[] {TenantIdColumn.Name}).ToArray(); + } + set + { + + } + } + + protected override string deriveIndexName() + { + return $"{_parent.TableName.Name}_idx_{_columns.Join("_")}"; + } + + } + +} diff --git a/src/Marten/Schema/DocumentMapping.cs b/src/Marten/Schema/DocumentMapping.cs index 32ec089db1..3dc2111278 100644 --- a/src/Marten/Schema/DocumentMapping.cs +++ b/src/Marten/Schema/DocumentMapping.cs @@ -12,6 +12,7 @@ using Marten.Linq.Filters; using Marten.Linq.Parsing; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Schema.Identity; using Marten.Schema.Identity.Sequences; using Marten.Schema.Indexing.Unique; @@ -19,6 +20,7 @@ using Marten.Util; using NpgsqlTypes; using Remotion.Linq; +using Weasel.Postgresql.Tables; namespace Marten.Schema { @@ -34,7 +36,7 @@ public interface IDocumentType DocumentMetadataCollection Metadata { get; } bool UseOptimisticConcurrency { get;} IList Indexes { get; } - IList ForeignKeys { get; } + IList ForeignKeys { get; } SubClasses SubClasses { get; } DbObjectName UpsertFunction { get; } DbObjectName InsertFunction { get; } @@ -52,7 +54,7 @@ public interface IDocumentType TenancyStyle TenancyStyle { get; } DuplicatedField[] DuplicatedFields { get; } bool IsHierarchy(); - IEnumerable IndexesFor(string column); + IEnumerable IndexesFor(string column); string AliasFor(Type subclassType); Type TypeFor(string alias); IField FieldFor(string memberName); @@ -126,7 +128,17 @@ private void applyAnyMartenAttributes(Type documentType) public IList Indexes { get; } = new List(); - public IList ForeignKeys { get; } = new List(); + public IList ForeignKeys { get; } = new List(); + + /// + /// Access to all other document types that are linked to by foreign keys + /// from this document type + /// + /// + public IEnumerable ReferencedTypes() + { + return ForeignKeys.OfType().Select(x => x.ReferenceDocumentType).Where(x => x != DocumentType); + } public SubClasses SubClasses { get; } @@ -226,7 +238,7 @@ public HiloSettings HiloSettings public DuplicatedField[] DuplicatedFields => fields().OfType().ToArray(); - public static DocumentMapping For(string databaseSchemaName = StoreOptions.DefaultDatabaseSchemaName) + public static DocumentMapping For(string databaseSchemaName = DbObjectName.DefaultDatabaseSchemaName) { var storeOptions = new StoreOptions { @@ -262,7 +274,7 @@ private static PropertyInfo[] GetProperties(Type type) } - public IndexDefinition AddGinIndexToData() + public DocumentIndex AddGinIndexToData() { var index = AddIndex("data"); index.Method = IndexMethod.gin; @@ -273,34 +285,38 @@ public IndexDefinition AddGinIndexToData() return index; } - public IndexDefinition AddLastModifiedIndex(Action configure = null) + public DocumentIndex AddLastModifiedIndex(Action configure = null) { - var index = new IndexDefinition(this, SchemaConstants.LastModifiedColumn); + var index = new DocumentIndex(this, SchemaConstants.LastModifiedColumn); configure?.Invoke(index); Indexes.Add(index); return index; } - public IndexDefinition AddDeletedAtIndex(Action configure = null) + public DocumentIndex AddDeletedAtIndex(Action configure = null) { if (DeleteStyle != DeleteStyle.SoftDelete) throw new InvalidOperationException( $"DocumentMapping for {DocumentType.FullName} is not configured to use Soft Delete"); - var index = new IndexDefinition(this, SchemaConstants.DeletedAtColumn) {Modifier = $"WHERE {SchemaConstants.DeletedColumn}"}; + var index = new DocumentIndex(this, SchemaConstants.DeletedAtColumn) + { + Predicate = SchemaConstants.DeletedColumn + }; + configure?.Invoke(index); Indexes.Add(index); return index; } - public IndexDefinition AddIndex(params string[] columns) + public DocumentIndex AddIndex(params string[] columns) { - var existing = Indexes.OfType().FirstOrDefault(x => x.Columns.SequenceEqual(columns)); + var existing = Indexes.OfType().FirstOrDefault(x => x.Columns.SequenceEqual(columns)); if (existing != null) return existing; - var index = new IndexDefinition(this, columns); + var index = new DocumentIndex(this, columns); Indexes.Add(index); return index; @@ -315,7 +331,7 @@ public IIndexDefinition AddUniqueIndex(MemberInfo[][] members, var fields = members.Select(memberPath => DuplicateField(memberPath)).ToList(); var index = AddIndex(fields.Select(m => m.ColumnName).ToArray()); - index.IndexName = indexName; + index.Name = indexName; index.Method = indexMethod; index.IsUnique = true; index.TenancyScope = tenancyScope; @@ -328,10 +344,10 @@ public IIndexDefinition AddUniqueIndex(MemberInfo[][] members, this, members) { - Method = indexMethod, IndexName = indexName, IsUnique = true, TenancyScope = tenancyScope + Method = indexMethod, Name = indexName, IsUnique = true, TenancyScope = tenancyScope }; - var existing = Indexes.OfType().FirstOrDefault(x => x.IndexName == index.IndexName); + var existing = Indexes.OfType().FirstOrDefault(x => x.Name == index.Name); if (existing != null) return existing; Indexes.Add(index); @@ -367,34 +383,34 @@ public FullTextIndex AddFullTextIndex(string regConfig = FullTextIndex.DefaultRe public FullTextIndex AddFullTextIndex(MemberInfo[][] members, string regConfig = FullTextIndex.DefaultRegConfig, string indexName = null) { - var index = new FullTextIndex(this, regConfig, members) {IndexName = indexName}; + var index = new FullTextIndex(this, regConfig, members) {Name = indexName}; return AddFullTextIndexIfDoesNotExist(index); } private FullTextIndex AddFullTextIndexIfDoesNotExist(FullTextIndex index) { - var existing = Indexes.OfType().FirstOrDefault(x => x.IndexName == index.IndexName); + var existing = Indexes.OfType().FirstOrDefault(x => x.Name == index.Name); if (existing != null) return existing; Indexes.Add(index); return index; } - public ForeignKeyDefinition AddForeignKey(string memberName, Type referenceType) + public DocumentForeignKey AddForeignKey(string memberName, Type referenceType) { var field = FieldFor(memberName); return AddForeignKey(field.Members, referenceType); } - public ForeignKeyDefinition AddForeignKey(MemberInfo[] members, Type referenceType) + public DocumentForeignKey AddForeignKey(MemberInfo[] members, Type referenceType) { var referenceMapping = referenceType != DocumentType ? _storeOptions.Storage.MappingFor(referenceType) : this; var duplicateField = DuplicateField(members); - var foreignKey = new ForeignKeyDefinition(duplicateField.ColumnName, this, referenceMapping); + var foreignKey = new DocumentForeignKey(duplicateField.ColumnName, this, referenceMapping); ForeignKeys.Add(foreignKey); return foreignKey; @@ -474,9 +490,9 @@ public DuplicatedField DuplicateField(MemberInfo[] members, string pgType = null return duplicatedField; } - public IEnumerable IndexesFor(string column) + public IEnumerable IndexesFor(string column) { - return Indexes.OfType().Where(x => x.Columns.Contains(column)); + return Indexes.OfType().Where(x => x.Columns.Contains(column)); } internal void CompileAndValidate() @@ -578,7 +594,7 @@ public IField FieldFor(Expression> expression) /// /// public void Duplicate(Expression> expression, string pgType = null, NpgsqlDbType? dbType = null, - Action configure = null, bool notNull = false) + Action configure = null, bool notNull = false) { var visitor = new FindMembers(); visitor.Visit(expression); diff --git a/src/Marten/Schema/DocumentSchema.cs b/src/Marten/Schema/DocumentSchema.cs index 27c69d606e..81d62e4ade 100644 --- a/src/Marten/Schema/DocumentSchema.cs +++ b/src/Marten/Schema/DocumentSchema.cs @@ -5,6 +5,7 @@ using Baseline; using Marten.Storage; using Marten.Storage.Metadata; +using Weasel.Postgresql; namespace Marten.Schema { @@ -44,13 +45,9 @@ public IEnumerable DependentTypes() { yield return typeof(SystemFunctions); - foreach (var foreignKey in _mapping.ForeignKeys) + foreach (var referencedType in _mapping.ReferencedTypes()) { - // ExternalForeignKeyDefinition's will have a null ReferenceDocumentType, so we can skip it - if (foreignKey.ReferenceDocumentType == null) - continue; - - yield return foreignKey.ReferenceDocumentType; + yield return referencedType; } } @@ -72,13 +69,14 @@ private IEnumerable toSchemaObjects() public ISchemaObject[] Objects => toSchemaObjects().ToArray(); public Type StorageType => _mapping.DocumentType; public string Identifier => _mapping.Alias.ToLowerInvariant(); - public void WritePermissions(DdlRules rules, StringWriter writer) + public void WritePermissions(DdlRules rules, TextWriter writer) { var template = _mapping.DdlTemplate.IsNotEmpty() ? rules.Templates[_mapping.DdlTemplate.ToLower()] : rules.Templates["default"]; Table.WriteTemplate(template, writer); + Upsert.WriteTemplate(rules, template, writer); Update.WriteTemplate(rules, template, writer); Insert.WriteTemplate(rules, template, writer); diff --git a/src/Marten/Schema/DuplicateFieldAttribute.cs b/src/Marten/Schema/DuplicateFieldAttribute.cs index 77a9522afa..71ef6748f4 100644 --- a/src/Marten/Schema/DuplicateFieldAttribute.cs +++ b/src/Marten/Schema/DuplicateFieldAttribute.cs @@ -2,6 +2,8 @@ using System.Reflection; using Baseline; using NpgsqlTypes; +using Weasel.Postgresql.Tables; + #nullable enable namespace Marten.Schema { @@ -24,7 +26,9 @@ public override void Modify(DocumentMapping mapping, MemberInfo member) var indexDefinition = mapping.AddIndex(field.ColumnName); indexDefinition.Method = IndexMethod; if (IndexName.IsNotEmpty()) - indexDefinition.IndexName = IndexName; + { + indexDefinition.Name = IndexName; + } indexDefinition.SortOrder = IndexSortOrder; } diff --git a/src/Marten/Schema/ForeignKeyAttribute.cs b/src/Marten/Schema/ForeignKeyAttribute.cs index 88baf20132..5a9a615f6d 100644 --- a/src/Marten/Schema/ForeignKeyAttribute.cs +++ b/src/Marten/Schema/ForeignKeyAttribute.cs @@ -16,7 +16,7 @@ public ForeignKeyAttribute(Type referenceType) public override void Modify(DocumentMapping mapping, MemberInfo member) { var fkDefinition = mapping.AddForeignKey(member.Name, _referenceType); - mapping.AddIndex(fkDefinition.ColumnName); + mapping.AddIndex(fkDefinition.ColumnNames[0]); } } } diff --git a/src/Marten/Schema/ForeignKeyDefinition.cs b/src/Marten/Schema/ForeignKeyDefinition.cs deleted file mode 100644 index 02d9fc9997..0000000000 --- a/src/Marten/Schema/ForeignKeyDefinition.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Text; -using Baseline; -using Marten.Storage; - -namespace Marten.Schema -{ - public class ForeignKeyDefinition - { - private readonly DocumentMapping _parent; - private readonly DocumentMapping _reference; - private string _keyName; - private readonly Func _fkeyTableRefFunc; - private readonly Func _fkeyColumnRefFunc; - private readonly Func _fkeyExtraFunc; - - public ForeignKeyDefinition( - string columnName, - DocumentMapping parent, - DocumentMapping reference - ) : this( - columnName, - parent, - _ => reference.TableName.QualifiedName, - _ => $"(id{(parent.TenancyStyle == TenancyStyle.Conjoined && reference?.TenancyStyle == TenancyStyle.Conjoined ? ", tenant_id" : "")})", - GenerateOnDeleteClause - ) - { - _reference = reference; - } - - protected ForeignKeyDefinition( - string columnName, - DocumentMapping parent, - Func fkeyTableRefFunc, - Func fkeyColumnRefFunc, - Func fkeyExtraFunc - ) - { - ColumnName = columnName; - _parent = parent; - _fkeyTableRefFunc = fkeyTableRefFunc; - _fkeyColumnRefFunc = fkeyColumnRefFunc; - _fkeyExtraFunc = fkeyExtraFunc; - } - - public string KeyName - { - get => _keyName ?? $"{_parent.TableName.Name}_{ColumnName}{(_parent.TenancyStyle == TenancyStyle.Conjoined && _reference?.TenancyStyle == TenancyStyle.Conjoined ? "_tenant_id" : "")}_fkey"; - set => _keyName = value; - } - - public string ColumnName { get; } - - public bool CascadeDeletes { get; set; } - - public Type ReferenceDocumentType => _reference?.DocumentType; - - public string ToDDL() - { - var sb = new StringBuilder(); - - sb.AppendLine($"ALTER TABLE {_parent.TableName.QualifiedName}"); - sb.AppendLine($"ADD CONSTRAINT {KeyName} FOREIGN KEY ({ColumnName}{(_parent.TenancyStyle == TenancyStyle.Conjoined && _reference?.TenancyStyle == TenancyStyle.Conjoined ? ", tenant_id" : "")})"); - sb.Append($"REFERENCES {_fkeyTableRefFunc.Invoke(this)} {_fkeyColumnRefFunc.Invoke(this)}"); - - var extra = _fkeyExtraFunc?.Invoke(this); - if (extra.IsNotEmpty()) - { - sb.AppendLine(); - sb.Append(extra); - } - - sb.Append(";"); - return sb.ToString(); - } - - protected static string GenerateOnDeleteClause(ForeignKeyDefinition fkd) => fkd.CascadeDeletes ? "ON DELETE CASCADE" : string.Empty; - } - - public class ExternalForeignKeyDefinition: ForeignKeyDefinition - { - public ExternalForeignKeyDefinition( - string columnName, - DocumentMapping parent, - string externalSchemaName, - string externalTableName, - string externalColumnName - ) : base( - columnName, - parent, - _ => $"{externalSchemaName}.{externalTableName}", - _ => $"({externalColumnName})", - GenerateOnDeleteClause - ) - { - } - } -} diff --git a/src/Marten/Schema/FullTextIndex.cs b/src/Marten/Schema/FullTextIndex.cs index 689ec9ab90..bb9c794e0b 100644 --- a/src/Marten/Schema/FullTextIndex.cs +++ b/src/Marten/Schema/FullTextIndex.cs @@ -2,11 +2,12 @@ using System.Reflection; using System.Text.RegularExpressions; using Baseline; -using Marten.Storage; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; namespace Marten.Schema { - public class FullTextIndex: IIndexDefinition + public class FullTextIndex: IndexDefinition { public const string DefaultRegConfig = "english"; public const string DefaultDataConfig = "data"; @@ -21,7 +22,9 @@ public FullTextIndex(DocumentMapping mapping, string regConfig = null, string da _table = mapping.TableName; RegConfig = regConfig; DataConfig = dataConfig; - IndexName = indexName; + _indexName = indexName; + + Method = IndexMethod.gin; } public FullTextIndex(DocumentMapping mapping, string regConfig, MemberInfo[][] members) @@ -29,23 +32,20 @@ public FullTextIndex(DocumentMapping mapping, string regConfig, MemberInfo[][] m { } - public string IndexName + protected override string deriveIndexName() { - get - { - var lowerValue = _indexName?.ToLowerInvariant(); - if (lowerValue?.StartsWith(SchemaConstants.MartenPrefix) == true) - return lowerValue.ToLowerInvariant(); - else if (lowerValue?.IsNotEmpty() == true) - return SchemaConstants.MartenPrefix + lowerValue.ToLowerInvariant(); - else if (_regConfig != DefaultRegConfig) - return $"{_table.Name}_{_regConfig}_idx_fts"; - else - return $"{_table.Name}_idx_fts"; - } - set => _indexName = value; + var lowerValue = _indexName?.ToLowerInvariant(); + if (lowerValue?.StartsWith(SchemaConstants.MartenPrefix) == true) + return lowerValue.ToLowerInvariant(); + else if (lowerValue?.IsNotEmpty() == true) + return SchemaConstants.MartenPrefix + lowerValue.ToLowerInvariant(); + else if (_regConfig != DefaultRegConfig) + return $"{_table.Name}_{_regConfig}_idx_fts"; + else + return $"{_table.Name}_idx_fts"; } + public string RegConfig { get => _regConfig; @@ -58,33 +58,41 @@ public string DataConfig set => _dataConfig = value ?? DefaultDataConfig; } - public string ToDDL() + public override string[] Columns { - return $"CREATE INDEX {IndexName} ON {_table.QualifiedName} USING gin (( to_tsvector('{_regConfig}', {_dataConfig}) ));"; - } - - public bool Matches(ActualIndex index) - { - var ddl = index?.DDL.ToLowerInvariant(); - - // To omit the null conditional operators that were following here before - if (ddl == null) + get { - return false; + return new string[] { $"( to_tsvector('{_regConfig}', {_dataConfig}) )"}; + } + set + { + // nothing } - - var regexStripType = new Regex(@"('.+?')::text"); - var regexStripParentheses = new Regex("[()]"); - - // Check for the existence of the 'to_tsvector' function, the correct table name, and the use of the data column - return ddl.Contains("to_tsvector") == true - && ddl.Contains(IndexName) == true - && ddl.Contains(_table.QualifiedName) == true - && ddl.Contains(_regConfig.ToLowerInvariant()) == true - // For comparison, strip out types (generated by pg_get_indexdef, but not by Marten) and parentheses (again, pg_get_indexdef produces a bit different output to Marten). - && regexStripParentheses.Replace(regexStripType.Replace(ddl, "$1"), string.Empty).Contains(regexStripParentheses.Replace(_dataConfig.ToLowerInvariant(), string.Empty)); } + // TODO -- keep this just in case? + // public bool Matches(ActualIndex index) + // { + // var ddl = index?.DDL.ToLowerInvariant(); + // + // // To omit the null conditional operators that were following here before + // if (ddl == null) + // { + // return false; + // } + // + // var regexStripType = new Regex(@"('.+?')::text"); + // var regexStripParentheses = new Regex("[()]"); + // + // // Check for the existence of the 'to_tsvector' function, the correct table name, and the use of the data column + // return ddl.Contains("to_tsvector") == true + // && ddl.Contains(IndexName) == true + // && ddl.Contains(_table.QualifiedName) == true + // && ddl.Contains(_regConfig.ToLowerInvariant()) == true + // // For comparison, strip out types (generated by pg_get_indexdef, but not by Marten) and parentheses (again, pg_get_indexdef produces a bit different output to Marten). + // && regexStripParentheses.Replace(regexStripType.Replace(ddl, "$1"), string.Empty).Contains(regexStripParentheses.Replace(_dataConfig.ToLowerInvariant(), string.Empty)); + // } + private static string GetDataConfig(DocumentMapping mapping, MemberInfo[][] members) { var dataConfig = members @@ -93,10 +101,5 @@ private static string GetDataConfig(DocumentMapping mapping, MemberInfo[][] memb return $"({dataConfig})"; } - - private void RefreshIndexName() - { - IndexName = _indexName; - } } } diff --git a/src/Marten/Schema/IDDLRunner.cs b/src/Marten/Schema/IDDLRunner.cs deleted file mode 100644 index 84dd0556ad..0000000000 --- a/src/Marten/Schema/IDDLRunner.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.IO; - -namespace Marten.Schema -{ - public interface IDDLRunner - { - void Apply(object subject, string ddl); - } - - public class DDLRecorder: IDDLRunner - { - private readonly StringWriter _writer; - - public DDLRecorder() : this(new StringWriter()) - { - } - - public DDLRecorder(StringWriter writer) - { - _writer = writer; - } - - public StringWriter Writer => _writer; - - public void Apply(object subject, string ddl) - { - _writer.WriteLine($"-- {subject}"); - _writer.WriteLine(ddl); - _writer.WriteLine(""); - _writer.WriteLine(""); - } - } -} diff --git a/src/Marten/Schema/IDbObjects.cs b/src/Marten/Schema/IDbObjects.cs deleted file mode 100644 index 3dcc4127c0..0000000000 --- a/src/Marten/Schema/IDbObjects.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using Marten.Storage; -#nullable enable -namespace Marten.Schema -{ - public interface IDbObjects - { - /// - /// Fetches a list of all of the Marten generated tables - /// in the database - /// - /// - DbObjectName[] SchemaTables(); - - /// - /// Fetches a list of the Marten document tables - /// in the database - /// - /// - DbObjectName[] DocumentTables(); - - /// - /// Fetches a list of functions generated by Marten - /// in the database - /// - /// - DbObjectName[] Functions(); - - /// - /// Checks whether or not a database table exists in the current tenant - /// - /// - /// - bool TableExists(DbObjectName table); - - /// - /// Query for the Marten related indexes in the current tenant - /// - /// - IEnumerable AllIndexes(); - - /// - /// Query for the indexes related to the named table - /// - /// - /// - IEnumerable IndexesFor(DbObjectName table); - - /// - /// Query for the designated FunctionBody - /// - /// - /// - FunctionBody DefinitionForFunction(DbObjectName function); - - ForeignKeyConstraint[] AllForeignKeys(); - - Table ExistingTableFor(Type type); - } -} diff --git a/src/Marten/Schema/IDocumentCleaner.cs b/src/Marten/Schema/IDocumentCleaner.cs index 7082f21479..a5136c7199 100644 --- a/src/Marten/Schema/IDocumentCleaner.cs +++ b/src/Marten/Schema/IDocumentCleaner.cs @@ -1,4 +1,6 @@ using System; +using System.Threading.Tasks; + #nullable enable namespace Marten.Schema { @@ -9,11 +11,22 @@ public interface IDocumentCleaner /// void DeleteAllDocuments(); + /// + /// Deletes all existing document data in the underlying Postgresql database + /// + Task DeleteAllDocumentsAsync(); + /// /// Deletes all the existing document data for the specified document type /// /// - void DeleteDocumentsFor(Type documentType); + void DeleteDocumentsByType(Type documentType); + + /// + /// Deletes all the existing document data for the specified document type + /// + /// + Task DeleteDocumentsByTypeAsync(Type documentType); /// /// Delete all document data *except* for the specified document types. @@ -21,6 +34,13 @@ public interface IDocumentCleaner /// void DeleteDocumentsExcept(params Type[] documentTypes); + /// + /// Delete all document data *except* for the specified document types. + /// + /// + Task DeleteDocumentsExceptAsync(params Type[] documentTypes); + + /// /// Drop all the schema objects in the underlying Postgresql database for the specified /// document type @@ -28,16 +48,33 @@ public interface IDocumentCleaner /// void CompletelyRemove(Type documentType); + /// + /// Drop all the schema objects in the underlying Postgresql database for the specified + /// document type + /// + /// + Task CompletelyRemoveAsync(Type documentType); + /// /// Remove all Marten-related schema objects from the underlying Postgresql database /// void CompletelyRemoveAll(); + /// + /// Remove all Marten-related schema objects from the underlying Postgresql database + /// + Task CompletelyRemoveAllAsync(); + /// /// Completely deletes all the event and stream data /// void DeleteAllEventData(); + /// + /// Completely deletes all the event and stream data + /// + Task DeleteAllEventDataAsync(); + /// /// Deletes all stream and event data for the designated streamId. Will /// not impact projected documents. USE WITH CAUTION! @@ -45,11 +82,27 @@ public interface IDocumentCleaner /// void DeleteSingleEventStream(Guid streamId); + /// + /// Deletes all stream and event data for the designated streamId. Will + /// not impact projected documents. USE WITH CAUTION! + /// + /// + Task DeleteSingleEventStreamAsync(Guid streamId); + /// /// Deletes all stream and event data for the designated streamId. Will /// not impact projected documents. USE WITH CAUTION! /// /// void DeleteSingleEventStream(string streamId); + + /// + /// Deletes all stream and event data for the designated streamId. Will + /// not impact projected documents. USE WITH CAUTION! + /// + /// + Task DeleteSingleEventStreamAsync(string streamId); + + } } diff --git a/src/Marten/Schema/IDocumentMapping.cs b/src/Marten/Schema/IDocumentMapping.cs index 967716e2f4..280447ebc6 100644 --- a/src/Marten/Schema/IDocumentMapping.cs +++ b/src/Marten/Schema/IDocumentMapping.cs @@ -1,4 +1,5 @@ using System; +using Weasel.Postgresql; using Marten.Schema.Identity; using Marten.Storage; diff --git a/src/Marten/Schema/IDocumentSchema.cs b/src/Marten/Schema/IDocumentSchema.cs index a1a206bae5..151dc4ac7e 100644 --- a/src/Marten/Schema/IDocumentSchema.cs +++ b/src/Marten/Schema/IDocumentSchema.cs @@ -1,5 +1,9 @@ using System; +using System.Threading.Tasks; +using Weasel.Postgresql; + #nullable enable + namespace Marten.Schema { public interface IDocumentSchema @@ -11,21 +15,21 @@ public interface IDocumentSchema /// objects to a file /// /// - void WriteDDL(string filename, bool transactionalScript = true); + void WriteDatabaseCreationScriptFile(string filename); /// /// Write all the SQL scripts to build the database schema, but /// split by document type /// /// - void WriteDDLByType(string directory, bool transactionalScript = true); + void WriteDatabaseCreationScriptByType(string directory); /// /// Creates all the SQL script that would build all the database /// schema objects for the configured schema /// /// - string ToDDL(bool transactionalScript = true); + string ToDatabaseScript(); /// /// Tries to write a "patch" SQL file to upgrade the database @@ -33,36 +37,40 @@ public interface IDocumentSchema /// rollback file as well. /// /// - /// - void WritePatch(string filename, bool withSchemas = true, bool transactionalScript = true); + Task WriteMigrationFile(string filename); /// /// Tries to write a "patch" SQL text to upgrade the database /// to the current Marten schema configuration /// /// - SchemaPatch ToPatch(bool withSchemas = true, bool withAutoCreateAll = false); + Task CreateMigration(); /// /// Validates the Marten configuration of documents and transforms against /// the current database schema. Will throw an exception if any differences are /// detected. Useful for "environment tests" /// - void AssertDatabaseMatchesConfiguration(); + Task AssertDatabaseMatchesConfiguration(); /// /// Executes all detected DDL patches to the schema based on current configuration /// upfront at one time /// - void ApplyAllConfiguredChangesToDatabase(AutoCreate? withAutoCreate = null); + Task ApplyAllConfiguredChangesToDatabase(AutoCreate? withAutoCreate = null); /// /// Generate a DDL patch for one specific document type /// /// /// - SchemaPatch ToPatch(Type documentType); + Task CreateMigration(Type documentType); - void WritePatchByType(string directory, bool transactionalScript = true); + /// + /// Write a migration file for a single document type to the supplied file name + /// + /// + /// + Task WriteMigrationFileByType(string directory); } } diff --git a/src/Marten/Schema/Identity/Sequences/HiLoSequence.cs b/src/Marten/Schema/Identity/Sequences/HiLoSequence.cs index d591176666..716eedac0f 100644 --- a/src/Marten/Schema/Identity/Sequences/HiLoSequence.cs +++ b/src/Marten/Schema/Identity/Sequences/HiLoSequence.cs @@ -1,7 +1,9 @@ using System; using System.Data; using System.Threading; +using System.Threading.Tasks; using Marten.Exceptions; +using Weasel.Postgresql; using Marten.Storage; using Marten.Util; using NpgsqlTypes; @@ -14,7 +16,7 @@ public class HiloSequence: ISequence private readonly StoreOptions _options; private readonly string _entityName; private readonly object _lock = new object(); - private HiloSettings _settings; + private readonly HiloSettings _settings; private DbObjectName GetNextFunction => new DbObjectName(_options.DatabaseSchemaName, "mt_get_next_hi"); @@ -37,27 +39,25 @@ public HiloSequence(ITenant tenant, StoreOptions options, string entityName, Hil public int MaxLo { get; } - public void SetFloor(long floor) + public async Task SetFloor(long floor) { var numberOfPages = (long)Math.Ceiling((double)floor / MaxLo); var updateSql = $"update {_options.DatabaseSchemaName}.mt_hilo set hi_value = :floor where entity_name = :name"; // This guarantees that the hilo row exists - AdvanceToNextHi(); + await AdvanceToNextHi(); - using (var conn = _tenant.CreateConnection()) - { - conn.Open(); + using var conn = _tenant.CreateConnection(); + await conn.OpenAsync(); - conn.CreateCommand(updateSql) - .With("floor", numberOfPages) - .With("name", _entityName) - .ExecuteNonQuery(); - } + await conn.CreateCommand(updateSql) + .With("floor", numberOfPages) + .With("name", _entityName) + .ExecuteNonQueryAsync(); // And again to get it where we need it to be - AdvanceToNextHi(); + await AdvanceToNextHi(); } public int NextInt() @@ -71,47 +71,45 @@ public long NextLong() { if(ShouldAdvanceHi()) { - AdvanceToNextHi(); + AdvanceToNextHi().GetAwaiter().GetResult(); } return AdvanceValue(); } } - public void AdvanceToNextHi() + public async Task AdvanceToNextHi() { - using (var conn = _tenant.CreateConnection()) - { - conn.Open(); + using var conn = _tenant.CreateConnection(); + await conn.OpenAsync(); - try + try + { + var attempts = 0; + do { - var attempts = 0; - do - { - attempts++; - - // Sproc is expected to return -1 if it's unable to - // atomically secure the next hi - var raw = conn.CreateCommand().CallsSproc(GetNextFunction) - .With("entity", _entityName) - .Returns("next", NpgsqlDbType.Bigint).ExecuteScalar(); - - CurrentHi = Convert.ToInt64(raw); - - } while (CurrentHi < 0 && attempts < _settings.MaxAdvanceToNextHiAttempts); - - // if CurrentHi is still less than 0 at this point, then throw exception - if (CurrentHi < 0) - { - throw new HiloSequenceAdvanceToNextHiAttemptsExceededException(); - } - } - finally + attempts++; + + // Sproc is expected to return -1 if it's unable to + // atomically secure the next hi + var raw = await conn.CreateCommand().CallsSproc(GetNextFunction) + .With("entity", _entityName) + .Returns("next", NpgsqlDbType.Bigint).ExecuteScalarAsync(); + + CurrentHi = Convert.ToInt64(raw); + + } while (CurrentHi < 0 && attempts < _settings.MaxAdvanceToNextHiAttempts); + + // if CurrentHi is still less than 0 at this point, then throw exception + if (CurrentHi < 0) { - conn.Close(); - conn.Dispose(); + throw new HiloSequenceAdvanceToNextHiAttemptsExceededException(); } } + finally + { + await conn.CloseAsync(); + conn.Dispose(); + } CurrentLo = 1; } diff --git a/src/Marten/Schema/Identity/Sequences/ISequence.cs b/src/Marten/Schema/Identity/Sequences/ISequence.cs index 7739ffe838..5066273836 100644 --- a/src/Marten/Schema/Identity/Sequences/ISequence.cs +++ b/src/Marten/Schema/Identity/Sequences/ISequence.cs @@ -1,3 +1,5 @@ +using System.Threading.Tasks; + #nullable enable namespace Marten.Schema.Identity.Sequences { @@ -9,6 +11,6 @@ public interface ISequence int MaxLo { get; } - void SetFloor(long floor); + Task SetFloor(long floor); } } diff --git a/src/Marten/Schema/Identity/Sequences/ISequences.cs b/src/Marten/Schema/Identity/Sequences/ISequences.cs index ce37064685..a4a7e2aaf7 100644 --- a/src/Marten/Schema/Identity/Sequences/ISequences.cs +++ b/src/Marten/Schema/Identity/Sequences/ISequences.cs @@ -1,5 +1,7 @@ using System; using Marten.Storage; +using Weasel.Postgresql; + #nullable enable namespace Marten.Schema.Identity.Sequences { diff --git a/src/Marten/Schema/Identity/Sequences/SequenceFactory.cs b/src/Marten/Schema/Identity/Sequences/SequenceFactory.cs index bd262943ed..4f9e5f0cc2 100644 --- a/src/Marten/Schema/Identity/Sequences/SequenceFactory.cs +++ b/src/Marten/Schema/Identity/Sequences/SequenceFactory.cs @@ -2,7 +2,10 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using Weasel.Postgresql; using Marten.Storage; +using Weasel.Postgresql.Tables; + #nullable enable namespace Marten.Schema.Identity.Sequences { @@ -32,8 +35,8 @@ public ISchemaObject[] Objects get { var table = new Table(new DbObjectName(_options.DatabaseSchemaName, "mt_hilo")); - table.AddPrimaryKey(new TableColumn("entity_name", "varchar")); - table.AddColumn("hi_value", "bigint", "default 0"); + table.AddColumn("entity_name").AsPrimaryKey(); + table.AddColumn("hi_value").DefaultValue(0L); var function = new SystemFunction(_options, "mt_get_next_hi", "varchar"); @@ -48,7 +51,7 @@ public ISchemaObject[] Objects public Type StorageType { get; } = typeof(SequenceFactory); public string Identifier { get; } = "hilo"; - public void WritePermissions(DdlRules rules, StringWriter writer) + public void WritePermissions(DdlRules rules, TextWriter writer) { // Nothing } diff --git a/src/Marten/Schema/IndexDefinition.cs b/src/Marten/Schema/IndexDefinition.cs deleted file mode 100644 index 230aca8d74..0000000000 --- a/src/Marten/Schema/IndexDefinition.cs +++ /dev/null @@ -1,159 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using Baseline; -using Marten.Schema.Indexing.Unique; -using Marten.Storage; - -namespace Marten.Schema -{ - public class IndexDefinition: IIndexDefinition - { - private readonly DocumentMapping _parent; - private readonly string[] _columns; - private string _indexName; - - public IndexDefinition(DocumentMapping parent, params string[] columns) - { - _parent = parent; - _columns = columns; - } - - public IndexMethod Method { get; set; } = IndexMethod.btree; - - public SortOrder SortOrder { get; set; } = SortOrder.Asc; - - public bool IsUnique { get; set; } - - public bool IsConcurrent { get; set; } - - public TenancyScope TenancyScope { get; set; } = TenancyScope.Global; - - public string IndexName - { - get - { - if (_indexName.IsNotEmpty()) - { - return _indexName.StartsWith(SchemaConstants.MartenPrefix) - ? _indexName.ToLowerInvariant() - : SchemaConstants.MartenPrefix + _indexName.ToLowerInvariant(); - } - return $"{_parent.TableName.Name}_idx_{_columns.Join("_")}"; - } - set { _indexName = value; } - } - - public string Expression { get; set; } - - public string Modifier { get; set; } - - public IEnumerable Columns => _columns; - - public string ToDDL() - { - var index = IsUnique ? "CREATE UNIQUE INDEX" : "CREATE INDEX"; - if (IsConcurrent) - { - index += " CONCURRENTLY"; - } - - index += $" {IndexName} ON {_parent.TableName.QualifiedName}"; - - if (Method != IndexMethod.btree) - { - index += $" USING {Method}"; - } - - var columns = _columns.Select(column => $"\"{column}\"").Join(", "); - - if (TenancyScope == TenancyScope.PerTenant) - { - columns += ", tenant_id"; - } - - // Only the B-tree index type supports modifying the sort order, and ascending is the default - if (Method == IndexMethod.btree && SortOrder == SortOrder.Desc) - { - columns += " DESC"; - } - - if (Expression.IsEmpty()) - { - index += $" ({columns})"; - } - else - { - index += $" ({Expression.Replace("?", columns)})"; - } - - if (Modifier.IsNotEmpty()) - { - index += " " + Modifier; - } - - return index + ";"; - } - - public bool Matches(ActualIndex index) - { - if (!index.Name.EqualsIgnoreCase(IndexName)) - return false; - - var actual = index.DDL; - if (Method == IndexMethod.btree) - { - actual = actual.Replace("USING btree", ""); - } - - var columnsGroupPattern = "(?.*(?:(?:[\\w.]+)\\s?(?:[\\w_]+).*))"; - var columnsMatchPattern = $"\\({columnsGroupPattern}\\)"; - - if (Expression.IsNotEmpty()) - { - var escapedExpression = Regex.Escape(Expression); - - columnsMatchPattern = $"\\({escapedExpression.Replace("\\?", columnsGroupPattern)}\\)"; - } - - var match = Regex.Match(actual, columnsMatchPattern); - - if (match.Success) - { - var columns = match.Groups["columns"].Value; - _columns.Each(col => - { - columns = Regex.Replace(columns, $"({col})\\s?([\\w_]+)?", "\"$1\"$2"); - }); - - var replacement = Expression.IsEmpty() ? - $"({columns.Trim()})" : - $"({Expression.Replace("?", columns.Trim())})"; - - actual = Regex.Replace(actual, columnsMatchPattern, replacement); - } - - if (!actual.Contains(_parent.TableName.QualifiedName)) - { - actual = actual.Replace("ON " + _parent.TableName.Name, "ON " + _parent.TableName.QualifiedName); - } - - actual = actual.Replace(" ", " ") + ";"; - - // if column name being a PostgreSQL keyword, column is already wrapped with double quotes - // above regex and replace logic will result in additional double quotes, remove the same - actual = actual.Replace("\"\"", "\""); - - return ToDDL().EqualsIgnoreCase(actual); - } - } - - public enum IndexMethod - { - btree, - hash, - gist, - gin, - brin - } -} diff --git a/src/Marten/Schema/InsertExceptionTransform.cs b/src/Marten/Schema/InsertExceptionTransform.cs index 1b92c6bee6..9a7d0a1808 100644 --- a/src/Marten/Schema/InsertExceptionTransform.cs +++ b/src/Marten/Schema/InsertExceptionTransform.cs @@ -1,4 +1,5 @@ using System; +using Baseline.Exceptions; using Marten.Exceptions; using Marten.Services; diff --git a/src/Marten/Schema/SchemaPatch.cs b/src/Marten/Schema/SchemaPatch.cs deleted file mode 100644 index d35840943b..0000000000 --- a/src/Marten/Schema/SchemaPatch.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Common; -using System.IO; -using System.Linq; -using Baseline; -using Marten.Exceptions; -using Marten.Storage; -using Marten.Util; -using Npgsql; - -namespace Marten.Schema -{ - public class SchemaPatch - { - public DdlRules Rules { get; } - - public static string ToDropFileName(string updateFile) - { - var containingFolder = updateFile.ParentDirectory(); - var rawFileName = Path.GetFileNameWithoutExtension(updateFile); - var ext = Path.GetExtension(updateFile); - - var dropFile = $"{rawFileName}.drop{ext}"; - - return containingFolder.IsEmpty() ? dropFile : containingFolder.AppendPath(dropFile); - } - - private readonly DDLRecorder _up = new DDLRecorder(); - private readonly DDLRecorder _down = new DDLRecorder(); - private readonly IDDLRunner _liveRunner; - - public SchemaPatch(DdlRules rules) - { - Rules = rules; - } - - public SchemaPatch(DdlRules rules, StringWriter upWriter) : this(rules, new DDLRecorder(upWriter)) - { - } - - public SchemaPatch(DdlRules rules, IDDLRunner liveRunner) : this(rules) - { - _liveRunner = liveRunner; - } - - public StringWriter DownWriter => _down.Writer; - - public StringWriter UpWriter => _up.Writer; - - public IDDLRunner Updates => _liveRunner ?? _up; - public IDDLRunner Rollbacks => _down; - - public string UpdateDDL => _up.Writer.ToString(); - public string RollbackDDL => _down.Writer.ToString(); - - public SchemaPatchDifference Difference - { - get - { - if (!Migrations.Any()) - return SchemaPatchDifference.None; - - if (Migrations.Any(x => x.Difference == SchemaPatchDifference.Invalid)) - { - return SchemaPatchDifference.Invalid; - } - - if (Migrations.Any(x => x.Difference == SchemaPatchDifference.Update)) - { - return SchemaPatchDifference.Update; - } - - if (Migrations.Any(x => x.Difference == SchemaPatchDifference.Create)) - { - return SchemaPatchDifference.Create; - } - - return SchemaPatchDifference.None; - } - } - - public void WriteScript(TextWriter writer, Action writeStep, bool transactionalScript = true) - { - if (transactionalScript) - { - writer.WriteLine("DO LANGUAGE plpgsql $tran$"); - writer.WriteLine("BEGIN"); - writer.WriteLine(""); - } - - if (Rules.Role.IsNotEmpty()) - { - writer.WriteLine($"SET ROLE {Rules.Role};"); - writer.WriteLine(""); - } - - writeStep(writer); - - if (Rules.Role.IsNotEmpty()) - { - writer.WriteLine($"RESET ROLE;"); - writer.WriteLine(""); - } - - if (transactionalScript) - { - writer.WriteLine(""); - writer.WriteLine("END;"); - writer.WriteLine("$tran$;"); - } - } - - public void WriteFile(string file, string sql, bool transactionalScript) - { - using (var stream = new FileStream(file, FileMode.Create)) - { - var writer = new StreamWriter(stream) { AutoFlush = true }; - - WriteScript(writer, w => w.WriteLine(sql), transactionalScript); - - stream.Flush(true); - } - } - - public void WriteUpdateFile(string file, bool transactionalScript = true) - { - WriteFile(file, UpdateDDL, transactionalScript); - } - - public void WriteRollbackFile(string file, bool transactionalScript = true) - { - WriteFile(file, RollbackDDL, transactionalScript); - } - - public readonly IList Migrations = new List(); - - public void Log(ISchemaObject schemaObject, SchemaPatchDifference difference) - { - var migration = new ObjectMigration(schemaObject, difference); - Migrations.Add(migration); - } - - public void AssertPatchingIsValid(AutoCreate autoCreate) - { - if (autoCreate == AutoCreate.All) - return; - - var difference = Difference; - - if (difference == SchemaPatchDifference.None) - return; - - if (difference == SchemaPatchDifference.Invalid) - { - var invalidObjects = Migrations.Where(x => x.Difference == SchemaPatchDifference.Invalid).Select(x => x.SchemaObject.Identifier.ToString()).Join(", "); - throw new InvalidOperationException($"Marten cannot derive updates for objects {invalidObjects}"); - } - - if (difference == SchemaPatchDifference.Update && autoCreate == AutoCreate.CreateOnly) - { - var updates = Migrations.Where(x => x.Difference == SchemaPatchDifference.Update).ToArray(); - if (updates.Any()) - { - throw new InvalidOperationException($"Marten cannot apply updates in CreateOnly mode to existing items {updates.Select(x => x.SchemaObject.Identifier.QualifiedName).Join(", ")}"); - } - } - } - - public void Apply(NpgsqlConnection conn, AutoCreate autoCreate, ISchemaObject[] schemaObjects) - { - if (!schemaObjects.Any()) - return; - - // Let folks just fail if anything is wrong. - // Per https://github.com/JasperFx/marten/issues/711 - if (autoCreate == AutoCreate.None) - return; - - var cmd = conn.CreateCommand(); - var builder = new CommandBuilder(cmd); - - foreach (var schemaObject in schemaObjects) - { - schemaObject.ConfigureQueryCommand(builder); - } - - cmd.CommandText = builder.ToString(); - - try - { - using (var reader = cmd.ExecuteReader()) - { - apply(schemaObjects[0], autoCreate, reader); - for (var i = 1; i < schemaObjects.Length; i++) - { - reader.NextResult(); - apply(schemaObjects[i], autoCreate, reader); - } - } - } - catch (Exception e) - { - throw MartenCommandExceptionFactory.Create(cmd, e); - } - - AssertPatchingIsValid(autoCreate); - } - - private void apply(ISchemaObject schemaObject, AutoCreate autoCreate, DbDataReader reader) - { - var difference = schemaObject.CreatePatch(reader, this, autoCreate); - Migrations.Add(new ObjectMigration(schemaObject, difference)); - } - - public void Apply(NpgsqlConnection connection, AutoCreate autoCreate, ISchemaObject schemaObject) - { - Apply(connection, autoCreate, new ISchemaObject[] { schemaObject }); - } - } - - public class ObjectMigration - { - public ISchemaObject SchemaObject { get; } - public SchemaPatchDifference Difference { get; } - - public ObjectMigration(ISchemaObject schemaObject, SchemaPatchDifference difference) - { - SchemaObject = schemaObject; - Difference = difference; - } - } -} diff --git a/src/Marten/Schema/SubClassMapping.cs b/src/Marten/Schema/SubClassMapping.cs index ee16280f8e..b356b1b203 100644 --- a/src/Marten/Schema/SubClassMapping.cs +++ b/src/Marten/Schema/SubClassMapping.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Reflection; using Baseline; +using Baseline.Reflection; +using Weasel.Postgresql; using Marten.Util; namespace Marten.Schema @@ -57,8 +59,14 @@ private static string GetTypeMartenAlias(Type documentType) private static string GetTypeMartenAlias(MappedType documentType) { + var typeName = documentType.Type.Name; + + if (documentType.Type.GetTypeInfo().IsGenericType) + typeName = documentType.Type.GetPrettyName(); return documentType.Alias ?? - documentType.Type.GetTypeName() + (documentType.Type.IsNested + ? $"{documentType.Type.DeclaringType.Name}.{typeName}" + : typeName) .Replace(".", "_") .SplitCamelCase() .Replace(" ", "_") diff --git a/src/Marten/SecurityRights.cs b/src/Marten/SecurityRights.cs deleted file mode 100644 index f012a76290..0000000000 --- a/src/Marten/SecurityRights.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Marten -{ - public enum SecurityRights - { - /// - /// Upsert functions will execute with the rights of the current Postgresql user. This is the default - /// in both Marten and Postgresql. - /// - Invoker, - - /// - /// Upsert functions will execute with the rights of the Postgresql user that created the schema - /// objects. - /// - Definer - } -} diff --git a/src/Marten/Services/CommandRunnerExtensions.cs b/src/Marten/Services/CommandRunnerExtensions.cs index b389d3857e..cf692b7e6b 100644 --- a/src/Marten/Services/CommandRunnerExtensions.cs +++ b/src/Marten/Services/CommandRunnerExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Baseline; using Marten.Linq; +using Weasel.Postgresql; using Marten.Util; using Npgsql; #nullable enable diff --git a/src/Marten/Services/Diagnostics.cs b/src/Marten/Services/Diagnostics.cs index 274b426842..4a354889ab 100644 --- a/src/Marten/Services/Diagnostics.cs +++ b/src/Marten/Services/Diagnostics.cs @@ -2,6 +2,7 @@ using System.Net; using Marten.Internal; using Marten.Linq; +using Weasel.Postgresql; using Marten.Util; using Npgsql; #nullable enable diff --git a/src/Marten/Services/EventStreamUnexpectedMaxEventIdExceptionTransform.cs b/src/Marten/Services/EventStreamUnexpectedMaxEventIdExceptionTransform.cs index 0a6e79a7f2..b8aced8e23 100644 --- a/src/Marten/Services/EventStreamUnexpectedMaxEventIdExceptionTransform.cs +++ b/src/Marten/Services/EventStreamUnexpectedMaxEventIdExceptionTransform.cs @@ -1,11 +1,13 @@ using System; using System.Text.RegularExpressions; +using Baseline.Exceptions; using Npgsql; namespace Marten.Services { internal class EventStreamUnexpectedMaxEventIdExceptionTransform: IExceptionTransform { + [Obsolete("let's get rid of this")] public static readonly EventStreamUnexpectedMaxEventIdExceptionTransform Instance = new EventStreamUnexpectedMaxEventIdExceptionTransform(); private const string ExpectedMessage = "duplicate key value violates unique constraint \"pk_mt_events_stream_and_version\""; diff --git a/src/Marten/Services/IExceptionTransform.cs b/src/Marten/Services/IExceptionTransform.cs deleted file mode 100644 index 6d6af3cc60..0000000000 --- a/src/Marten/Services/IExceptionTransform.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Marten.Services -{ - public interface IExceptionTransform - { - bool TryTransform(Exception original, out Exception transformed); - } -} \ No newline at end of file diff --git a/src/Marten/Services/Json/SerializerOptions.cs b/src/Marten/Services/Json/SerializerOptions.cs index b34c01b9f6..4607e28207 100644 --- a/src/Marten/Services/Json/SerializerOptions.cs +++ b/src/Marten/Services/Json/SerializerOptions.cs @@ -1,3 +1,5 @@ +using Weasel.Postgresql; + #nullable enable namespace Marten.Services.Json { diff --git a/src/Marten/Services/JsonNetSerializer.cs b/src/Marten/Services/JsonNetSerializer.cs index f4bd2e322e..7d9b1ef8d2 100644 --- a/src/Marten/Services/JsonNetSerializer.cs +++ b/src/Marten/Services/JsonNetSerializer.cs @@ -9,6 +9,7 @@ using Marten.Util; using Newtonsoft.Json; using Newtonsoft.Json.Converters; +using Weasel.Postgresql; using ConstructorHandling = Newtonsoft.Json.ConstructorHandling; namespace Marten.Services diff --git a/src/Marten/Services/ManagedConnection.cs b/src/Marten/Services/ManagedConnection.cs index 39414fdda2..a102023e26 100644 --- a/src/Marten/Services/ManagedConnection.cs +++ b/src/Marten/Services/ManagedConnection.cs @@ -201,29 +201,13 @@ public NpgsqlConnection Connection } - + [Obsolete("Replace with ExceptionTransforms from Baseline")] private void handleCommandException(NpgsqlCommand cmd, Exception e) { this.SafeDispose(); Logger.LogFailure(cmd, e); - if ((e as PostgresException)?.SqlState == PostgresErrorCodes.SerializationFailure) - { - throw new ConcurrentUpdateException(e); - } - - // TODO -- this is fine for now, but we might wanna do more to centralize the - // exception transformations - if (EventStreamUnexpectedMaxEventIdExceptionTransform.Instance.TryTransform(e, - out var eventStreamUnexpectedMaxEventIdException)) - { - throw eventStreamUnexpectedMaxEventIdException; - } - - if (e is NpgsqlException) - { - throw MartenCommandExceptionFactory.Create(cmd, e); - } + MartenExceptionTransformer.WrapAndThrow(cmd, e); } public int Execute(NpgsqlCommand cmd) diff --git a/src/Marten/Services/MetadataCache.cs b/src/Marten/Services/MetadataCache.cs index 2b2470fc4c..e6dda23c0f 100644 --- a/src/Marten/Services/MetadataCache.cs +++ b/src/Marten/Services/MetadataCache.cs @@ -1,6 +1,7 @@ using Marten.Storage; using Marten.Util; using System; +using Baseline.ImTools; using Marten.Storage.Metadata; namespace Marten.Services diff --git a/src/Marten/Services/SystemTextJsonSerializer.cs b/src/Marten/Services/SystemTextJsonSerializer.cs index 0565476fdd..b85e0dceca 100644 --- a/src/Marten/Services/SystemTextJsonSerializer.cs +++ b/src/Marten/Services/SystemTextJsonSerializer.cs @@ -9,6 +9,7 @@ using Marten.Services.Json; using Marten.Util; using Npgsql; +using Weasel.Postgresql; namespace Marten.Services { diff --git a/src/Marten/SortOrder.cs b/src/Marten/SortOrder.cs deleted file mode 100644 index fcf13ce312..0000000000 --- a/src/Marten/SortOrder.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Marten -{ - /// - /// Specifies the direction used to sort items - /// - public enum SortOrder - { - /// - /// Sorts in ascending order, from smallest to largest - /// - Asc, - - /// - /// Sorts in descending order, from largest to smallest - /// - Desc, - } -} diff --git a/src/Marten/Storage/BulkInsertion.cs b/src/Marten/Storage/BulkInsertion.cs index c43b02bbdf..bd910bd0fd 100644 --- a/src/Marten/Storage/BulkInsertion.cs +++ b/src/Marten/Storage/BulkInsertion.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using Baseline; +using Weasel.Postgresql; using Marten.Schema.BulkLoading; using Marten.Util; using Npgsql; @@ -157,7 +158,7 @@ private void bulkInsertDocuments(IReadOnlyCollection documents, int batchS if (mode != BulkInsertMode.InsertsOnly) { var sql = loader.CreateTempTableForCopying(); - conn.RunSql(sql); + conn.CreateCommand(sql).ExecuteNonQuery(); } if (documents.Count <= batchSize) @@ -185,14 +186,14 @@ private void bulkInsertDocuments(IReadOnlyCollection documents, int batchS { var copy = loader.CopyNewDocumentsFromTempTable(); - conn.RunSql(copy); + conn.CreateCommand(copy).ExecuteNonQuery(); } else if (mode == BulkInsertMode.OverwriteExisting) { var overwrite = loader.OverwriteDuplicatesFromTempTable(); var copy = loader.CopyNewDocumentsFromTempTable(); - conn.RunSql(overwrite, copy); + conn.CreateCommand(overwrite + ";" + copy).ExecuteNonQuery(); } } diff --git a/src/Marten/Storage/DataColumn.cs b/src/Marten/Storage/DataColumn.cs index c4c65ca337..2d6d9e569f 100644 --- a/src/Marten/Storage/DataColumn.cs +++ b/src/Marten/Storage/DataColumn.cs @@ -1,13 +1,15 @@ using LamarCodeGeneration; using Marten.Internal.CodeGeneration; using Marten.Schema; +using Weasel.Postgresql.Tables; namespace Marten.Storage { internal class DataColumn: TableColumn, ISelectableColumn { - public DataColumn() : base("data", "JSONB", "NOT NULL") + public DataColumn() : base("data", "JSONB") { + AllowNulls = false; } public void GenerateCode(StorageStyle storageStyle, GeneratedType generatedType, GeneratedMethod async, diff --git a/src/Marten/Storage/DefaultTenancy.cs b/src/Marten/Storage/DefaultTenancy.cs index 9af36a0d4c..dd466e5e71 100644 --- a/src/Marten/Storage/DefaultTenancy.cs +++ b/src/Marten/Storage/DefaultTenancy.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Data; using System.Threading; using System.Threading.Tasks; @@ -11,6 +12,10 @@ using Marten.Services; using Marten.Transforms; using Npgsql; +using Weasel.Postgresql; +using Weasel.Postgresql.Functions; +using Weasel.Postgresql.Tables; + #nullable enable namespace Marten.Storage { @@ -49,8 +54,6 @@ public LightweightTenant(string tenantId, ITenant inner, IRetryPolicy retryPolic _retryPolicy = retryPolicy; } - public IDbObjects DbObjects => _inner.DbObjects; - public string TenantId { get; } public IDocumentStorage StorageFor() where T : notnull @@ -86,9 +89,9 @@ public IManagedConnection OpenConnection(CommandRunnerMode mode = CommandRunnerM return _inner.OpenConnection(mode, isolationLevel, timeout); } - public void ResetHiloSequenceFloor(long floor) + public Task ResetHiloSequenceFloor(long floor) { - _inner.ResetHiloSequenceFloor(floor); + return _inner.ResetHiloSequenceFloor(floor); } public NpgsqlConnection CreateConnection() @@ -97,5 +100,29 @@ public NpgsqlConnection CreateConnection() } public IProviderGraph Providers => _inner.Providers; + public Task> SchemaTables() + { + return _inner.SchemaTables(); + } + + public Task> DocumentTables() + { + return _inner.DocumentTables(); + } + + public Task> Functions() + { + return _inner.Functions(); + } + + public Task DefinitionForFunction(DbObjectName function) + { + return _inner.DefinitionForFunction(function); + } + + public Task ExistingTableFor(Type type) + { + return _inner.ExistingTableFor(type); + } } } diff --git a/src/Marten/Storage/DocumentTable.cs b/src/Marten/Storage/DocumentTable.cs index 850f94970a..aff02d6b3c 100644 --- a/src/Marten/Storage/DocumentTable.cs +++ b/src/Marten/Storage/DocumentTable.cs @@ -5,6 +5,8 @@ using Marten.Internal.CodeGeneration; using Marten.Schema; using Marten.Storage.Metadata; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; namespace Marten.Storage { @@ -21,15 +23,13 @@ public DocumentTable(DocumentMapping mapping): base(mapping.TableName) var idColumn = new IdColumn(mapping); + AddColumn(idColumn).AsPrimaryKey(); + if (mapping.TenancyStyle == TenancyStyle.Conjoined) { - AddPrimaryKeys(new List {idColumn, mapping.Metadata.TenantId}); + AddColumn(mapping.Metadata.TenantId).AsPrimaryKey(); - Indexes.Add(new IndexDefinition(mapping, TenantIdColumn.Name)); - } - else - { - AddPrimaryKey(idColumn); + Indexes.Add(new DocumentIndex(mapping, TenantIdColumn.Name)); } AddColumn(); @@ -47,20 +47,23 @@ public DocumentTable(DocumentMapping mapping): base(mapping.TableName) if (mapping.IsHierarchy()) { - Indexes.Add(new IndexDefinition(_mapping, SchemaConstants.DocumentTypeColumn)); + Indexes.Add(new DocumentIndex(_mapping, SchemaConstants.DocumentTypeColumn)); AddColumn(_mapping.Metadata.DocumentType); } if (mapping.DeleteStyle == DeleteStyle.SoftDelete) { AddColumn(_mapping.Metadata.IsSoftDeleted); - Indexes.Add(new IndexDefinition(mapping, SchemaConstants.DeletedColumn)); + Indexes.Add(new DocumentIndex(mapping, SchemaConstants.DeletedColumn)); AddColumn(_mapping.Metadata.SoftDeletedAt); } Indexes.AddRange(mapping.Indexes); ForeignKeys.AddRange(mapping.ForeignKeys); + + // Compatibility with Marten rules + PrimaryKeyName = $"{Identifier.Name}_pkey"; } public void AddIfActive(MetadataColumn column) @@ -82,7 +85,7 @@ public string BuildTemplate(string template) .Replace(DdlRules.METADATA_COLUMNS, Columns.OfType().Select(x => x.Name).Join(", ")); } - public void WriteTemplate(DdlTemplate template, StringWriter writer) + public void WriteTemplate(DdlTemplate template, TextWriter writer) { var text = template?.TableCreation; if (text.IsNotEmpty()) diff --git a/src/Marten/Storage/DropFunction.cs b/src/Marten/Storage/DropFunction.cs deleted file mode 100644 index f024aa46a3..0000000000 --- a/src/Marten/Storage/DropFunction.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Data.Common; -using System.IO; -using Marten.Schema; - -namespace Marten.Storage -{ - public class DropFunction: SystemFunction - { - public DropFunction(string schema, string functionName, string args) : - base(schema, functionName, args, true) - { - } - - public override void Write(DdlRules rules, StringWriter writer) - { - writer.WriteLine(_dropSql); - } - } -} diff --git a/src/Marten/Storage/DuplicatedFieldColumn.cs b/src/Marten/Storage/DuplicatedFieldColumn.cs index 1e1536a4d8..62576a86cf 100644 --- a/src/Marten/Storage/DuplicatedFieldColumn.cs +++ b/src/Marten/Storage/DuplicatedFieldColumn.cs @@ -1,4 +1,5 @@ using Marten.Linq.Fields; +using Weasel.Postgresql.Tables; namespace Marten.Storage { @@ -9,9 +10,10 @@ internal class DuplicatedFieldColumn: TableColumn private const string NotNullConstraint = "NOT NULL"; - public DuplicatedFieldColumn(DuplicatedField field) : base(field.ColumnName, field.PgType, field.NotNull ? NotNullConstraint : NullConstraint) + public DuplicatedFieldColumn(DuplicatedField field) : base(field.ColumnName, field.PgType) { - CanAdd = true; + AllowNulls = !field.NotNull; + _field = field; } diff --git a/src/Marten/Storage/FeatureSchemaExtensions.cs b/src/Marten/Storage/FeatureSchemaExtensions.cs new file mode 100644 index 0000000000..99a5f0b88d --- /dev/null +++ b/src/Marten/Storage/FeatureSchemaExtensions.cs @@ -0,0 +1,35 @@ +using System; +using System.IO; +using System.Linq; +using Marten.Exceptions; +using Weasel.Postgresql; +using Npgsql; + +namespace Marten.Storage +{ + internal static class FeatureSchemaExtensions + { + public static void AssertValidNames(this IFeatureSchema schema, StoreOptions options) + { + AssertValidNames(schema.Objects, options); + } + + public static void AssertValidNames(this ISchemaObject[] schemaObjects, StoreOptions options) + { + foreach (var objectName in schemaObjects.SelectMany(x => x.AllNames())) + { + options.AssertValidIdentifier(objectName.Name); + } + } + + public static void Write(this IFeatureSchema schema, DdlRules rules, TextWriter writer) + { + foreach (var schemaObject in schema.Objects) + { + schemaObject.WriteCreateStatement(rules, writer); + } + + schema.WritePermissions(rules, writer); + } + } +} diff --git a/src/Marten/Storage/Function.cs b/src/Marten/Storage/Function.cs deleted file mode 100644 index 0f162b4553..0000000000 --- a/src/Marten/Storage/Function.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System.Collections.Generic; -using System.Data.Common; -using System.IO; -using Marten.Schema; -using Marten.Util; -using Npgsql; - -namespace Marten.Storage -{ - /// - /// Base class for an ISchemaObject manager for a Postgresql function - /// - public abstract class Function: ISchemaObject - { - public DbObjectName Identifier { get; } - public bool IsRemoved { get; } - - protected Function(DbObjectName identifier, bool isRemoved = false) - { - Identifier = identifier; - IsRemoved = isRemoved; - } - - /// - /// Override to write the actual DDL code - /// - /// - /// - public abstract void Write(DdlRules rules, StringWriter writer); - - public void ConfigureQueryCommand(CommandBuilder builder) - { - var schemaParam = builder.AddParameter(Identifier.Schema).ParameterName; - var nameParam = builder.AddParameter(Identifier.Name).ParameterName; - - builder.Append($@" -SELECT pg_get_functiondef(pg_proc.oid) -FROM pg_proc JOIN pg_namespace as ns ON pg_proc.pronamespace = ns.oid WHERE ns.nspname = :{schemaParam} and proname = :{nameParam}; - -SELECT format('DROP FUNCTION IF EXISTS %s.%s(%s);' - ,n.nspname - ,p.proname - ,pg_get_function_identity_arguments(p.oid)) -FROM pg_proc p -LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace -WHERE p.proname = :{nameParam} -AND n.nspname = :{schemaParam}; -"); - } - - public SchemaPatchDifference CreatePatch(DbDataReader reader, SchemaPatch patch, AutoCreate autoCreate) - { - var diff = fetchDelta(reader, patch.Rules); - - if (diff == null && IsRemoved) - { - return SchemaPatchDifference.None; - } - - if (diff == null) - { - Write(patch.Rules, patch.UpWriter); - WriteDropStatement(patch.Rules, patch.DownWriter); - - return SchemaPatchDifference.Create; - } - - if (diff.Removed) - { - Write(patch.Rules, patch.UpWriter); - return SchemaPatchDifference.Update; - } - - if (diff.AllNew) - { - Write(patch.Rules, patch.UpWriter); - WriteDropStatement(patch.Rules, patch.DownWriter); - - return SchemaPatchDifference.Create; - } - - if (diff.HasChanged) - { - diff.WritePatch(patch); - - return SchemaPatchDifference.Update; - } - - return SchemaPatchDifference.None; - } - - public IEnumerable AllNames() - { - yield return Identifier; - } - - protected FunctionDelta fetchDelta(DbDataReader reader, DdlRules rules) - { - if (!reader.Read()) - { - reader.NextResult(); - return null; - } - - var existingFunction = reader.GetString(0); - - if (string.IsNullOrEmpty(existingFunction)) - return null; - - reader.NextResult(); - var drops = new List(); - while (reader.Read()) - { - drops.Add(reader.GetString(0)); - } - - var actualBody = new FunctionBody(Identifier, drops.ToArray(), existingFunction.TrimEnd() + ";"); - - var expectedBody = IsRemoved ? null : ToBody(rules); - - return new FunctionDelta(expectedBody, actualBody); - } - - public FunctionBody ToBody(DdlRules rules) - { - var dropSql = toDropSql(); - - var writer = new StringWriter(); - Write(rules, writer); - - return new FunctionBody(Identifier, new string[] { dropSql }, writer.ToString()); - } - - /// - /// Override to customize the DROP statements for this function - /// - /// - protected abstract string toDropSql(); - - public void WriteDropStatement(DdlRules rules, StringWriter writer) - { - var dropSql = toDropSql(); - writer.WriteLine(dropSql); - } - - public FunctionDelta FetchDelta(NpgsqlConnection conn, DdlRules rules) - { - var cmd = conn.CreateCommand(); - var builder = new CommandBuilder(cmd); - - ConfigureQueryCommand(builder); - - cmd.CommandText = builder.ToString(); - - using (var reader = cmd.ExecuteReader()) - { - return fetchDelta(reader, rules); - } - } - } -} diff --git a/src/Marten/Storage/FunctionBody.cs b/src/Marten/Storage/FunctionBody.cs deleted file mode 100644 index c73268b0b4..0000000000 --- a/src/Marten/Storage/FunctionBody.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using Baseline; -using Marten.Schema; - -namespace Marten.Storage -{ - public class FunctionBody - { - public DbObjectName Function { get; set; } - public string[] DropStatements { get; set; } - public string Body { get; set; } - - public string Signature() - { - var functionIndex = Body.IndexOf("FUNCTION", StringComparison.OrdinalIgnoreCase); - var openParen = Body.IndexOf("("); - var closeParen = Body.IndexOf(")"); - - var args = Body.Substring(openParen + 1, closeParen - openParen - 1).Trim() - .Split(',').Select(x => - { - var parts = x.Trim().Split(' '); - return parts.Skip(1).Join(" "); - }).Join(", "); - - var nameStart = functionIndex + "function".Length; - var funcName = Body.Substring(nameStart, openParen - nameStart).Trim(); - - return $"{funcName}({args})"; - } - - public string ToOwnershipCommand(string owner) - { - return $"ALTER FUNCTION {Signature()} OWNER TO \"{owner}\";"; - } - - public FunctionBody(DbObjectName function, string[] dropStatements, string body) - { - Function = function; - DropStatements = dropStatements; - Body = body; - } - - public string BuildTemplate(string template) - { - return template - .Replace(DdlRules.SCHEMA, Function.Schema) - .Replace(DdlRules.FUNCTION, Function.Name) - .Replace(DdlRules.SIGNATURE, Signature()) - ; - } - - public void WriteTemplate(DdlTemplate template, StringWriter writer) - { - var text = template?.FunctionCreation; - if (text.IsNotEmpty()) - { - writer.WriteLine(BuildTemplate(text)); - } - } - } -} diff --git a/src/Marten/Storage/FunctionDelta.cs b/src/Marten/Storage/FunctionDelta.cs deleted file mode 100644 index fc46dbd4b6..0000000000 --- a/src/Marten/Storage/FunctionDelta.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using Baseline; -using Marten.Schema; -using Marten.Util; - -namespace Marten.Storage -{ - public class FunctionDelta - { - public FunctionBody Expected { get; set; } - public FunctionBody Actual { get; set; } - - public FunctionDelta(FunctionBody expected, FunctionBody actual) - { - Expected = expected; - Actual = actual; - } - - public bool AllNew => Actual == null; - - public bool Removed => Expected == null && Actual != null; - - public bool HasChanged => AllNew || (Expected != null && !Expected.Body.CanonicizeSql().Equals(Actual.Body.CanonicizeSql(), StringComparison.OrdinalIgnoreCase)); - - public void WritePatch(SchemaPatch patch) - { - if (AllNew) - { - patch.Updates.Apply(this, Expected.Body); - - Expected.DropStatements.Each(drop => - { - if (!drop.EndsWith("cascade", StringComparison.OrdinalIgnoreCase)) - { - drop = drop.TrimEnd(';') + " cascade;"; - } - - patch.Rollbacks.Apply(this, drop); - }); - } - else if (HasChanged) - { - Actual.DropStatements.Each(drop => - { - if (!drop.EndsWith("cascade", StringComparison.OrdinalIgnoreCase)) - { - drop = drop.TrimEnd(';') + " cascade;"; - } - - patch.Updates.Apply(this, drop); - }); - - patch.Updates.Apply(this, Expected.Body); - - Expected.DropStatements.Each(drop => - { - patch.Rollbacks.Apply(this, drop); - }); - - patch.Rollbacks.Apply(this, Actual.Body); - } - } - - public override string ToString() - { - return Expected.Function.QualifiedName + " Diff"; - } - } -} diff --git a/src/Marten/Storage/IFeatureSchema.cs b/src/Marten/Storage/IFeatureSchema.cs index 45d49d5230..0e04ecac14 100644 --- a/src/Marten/Storage/IFeatureSchema.cs +++ b/src/Marten/Storage/IFeatureSchema.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Marten.Exceptions; -using Marten.Util; -using Npgsql; +using Weasel.Postgresql; + #nullable enable + namespace Marten.Storage { #region sample_IFeatureSchema @@ -23,13 +23,6 @@ public interface IFeatureSchema /// IEnumerable DependentTypes(); - /// - /// Should this feature be active based on the current options? - /// - /// - /// - bool IsActive(StoreOptions options); - /// /// All the schema objects in this feature /// @@ -52,7 +45,7 @@ public interface IFeatureSchema /// /// /// - void WritePermissions(DdlRules rules, StringWriter writer); + void WritePermissions(DdlRules rules, TextWriter writer); } #endregion sample_IFeatureSchema @@ -63,12 +56,10 @@ public interface IFeatureSchema public abstract class FeatureSchemaBase: IFeatureSchema { public string Identifier { get; } - public StoreOptions Options { get; } - protected FeatureSchemaBase(string identifier, StoreOptions options) + protected FeatureSchemaBase(string identifier) { Identifier = identifier; - Options = options; } public virtual IEnumerable DependentTypes() @@ -76,80 +67,15 @@ public virtual IEnumerable DependentTypes() return new Type[0]; } - public virtual bool IsActive(StoreOptions options) - { - return true; - } - protected abstract IEnumerable schemaObjects(); public ISchemaObject[] Objects => schemaObjects().ToArray(); public virtual Type StorageType => GetType(); - public virtual void WritePermissions(DdlRules rules, StringWriter writer) + public virtual void WritePermissions(DdlRules rules, TextWriter writer) { // Nothing } } - - public static class FeatureSchemaExtensions - { - public static void AssertValidNames(this IFeatureSchema schema, StoreOptions options) - { - AssertValidNames(schema.Objects, options); - } - - public static void AssertValidNames(this ISchemaObject[] schemaObjects, StoreOptions options) - { - foreach (var objectName in schemaObjects.SelectMany(x => x.AllNames())) - { - options.AssertValidIdentifier(objectName.Name); - } - } - - public static string ToDDL(this ISchemaObject @object, DdlRules rules) - { - var writer = new StringWriter(); - @object.Write(rules, writer); - - return writer.ToString(); - } - - public static void Write(this IFeatureSchema schema, DdlRules rules, StringWriter writer) - { - foreach (var schemaObject in schema.Objects) - { - schemaObject.Write(rules, writer); - } - - schema.WritePermissions(rules, writer); - } - - public static void WriteDropStatements(this IFeatureSchema schema, DdlRules rules, StringWriter writer) - { - foreach (var schemaObject in schema.Objects) - { - schemaObject.WriteDropStatement(rules, writer); - } - } - - public static void RemoveAllObjects(this IFeatureSchema schema, DdlRules rules, NpgsqlConnection conn) - { - var writer = new StringWriter(); - schema.WriteDropStatements(rules, writer); - - var sql = writer.ToString(); - var cmd = conn.CreateCommand(sql); - - try - { - cmd.ExecuteNonQuery(); - } - catch (Exception e) - { - throw MartenCommandExceptionFactory.Create(cmd, e); - } - } - } } diff --git a/src/Marten/Storage/IIndexDefinition.cs b/src/Marten/Storage/IIndexDefinition.cs deleted file mode 100644 index 562f2ba444..0000000000 --- a/src/Marten/Storage/IIndexDefinition.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Marten.Schema; - -namespace Marten.Storage -{ - public interface IIndexDefinition - { - string IndexName { get; } - - string ToDDL(); - - bool Matches(ActualIndex index); - } -} diff --git a/src/Marten/Storage/ISchemaObject.cs b/src/Marten/Storage/ISchemaObject.cs deleted file mode 100644 index 289c5e5202..0000000000 --- a/src/Marten/Storage/ISchemaObject.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using System.Data.Common; -using System.IO; -using Marten.Schema; -using Marten.Util; - -namespace Marten.Storage -{ - public interface ISchemaObject - { - void Write(DdlRules rules, StringWriter writer); - - void WriteDropStatement(DdlRules rules, StringWriter writer); - - DbObjectName Identifier { get; } - - void ConfigureQueryCommand(CommandBuilder builder); - - SchemaPatchDifference CreatePatch(DbDataReader reader, SchemaPatch patch, AutoCreate autoCreate); - - IEnumerable AllNames(); - } -} diff --git a/src/Marten/Storage/ITenant.cs b/src/Marten/Storage/ITenant.cs index 03127dc282..8b0e48aac0 100644 --- a/src/Marten/Storage/ITenant.cs +++ b/src/Marten/Storage/ITenant.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Data; using System.Threading; using System.Threading.Tasks; @@ -10,6 +11,10 @@ using Marten.Services; using Marten.Transforms; using Npgsql; +using Weasel.Postgresql; +using Weasel.Postgresql.Functions; +using Weasel.Postgresql.Tables; + #nullable enable namespace Marten.Storage { @@ -35,12 +40,6 @@ public interface ITenant : ITenantStorage { string TenantId { get; } - /// - /// Query against the actual Postgresql database schema objects - /// - [Obsolete("Make this a method? Put on Schema?")] - IDbObjects DbObjects { get; } - /// /// Retrieves or generates the active IDocumentStorage object /// for the given document type @@ -72,7 +71,7 @@ public interface ITenant : ITenantStorage /// /// /// - void ResetHiloSequenceFloor(long floor); + Task ResetHiloSequenceFloor(long floor); /// /// Fetch a connection to the tenant database @@ -83,6 +82,43 @@ public interface ITenant : ITenantStorage IProviderGraph Providers { get; } + + + + /// + /// Fetches a list of all of the Marten generated tables + /// in the database + /// + /// + Task> SchemaTables(); + + /// + /// Fetches a list of the Marten document tables + /// in the database + /// + /// + Task> DocumentTables(); + + /// + /// Fetches a list of functions generated by Marten + /// in the database + /// + /// + Task> Functions(); + + /// + /// Query for the designated FunctionBody + /// + /// + /// + Task DefinitionForFunction(DbObjectName function); + + /// + /// Retrieve the existing Table for the document type + /// + /// + /// + Task
ExistingTableFor(Type type); } } diff --git a/src/Marten/Storage/IdColumn.cs b/src/Marten/Storage/IdColumn.cs index 81d21d9193..00be5857a9 100644 --- a/src/Marten/Storage/IdColumn.cs +++ b/src/Marten/Storage/IdColumn.cs @@ -2,6 +2,8 @@ using Marten.Internal.CodeGeneration; using Marten.Schema; using Marten.Util; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; namespace Marten.Storage { diff --git a/src/Marten/Storage/InsertFunction.cs b/src/Marten/Storage/InsertFunction.cs index 927cc71619..3e2101d321 100644 --- a/src/Marten/Storage/InsertFunction.cs +++ b/src/Marten/Storage/InsertFunction.cs @@ -11,7 +11,8 @@ public InsertFunction(DocumentMapping mapping) : base(mapping, mapping.InsertFun { } - protected override void writeFunction(StringWriter writer, string argList, string securityDeclaration, string inserts, string valueList, + protected override void writeFunction(TextWriter writer, string argList, string securityDeclaration, + string inserts, string valueList, string updates) { var versionArg = _mapping.Metadata.Version.Enabled diff --git a/src/Marten/Storage/Metadata/DeletedAtColumn.cs b/src/Marten/Storage/Metadata/DeletedAtColumn.cs index 46ff73ea74..1de9b83379 100644 --- a/src/Marten/Storage/Metadata/DeletedAtColumn.cs +++ b/src/Marten/Storage/Metadata/DeletedAtColumn.cs @@ -10,8 +10,7 @@ internal class DeletedAtColumn: MetadataColumn , ISelectableCol { public DeletedAtColumn(): base(SchemaConstants.DeletedAtColumn, x => x.DeletedAt) { - CanAdd = true; - Directive = "NULL"; + AllowNulls = true; } public void GenerateCode(StorageStyle storageStyle, GeneratedType generatedType, GeneratedMethod async, GeneratedMethod sync, diff --git a/src/Marten/Storage/Metadata/DocumentTypeColumn.cs b/src/Marten/Storage/Metadata/DocumentTypeColumn.cs index e8c1f3f5f8..673fd0255e 100644 --- a/src/Marten/Storage/Metadata/DocumentTypeColumn.cs +++ b/src/Marten/Storage/Metadata/DocumentTypeColumn.cs @@ -1,6 +1,7 @@ using LamarCodeGeneration; using Marten.Internal.CodeGeneration; using Marten.Schema; +using Weasel.Postgresql.Tables; namespace Marten.Storage.Metadata { @@ -8,8 +9,7 @@ internal class DocumentTypeColumn: MetadataColumn, ISelectableColumn { public DocumentTypeColumn(DocumentMapping mapping) : base(SchemaConstants.DocumentTypeColumn, x => x.DocumentType) { - CanAdd = true; - Directive = $"DEFAULT '{mapping.AliasFor(mapping.DocumentType)}'"; + DefaultExpression = $"'{mapping.AliasFor(mapping.DocumentType)}'"; } public void GenerateCode(StorageStyle storageStyle, GeneratedType generatedType, GeneratedMethod async, diff --git a/src/Marten/Storage/Metadata/DotNetTypeColumn.cs b/src/Marten/Storage/Metadata/DotNetTypeColumn.cs index b899fc5554..328caad515 100644 --- a/src/Marten/Storage/Metadata/DotNetTypeColumn.cs +++ b/src/Marten/Storage/Metadata/DotNetTypeColumn.cs @@ -10,7 +10,7 @@ internal class DotNetTypeColumn: MetadataColumn, IEventTableColumn { public DotNetTypeColumn(): base(SchemaConstants.DotNetTypeColumn, x => x.DotNetType) { - CanAdd = true; + AllowNulls = true; } public void GenerateSelectorCodeSync(GeneratedMethod method, EventGraph graph, int index) diff --git a/src/Marten/Storage/Metadata/EntityMetadataQueryHandler.cs b/src/Marten/Storage/Metadata/EntityMetadataQueryHandler.cs index 40b8a0a8f8..2b1f97b6be 100644 --- a/src/Marten/Storage/Metadata/EntityMetadataQueryHandler.cs +++ b/src/Marten/Storage/Metadata/EntityMetadataQueryHandler.cs @@ -7,6 +7,7 @@ using Marten.Internal; using Marten.Internal.Storage; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Marten.Schema; using Marten.Util; @@ -27,7 +28,7 @@ public EntityMetadataQueryHandler(object id, IDocumentStorage storage) if (storage.Fields is DocumentMapping m) { - _columns = m.Schema.Table.OfType().ToArray(); + _columns = m.Schema.Table.Columns.OfType().ToArray(); } else { diff --git a/src/Marten/Storage/Metadata/LastModifiedColumn.cs b/src/Marten/Storage/Metadata/LastModifiedColumn.cs index 053098837b..5cc337ef93 100644 --- a/src/Marten/Storage/Metadata/LastModifiedColumn.cs +++ b/src/Marten/Storage/Metadata/LastModifiedColumn.cs @@ -2,6 +2,7 @@ using LamarCodeGeneration; using Marten.Internal.CodeGeneration; using Marten.Schema; +using Weasel.Postgresql.Tables; namespace Marten.Storage.Metadata { @@ -9,8 +10,7 @@ internal class LastModifiedColumn: MetadataColumn, ISelectableCo { public LastModifiedColumn() : base(SchemaConstants.LastModifiedColumn, x => x.LastModified) { - Directive = "DEFAULT transaction_timestamp()"; - CanAdd = true; + DefaultExpression = "(transaction_timestamp())"; Type = "timestamp with time zone"; } diff --git a/src/Marten/Storage/Metadata/MetadataColumn.cs b/src/Marten/Storage/Metadata/MetadataColumn.cs index 8476bad8e3..26a7e4022c 100644 --- a/src/Marten/Storage/Metadata/MetadataColumn.cs +++ b/src/Marten/Storage/Metadata/MetadataColumn.cs @@ -5,14 +5,16 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +using Baseline.Expressions; using LamarCodeGeneration; using Marten.Internal; using Marten.Internal.CodeGeneration; using Marten.Schema; using Marten.Schema.Arguments; using Marten.Util; +using Weasel.Postgresql; +using Weasel.Postgresql.Tables; using FindMembers = Marten.Linq.Parsing.FindMembers; -using LambdaBuilder = Marten.Util.LambdaBuilder; namespace Marten.Storage.Metadata { diff --git a/src/Marten/Storage/Metadata/SoftDeletedColumn.cs b/src/Marten/Storage/Metadata/SoftDeletedColumn.cs index 3df14e68ab..7e8bb839f2 100644 --- a/src/Marten/Storage/Metadata/SoftDeletedColumn.cs +++ b/src/Marten/Storage/Metadata/SoftDeletedColumn.cs @@ -1,6 +1,7 @@ using LamarCodeGeneration; using Marten.Internal.CodeGeneration; using Marten.Schema; +using Weasel.Postgresql.Tables; namespace Marten.Storage.Metadata { @@ -8,8 +9,7 @@ internal class SoftDeletedColumn: MetadataColumn, ISelectableColumn { public SoftDeletedColumn() : base(SchemaConstants.DeletedColumn, x => x.Deleted) { - Directive = "DEFAULT FALSE"; - CanAdd = true; + DefaultExpression = "FALSE"; } public void GenerateCode(StorageStyle storageStyle, GeneratedType generatedType, GeneratedMethod async, GeneratedMethod sync, diff --git a/src/Marten/Storage/Metadata/TenantIdColumn.cs b/src/Marten/Storage/Metadata/TenantIdColumn.cs index 05a4fafc75..0d95215a46 100644 --- a/src/Marten/Storage/Metadata/TenantIdColumn.cs +++ b/src/Marten/Storage/Metadata/TenantIdColumn.cs @@ -3,6 +3,7 @@ using Marten.Events.Schema; using Marten.Internal.CodeGeneration; using Marten.Schema; +using Weasel.Postgresql.Tables; namespace Marten.Storage.Metadata { @@ -12,8 +13,7 @@ internal class TenantIdColumn: MetadataColumn, ISelectableColumn, IEvent public TenantIdColumn() : base(Name, x => x.TenantId) { - CanAdd = true; - Directive = $"DEFAULT '{Tenancy.DefaultTenantId}'"; + DefaultExpression = $"'{Tenancy.DefaultTenantId}'"; } public void GenerateCode(StorageStyle storageStyle, GeneratedType generatedType, GeneratedMethod async, GeneratedMethod sync, diff --git a/src/Marten/Storage/OriginWriter.cs b/src/Marten/Storage/OriginWriter.cs index 7eea2800e2..ef11d81f7a 100644 --- a/src/Marten/Storage/OriginWriter.cs +++ b/src/Marten/Storage/OriginWriter.cs @@ -1,5 +1,9 @@ +using System; +using Weasel.Postgresql.Tables; + namespace Marten.Storage { + [Obsolete("Move this to Weasel")] internal static class OriginWriter { private static readonly string MartenFqn = typeof(IDocumentStore).AssemblyQualifiedName; diff --git a/src/Marten/Storage/OverwriteFunction.cs b/src/Marten/Storage/OverwriteFunction.cs index 4d4696ee65..d06d45e8d1 100644 --- a/src/Marten/Storage/OverwriteFunction.cs +++ b/src/Marten/Storage/OverwriteFunction.cs @@ -9,7 +9,8 @@ public OverwriteFunction(DocumentMapping mapping) : base(mapping, mapping.Overwr { } - protected override void writeFunction(StringWriter writer, string argList, string securityDeclaration, string inserts, string valueList, + protected override void writeFunction(TextWriter writer, string argList, string securityDeclaration, + string inserts, string valueList, string updates) { writer.WriteLine($@" diff --git a/src/Marten/Storage/SchemaPatchDifference.cs b/src/Marten/Storage/SchemaPatchDifference.cs deleted file mode 100644 index 3c6a903cb4..0000000000 --- a/src/Marten/Storage/SchemaPatchDifference.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Marten.Storage -{ - public enum SchemaPatchDifference - { - None = 3, - Create = 1, - Update = 2, - Invalid = 0 - } -} \ No newline at end of file diff --git a/src/Marten/Storage/Sequence.cs b/src/Marten/Storage/Sequence.cs deleted file mode 100644 index 46a0779ab0..0000000000 --- a/src/Marten/Storage/Sequence.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Generic; -using System.Data.Common; -using System.IO; -using Marten.Schema; -using Marten.Util; - -namespace Marten.Storage -{ - public class Sequence: ISchemaObject - { - public DbObjectName Identifier { get; } - - private long? _startWith; - - public Sequence(DbObjectName identifier) - { - Identifier = identifier; - } - - public Sequence(DbObjectName identifier, long startWith) - { - Identifier = identifier; - _startWith = startWith; - } - - public DbObjectName Owner { get; set; } - public string OwnerColumn { get; set; } - - public IEnumerable AllNames() - { - yield return Identifier; - } - - public void Write(DdlRules rules, StringWriter writer) - { - writer.WriteLine($"CREATE SEQUENCE {Identifier}{(_startWith.HasValue ? $" START {_startWith.Value}" : string.Empty)};"); - - if (Owner != null) - { - writer.WriteLine($"ALTER SEQUENCE {Identifier} OWNED BY {Owner}.{OwnerColumn};"); - } - } - - public void WriteDropStatement(DdlRules rules, StringWriter writer) - { - writer.WriteLine($"DROP SEQUENCE IF EXISTS {Identifier};"); - } - - public void ConfigureQueryCommand(CommandBuilder builder) - { - var schemaParam = builder.AddParameter(Identifier.Schema).ParameterName; - var nameParam = builder.AddParameter(Identifier.Name).ParameterName; - builder.Append($"select count(*) from information_schema.sequences where sequence_schema = :{schemaParam} and sequence_name = :{nameParam};"); - } - - public SchemaPatchDifference CreatePatch(DbDataReader reader, SchemaPatch patch, AutoCreate autoCreate) - { - if (!reader.Read() || reader.GetInt32(0) == 0) - { - Write(patch.Rules, patch.UpWriter); - return SchemaPatchDifference.Create; - } - - return SchemaPatchDifference.None; - } - } -} diff --git a/src/Marten/Storage/StorageFeatures.cs b/src/Marten/Storage/StorageFeatures.cs index 94120bd1fd..ec7bd49459 100644 --- a/src/Marten/Storage/StorageFeatures.cs +++ b/src/Marten/Storage/StorageFeatures.cs @@ -3,11 +3,13 @@ using System.Linq; using System.Reflection; using Baseline; +using Baseline.ImTools; using LamarCodeGeneration; using Marten.Events; using Marten.Exceptions; using Marten.Schema; -using Marten.Util; +using Weasel.Postgresql; + #nullable enable namespace Marten.Storage { @@ -244,13 +246,8 @@ public IEnumerable AllActiveFeatures(ITenant tenant) var mappings = _documentMappings.Value .Enumerate().Select(x => x.Value) .OrderBy(x => x.DocumentType.Name) - .TopologicalSort(m => - { - return m.ForeignKeys - .Where(x => x.ReferenceDocumentType != m.DocumentType && x.ReferenceDocumentType != null) - .Select(keyDefinition => keyDefinition.ReferenceDocumentType) - .Select(MappingFor); - }); + .TopologicalSort(m => m.ReferencedTypes() + .Select(MappingFor)); foreach (var mapping in mappings) { @@ -267,13 +264,13 @@ public IEnumerable AllActiveFeatures(ITenant tenant) yield return Transforms; } - if (_options.Events.As().IsActive(_options)) + if (_options.Events.As().IsActive(_options)) { yield return _options.EventGraph; } var custom = _features.Values - .Where(x => x.GetType().GetTypeInfo().Assembly != GetType().GetTypeInfo().Assembly).ToArray(); + .Where(x => x.GetType().Assembly != GetType().Assembly).ToArray(); foreach (var featureSchema in custom) { @@ -308,17 +305,18 @@ private IEnumerable determineTypeDependencies(Type type) if (documentMapping == null) return Enumerable.Empty(); - return documentMapping.ForeignKeys.Where(x => x.ReferenceDocumentType != type && x.ReferenceDocumentType != null) + + return documentMapping.ReferencedTypes() .SelectMany(keyDefinition => { var results = new List(); // If the reference type has sub-classes, also need to insert/update them first too - if (FindMapping(keyDefinition.ReferenceDocumentType) is DocumentMapping referenceMappingType && referenceMappingType.SubClasses.Any()) + if (FindMapping(keyDefinition) is DocumentMapping referenceMappingType && referenceMappingType.SubClasses.Any()) { results.AddRange(referenceMappingType.SubClasses.Select(s => s.DocumentType)); } - results.Add(keyDefinition.ReferenceDocumentType); + results.Add(keyDefinition); return results; }); } diff --git a/src/Marten/Storage/SystemFunction.cs b/src/Marten/Storage/SystemFunction.cs index 4d07eb0dca..192cd8ccdb 100644 --- a/src/Marten/Storage/SystemFunction.cs +++ b/src/Marten/Storage/SystemFunction.cs @@ -1,13 +1,13 @@ using System.IO; +using Weasel.Postgresql; using Marten.Schema; +using Weasel.Postgresql.Functions; namespace Marten.Storage { public class SystemFunction: Function { private readonly string _args; - protected readonly string _dropSql; - protected readonly DbObjectName _function; public SystemFunction(StoreOptions options, string functionName, string args, bool isRemoved=false) : this(options.DatabaseSchemaName, functionName, args, isRemoved) @@ -15,18 +15,17 @@ public SystemFunction(StoreOptions options, string functionName, string args, bo } public SystemFunction(string schema, string functionName, string args, bool isRemoved=false) - : base(new DbObjectName(schema, functionName), isRemoved) + : base(new DbObjectName(schema, functionName)) { + IsRemoved = isRemoved; _args = args; - _function = new DbObjectName(schema, functionName); - _dropSql = $"drop function if exists {schema}.{functionName}({args}) cascade;"; Name = functionName; } public string Name { get; } - public override void Write(DdlRules rules, StringWriter writer) + public override void WriteCreateStatement(DdlRules rules, TextWriter writer) { var body = SchemaBuilder.GetSqlScript(Identifier.Schema, Identifier.Name); @@ -34,9 +33,5 @@ public override void Write(DdlRules rules, StringWriter writer) writer.WriteLine(""); } - protected override string toDropSql() - { - return _dropSql; - } } } diff --git a/src/Marten/Storage/SystemFunctions.cs b/src/Marten/Storage/SystemFunctions.cs index f1179096c0..1638c73b6f 100644 --- a/src/Marten/Storage/SystemFunctions.cs +++ b/src/Marten/Storage/SystemFunctions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Weasel.Postgresql; namespace Marten.Storage { @@ -40,7 +41,7 @@ public bool IsActive(StoreOptions options) public Type StorageType { get; } = typeof(SystemFunctions); public string Identifier { get; } = "system_functions"; - public void WritePermissions(DdlRules rules, StringWriter writer) + public void WritePermissions(DdlRules rules, TextWriter writer) { // Nothing } diff --git a/src/Marten/Storage/Table.cs b/src/Marten/Storage/Table.cs deleted file mode 100644 index 849a5b5525..0000000000 --- a/src/Marten/Storage/Table.cs +++ /dev/null @@ -1,471 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data.Common; -using System.IO; -using System.Linq; -using Baseline; -using Marten.Schema; -using Marten.Util; -using Npgsql; - -namespace Marten.Storage -{ - /// - /// Model a database table in Postgresql - /// - public class Table: ISchemaObject, IEnumerable - { - public readonly List Columns = new List(); - - public DbObjectName Identifier { get; } - - public IList ForeignKeys { get; } = new List(); - public IList Indexes { get; } = new List(); - - public IEnumerable AllNames() - { - yield return Identifier; - - foreach (var index in Indexes) - { - yield return new DbObjectName(Identifier.Schema, index.IndexName); - } - - foreach (var fk in ForeignKeys) - { - yield return new DbObjectName(Identifier.Schema, fk.KeyName); - } - } - - public Table(DbObjectName name) - { - Identifier = name ?? throw new ArgumentNullException(nameof(name)); - } - - public void AddPrimaryKey(TableColumn column) - { - PrimaryKey = column ?? throw new ArgumentNullException(nameof(column)); - column.Directive = $"CONSTRAINT pk_{Identifier.Name} PRIMARY KEY"; - Columns.Add(column); - } - - public void AddPrimaryKeys(List columns) - { - PrimaryKeys.AddRange(columns); - Columns.AddRange(columns); - } - - public TableColumn PrimaryKey { get; private set; } - - public void AddColumn() where T : TableColumn, new() - { - Columns.Add(new T()); - } - - public TableColumn AddColumn(string name, string type, string directive = null) - { - var column = new TableColumn(name, type) - { - Directive = directive - }; - - AddColumn(column); - - return column; - } - - public void AddColumn(TableColumn column) - { - Columns.Add(column); - } - - public TableColumn Column(string name) - { - return Columns.FirstOrDefault(x => x.Name.EqualsIgnoreCase(name)); - } - - public void ReplaceOrAddColumn(string name, string type, string directive = null) - { - var column = new TableColumn(name, type) { Directive = directive }; - var columnIndex = Columns.FindIndex(c => c.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); - - if (columnIndex >= 0) - { - Columns[columnIndex] = column; - } - else - { - Columns.Add(column); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - return Columns.GetEnumerator(); - } - - public readonly IList Constraints = new List(); - - public virtual void Write(DdlRules rules, StringWriter writer) - { - if (rules.TableCreation == CreationStyle.DropThenCreate) - { - writer.WriteLine("DROP TABLE IF EXISTS {0} CASCADE;", Identifier); - writer.WriteLine("CREATE TABLE {0} (", Identifier); - } - else - { - writer.WriteLine("CREATE TABLE IF NOT EXISTS {0} (", Identifier); - } - - var length = Columns.Select(x => x.Name.Length).Max() + 4; - - var lines = Columns.Select(x => x.ToDeclaration(length)).Concat(Constraints).ToArray(); - - for (int i = 0; i < lines.Length - 1; i++) - { - writer.WriteLine($" {lines[i]},"); - } - - writer.WriteLine($" {lines.Last()}"); - - if (PrimaryKeys.Any()) - { - writer.WriteLine($" ,PRIMARY KEY ({PrimaryKeys.Select(x => x.Name).Join(", ")})"); - } - - writer.WriteLine(");"); - - writer.WriteLine(OriginWriter.OriginStatement("TABLE", Identifier.QualifiedName)); - - foreach (var foreignKey in ForeignKeys) - { - writer.WriteLine(); - writer.WriteLine(foreignKey.ToDDL()); - } - - foreach (var index in Indexes) - { - writer.WriteLine(); - writer.WriteLine(index.ToDDL()); - } - } - - public List PrimaryKeys { get; } = new List(); - - public void WriteDropStatement(DdlRules rules, StringWriter writer) - { - writer.WriteLine($"DROP TABLE IF EXISTS {Identifier} CASCADE;"); - } - - public void ConfigureQueryCommand(CommandBuilder builder) - { - var schemaParam = builder.AddParameter(Identifier.Schema).ParameterName; - var nameParam = builder.AddParameter(Identifier.Name).ParameterName; - - builder.Append($@" -select column_name, data_type, character_maximum_length, udt_name -from information_schema.columns where table_schema = :{schemaParam} and table_name = :{nameParam} -order by ordinal_position; - -select a.attname, format_type(a.atttypid, a.atttypmod) as data_type -from pg_index i -join pg_attribute a on a.attrelid = i.indrelid and a.attnum = ANY(i.indkey) -where attrelid = (select pg_class.oid - from pg_class - join pg_catalog.pg_namespace n ON n.oid = pg_class.relnamespace - where n.nspname = :{schemaParam} and relname = :{nameParam}) -and i.indisprimary; - -SELECT - R.rolname AS user_name, - ns.nspname AS schema_name, - pg_catalog.textin(pg_catalog.regclassout(idx.indrelid :: REGCLASS)) AS table_name, - i.relname AS index_name, - pg_get_indexdef(i.oid) as ddl, - idx.indisunique AS is_unique, - idx.indisprimary AS is_primary, - am.amname AS index_type, - idx.indkey, - ARRAY( - SELECT pg_get_indexdef(idx.indexrelid, k + 1, TRUE) - FROM - generate_subscripts(idx.indkey, 1) AS k - ORDER BY k - ) AS index_keys, - (idx.indexprs IS NOT NULL) OR (idx.indkey::int[] @> array[0]) AS is_functional, - idx.indpred IS NOT NULL AS is_partial -FROM pg_index AS idx - JOIN pg_class AS i - ON i.oid = idx.indexrelid - JOIN pg_am AS am - ON i.relam = am.oid - JOIN pg_namespace AS NS ON i.relnamespace = NS.OID - JOIN pg_roles AS R ON i.relowner = r.oid -WHERE - nspname = :{schemaParam} AND - NOT nspname LIKE 'pg%' AND - i.relname like 'mt_%'; - -SELECT c.conname AS constraint_name, - c.contype AS constraint_type, - sch.nspname AS schema_name, - tbl.relname AS table_name, - ARRAY_AGG(col.attname ORDER BY u.attposition) AS columns, - pg_get_constraintdef(c.oid) AS definition -FROM pg_constraint c - JOIN LATERAL UNNEST(c.conkey) WITH ORDINALITY AS u(attnum, attposition) ON TRUE - JOIN pg_class tbl ON tbl.oid = c.conrelid - JOIN pg_namespace sch ON sch.oid = tbl.relnamespace - JOIN pg_attribute col ON (col.attrelid = tbl.oid AND col.attnum = u.attnum) -WHERE - c.conname like 'mt_%' and - c.contype = 'f' and - sch.nspname = :{schemaParam} and - tbl.relname = :{nameParam} -GROUP BY constraint_name, constraint_type, schema_name, table_name, definition; - -"); - } - - public Table FetchExisting(NpgsqlConnection conn) - { - var cmd = conn.CreateCommand(); - var builder = new CommandBuilder(cmd); - - ConfigureQueryCommand(builder); - - cmd.CommandText = builder.ToString(); - - using (var reader = cmd.ExecuteReader()) - { - return readExistingTable(reader); - } - } - - public TableDelta FetchDelta(NpgsqlConnection conn) - { - var actual = FetchExisting(conn); - if (actual == null) - return null; - - return new TableDelta(this, actual); - } - - public SchemaPatchDifference CreatePatch(DbDataReader reader, SchemaPatch patch, AutoCreate autoCreate) - { - var existing = readExistingTable(reader); - if (existing == null) - { - Write(patch.Rules, patch.UpWriter); - patch.Rollbacks.Drop(this, Identifier); - - return SchemaPatchDifference.Create; - } - - var delta = new TableDelta(this, existing); - if (delta.Matches) - { - return SchemaPatchDifference.None; - } - - if (delta.Extras.Any() || delta.Different.Any()) - { - if (autoCreate == AutoCreate.All) - { - delta.ForeignKeyMissing.Each(x => patch.Updates.Apply(this, x)); - delta.ForeignKeyRollbacks.Each(x => patch.Rollbacks.Apply(this, x)); - delta.ForeignKeyMissingRollbacks.Each(x => patch.Rollbacks.Apply(this, x)); - - Write(patch.Rules, patch.UpWriter); - - return SchemaPatchDifference.Create; - } - - if (!delta.AlteredColumnTypes.Any()) - { - return SchemaPatchDifference.Invalid; - } - } - - if (!delta.Missing.All(x => x.CanAdd)) - { - return SchemaPatchDifference.Invalid; - } - - foreach (var missing in delta.Missing) - { - patch.Updates.Apply(this, missing.AddColumnSql(this)); - patch.Rollbacks.RemoveColumn(this, Identifier, missing.Name); - } - - delta.AlteredColumnTypes.Each(x => patch.Updates.Apply(this, x)); - delta.AlteredColumnTypeRollbacks.Each(x => patch.Rollbacks.Apply(this, x)); - - delta.IndexChanges.Each(x => patch.Updates.Apply(this, x)); - delta.IndexRollbacks.Each(x => patch.Rollbacks.Apply(this, x)); - - delta.ForeignKeyChanges.Each(x => patch.Updates.Apply(this, x)); - delta.ForeignKeyRollbacks.Each(x => patch.Rollbacks.Apply(this, x)); - delta.ForeignKeyMissingRollbacks.Each(x => patch.Rollbacks.Apply(this, x)); - - return SchemaPatchDifference.Update; - } - - private Table readExistingTable(DbDataReader reader) - { - var columns = readColumns(reader); - var pks = readPrimaryKeys(reader); - var indexes = readIndexes(reader); - var constraints = readConstraints(reader); - - if (!columns.Any()) - return null; - - var existing = new Table(Identifier); - foreach (var column in columns) - { - existing.AddColumn(column); - } - - if (pks.Any()) - { - existing.SetPrimaryKey(pks.First()); - } - - existing.ActualIndices = indexes; - existing.ActualForeignKeys = constraints; - - return existing; - } - - public List ActualForeignKeys { get; set; } = new List(); - - public Dictionary ActualIndices { get; set; } = new Dictionary(); - - private List readConstraints(DbDataReader reader) - { - reader.NextResult(); - var constraints = new List(); - while (reader.Read()) - { - constraints.Add(new ActualForeignKey(Identifier, reader.GetString(0), reader.GetString(5))); - } - - return constraints; - } - - private Dictionary readIndexes(DbDataReader reader) - { - var dict = new Dictionary(); - - reader.NextResult(); - while (reader.Read()) - { - if (reader.IsDBNull(2)) - continue; - - var schemaName = reader.GetString(1); - var tableName = reader.GetString(2); - - if ((Identifier.Schema == schemaName && Identifier.Name == tableName) || Identifier.QualifiedName == tableName) - { - var index = new ActualIndex(Identifier, reader.GetString(3), - reader.GetString(4)); - - dict.Add(index.Name, index); - } - } - - return dict; - } - - private static List readPrimaryKeys(DbDataReader reader) - { - var pks = new List(); - reader.NextResult(); - while (reader.Read()) - { - pks.Add(reader.GetString(0)); - } - return pks; - } - - private static List readColumns(DbDataReader reader) - { - var columns = new List(); - while (reader.Read()) - { - var column = new TableColumn(reader.GetString(0), reader.GetString(1)); - - if (column.Type.Equals("user-defined")) - { - column.Type = reader.GetString(3); - } - - if (!reader.IsDBNull(2)) - { - var length = reader.GetInt32(2); - column.Type = $"{column.Type}({length})"; - } - - columns.Add(column); - } - return columns; - } - - public void SetPrimaryKey(string columnName) - { - var column = Columns.FirstOrDefault(x => x.Name == columnName); - PrimaryKey = column; - } - - public bool HasColumn(string columnName) - { - return Columns.Any(x => x.Name == columnName); - } - - public TableColumn ColumnFor(string columnName) - { - return Columns.FirstOrDefault(x => x.Name == columnName); - } - - public void RemoveColumn(string columnName) - { - Columns.RemoveAll(x => x.Name == columnName); - } - - protected bool Equals(Table other) - { - return Columns.OrderBy(x => x.Name).SequenceEqual(other.OrderBy(x => x.Name)) && Equals(PrimaryKey, other.PrimaryKey) && Identifier.Equals(other.Identifier); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - return false; - if (ReferenceEquals(this, obj)) - return true; - if (!obj.GetType().CanBeCastTo
()) - return false; - return Equals((Table)obj); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = (Columns != null ? Columns.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (PrimaryKey != null ? PrimaryKey.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (Identifier != null ? Identifier.GetHashCode() : 0); - return hashCode; - } - } - } -} diff --git a/src/Marten/Storage/TableColumn.cs b/src/Marten/Storage/TableColumn.cs deleted file mode 100644 index a3fcc575da..0000000000 --- a/src/Marten/Storage/TableColumn.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using Baseline; -using Marten.Util; - -namespace Marten.Storage -{ - public class TableColumn - { - public TableColumn(string name, string type) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentOutOfRangeException(nameof(name)); - if (string.IsNullOrEmpty(type)) - throw new ArgumentOutOfRangeException(nameof(type)); - Name = name.ToLower().Trim().Replace(' ', '_'); - Type = type.ToLower(); - } - - public TableColumn(string name, string type, string directive) : this(name, type) - { - Directive = directive; - } - - public string Name { get; } - - // Needs to be writeable here. - public string Type { get; set; } - - public string RawType() - { - return Type.Split('(')[0].Trim(); - } - - public string Directive { get; set; } - - protected bool Equals(TableColumn other) - { - return string.Equals(Name, other.Name) && - string.Equals(TypeMappings.ConvertSynonyms(RawType()), TypeMappings.ConvertSynonyms(other.RawType())); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - return false; - if (ReferenceEquals(this, obj)) - return true; - if (!obj.GetType().CanBeCastTo()) - return false; - return Equals((TableColumn)obj); - } - - public override int GetHashCode() - { - unchecked - { - return (Name.GetHashCode() * 397) ^ Type.GetHashCode(); - } - } - - public string ToDeclaration(int length) - { - return $"{Name.PadRight(length)}{Type} {Directive}"; - } - - public override string ToString() - { - return $"{Name} {Type} {Directive}"; - } - - public bool CanAdd { get; set; } = false; - - public virtual string AddColumnSql(Table table) - { - return $"alter table {table.Identifier} add column {ToDeclaration(Name.Length + 1)};"; - } - - public virtual string AlterColumnTypeSql(Table table) - { - return $"alter table {table.Identifier} alter column {Name.PadRight(Name.Length)} type {Type};"; - } - } -} diff --git a/src/Marten/Storage/TableDelta.cs b/src/Marten/Storage/TableDelta.cs deleted file mode 100644 index 15c89c62fe..0000000000 --- a/src/Marten/Storage/TableDelta.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Baseline; -using Marten.Schema; -using Marten.Util; - -namespace Marten.Storage -{ - public class TableDelta - { - private readonly DbObjectName _tableName; - - public TableDelta(Table expected, Table actual) - { - Missing = expected.Where(x => actual.All(_ => _.Name != x.Name)).ToArray(); - Extras = actual.Where(x => expected.All(_ => _.Name != x.Name)).ToArray(); - Matched = expected.Where(x => actual.Any(a => Equals(a, x))).ToArray(); - Different = - expected.Where(x => actual.HasColumn(x.Name) && !x.Equals(actual.ColumnFor(x.Name))).ToArray(); - - _tableName = expected.Identifier; - - compareColumns(expected, actual, Different); - - compareIndices(expected, actual); - - compareForeignKeys(expected, actual); - } - - private void compareIndices(Table expected, Table actual) - { - // TODO -- drop obsolete indices? - - var schemaName = expected.Identifier.Schema; - - var obsoleteIndexes = actual.ActualIndices.Values.Where(x => expected.Indexes.All(_ => _.IndexName != x.Name)); - foreach (var index in obsoleteIndexes) - { - IndexRollbacks.Add(index.DDL); - - if (!index.Name.EndsWith("pkey")) - { - IndexChanges.Add($"drop index concurrently if exists {schemaName}.{index.Name};"); - } - /* else - { - IndexChanges.Add($"alter table {_tableName} drop constraint if exists {schemaName}.{index.Name};"); - }*/ - } - - foreach (var index in expected.Indexes) - { - if (actual.ActualIndices.TryGetValue(index.IndexName, out var actualIndex)) - { - if (!index.Matches(actualIndex)) - { - IndexChanges.Add($"drop index {schemaName}.{index.IndexName};{Environment.NewLine}{index.ToDDL()};"); - IndexRollbacks.Add($"drop index {schemaName}.{index.IndexName};{Environment.NewLine}{actualIndex.DDL};"); - } - } - else - { - IndexChanges.Add(index.ToDDL()); - IndexRollbacks.Add($"drop index concurrently if exists {schemaName}.{index.IndexName};"); - } - } - } - - private void compareForeignKeys(Table expected, Table actual) - { - var schemaName = expected.Identifier.Schema; - var tableName = expected.Identifier.Name; - - // Locate FKs that exist, but aren't defined - var obsoleteFkeys = actual.ActualForeignKeys.Where(afk => expected.ForeignKeys.All(fk => fk.KeyName != afk.Name)); - foreach (var fkey in obsoleteFkeys) - { - ForeignKeyMissing.Add($"ALTER TABLE {schemaName}.{tableName} DROP CONSTRAINT {fkey.Name};"); - ForeignKeyMissingRollbacks.Add($"ALTER TABLE {schemaName}.{tableName} ADD CONSTRAINT {fkey.Name} {fkey.DDL};"); - } - - // Detect changes - foreach (var fkey in expected.ForeignKeys) - { - var actualFkey = actual.ActualForeignKeys.SingleOrDefault(afk => afk.Name == fkey.KeyName); - if (actualFkey != null && fkey.CascadeDeletes != actualFkey.DoesCascadeDeletes()) - { - // The fkey cascading has changed, drop and re-create the key - ForeignKeyChanges.Add($"ALTER TABLE {schemaName}.{tableName} DROP CONSTRAINT {actualFkey.Name}; {fkey.ToDDL()};"); - ForeignKeyRollbacks.Add($"ALTER TABLE {schemaName}.{tableName} DROP CONSTRAINT {fkey.KeyName}; ALTER TABLE {schemaName}.{tableName} ADD CONSTRAINT {actualFkey.Name} {actualFkey.DDL};"); - } - else if (actualFkey == null)// The foreign key is missing - { - ForeignKeyChanges.Add(fkey.ToDDL()); - ForeignKeyRollbacks.Add($"ALTER TABLE {schemaName}.{tableName} DROP CONSTRAINT {fkey.KeyName};"); - } - } - } - - private void compareColumns(Table expected, Table actual, IEnumerable changedColumns) - { - foreach (var expectedColumn in changedColumns) - { - var actualColumn = actual.ColumnFor(expectedColumn.Name); - var actualType = TypeMappings.ConvertSynonyms(actualColumn.Type); - var expectedType = TypeMappings.ConvertSynonyms(expectedColumn.Type); - - // check for altered column type which can be auto converted - if (actualType.EqualsIgnoreCase(expectedType) || - !TypeMappings.CanAutoConvertType(actualType, expectedType)) continue; - - AlteredColumnTypes.Add(expectedColumn.AlterColumnTypeSql(expected)); - AlteredColumnTypeRollbacks.Add(actualColumn.AlterColumnTypeSql(actual)); - } - } - - public readonly IList IndexChanges = new List(); - public readonly IList IndexRollbacks = new List(); - - public readonly IList ForeignKeyMissing = new List(); - public readonly IList ForeignKeyMissingRollbacks = new List(); - - public readonly IList ForeignKeyChanges = new List(); - public readonly IList ForeignKeyRollbacks = new List(); - - public readonly IList AlteredColumnTypes = new List(); - public readonly IList AlteredColumnTypeRollbacks = new List(); - - public TableColumn[] Different { get; set; } - - public TableColumn[] Matched { get; set; } - - public TableColumn[] Extras { get; set; } - - public TableColumn[] Missing { get; set; } - - public bool Matches - { - get - { - if (Missing.Any()) - return false; - if (Extras.Any()) - return false; - if (Different.Any()) - return false; - if (IndexChanges.Any()) - return false; - if (ForeignKeyChanges.Any()) - return false; - - return true; - } - } - - public override string ToString() - { - return $"TableDiff for {_tableName}"; - } - } -} diff --git a/src/Marten/Storage/Tenancy.cs b/src/Marten/Storage/Tenancy.cs index a58ab69710..f174d322bb 100644 --- a/src/Marten/Storage/Tenancy.cs +++ b/src/Marten/Storage/Tenancy.cs @@ -1,4 +1,5 @@ using Marten.Schema; +using Weasel.Postgresql; namespace Marten.Storage { diff --git a/src/Marten/Storage/Tenant.cs b/src/Marten/Storage/Tenant.cs index 5d81167338..8756892c16 100644 --- a/src/Marten/Storage/Tenant.cs +++ b/src/Marten/Storage/Tenant.cs @@ -2,29 +2,36 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Data; -using System.IO; -using System.Threading; +using System.Linq; using System.Threading.Tasks; using Baseline; using Marten.Exceptions; using Marten.Internal; using Marten.Internal.Storage; using Marten.Schema; -using Marten.Schema.Identity; using Marten.Schema.Identity.Sequences; using Marten.Services; using Marten.Transforms; -using Marten.Util; using Npgsql; +using Weasel.Postgresql; +using Weasel.Postgresql.Functions; +using Weasel.Postgresql.Tables; namespace Marten.Storage { public class Tenant: ITenant { - private readonly ConcurrentDictionary _checks = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _bulkLoaders = new(); + private readonly ConcurrentDictionary _checks = new(); private readonly IConnectionFactory _factory; private readonly StorageFeatures _features; + + private readonly ConcurrentDictionary _identityAssignments = + new(); + private readonly StoreOptions _options; + + private readonly object _updateLock = new(); private Lazy _sequences; public Tenant(StorageFeatures features, StoreOptions options, IConnectionFactory factory, string tenantId) @@ -41,20 +48,7 @@ public Tenant(StorageFeatures features, StoreOptions options, IConnectionFactory : new StorageCheckingProviderGraph(this, options.Providers); } - private void resetSequences() - { - _sequences = new Lazy(() => - { - var sequences = new SequenceFactory(_options, this); - - generateOrUpdateFeature(typeof(SequenceFactory), sequences); - - return sequences; - }); - } - public string TenantId { get; } - public IDbObjects DbObjects => new DbObjects(this, _features); public void ResetSchemaExistenceChecks() @@ -70,21 +64,93 @@ public void ResetSchemaExistenceChecks() public void EnsureStorageExists(Type featureType) { if (_options.AutoCreateSchemaObjects == AutoCreate.None) + { return; + } ensureStorageExists(new List(), featureType); } + public IDocumentStorage StorageFor() + { + return Providers.StorageFor().QueryOnly; + } + + public ISequences Sequences => _sequences.Value; + + public TransformFunction TransformFor(string name) + { + EnsureStorageExists(typeof(Transforms.Transforms)); + return _features.Transforms.For(name); + } + + public void MarkAllFeaturesAsChecked() + { + foreach (var feature in _features.AllActiveFeatures(this)) _checks[feature.StorageType] = true; + } + + /// + /// Directly open a managed connection to the underlying Postgresql database + /// + /// + /// + /// + /// + public IManagedConnection OpenConnection(CommandRunnerMode mode = CommandRunnerMode.AutoCommit, + IsolationLevel isolationLevel = IsolationLevel.ReadCommitted, int? timeout = null) + { + return new ManagedConnection(_factory, mode, _options.RetryPolicy(), isolationLevel, timeout); + } + + /// + /// Fetch a connection to the tenant database + /// + /// + public NpgsqlConnection CreateConnection() + { + return _factory.Create(); + } + + public IProviderGraph Providers { get; private set; } + + /// + /// Set the minimum sequence number for a Hilo sequence for a specific document type + /// to the specified floor. Useful for migrating data between databases + /// + /// + /// + public Task ResetHiloSequenceFloor(long floor) + { + var sequence = Sequences.SequenceFor(typeof(T)); + return sequence.SetFloor(floor); + } + + private void resetSequences() + { + _sequences = new Lazy(() => + { + var sequences = new SequenceFactory(_options, this); + + generateOrUpdateFeature(typeof(SequenceFactory), sequences); + + return sequences; + }); + } + private void ensureStorageExists(IList types, Type featureType) { if (_checks.ContainsKey(featureType)) + { return; + } var feature = _features.FindFeature(featureType); if (feature == null) + { throw new ArgumentOutOfRangeException(nameof(featureType), $"Unknown feature type {featureType.FullName}"); + } if (_checks.ContainsKey(feature.StorageType)) { @@ -94,61 +160,61 @@ private void ensureStorageExists(IList types, Type featureType) // Preventing cyclic dependency problems if (types.Contains(featureType)) + { return; + } types.Fill(featureType); - foreach (var dependentType in feature.DependentTypes()) - { - ensureStorageExists(types, dependentType); - } + foreach (var dependentType in feature.DependentTypes()) ensureStorageExists(types, dependentType); generateOrUpdateFeature(featureType, feature); } - private readonly object _updateLock = new object(); + private static readonly object _migrateLocker = new object(); private void generateOrUpdateFeature(Type featureType, IFeatureSchema feature) { lock (_updateLock) { if (_checks.ContainsKey(featureType)) + { + RegisterCheck(featureType, feature); return; + } var schemaObjects = feature.Objects; schemaObjects.AssertValidNames(_options); - using (var conn = _factory.Create()) + lock (_migrateLocker) // Not happy about this, but it should only come into play at development time { - conn.Open(); - - var patch = new SchemaPatch(_options.Advanced.DdlRules); - patch.Apply(conn, _options.AutoCreateSchemaObjects, schemaObjects); - patch.AssertPatchingIsValid(_options.AutoCreateSchemaObjects); - - var ddl = patch.UpdateDDL; - if (patch.Difference != SchemaPatchDifference.None && ddl.IsNotEmpty()) - { - var cmd = conn.CreateCommand(ddl); - try - { - cmd.ExecuteNonQuery(); - _options.Logger().SchemaChange(ddl); - RegisterCheck(featureType, feature); - } - catch (Exception e) - { - throw MartenCommandExceptionFactory.Create(cmd, e); - } - } - else if (patch.Difference == SchemaPatchDifference.None) - { - RegisterCheck(featureType, feature); - } + executeMigration(schemaObjects).GetAwaiter().GetResult(); } + + RegisterCheck(featureType, feature); } } + private async Task executeMigration(ISchemaObject[] schemaObjects) + { + using var conn = _factory.Create(); + await conn.OpenAsync(); + + var migration = await SchemaMigration.Determine(conn, schemaObjects); + + if (migration.Difference == SchemaPatchDifference.None) return; + + migration.AssertPatchingIsValid(_options.AutoCreateSchemaObjects); + + await migration.ApplyAll( + conn, + _options.Advanced.DdlRules, + _options.AutoCreateSchemaObjects, + sql => _options.Logger().SchemaChange(sql), + MartenExceptionTransformer.WrapAndThrow); + + } + private void RegisterCheck(Type featureType, IFeatureSchema feature) { _checks[featureType] = true; @@ -158,67 +224,49 @@ private void RegisterCheck(Type featureType, IFeatureSchema feature) } } - public IDocumentStorage StorageFor() - { - return Providers.StorageFor().QueryOnly; - } - public ISequences Sequences => _sequences.Value; + public async Task> SchemaTables() + { + var schemaNames = _features.AllSchemaNames(); - private readonly ConcurrentDictionary _identityAssignments = - new ConcurrentDictionary(); + using var conn = CreateConnection(); + await conn.OpenAsync(); - public TransformFunction TransformFor(string name) - { - EnsureStorageExists(typeof(Transforms.Transforms)); - return _features.Transforms.For(name); + return await conn.ExistingTables(schemas:schemaNames); } - private readonly ConcurrentDictionary _bulkLoaders = new ConcurrentDictionary(); - - public void MarkAllFeaturesAsChecked() + public async Task> DocumentTables() { - foreach (var feature in _features.AllActiveFeatures(this)) - { - _checks[feature.StorageType] = true; - } + var tables = await SchemaTables(); + return tables.Where(x => x.Name.StartsWith(SchemaConstants.TablePrefix)).ToList(); } - /// - /// Directly open a managed connection to the underlying Postgresql database - /// - /// - /// - /// - /// - public IManagedConnection OpenConnection(CommandRunnerMode mode = CommandRunnerMode.AutoCommit, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted, int? timeout = null) + public async Task> Functions() { - return new ManagedConnection(_factory, mode, _options.RetryPolicy(), isolationLevel, timeout); + using var conn = CreateConnection(); + await conn.OpenAsync(); + + var schemaNames = _features.AllSchemaNames(); + return await conn.ExistingFunctions(namePattern:"mt_%", schemas:schemaNames); } - /// - /// Fetch a connection to the tenant database - /// - /// - public NpgsqlConnection CreateConnection() + public async Task DefinitionForFunction(DbObjectName function) { - return _factory.Create(); - } + using var conn = CreateConnection(); + await conn.OpenAsync(); - public IProviderGraph Providers { get; private set; } + return await conn.FindExistingFunction(function); + } - /// - /// Set the minimum sequence number for a Hilo sequence for a specific document type - /// to the specified floor. Useful for migrating data between databases - /// - /// - /// - public void ResetHiloSequenceFloor(long floor) + public async Task
ExistingTableFor(Type type) { - var sequence = Sequences.SequenceFor(typeof(T)); - sequence.SetFloor(floor); - } + var mapping = _features.MappingFor(type).As(); + var expected = mapping.Schema.Table; + using var conn = CreateConnection(); + await conn.OpenAsync(); + return await expected.FetchExisting(conn); + } } } diff --git a/src/Marten/Storage/TenantExtensions.cs b/src/Marten/Storage/TenantExtensions.cs index 4d8449efde..13092ab4a8 100644 --- a/src/Marten/Storage/TenantExtensions.cs +++ b/src/Marten/Storage/TenantExtensions.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.Data.Common; +using System.Threading.Tasks; using Baseline; using Marten.Events; +using Weasel.Postgresql; using Marten.Util; using Npgsql; @@ -15,102 +17,37 @@ public static IEventStorage EventStorage(this ITenant tenant) return (IEventStorage) tenant.StorageFor(); } - public static void RunSql(this ITenant tenant, string sql) + internal static void RunSql(this ITenant tenant, string sql) { - using (var conn = tenant.CreateConnection()) - { - conn.Open(); + using var conn = tenant.CreateConnection(); + conn.Open(); - try - { - conn.CreateCommand().WithText(sql).ExecuteNonQuery(); - } - finally - { - conn.Close(); - conn.Dispose(); - } - } - } - - private static T execute(this ITenant tenant, Func func) - { - using (var conn = tenant.CreateConnection()) + try { - conn.Open(); - - try - { - return func(conn); - } - finally - { - conn.Close(); - conn.Dispose(); - } + conn.CreateCommand().WithText(sql).ExecuteNonQuery(); } - } - - private static void execute(this ITenant tenant, Action action) - { - using (var conn = tenant.CreateConnection()) + finally { - conn.Open(); - - try - { - action(conn); - } - finally - { - conn.Close(); - conn.Dispose(); - } + conn.Close(); + conn.Dispose(); } } - public static IList GetStringList(this ITenant tenant, string sql, params object[] parameters) + internal static async Task RunSqlAsync(this ITenant tenant, string sql) { - var list = new List(); + using var conn = tenant.CreateConnection(); + await conn.OpenAsync(); - tenant.execute(conn => + try { - var cmd = conn.CreateCommand().WithText(sql); - - cmd.WithText(sql); - parameters.Each(x => - { - var param = cmd.AddParameter(x); - cmd.CommandText = cmd.CommandText.UseParameter(param); - }); - - using (var reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - list.Add(reader.GetString(0)); - } - - reader.Close(); - } - }); - - return list; - } - - public static IEnumerable Fetch(this ITenant tenant, string sql, Func transform, params object[] parameters) - { - return tenant.execute(conn => + await conn.CreateCommand(sql).ExecuteNonQueryAsync(); + } + finally { - try - { - return conn.CreateCommand().Fetch(sql, transform, parameters); - } - catch (Exception e) - { - throw new Exception($"Error trying to fetch w/ sql '{sql}'", e); - } - }); + await conn.CloseAsync(); + conn.Dispose(); + } } + } } diff --git a/src/Marten/Storage/TenantSchema.cs b/src/Marten/Storage/TenantSchema.cs index b775246576..d35ae9f51f 100644 --- a/src/Marten/Storage/TenantSchema.cs +++ b/src/Marten/Storage/TenantSchema.cs @@ -1,9 +1,11 @@ using System; using System.IO; using System.Linq; +using System.Threading.Tasks; using Baseline; using Marten.Exceptions; using Marten.Schema; +using Weasel.Postgresql; namespace Marten.Storage { @@ -24,13 +26,13 @@ public TenantSchema(StoreOptions options, Tenant tenant) public DdlRules DdlRules { get; } - public void WriteDDL(string filename, bool transactionalScript = true) + public void WriteDatabaseCreationScriptFile(string filename) { - var sql = ToDDL(transactionalScript); + var sql = ToDatabaseScript(); new FileSystem().WriteStringToFile(filename, sql); } - public void WriteDDLByType(string directory, bool transactionalScript = true) + public void WriteDatabaseCreationScriptByType(string directory) { var system = new FileSystem(); @@ -42,12 +44,12 @@ public void WriteDDLByType(string directory, bool transactionalScript = true) foreach (var feature in features) { - var writer = new StringWriter(); - feature.Write(DdlRules, writer); - var file = directory.AppendPath(feature.Identifier + ".sql"); - new SchemaPatch(DdlRules).WriteFile(file, writer.ToString(), transactionalScript); + DdlRules.WriteTemplatedFile(file, (r, w) => + { + feature.Write(r, w); + }); } } @@ -74,141 +76,128 @@ private void writeDatabaseSchemaGenerationScript(string directory, FileSystem sy system.WriteStringToFile(filename, writer.ToString()); } - private SchemaPatch ToPatch(bool withSchemas, AutoCreate withAutoCreate) + public async Task CreateMigration() { - var patch = new SchemaPatch(DdlRules); - - if (withSchemas) - { - var allSchemaNames = StoreOptions.Storage.AllSchemaNames(); - DatabaseSchemaGenerator.WriteSql(StoreOptions, allSchemaNames, patch.UpWriter); - } - var @objects = _features.AllActiveFeatures(_tenant).SelectMany(x => x.Objects).ToArray(); - using (var conn = _tenant.CreateConnection()) - { - conn.Open(); - - patch.Apply(conn, withAutoCreate, @objects); - } + using var conn = _tenant.CreateConnection(); + await conn.OpenAsync(); - return patch; + return await SchemaMigration.Determine(conn, @objects); } - public string ToDDL(bool transactionalScript = true) + public string ToDatabaseScript() { var writer = new StringWriter(); - new SchemaPatch(DdlRules).WriteScript(writer, w => + StoreOptions.Advanced.DdlRules.WriteScript(writer, (r, w) => { var allSchemaNames = StoreOptions.Storage.AllSchemaNames(); DatabaseSchemaGenerator.WriteSql(StoreOptions, allSchemaNames, w); foreach (var feature in _features.AllActiveFeatures(_tenant)) { - feature.Write(DdlRules, writer); + feature.Write(r, w); } - }, transactionalScript); + }); return writer.ToString(); } - public void WritePatch(string filename, bool withSchemas = true, bool transactionalScript = true) + public async Task WriteMigrationFile(string filename) { if (!Path.IsPathRooted(filename)) { filename = AppContext.BaseDirectory.AppendPath(filename); } - var patch = ToPatch(withSchemas, withAutoCreateAll: true); + var patch = await CreateMigration(); - patch.WriteUpdateFile(filename, transactionalScript); - - var dropFile = SchemaPatch.ToDropFileName(filename); - patch.WriteRollbackFile(dropFile, transactionalScript); - } + DdlRules.WriteTemplatedFile(filename, (r, w) => + { + patch.WriteAllUpdates(w, r, AutoCreate.All); + }); - public SchemaPatch ToPatch(bool withSchemas = true, bool withAutoCreateAll = false) - { - return ToPatch(withSchemas, withAutoCreateAll ? AutoCreate.All : StoreOptions.AutoCreateSchemaObjects); + var dropFile = SchemaMigration.ToDropFileName(filename); + DdlRules.WriteTemplatedFile(dropFile, (r, w) => + { + patch.WriteAllRollbacks(w, r); + }); } - public void AssertDatabaseMatchesConfiguration() + public async Task AssertDatabaseMatchesConfiguration() { - var patch = ToPatch(false, withAutoCreateAll: true); - - if (patch.UpdateDDL.Trim().IsNotEmpty()) + var patch = await CreateMigration(); + if (patch.Difference != SchemaPatchDifference.None) { - throw new SchemaValidationException(patch.UpdateDDL); + throw new SchemaValidationException(patch.UpdateSql); } } - public void ApplyAllConfiguredChangesToDatabase(AutoCreate? withCreateSchemaObjects = null) + public async Task ApplyAllConfiguredChangesToDatabase(AutoCreate? withCreateSchemaObjects = null) { var defaultAutoCreate = StoreOptions.AutoCreateSchemaObjects != AutoCreate.None ? StoreOptions.AutoCreateSchemaObjects : AutoCreate.CreateOrUpdate; - var patch = ToPatch(true, withCreateSchemaObjects ?? defaultAutoCreate); - var ddl = patch.UpdateDDL.Trim(); + var patch = await CreateMigration(); + + if (patch.Difference == SchemaPatchDifference.None) return; - if (ddl.IsEmpty()) return; + using var conn = _tenant.CreateConnection(); + await conn.OpenAsync(); try { - _tenant.RunSql(ddl); - StoreOptions.Logger().SchemaChange(ddl); + var martenLogger = StoreOptions.Logger(); + await patch.ApplyAll(conn, DdlRules, withCreateSchemaObjects ?? defaultAutoCreate, sql => martenLogger.SchemaChange(sql)); _tenant.MarkAllFeaturesAsChecked(); } catch (Exception e) { - throw new MartenSchemaException("All Configured Changes", ddl, e); + throw new MartenSchemaException("All Configured Changes", patch.UpdateSql, e); } } - public SchemaPatch ToPatch(Type documentType) + public async Task CreateMigration(Type documentType) { var mapping = _features.MappingFor(documentType); - var patch = new SchemaPatch(DdlRules); + using var conn = _tenant.CreateConnection(); + await conn.OpenAsync(); - using (var conn = _tenant.CreateConnection()) - { - conn.Open(); - - patch.Apply(conn, AutoCreate.CreateOrUpdate, mapping.Schema.Objects); - } + var migration = await SchemaMigration.Determine(conn, mapping.Schema.Objects); - return patch; + return migration; } - public void WritePatchByType(string directory, bool transactionalScript = true) + public async Task WriteMigrationFileByType(string directory) { var system = new FileSystem(); system.DeleteDirectory(directory); system.CreateDirectory(directory); - var features = _features.AllActiveFeatures(_tenant).ToArray(); writeDatabaseSchemaGenerationScript(directory, system, features); - using (var conn = _tenant.CreateConnection()) + using var conn = _tenant.CreateConnection(); + await conn.OpenAsync(); + + foreach (var feature in features) { - conn.Open(); + var migration = await SchemaMigration.Determine(conn, feature.Objects); - foreach (var feature in features) + if (migration.Difference == SchemaPatchDifference.None) { - var patch = new SchemaPatch(DdlRules); - patch.Apply(conn, AutoCreate.CreateOrUpdate, feature.Objects); - - if (patch.UpdateDDL.IsNotEmpty()) - { - var file = directory.AppendPath(feature.Identifier + ".sql"); - patch.WriteUpdateFile(file, transactionalScript); - } + continue; } + + var file = directory.AppendPath(feature.Identifier + ".sql"); + DdlRules.WriteTemplatedFile(file, (r, w) => + { + migration.WriteAllUpdates(w, r, AutoCreate.CreateOrUpdate); + }); } } } diff --git a/src/Marten/Storage/UpdateFunction.cs b/src/Marten/Storage/UpdateFunction.cs index 8b3ea5c40a..1075b47d63 100644 --- a/src/Marten/Storage/UpdateFunction.cs +++ b/src/Marten/Storage/UpdateFunction.cs @@ -10,7 +10,8 @@ public UpdateFunction(DocumentMapping mapping) : base(mapping, mapping.UpdateFun { } - protected override void writeFunction(StringWriter writer, string argList, string securityDeclaration, string inserts, string valueList, + protected override void writeFunction(TextWriter writer, string argList, string securityDeclaration, + string inserts, string valueList, string updates) { var statement = updates.Contains("where") diff --git a/src/Marten/Storage/UpsertFunction.cs b/src/Marten/Storage/UpsertFunction.cs index 24e8448df4..57d3557f2d 100644 --- a/src/Marten/Storage/UpsertFunction.cs +++ b/src/Marten/Storage/UpsertFunction.cs @@ -3,10 +3,12 @@ using System.IO; using System.Linq; using Baseline; +using Weasel.Postgresql; using Marten.Schema; using Marten.Schema.Arguments; using Marten.Storage.Metadata; using Marten.Util; +using Weasel.Postgresql.Functions; namespace Marten.Storage { @@ -32,14 +34,8 @@ public UpsertFunction(DocumentMapping mapping, DbObjectName identifier = null, b // 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; - } + + _primaryKeyConstraintName = table.PrimaryKeyName; var idType = mapping.IdMember.GetMemberType(); var pgIdType = TypeMappings.GetPgType(idType, mapping.EnumStorage); @@ -93,7 +89,7 @@ public void AddIfActive(MetadataColumn column) } } - public override void Write(DdlRules rules, StringWriter writer) + public override void WriteCreateStatement(DdlRules rules, TextWriter writer) { // TODO -- this code could be a lot cleaner! The metadata made it go bad @@ -147,7 +143,8 @@ public override void Write(DdlRules rules, StringWriter writer) writeFunction(writer, argList, securityDeclaration, inserts, valueList, updates); } - protected virtual void writeFunction(StringWriter writer, string argList, string securityDeclaration, string inserts, + protected virtual void writeFunction(TextWriter writer, string argList, string securityDeclaration, + string inserts, string valueList, string updates) { if (_mapping.Metadata.Version.Enabled) @@ -197,17 +194,5 @@ public UpsertArgument[] OrderedArguments() return Arguments.OrderBy(x => x.Arg).ToArray(); } - protected override string toDropSql() - { - var argList = OrderedArguments().Select(x => x.PostgresType).Join(", "); - var dropSql = $"drop function if exists {Identifier.QualifiedName}({argList});"; - return dropSql; - } - - public void WriteTemplate(DdlRules rules, DdlTemplate template, StringWriter writer) - { - var body = ToBody(rules); - body.WriteTemplate(template, writer); - } } } diff --git a/src/Marten/Storage/VersionColumn.cs b/src/Marten/Storage/VersionColumn.cs index 537213ebad..3c62fed94c 100644 --- a/src/Marten/Storage/VersionColumn.cs +++ b/src/Marten/Storage/VersionColumn.cs @@ -6,6 +6,7 @@ using Marten.Internal.CodeGeneration; using Marten.Schema; using Marten.Storage.Metadata; +using Weasel.Postgresql.Tables; namespace Marten.Storage { @@ -13,8 +14,8 @@ internal class VersionColumn: MetadataColumn, ISelectableColumn { public VersionColumn() : base(SchemaConstants.VersionColumn, x => x.CurrentVersion) { - Directive = "NOT NULL default(md5(random()::text || clock_timestamp()::text)::uuid)"; - CanAdd = true; + AllowNulls = false; + DefaultExpression = "(md5(random()::text || clock_timestamp()::text)::uuid)"; } public void GenerateCode(StorageStyle storageStyle, GeneratedType generatedType, GeneratedMethod async, diff --git a/src/Marten/StoreOptions.cs b/src/Marten/StoreOptions.cs index bf5ec1a0ca..a77fe36cb6 100644 --- a/src/Marten/StoreOptions.cs +++ b/src/Marten/StoreOptions.cs @@ -4,9 +4,9 @@ using System.Linq; using System.Threading.Tasks; using Baseline; +using Baseline.ImTools; using Marten.Events; using Marten.Events.Daemon; -using Marten.Events.TestSupport; using Marten.Exceptions; using Marten.Internal; using Marten.Internal.CompiledQueries; @@ -18,8 +18,9 @@ using Marten.Services.Json; using Marten.Storage; using Marten.Transforms; -using Marten.Util; using Npgsql; +using Weasel.Postgresql; + #nullable enable namespace Marten { @@ -30,17 +31,16 @@ namespace Marten /// public class StoreOptions: IReadOnlyStoreOptions { - /// - /// The default database schema used 'public'. - /// - public const string DefaultDatabaseSchemaName = "public"; - public const string PatchDoc = "patch_doc"; private readonly ConcurrentDictionary> _childDocs = new(); - public StorageFeatures Storage { get; } + private readonly IList _policies = new List + { + new VersionedPolicy(), new SoftDeletedPolicy(), new TrackedPolicy(), new TenancyPolicy() + }; + public readonly IList InitialData = new List(); /// @@ -53,13 +53,18 @@ private readonly ConcurrentDictionary public readonly MartenRegistry Schema; - private string _databaseSchemaName = DefaultDatabaseSchemaName; + + private ImHashMap _childFieldMappings = ImHashMap.Empty; + + private string _databaseSchemaName = DbObjectName.DefaultDatabaseSchemaName; private IMartenLogger _logger = new NulloMartenLogger(); - private ISerializer? _serializer; + + private ImHashMap _querySources = ImHashMap.Empty; private IRetryPolicy _retryPolicy = new NulloRetryPolicy(); + private ISerializer? _serializer; /// /// Whether or Marten should attempt to create any missing database schema objects at runtime. This @@ -67,19 +72,6 @@ private readonly ConcurrentDictionary public AutoCreate AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate; - /// - /// Configure Marten to create databases for tenants in case databases do not exist or need to be dropped & re-created - /// - /// Creating and dropping databases requires the CREATEDB privilege - public void CreateDatabasesForTenants(Action configure) - { - CreateDatabases = configure ?? throw new ArgumentNullException(nameof(configure)); - } - - internal Action? CreateDatabases { get; set; } - - internal IProviderGraph Providers { get; } - public StoreOptions() { EventGraph = new EventGraph(this); @@ -91,20 +83,15 @@ public StoreOptions() Advanced = new AdvancedOptions(this); } - public AdvancedOptions Advanced { get; } + public StorageFeatures Storage { get; } - IReadOnlyAdvancedOptions IReadOnlyStoreOptions.Advanced => Advanced; + internal Action? CreateDatabases { get; set; } - internal EventGraph EventGraph { get; } + internal IProviderGraph Providers { get; } - /// - /// Sets the database default schema name used to store the documents. - /// - public string DatabaseSchemaName - { - get { return _databaseSchemaName; } - set { _databaseSchemaName = value.ToLowerInvariant(); } - } + public AdvancedOptions Advanced { get; } + + internal EventGraph EventGraph { get; } /// /// Configuration of event streams and projections @@ -114,10 +101,26 @@ public string DatabaseSchemaName /// /// Extension point to add custom Linq query parsers /// - public LinqParsing Linq { get; } = new LinqParsing(); + public LinqParsing Linq { get; } = new(); public ITransforms Transforms { get; } + /// + /// Apply conventional policies to how documents are mapped + /// + public PoliciesExpression Policies => new(this); + + IReadOnlyAdvancedOptions IReadOnlyStoreOptions.Advanced => Advanced; + + /// + /// Sets the database default schema name used to store the documents. + /// + public string DatabaseSchemaName + { + get => _databaseSchemaName; + set => _databaseSchemaName = value.ToLowerInvariant(); + } + /// /// Used to validate database object name lengths against Postgresql's NAMEDATALEN property to avoid /// Marten getting confused when comparing database schemas against the configuration. See @@ -127,11 +130,65 @@ public string DatabaseSchemaName public int NameDataLength { get; set; } = 64; /// - /// Gets Enum values stored as either integers or strings. This is configured on your ISerializer + /// Gets Enum values stored as either integers or strings. This is configured on your ISerializer /// public EnumStorage EnumStorage => Serializer().EnumStorage; + /// + /// Sets the batch size for updating or deleting documents in IDocumentSession.SaveChanges() / + /// IUnitOfWork.ApplyChanges() + /// + public int UpdateBatchSize { get; set; } = 500; + + public ISerializer Serializer() + { + return _serializer ?? SerializerFactory.New(); + } + + public IMartenLogger Logger() + { + return _logger ?? new NulloMartenLogger(); + } + + public IRetryPolicy RetryPolicy() + { + return _retryPolicy ?? new NulloRetryPolicy(); + } + + IReadOnlyList IReadOnlyStoreOptions.AllKnownDocumentTypes() + { + return Storage.AllDocumentMappings.OfType().ToList(); + } + + public IDocumentType FindOrResolveDocumentType(Type documentType) + { + return (Storage.FindMapping(documentType).Root as IDocumentType)!; + } + + public ITenancy Tenancy { get; set; } = null!; + + public bool PLV8Enabled { get; set; } = true; + + IReadOnlyEventStoreOptions IReadOnlyStoreOptions.Events => EventGraph; + + IReadOnlyLinqParsing IReadOnlyStoreOptions.Linq => Linq; + + IReadOnlyList IReadOnlyStoreOptions.Transforms() + { + return Transforms.AllFunctions().ToList(); + } + + /// + /// Configure Marten to create databases for tenants in case databases do not exist or need to be dropped & re-created + /// + /// Creating and dropping databases requires the CREATEDB privilege + public void CreateDatabasesForTenants(Action configure) + { + CreateDatabases = configure ?? throw new ArgumentNullException(nameof(configure)); + } + + internal void CreatePatching() { if (PLV8Enabled) @@ -178,13 +235,6 @@ public void Connection(Func source) Tenancy = new DefaultTenancy(new LambdaConnectionFactory(source), this); } - - /// - /// Sets the batch size for updating or deleting documents in IDocumentSession.SaveChanges() / - /// IUnitOfWork.ApplyChanges() - /// - public int UpdateBatchSize { get; set; } = 500; - /// /// Override the JSON serialization by ISerializer type /// @@ -231,36 +281,11 @@ public void UseDefaultSerialization( _serializer = new T(); } - public ISerializer Serializer() - { - return _serializer ?? SerializerFactory.New(); - } - - public IMartenLogger Logger() - { - return _logger ?? new NulloMartenLogger(); - } - public void Logger(IMartenLogger logger) { _logger = logger; } - public IRetryPolicy RetryPolicy() - { - return _retryPolicy ?? new NulloRetryPolicy(); - } - - IReadOnlyList IReadOnlyStoreOptions.AllKnownDocumentTypes() - { - return Storage.AllDocumentMappings.OfType().ToList(); - } - - public IDocumentType FindOrResolveDocumentType(Type documentType) - { - return (Storage.FindMapping(documentType).Root as IDocumentType)!; - } - public void RetryPolicy(IRetryPolicy retryPolicy) { _retryPolicy = retryPolicy; @@ -296,11 +321,20 @@ public void RegisterDocumentTypes(IEnumerable documentTypes) internal void AssertValidIdentifier(string name) { if (string.IsNullOrWhiteSpace(name)) + { throw new PostgresqlIdentifierInvalidException(name); + } + if (name.IndexOf(' ') >= 0) + { throw new PostgresqlIdentifierInvalidException(name); + } + if (name.Length < NameDataLength) + { return; + } + throw new PostgresqlIdentifierTooLongException(NameDataLength, name); } @@ -310,50 +344,28 @@ internal void ApplyConfiguration() Schema.For().DatabaseSchemaName(Events.DatabaseSchemaName); - foreach (var mapping in Storage.AllDocumentMappings) - { - mapping.CompileAndValidate(); - } + foreach (var mapping in Storage.AllDocumentMappings) mapping.CompileAndValidate(); } - public ITenancy Tenancy { get; set; } = null!; - - private readonly IList _policies = new List - { - new VersionedPolicy(), new SoftDeletedPolicy(), new TrackedPolicy(), new TenancyPolicy() - }; - internal void applyPolicies(DocumentMapping mapping) { - foreach (var policy in _policies) - { - policy.Apply(mapping); - } + foreach (var policy in _policies) policy.Apply(mapping); } /// - /// Validate that minimal options to initialize a document store have been specified + /// Validate that minimal options to initialize a document store have been specified /// internal void Validate() { if (Tenancy == null) { - throw new InvalidOperationException("Tenancy not specified - provide either connection string or connection factory through Connection(..)"); + throw new InvalidOperationException( + "Tenancy not specified - provide either connection string or connection factory through Connection(..)"); } } /// - /// Apply conventional policies to how documents are mapped - /// - public PoliciesExpression Policies => new PoliciesExpression(this); - - public bool PLV8Enabled { get; set; } = true; - - - private ImHashMap _childFieldMappings = ImHashMap.Empty; - - /// - /// These mappings should only be used for Linq querying within the SelectMany() body + /// These mappings should only be used for Linq querying within the SelectMany() body /// /// /// @@ -369,7 +381,26 @@ internal IFieldMapping ChildTypeMappingFor(Type type) _childFieldMappings = _childFieldMappings.AddOrUpdate(type, mapping); return mapping; + } + + internal ICompiledQuerySource GetCompiledQuerySourceFor(ICompiledQuery query, + IMartenSession session) + { + if (_querySources.TryFind(query.GetType(), out var source)) + { + return source; + } + + if (typeof(TOut).CanBeCastTo()) + { + throw InvalidCompiledQueryException.ForCannotBeAsync(query.GetType()); + } + + var plan = QueryCompiler.BuildPlan(session, query, this); + source = new CompiledQuerySourceBuilder(plan, this).Build(); + _querySources = _querySources.AddOrUpdate(query.GetType(), source); + return source; } public class PoliciesExpression @@ -382,7 +413,7 @@ public PoliciesExpression(StoreOptions parent) } /// - /// Add a pre-built Marten document policy + /// Add a pre-built Marten document policy /// /// /// @@ -392,7 +423,7 @@ public PoliciesExpression(StoreOptions parent) } /// - /// Add a pre-built Marten document policy + /// Add a pre-built Marten document policy /// /// /// @@ -403,8 +434,8 @@ public PoliciesExpression OnDocuments(IDocumentPolicy policy) } /// - /// Apply configuration to the persistence of all Marten document - /// types + /// Apply configuration to the persistence of all Marten document + /// types /// /// /// @@ -414,8 +445,8 @@ public PoliciesExpression ForAllDocuments(Action configure) } /// - /// Unless explicitly marked otherwise, all documents should - /// use conjoined multi-tenancy + /// Unless explicitly marked otherwise, all documents should + /// use conjoined multi-tenancy /// /// public PoliciesExpression AllDocumentsAreMultiTenanted() @@ -424,9 +455,9 @@ public PoliciesExpression AllDocumentsAreMultiTenanted() } /// - /// Turn off the informational metadata columns - /// in storage like the last modified, version, and - /// dot net type for leaner storage + /// Turn off the informational metadata columns + /// in storage like the last modified, version, and + /// dot net type for leaner storage /// public PoliciesExpression DisableInformationalFields() { @@ -438,36 +469,6 @@ public PoliciesExpression DisableInformationalFields() }); } } - - private ImHashMap _querySources = ImHashMap.Empty; - - internal ICompiledQuerySource GetCompiledQuerySourceFor(ICompiledQuery query, IMartenSession session) - { - if (_querySources.TryFind(query.GetType(), out var source)) - { - return source; - } - - if (typeof(TOut).CanBeCastTo()) - { - throw InvalidCompiledQueryException.ForCannotBeAsync(query.GetType()); - } - - var plan = QueryCompiler.BuildPlan(session, query, this); - source = new CompiledQuerySourceBuilder(plan, this).Build(); - _querySources = _querySources.AddOrUpdate(query.GetType(), source); - - return source; - } - - IReadOnlyEventStoreOptions IReadOnlyStoreOptions.Events => EventGraph; - - IReadOnlyLinqParsing IReadOnlyStoreOptions.Linq => Linq; - - IReadOnlyList IReadOnlyStoreOptions.Transforms() - { - return Transforms.AllFunctions().ToList(); - } } public interface IDocumentPolicy @@ -493,12 +494,12 @@ public void Apply(DocumentMapping mapping) public interface IReadOnlyAdvancedOptions { /// - /// Sets Enum values stored as either integers or strings for DuplicatedField. + /// Sets Enum values stored as either integers or strings for DuplicatedField. /// - EnumStorage DuplicatedFieldEnumStorage { get; } + EnumStorage DuplicatedFieldEnumStorage { get; } /// - /// Decides if `timestamp without time zone` database type should be used for `DateTime` DuplicatedField. + /// Decides if `timestamp without time zone` database type should be used for `DateTime` DuplicatedField. /// bool DuplicatedFieldUseTimestampWithoutTimeZoneForDateTime { get; } @@ -509,7 +510,7 @@ public interface IReadOnlyAdvancedOptions IReadOnlyHiloSettings HiloSequenceDefaults { get; } /// - /// Option to enable or disable usage of default tenant when using multi-tenanted documents + /// Option to enable or disable usage of default tenant when using multi-tenanted documents /// bool DefaultTenantUsageEnabled { get; } } @@ -524,23 +525,6 @@ internal AdvancedOptions(StoreOptions storeOptions) _storeOptions = storeOptions; } - /// - /// Sets Enum values stored as either integers or strings for DuplicatedField. - /// - public EnumStorage DuplicatedFieldEnumStorage - { - get { return _duplicatedFieldEnumStorage ?? _storeOptions.EnumStorage; } - set - { - _duplicatedFieldEnumStorage = value; - } - } - - /// - /// Decides if `timestamp without time zone` database type should be used for `DateTime` DuplicatedField. - /// - public bool DuplicatedFieldUseTimestampWithoutTimeZoneForDateTime { get; set; } = true; - /// /// Global default parameters for Hilo sequences within the DocumentStore. Can be overridden per document @@ -548,22 +532,33 @@ public EnumStorage DuplicatedFieldEnumStorage /// public HiloSettings HiloSequenceDefaults { get; } = new(); - IReadOnlyHiloSettings IReadOnlyAdvancedOptions.HiloSequenceDefaults => HiloSequenceDefaults; - /// - /// Option to enable or disable usage of default tenant when using multi-tenanted documents + /// Allows you to modify how the DDL for document tables and upsert functions is + /// written /// - public bool DefaultTenantUsageEnabled { get; set; } = true; + public DdlRules DdlRules { get; } = new(); + /// + /// Sets Enum values stored as either integers or strings for DuplicatedField. + /// + public EnumStorage DuplicatedFieldEnumStorage + { + get => _duplicatedFieldEnumStorage ?? _storeOptions.EnumStorage; + set => _duplicatedFieldEnumStorage = value; + } /// - /// Allows you to modify how the DDL for document tables and upsert functions is - /// written + /// Decides if `timestamp without time zone` database type should be used for `DateTime` DuplicatedField. /// - public DdlRules DdlRules { get; } = new DdlRules(); + public bool DuplicatedFieldUseTimestampWithoutTimeZoneForDateTime { get; set; } = true; + IReadOnlyHiloSettings IReadOnlyAdvancedOptions.HiloSequenceDefaults => HiloSequenceDefaults; - } + /// + /// Option to enable or disable usage of default tenant when using multi-tenanted documents + /// + public bool DefaultTenantUsageEnabled { get; set; } = true; + } } diff --git a/src/Marten/Transforms/DocumentTransformOperationFragment.cs b/src/Marten/Transforms/DocumentTransformOperationFragment.cs index cdcb7b75a4..a4255b52b1 100644 --- a/src/Marten/Transforms/DocumentTransformOperationFragment.cs +++ b/src/Marten/Transforms/DocumentTransformOperationFragment.cs @@ -1,6 +1,7 @@ using Marten.Internal.Operations; using Marten.Internal.Storage; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Schema; using Marten.Schema.Identity; using Marten.Util; diff --git a/src/Marten/Transforms/ITransforms.cs b/src/Marten/Transforms/ITransforms.cs index bcff8b2dee..9b8bd4d42e 100644 --- a/src/Marten/Transforms/ITransforms.cs +++ b/src/Marten/Transforms/ITransforms.cs @@ -4,6 +4,7 @@ using System.Linq; using Baseline; using Marten.Storage; +using Weasel.Postgresql; namespace Marten.Transforms { @@ -130,7 +131,7 @@ public ISchemaObject[] Objects public Type StorageType { get; } = typeof(Transforms); public string Identifier { get; } = "transforms"; - public void WritePermissions(DdlRules rules, StringWriter writer) + public void WritePermissions(DdlRules rules, TextWriter writer) { // Nothing } diff --git a/src/Marten/Transforms/TransformFunction.cs b/src/Marten/Transforms/TransformFunction.cs index 7262accbf2..f04aa9e84f 100644 --- a/src/Marten/Transforms/TransformFunction.cs +++ b/src/Marten/Transforms/TransformFunction.cs @@ -2,8 +2,8 @@ using System.IO; using System.Linq; using Baseline; -using Marten.Schema; -using Marten.Storage; +using Weasel.Postgresql; +using Weasel.Postgresql.Functions; namespace Marten.Transforms { @@ -28,17 +28,12 @@ private IEnumerable allArgs() return new[] { "doc" }.Concat(OtherArgs); } - public override void Write(DdlRules rules, StringWriter writer) + public override void WriteCreateStatement(DdlRules rules, TextWriter writer) { writer.WriteLine(GenerateFunction()); writer.WriteLine(); } - protected override string toDropSql() - { - return ToDropSignature(); - } - public string ToDropSignature() { var signature = allArgs().Select(_ => $"JSONB").Join(", "); diff --git a/src/Marten/UniqueIndexAttribute.cs b/src/Marten/UniqueIndexAttribute.cs index e7dab6e12e..2705874ba6 100644 --- a/src/Marten/UniqueIndexAttribute.cs +++ b/src/Marten/UniqueIndexAttribute.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Reflection; using Marten.Schema.Indexing.Unique; +using Weasel.Postgresql.Tables; namespace Marten.Schema { diff --git a/src/Marten/Util/CommandBuilder.cs b/src/Marten/Util/CommandBuilder.cs deleted file mode 100644 index 6e7e3414b6..0000000000 --- a/src/Marten/Util/CommandBuilder.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System; -using System.Reflection; -using System.Text; -using Npgsql; -using NpgsqlTypes; -#nullable enable -namespace Marten.Util -{ - public class CommandBuilder: IDisposable - { - private readonly NpgsqlCommand _command; - - // TEMP -- will shift this to being pooled later - private readonly StringBuilder _sql = new StringBuilder(); - - public CommandBuilder() : this(new NpgsqlCommand()) - { - } - - public CommandBuilder(NpgsqlCommand command) - { - _command = command; - } - - public NpgsqlCommand Compile() - { - _command.CommandText = _sql.ToString(); - return _command; - } - - public void Dispose() - { - } - - public static string BuildJsonStringLocator(string column, MemberInfo[] members, Casing casing = Casing.Default) - { - var locator = new StringBuilder(column); - var depth = 1; - foreach (var memberInfo in members) - { - locator.Append(depth == members.Length ? " ->> " : " -> "); - locator.Append($"'{memberInfo.Name.FormatCase(casing)}'"); - depth++; - } - - return locator.ToString(); - } - - public static string BuildJsonObjectLocator(string column, MemberInfo[] members, Casing casing = Casing.Default) - { - var locator = new StringBuilder(column); - foreach (var memberInfo in members) locator.Append($" -> '{memberInfo.Name.FormatCase(casing)}'"); - return locator.ToString(); - } - - public static NpgsqlCommand BuildCommand(Action configure) - { - var cmd = new NpgsqlCommand(); - using (var builder = new CommandBuilder(cmd)) - { - configure(builder); - - cmd.CommandText = builder.ToString(); - } - - return cmd; - } - - public void Append(string text) - { - _sql.Append(text); - } - - public void Append(object o) - { - _sql.Append(o); - } - - public void AppendPathToObject(MemberInfo[] members, string column) - { - _sql.Append(BuildJsonObjectLocator(column, members)); - } - - public void AppendPathToValue(MemberInfo[] members, string column) - { - _sql.Append(BuildJsonStringLocator(column, members)); - } - - public override string ToString() - { - return _sql.ToString(); - } - - public void Clear() - { - _sql.Clear(); - } - - public void AddParameters(object parameters) - { - _command.AddParameters(parameters); - } - - public NpgsqlParameter AddParameter(object value, NpgsqlDbType? dbType = null) - { - return _command.AddParameter(value, dbType); - } - - public NpgsqlParameter AddJsonParameter(string json) - { - return _command.AddParameter(json, NpgsqlDbType.Jsonb); - } - - public NpgsqlParameter AddNamedParameter(string name, object value) - { - return _command.AddNamedParameter(name, value); - } - - public void UseParameter(NpgsqlParameter parameter) - { - var sql = _sql.ToString(); - _sql.Clear(); - _sql.Append(sql.UseParameter(parameter)); - } - - public NpgsqlParameter[] AppendWithParameters(string text) - { - var split = text.Split('?'); - var parameters = new NpgsqlParameter[split.Length - 1]; - - _sql.Append(split[0]); - for (var i = 0; i < parameters.Length; i++) - { - var parameter = _command.AddParameter(DBNull.Value); - parameters[i] = parameter; - _sql.Append(':'); - _sql.Append(parameter.ParameterName); - _sql.Append(split[i + 1]); - } - - return parameters; - } - } -} diff --git a/src/Marten/Util/CommandExtensions.cs b/src/Marten/Util/CommandExtensions.cs index bcd84f612a..1e343cc227 100644 --- a/src/Marten/Util/CommandExtensions.cs +++ b/src/Marten/Util/CommandExtensions.cs @@ -7,6 +7,7 @@ using Marten.Internal; using Marten.Linq.QueryHandlers; using Marten.Linq.SqlGeneration; +using Weasel.Postgresql; using Marten.Schema; using Marten.Schema.Arguments; using Npgsql; @@ -14,7 +15,7 @@ #nullable enable namespace Marten.Util { - public static class CommandExtensions + internal static class CommandExtensions { public static NpgsqlCommand BuildCommand(this IMartenSession session, Statement statement) { @@ -77,181 +78,6 @@ public static NpgsqlCommand BuildCommand(this IMartenSession session, IEnumerabl return command; } - public static int RunSql(this NpgsqlConnection conn, params string[] sqls) - { - var sql = sqls.Join(";"); - return conn.CreateCommand().Sql(sql).ExecuteNonQuery(); - } - - public static IEnumerable Fetch(this NpgsqlCommand cmd, string sql, Func transform, params object[] parameters) - { - cmd.WithText(sql); - parameters.Each(x => - { - var param = cmd.AddParameter(x); - cmd.CommandText = cmd.CommandText.UseParameter(param); - }); - - var list = new List(); - - using (var reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - list.Add(transform(reader)); - } - } - - return list; - } - - public static void AddParameters(this NpgsqlCommand command, object? parameters) - { - if (parameters == null) - return; - - var parameterDictionary = parameters.GetType().GetProperties().ToDictionary(x => x.Name, x => x.GetValue(parameters, null)); - - foreach (var item in parameterDictionary) - { - var parameter = command.CreateParameter(); - parameter.ParameterName = item.Key; - parameter.Value = item.Value ?? DBNull.Value; - - command.Parameters.Add(parameter); - } - } - - public static NpgsqlParameter AddParameter(this NpgsqlCommand command, object value, NpgsqlDbType? dbType = null) - { - var name = "p" + command.Parameters.Count; - - var parameter = command.CreateParameter(); - parameter.ParameterName = name; - parameter.Value = value ?? DBNull.Value; - - if (dbType.HasValue) - { - parameter.NpgsqlDbType = dbType.Value; - } - - command.Parameters.Add(parameter); - - return parameter; - } - - public static NpgsqlParameter AddNamedParameter(this NpgsqlCommand command, string name, object value) - { - var existing = command.Parameters.FirstOrDefault(x => x.ParameterName == name); - if (existing != null) return existing; - - var parameter = command.CreateParameter(); - parameter.ParameterName = name; - parameter.Value = value ?? DBNull.Value; - command.Parameters.Add(parameter); - - return parameter; - } - - public static NpgsqlCommand With(this NpgsqlCommand command, string name, Guid value) - { - var parameter = command.CreateParameter(); - parameter.ParameterName = name; - parameter.NpgsqlDbType = NpgsqlDbType.Uuid; - parameter.Value = value; - - command.Parameters.Add(parameter); - - return command; - } - - public static NpgsqlCommand With(this NpgsqlCommand command, string name, string? value) - { - var parameter = command.CreateParameter(); - parameter.ParameterName = name; - parameter.NpgsqlDbType = NpgsqlDbType.Varchar; - - if (value == null) - { - parameter.Value = DBNull.Value; - } - else - { - parameter.Value = value; - } - - command.Parameters.Add(parameter); - - return command; - } - - public static NpgsqlCommand With(this NpgsqlCommand command, string name, object value) - { - var parameter = command.CreateParameter(); - parameter.ParameterName = name; - parameter.Value = value ?? DBNull.Value; - command.Parameters.Add(parameter); - - return command; - } - - public static NpgsqlCommand With(this NpgsqlCommand command, string name, object value, NpgsqlDbType dbType) - { - var parameter = command.CreateParameter(); - parameter.ParameterName = name; - parameter.Value = value ?? DBNull.Value; - parameter.NpgsqlDbType = dbType; - command.Parameters.Add(parameter); - - return command; - } - - public static NpgsqlCommand WithJsonParameter(this NpgsqlCommand command, string name, string json) - { - command.Parameters.Add(name, NpgsqlDbType.Jsonb).Value = json; - - return command; - } - - public static NpgsqlCommand Sql(this NpgsqlCommand cmd, string sql) - { - cmd.CommandText = sql; - return cmd; - } - public static NpgsqlCommand CallsSproc(this NpgsqlCommand cmd, DbObjectName function) - { - if (cmd == null) - throw new ArgumentNullException(nameof(cmd)); - if (function == null) - throw new ArgumentNullException(nameof(function)); - - cmd.CommandText = function.QualifiedName; - cmd.CommandType = CommandType.StoredProcedure; - - return cmd; - } - - public static NpgsqlCommand Returns(this NpgsqlCommand command, string name, NpgsqlDbType type) - { - var parameter = command.AddParameter(name); - parameter.NpgsqlDbType = type; - parameter.Direction = ParameterDirection.ReturnValue; - return command; - } - - public static NpgsqlCommand WithText(this NpgsqlCommand command, string sql) - { - command.CommandText = sql; - return command; - } - - public static NpgsqlCommand CreateCommand(this NpgsqlConnection conn, string command) - { - var cmd = conn.CreateCommand(); - cmd.CommandText = command; - - return cmd; - } } } diff --git a/src/Marten/Util/ImTools.cs b/src/Marten/Util/ImTools.cs deleted file mode 100644 index 9eae517f62..0000000000 --- a/src/Marten/Util/ImTools.cs +++ /dev/null @@ -1,1465 +0,0 @@ -// From https://raw.githubusercontent.com/dadhi/ImTools/master/src/ImTools/ImTools.cs - -/* -The MIT License (MIT) - -Copyright (c) 2016-2018 Maksim Volkau - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading; - -namespace Marten.Util -{ // For [MethodImpl(AggressiveInlining)] - /// Helpers for functional composition - public static class Fun - { - /// Identity function returning passed argument as result. - public static T It(T x) => x; - - /// Forward pipe operator to combine multiple actions. - public static R Do(this T x, Func map) => map(x); - - /// Forward pipe operator to combine multiple actions. - public static T Do(this T x, Action effect) - { - effect(x); - return x; - } - } - - /// Methods to work with immutable arrays, and general array sugar. - public static class ArrayTools - { - private static class EmptyArray - { - public static readonly T[] Value = new T[0]; - } - - /// Returns singleton empty array of provided type. - /// Array item type. Empty array. - public static T[] Empty() => EmptyArray.Value; - - /// Wraps item in array. - public static T[] One(this T one) => new[] { one }; - - /// Returns true if array is null or have no items. Type of array item. - /// Source array to check. True if null or has no items, false otherwise. - public static bool IsNullOrEmpty(this T[] source) => source == null || source.Length == 0; - - /// Returns empty array instead of null, or source array otherwise. Type of array item. - public static T[] EmptyIfNull(this T[] source) => source ?? Empty(); - - /// Returns source enumerable if it is array, otherwise converts source to array. - public static T[] ToArrayOrSelf(this IEnumerable source) => - source == null ? Empty() : - (source as T[] ?? (((source as ICollection)?.Count ?? 0) == 0 ? Empty() : source.ToArray())); - - /// Returns new array consisting from all items from source array then all items from added array. - /// If source is null or empty, then added array will be returned. - /// If added is null or empty, then source will be returned. - /// Array item type. - /// Array with leading items. - /// Array with following items. - /// New array with items of source and added arrays. - public static T[] Append(this T[] source, params T[] added) - { - if (added == null || added.Length == 0) - return source; - if (source == null || source.Length == 0) - return added; - - var result = new T[source.Length + added.Length]; - Array.Copy(source, 0, result, 0, source.Length); - if (added.Length == 1) - result[source.Length] = added[0]; - else - Array.Copy(added, 0, result, source.Length, added.Length); - return result; - } - - /// Performant concat of enumerables in case of arrays. - /// But performance will degrade if you use Concat().Where(). - /// Type of item. - /// goes first. - /// appended to source. - /// empty array or concat of source and other. - public static T[] Append(this IEnumerable source, IEnumerable other) => - source.ToArrayOrSelf().Append(other.ToArrayOrSelf()); - - /// Returns new array with appended, - /// or at , if specified. - /// If source array could be null or empty, then single value item array will be created despite any index. - /// Array item type. - /// Array to append value to. - /// Value to append. - /// (optional) Index of value to update. - /// New array with appended or updated value. - public static T[] AppendOrUpdate(this T[] source, T value, int index = -1) - { - if (source == null || source.Length == 0) - return new[] { value }; - var sourceLength = source.Length; - index = index < 0 ? sourceLength : index; - var result = new T[index < sourceLength ? sourceLength : sourceLength + 1]; - Array.Copy(source, result, sourceLength); - result[index] = value; - return result; - } - - /// Calls predicate on each item in array until predicate returns true, - /// then method will return this item index, or if predicate returns false for each item, method will return -1. - /// Type of array items. - /// Source array: if null or empty, then method will return -1. - /// Delegate to evaluate on each array item until delegate returns true. - /// Index of item for which predicate returns true, or -1 otherwise. - public static int IndexOf(this T[] source, Func predicate) - { - if (source != null && source.Length != 0) - for (var i = 0; i < source.Length; ++i) - if (predicate(source[i])) - return i; - return -1; - } - - /// Looks up for item in source array equal to provided value, and returns its index, or -1 if not found. - /// Type of array items. - /// Source array: if null or empty, then method will return -1. - /// Value to look up. - /// Index of item equal to value, or -1 item is not found. - public static int IndexOf(this T[] source, T value) - { - if (source != null && source.Length != 0) - for (var i = 0; i < source.Length; ++i) - { - var item = source[i]; - if (Equals(item, value)) - return i; - } - return -1; - } - - /// Produces new array without item at specified . - /// Will return array if index is out of bounds, or source is null/empty. - /// Type of array item. - /// Input array. Index if item to remove. - /// New array with removed item at index, or input source array if index is not in array. - public static T[] RemoveAt(this T[] source, int index) - { - if (source == null || source.Length == 0 || index < 0 || index >= source.Length) - return source; - if (index == 0 && source.Length == 1) - return new T[0]; - var result = new T[source.Length - 1]; - if (index != 0) - Array.Copy(source, 0, result, 0, index); - if (index != result.Length) - Array.Copy(source, index + 1, result, index, result.Length - index); - return result; - } - - /// Looks for item in array using equality comparison, and returns new array with found item remove, or original array if not item found. - /// Type of array item. - /// Input array. Value to find and remove. - /// New array with value removed or original array if value is not found. - public static T[] Remove(this T[] source, T value) => - source.RemoveAt(source.IndexOf(value)); - - /// Returns first item matching the , or default item value. - /// item type - /// items collection to search - /// condition to evaluate for each item. - /// First item matching condition or default value. - public static T FindFirst(this T[] source, Func predicate) - { - if (source != null && source.Length != 0) - for (var i = 0; i < source.Length; ++i) - { - var item = source[i]; - if (predicate(item)) - return item; - } - return default(T); - } - - /// Returns first item matching the , or default item value. - /// item type - /// items collection to search - /// condition to evaluate for each item. - /// First item matching condition or default value. - public static T FindFirst(this IEnumerable source, Func predicate) - { - if (source is T[] sourceArr) - return sourceArr.FindFirst(predicate); - return source.FirstOrDefault(predicate); - } - - private static T[] AppendTo(T[] source, int sourcePos, int count, T[] results = null) - { - if (results == null) - { - var newResults = new T[count]; - if (count == 1) - newResults[0] = source[sourcePos]; - else - for (int i = 0, j = sourcePos; i < count; ++i, ++j) - newResults[i] = source[j]; - return newResults; - } - - var matchCount = results.Length; - var appendedResults = new T[matchCount + count]; - if (matchCount == 1) - appendedResults[0] = results[0]; - else - Array.Copy(results, 0, appendedResults, 0, matchCount); - - if (count == 1) - appendedResults[matchCount] = source[sourcePos]; - else - Array.Copy(source, sourcePos, appendedResults, matchCount, count); - - return appendedResults; - } - - private static R[] AppendTo(T[] source, int sourcePos, int count, Func map, R[] results = null) - { - if (results == null || results.Length == 0) - { - var newResults = new R[count]; - if (count == 1) - newResults[0] = map(source[sourcePos]); - else - for (int i = 0, j = sourcePos; i < count; ++i, ++j) - newResults[i] = map(source[j]); - return newResults; - } - - var oldResultsCount = results.Length; - var appendedResults = new R[oldResultsCount + count]; - if (oldResultsCount == 1) - appendedResults[0] = results[0]; - else - Array.Copy(results, 0, appendedResults, 0, oldResultsCount); - - if (count == 1) - appendedResults[oldResultsCount] = map(source[sourcePos]); - else - { - for (int i = oldResultsCount, j = sourcePos; i < appendedResults.Length; ++i, ++j) - appendedResults[i] = map(source[j]); - } - - return appendedResults; - } - - /// Where method similar to Enumerable.Where but more performant and non necessary allocating. - /// It returns source array and does Not create new one if all items match the condition. - /// Type of source items. - /// If null, the null will be returned. - /// Condition to keep items. - /// New array if some items are filter out. Empty array if all items are filtered out. Original array otherwise. - public static T[] Match(this T[] source, Func condition) - { - if (source == null || source.Length == 0) - return source; - - if (source.Length == 1) - return condition(source[0]) ? source : Empty(); - - if (source.Length == 2) - { - var condition0 = condition(source[0]); - var condition1 = condition(source[1]); - return condition0 && condition1 ? new[] { source[0], source[1] } - : condition0 ? new[] { source[0] } - : condition1 ? new[] { source[1] } - : Empty(); - } - - var matchStart = 0; - T[] matches = null; - var matchFound = false; - - var i = 0; - while (i < source.Length) - { - matchFound = condition(source[i]); - if (!matchFound) - { - // for accumulated matched items - if (i != 0 && i > matchStart) - matches = AppendTo(source, matchStart, i - matchStart, matches); - matchStart = i + 1; // guess the next match start will be after the non-matched item - } - ++i; - } - - // when last match was found but not all items are matched (hence matchStart != 0) - if (matchFound && matchStart != 0) - return AppendTo(source, matchStart, i - matchStart, matches); - - if (matches != null) - return matches; - - if (matchStart != 0) // no matches - return Empty(); - - return source; - } - - /// Where method similar to Enumerable.Where but more performant and non necessary allocating. - /// It returns source array and does Not create new one if all items match the condition. - /// Type of source items. Type of result items. - /// If null, the null will be returned. - /// Condition to keep items. Converter from source to result item. - /// New array of result items. - public static R[] Match(this T[] source, Func condition, Func map) - { - if (source == null) - return null; - - if (source.Length == 0) - return Empty(); - - if (source.Length == 1) - { - var item = source[0]; - return condition(item) ? new[] { map(item) } : Empty(); - } - - if (source.Length == 2) - { - var condition0 = condition(source[0]); - var condition1 = condition(source[1]); - return condition0 && condition1 ? new[] { map(source[0]), map(source[1]) } - : condition0 ? new[] { map(source[0]) } - : condition1 ? new[] { map(source[1]) } - : Empty(); - } - - var matchStart = 0; - R[] matches = null; - var matchFound = false; - - var i = 0; - while (i < source.Length) - { - matchFound = condition(source[i]); - if (!matchFound) - { - // for accumulated matched items - if (i != 0 && i > matchStart) - matches = AppendTo(source, matchStart, i - matchStart, map, matches); - matchStart = i + 1; // guess the next match start will be after the non-matched item - } - ++i; - } - - // when last match was found but not all items are matched (hence matchStart != 0) - if (matchFound && matchStart != 0) - return AppendTo(source, matchStart, i - matchStart, map, matches); - - if (matches != null) - return matches; - - if (matchStart != 0) // no matches - return Empty(); - - return AppendTo(source, 0, source.Length, map); - } - - /// Maps all items from source to result array. - /// Source item type Result item type - /// Source items Function to convert item from source to result. - /// Converted items - public static R[] Map(this T[] source, Func map) - { - if (source == null) - return null; - - var sourceCount = source.Length; - if (sourceCount == 0) - return Empty(); - - if (sourceCount == 1) - return new[] { map(source[0]) }; - - if (sourceCount == 2) - return new[] { map(source[0]), map(source[1]) }; - - if (sourceCount == 3) - return new[] { map(source[0]), map(source[1]), map(source[2]) }; - - var results = new R[sourceCount]; - for (var i = 0; i < source.Length; i++) - results[i] = map(source[i]); - return results; - } - - /// Maps all items from source to result collection. - /// If possible uses fast array Map otherwise Enumerable.Select. - /// Source item type Result item type - /// Source items Function to convert item from source to result. - /// Converted items - public static IEnumerable Map(this IEnumerable source, Func map) - { - if (source == null) - return null; - if (source is T[] arr) - return arr.Map(map); - return source.Select(map); - } - - /// If is array uses more effective Match for array, otherwise just calls Where - /// Type of source items. - /// If null, the null will be returned. - /// Condition to keep items. - /// Result items, may be an array. - public static IEnumerable Match(this IEnumerable source, Func condition) - { - if (source == null) - return null; - if (source is T[] arr) - return arr.Match(condition); - return source.Where(condition); - } - - /// If is array uses more effective Match for array, - /// otherwise just calls Where, Select - /// Type of source items. Type of result items. - /// If null, the null will be returned. - /// Condition to keep items. Converter from source to result item. - /// Result items, may be an array. - public static IEnumerable Match(this IEnumerable source, Func condition, Func map) - { - if (source == null) - return null; - if (source is T[] arr) - return arr.Match(condition, map); - return source.Where(condition).Select(map); - } - } - - /// Wrapper that provides optimistic-concurrency Swap operation implemented using . - /// Type of object to wrap. - public sealed class Ref where T : class - { - /// Gets the wrapped value. - public T Value => _value; - - /// Creates ref to object, optionally with initial value provided. - /// (optional) Initial value. - public Ref(T initialValue = default(T)) - { - _value = initialValue; - } - - /// Exchanges currently hold object with - see for details. - /// Delegate to produce new object value from current one passed as parameter. - /// Returns old object value the same way as - /// Important: May be called multiple times to retry update with value concurrently changed by other code. - public T Swap(Func getNewValue) => - Ref.Swap(ref _value, getNewValue); - - /// Just sets new value ignoring any intermingled changes. - /// old value - public T Swap(T newValue) => - Interlocked.Exchange(ref _value, newValue); - - /// Compares current Referred value with and if equal replaces current with - /// - /// True if current value was replaced with new value, and false if current value is outdated (already changed by other party). - /// [!CDATA[ - /// var value = SomeRef.Value; - /// if (!SomeRef.TrySwapIfStillCurrent(value, Update(value)) - /// SomeRef.Swap(v => Update(v)); // fallback to normal Swap with delegate allocation - /// ]] - public bool TrySwapIfStillCurrent(T currentValue, T newValue) => - Interlocked.CompareExchange(ref _value, newValue, currentValue) == currentValue; - - private T _value; - } - - /// Provides optimistic-concurrency consistent operation. - public static class Ref - { - /// Factory for with type of value inference. - /// Type of value to wrap. - /// Initial value to wrap. - /// New ref. - public static Ref Of(T value) where T : class => new Ref(value); - - /// Creates new ref to the value of original ref. Ref value type. - /// Original ref. New ref to original value. - public static Ref NewRef(this Ref original) where T : class => Of(original.Value); - - /// First, it evaluates new value using function. - /// Second, it checks that original value is not changed. - /// If it is changed it will retry first step, otherwise it assigns new value and returns original (the one used for ). - /// Type of value to swap. - /// Reference to change to new value - /// Delegate to get value from old one. - /// Old/original value. By analogy with . - /// Important: May be called multiple times to retry update with value concurrently changed by other code. - public static T Swap(ref T value, Func getNewValue) where T : class - { - var retryCount = 0; - while (true) - { - var oldValue = value; - var newValue = getNewValue(oldValue); - if (Interlocked.CompareExchange(ref value, newValue, oldValue) == oldValue) - return oldValue; - if (++retryCount > RETRY_COUNT_UNTIL_THROW) - throw new InvalidOperationException(_errorRetryCountExceeded); - } - } - - private const int RETRY_COUNT_UNTIL_THROW = 50; - - private static readonly string _errorRetryCountExceeded = - "Ref retried to Update for " + RETRY_COUNT_UNTIL_THROW + " times But there is always someone else intervened."; - } - - /// Immutable Key-Value pair. It is reference type (could be check for null), - /// which is different from System value type . - /// In addition provides and implementations. - /// Type of Key.Type of Value. - public class KV - { - /// Key. - public readonly K Key; - - /// Value. - public readonly V Value; - - /// Creates Key-Value object by providing key and value. Does Not check either one for null. - /// key.value. - public KV(K key, V value) - { - Key = key; - Value = value; - } - - /// Creates nice string view.String representation. - public override string ToString() - { - var s = new StringBuilder('{'); - if (Key != null) - s.Append(Key); - s.Append(','); - if (Value != null) - s.Append(Value); - s.Append('}'); - return s.ToString(); - } - - /// Returns true if both key and value are equal to corresponding key-value of other object. - /// Object to check equality with. True if equal. - public override bool Equals(object obj) - { - return obj is KV other - && (ReferenceEquals(other.Key, Key) || Equals(other.Key, Key)) - && (ReferenceEquals(other.Value, Value) || Equals(other.Value, Value)); - } - - /// Combines key and value hash code. R# generated default implementation. - /// Combined hash code for key-value. - public override int GetHashCode() - { - unchecked - { - return ((object)Key == null ? 0 : Key.GetHashCode() * 397) - ^ ((object)Value == null ? 0 : Value.GetHashCode()); - } - } - } - - /// Helpers for . - public static class KV - { - /// Creates the key value pair. - /// Key type Value type - /// Key Value New pair. - public static KV Of(K key, V value) => new KV(key, value); - - /// Creates the new pair with new key and old value. - /// Key type Value type - /// Source value New key New pair - public static KV WithKey(this KV source, K key) => new KV(key, source.Value); - - /// Creates the new pair with old key and new value. - /// Key type Value type - /// Source value New value. New pair - public static KV WithValue(this KV source, V value) => new KV(source.Key, value); - } - - /// Simple helper for creation of the pair of two parts. - public static class KeyValuePair - { - /// Pairs key with value. - public static KeyValuePair Pair(this K key, V value) => - new KeyValuePair(key, value); - } - - /// Helper structure which allows to distinguish null value from the default value for optional parameter. - public struct Opt - { - /// Allows to transparently convert parameter argument to opt structure. - public static implicit operator Opt(T value) => new Opt(value); - - /// Argument value. - public readonly T Value; - - /// Indicates that value is provided. - public readonly bool HasValue; - - /// Wraps passed value in structure. Sets the flag that value is present. - public Opt(T value) - { - HasValue = true; - Value = value; - } - - /// Helper to get value or default value if value is not present. - public T OrDefault(T defaultValue = default(T)) => HasValue ? Value : defaultValue; - } - - /// Immutable list - simplest linked list with Head and Rest. - /// Type of the item. - public sealed class ImList - { - /// Empty list to Push to. - public static readonly ImList Empty = new ImList(); - - /// True for empty list. - public bool IsEmpty => Tail == null; - - /// First value in a list. - public readonly T Head; - - /// The rest of values or Empty if list has a single value. - public readonly ImList Tail; - - /// Prepends new value and returns new list. - /// New first value. - /// List with the new head. - public ImList Prep(T head) => new ImList(head, this); - - /// Enumerates the list. - /// Each item in turn. - public IEnumerable Enumerate() - { - if (IsEmpty) - yield break; - for (var list = this; !list.IsEmpty; list = list.Tail) - yield return list.Head; - } - - #region Implementation - - private ImList() - { - } - - private ImList(T head, ImList tail) - { - Head = head; - Tail = tail; - } - - #endregion Implementation - } - - /// Extension methods providing basic operations on a list. - public static class ImList - { - /// This a basically a Fold function, to address needs in Map, Filter, Reduce. - /// Type of list item. - /// Type of result. - /// List to fold. - /// From were to start. - /// Collects list item into result - /// Return result or for empty list. - public static R To(this ImList source, R initialValue, Func collect) - { - if (source.IsEmpty) - return initialValue; - var value = initialValue; - for (; !source.IsEmpty; source = source.Tail) - value = collect(source.Head, value); - return value; - } - - /// Form of fold function with element index for convenience. - /// Type of list item. - /// Type of result. - /// List to fold. - /// From were to start. - /// Collects list item into result - /// Return result or for empty list. - public static R To(this ImList source, R initialValue, Func collect) - { - if (source.IsEmpty) - return initialValue; - var value = initialValue; - for (var i = 0; !source.IsEmpty; source = source.Tail) - value = collect(source.Head, i++, value); - return value; - } - - /// Returns new list in reverse order. - /// List item type List to reverse. - /// New list. If list consist on single element, then the same list. - public static ImList Reverse(this ImList source) - { - if (source.IsEmpty || source.Tail.IsEmpty) - return source; - return source.To(ImList.Empty, (it, _) => _.Prep(it)); - } - - /// Maps the items from the first list to the result list. - /// source item type. - /// result item type. - /// input list. converter func. - /// result list. - public static ImList Map(this ImList source, Func map) - { - return source.To(ImList.Empty, (it, _) => _.Prep(map(it))).Reverse(); - } - - /// Maps the items from the first list to the result list with item index. - /// source item type. - /// result item type. - /// input list. converter func. - /// result list. - public static ImList Map(this ImList source, Func map) - { - return source.To(ImList.Empty, (it, i, _) => _.Prep(map(it, i))).Reverse(); - } - - /// Copies list to array. - /// list to convert. - /// Array with list items. - public static T[] ToArray(this ImList source) - { - if (source.IsEmpty) - return ArrayTools.Empty(); - if (source.Tail.IsEmpty) - return new[] { source.Head }; - return source.Enumerate().ToArray(); - } - } - - /// Given the old value should and the new value should return result updated value. - public delegate V Update(V oldValue, V newValue); - - /// Immutable http://en.wikipedia.org/wiki/AVL_tree with integer keys and values. - public sealed class ImMap - { - /// Empty tree to start with. - public static readonly ImMap Empty = new ImMap(); - - /// Key. - public readonly int Key; - - /// Value. - public readonly V Value; - - /// Left sub-tree/branch, or empty. - public readonly ImMap Left; - - /// Right sub-tree/branch, or empty. - public readonly ImMap Right; - - /// Height of longest sub-tree/branch plus 1. It is 0 for empty tree, and 1 for single node tree. - public readonly int Height; - - /// Returns true is tree is empty. - public bool IsEmpty => Height == 0; - - /// Returns new tree with added or updated value for specified key. - /// - /// New tree. - public ImMap AddOrUpdate(int key, V value) => - AddOrUpdateImpl(key, value); - - /// Returns new tree with added or updated value for specified key. - /// Key Value - /// (optional) Delegate to calculate new value from and old and a new value. - /// New tree. - public ImMap AddOrUpdate(int key, V value, Update updateValue) => - AddOrUpdateImpl(key, value, false, updateValue); - - /// Returns new tree with updated value for the key, Or the same tree if key was not found. - /// - /// New tree if key is found, or the same tree otherwise. - public ImMap Update(int key, V value) => - AddOrUpdateImpl(key, value, true, null); - - /// Get value for found key or null otherwise. - /// (optional) Value to return if key is not found. - /// Found value or . - public V GetValueOrDefault(int key, V defaultValue = default(V)) - { - var node = this; - while (node.Height != 0 && node.Key != key) - node = key < node.Key ? node.Left : node.Right; - return node.Height != 0 ? node.Value : defaultValue; - } - - /// Returns true if key is found and sets the value. - /// Key to look for. Result value - /// True if key found, false otherwise. - public bool TryFind(int key, out V value) - { - var hash = key.GetHashCode(); - - var node = this; - while (node.Height != 0 && node.Key != key) - node = hash < node.Key ? node.Left : node.Right; - - if (node.Height != 0) - { - value = node.Value; - return true; - } - - value = default(V); - return false; - } - - /// Returns all sub-trees enumerated from left to right. - /// Enumerated sub-trees or empty if tree is empty. - public IEnumerable> Enumerate() - { - if (Height == 0) - yield break; - - var parents = new ImMap[Height]; - - var node = this; - var parentCount = -1; - while (node.Height != 0 || parentCount != -1) - { - if (node.Height != 0) - { - parents[++parentCount] = node; - node = node.Left; - } - else - { - node = parents[parentCount--]; - yield return node; - node = node.Right; - } - } - } - - /// Removes or updates value for specified key, or does nothing if key is not found. - /// Based on Eric Lippert http://blogs.msdn.com/b/ericlippert/archive/2008/01/21/immutability-in-c-part-nine-academic-plus-my-avl-tree-implementation.aspx - /// Key to look for. - /// New tree with removed or updated value. - public ImMap Remove(int key) => - RemoveImpl(key); - - /// Outputs key value pair - public override string ToString() => Key + ": " + Value; - - #region Implementation - - private ImMap() - { - } - - private ImMap(int key, V value) - { - Key = key; - Value = value; - Left = Empty; - Right = Empty; - Height = 1; - } - - private ImMap(int key, V value, ImMap left, ImMap right, int height) - { - Key = key; - Value = value; - Left = left; - Right = right; - Height = height; - } - - private ImMap(int key, V value, ImMap left, ImMap right) - { - Key = key; - Value = value; - Left = left; - Right = right; - Height = 1 + (left.Height > right.Height ? left.Height : right.Height); - } - - private ImMap AddOrUpdateImpl(int key, V value) - { - return Height == 0 // add new node - ? new ImMap(key, value) - : (key == Key // update found node - ? new ImMap(key, value, Left, Right) - : (key < Key // search for node - ? (Height == 1 - ? new ImMap(Key, Value, new ImMap(key, value), Right, height: 2) - : new ImMap(Key, Value, Left.AddOrUpdateImpl(key, value), Right).KeepBalance()) - : (Height == 1 - ? new ImMap(Key, Value, Left, new ImMap(key, value), height: 2) - : new ImMap(Key, Value, Left, Right.AddOrUpdateImpl(key, value)).KeepBalance()))); - } - - private ImMap AddOrUpdateImpl(int key, V value, bool updateOnly, Update update) - { - return Height == 0 ? // tree is empty - (updateOnly ? this : new ImMap(key, value)) - : (key == Key ? // actual update - new ImMap(key, update == null ? value : update(Value, value), Left, Right) - : (key < Key // try update on left or right sub-tree - ? new ImMap(Key, Value, Left.AddOrUpdateImpl(key, value, updateOnly, update), Right) - : new ImMap(Key, Value, Left, Right.AddOrUpdateImpl(key, value, updateOnly, update))) - .KeepBalance()); - } - - private ImMap KeepBalance() - { - var delta = Left.Height - Right.Height; - if (delta >= 2) // left is longer by 2, rotate left - { - var left = Left; - var leftLeft = left.Left; - var leftRight = left.Right; - if (leftRight.Height - leftLeft.Height == 1) - { - // double rotation: - // 5 => 5 => 4 - // 2 6 4 6 2 5 - // 1 4 2 3 1 3 6 - // 3 1 - return new ImMap(leftRight.Key, leftRight.Value, - left: new ImMap(left.Key, left.Value, - left: leftLeft, right: leftRight.Left), right: new ImMap(Key, Value, - left: leftRight.Right, right: Right)); - } - - // todo: do we need this? - // one rotation: - // 5 => 2 - // 2 6 1 5 - // 1 4 4 6 - return new ImMap(left.Key, left.Value, - left: leftLeft, right: new ImMap(Key, Value, - left: leftRight, right: Right)); - } - - if (delta <= -2) - { - var right = Right; - var rightLeft = right.Left; - var rightRight = right.Right; - if (rightLeft.Height - rightRight.Height == 1) - { - return new ImMap(rightLeft.Key, rightLeft.Value, - left: new ImMap(Key, Value, - left: Left, right: rightLeft.Left), right: new ImMap(right.Key, right.Value, - left: rightLeft.Right, right: rightRight)); - } - - return new ImMap(right.Key, right.Value, - left: new ImMap(Key, Value, - left: Left, right: rightLeft), right: rightRight); - } - - return this; - } - - private ImMap RemoveImpl(int key, bool ignoreKey = false) - { - if (Height == 0) - return this; - - ImMap result; - if (key == Key || ignoreKey) // found node - { - if (Height == 1) // remove node - return Empty; - - if (Right.IsEmpty) - result = Left; - else if (Left.IsEmpty) - result = Right; - else - { - // we have two children, so remove the next highest node and replace this node with it. - var successor = Right; - while (!successor.Left.IsEmpty) - successor = successor.Left; - result = new ImMap(successor.Key, successor.Value, - Left, Right.RemoveImpl(successor.Key, ignoreKey: true)); - } - } - else if (key < Key) - result = new ImMap(Key, Value, Left.RemoveImpl(key), Right); - else - result = new ImMap(Key, Value, Left, Right.RemoveImpl(key)); - - return result.KeepBalance(); - } - - #endregion Implementation - } - - /// Immutable http://en.wikipedia.org/wiki/AVL_tree - /// where node key is the hash code of . - public sealed class ImHashMap - { - /// Empty tree to start with. - public static readonly ImHashMap Empty = new ImHashMap(); - - /// Calculated key hash. - public int Hash => _data.Hash; - - /// Key of type K that should support and . - public K Key => _data.Key; - - /// Value of any type V. - public V Value => _data.Value; - - /// In case of conflicts for different keys contains conflicted keys with their values. - public KV[] Conflicts => _data.Conflicts; - - /// Left sub-tree/branch, or empty. - public readonly ImHashMap Left; - - /// Right sub-tree/branch, or empty. - public readonly ImHashMap Right; - - /// Height of longest sub-tree/branch plus 1. It is 0 for empty tree, and 1 for single node tree. - public readonly int Height; - - /// Returns true if tree is empty. - public bool IsEmpty => Height == 0; - - /// Returns new tree with added key-value. - /// If value with the same key is exist then the value is replaced. - /// Key to add.Value to add. - /// New tree with added or updated key-value. - public ImHashMap AddOrUpdate(K key, V value) => - AddOrUpdate(key.GetHashCode(), key, value); - - /// Returns new tree with added key-value. If value with the same key is exist, then - /// if is not specified: then existing value will be replaced by ; - /// if is specified: then update delegate will decide what value to keep. - /// Key to add.Value to add. - /// Update handler. - /// New tree with added or updated key-value. - public ImHashMap AddOrUpdate(K key, V value, Update update) => - AddOrUpdate(key.GetHashCode(), key, value, update); - - /// Looks for and replaces its value with new , or - /// runs custom update handler () with old and new value to get the updated result. - /// Key to look for. - /// New value to replace key value with. - /// (optional) Delegate for custom update logic, it gets old and new - /// as inputs and should return updated value as output. - /// New tree with updated value or the SAME tree if no key found. - public ImHashMap Update(K key, V value, Update update = null) => - Update(key.GetHashCode(), key, value, update); - - /// Looks for key in a tree and returns the key value if found, or otherwise. - /// Key to look for. (optional) Value to return if key is not found. - /// Found value or . - [MethodImpl((MethodImplOptions)256)] - public V GetValueOrDefault(K key, V defaultValue = default(V)) - { - var t = this; - var hash = key.GetHashCode(); - while (t.Height != 0 && t.Hash != hash) - t = hash < t.Hash ? t.Left : t.Right; - return t.Height != 0 && (ReferenceEquals(key, t.Key) || key.Equals(t.Key)) - ? t.Value : t.GetConflictedValueOrDefault(key, defaultValue); - } - - /// Returns true if key is found and sets the value. - /// Key to look for. Result value - /// True if key found, false otherwise. - [MethodImpl((MethodImplOptions)256)] - public bool TryFind(K key, out V value) - { - var hash = key.GetHashCode(); - - var t = this; - while (t.Height != 0 && t._data.Hash != hash) - t = hash < t._data.Hash ? t.Left : t.Right; - - if (t.Height != 0 && (ReferenceEquals(key, t._data.Key) || key.Equals(t._data.Key))) - { - value = t._data.Value; - return true; - } - - return t.TryFindConflictedValue(key, out value); - } - - /// Depth-first in-order traversal as described in http://en.wikipedia.org/wiki/Tree_traversal - /// The only difference is using fixed size array instead of stack for speed-up (~20% faster than stack). - /// Sequence of enumerated key value pairs. - public IEnumerable> Enumerate() - { - if (Height == 0) - yield break; - - var parents = new ImHashMap[Height]; - - var node = this; - var parentCount = -1; - while (node.Height != 0 || parentCount != -1) - { - if (node.Height != 0) - { - parents[++parentCount] = node; - node = node.Left; - } - else - { - node = parents[parentCount--]; - yield return new KV(node.Key, node.Value); - - if (node.Conflicts != null) - for (var i = 0; i < node.Conflicts.Length; i++) - yield return node.Conflicts[i]; - - node = node.Right; - } - } - } - - /// Removes or updates value for specified key, or does nothing if key is not found. - /// Based on Eric Lippert http://blogs.msdn.com/b/ericlippert/archive/2008/01/21/immutability-in-c-part-nine-academic-plus-my-avl-tree-implementation.aspx - /// Key to look for. - /// New tree with removed or updated value. - public ImHashMap Remove(K key) => - Remove(key.GetHashCode(), key); - - /// Outputs key value pair - public override string ToString() => Key + ": " + Value; - - #region Implementation - - private sealed class Data - { - public readonly int Hash; - public readonly K Key; - public readonly V Value; - - public readonly KV[] Conflicts; - - public Data() - { - } - - public Data(int hash, K key, V value, KV[] conflicts = null) - { - Hash = hash; - Key = key; - Value = value; - Conflicts = conflicts; - } - } - - private readonly Data _data; - - private ImHashMap() - { - _data = new Data(); - } - - private ImHashMap(Data data) - { - _data = data; - Left = Empty; - Right = Empty; - Height = 1; - } - - private ImHashMap(Data data, ImHashMap left, ImHashMap right) - { - _data = data; - Left = left; - Right = right; - Height = 1 + (left.Height > right.Height ? left.Height : right.Height); - } - - private ImHashMap(Data data, ImHashMap left, ImHashMap right, int height) - { - _data = data; - Left = left; - Right = right; - Height = height; - } - - // todo: made public for benchmarking - /// It is fine - public ImHashMap AddOrUpdate(int hash, K key, V value) - { - return Height == 0 // add new node - ? new ImHashMap(new Data(hash, key, value)) - : (hash == Hash // update found node - ? (ReferenceEquals(Key, key) || Key.Equals(key) - ? new ImHashMap(new Data(hash, key, value, Conflicts), Left, Right) - : UpdateValueAndResolveConflicts(key, value, null, false)) - : (hash < Hash // search for node - ? (Height == 1 - ? new ImHashMap(_data, - new ImHashMap(new Data(hash, key, value)), Right, height: 2) - : new ImHashMap(_data, - Left.AddOrUpdate(hash, key, value), Right).KeepBalance()) - : (Height == 1 - ? new ImHashMap(_data, - Left, new ImHashMap(new Data(hash, key, value)), height: 2) - : new ImHashMap(_data, - Left, Right.AddOrUpdate(hash, key, value)).KeepBalance()))); - } - - private ImHashMap AddOrUpdate(int hash, K key, V value, Update update) - { - return Height == 0 - ? new ImHashMap(new Data(hash, key, value)) - : (hash == Hash // update - ? (ReferenceEquals(Key, key) || Key.Equals(key) - ? new ImHashMap(new Data(hash, key, update(Value, value), Conflicts), Left, Right) - : UpdateValueAndResolveConflicts(key, value, update, false)) - : (hash < Hash - ? With(Left.AddOrUpdate(hash, key, value, update), Right) - : With(Left, Right.AddOrUpdate(hash, key, value, update))) - .KeepBalance()); - } - - // todo: made public for benchmarking - /// It is fine - public ImHashMap Update(int hash, K key, V value, Update update) - { - return Height == 0 ? this - : (hash == Hash - ? (ReferenceEquals(Key, key) || Key.Equals(key) - ? new ImHashMap(new Data(hash, key, update == null ? value : update(Value, value), Conflicts), Left, Right) - : UpdateValueAndResolveConflicts(key, value, update, true)) - : (hash < Hash - ? With(Left.Update(hash, key, value, update), Right) - : With(Left, Right.Update(hash, key, value, update))) - .KeepBalance()); - } - - private ImHashMap UpdateValueAndResolveConflicts(K key, V value, Update update, bool updateOnly) - { - if (Conflicts == null) // add only if updateOnly is false. - return updateOnly ? this - : new ImHashMap(new Data(Hash, Key, Value, new[] { new KV(key, value) }), Left, Right); - - var found = Conflicts.Length - 1; - while (found >= 0 && !Equals(Conflicts[found].Key, Key)) - --found; - if (found == -1) - { - if (updateOnly) - return this; - var newConflicts = new KV[Conflicts.Length + 1]; - Array.Copy(Conflicts, 0, newConflicts, 0, Conflicts.Length); - newConflicts[Conflicts.Length] = new KV(key, value); - return new ImHashMap(new Data(Hash, Key, Value, newConflicts), Left, Right); - } - - var conflicts = new KV[Conflicts.Length]; - Array.Copy(Conflicts, 0, conflicts, 0, Conflicts.Length); - conflicts[found] = new KV(key, update == null ? value : update(Conflicts[found].Value, value)); - return new ImHashMap(new Data(Hash, Key, Value, conflicts), Left, Right); - } - - // todo: temporary made public for benchmarking - /// It is fine - public V GetConflictedValueOrDefault(K key, V defaultValue) - { - if (Conflicts != null) - for (var i = Conflicts.Length - 1; i >= 0; --i) - if (Equals(Conflicts[i].Key, key)) - return Conflicts[i].Value; - return defaultValue; - } - - // todo: temporary made public for benchmarking - /// It is fine - public bool TryFindConflictedValue(K key, out V value) - { - if (Height != 0 && Conflicts != null) - for (var i = Conflicts.Length - 1; i >= 0; --i) - if (Equals(Conflicts[i].Key, key)) - { - value = Conflicts[i].Value; - return true; - } - - value = default(V); - return false; - } - - private ImHashMap KeepBalance() - { - var delta = Left.Height - Right.Height; - if (delta >= 2) // left is longer by 2, rotate left - { - var left = Left; - var leftLeft = left.Left; - var leftRight = left.Right; - if (leftRight.Height - leftLeft.Height == 1) - { - // double rotation: - // 5 => 5 => 4 - // 2 6 4 6 2 5 - // 1 4 2 3 1 3 6 - // 3 1 - return new ImHashMap(leftRight._data, - left: new ImHashMap(left._data, - left: leftLeft, right: leftRight.Left), right: new ImHashMap(_data, - left: leftRight.Right, right: Right)); - } - - // todo: do we need this? - // one rotation: - // 5 => 2 - // 2 6 1 5 - // 1 4 4 6 - return new ImHashMap(left._data, - left: leftLeft, right: new ImHashMap(_data, - left: leftRight, right: Right)); - } - - if (delta <= -2) - { - var right = Right; - var rightLeft = right.Left; - var rightRight = right.Right; - if (rightLeft.Height - rightRight.Height == 1) - { - return new ImHashMap(rightLeft._data, - left: new ImHashMap(_data, - left: Left, right: rightLeft.Left), right: new ImHashMap(right._data, - left: rightLeft.Right, right: rightRight)); - } - - return new ImHashMap(right._data, - left: new ImHashMap(_data, - left: Left, right: rightLeft), right: rightRight); - } - - return this; - } - - private ImHashMap With(ImHashMap left, ImHashMap right) - { - return left == Left && right == Right ? this : new ImHashMap(_data, left, right); - } - - internal ImHashMap Remove(int hash, K key, bool ignoreKey = false) - { - if (Height == 0) - return this; - - ImHashMap result; - if (hash == Hash) // found node - { - if (ignoreKey || Equals(Key, key)) - { - if (!ignoreKey && Conflicts != null) - return ReplaceRemovedWithConflicted(); - - if (Height == 1) // remove node - return Empty; - - if (Right.IsEmpty) - result = Left; - else if (Left.IsEmpty) - result = Right; - else - { - // we have two children, so remove the next highest node and replace this node with it. - var successor = Right; - while (!successor.Left.IsEmpty) - successor = successor.Left; - result = new ImHashMap(successor._data, - Left, Right.Remove(successor.Hash, default(K), ignoreKey: true)); - } - } - else if (Conflicts != null) - return TryRemoveConflicted(key); - else - return this; // if key is not matching and no conflicts to lookup - just return - } - else if (hash < Hash) - result = new ImHashMap(_data, Left.Remove(hash, key, ignoreKey), Right); - else - result = new ImHashMap(_data, Left, Right.Remove(hash, key, ignoreKey)); - - if (result.Height == 1) - return result; - - return result.KeepBalance(); - } - - private ImHashMap TryRemoveConflicted(K key) - { - var index = Conflicts.Length - 1; - while (index >= 0 && !Equals(Conflicts[index].Key, key)) - --index; - if (index == -1) // key is not found in conflicts - just return - return this; - - if (Conflicts.Length == 1) - return new ImHashMap(new Data(Hash, Key, Value), Left, Right); - var shrinkedConflicts = new KV[Conflicts.Length - 1]; - var newIndex = 0; - for (var i = 0; i < Conflicts.Length; ++i) - if (i != index) - shrinkedConflicts[newIndex++] = Conflicts[i]; - return new ImHashMap(new Data(Hash, Key, Value, shrinkedConflicts), Left, Right); - } - - private ImHashMap ReplaceRemovedWithConflicted() - { - if (Conflicts.Length == 1) - return new ImHashMap(new Data(Hash, Conflicts[0].Key, Conflicts[0].Value), Left, Right); - var shrinkedConflicts = new KV[Conflicts.Length - 1]; - Array.Copy(Conflicts, 1, shrinkedConflicts, 0, shrinkedConflicts.Length); - return new ImHashMap(new Data(Hash, Conflicts[0].Key, Conflicts[0].Value, shrinkedConflicts), Left, Right); - } - - #endregion Implementation - } -} diff --git a/src/Marten/Util/LambdaBuilder.cs b/src/Marten/Util/LambdaBuilder.cs deleted file mode 100644 index e78f655001..0000000000 --- a/src/Marten/Util/LambdaBuilder.cs +++ /dev/null @@ -1,180 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using Baseline; - -namespace Marten.Util -{ - public static class LambdaBuilder - { - public static Func GetProperty(PropertyInfo property) - { - var target = Expression.Parameter(property.DeclaringType, "target"); - var method = property.GetGetMethod(); - - var callGetMethod = Expression.Call(target, method); - - var lambda = method.ReturnType == typeof(TProperty) - ? Expression.Lambda>(callGetMethod, target) - : Expression.Lambda>(Expression.Convert(callGetMethod, typeof(TProperty)), - target); - - return ExpressionCompiler.Compile>(lambda); - } - - public static Action SetProperty(PropertyInfo property) - { - var target = Expression.Parameter(property.DeclaringType, "target"); - var value = Expression.Parameter(property.PropertyType, "value"); - - var method = property.SetMethod; - - if (method == null) - return null; - - var callSetMethod = Expression.Call(target, method, value); - - var lambda = Expression.Lambda>(callSetMethod, target, value); - - return ExpressionCompiler.Compile>(lambda); - } - - public static Func GetField(FieldInfo field) - { - var target = Expression.Parameter(typeof(TTarget), "target"); - - var fieldAccess = Expression.Field(target, field); - - var lambda = field.FieldType == typeof(TField) - ? Expression.Lambda>(fieldAccess, target) - : Expression.Lambda>(Expression.Convert(fieldAccess, typeof(TField)), target); - - return ExpressionCompiler.Compile>(lambda); - } - - public static Func Getter(MemberInfo member) - { - return member is PropertyInfo - ? GetProperty(member.As()) - : GetField(member.As()); - } - - public static Action SetField(FieldInfo field) - { - var target = Expression.Parameter(typeof(TTarget), "target"); - var value = Expression.Parameter(typeof(TField), "value"); - - var fieldAccess = Expression.Field(target, field); - var fieldSetter = Expression.Assign(fieldAccess, value); - - var lambda = Expression.Lambda>(fieldSetter, target, value); - - return ExpressionCompiler.Compile>(lambda); - } - - public static Action Setter(MemberInfo member) - { - return member is PropertyInfo - ? SetProperty(member.As()) - : SetField(member.As()); - } - - public static Func Getter(EnumStorage enumStorage, MemberInfo[] members) - { - if (members.Length == 1) - { - return Getter(members.Single()); - } - - var target = Expression.Parameter(typeof(TTarget), "target"); - - var body = ToExpression(enumStorage, members, target); - - var lambda = Expression.Lambda>(body, target); - - return ExpressionCompiler.Compile>(lambda); - } - - private static readonly MethodInfo _getEnumStringValue = typeof(Enum).GetMethods(BindingFlags.Static | BindingFlags.Public).Single(mi => mi.Name == nameof(Enum.GetName) && !mi.IsGenericMethod); - private static readonly MethodInfo _getEnumIntValue = typeof(Convert).GetMethods(BindingFlags.Static | BindingFlags.Public).Single(mi => mi.Name == nameof(Convert.ToInt32) && mi.GetParameters().Count() == 1 && mi.GetParameters().Single().ParameterType == typeof(object)); - private static readonly Expression _trueConstant = Expression.Constant(true); - - public static Expression ToExpression(EnumStorage enumStorage, MemberInfo[] members, ParameterExpression target) - { - // Builds expression to retrieve value including enum conversion and null checks: - // Simple property/field target => target.Property - // Enum conversion to int target => Convert.ToInt32(target.EnumProperty) - // Enum conversion to string target => Enum.GetName(type, target.EnumProperty) - // Nested property/field null checks target => target.Inner != null ? target.Inner.Property : default() - - static Expression NullCheck(Expression accessor) - { - return accessor.Type.IsValueType && !accessor.Type.IsNullableOfT() - ? _trueConstant - : Expression.NotEqual(accessor, Expression.Constant(null, accessor.Type)); - } - - Expression AddToNullChecks(Expression nullChecks, Expression accessor) - { - var check = NullCheck(accessor); - return check == _trueConstant - ? nullChecks - : Expression.AndAlso(nullChecks, check); - } - - Expression ConvertEnumExpression(Type type, Expression accessor) - { - return enumStorage == EnumStorage.AsString - ? Expression.Call(_getEnumStringValue, Expression.Constant(type), - Expression.Convert(accessor, typeof(object))) - : Expression.Call(_getEnumIntValue, - Expression.Convert(accessor, typeof(object))); - } - - static Expression PropertyOrField(Expression expr, string propertyOrFieldName) - { - if (!expr.Type.IsInterface) - { - return Expression.PropertyOrField(expr, propertyOrFieldName); - } - - var member = expr.Type.GetPublicPropertyOrField(propertyOrFieldName); - - if (member is PropertyInfo) - { - return Expression.Property(expr, member.As()); - } - else - { - return Expression.Field(expr, member.As()); - } - } - - // Build accessor and null checks expressions. - var aggregatedExpressions = members.Aggregate(new - { - Accessor = (Expression)target, - NullChecks = NullCheck(target) - }, - (acc, member) => - { - var memberType = member.GetMemberType(); - var accessor = PropertyOrField(acc.Accessor, member.Name); - return new - { - Accessor = memberType.GetTypeInfo().IsEnum - ? ConvertEnumExpression(memberType, accessor) - : accessor, - NullChecks = AddToNullChecks(acc.NullChecks, accessor) - }; - }); - - // If there are potential nulls add condition. - return aggregatedExpressions.NullChecks == _trueConstant - ? aggregatedExpressions.Accessor - : Expression.Condition(aggregatedExpressions.NullChecks, aggregatedExpressions.Accessor, - Expression.Default(aggregatedExpressions.Accessor.Type)); - } - } -} diff --git a/src/Marten/Util/New.cs b/src/Marten/Util/New.cs deleted file mode 100644 index c166afc4e1..0000000000 --- a/src/Marten/Util/New.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; -using System.Runtime.Serialization; -#nullable enable -namespace Marten.Util -{ - public static class New - { - public static readonly Func Instance = Creator(); - - private static Func Creator() - { - var t = typeof(T); - if (t == typeof(string)) - return Expression.Lambda>(Expression.Constant(string.Empty)).Compile(); - - if (t.HasDefaultConstructor()) - return Expression.Lambda>(Expression.New(t)).Compile(); - - return () => (T)FormatterServices.GetUninitializedObject(t); - } - } - - public static class New - { - public static bool HasDefaultConstructor(this Type t) - { - return t.IsValueType || t.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) != null; - } - } - - public enum ConstructorHandling - { - DefaultPublic = 1, - DefaultProtected = 2, - DefaultPrivate = 4, - NotInitialized = 8, - AnyDefault = DefaultPublic | DefaultProtected | DefaultPrivate, - All = AnyDefault | NotInitialized - } -} diff --git a/src/Marten/Util/ReflectionExtensions.cs b/src/Marten/Util/ReflectionExtensions.cs index bdcb89e774..30efcc2e6a 100644 --- a/src/Marten/Util/ReflectionExtensions.cs +++ b/src/Marten/Util/ReflectionExtensions.cs @@ -8,20 +8,8 @@ namespace Marten.Util { - public static class ReflectionExtensions + internal static class ReflectionExtensions { - internal static readonly Dictionary Aliases = new Dictionary - { - {typeof(int), "int"}, - {typeof(void), "void"}, - {typeof(string), "string"}, - {typeof(long), "long"}, - {typeof(double), "double"}, - {typeof(bool), "bool"}, - {typeof(object), "object"}, - {typeof(object[]), "object[]"} - }; - public static string ToTableAlias(this MemberInfo[] members) { return members.Select(x => x.ToTableAlias()).Join("_"); @@ -61,104 +49,5 @@ public static Type GetRawMemberType(this MemberInfo member) return rawType; } - public static MemberInfo GetPublicPropertyOrField(this Type type, string memberName) - { - return type.GetPublicMembersFromTypeHierarchy( - BindingFlags.GetProperty | BindingFlags.GetField - ).Cast().FirstOrDefault(p => p.Name == memberName); - } - - public static MemberInfo[] GetPublicMembersFromTypeHierarchy(this Type type, BindingFlags bindingFlags) - { - if (!type.IsInterface) - { - return type.GetMembers( - bindingFlags - | BindingFlags.FlattenHierarchy - | BindingFlags.Public - | BindingFlags.Instance); - } - - var memberInfos = new List(); - - var considered = new List(); - var queue = new Queue(); - considered.Add(type); - queue.Enqueue(type); - while (queue.Count > 0) - { - var subType = queue.Dequeue(); - foreach (var subInterface in subType.GetInterfaces()) - { - if (considered.Contains(subInterface)) - continue; - - considered.Add(subInterface); - queue.Enqueue(subInterface); - } - - var typeProperties = subType.GetMembers( - bindingFlags - | BindingFlags.FlattenHierarchy - | BindingFlags.Public - | BindingFlags.Instance); - - var newPropertyInfos = typeProperties - .Where(x => !memberInfos.Contains(x)); - - memberInfos.InsertRange(0, newPropertyInfos); - } - - return memberInfos.ToArray(); - } - - public static string GetPrettyName(this Type t) - { - if (!t.GetTypeInfo().IsGenericType) - return t.Name; - - var sb = new StringBuilder(); - - sb.Append(t.Name.Substring(0, t.Name.LastIndexOf("`", StringComparison.Ordinal))); - sb.Append(t.GetGenericArguments().Aggregate("<", - (aggregate, type) => aggregate + (aggregate == "<" ? "" : ",") + GetPrettyName(type))); - sb.Append(">"); - - return sb.ToString(); - } - - public static string GetTypeName(this Type type) - { - var typeName = type.Name; - - if (type.GetTypeInfo().IsGenericType) - typeName = GetPrettyName(type); - - return type.IsNested - ? $"{type.DeclaringType.Name}.{typeName}" - : typeName; - } - - public static string GetTypeFullName(this Type type) - { - return type.IsNested - ? $"{type.DeclaringType.FullName}.{type.Name}" - : type.FullName; - } - - public static bool IsGenericDictionary(this Type type) - { - return type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>); - } - - // http://stackoverflow.com/a/15273117/426840 - public static bool IsAnonymousType(this object instance) - { - if (instance == null) - return false; - - return instance.GetType().Namespace == null; - } - } } diff --git a/src/Marten/Util/StreamExtensions.cs b/src/Marten/Util/StreamExtensions.cs index c84862c3cb..84aa090c9d 100644 --- a/src/Marten/Util/StreamExtensions.cs +++ b/src/Marten/Util/StreamExtensions.cs @@ -6,7 +6,7 @@ #nullable enable namespace Marten.Util { - public static class StreamExtensions + internal static class StreamExtensions { private const int BufferSize = 81920; diff --git a/src/Marten/Util/StringExtensions.cs b/src/Marten/Util/StringExtensions.cs index 6bf8c74dac..98566a4825 100644 --- a/src/Marten/Util/StringExtensions.cs +++ b/src/Marten/Util/StringExtensions.cs @@ -1,60 +1,12 @@ using System; +using Baseline; using Newtonsoft.Json.Serialization; using Npgsql; #nullable enable namespace Marten.Util { - public static class StringExtensionMethods + internal static class StringExtensionMethods { - public static string ReplaceFirst(this string text, string search, string replace) - { - int pos = text.IndexOf(search); - if (pos < 0) - { - return text; - } - - return text.Substring(0, pos) + replace + text.Substring(pos + search.Length); - } - - public static string UseParameter(this string text, NpgsqlParameter parameter) - { - return text.ReplaceFirst("?", ":" + parameter.ParameterName); - } - - public static bool Contains(this string source, string value, StringComparison comparison) - { - return source.IndexOf(value, comparison) >= 0; - } - - public static string ToCamelCase(this string s) - { - if (string.IsNullOrEmpty(s) || !char.IsUpper(s[0])) - { - return s; - } - - char[] chars = s.ToCharArray(); - - for (int i = 0; i < chars.Length; i++) - { - if (i == 1 && !char.IsUpper(chars[i])) - { - break; - } - - bool hasNext = (i + 1 < chars.Length); - if (i > 0 && hasNext && !char.IsUpper(chars[i + 1])) - { - break; - } - - chars[i] = char.ToLowerInvariant(chars[i]); - } - - return new string(chars); - } - private static readonly SnakeCaseNamingStrategy _snakeCaseNamingStrategy = new SnakeCaseNamingStrategy(); public static string ToSnakeCase(this string s) diff --git a/src/Marten/Util/TypeMappings.cs b/src/Marten/Util/TypeMappings.cs deleted file mode 100644 index e8c74a1c37..0000000000 --- a/src/Marten/Util/TypeMappings.cs +++ /dev/null @@ -1,340 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text.RegularExpressions; -using Baseline; -using Npgsql; -using Npgsql.TypeMapping; -using NpgsqlTypes; -#nullable enable -namespace Marten.Util -{ - public static class TypeMappings - { - private static readonly Ref> PgTypeMemo; - private static readonly Ref> NpgsqlDbTypeMemo; - private static readonly Ref> TypeMemo; - - public static List ContainmentOperatorTypes { get; } = new List(); - public static List TimespanTypes { get; } = new List(); - public static List TimespanZTypes { get; } = new List(); - - static TypeMappings() - { - // Initialize PgTypeMemo with Types which are not available in Npgsql mappings - PgTypeMemo = Ref.Of(ImHashMap.Empty); - - PgTypeMemo.Swap(d => d.AddOrUpdate(typeof(long), "bigint")); - PgTypeMemo.Swap(d => d.AddOrUpdate(typeof(Guid), "uuid")); - PgTypeMemo.Swap(d => d.AddOrUpdate(typeof(string), "varchar")); - PgTypeMemo.Swap(d => d.AddOrUpdate(typeof(float), "decimal")); - - // Default Npgsql mapping is 'numeric' but we are using 'decimal' - PgTypeMemo.Swap(d => d.AddOrUpdate(typeof(decimal), "decimal")); - - // Default Npgsql mappings is 'timestamp' but we are using 'timestamp without time zone' - PgTypeMemo.Swap(d => d.AddOrUpdate(typeof(DateTime), "timestamp without time zone")); - - NpgsqlDbTypeMemo = Ref.Of(ImHashMap.Empty); - - TypeMemo = Ref.Of(ImHashMap.Empty); - - AddTimespanTypes(NpgsqlDbType.Timestamp, ResolveTypes(NpgsqlDbType.Timestamp)); - AddTimespanTypes(NpgsqlDbType.TimestampTz, ResolveTypes(NpgsqlDbType.TimestampTz)); - - RegisterMapping(typeof(uint), "oid", NpgsqlDbType.Oid); - } - - public static void RegisterMapping(Type type, string pgType, NpgsqlDbType? npgsqlDbType) - { - PgTypeMemo.Swap(d => d.AddOrUpdate(type, pgType)); - NpgsqlDbTypeMemo.Swap(d => d.AddOrUpdate(type, npgsqlDbType)); - } - - // Lazily retrieve the CLR type to NpgsqlDbType and PgTypeName mapping from exposed INpgsqlTypeMapper.Mappings. - // This is lazily calculated instead of precached because it allows consuming code to register - // custom npgsql mappings prior to execution. - private static string? ResolvePgType(Type type) - { - if (PgTypeMemo.Value.TryFind(type, out var value)) - return value; - - value = GetTypeMapping(type)?.PgTypeName; - - PgTypeMemo.Swap(d => d.AddOrUpdate(type, value!)); - - return value; - } - - private static NpgsqlDbType? ResolveNpgsqlDbType(Type type) - { - if (NpgsqlDbTypeMemo.Value.TryFind(type, out var value)) - return value; - - value = GetTypeMapping(type)?.NpgsqlDbType; - - NpgsqlDbTypeMemo.Swap(d => d.AddOrUpdate(type, value)); - - return value; - } - - internal static Type[] ResolveTypes(NpgsqlDbType npgsqlDbType) - { - if (TypeMemo.Value.TryFind(npgsqlDbType, out var values)) - return values; - - values = GetTypeMapping(npgsqlDbType)?.ClrTypes; - - TypeMemo.Swap(d => d.AddOrUpdate(npgsqlDbType, values!)); - - return values!; - } - - private static NpgsqlTypeMapping? GetTypeMapping(Type type) - => NpgsqlConnection - .GlobalTypeMapper - .Mappings - .FirstOrDefault(mapping => mapping.ClrTypes.Contains(type)); - - private static NpgsqlTypeMapping? GetTypeMapping(NpgsqlDbType type) - => NpgsqlConnection - .GlobalTypeMapper - .Mappings - .FirstOrDefault(mapping => mapping.NpgsqlDbType == type); - - public static string ConvertSynonyms(string type) - { - switch (type.ToLower()) - { - case "character varying": - case "varchar": - return "varchar"; - - case "boolean": - case "bool": - return "boolean"; - - case "integer": - case "serial": - return "int"; - - case "integer[]": - return "int[]"; - - case "decimal": - case "numeric": - return "decimal"; - - case "timestamp without time zone": - return "timestamp"; - - case "timestamp with time zone": - return "timestamptz"; - - case "array": - case "character varying[]": - case "varchar[]": - case "text[]": - return "array"; - } - - return type; - } - - public static bool CanAutoConvertType(string fromType, string toType) - { - toType = toType.ToLower(); - - return fromType.ToLower() switch - { - "int" => new[] {"bigint"}.Contains(toType), - "int[]" => new[] {"bigint[]"}.Contains(toType), - _ => false - }; - } - - public static string ReplaceMultiSpace(this string str, string newStr) - { - var regex = new Regex("\\s+"); - return regex.Replace(str, newStr); - } - - public static string CanonicizeSql(this string sql) - { - var replaced = sql - .Trim() - .Replace('\n', ' ') - .Replace('\r', ' ') - .Replace('\t', ' ') - .ReplaceMultiSpace(" ") - .Replace(" ;", ";") - .Replace("SECURITY INVOKER", "") - .Replace(" ", " ") - .Replace("LANGUAGE plpgsql AS $function$", "") - .Replace("$$ LANGUAGE plpgsql", "$function$") - .Replace("AS $$ DECLARE", "DECLARE") - .Replace("character varying", "varchar") - .Replace("Boolean", "boolean") - .Replace("bool,", "boolean,") - .Replace("int[]", "integer[]") - .Replace("numeric", "decimal").TrimEnd(';').TrimEnd(); - - if (replaced.Contains("PLV8", StringComparison.OrdinalIgnoreCase)) - { - replaced = replaced - .Replace("LANGUAGE plv8 IMMUTABLE STRICT AS $function$", "AS $$"); - - const string languagePlv8ImmutableStrict = "$$ LANGUAGE plv8 IMMUTABLE STRICT"; - const string functionMarker = "$function$"; - if (replaced.EndsWith(functionMarker)) - { - replaced = replaced.Substring(0, replaced.LastIndexOf(functionMarker)) + languagePlv8ImmutableStrict; - } - } - - return replaced - .Replace(" ", " ").TrimEnd().TrimEnd(';'); - } - - /// - /// Some portion of implementation adapted from Npgsql GlobalTypeMapper.ToNpgsqlDbType(Type type) - /// https://github.com/npgsql/npgsql/blob/dev/src/Npgsql/TypeMapping/GlobalTypeMapper.cs - /// Possibly this method can be trimmed down when Npgsql eventually exposes ToNpgsqlDbType - /// - public static NpgsqlDbType ToDbType(Type type) - { - if (determineNpgsqlDbType(type, out var dbType)) - return dbType; - - throw new NotSupportedException("Can't infer NpgsqlDbType for type " + type); - } - - public static NpgsqlDbType? TryGetDbType(Type? type) - { - if (type == null || !determineNpgsqlDbType(type, out var dbType)) - return null; - - return dbType; - } - - private static bool determineNpgsqlDbType(Type type, out NpgsqlDbType dbType) - { - var npgsqlDbType = ResolveNpgsqlDbType(type); - if (npgsqlDbType != null) - { - { - dbType = npgsqlDbType.Value; - return true; - } - } - - if (type.IsNullable()) - { - dbType = ToDbType(type.GetInnerTypeFromNullable()); - return true; - } - - if (type.IsEnum) - { - dbType = NpgsqlDbType.Integer; - return true; - } - - if (type.IsArray) - { - if (type == typeof(byte[])) - { - dbType = NpgsqlDbType.Bytea; - return true; - } - - { - dbType = NpgsqlDbType.Array | ToDbType(type.GetElementType()!); - return true; - } - } - - var typeInfo = type.GetTypeInfo(); - - var ilist = typeInfo.ImplementedInterfaces.FirstOrDefault(x => - x.GetTypeInfo().IsGenericType && x.GetGenericTypeDefinition() == typeof(IList<>)); - if (ilist != null) - { - dbType = NpgsqlDbType.Array | ToDbType(ilist.GetGenericArguments()[0]); - return true; - } - - if (typeInfo.IsGenericType && type.GetGenericTypeDefinition() == typeof(NpgsqlRange<>)) - { - dbType = NpgsqlDbType.Range | ToDbType(type.GetGenericArguments()[0]); - return true; - } - - if (type == typeof(DBNull)) - { - dbType = NpgsqlDbType.Unknown; - return true; - } - - dbType = NpgsqlDbType.Unknown; - return false; - } - - public static string GetPgType(Type memberType, EnumStorage enumStyle) - { - if (memberType.IsEnum) - { - return enumStyle == EnumStorage.AsInteger ? "integer" : "varchar"; - } - - if (memberType.IsArray) - { - return GetPgType(memberType.GetElementType()!, enumStyle) + "[]"; - } - - if (memberType.IsNullable()) - { - return GetPgType(memberType.GetInnerTypeFromNullable(), enumStyle); - } - - if (memberType.IsConstructedGenericType) - { - var templateType = memberType.GetGenericTypeDefinition(); - return ResolvePgType(templateType) ?? "jsonb"; - } - - return ResolvePgType(memberType) ?? "jsonb"; - } - - public static bool HasTypeMapping(Type memberType) - { - if (memberType.IsNullable()) - { - return HasTypeMapping(memberType.GetInnerTypeFromNullable()); - } - - // more complicated later - return ResolvePgType(memberType) != null || memberType.IsEnum; - } - - private static Type GetNullableType(Type type) - { - type = Nullable.GetUnderlyingType(type) ?? type; - if (type.IsValueType) - return typeof(Nullable<>).MakeGenericType(type); - else - return type; - } - - public static void AddTimespanTypes(NpgsqlDbType npgsqlDbType, params Type[] types) - { - var timespanTypesList = (npgsqlDbType == NpgsqlDbType.Timestamp) ? TimespanTypes : TimespanZTypes; - var typesWithNullables = types.Union(types.Select(t => GetNullableType(t))).Where(t => !timespanTypesList.Contains(t)).ToList(); - - timespanTypesList.AddRange(typesWithNullables); - - ContainmentOperatorTypes.AddRange(typesWithNullables); - } - } -} diff --git a/src/MartenBenchmarks/BenchmarkStore.cs b/src/MartenBenchmarks/BenchmarkStore.cs index 695d6ab686..d9e2d6906b 100644 --- a/src/MartenBenchmarks/BenchmarkStore.cs +++ b/src/MartenBenchmarks/BenchmarkStore.cs @@ -20,7 +20,7 @@ static BenchmarkStore() }); Store.Advanced.Clean.CompletelyRemoveAll(); - Store.Schema.ApplyAllConfiguredChangesToDatabase(); + Store.Schema.ApplyAllConfiguredChangesToDatabase().GetAwaiter().GetResult(); } } } diff --git a/src/MartenBenchmarks/BulkLoading.cs b/src/MartenBenchmarks/BulkLoading.cs index 190874b060..8dfbe4ad81 100644 --- a/src/MartenBenchmarks/BulkLoading.cs +++ b/src/MartenBenchmarks/BulkLoading.cs @@ -14,13 +14,13 @@ public class BulkLoading [GlobalSetup] public void Setup() { - BenchmarkStore.Store.Advanced.Clean.DeleteDocumentsFor(typeof(Target)); + BenchmarkStore.Store.Advanced.Clean.DeleteDocumentsByType(typeof(Target)); } [Benchmark] public void BulkInsertDocuments() { - BenchmarkStore.Store.Advanced.Clean.DeleteDocumentsFor(typeof(Target)); + BenchmarkStore.Store.Advanced.Clean.DeleteDocumentsByType(typeof(Target)); BenchmarkStore.Store.BulkInsert(Docs); } } diff --git a/src/MartenBenchmarks/DocumentActions.cs b/src/MartenBenchmarks/DocumentActions.cs index 1aed8e2e0d..f90c3b32bf 100644 --- a/src/MartenBenchmarks/DocumentActions.cs +++ b/src/MartenBenchmarks/DocumentActions.cs @@ -14,7 +14,7 @@ public class DocumentActions [GlobalSetup] public void Setup() { - BenchmarkStore.Store.Advanced.Clean.DeleteDocumentsFor(typeof(Target)); + BenchmarkStore.Store.Advanced.Clean.DeleteDocumentsByType(typeof(Target)); } [Benchmark] diff --git a/src/MartenBenchmarks/LinqActions.cs b/src/MartenBenchmarks/LinqActions.cs index d53ec81b01..56a484f755 100644 --- a/src/MartenBenchmarks/LinqActions.cs +++ b/src/MartenBenchmarks/LinqActions.cs @@ -22,7 +22,7 @@ public void Setup() docs.Skip(100).Each(x => x.Color = Colors.Green); docs.Take(100).Each(x => x.Color = Colors.Blue); - BenchmarkStore.Store.Advanced.Clean.DeleteDocumentsFor(typeof(Target)); + BenchmarkStore.Store.Advanced.Clean.DeleteDocumentsByType(typeof(Target)); BenchmarkStore.Store.BulkInsert(docs); }