From 8c36409db8acce3361237318ca5103b874d7cf41 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 27 May 2018 23:13:14 +0200 Subject: [PATCH] Tests fixed. --- .../Partitioning.cs | 7 + .../Schemas/ArrayField.cs | 2 +- .../Schemas/ArrayFieldProperties.cs | 2 +- .../Schemas/FieldExtensions.cs | 145 ++++++++++++++++++ .../Schemas/FieldRegistry.cs | 2 +- .../Schemas/Fields.cs | 78 +++++++++- .../Schemas/IArrayField.cs | 6 +- .../Schemas/IField.cs | 2 + .../Schemas/IRootField.cs | 2 - .../Schemas/Json/JsonFieldModel.cs | 14 +- .../Schemas/Json/JsonNestedFieldModel.cs | 29 ++++ .../Schemas/Json/JsonSchemaModel.cs | 47 +++++- .../Schemas/NestedField.cs | 5 + .../GenerateJsonSchema/JsonTypeVisitor.cs | 2 +- .../Schemas/Commands/AddField.cs | 2 + .../Schemas/Commands/FieldCommand.cs | 2 + .../Schemas/Guards/GuardSchemaField.cs | 31 +++- .../Schemas/State/SchemaState.cs | 65 +++++--- .../Schemas/FieldEvent.cs | 2 + .../Schemas/SchemaCreatedField.cs | 3 + .../Schemas/SchemaCreatedNestedField.cs | 24 +++ .../Schemas/SchemaFieldsReordered.cs | 3 + .../TestData.cs | 81 +++++----- 23 files changed, 467 insertions(+), 89 deletions(-) create mode 100644 src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs create mode 100644 src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonNestedFieldModel.cs create mode 100644 src/Squidex.Domain.Apps.Events/Schemas/SchemaCreatedNestedField.cs diff --git a/src/Squidex.Domain.Apps.Core.Model/Partitioning.cs b/src/Squidex.Domain.Apps.Core.Model/Partitioning.cs index f6600ede5..8190674f1 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Partitioning.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Partitioning.cs @@ -45,5 +45,12 @@ namespace Squidex.Domain.Apps.Core { return Key; } + + public static Partitioning FromString(string value) + { + var isLanguage = string.Equals(value, Language.Key, StringComparison.OrdinalIgnoreCase); + + return isLanguage ? Language : Invariant; + } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs index d61950601..7a74a39f0 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs @@ -11,7 +11,7 @@ using System.Diagnostics.Contracts; namespace Squidex.Domain.Apps.Core.Schemas { - public sealed class ArrayField : RootField + public sealed class ArrayField : RootField, IArrayField { private FieldCollection fields = FieldCollection.Empty; diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayFieldProperties.cs index 5e4f3dc1a..f3f6100d9 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayFieldProperties.cs @@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Core.Schemas public override T Accept(IFieldVisitor visitor, IField field) { - return visitor.Visit((IField)field); + return visitor.Visit((IArrayField)field); } public override RootField CreateRootField(long id, string name, Partitioning partitioning) diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs new file mode 100644 index 000000000..8203d5921 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs @@ -0,0 +1,145 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; + +namespace Squidex.Domain.Apps.Core.Schemas +{ + public static class FieldExtensions + { + public static Schema LockField(this Schema schema, long fieldId) + { + return schema.UpdateField(fieldId, f => f.Lock()); + } + + public static Schema ReorderFields(this Schema schema, List ids, long? parentId = null) + { + if (parentId != null) + { + return schema.UpdateField(parentId.Value, f => + { + if (f is ArrayField arrayField) + { + return arrayField.ReorderFields(ids); + } + + return f; + }); + } + + return schema.ReorderFields(ids); + } + + public static Schema DeleteField(this Schema schema, long fieldId, long? parentId = null) + { + if (parentId != null) + { + return schema.UpdateField(parentId.Value, f => + { + if (f is ArrayField arrayField) + { + return arrayField.DeleteField(fieldId); + } + + return f; + }); + } + + return schema.DeleteField(fieldId); + } + + public static Schema HideField(this Schema schema, long fieldId, long? parentId = null) + { + if (parentId != null) + { + return schema.UpdateField(parentId.Value, f => + { + if (f is ArrayField arrayField) + { + return arrayField.UpdateField(fieldId, n => n.Hide()); + } + + return f; + }); + } + + return schema.UpdateField(fieldId, f => f.Hide()); + } + + public static Schema ShowField(this Schema schema, long fieldId, long? parentId = null) + { + if (parentId != null) + { + return schema.UpdateField(parentId.Value, f => + { + if (f is ArrayField arrayField) + { + return arrayField.UpdateField(fieldId, n => n.Show()); + } + + return f; + }); + } + + return schema.UpdateField(fieldId, f => f.Show()); + } + + public static Schema EnableField(this Schema schema, long fieldId, long? parentId = null) + { + if (parentId != null) + { + return schema.UpdateField(parentId.Value, f => + { + if (f is ArrayField arrayField) + { + return arrayField.UpdateField(fieldId, n => n.Enable()); + } + + return f; + }); + } + + return schema.UpdateField(fieldId, f => f.Enable()); + } + + public static Schema DisableField(this Schema schema, long fieldId, long? parentId = null) + { + if (parentId != null) + { + return schema.UpdateField(parentId.Value, f => + { + if (f is ArrayField arrayField) + { + return arrayField.UpdateField(fieldId, n => n.Disable()); + } + + return f; + }); + } + + return schema.UpdateField(fieldId, f => f.Disable()); + } + + public static Schema UpdateField(this Schema schema, long fieldId, FieldProperties properties, long? parentId = null) + { + if (parentId != null) + { + return schema.UpdateField(parentId.Value, f => + { + if (f is ArrayField arrayField) + { + return arrayField.UpdateField(fieldId, n => n.Update(properties)); + } + + return f; + }); + } + + return schema.UpdateField(fieldId, f => f.Update(properties)); + } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs index 9c896d365..fe778009b 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs @@ -49,7 +49,7 @@ namespace Squidex.Domain.Apps.Core.Schemas return properties.CreateRootField(id, name, partitioning); } - public NestedField CreateNestedField(long id, string name, Partitioning partitioning, FieldProperties properties) + public NestedField CreateNestedField(long id, string name, FieldProperties properties) { CheckProperties(properties); diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs index 66e8410cb..de6e49e28 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs @@ -5,13 +5,30 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; + namespace Squidex.Domain.Apps.Core.Schemas { public static class Fields { - public static RootField Array(long id, string name, Partitioning partitioning, ArrayFieldProperties properties = null) + public static RootField Array(long id, string name, Partitioning partitioning, params NestedField[] fields) + { + var result = new ArrayField(id, name, partitioning, new ArrayFieldProperties()); + + if (fields != null) + { + foreach (var field in fields) + { + result = result.AddField(field); + } + } + + return result; + } + + public static ArrayField Array(long id, string name, Partitioning partitioning, ArrayFieldProperties properties = null) { - return new RootField(id, name, partitioning, properties ?? new ArrayFieldProperties()); + return new ArrayField(id, name, partitioning, properties ?? new ArrayFieldProperties()); } public static RootField Assets(long id, string name, Partitioning partitioning, AssetsFieldProperties properties = null) @@ -104,6 +121,18 @@ namespace Squidex.Domain.Apps.Core.Schemas return new NestedField(id, name, properties ?? new TagsFieldProperties()); } + public static Schema AddArray(this Schema schema, long id, string name, Partitioning partitioning, Func handler, ArrayFieldProperties properties = null) + { + var field = Array(id, name, partitioning, properties); + + if (handler != null) + { + field = handler(field); + } + + return schema.AddField(field); + } + public static Schema AddAssets(this Schema schema, long id, string name, Partitioning partitioning, AssetsFieldProperties properties = null) { return schema.AddField(Assets(id, name, partitioning, properties)); @@ -148,5 +177,50 @@ namespace Squidex.Domain.Apps.Core.Schemas { return schema.AddField(Tags(id, name, partitioning, properties)); } + + public static ArrayField AddAssets(this ArrayField field, long id, string name, AssetsFieldProperties properties = null) + { + return field.AddField(Assets(id, name, properties)); + } + + public static ArrayField AddBoolean(this ArrayField field, long id, string name, BooleanFieldProperties properties = null) + { + return field.AddField(Boolean(id, name, properties)); + } + + public static ArrayField AddDateTime(this ArrayField field, long id, string name, DateTimeFieldProperties properties = null) + { + return field.AddField(DateTime(id, name, properties)); + } + + public static ArrayField AddGeolocation(this ArrayField field, long id, string name, GeolocationFieldProperties properties = null) + { + return field.AddField(Geolocation(id, name, properties)); + } + + public static ArrayField AddJson(this ArrayField field, long id, string name, JsonFieldProperties properties = null) + { + return field.AddField(Json(id, name, properties)); + } + + public static ArrayField AddNumber(this ArrayField field, long id, string name, NumberFieldProperties properties = null) + { + return field.AddField(Number(id, name, properties)); + } + + public static ArrayField AddReferences(this ArrayField field, long id, string name, ReferencesFieldProperties properties = null) + { + return field.AddField(References(id, name, properties)); + } + + public static ArrayField AddString(this ArrayField field, long id, string name, StringFieldProperties properties = null) + { + return field.AddField(String(id, name, properties)); + } + + public static ArrayField AddTags(this ArrayField field, long id, string name, TagsFieldProperties properties = null) + { + return field.AddField(Tags(id, name, properties)); + } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/IArrayField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/IArrayField.cs index c47dfee3b..0ea74cfbd 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/IArrayField.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/IArrayField.cs @@ -11,10 +11,10 @@ namespace Squidex.Domain.Apps.Core.Schemas { public interface IArrayField : IField { - IReadOnlyList Fields { get; } + IReadOnlyList Fields { get; } - IReadOnlyDictionary FieldsById { get; } + IReadOnlyDictionary FieldsById { get; } - IReadOnlyDictionary FieldsByName { get; } + IReadOnlyDictionary FieldsByName { get; } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/IField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/IField.cs index ebbc6ab49..6cc86239d 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/IField.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/IField.cs @@ -13,6 +13,8 @@ namespace Squidex.Domain.Apps.Core.Schemas string Name { get; } + bool IsLocked { get; } + bool IsDisabled { get; } bool IsHidden { get; } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/IRootField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/IRootField.cs index c05c182f8..31d9cd05f 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/IRootField.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/IRootField.cs @@ -9,8 +9,6 @@ namespace Squidex.Domain.Apps.Core.Schemas { public interface IRootField : IField { - bool IsLocked { get; } - Partitioning Partitioning { get; } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonFieldModel.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonFieldModel.cs index e4c04fdf8..952ef87f1 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonFieldModel.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonFieldModel.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Collections.Generic; using Newtonsoft.Json; namespace Squidex.Domain.Apps.Core.Schemas.Json @@ -15,21 +16,24 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json public long Id { get; set; } [JsonProperty] - public bool IsHidden { get; set; } + public string Name { get; set; } [JsonProperty] - public bool IsLocked { get; set; } + public string Partitioning { get; set; } [JsonProperty] - public bool IsDisabled { get; set; } + public bool IsHidden { get; set; } [JsonProperty] - public string Name { get; set; } + public bool IsLocked { get; set; } [JsonProperty] - public string Partitioning { get; set; } + public bool IsDisabled { get; set; } [JsonProperty] public FieldProperties Properties { get; set; } + + [JsonProperty] + public List Children { get; set; } } } \ No newline at end of file diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonNestedFieldModel.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonNestedFieldModel.cs new file mode 100644 index 000000000..59b2035e7 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonNestedFieldModel.cs @@ -0,0 +1,29 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Newtonsoft.Json; + +namespace Squidex.Domain.Apps.Core.Schemas.Json +{ + public sealed class JsonNestedFieldModel + { + [JsonProperty] + public long Id { get; set; } + + [JsonProperty] + public string Name { get; set; } + + [JsonProperty] + public bool IsHidden { get; set; } + + [JsonProperty] + public bool IsDisabled { get; set; } + + [JsonProperty] + public FieldProperties Properties { get; set; } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonSchemaModel.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonSchemaModel.cs index 1bb0c98ca..d45620c9a 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonSchemaModel.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonSchemaModel.cs @@ -38,11 +38,12 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json Properties = schema.Properties; Fields = - schema.Fields?.Select(x => + schema.Fields.Select(x => new JsonFieldModel { Id = x.Id, Name = x.Name, + Children = CreateChildren(x), IsHidden = x.IsHidden, IsLocked = x.IsLocked, IsDisabled = x.IsDisabled, @@ -53,7 +54,25 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json IsPublished = schema.IsPublished; } - public Schema ToSchema(FieldRegistry fieldRegistry) + private static List CreateChildren(IField field) + { + if (field is ArrayField arrayField) + { + return arrayField.Fields.Select(x => + new JsonNestedFieldModel + { + Id = x.Id, + Name = x.Name, + IsHidden = x.IsHidden, + IsDisabled = x.IsDisabled, + Properties = x.RawProperties + }).ToList(); + } + + return null; + } + + public Schema ToSchema(FieldRegistry registry) { RootField[] fields = Empty; @@ -67,7 +86,29 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json var parititonKey = new Partitioning(fieldModel.Partitioning); - var field = fieldRegistry.CreateRootField(fieldModel.Id, fieldModel.Name, parititonKey, fieldModel.Properties); + var field = registry.CreateRootField(fieldModel.Id, fieldModel.Name, parititonKey, fieldModel.Properties); + + if (field is ArrayField arrayField && fieldModel.Children?.Count > 0) + { + foreach (var nestedFieldModel in fieldModel.Children) + { + var nestedField = registry.CreateNestedField(nestedFieldModel.Id, nestedFieldModel.Name, nestedFieldModel.Properties); + + if (nestedFieldModel.IsHidden) + { + nestedField = nestedField.Hide(); + } + + if (nestedFieldModel.IsDisabled) + { + nestedField = nestedField.Disable(); + } + + arrayField = arrayField.AddField(nestedField); + } + + field = arrayField; + } if (fieldModel.IsDisabled) { diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField.cs index d209143de..4a580ea80 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField.cs @@ -37,6 +37,11 @@ namespace Squidex.Domain.Apps.Core.Schemas get { return isDisabled; } } + public bool IsLocked + { + get { return false; } + } + public abstract FieldProperties RawProperties { get; } protected NestedField(long id, string name) diff --git a/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs b/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs index 20ed81ca5..00ad5f60f 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs @@ -33,7 +33,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema foreach (var nestedField in field.Fields.Where(x => !x.IsHidden)) { - var childProperty = field.Accept(this); + var childProperty = nestedField.Accept(this); childProperty.Description = nestedField.RawProperties.Hints; childProperty.IsRequired = nestedField.RawProperties.IsRequired; diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/AddField.cs b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/AddField.cs index 8856821d6..09cc26f0a 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/AddField.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/AddField.cs @@ -11,6 +11,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands { public sealed class AddField : SchemaCommand { + public long? ParentFieldId { get; set; } + public string Name { get; set; } public string Partitioning { get; set; } diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/FieldCommand.cs b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/FieldCommand.cs index 5ad93ddf1..6246ad94c 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/FieldCommand.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/FieldCommand.cs @@ -9,6 +9,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands { public class FieldCommand : SchemaCommand { + public long? ParentFieldId { get; set; } + public long FieldId { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchemaField.cs b/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchemaField.cs index a2958750c..7fb424d87 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchemaField.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchemaField.cs @@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards } }); - var field = GetFieldOrThrow(schema, command.FieldId); + var field = GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId); if (field.IsLocked) { @@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { Guard.NotNull(command, nameof(command)); - var field = GetFieldOrThrow(schema, command.FieldId); + var field = GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId); if (field.IsLocked) { @@ -92,7 +92,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { Guard.NotNull(command, nameof(command)); - var field = GetFieldOrThrow(schema, command.FieldId); + var field = GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId); if (field.IsHidden) { @@ -104,7 +104,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { Guard.NotNull(command, nameof(command)); - var field = GetFieldOrThrow(schema, command.FieldId); + var field = GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId); if (!field.IsHidden) { @@ -116,7 +116,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { Guard.NotNull(command, nameof(command)); - var field = GetFieldOrThrow(schema, command.FieldId); + var field = GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId); if (field.IsDisabled) { @@ -126,7 +126,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards public static void CanEnable(Schema schema, EnableField command) { - var field = GetFieldOrThrow(schema, command.FieldId); + var field = GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId); if (!field.IsDisabled) { @@ -138,7 +138,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { Guard.NotNull(command, nameof(command)); - var field = GetFieldOrThrow(schema, command.FieldId); + var field = GetFieldOrThrow(schema, command.FieldId, null); if (field.IsLocked) { @@ -146,8 +146,23 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards } } - private static IRootField GetFieldOrThrow(Schema schema, long fieldId) + private static IField GetFieldOrThrow(Schema schema, long fieldId, long? parentId) { + if (parentId.HasValue) + { + if (!schema.FieldsById.TryGetValue(parentId.Value, out var rootField) || !(rootField is ArrayField arrayField)) + { + throw new DomainObjectNotFoundException(parentId.ToString(), "Fields", typeof(Schema)); + } + + if (!arrayField.FieldsById.TryGetValue(fieldId, out var nestedField)) + { + throw new DomainObjectNotFoundException(fieldId.ToString(), $"Fields[{parentId}].Fields", typeof(Schema)); + } + + return nestedField; + } + if (!schema.FieldsById.TryGetValue(fieldId, out var field)) { throw new DomainObjectNotFoundException(fieldId.ToString(), "Fields", typeof(Schema)); diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs b/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs index 6d4f0847f..81f104b6c 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs @@ -83,13 +83,34 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State { TotalFields++; - var partitioning = - string.Equals(eventField.Partitioning, Partitioning.Language.Key, StringComparison.OrdinalIgnoreCase) ? - Partitioning.Language : - Partitioning.Invariant; + var partitioning = Partitioning.FromString(eventField.Partitioning); var field = registry.CreateRootField(TotalFields, eventField.Name, partitioning, eventField.Properties); + if (field is ArrayField arrayField && eventField.Children?.Count > 0) + { + foreach (var nestedEventField in eventField.Children) + { + TotalFields++; + + var nestedField = registry.CreateNestedField(TotalFields, nestedEventField.Name, nestedEventField.Properties); + + if (nestedEventField.IsHidden) + { + nestedField = nestedField.Hide(); + } + + if (nestedEventField.IsDisabled) + { + nestedField = nestedField.Disable(); + } + + arrayField = arrayField.AddField(nestedField); + } + + field = arrayField; + } + if (eventField.IsHidden) { field = field.Hide(); @@ -116,15 +137,21 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State protected void On(FieldAdded @event, FieldRegistry registry) { - var partitioning = - string.Equals(@event.Partitioning, Partitioning.Language.Key, StringComparison.OrdinalIgnoreCase) ? - Partitioning.Language : - Partitioning.Invariant; + if (@event.ParentFieldId != null) + { + var field = registry.CreateNestedField(@event.FieldId.Id, @event.Name, @event.Properties); + + SchemaDef = SchemaDef.UpdateField(@event.ParentFieldId.Id, x => ((ArrayField)x).AddField(field)); + } + else + { + var partitioning = Partitioning.FromString(@event.Partitioning); - var field = registry.CreateRootField(@event.FieldId.Id, @event.Name, partitioning, @event.Properties); + var field = registry.CreateRootField(@event.FieldId.Id, @event.Name, partitioning, @event.Properties); - SchemaDef = SchemaDef.DeleteField(@event.FieldId.Id); - SchemaDef = SchemaDef.AddField(field); + SchemaDef = SchemaDef.DeleteField(@event.FieldId.Id); + SchemaDef = SchemaDef.AddField(field); + } TotalFields++; } @@ -151,42 +178,42 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State protected void On(SchemaFieldsReordered @event, FieldRegistry registry) { - SchemaDef = SchemaDef.ReorderFields(@event.FieldIds); + SchemaDef = SchemaDef.ReorderFields(@event.FieldIds, @event.ParentFieldIdId?.Id); } protected void On(FieldUpdated @event, FieldRegistry registry) { - SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Update(@event.Properties)); + SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, @event.Properties, @event.ParentFieldId?.Id); } protected void On(FieldLocked @event, FieldRegistry registry) { - SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Lock()); + SchemaDef = SchemaDef.LockField(@event.FieldId.Id); } protected void On(FieldDisabled @event, FieldRegistry registry) { - SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Disable()); + SchemaDef = SchemaDef.DisableField(@event.FieldId.Id, @event.ParentFieldId?.Id); } protected void On(FieldEnabled @event, FieldRegistry registry) { - SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Enable()); + SchemaDef = SchemaDef.EnableField(@event.FieldId.Id, @event.ParentFieldId?.Id); } protected void On(FieldHidden @event, FieldRegistry registry) { - SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Hide()); + SchemaDef = SchemaDef.HideField(@event.FieldId.Id, @event.ParentFieldId?.Id); } protected void On(FieldShown @event, FieldRegistry registry) { - SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Show()); + SchemaDef = SchemaDef.ShowField(@event.FieldId.Id, @event.ParentFieldId?.Id); } protected void On(FieldDeleted @event, FieldRegistry registry) { - SchemaDef = SchemaDef.DeleteField(@event.FieldId.Id); + SchemaDef = SchemaDef.DeleteField(@event.FieldId.Id, @event.ParentFieldId?.Id); } protected void On(SchemaDeleted @event, FieldRegistry registry) diff --git a/src/Squidex.Domain.Apps.Events/Schemas/FieldEvent.cs b/src/Squidex.Domain.Apps.Events/Schemas/FieldEvent.cs index 8887bf696..0c2a9690f 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/FieldEvent.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/FieldEvent.cs @@ -12,5 +12,7 @@ namespace Squidex.Domain.Apps.Events.Schemas public abstract class FieldEvent : SchemaEvent { public NamedId FieldId { get; set; } + + public NamedId ParentFieldId { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreatedField.cs b/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreatedField.cs index 3858eb897..75302b7fa 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreatedField.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreatedField.cs @@ -6,6 +6,7 @@ // ========================================================================== using Squidex.Domain.Apps.Core.Schemas; +using FieldChildren = System.Collections.Generic.List; namespace Squidex.Domain.Apps.Events.Schemas { @@ -21,6 +22,8 @@ namespace Squidex.Domain.Apps.Events.Schemas public bool IsDisabled { get; set; } + public FieldChildren Children { get; set; } + public FieldProperties Properties { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreatedNestedField.cs b/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreatedNestedField.cs new file mode 100644 index 000000000..7d8fb5878 --- /dev/null +++ b/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreatedNestedField.cs @@ -0,0 +1,24 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core.Schemas; + +namespace Squidex.Domain.Apps.Events.Schemas +{ + public sealed class SchemaCreatedNestedField + { + public string Name { get; set; } + + public bool IsHidden { get; set; } + + public bool IsLocked { get; set; } + + public bool IsDisabled { get; set; } + + public FieldProperties Properties { get; set; } + } +} diff --git a/src/Squidex.Domain.Apps.Events/Schemas/SchemaFieldsReordered.cs b/src/Squidex.Domain.Apps.Events/Schemas/SchemaFieldsReordered.cs index 9a34fd94e..154f1db1e 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/SchemaFieldsReordered.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/SchemaFieldsReordered.cs @@ -6,6 +6,7 @@ // ========================================================================== using System.Collections.Generic; +using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Schemas @@ -13,6 +14,8 @@ namespace Squidex.Domain.Apps.Events.Schemas [EventType(nameof(SchemaFieldsReordered))] public sealed class SchemaFieldsReordered : SchemaEvent { + public NamedId ParentFieldIdId { get; set; } + public List FieldIds { get; set; } } } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/TestData.cs b/tests/Squidex.Domain.Apps.Core.Tests/TestData.cs index 054969ca5..3fb7d451f 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/TestData.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/TestData.cs @@ -54,49 +54,44 @@ namespace Squidex.Domain.Apps.Core public static Schema MixedSchema() { - var inv = Partitioning.Invariant; - - var schema = new Schema("user"); - - schema = schema.Publish(); - schema = schema.Update(new SchemaProperties { Hints = "The User" }); - - schema = schema.AddJson(1, "my-json", inv, - new JsonFieldProperties()); - - schema = schema.AddAssets(2, "my-assets", inv, - new AssetsFieldProperties()); - - schema = schema.AddString(3, "my-string1", inv, - new StringFieldProperties { Label = "My String1", IsRequired = true, AllowedValues = ImmutableList.Create("a", "b") }); - - schema = schema.AddString(4, "my-string2", inv, - new StringFieldProperties { Hints = "My String1" }); - - schema = schema.AddNumber(5, "my-number", inv, - new NumberFieldProperties { MinValue = 1, MaxValue = 10 }); - - schema = schema.AddBoolean(6, "my-boolean", inv, - new BooleanFieldProperties()); - - schema = schema.AddDateTime(7, "my-datetime", inv, - new DateTimeFieldProperties { Editor = DateTimeFieldEditor.DateTime }); - - schema = schema.AddDateTime(8, "my-date", inv, - new DateTimeFieldProperties { Editor = DateTimeFieldEditor.Date }); - - schema = schema.AddGeolocation(9, "my-geolocation", inv, - new GeolocationFieldProperties()); - - schema = schema.AddReferences(10, "my-references", inv, - new ReferencesFieldProperties()); - - schema = schema.AddTags(11, "my-tags", Partitioning.Language, - new TagsFieldProperties()); - - schema = schema.UpdateField(7, f => f.Hide()); - schema = schema.UpdateField(8, f => f.Lock()); - schema = schema.UpdateField(9, f => f.Disable()); + var schema = new Schema("user") + .Publish() + .AddArray(101, "root-array", Partitioning.Language, f => f + .AddAssets(201, "nested-assets") + .AddBoolean(202, "nested-boolean") + .AddDateTime(203, "nested-datetime") + .AddGeolocation(204, "nested-geolocation") + .AddJson(205, "nested-json") + .AddNumber(206, "nested-number") + .AddReferences(207, "nested-references") + .AddString(208, "nested-string") + .AddTags(209, "nested-tags")) + .AddAssets(102, "root-assets", Partitioning.Invariant, + new AssetsFieldProperties()) + .AddBoolean(103, "root-boolean", Partitioning.Invariant, + new BooleanFieldProperties()) + .AddDateTime(104, "root-datetime", Partitioning.Invariant, + new DateTimeFieldProperties { Editor = DateTimeFieldEditor.DateTime }) + .AddDateTime(105, "root-date", Partitioning.Invariant, + new DateTimeFieldProperties { Editor = DateTimeFieldEditor.Date }) + .AddGeolocation(106, "root-geolocation", Partitioning.Invariant, + new GeolocationFieldProperties()) + .AddJson(107, "root-json", Partitioning.Invariant, + new JsonFieldProperties()) + .AddNumber(108, "root-number", Partitioning.Invariant, + new NumberFieldProperties { MinValue = 1, MaxValue = 10 }) + .AddReferences(109, "root-references", Partitioning.Invariant, + new ReferencesFieldProperties()) + .AddString(110, "root-string1", Partitioning.Invariant, + new StringFieldProperties { Label = "My String1", IsRequired = true, AllowedValues = ImmutableList.Create("a", "b") }) + .AddString(111, "root-string2", Partitioning.Invariant, + new StringFieldProperties { Hints = "My String1" }) + .AddTags(112, "root-tags", Partitioning.Language, + new TagsFieldProperties()) + .Update(new SchemaProperties { Hints = "The User" }) + .UpdateField(107, f => f.Hide()) + .UpdateField(108, f => f.Lock()) + .UpdateField(109, f => f.Disable()); return schema; }