diff --git a/src/Marten.CommandLine/Marten.CommandLine.csproj b/src/Marten.CommandLine/Marten.CommandLine.csproj index 7231963c7f..e7882e9d70 100644 --- a/src/Marten.CommandLine/Marten.CommandLine.csproj +++ b/src/Marten.CommandLine/Marten.CommandLine.csproj @@ -4,7 +4,7 @@ Command line tooling for managing Marten development 2.9.0 Jeremy D. Miller;Tim Cools;Jeff Doolittle - net46;netstandard1.3;netstandard2.0 + net46;netstandard2.0 Marten.CommandLine Marten.CommandLine http://jasperfx.github.io/marten/content/images/emblem.png diff --git a/src/Marten.Testing/Acceptance/computed_indexes.cs b/src/Marten.Testing/Acceptance/computed_indexes.cs index 5618548c5a..6afefb3cd8 100644 --- a/src/Marten.Testing/Acceptance/computed_indexes.cs +++ b/src/Marten.Testing/Acceptance/computed_indexes.cs @@ -121,11 +121,13 @@ public void specifying_an_index_type_should_create_the_index_with_that_type() var data = Target.GenerateRandomData(100).ToArray(); theStore.BulkInsert(data.ToArray()); - theStore.Tenancy.Default.DbObjects.AllIndexes() + var ddl = theStore.Tenancy.Default.DbObjects.AllIndexes() .Where(x => x.Name == "mt_doc_target_idx_number") .Select(x => x.DDL.ToLower()) - .First() - .ShouldContain("mt_doc_target_idx_number on mt_doc_target using brin"); + .First(); + + ddl.ShouldContain("mt_doc_target_idx_number on"); + ddl.ShouldContain("mt_doc_target using brin"); } [Fact] @@ -149,7 +151,7 @@ public void create_multi_property_index() .DDL .ToLower(); - ddl.ShouldContain("index mt_doc_target_idx_user_idflag on mt_doc_target"); + ddl.ShouldContain("index mt_doc_target_idx_user_idflag on"); ddl.ShouldContain("((((data ->> 'userid'::text))::uuid), (((data ->> 'flag'::text))::boolean))"); } @@ -168,7 +170,7 @@ public void creating_index_using_date_should_work() .Where(x => x.Name == "mt_doc_target_idx_date") .Select(x => x.DDL.ToLower()) .First() - .ShouldContain("mt_doc_target_idx_date on mt_doc_target"); + .ShouldContain("mt_doc_target_idx_date on"); } [Fact] diff --git a/src/Marten.Testing/Bugs/Bug_1069_using_generic_event_types_because_why_not.cs b/src/Marten.Testing/Bugs/Bug_1069_using_generic_event_types_because_why_not.cs new file mode 100644 index 0000000000..d2a687240e --- /dev/null +++ b/src/Marten.Testing/Bugs/Bug_1069_using_generic_event_types_because_why_not.cs @@ -0,0 +1,76 @@ +using System; +using System.Linq; +using Shouldly; +using Xunit; + +namespace Marten.Testing.Bugs +{ + public class Bug_1069_using_generic_event_types_because_why_not : IntegratedFixture + { + public class Envelope + { + public T Value { get; set; } + public Guid ExecutingUserId { get; set; } + } + + public class Created + { + public Guid Id { get; set; } + } + + public class Updated + { + public String UpdateValue { get; set; } + } + + [Fact] + public void try_to_save_then_load_events() + { + var streamId = Guid.NewGuid(); + var event1 = new Envelope{Value = new Created{Id = Guid.NewGuid()}}; + var event2 = new Envelope{Value = new Updated{UpdateValue = "something"}}; + + using (var session = theStore.LightweightSession()) + { + session.Events.StartStream(streamId, event1, event2); + session.SaveChanges(); + } + + using (var session = theStore.LightweightSession()) + { + + + var events = session.Events.FetchStream(streamId); + events.Select(x => x.Data.GetType()) + .ShouldHaveTheSameElementsAs(typeof(Envelope), typeof(Envelope)); + } + } + + [Fact] + public void try_to_save_then_load_events_across_stores() + { + var streamId = Guid.NewGuid(); + var event1 = new Envelope{Value = new Created{Id = Guid.NewGuid()}}; + var event2 = new Envelope{Value = new Updated{UpdateValue = "something"}}; + + using (var session = theStore.LightweightSession()) + { + session.Events.StartStream(streamId, event1, event2); + session.SaveChanges(); + } + + var store2 = DocumentStore.For(_ => + { + _.Connection(ConnectionSource.ConnectionString); + _.AutoCreateSchemaObjects = AutoCreate.All; + }); + + using (var session = store2.LightweightSession()) + { + var events = session.Events.FetchStream(streamId); + events.Select(x => x.Data.GetType()) + .ShouldHaveTheSameElementsAs(typeof(Envelope), typeof(Envelope)); + } + } + } +} \ No newline at end of file diff --git a/src/Marten.Testing/Marten.Testing.csproj b/src/Marten.Testing/Marten.Testing.csproj index a89315e0f6..466da34e09 100644 --- a/src/Marten.Testing/Marten.Testing.csproj +++ b/src/Marten.Testing/Marten.Testing.csproj @@ -1,5 +1,4 @@  - net46;netcoreapp2.0;netcoreapp2.1 Marten.Testing @@ -7,16 +6,13 @@ true false - $(NuGetPackageRoot)microsoft.targetingpack.netframework.v4.6/1.0.1/lib/net46/ https://dotnet.myget.org/F/dotnet-core/api/v3/index.json - - + - PreserveNewest @@ -26,12 +22,10 @@ - - @@ -41,15 +35,12 @@ - - - @@ -60,9 +51,7 @@ - - - + \ No newline at end of file diff --git a/src/Marten.Testing/Schema/DocumentMapping_schema_patch_writing.cs b/src/Marten.Testing/Schema/DocumentMapping_schema_patch_writing.cs index 2363e8a6b7..3d96474440 100644 --- a/src/Marten.Testing/Schema/DocumentMapping_schema_patch_writing.cs +++ b/src/Marten.Testing/Schema/DocumentMapping_schema_patch_writing.cs @@ -111,7 +111,8 @@ public void can_revert_indexes_that_changed() var patch = store.Schema.ToPatch(); patch.RollbackDDL.ShouldContain("drop index public.mt_doc_user_idx_user_name;"); - patch.RollbackDDL.ShouldContain("CREATE INDEX mt_doc_user_idx_user_name ON mt_doc_user USING btree (user_name);"); + patch.RollbackDDL.ShouldContain("CREATE INDEX mt_doc_user_idx_user_name ON"); + patch.RollbackDDL.ShouldContain("mt_doc_user USING btree (user_name);"); } } diff --git a/src/Marten/Events/EventMapping.cs b/src/Marten/Events/EventMapping.cs index 9b1035a7ee..00ac54c743 100644 --- a/src/Marten/Events/EventMapping.cs +++ b/src/Marten/Events/EventMapping.cs @@ -29,7 +29,9 @@ protected EventMapping(EventGraph parent, Type eventType) _parent = parent; DocumentType = eventType; - EventTypeName = DocumentType.Name.ToTableAlias(); + + + EventTypeName = eventType.IsGenericType ? eventType.ShortNameInCode() : DocumentType.Name.ToTableAlias(); IdMember = DocumentType.GetProperty(nameof(IEvent.Id)); _inner = new DocumentMapping(eventType, parent.Options); diff --git a/src/Marten/Events/EventsTable.cs b/src/Marten/Events/EventsTable.cs index 4e656ce5f1..c031113a95 100644 --- a/src/Marten/Events/EventsTable.cs +++ b/src/Marten/Events/EventsTable.cs @@ -15,24 +15,24 @@ public EventsTable(EventGraph events) : base(new DbObjectName(events.DatabaseSch AddColumn("stream_id", stringIdType, (events.TenancyStyle != TenancyStyle.Conjoined) ? $"REFERENCES {events.DatabaseSchemaName}.mt_streams ON DELETE CASCADE" : null); AddColumn("version", "integer", "NOT NULL"); AddColumn("data", "jsonb", "NOT NULL"); - AddColumn("type", "varchar(100)", "NOT NULL"); + AddColumn("type", "varchar(500)", "NOT NULL"); AddColumn("timestamp", "timestamptz", "default (now()) NOT NULL"); AddColumn(); AddColumn(new DotNetTypeColumn { Directive = "NULL" }); if (events.TenancyStyle == TenancyStyle.Conjoined) - { - Constraints.Add($"FOREIGN KEY(stream_id, {TenantIdColumn.Name}) REFERENCES {events.DatabaseSchemaName}.mt_streams(id, {TenantIdColumn.Name})"); + { + 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)"); } - else - { - Constraints.Add("CONSTRAINT pk_mt_events_stream_and_version UNIQUE(stream_id, version)"); + else + { + Constraints.Add("CONSTRAINT pk_mt_events_stream_and_version UNIQUE(stream_id, version)"); } Constraints.Add("CONSTRAINT pk_mt_events_id_unique UNIQUE(id)"); } } - + // ENDSAMPLE } \ No newline at end of file diff --git a/src/Marten/Marten.csproj b/src/Marten/Marten.csproj index 3c9bcc6834..a1b27b5970 100644 --- a/src/Marten/Marten.csproj +++ b/src/Marten/Marten.csproj @@ -3,7 +3,7 @@ Postgresql as a Document Db and Event Store for .Net Development 2.9.0 Jeremy D. Miller;Tim Cools;Jeff Doolittle;James Hopper - net46;netstandard1.3;netstandard2.0 + net46;netstandard2.0 Marten Marten http://jasperfx.github.io/marten/content/images/emblem.png diff --git a/src/Marten/Util/ReflectionExtensions.cs b/src/Marten/Util/ReflectionExtensions.cs index 8d7ebd7de0..86bbee39ac 100644 --- a/src/Marten/Util/ReflectionExtensions.cs +++ b/src/Marten/Util/ReflectionExtensions.cs @@ -3,12 +3,26 @@ using System.Linq; using System.Reflection; using System.Text; +using System.Threading.Tasks; using Baseline; namespace Marten.Util { public 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(Task), "Task"}, + {typeof(object), "object"}, + {typeof(object[]), "object[]"} + }; + public static string ToTableAlias(this MemberInfo[] members) { return members.Select(x => x.ToTableAlias()).Join("_"); @@ -28,14 +42,8 @@ public static Type GetMemberType(this MemberInfo member) { Type rawType = null; - if (member is FieldInfo) - { - rawType = member.As().FieldType; - } - if (member is PropertyInfo) - { - rawType = member.As().PropertyType; - } + if (member is FieldInfo) rawType = member.As().FieldType; + if (member is PropertyInfo) rawType = member.As().PropertyType; return rawType.IsNullable() ? rawType.GetInnerTypeFromNullable() : rawType; } @@ -48,7 +56,8 @@ public static string GetPrettyName(this Type t) 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(t.GetGenericArguments().Aggregate("<", + (aggregate, type) => aggregate + (aggregate == "<" ? "" : ",") + GetPrettyName(type))); sb.Append(">"); return sb.ToString(); @@ -58,26 +67,23 @@ public static string GetTypeName(this Type type) { var typeName = type.Name; - if (type.GetTypeInfo().IsGenericType) - { - typeName = GetPrettyName(type); - } + if (type.GetTypeInfo().IsGenericType) typeName = GetPrettyName(type); return type.IsNested - ? $"{type.DeclaringType.Name}.{typeName}" - : typeName; + ? $"{type.DeclaringType.Name}.{typeName}" + : typeName; } public static string GetTypeFullName(this Type type) { return type.IsNested - ? $"{type.DeclaringType.FullName}.{type.Name}" - : type.FullName; + ? $"{type.DeclaringType.FullName}.{type.Name}" + : type.FullName; } public static bool IsGenericDictionary(this Type type) { - return type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof (IDictionary<,>); + return type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>); } // http://stackoverflow.com/a/15273117/426840 @@ -88,5 +94,73 @@ public static bool IsAnonymousType(this object instance) return instance.GetType().Namespace == null; } + + + /// + /// Derives the full type name *as it would appear in C# code* + /// + /// + /// + internal static string FullNameInCode(this Type type) + { + if (Aliases.ContainsKey(type)) return Aliases[type]; + + if (type.IsGenericType && !type.IsGenericTypeDefinition) + { + var cleanName = type.Name.Split('`').First(); + if (type.IsNested) cleanName = $"{type.ReflectedType.NameInCode()}.{cleanName}"; + + var args = type.GetGenericArguments().Select(x => x.FullNameInCode()).Join(", "); + + return $"{type.Namespace}.{cleanName}<{args}>"; + } + + if (type.FullName == null) return type.Name; + + return type.FullName.Replace("+", "."); + } + + /// + /// Derives the type name *as it would appear in C# code* + /// + /// + /// + internal static string NameInCode(this Type type) + { + if (Aliases.ContainsKey(type)) return Aliases[type]; + + if (type.IsGenericType && !type.IsGenericTypeDefinition) + { + var cleanName = type.Name.Split('`').First().Replace("+", "."); + if (type.IsNested) cleanName = $"{type.ReflectedType.NameInCode()}.{cleanName}"; + + var args = type.GetGenericArguments().Select(x => x.FullNameInCode()).Join(", "); + + return $"{cleanName}<{args}>"; + } + + if (type.MemberType == MemberTypes.NestedType) return $"{type.ReflectedType.NameInCode()}.{type.Name}"; + + return type.Name.Replace("+", "."); + } + + internal static string ShortNameInCode(this Type type) + { + if (Aliases.ContainsKey(type)) return Aliases[type]; + + if (type.IsGenericType && !type.IsGenericTypeDefinition) + { + var cleanName = type.Name.Split('`').First().Replace("+", "."); + if (type.IsNested) cleanName = $"{type.ReflectedType.NameInCode()}.{cleanName}"; + + var args = type.GetGenericArguments().Select(x => x.ShortNameInCode()).Join(", "); + + return $"{cleanName}<{args}>"; + } + + if (type.MemberType == MemberTypes.NestedType) return $"{type.ReflectedType.NameInCode()}.{type.Name}"; + + return type.Name.Replace("+", "."); + } } } \ No newline at end of file