mirror of https://github.com/Squidex/squidex.git
47 changed files with 593 additions and 373 deletions
@ -0,0 +1,16 @@ |
|||||
|
// ==========================================================================
|
||||
|
// IModelFieldProperties.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using PinkParrot.Infrastructure; |
||||
|
|
||||
|
namespace PinkParrot.Core.Schema |
||||
|
{ |
||||
|
public interface IModelFieldProperties : IValidatable |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
// ==========================================================================
|
||||
|
// IRegisterModelField.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace PinkParrot.Core.Schema |
||||
|
{ |
||||
|
public interface IRegisterModelField |
||||
|
{ |
||||
|
Type PropertiesType { get; } |
||||
|
|
||||
|
ModelField CreateField(long id, string name, IModelFieldProperties properties); |
||||
|
} |
||||
|
} |
||||
@ -1,64 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// SerializationModel.cs
|
|
||||
// PinkParrot Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) PinkParrot Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.Collections.Immutable; |
|
||||
using PinkParrot.Infrastructure; |
|
||||
|
|
||||
// ReSharper disable LoopCanBeConvertedToQuery
|
|
||||
|
|
||||
namespace PinkParrot.Core.Schema.Json |
|
||||
{ |
|
||||
public class SchemaDto |
|
||||
{ |
|
||||
private readonly ModelSchemaProperties properties; |
|
||||
private readonly ImmutableDictionary<long, ModelFieldProperties> fields; |
|
||||
|
|
||||
public ImmutableDictionary<long, ModelFieldProperties> Fields |
|
||||
{ |
|
||||
get { return fields; } |
|
||||
} |
|
||||
|
|
||||
public ModelSchemaProperties Properties |
|
||||
{ |
|
||||
get { return properties; } |
|
||||
} |
|
||||
|
|
||||
public SchemaDto(ModelSchemaProperties properties, ImmutableDictionary<long, ModelFieldProperties> fields) |
|
||||
{ |
|
||||
Guard.NotNull(fields, nameof(fields)); |
|
||||
Guard.NotNull(properties, nameof(properties)); |
|
||||
|
|
||||
this.properties = properties; |
|
||||
|
|
||||
this.fields = fields; |
|
||||
} |
|
||||
|
|
||||
public static SchemaDto Create(ModelSchema schema) |
|
||||
{ |
|
||||
Guard.NotNull(schema, nameof(schema)); |
|
||||
|
|
||||
var fields = schema.Fields.ToImmutableDictionary(x => x.Key, x => x.Value.RawProperties); |
|
||||
|
|
||||
return new SchemaDto(schema.Properties, fields); |
|
||||
} |
|
||||
|
|
||||
public ModelSchema ToModelSchema(ModelFieldFactory factory) |
|
||||
{ |
|
||||
Guard.NotNull(factory, nameof(factory)); |
|
||||
|
|
||||
var schema = ModelSchema.Create(properties); |
|
||||
|
|
||||
foreach (var field in fields) |
|
||||
{ |
|
||||
schema = schema.AddField(field.Key, field.Value, factory); |
|
||||
} |
|
||||
|
|
||||
return schema; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,49 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// ModelFieldFactory.cs
|
|
||||
// PinkParrot Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) PinkParrot Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using PinkParrot.Infrastructure; |
|
||||
|
|
||||
namespace PinkParrot.Core.Schema |
|
||||
{ |
|
||||
public class ModelFieldFactory |
|
||||
{ |
|
||||
private readonly Dictionary<Type, Func<long, ModelFieldProperties, ModelField>> factories |
|
||||
= new Dictionary<Type, Func<long, ModelFieldProperties, ModelField>>(); |
|
||||
|
|
||||
public ModelFieldFactory() |
|
||||
{ |
|
||||
AddFactory<NumberFieldProperties>((id, p) => new NumberField(id, (NumberFieldProperties)p)); |
|
||||
} |
|
||||
|
|
||||
public ModelFieldFactory AddFactory<T>(Func<long, ModelFieldProperties, ModelField> factory) where T : ModelFieldProperties |
|
||||
{ |
|
||||
Guard.NotNull(factory, nameof(factory)); |
|
||||
|
|
||||
factories[typeof(T)] = factory; |
|
||||
|
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public virtual ModelField CreateField(long id, ModelFieldProperties properties) |
|
||||
{ |
|
||||
Guard.NotNull(properties, nameof(properties)); |
|
||||
|
|
||||
var factory = factories.GetOrDefault(properties.GetType()); |
|
||||
|
|
||||
if (factory == null) |
|
||||
{ |
|
||||
throw new InvalidOperationException("Field type is not supported."); |
|
||||
} |
|
||||
|
|
||||
return factory(id, properties); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@ -0,0 +1,97 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ModelFieldRegistry.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using PinkParrot.Infrastructure; |
||||
|
|
||||
|
namespace PinkParrot.Core.Schema |
||||
|
{ |
||||
|
public delegate ModelField FactoryFunction(long id, string name, IModelFieldProperties properties); |
||||
|
|
||||
|
public sealed class ModelFieldRegistry |
||||
|
{ |
||||
|
private readonly Dictionary<string, IRegisterModelField> fieldsByTypeName = new Dictionary<string, IRegisterModelField>(); |
||||
|
private readonly Dictionary<Type, IRegisterModelField> fieldsByPropertyType = new Dictionary<Type, IRegisterModelField>(); |
||||
|
|
||||
|
private sealed class Registered : IRegisterModelField |
||||
|
{ |
||||
|
private readonly FactoryFunction fieldFactory; |
||||
|
private readonly Type propertiesType; |
||||
|
private readonly string typeName; |
||||
|
|
||||
|
public Type PropertiesType |
||||
|
{ |
||||
|
get { return propertiesType; } |
||||
|
} |
||||
|
|
||||
|
public string TypeName |
||||
|
{ |
||||
|
get { return typeName; } |
||||
|
} |
||||
|
|
||||
|
public Registered(FactoryFunction fieldFactory, Type propertiesType) |
||||
|
{ |
||||
|
typeName = TypeNameRegistry.GetName(propertiesType); |
||||
|
|
||||
|
this.fieldFactory = fieldFactory; |
||||
|
this.propertiesType = propertiesType; |
||||
|
} |
||||
|
|
||||
|
ModelField IRegisterModelField.CreateField(long id, string name, IModelFieldProperties properties) |
||||
|
{ |
||||
|
return fieldFactory(id, name, properties); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void Add<TFieldProperties>(FactoryFunction fieldFactory) |
||||
|
{ |
||||
|
Guard.NotNull(fieldFactory, nameof(fieldFactory)); |
||||
|
|
||||
|
var registered = new Registered(fieldFactory, typeof(TFieldProperties)); |
||||
|
|
||||
|
fieldsByTypeName[registered.TypeName] = registered; |
||||
|
fieldsByPropertyType[registered.PropertiesType] = registered; |
||||
|
} |
||||
|
|
||||
|
public ModelField CreateField(long id, string name, IModelFieldProperties properties) |
||||
|
{ |
||||
|
var registered = fieldsByPropertyType[properties.GetType()]; |
||||
|
|
||||
|
return registered.CreateField(id, name, properties); |
||||
|
} |
||||
|
|
||||
|
public IRegisterModelField FindByPropertiesType(Type type) |
||||
|
{ |
||||
|
Guard.NotNull(type, nameof(type)); |
||||
|
|
||||
|
var registered = fieldsByPropertyType.GetOrDefault(type); |
||||
|
|
||||
|
if (registered == null) |
||||
|
{ |
||||
|
throw new InvalidOperationException($"The field property '{type}' is not supported."); |
||||
|
} |
||||
|
|
||||
|
return registered; |
||||
|
} |
||||
|
|
||||
|
public IRegisterModelField FindByTypeName(string typeName) |
||||
|
{ |
||||
|
Guard.NotNullOrEmpty(typeName, nameof(typeName)); |
||||
|
|
||||
|
var registered = fieldsByTypeName.GetOrDefault(typeName); |
||||
|
|
||||
|
if (registered == null) |
||||
|
{ |
||||
|
throw new DomainException($"A field with type '{typeName} is not known."); |
||||
|
} |
||||
|
|
||||
|
return registered; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,75 @@ |
|||||
|
// ==========================================================================
|
||||
|
// TypeNameRegistry.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
namespace PinkParrot.Infrastructure |
||||
|
{ |
||||
|
public class TypeNameRegistry |
||||
|
{ |
||||
|
private static readonly Dictionary<Type, string> namesByType = new Dictionary<Type, string>(); |
||||
|
private static readonly Dictionary<string, Type> typesByName = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase); |
||||
|
|
||||
|
public static void Map(Type type, string name) |
||||
|
{ |
||||
|
Guard.NotNull(type, nameof(type)); |
||||
|
Guard.NotNull(name, nameof(name)); |
||||
|
|
||||
|
lock (namesByType) |
||||
|
{ |
||||
|
namesByType.Add(type, name); |
||||
|
|
||||
|
typesByName.Add(name, type); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static void Map(Assembly assembly) |
||||
|
{ |
||||
|
foreach (var type in assembly.GetTypes()) |
||||
|
{ |
||||
|
var typeNameAttribute = type.GetTypeInfo().GetCustomAttribute<TypeNameAttribute>(); |
||||
|
|
||||
|
if (!string.IsNullOrWhiteSpace(typeNameAttribute?.TypeName)) |
||||
|
{ |
||||
|
Map(type, typeNameAttribute.TypeName); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static string GetName<T>() |
||||
|
{ |
||||
|
return GetName(typeof(T)); |
||||
|
} |
||||
|
|
||||
|
public static string GetName(Type type) |
||||
|
{ |
||||
|
var result = namesByType.GetOrDefault(type); |
||||
|
|
||||
|
if (result == null) |
||||
|
{ |
||||
|
throw new ArgumentException($"There is not name for type '{type}"); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public static Type GetType(string name) |
||||
|
{ |
||||
|
var result = typesByName.GetOrDefault(name); |
||||
|
|
||||
|
if (result == null) |
||||
|
{ |
||||
|
throw new ArgumentException($"There is not type for name '{name}"); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ModelFieldDto.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Newtonsoft.Json; |
||||
|
using PinkParrot.Core.Schema; |
||||
|
|
||||
|
namespace PinkParrot.Read.Models |
||||
|
{ |
||||
|
public class ModelFieldDto |
||||
|
{ |
||||
|
[JsonProperty] |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
[JsonProperty] |
||||
|
public IModelFieldProperties Properties { get; set; } |
||||
|
|
||||
|
public static ModelFieldDto Create(ModelField field) |
||||
|
{ |
||||
|
return new ModelFieldDto { Name = field.Name, Properties = field.RawProperties }; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,63 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ModelSchemaDto.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using PinkParrot.Core.Schema; |
||||
|
using PinkParrot.Infrastructure; |
||||
|
using Newtonsoft.Json; |
||||
|
// ReSharper disable UseObjectOrCollectionInitializer
|
||||
|
// ReSharper disable InvertIf
|
||||
|
|
||||
|
namespace PinkParrot.Read.Models |
||||
|
{ |
||||
|
public sealed class ModelSchemaDto |
||||
|
{ |
||||
|
[JsonProperty] |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
[JsonProperty] |
||||
|
public Dictionary<long, ModelFieldDto> Fields { get; set; } |
||||
|
|
||||
|
[JsonProperty] |
||||
|
public ModelSchemaProperties Properties { get; set; } |
||||
|
|
||||
|
public static ModelSchemaDto Create(ModelSchema schema) |
||||
|
{ |
||||
|
Guard.NotNull(schema, nameof(schema)); |
||||
|
|
||||
|
var dto = new ModelSchemaDto { Properties = schema.Properties, Name = schema.Name }; |
||||
|
|
||||
|
dto.Fields = |
||||
|
schema.Fields.ToDictionary( |
||||
|
kvp => kvp.Key, |
||||
|
kvp => ModelFieldDto.Create(kvp.Value)); |
||||
|
|
||||
|
return dto; |
||||
|
} |
||||
|
|
||||
|
public ModelSchema ToSchema(ModelFieldRegistry registry) |
||||
|
{ |
||||
|
Guard.NotNull(registry, nameof(registry)); |
||||
|
|
||||
|
var schema = ModelSchema.Create(Name, Properties); |
||||
|
|
||||
|
if (Fields != null) |
||||
|
{ |
||||
|
foreach (var kvp in Fields) |
||||
|
{ |
||||
|
var field = kvp.Value; |
||||
|
|
||||
|
schema = schema.AddOrUpdateField(registry.CreateField(kvp.Key, field.Name, field.Properties)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return schema; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue