diff --git a/zero.Core/Entities/Blueprints/Blueprint.cs b/zero.Core/Entities/Blueprints/Blueprint.cs
new file mode 100644
index 00000000..cfe1ea1d
--- /dev/null
+++ b/zero.Core/Entities/Blueprints/Blueprint.cs
@@ -0,0 +1,23 @@
+using zero.Core.Attributes;
+
+namespace zero.Core.Entities
+{
+ public class Blueprint : IBlueprint
+ {
+ ///
+ public string Id { get; set; }
+
+ ///
+ public IZeroEntity Content { get; set; }
+ }
+
+
+ [Collection("Blueprints")]
+ public interface IBlueprint : IZeroIdEntity, IZeroDbConventions
+ {
+ ///
+ /// Contains the entity content
+ ///
+ IZeroEntity Content { get; set; }
+ }
+}
diff --git a/zero.Core/Entities/InheritAttribute.cs b/zero.Core/Entities/InheritAttribute.cs
index b5a06d26..8b1e17c2 100644
--- a/zero.Core/Entities/InheritAttribute.cs
+++ b/zero.Core/Entities/InheritAttribute.cs
@@ -5,4 +5,15 @@ namespace zero.Core.Entities
public class OverwriteAttribute : Attribute
{
}
+
+
+ public class ReferenceAttribute : Attribute
+ {
+ public Type Type { get; set; }
+
+ public ReferenceAttribute(Type type)
+ {
+ Type = type;
+ }
+ }
}
\ No newline at end of file
diff --git a/zero.Core/Entities/Ref.cs b/zero.Core/Entities/Ref.cs
new file mode 100644
index 00000000..9b99a944
--- /dev/null
+++ b/zero.Core/Entities/Ref.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace zero.Core.Entities
+{
+ public class Ref where T : IZeroIdEntity
+ {
+ public Ref() { }
+
+ public Ref(string id)
+ {
+ Id = id;
+ }
+
+ public string Id { get; private set; }
+
+
+ public override string ToString()
+ {
+ return Id;
+ }
+ }
+
+
+ public class Refs where T : IZeroIdEntity
+ {
+ public Refs() { }
+
+ public Refs(params string[] ids)
+ {
+ Ids = ids;
+ }
+
+ public string[] Ids { get; private set; } = new string[0] { };
+ }
+}
diff --git a/zero.Core/Entities/ZeroEntity.cs b/zero.Core/Entities/ZeroEntity.cs
index 28e83ee3..29a4a6ce 100644
--- a/zero.Core/Entities/ZeroEntity.cs
+++ b/zero.Core/Entities/ZeroEntity.cs
@@ -34,7 +34,7 @@ namespace zero.Core.Entities
public DateTimeOffset CreatedDate { get; set; }
///
- public string OriginId { get; set; }
+ public string BlueprintId { get; set; }
}
@@ -85,6 +85,6 @@ namespace zero.Core.Entities
///
/// Id of the original base entity (which this one inherits from)
///
- string OriginId { get; set; }
+ string BlueprintId { get; set; }
}
}
diff --git a/zero.Core/Extensions/RavenDocumentStoreExtensions.cs b/zero.Core/Extensions/RavenDocumentStoreExtensions.cs
index 4e0c2772..e5816c1b 100644
--- a/zero.Core/Extensions/RavenDocumentStoreExtensions.cs
+++ b/zero.Core/Extensions/RavenDocumentStoreExtensions.cs
@@ -1,6 +1,7 @@
using Raven.Client.Documents;
using Raven.Client.Documents.Conventions;
using Raven.Client.Documents.Operations.CompareExchange;
+using Raven.Client.Json.Serialization.NewtonsoftJson;
using System;
using System.Linq;
using System.Reflection;
@@ -25,6 +26,15 @@ namespace zero.Core.Extensions
store.Conventions.IdentityPartsSeparator = '.';
+ (store.Conventions.Serialization as NewtonsoftJsonSerializationConventions).CustomizeJsonDeserializer = x =>
+ {
+ x.Converters.Add(new RefJsonConverter());
+ };
+ (store.Conventions.Serialization as NewtonsoftJsonSerializationConventions).CustomizeJsonSerializer = x =>
+ {
+ x.Converters.Add(new RefJsonConverter());
+ };
+
store.Conventions.FindCollectionName = type =>
{
Type finalType = type;
diff --git a/zero.Core/Utils/ObjectTraverser.cs b/zero.Core/Utils/ObjectTraverser.cs
index dcf7f66e..d669ba8b 100644
--- a/zero.Core/Utils/ObjectTraverser.cs
+++ b/zero.Core/Utils/ObjectTraverser.cs
@@ -110,24 +110,10 @@ namespace zero.Core.Utils
exploredObjects.Add(key);
- System.Collections.ICollection enumerable = value as System.Collections.ICollection;
-
- // this property is a list
- if (enumerable != null && !(value is string))
- {
- int idx = 0;
- foreach (object item in enumerable)
- {
- FindAttribute(item, value, CombineKey(String.Empty, key, SQBKT_OPEN + idx + SQBKT_CLOSE), null, exploredObjects, found);
- idx += 1;
- }
- return;
- }
-
// check if the current property contains the attribute
if (property != null)
{
- T attribute = property.GetCustomAttribute();
+ T attribute = property.GetCustomAttribute(true);
if (attribute != null)
{
@@ -142,6 +128,20 @@ namespace zero.Core.Utils
}
}
+ System.Collections.ICollection enumerable = value as System.Collections.ICollection;
+
+ // this property is a list
+ if (enumerable != null && !(value is string))
+ {
+ int idx = 0;
+ foreach (object item in enumerable)
+ {
+ FindAttribute(item, value, CombineKey(String.Empty, key, SQBKT_OPEN + idx + SQBKT_CLOSE), null, exploredObjects, found);
+ idx += 1;
+ }
+ return;
+ }
+
// check if our property is a primitive type
if (value == null || value.GetType().IsPrimitive || value is string || value is DateTime || value is DateTimeOffset || value is Uri)
{
diff --git a/zero.Core/Utils/RefJsonConverter.cs b/zero.Core/Utils/RefJsonConverter.cs
new file mode 100644
index 00000000..74e44a81
--- /dev/null
+++ b/zero.Core/Utils/RefJsonConverter.cs
@@ -0,0 +1,60 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using zero.Core.Entities;
+using zero.Core.Extensions;
+
+namespace zero.Core.Utils
+{
+ public class RefJsonConverter : JsonConverter
+ {
+ private readonly Type type;
+
+ private readonly string idProperty;
+
+ public RefJsonConverter()
+ {
+ type = typeof(Ref<>);
+ idProperty = nameof(Ref.Id);
+ }
+
+
+ public override bool CanRead => true;
+
+ public override bool CanWrite => true;
+
+ public override bool CanConvert(Type objectType) => objectType.IsGenericType && objectType.GetGenericTypeDefinition() == type;
+
+
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ JToken t = JToken.FromObject(value);
+ string id = t?.Value(idProperty);
+
+ if (t.Type != JTokenType.Object || id.IsNullOrEmpty())
+ {
+ writer.WriteNull();
+ }
+ else
+ {
+ writer.WriteValue(id);
+ }
+ }
+
+
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ if (!(reader.Value is string))
+ {
+ return null;
+ }
+
+ if (((string)reader.Value).IsNullOrEmpty())
+ {
+ return null;
+ }
+
+ return Activator.CreateInstance(objectType, new object[1] { reader.Value });
+ }
+ }
+}
diff --git a/zero.Debug/Controllers/MigrationController.Blueprints.cs b/zero.Debug/Controllers/MigrationController.Blueprints.cs
new file mode 100644
index 00000000..8c49719a
--- /dev/null
+++ b/zero.Debug/Controllers/MigrationController.Blueprints.cs
@@ -0,0 +1,138 @@
+using Microsoft.AspNetCore.Mvc;
+using Raven.Client.Documents;
+using Raven.Client.Documents.Session;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using zero.Commerce.Entities;
+using zero.Core;
+using zero.Core.Api;
+using zero.Core.Attributes;
+using zero.Core.Entities;
+using zero.Core.Extensions;
+using zero.Core.Utils;
+
+namespace zero.Debug.Controllers
+{
+ public partial class MigrationController : Controller
+ {
+
+
+ [HttpGet]
+ public async Task CreateBlueprints()
+ {
+ IList apps;
+
+ using (IAsyncDocumentSession session = Raven.OpenAsyncSession())
+ {
+ apps = await session.Query().ToListAsync();
+ }
+
+ async Task