diff --git a/.gitignore b/.gitignore index 49682e0d7..09eeeb783 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ node_modules/ /src/Squidex/Assets /src/Squidex/appsettings.Development.json -/src/Squidex/Properties/launchSettings.json \ No newline at end of file +/src/Squidex/Properties/launchSettings.json +/global.json diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs new file mode 100644 index 000000000..d61950601 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs @@ -0,0 +1,77 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; + +namespace Squidex.Domain.Apps.Core.Schemas +{ + public sealed class ArrayField : RootField + { + private FieldCollection fields = FieldCollection.Empty; + + public IReadOnlyList Fields + { + get { return fields.Ordered; } + } + + public IReadOnlyDictionary FieldsById + { + get { return fields.ById; } + } + + public IReadOnlyDictionary FieldsByName + { + get { return fields.ByName; } + } + + public ArrayField(long id, string name, Partitioning partitioning, ArrayFieldProperties properties) + : base(id, name, partitioning, properties) + { + } + + [Pure] + public ArrayField DeleteField(long fieldId) + { + return Updatefields(f => f.Remove(fieldId)); + } + + [Pure] + public ArrayField ReorderFields(List ids) + { + return Updatefields(f => f.Reorder(ids)); + } + + [Pure] + public ArrayField AddField(NestedField field) + { + return Updatefields(f => f.Add(field)); + } + + [Pure] + public ArrayField UpdateField(long fieldId, Func updater) + { + return Updatefields(f => f.Update(fieldId, updater)); + } + + private ArrayField Updatefields(Func, FieldCollection> updater) + { + var newFields = updater(fields); + + if (ReferenceEquals(newFields, fields)) + { + return this; + } + + return Clone(clone => + { + clone.fields = newFields; + }); + } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayFieldProperties.cs index 46d7d5198..5e4f3dc1a 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayFieldProperties.cs @@ -19,17 +19,22 @@ namespace Squidex.Domain.Apps.Core.Schemas public override T Accept(IFieldPropertiesVisitor visitor) { - throw new NotImplementedException(); + return visitor.Visit(this); } public override T Accept(IFieldVisitor visitor, IField field) { - throw new NotImplementedException(); + return visitor.Visit((IField)field); } - public override Field CreateField(long id, string name, Partitioning partitioning) + public override RootField CreateRootField(long id, string name, Partitioning partitioning) { - throw new NotImplementedException(); + return Fields.Array(id, name, partitioning, this); + } + + public override NestedField CreateNestedField(long id, string name) + { + throw new NotSupportedException(); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/AssetsFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/AssetsFieldProperties.cs index 182030e50..62b3be7c1 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/AssetsFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/AssetsFieldProperties.cs @@ -47,9 +47,14 @@ namespace Squidex.Domain.Apps.Core.Schemas return visitor.Visit((IField)field); } - public override Field CreateField(long id, string name, Partitioning partitioning) + public override RootField CreateRootField(long id, string name, Partitioning partitioning) { - return new Field(id, name, partitioning, this); + return Fields.Assets(id, name, partitioning, this); + } + + public override NestedField CreateNestedField(long id, string name) + { + return Fields.Assets(id, name, this); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/BooleanFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/BooleanFieldProperties.cs index 363a1a6fa..a4a0750a5 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/BooleanFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/BooleanFieldProperties.cs @@ -28,9 +28,14 @@ namespace Squidex.Domain.Apps.Core.Schemas return visitor.Visit((IField)field); } - public override Field CreateField(long id, string name, Partitioning partitioning) + public override RootField CreateRootField(long id, string name, Partitioning partitioning) { - return new Field(id, name, partitioning, this); + return Fields.Boolean(id, name, partitioning, this); + } + + public override NestedField CreateNestedField(long id, string name) + { + return Fields.Boolean(id, name, this); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/DateTimeFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/DateTimeFieldProperties.cs index 0a740490f..efbcad12b 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/DateTimeFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/DateTimeFieldProperties.cs @@ -33,9 +33,14 @@ namespace Squidex.Domain.Apps.Core.Schemas return visitor.Visit((IField)field); } - public override Field CreateField(long id, string name, Partitioning partitioning) + public override RootField CreateRootField(long id, string name, Partitioning partitioning) { - return new Field(id, name, partitioning, this); + return Fields.DateTime(id, name, partitioning, this); + } + + public override NestedField CreateNestedField(long id, string name) + { + return Fields.DateTime(id, name, this); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs new file mode 100644 index 000000000..d62ef5873 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs @@ -0,0 +1,161 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.Contracts; +using System.Linq; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Core.Schemas +{ + public sealed class FieldCollection : Cloneable> where T : IField + { + public static readonly FieldCollection Empty = new FieldCollection(); + + private ImmutableArray fieldsOrdered = ImmutableArray.Empty; + private ImmutableDictionary fieldsById; + private ImmutableDictionary fieldsByName; + + public IReadOnlyList Ordered + { + get { return fieldsOrdered; } + } + + public IReadOnlyDictionary ById + { + get + { + if (fieldsById == null) + { + if (fieldsOrdered.Length == 0) + { + fieldsById = ImmutableDictionary.Empty; + } + else + { + fieldsById = fieldsOrdered.ToImmutableDictionary(x => x.Id); + } + } + + return fieldsById; + } + } + + public IReadOnlyDictionary ByName + { + get + { + if (fieldsByName == null) + { + if (fieldsOrdered.Length == 0) + { + fieldsByName = ImmutableDictionary.Empty; + } + else + { + fieldsByName = fieldsOrdered.ToImmutableDictionary(x => x.Name); + } + } + + return fieldsByName; + } + } + + private FieldCollection() + { + } + + public FieldCollection(T[] fields) + { + Guard.NotNull(fields, nameof(fields)); + + fieldsOrdered = ImmutableArray.Create(fields); + } + + protected override void OnCloned() + { + fieldsById = null; + fieldsByName = null; + } + + [Pure] + public FieldCollection Remove(long fieldId) + { + if (!ById.TryGetValue(fieldId, out var field)) + { + return this; + } + + return Clone(clone => + { + clone.fieldsOrdered = fieldsOrdered.Remove(field); + }); + } + + [Pure] + public FieldCollection Reorder(List ids) + { + Guard.NotNull(ids, nameof(ids)); + + if (ids.Count != fieldsOrdered.Length || ids.Any(x => !ById.ContainsKey(x))) + { + throw new ArgumentException("Ids must cover all fields.", nameof(ids)); + } + + return Clone(clone => + { + clone.fieldsOrdered = fieldsOrdered.OrderBy(f => ids.IndexOf(f.Id)).ToImmutableArray(); + }); + } + + [Pure] + public FieldCollection Add(T field) + { + Guard.NotNull(field, nameof(field)); + + if (ByName.ContainsKey(field.Name) || ById.ContainsKey(field.Id)) + { + throw new ArgumentException($"A field with name '{field.Name}' and id {field.Id} already exists.", nameof(field)); + } + + return Clone(clone => + { + clone.fieldsOrdered = clone.fieldsOrdered.Add(field); + }); + } + + [Pure] + public FieldCollection Update(long fieldId, Func updater) + { + Guard.NotNull(updater, nameof(updater)); + + if (!ById.TryGetValue(fieldId, out var field)) + { + return this; + } + + var newField = updater(field); + + if (ReferenceEquals(newField, field)) + { + return this; + } + + if (!(newField is T typedField)) + { + throw new InvalidOperationException($"Field must be of type {typeof(T)}"); + } + + return Clone(clone => + { + clone.fieldsOrdered = clone.fieldsOrdered.Replace(field, typedField); + }); + } + } +} \ No newline at end of file diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldProperties.cs index 35da7cf8b..a9c8d0421 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldProperties.cs @@ -21,6 +21,8 @@ namespace Squidex.Domain.Apps.Core.Schemas public abstract T Accept(IFieldVisitor visitor, IField field); - public abstract Field CreateField(long id, string name, Partitioning partitioning); + public abstract RootField CreateRootField(long id, string name, Partitioning partitioning); + + public abstract NestedField CreateNestedField(long id, string name); } } \ No newline at end of file diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs index f3488d75e..9c896d365 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldRegistry.cs @@ -14,10 +14,8 @@ namespace Squidex.Domain.Apps.Core.Schemas { public sealed class FieldRegistry { - private delegate Field FactoryFunction(long id, string name, Partitioning partitioning, FieldProperties properties); - private readonly TypeNameRegistry typeNameRegistry; - private readonly Dictionary fieldsByPropertyType = new Dictionary(); + private readonly HashSet supportedFields = new HashSet(); public FieldRegistry(TypeNameRegistry typeNameRegistry) { @@ -38,23 +36,34 @@ namespace Squidex.Domain.Apps.Core.Schemas private void RegisterField(Type type) { - typeNameRegistry.Map(type); + if (supportedFields.Add(type)) + { + typeNameRegistry.Map(type); + } + } + + public RootField CreateRootField(long id, string name, Partitioning partitioning, FieldProperties properties) + { + CheckProperties(properties); - fieldsByPropertyType[type] = (id, name, partitioning, properties) => properties.CreateField(id, name, partitioning); + return properties.CreateRootField(id, name, partitioning); } - public Field CreateField(long id, string name, Partitioning partitioning, FieldProperties properties) + public NestedField CreateNestedField(long id, string name, Partitioning partitioning, FieldProperties properties) { - Guard.NotNull(properties, nameof(properties)); + CheckProperties(properties); + + return properties.CreateNestedField(id, name); + } - var factory = fieldsByPropertyType.GetOrDefault(properties.GetType()); + private void CheckProperties(FieldProperties properties) + { + Guard.NotNull(properties, nameof(properties)); - if (factory == null) + if (!supportedFields.Contains(properties.GetType())) { throw new InvalidOperationException($"The field property '{properties.GetType()}' is not supported."); } - - return factory(id, name, partitioning, properties); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs index a74402b24..66e8410cb 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs @@ -9,49 +9,99 @@ namespace Squidex.Domain.Apps.Core.Schemas { public static class Fields { - public static Field Assets(long id, string name, Partitioning partitioning, AssetsFieldProperties properties = null) + public static RootField Array(long id, string name, Partitioning partitioning, ArrayFieldProperties properties = null) { - return new Field(id, name, partitioning, properties ?? new AssetsFieldProperties()); + return new RootField(id, name, partitioning, properties ?? new ArrayFieldProperties()); } - public static Field Boolean(long id, string name, Partitioning partitioning, BooleanFieldProperties properties = null) + public static RootField Assets(long id, string name, Partitioning partitioning, AssetsFieldProperties properties = null) { - return new Field(id, name, partitioning, properties ?? new BooleanFieldProperties()); + return new RootField(id, name, partitioning, properties ?? new AssetsFieldProperties()); } - public static Field DateTime(long id, string name, Partitioning partitioning, DateTimeFieldProperties properties = null) + public static RootField Boolean(long id, string name, Partitioning partitioning, BooleanFieldProperties properties = null) { - return new Field(id, name, partitioning, properties ?? new DateTimeFieldProperties()); + return new RootField(id, name, partitioning, properties ?? new BooleanFieldProperties()); } - public static Field Geolocation(long id, string name, Partitioning partitioning, GeolocationFieldProperties properties = null) + public static RootField DateTime(long id, string name, Partitioning partitioning, DateTimeFieldProperties properties = null) { - return new Field(id, name, partitioning, properties ?? new GeolocationFieldProperties()); + return new RootField(id, name, partitioning, properties ?? new DateTimeFieldProperties()); } - public static Field Json(long id, string name, Partitioning partitioning, JsonFieldProperties properties = null) + public static RootField Geolocation(long id, string name, Partitioning partitioning, GeolocationFieldProperties properties = null) { - return new Field(id, name, partitioning, properties ?? new JsonFieldProperties()); + return new RootField(id, name, partitioning, properties ?? new GeolocationFieldProperties()); } - public static Field Number(long id, string name, Partitioning partitioning, NumberFieldProperties properties = null) + public static RootField Json(long id, string name, Partitioning partitioning, JsonFieldProperties properties = null) { - return new Field(id, name, partitioning, properties ?? new NumberFieldProperties()); + return new RootField(id, name, partitioning, properties ?? new JsonFieldProperties()); } - public static Field References(long id, string name, Partitioning partitioning, ReferencesFieldProperties properties = null) + public static RootField Number(long id, string name, Partitioning partitioning, NumberFieldProperties properties = null) { - return new Field(id, name, partitioning, properties ?? new ReferencesFieldProperties()); + return new RootField(id, name, partitioning, properties ?? new NumberFieldProperties()); } - public static Field String(long id, string name, Partitioning partitioning, StringFieldProperties properties = null) + public static RootField References(long id, string name, Partitioning partitioning, ReferencesFieldProperties properties = null) { - return new Field(id, name, partitioning, properties ?? new StringFieldProperties()); + return new RootField(id, name, partitioning, properties ?? new ReferencesFieldProperties()); } - public static Field Tags(long id, string name, Partitioning partitioning, TagsFieldProperties properties = null) + public static RootField String(long id, string name, Partitioning partitioning, StringFieldProperties properties = null) { - return new Field(id, name, partitioning, properties ?? new TagsFieldProperties()); + return new RootField(id, name, partitioning, properties ?? new StringFieldProperties()); + } + + public static RootField Tags(long id, string name, Partitioning partitioning, TagsFieldProperties properties = null) + { + return new RootField(id, name, partitioning, properties ?? new TagsFieldProperties()); + } + + public static NestedField Assets(long id, string name, AssetsFieldProperties properties = null) + { + return new NestedField(id, name, properties ?? new AssetsFieldProperties()); + } + + public static NestedField Boolean(long id, string name, BooleanFieldProperties properties = null) + { + return new NestedField(id, name, properties ?? new BooleanFieldProperties()); + } + + public static NestedField DateTime(long id, string name, DateTimeFieldProperties properties = null) + { + return new NestedField(id, name, properties ?? new DateTimeFieldProperties()); + } + + public static NestedField Geolocation(long id, string name, GeolocationFieldProperties properties = null) + { + return new NestedField(id, name, properties ?? new GeolocationFieldProperties()); + } + + public static NestedField Json(long id, string name, JsonFieldProperties properties = null) + { + return new NestedField(id, name, properties ?? new JsonFieldProperties()); + } + + public static NestedField Number(long id, string name, NumberFieldProperties properties = null) + { + return new NestedField(id, name, properties ?? new NumberFieldProperties()); + } + + public static NestedField References(long id, string name, ReferencesFieldProperties properties = null) + { + return new NestedField(id, name, properties ?? new ReferencesFieldProperties()); + } + + public static NestedField String(long id, string name, StringFieldProperties properties = null) + { + return new NestedField(id, name, properties ?? new StringFieldProperties()); + } + + public static NestedField Tags(long id, string name, TagsFieldProperties properties = null) + { + return new NestedField(id, name, properties ?? new TagsFieldProperties()); } public static Schema AddAssets(this Schema schema, long id, string name, Partitioning partitioning, AssetsFieldProperties properties = null) diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/GeolocationFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/GeolocationFieldProperties.cs index d5a48136c..9136b723c 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/GeolocationFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/GeolocationFieldProperties.cs @@ -24,9 +24,14 @@ namespace Squidex.Domain.Apps.Core.Schemas return visitor.Visit((IField)field); } - public override Field CreateField(long id, string name, Partitioning partitioning) + public override RootField CreateRootField(long id, string name, Partitioning partitioning) { - return new Field(id, name, partitioning, this); + return Fields.Geolocation(id, name, partitioning, this); + } + + public override NestedField CreateNestedField(long id, string name) + { + return Fields.Geolocation(id, name, this); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/IArrayField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/IArrayField.cs index 4ee839be5..c47dfee3b 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 552a24eda..ebbc6ab49 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/IField.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/IField.cs @@ -17,8 +17,6 @@ namespace Squidex.Domain.Apps.Core.Schemas bool IsHidden { get; } - bool IsLocked { get; } - FieldProperties RawProperties { get; } T Accept(IFieldVisitor visitor); diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/INestedField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/INestedField.cs new file mode 100644 index 000000000..5bacd00eb --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/INestedField.cs @@ -0,0 +1,13 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Core.Schemas +{ + public interface INestedField : IField + { + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/IRootField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/IRootField.cs new file mode 100644 index 000000000..c05c182f8 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/IRootField.cs @@ -0,0 +1,16 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +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/JsonSchemaModel.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonSchemaModel.cs index be5b64a66..1bb0c98ca 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonSchemaModel.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonSchemaModel.cs @@ -13,7 +13,7 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json { public sealed class JsonSchemaModel { - private static readonly Field[] Empty = new Field[0]; + private static readonly RootField[] Empty = new RootField[0]; [JsonProperty] public string Name { get; set; } @@ -55,11 +55,11 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json public Schema ToSchema(FieldRegistry fieldRegistry) { - Field[] fields = Empty; + RootField[] fields = Empty; if (Fields != null) { - fields = new Field[Fields.Count]; + fields = new RootField[Fields.Count]; for (var i = 0; i < fields.Length; i++) { @@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json var parititonKey = new Partitioning(fieldModel.Partitioning); - var field = fieldRegistry.CreateField(fieldModel.Id, fieldModel.Name, parititonKey, fieldModel.Properties); + var field = fieldRegistry.CreateRootField(fieldModel.Id, fieldModel.Name, parititonKey, fieldModel.Properties); if (fieldModel.IsDisabled) { diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/JsonFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/JsonFieldProperties.cs index b0801ef60..6edb4f80b 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/JsonFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/JsonFieldProperties.cs @@ -22,9 +22,14 @@ namespace Squidex.Domain.Apps.Core.Schemas return visitor.Visit((IField)field); } - public override Field CreateField(long id, string name, Partitioning partitioning) + public override RootField CreateRootField(long id, string name, Partitioning partitioning) { - return new Field(id, name, partitioning, this); + return Fields.Json(id, name, partitioning, this); + } + + public override NestedField CreateNestedField(long id, string name) + { + return Fields.Json(id, name, this); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField.cs new file mode 100644 index 000000000..d209143de --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField.cs @@ -0,0 +1,91 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Diagnostics.Contracts; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Core.Schemas +{ + public abstract class NestedField : Cloneable, INestedField + { + private readonly long fieldId; + private readonly string fieldName; + private bool isDisabled; + private bool isHidden; + + public long Id + { + get { return fieldId; } + } + + public string Name + { + get { return fieldName; } + } + + public bool IsHidden + { + get { return isHidden; } + } + + public bool IsDisabled + { + get { return isDisabled; } + } + + public abstract FieldProperties RawProperties { get; } + + protected NestedField(long id, string name) + { + Guard.NotNullOrEmpty(name, nameof(name)); + Guard.GreaterThan(id, 0, nameof(id)); + + fieldId = id; + fieldName = name; + } + + [Pure] + public NestedField Hide() + { + return Clone(clone => + { + clone.isHidden = true; + }); + } + + [Pure] + public NestedField Show() + { + return Clone(clone => + { + clone.isHidden = false; + }); + } + + [Pure] + public NestedField Disable() + { + return Clone(clone => + { + clone.isDisabled = true; + }); + } + + [Pure] + public NestedField Enable() + { + return Clone(clone => + { + clone.isDisabled = false; + }); + } + + public abstract T Accept(IFieldVisitor visitor); + + public abstract NestedField Update(FieldProperties newProperties); + } +} \ No newline at end of file diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs new file mode 100644 index 000000000..7de914a4b --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs @@ -0,0 +1,70 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Diagnostics.Contracts; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Core.Schemas +{ + public class NestedField : NestedField, IField where T : FieldProperties, new() + { + private T properties; + + public T Properties + { + get { return properties; } + } + + public override FieldProperties RawProperties + { + get { return properties; } + } + + public NestedField(long id, string name, T properties) + : base(id, name) + { + Guard.NotNull(properties, nameof(properties)); + + SetProperties(properties); + } + + [Pure] + public override NestedField Update(FieldProperties newProperties) + { + var typedProperties = ValidateProperties(newProperties); + + return Clone>(clone => + { + clone.SetProperties(typedProperties); + }); + } + + private void SetProperties(T newProperties) + { + properties = newProperties; + properties.Freeze(); + } + + private T ValidateProperties(FieldProperties newProperties) + { + Guard.NotNull(newProperties, nameof(newProperties)); + + if (!(newProperties is T typedProperties)) + { + throw new ArgumentException($"Properties must be of type '{typeof(T)}", nameof(newProperties)); + } + + return typedProperties; + } + + public override TResult Accept(IFieldVisitor visitor) + { + return properties.Accept(visitor, this); + } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/NumberFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/NumberFieldProperties.cs index 4f08f1972..3238aff25 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/NumberFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/NumberFieldProperties.cs @@ -35,9 +35,14 @@ namespace Squidex.Domain.Apps.Core.Schemas return visitor.Visit((IField)field); } - public override Field CreateField(long id, string name, Partitioning partitioning) + public override RootField CreateRootField(long id, string name, Partitioning partitioning) { - return new Field(id, name, partitioning, this); + return Fields.Number(id, name, partitioning, this); + } + + public override NestedField CreateNestedField(long id, string name) + { + return Fields.Number(id, name, this); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/ReferencesFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/ReferencesFieldProperties.cs index 2bb64e682..98e4bb5ec 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/ReferencesFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/ReferencesFieldProperties.cs @@ -29,9 +29,14 @@ namespace Squidex.Domain.Apps.Core.Schemas return visitor.Visit((IField)field); } - public override Field CreateField(long id, string name, Partitioning partitioning) + public override RootField CreateRootField(long id, string name, Partitioning partitioning) { - return new Field(id, name, partitioning, this); + return Fields.References(id, name, partitioning, this); + } + + public override NestedField CreateNestedField(long id, string name) + { + return Fields.References(id, name, this); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Field.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField.cs similarity index 84% rename from src/Squidex.Domain.Apps.Core.Model/Schemas/Field.cs rename to src/Squidex.Domain.Apps.Core.Model/Schemas/RootField.cs index b69071fb3..461f60365 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Field.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField.cs @@ -10,11 +10,11 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Schemas { - public abstract class Field : Cloneable, IField + public abstract class RootField : Cloneable, IRootField { private readonly long fieldId; - private readonly Partitioning partitioning; private readonly string fieldName; + private readonly Partitioning partitioning; private bool isDisabled; private bool isHidden; private bool isLocked; @@ -51,11 +51,11 @@ namespace Squidex.Domain.Apps.Core.Schemas public abstract FieldProperties RawProperties { get; } - protected Field(long id, string name, Partitioning partitioning) + protected RootField(long id, string name, Partitioning partitioning) { Guard.NotNullOrEmpty(name, nameof(name)); - Guard.NotNull(partitioning, nameof(partitioning)); Guard.GreaterThan(id, 0, nameof(id)); + Guard.NotNull(partitioning, nameof(partitioning)); fieldId = id; fieldName = name; @@ -64,16 +64,16 @@ namespace Squidex.Domain.Apps.Core.Schemas } [Pure] - public Field Lock() + public RootField Lock() { - return Clone(clone => + return Clone(clone => { clone.isLocked = true; }); } [Pure] - public Field Hide() + public RootField Hide() { return Clone(clone => { @@ -82,7 +82,7 @@ namespace Squidex.Domain.Apps.Core.Schemas } [Pure] - public Field Show() + public RootField Show() { return Clone(clone => { @@ -91,7 +91,7 @@ namespace Squidex.Domain.Apps.Core.Schemas } [Pure] - public Field Disable() + public RootField Disable() { return Clone(clone => { @@ -100,7 +100,7 @@ namespace Squidex.Domain.Apps.Core.Schemas } [Pure] - public Field Enable() + public RootField Enable() { return Clone(clone => { @@ -108,8 +108,8 @@ namespace Squidex.Domain.Apps.Core.Schemas }); } - public abstract Field Update(FieldProperties newProperties); - public abstract T Accept(IFieldVisitor visitor); + + public abstract RootField Update(FieldProperties newProperties); } } \ No newline at end of file diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Field{T}.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs similarity index 71% rename from src/Squidex.Domain.Apps.Core.Model/Schemas/Field{T}.cs rename to src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs index e1da04c62..90165643b 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Field{T}.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Schemas { - public sealed class Field : Field, IField where T : FieldProperties, new() + public class RootField : RootField, IField where T : FieldProperties, new() { private T properties; @@ -25,27 +25,31 @@ namespace Squidex.Domain.Apps.Core.Schemas get { return properties; } } - public Field(long id, string name, Partitioning partitioning, T properties) + public RootField(long id, string name, Partitioning partitioning, T properties) : base(id, name, partitioning) { Guard.NotNull(properties, nameof(properties)); - this.properties = properties; - this.properties.Freeze(); + SetProperties(properties); } [Pure] - public override Field Update(FieldProperties newProperties) + public override RootField Update(FieldProperties newProperties) { var typedProperties = ValidateProperties(newProperties); - return Clone>(clone => + return Clone>(clone => { - clone.properties = typedProperties; - clone.properties.Freeze(); + clone.SetProperties(typedProperties); }); } + private void SetProperties(T newProperties) + { + properties = newProperties; + properties.Freeze(); + } + private T ValidateProperties(FieldProperties newProperties) { Guard.NotNull(newProperties, nameof(newProperties)); @@ -60,7 +64,7 @@ namespace Squidex.Domain.Apps.Core.Schemas public override TResult Accept(IFieldVisitor visitor) { - return RawProperties.Accept(visitor, this); + return properties.Accept(visitor, this); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Schema.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/Schema.cs index ec20d7e8a..c6e187087 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Schema.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/Schema.cs @@ -7,9 +7,7 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics.Contracts; -using System.Linq; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Schemas @@ -17,9 +15,7 @@ namespace Squidex.Domain.Apps.Core.Schemas public sealed class Schema : Cloneable { private readonly string name; - private ImmutableArray fieldsOrdered = ImmutableArray.Empty; - private ImmutableDictionary fieldsById; - private ImmutableDictionary fieldsByName; + private FieldCollection fields = FieldCollection.Empty; private SchemaProperties properties; private bool isPublished; @@ -33,49 +29,19 @@ namespace Squidex.Domain.Apps.Core.Schemas get { return isPublished; } } - public IReadOnlyList Fields + public IReadOnlyList Fields { - get { return fieldsOrdered; } + get { return fields.Ordered; } } - public IReadOnlyDictionary FieldsById + public IReadOnlyDictionary FieldsById { - get - { - if (fieldsById == null) - { - if (fieldsOrdered.Length == 0) - { - fieldsById = ImmutableDictionary.Empty; - } - else - { - fieldsById = fieldsOrdered.ToImmutableDictionary(x => x.Id); - } - } - - return fieldsById; - } + get { return fields.ById; } } - public IReadOnlyDictionary FieldsByName + public IReadOnlyDictionary FieldsByName { - get - { - if (fieldsByName == null) - { - if (fieldsOrdered.Length == 0) - { - fieldsByName = ImmutableDictionary.Empty; - } - else - { - fieldsByName = fieldsOrdered.ToImmutableDictionary(x => x.Name); - } - } - - return fieldsByName; - } + get { return fields.ByName; } } public SchemaProperties Properties @@ -93,21 +59,14 @@ namespace Squidex.Domain.Apps.Core.Schemas this.properties.Freeze(); } - public Schema(string name, Field[] fields, SchemaProperties properties, bool isPublished) + public Schema(string name, RootField[] fields, SchemaProperties properties, bool isPublished) : this(name, properties) { - Guard.NotNullOrEmpty(name, nameof(name)); Guard.NotNull(fields, nameof(fields)); - this.isPublished = isPublished; - - fieldsOrdered = ImmutableArray.Create(fields); - } + this.fields = new FieldCollection(fields); - protected override void OnCloned() - { - fieldsById = null; - fieldsByName = null; + this.isPublished = isPublished; } [Pure] @@ -122,60 +81,6 @@ namespace Squidex.Domain.Apps.Core.Schemas }); } - [Pure] - public Schema UpdateField(long fieldId, FieldProperties newProperties) - { - return UpdateField(fieldId, field => - { - return field.Update(newProperties); - }); - } - - [Pure] - public Schema LockField(long fieldId) - { - return UpdateField(fieldId, field => - { - return field.Lock(); - }); - } - - [Pure] - public Schema DisableField(long fieldId) - { - return UpdateField(fieldId, field => - { - return field.Disable(); - }); - } - - [Pure] - public Schema EnableField(long fieldId) - { - return UpdateField(fieldId, field => - { - return field.Enable(); - }); - } - - [Pure] - public Schema HideField(long fieldId) - { - return UpdateField(fieldId, field => - { - return field.Hide(); - }); - } - - [Pure] - public Schema ShowField(long fieldId) - { - return UpdateField(fieldId, field => - { - return field.Show(); - }); - } - [Pure] public Schema Publish() { @@ -197,62 +102,39 @@ namespace Squidex.Domain.Apps.Core.Schemas [Pure] public Schema DeleteField(long fieldId) { - if (!FieldsById.TryGetValue(fieldId, out var field)) - { - return this; - } - - return Clone(clone => - { - clone.fieldsOrdered = fieldsOrdered.Remove(field); - }); + return Updatefields(f => f.Remove(fieldId)); } [Pure] public Schema ReorderFields(List ids) { - Guard.NotNull(ids, nameof(ids)); - - if (ids.Count != fieldsOrdered.Length || ids.Any(x => !FieldsById.ContainsKey(x))) - { - throw new ArgumentException("Ids must cover all fields.", nameof(ids)); - } - - return Clone(clone => - { - clone.fieldsOrdered = fieldsOrdered.OrderBy(f => ids.IndexOf(f.Id)).ToImmutableArray(); - }); + return Updatefields(f => f.Reorder(ids)); } [Pure] - public Schema AddField(Field field) + public Schema AddField(RootField field) { - Guard.NotNull(field, nameof(field)); - - if (FieldsByName.ContainsKey(field.Name) || FieldsById.ContainsKey(field.Id)) - { - throw new ArgumentException($"A field with name '{field.Name}' and id {field.Id} already exists.", nameof(field)); - } - - return Clone(clone => - { - clone.fieldsOrdered = clone.fieldsOrdered.Add(field); - }); + return Updatefields(f => f.Add(field)); } [Pure] - public Schema UpdateField(long fieldId, Func updater) + public Schema UpdateField(long fieldId, Func updater) + { + return Updatefields(f => f.Update(fieldId, updater)); + } + + private Schema Updatefields(Func, FieldCollection> updater) { - Guard.NotNull(updater, nameof(updater)); + var newFields = updater(fields); - if (!FieldsById.TryGetValue(fieldId, out var field)) + if (ReferenceEquals(newFields, fields)) { return this; } return Clone(clone => { - clone.fieldsOrdered = clone.fieldsOrdered.Replace(field, updater(field)); + clone.fields = newFields; }); } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/StringFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/StringFieldProperties.cs index 288e36bf5..e9731480d 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/StringFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/StringFieldProperties.cs @@ -39,9 +39,14 @@ namespace Squidex.Domain.Apps.Core.Schemas return visitor.Visit((IField)field); } - public override Field CreateField(long id, string name, Partitioning partitioning) + public override RootField CreateRootField(long id, string name, Partitioning partitioning) { - return new Field(id, name, partitioning, this); + return Fields.String(id, name, partitioning, this); + } + + public override NestedField CreateNestedField(long id, string name) + { + return Fields.String(id, name, this); } } } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/TagsFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/TagsFieldProperties.cs index 61f3298a2..31da100e6 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/TagsFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/TagsFieldProperties.cs @@ -26,9 +26,14 @@ namespace Squidex.Domain.Apps.Core.Schemas return visitor.Visit((IField)field); } - public override Field CreateField(long id, string name, Partitioning partitioning) + public override RootField CreateRootField(long id, string name, Partitioning partitioning) { - return new Field(id, name, partitioning, this); + return Fields.Tags(id, name, partitioning, this); + } + + public override NestedField CreateNestedField(long id, string name) + { + return Fields.Tags(id, name, this); } } } diff --git a/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs b/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs index e450d470d..1480a807f 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.ConvertContent { - public delegate ContentFieldData FieldConverter(ContentFieldData data, Field field); + public delegate ContentFieldData FieldConverter(ContentFieldData data, IRootField field); public static class ContentConverter { @@ -111,7 +111,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent return result; } - private static ContentFieldData Convert(ContentFieldData fieldData, Field field, FieldConverter[] converters) + private static ContentFieldData Convert(ContentFieldData fieldData, IRootField field, FieldConverter[] converters) { if (converters != null) { diff --git a/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs b/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs index 678842c37..69ee24968 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs @@ -77,7 +77,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent return new ObjectValidator(fieldsValidators, isPartial, "field", DefaultFieldData, Formatter.CombineForLanguage); } - private IValidator CreateFieldValidator(Field field, bool isPartial) + private IValidator CreateFieldValidator(IRootField field, bool isPartial) { var partitioning = partitionResolver(field.Partitioning); diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchemaField.cs b/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchemaField.cs index 73463a710..a2958750c 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchemaField.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchemaField.cs @@ -146,7 +146,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards } } - private static Field GetFieldOrThrow(Schema schema, long fieldId) + private static IRootField GetFieldOrThrow(Schema schema, long fieldId) { if (!schema.FieldsById.TryGetValue(fieldId, out var field)) { diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs b/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs index 256d42673..6d4f0847f 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs @@ -88,7 +88,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State Partitioning.Language : Partitioning.Invariant; - var field = registry.CreateField(TotalFields, eventField.Name, partitioning, eventField.Properties); + var field = registry.CreateRootField(TotalFields, eventField.Name, partitioning, eventField.Properties); if (eventField.IsHidden) { @@ -121,7 +121,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State Partitioning.Language : Partitioning.Invariant; - var field = registry.CreateField(@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); @@ -156,32 +156,32 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State protected void On(FieldUpdated @event, FieldRegistry registry) { - SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, @event.Properties); + SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Update(@event.Properties)); } protected void On(FieldLocked @event, FieldRegistry registry) { - SchemaDef = SchemaDef.LockField(@event.FieldId.Id); + SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Lock()); } protected void On(FieldDisabled @event, FieldRegistry registry) { - SchemaDef = SchemaDef.DisableField(@event.FieldId.Id); + SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Disable()); } protected void On(FieldEnabled @event, FieldRegistry registry) { - SchemaDef = SchemaDef.EnableField(@event.FieldId.Id); + SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Enable()); } protected void On(FieldHidden @event, FieldRegistry registry) { - SchemaDef = SchemaDef.HideField(@event.FieldId.Id); + SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Hide()); } protected void On(FieldShown @event, FieldRegistry registry) { - SchemaDef = SchemaDef.ShowField(@event.FieldId.Id); + SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, f => f.Show()); } protected void On(FieldDeleted @event, FieldRegistry registry) diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/FieldRegistryTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/FieldRegistryTests.cs index 95a56d739..597b54f8d 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/FieldRegistryTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/FieldRegistryTests.cs @@ -28,7 +28,12 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas return default(T); } - public override Field CreateField(long id, string name, Partitioning partitioning) + public override RootField CreateRootField(long id, string name, Partitioning partitioning) + { + return null; + } + + public override NestedField CreateNestedField(long id, string name) { return null; } @@ -37,7 +42,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas [Fact] public void Should_throw_exception_if_creating_field_and_field_is_not_registered() { - Assert.Throws(() => sut.CreateField(1, "name", Partitioning.Invariant, new InvalidProperties())); + Assert.Throws(() => sut.CreateRootField(1, "name", Partitioning.Invariant, new InvalidProperties())); } [Theory] @@ -54,7 +59,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas { var properties = (FieldProperties)Activator.CreateInstance(propertyType); - var field = sut.CreateField(1, "name", Partitioning.Invariant, properties); + var field = sut.CreateRootField(1, "name", Partitioning.Invariant, properties); Assert.Equal(properties, field.RawProperties); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaFieldTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaFieldTests.cs index 2878a87e0..b27784278 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaFieldTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaFieldTests.cs @@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas .Select(x => new object[] { x }) .ToList(); - private readonly Field field_0 = Fields.Number(1, "my-field", Partitioning.Invariant); + private readonly RootField field_0 = Fields.Number(1, "my-field", Partitioning.Invariant); [Fact] public void Should_instantiate_field() diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs index cd267b57e..bcee356da 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs @@ -78,8 +78,8 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas { var schema_1 = schema_0.AddField(CreateField(1)); - var schema_2 = schema_1.HideField(1); - var schema_3 = schema_2.HideField(1); + var schema_2 = schema_1.UpdateField(1, f => f.Hide()); + var schema_3 = schema_2.UpdateField(1, f => f.Hide()); Assert.False(schema_1.FieldsById[1].IsHidden); Assert.True(schema_3.FieldsById[1].IsHidden); @@ -88,7 +88,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas [Fact] public void Should_return_same_schema_if_field_to_hide_does_not_exist() { - var schema_1 = schema_0.HideField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Hide()); ; Assert.Same(schema_0, schema_1); } @@ -98,9 +98,9 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas { var schema_1 = schema_0.AddField(CreateField(1)); - var schema_2 = schema_1.HideField(1); - var schema_3 = schema_2.ShowField(1); - var schema_4 = schema_3.ShowField(1); + var schema_2 = schema_1.UpdateField(1, f => f.Hide()); + var schema_3 = schema_2.UpdateField(1, f => f.Show()); + var schema_4 = schema_3.UpdateField(1, f => f.Show()); Assert.True(schema_2.FieldsById[1].IsHidden); Assert.False(schema_4.FieldsById[1].IsHidden); @@ -109,7 +109,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas [Fact] public void Should_return_same_schema_if_field_to_show_does_not_exist() { - var schema_1 = schema_0.ShowField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Show()); Assert.Same(schema_0, schema_1); } @@ -119,8 +119,8 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas { var schema_1 = schema_0.AddField(CreateField(1)); - var schema_2 = schema_1.DisableField(1); - var schema_3 = schema_2.DisableField(1); + var schema_2 = schema_1.UpdateField(1, f => f.Disable()); + var schema_3 = schema_2.UpdateField(1, f => f.Disable()); Assert.False(schema_1.FieldsById[1].IsDisabled); Assert.True(schema_3.FieldsById[1].IsDisabled); @@ -129,7 +129,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas [Fact] public void Should_return_same_schema_if_field_to_disable_does_not_exist() { - var schema_1 = schema_0.DisableField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Disable()); Assert.Same(schema_0, schema_1); } @@ -139,9 +139,9 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas { var schema_1 = schema_0.AddField(CreateField(1)); - var schema_2 = schema_1.DisableField(1); - var schema_3 = schema_2.EnableField(1); - var schema_4 = schema_3.EnableField(1); + var schema_2 = schema_1.UpdateField(1, f => f.Disable()); + var schema_3 = schema_2.UpdateField(1, f => f.Enable()); + var schema_4 = schema_3.UpdateField(1, f => f.Enable()); Assert.True(schema_2.FieldsById[1].IsDisabled); Assert.False(schema_4.FieldsById[1].IsDisabled); @@ -150,7 +150,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas [Fact] public void Should_return_same_schema_if_field_to_enable_does_not_exist() { - var schema_1 = schema_0.EnableField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Enable()); Assert.Same(schema_0, schema_1); } @@ -160,8 +160,8 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas { var schema_1 = schema_0.AddField(CreateField(1)); - var schema_2 = schema_1.LockField(1); - var schema_3 = schema_2.LockField(1); + var schema_2 = schema_1.UpdateField(1, f => f.Lock()); + var schema_3 = schema_2.UpdateField(1, f => f.Lock()); Assert.False(schema_1.FieldsById[1].IsLocked); Assert.True(schema_3.FieldsById[1].IsLocked); @@ -170,7 +170,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas [Fact] public void Should_return_same_schema_if_field_to_lock_does_not_exist() { - var schema_1 = schema_0.LockField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Lock()); Assert.Same(schema_0, schema_1); } @@ -181,7 +181,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas var properties = new NumberFieldProperties(); var schema_1 = schema_0.AddField(CreateField(1)); - var schema_2 = schema_1.UpdateField(1, properties); + var schema_2 = schema_1.UpdateField(1, f => f.Update(properties)); Assert.NotSame(properties, schema_1.FieldsById[1].RawProperties); Assert.Same(properties, schema_2.FieldsById[1].RawProperties); @@ -192,13 +192,13 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas { var schema_1 = schema_0.AddField(CreateField(1)); - Assert.Throws(() => schema_1.UpdateField(1, new StringFieldProperties())); + Assert.Throws(() => schema_1.UpdateField(1, f => f.Update(new StringFieldProperties()))); } [Fact] public void Should_return_same_schema_if_field_to_update_does_not_exist() { - var schema_1 = schema_0.UpdateField(1, new StringFieldProperties()); + var schema_1 = schema_0.UpdateField(1, f => f.Update(new StringFieldProperties())); Assert.Same(schema_0, schema_1); } @@ -251,7 +251,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas var schema_3 = schema_2.AddField(field3); var schema_4 = schema_3.ReorderFields(new List { 3, 2, 1 }); - Assert.Equal(new List { field3, field2, field1 }, schema_4.Fields.ToList()); + Assert.Equal(new List { field3, field2, field1 }, schema_4.Fields.ToList()); } [Fact] @@ -287,7 +287,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas schemaTarget.ShouldBeEquivalentTo(schemaSource); } - private static Field CreateField(int id) + private static RootField CreateField(int id) { return Fields.Number(id, $"my-field-{id}", Partitioning.Invariant); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionFlatTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionFlatTests.cs index ecd72adef..6b12ded85 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionFlatTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionFlatTests.cs @@ -33,7 +33,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent .AddAssets(5, "assets1", Partitioning.Invariant) .AddAssets(6, "assets2", Partitioning.Invariant) .AddJson(4, "json", Partitioning.Language) - .HideField(3); + .UpdateField(3, f => f.Hide()); } [Fact] diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionTests.cs index c6631888c..1aea61c08 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionTests.cs @@ -26,7 +26,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent .AddAssets(5, "assets1", Partitioning.Invariant) .AddAssets(6, "assets2", Partitioning.Invariant) .AddJson(4, "json", Partitioning.Language) - .HideField(3); + .UpdateField(3, f => f.Hide()); } [Fact] diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs index 75413bf6a..0a3937dca 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs @@ -19,9 +19,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent public class FieldConvertersTests { private readonly LanguagesConfig languagesConfig = LanguagesConfig.Build(Language.EN, Language.DE); - private readonly Field stringLanguageField = Fields.String(1, "1", Partitioning.Language); - private readonly Field stringInvariantField = Fields.String(1, "1", Partitioning.Invariant); - private readonly Field numberField = Fields.Number(1, "1", Partitioning.Invariant); + private readonly RootField stringLanguageField = Fields.String(1, "1", Partitioning.Language); + private readonly RootField stringInvariantField = Fields.String(1, "1", Partitioning.Invariant); + private readonly RootField numberField = Fields.Number(1, "1", Partitioning.Invariant); [Fact] public void Should_encode_json_values() diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs index 43d2c5522..032431e77 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs @@ -37,7 +37,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds .AddAssets(5, "assets1", Partitioning.Invariant) .AddAssets(6, "assets2", Partitioning.Invariant) .AddJson(4, "json", Partitioning.Language) - .HideField(3); + .UpdateField(3, f => f.Hide()); } [Fact] diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs index 99527b079..bea569525 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs @@ -268,7 +268,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return ids == null ? JValue.CreateNull() : (JToken)new JArray(ids.OfType().ToArray()); } - private static Field Field(AssetsFieldProperties properties) + private static RootField Field(AssetsFieldProperties properties) { return Fields.Assets(1, "my-assets", Partitioning.Invariant, properties); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/BooleanFieldTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/BooleanFieldTests.cs index b5c110e06..2c63b643b 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/BooleanFieldTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/BooleanFieldTests.cs @@ -73,7 +73,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return new JValue(v); } - private static Field Field(BooleanFieldProperties properties) + private static RootField Field(BooleanFieldProperties properties) { return Fields.Boolean(1, "my-boolean", Partitioning.Invariant, properties); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/DateTimeFieldTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/DateTimeFieldTests.cs index 47e037228..7950209ea 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/DateTimeFieldTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/DateTimeFieldTests.cs @@ -103,7 +103,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return v is Instant ? new JValue(v.ToString()) : new JValue(v); } - private static Field Field(DateTimeFieldProperties properties) + private static RootField Field(DateTimeFieldProperties properties) { return Fields.DateTime(1, "my-datetime", Partitioning.Invariant, properties); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs index e9093cc30..65ad9140b 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs @@ -112,7 +112,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return v; } - private static Field Field(GeolocationFieldProperties properties) + private static RootField Field(GeolocationFieldProperties properties) { return Fields.Geolocation(1, "my-geolocation", Partitioning.Invariant, properties); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/JsonFieldTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/JsonFieldTests.cs index ca5a40c6d..7e2844cb2 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/JsonFieldTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/JsonFieldTests.cs @@ -52,7 +52,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return v; } - private static Field Field(JsonFieldProperties properties) + private static RootField Field(JsonFieldProperties properties) { return Fields.Json(1, "my-json", Partitioning.Invariant, properties); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/NumberFieldTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/NumberFieldTests.cs index 0312149b9..d62b93f05 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/NumberFieldTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/NumberFieldTests.cs @@ -97,7 +97,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return new JValue(v); } - private static Field Field(NumberFieldProperties properties) + private static RootField Field(NumberFieldProperties properties) { return Fields.Number(1, "my-number", Partitioning.Invariant, properties); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs index f4c56fbc8..9f43a92ed 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs @@ -124,7 +124,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return ids == null ? JValue.CreateNull() : (JToken)new JArray(ids.OfType().ToArray()); } - private static Field Field(ReferencesFieldProperties properties) + private static RootField Field(ReferencesFieldProperties properties) { return Fields.References(1, "my-refs", Partitioning.Invariant, properties); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/StringFieldTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/StringFieldTests.cs index 818384a5b..0f4329e43 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/StringFieldTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/StringFieldTests.cs @@ -108,7 +108,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return new JValue(v); } - private static Field Field(StringFieldProperties properties) + private static RootField Field(StringFieldProperties properties) { return Fields.String(1, "my-string", Partitioning.Invariant, properties); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/TagsFieldTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/TagsFieldTests.cs index 3ea8b8138..132c41ca8 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/TagsFieldTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/TagsFieldTests.cs @@ -110,7 +110,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return ids == null ? JValue.CreateNull() : (JToken)new JArray(ids.OfType().ToArray()); } - private static Field Field(TagsFieldProperties properties) + private static RootField Field(TagsFieldProperties properties) { return Fields.Tags(1, "my-tags", Partitioning.Invariant, properties); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/TestData.cs b/tests/Squidex.Domain.Apps.Core.Tests/TestData.cs index 3fc8ed13c..054969ca5 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/TestData.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/TestData.cs @@ -94,9 +94,9 @@ namespace Squidex.Domain.Apps.Core schema = schema.AddTags(11, "my-tags", Partitioning.Language, new TagsFieldProperties()); - schema = schema.HideField(7); - schema = schema.LockField(8); - schema = schema.DisableField(9); + schema = schema.UpdateField(7, f => f.Hide()); + schema = schema.UpdateField(8, f => f.Lock()); + schema = schema.UpdateField(9, f => f.Disable()); return schema; } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaFieldTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaFieldTests.cs index 2b2511a54..d85be5c73 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaFieldTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaFieldTests.cs @@ -34,7 +34,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { var command = new HideField { FieldId = 1 }; - var schema_1 = schema_0.HideField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Hide()); Assert.Throws(() => GuardSchemaField.CanHide(schema_1, command)); } @@ -60,7 +60,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { var command = new DisableField { FieldId = 1 }; - var schema_1 = schema_0.DisableField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Disable()); Assert.Throws(() => GuardSchemaField.CanDisable(schema_1, command)); } @@ -102,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { var command = new ShowField { FieldId = 1 }; - var schema_1 = schema_0.HideField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Hide()); ; GuardSchemaField.CanShow(schema_1, command); } @@ -128,7 +128,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { var command = new EnableField { FieldId = 1 }; - var schema_1 = schema_0.DisableField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Disable()); GuardSchemaField.CanEnable(schema_1, command); } @@ -138,7 +138,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { var command = new LockField { FieldId = 1 }; - var schema_1 = schema_0.LockField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Lock()); Assert.Throws(() => GuardSchemaField.CanLock(schema_1, command)); } @@ -172,7 +172,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { var command = new DeleteField { FieldId = 1 }; - var schema_1 = schema_0.LockField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Lock()); Assert.Throws(() => GuardSchemaField.CanDelete(schema_1, command)); } @@ -190,7 +190,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards { var command = new UpdateField { FieldId = 1, Properties = new StringFieldProperties() }; - var schema_1 = schema_0.LockField(1); + var schema_1 = schema_0.UpdateField(1, f => f.Lock()); Assert.Throws(() => GuardSchemaField.CanUpdate(schema_1, command)); }