// ========================================================================== // 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; using System.Linq; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Schemas { public sealed class Schema { private static readonly Dictionary EmptyPreviewUrls = new Dictionary(); private readonly string name; private readonly bool isSingleton; private string category; private FieldNames fieldsInLists = FieldNames.Empty; private FieldNames fieldsInReferences = FieldNames.Empty; private FieldRules fieldRules = FieldRules.Empty; private FieldCollection fields = FieldCollection.Empty; private IReadOnlyDictionary previewUrls = EmptyPreviewUrls; private SchemaScripts scripts = SchemaScripts.Empty; private SchemaProperties properties; private bool isPublished; public string Name { get => name; } public string Category { get => category; } public bool IsPublished { get => isPublished; } public bool IsSingleton { get => isSingleton; } public IReadOnlyList Fields { get => fields.Ordered; } public IReadOnlyDictionary FieldsById { get => fields.ById; } public IReadOnlyDictionary FieldsByName { get => fields.ByName; } public IReadOnlyDictionary PreviewUrls { get => previewUrls; } public FieldCollection FieldCollection { get => fields; } public FieldRules FieldRules { get => fieldRules; } public FieldNames FieldsInLists { get => fieldsInLists; } public FieldNames FieldsInReferences { get => fieldsInReferences; } public SchemaScripts Scripts { get => scripts; } public SchemaProperties Properties { get => properties; } public Schema(string name, SchemaProperties? properties = null, bool isSingleton = false) { Guard.NotNullOrEmpty(name, nameof(name)); this.name = name; this.properties = properties ?? new SchemaProperties(); this.isSingleton = isSingleton; } public Schema(string name, RootField[] fields, SchemaProperties properties, bool isPublished, bool isSingleton = false) : this(name, properties, isSingleton) { Guard.NotNull(fields, nameof(fields)); this.fields = new FieldCollection(fields); this.isPublished = isPublished; } [Pure] public Schema Update(SchemaProperties newProperties) { newProperties ??= new SchemaProperties(); if (properties.Equals(newProperties)) { return this; } return Clone(clone => { clone.properties = newProperties; }); } [Pure] public Schema SetScripts(SchemaScripts newScripts) { newScripts ??= new SchemaScripts(); if (scripts.Equals(newScripts)) { return this; } return Clone(clone => { clone.scripts = newScripts; }); } [Pure] public Schema SetFieldsInLists(FieldNames names) { names ??= FieldNames.Empty; if (fieldsInLists.SequenceEqual(names)) { return this; } return Clone(clone => { clone.fieldsInLists = names; }); } [Pure] public Schema SetFieldsInLists(params string[] names) { return SetFieldsInLists(new FieldNames(names)); } [Pure] public Schema SetFieldsInReferences(FieldNames names) { names ??= FieldNames.Empty; if (fieldsInReferences.SequenceEqual(names)) { return this; } return Clone(clone => { clone.fieldsInReferences = names; }); } [Pure] public Schema SetFieldsInReferences(params string[] names) { return SetFieldsInReferences(new FieldNames(names)); } [Pure] public Schema SetFieldRules(FieldRules rules) { rules ??= FieldRules.Empty; if (fieldRules.Equals(rules)) { return this; } return Clone(clone => { clone.fieldRules = rules; }); } [Pure] public Schema SetFieldRules(params FieldRule[] rules) { return SetFieldRules(new FieldRules(rules)); } [Pure] public Schema Publish() { if (isPublished) { return this; } return Clone(clone => { clone.isPublished = true; }); } [Pure] public Schema Unpublish() { if (!isPublished) { return this; } return Clone(clone => { clone.isPublished = false; }); } [Pure] public Schema ChangeCategory(string newCategory) { if (string.Equals(category, newCategory)) { return this; } return Clone(clone => { clone.category = newCategory; }); } [Pure] public Schema SetPreviewUrls(IReadOnlyDictionary newPreviewUrls) { previewUrls ??= EmptyPreviewUrls; if (previewUrls.EqualsDictionary(newPreviewUrls)) { return this; } return Clone(clone => { clone.previewUrls = newPreviewUrls; }); } [Pure] public Schema DeleteField(long fieldId) { if (!FieldsById.TryGetValue(fieldId, out var field)) { return this; } return Clone(clone => { clone.fields = fields.Remove(fieldId); clone.fieldsInLists = fieldsInLists.Remove(field.Name); clone.fieldsInReferences = fieldsInReferences.Remove(field.Name); }); } [Pure] public Schema ReorderFields(List ids) { return UpdateFields(f => f.Reorder(ids)); } [Pure] public Schema AddField(RootField field) { return UpdateFields(f => f.Add(field)); } [Pure] public Schema UpdateField(long fieldId, Func updater) { return UpdateFields(f => f.Update(fieldId, updater)); } private Schema UpdateFields(Func, FieldCollection> updater) { var newFields = updater(fields); if (ReferenceEquals(newFields, fields)) { return this; } return Clone(clone => { clone.fields = newFields; }); } private Schema Clone(Action updater) { var clone = (Schema)MemberwiseClone(); updater(clone); return clone; } } }