mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
7.3 KiB
239 lines
7.3 KiB
// ==========================================================================
|
|
// Schema.cs
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex Group
|
|
// All rights reserved.
|
|
// ==========================================================================
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using Microsoft.OData.Edm;
|
|
using NJsonSchema;
|
|
using Squidex.Infrastructure;
|
|
|
|
// ReSharper disable ConvertIfStatementToConditionalTernaryExpression
|
|
// ReSharper disable InvertIf
|
|
|
|
namespace Squidex.Domain.Apps.Core.Schemas
|
|
{
|
|
public sealed class Schema : CloneableBase
|
|
{
|
|
private readonly string name;
|
|
private readonly SchemaProperties properties;
|
|
private readonly ImmutableList<Field> fields;
|
|
private readonly ImmutableDictionary<long, Field> fieldsById;
|
|
private readonly ImmutableDictionary<string, Field> fieldsByName;
|
|
private readonly bool isPublished;
|
|
|
|
public string Name
|
|
{
|
|
get { return name; }
|
|
}
|
|
|
|
public bool IsPublished
|
|
{
|
|
get { return isPublished; }
|
|
}
|
|
|
|
public ImmutableList<Field> Fields
|
|
{
|
|
get { return fields; }
|
|
}
|
|
|
|
public ImmutableDictionary<long, Field> FieldsById
|
|
{
|
|
get { return fieldsById; }
|
|
}
|
|
|
|
public ImmutableDictionary<string, Field> FieldsByName
|
|
{
|
|
get { return fieldsByName; }
|
|
}
|
|
|
|
public SchemaProperties Properties
|
|
{
|
|
get { return properties; }
|
|
}
|
|
|
|
public Schema(string name, bool isPublished, SchemaProperties properties, ImmutableList<Field> fields)
|
|
{
|
|
Guard.NotNull(fields, nameof(fields));
|
|
Guard.NotNull(properties, nameof(properties));
|
|
Guard.ValidSlug(name, nameof(name));
|
|
|
|
fieldsById = fields.ToImmutableDictionary(x => x.Id);
|
|
fieldsByName = fields.ToImmutableDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase);
|
|
|
|
this.name = name;
|
|
|
|
this.fields = fields;
|
|
|
|
this.properties = properties;
|
|
this.properties.Freeze();
|
|
|
|
this.isPublished = isPublished;
|
|
}
|
|
|
|
public static Schema Create(string name, SchemaProperties newProperties)
|
|
{
|
|
if (!name.IsSlug())
|
|
{
|
|
var error = new ValidationError("Name must be a valid slug", "Name");
|
|
|
|
throw new ValidationException("Cannot create a new schema", error);
|
|
}
|
|
|
|
return new Schema(name, false, newProperties, ImmutableList<Field>.Empty);
|
|
}
|
|
|
|
public Schema Update(SchemaProperties newProperties)
|
|
{
|
|
Guard.NotNull(newProperties, nameof(newProperties));
|
|
|
|
return new Schema(name, isPublished, newProperties, fields);
|
|
}
|
|
|
|
public Schema UpdateField(long fieldId, FieldProperties newProperties)
|
|
{
|
|
return UpdateField(fieldId, field => field.Update(newProperties));
|
|
}
|
|
|
|
public Schema DisableField(long fieldId)
|
|
{
|
|
return UpdateField(fieldId, field => field.Disable());
|
|
}
|
|
|
|
public Schema EnableField(long fieldId)
|
|
{
|
|
return UpdateField(fieldId, field => field.Enable());
|
|
}
|
|
|
|
public Schema HideField(long fieldId)
|
|
{
|
|
return UpdateField(fieldId, field => field.Hide());
|
|
}
|
|
|
|
public Schema ShowField(long fieldId)
|
|
{
|
|
return UpdateField(fieldId, field => field.Show());
|
|
}
|
|
|
|
public Schema RenameField(long fieldId, string newName)
|
|
{
|
|
return UpdateField(fieldId, field => field.Rename(newName));
|
|
}
|
|
|
|
public Schema DeleteField(long fieldId)
|
|
{
|
|
return new Schema(name, isPublished, properties, fields.Where(x => x.Id != fieldId).ToImmutableList());
|
|
}
|
|
|
|
public Schema Publish()
|
|
{
|
|
if (isPublished)
|
|
{
|
|
throw new DomainException("Schema is already published");
|
|
}
|
|
|
|
return new Schema(name, true, properties, fields);
|
|
}
|
|
|
|
public Schema Unpublish()
|
|
{
|
|
if (!isPublished)
|
|
{
|
|
throw new DomainException("Schema is not published");
|
|
}
|
|
|
|
return new Schema(name, false, properties, fields);
|
|
}
|
|
|
|
public Schema ReorderFields(List<long> ids)
|
|
{
|
|
Guard.NotNull(ids, nameof(ids));
|
|
|
|
if (ids.Count != fields.Count || ids.Any(x => !fieldsById.ContainsKey(x)))
|
|
{
|
|
throw new ArgumentException("Ids must cover all fields.", nameof(ids));
|
|
}
|
|
|
|
var newFields = fields.OrderBy(f => ids.IndexOf(f.Id)).ToImmutableList();
|
|
|
|
return new Schema(name, isPublished, properties, newFields);
|
|
}
|
|
|
|
public Schema UpdateField(long fieldId, Func<Field, Field> updater)
|
|
{
|
|
Guard.NotNull(updater, nameof(updater));
|
|
|
|
if (!fieldsById.TryGetValue(fieldId, out Field field))
|
|
{
|
|
throw new DomainObjectNotFoundException(fieldId.ToString(), "Fields", typeof(Field));
|
|
}
|
|
|
|
var newField = updater(field);
|
|
|
|
return AddOrUpdateField(newField);
|
|
}
|
|
|
|
public Schema AddOrUpdateField(Field field)
|
|
{
|
|
Guard.NotNull(field, nameof(field));
|
|
|
|
if (fieldsById.Values.Any(f => f.Name == field.Name && f.Id != field.Id))
|
|
{
|
|
throw new ValidationException($"A field with name '{field.Name}' already exists.");
|
|
}
|
|
|
|
ImmutableList<Field> newFields;
|
|
|
|
if (fieldsById.ContainsKey(field.Id))
|
|
{
|
|
newFields = fields.Select(f => f.Id == field.Id ? field : f).ToImmutableList();
|
|
}
|
|
else
|
|
{
|
|
newFields = fields.Add(field);
|
|
}
|
|
|
|
return new Schema(name, isPublished, properties, newFields);
|
|
}
|
|
|
|
public EdmComplexType BuildEdmType(PartitionResolver partitionResolver, Func<EdmComplexType, EdmComplexType> typeResolver)
|
|
{
|
|
Guard.NotNull(typeResolver, nameof(typeResolver));
|
|
Guard.NotNull(partitionResolver, nameof(partitionResolver));
|
|
|
|
var schemaName = Name.ToPascalCase();
|
|
|
|
var edmType = new EdmComplexType("Squidex", schemaName);
|
|
|
|
foreach (var field in fieldsByName.Values.Where(x => !x.IsHidden))
|
|
{
|
|
field.AddToEdmType(edmType, partitionResolver, schemaName, typeResolver);
|
|
}
|
|
|
|
return edmType;
|
|
}
|
|
|
|
public JsonSchema4 BuildJsonSchema(PartitionResolver partitionResolver, Func<string, JsonSchema4, JsonSchema4> schemaResolver)
|
|
{
|
|
Guard.NotNull(schemaResolver, nameof(schemaResolver));
|
|
Guard.NotNull(partitionResolver, nameof(partitionResolver));
|
|
|
|
var schemaName = Name.ToPascalCase();
|
|
|
|
var schema = new JsonSchema4 { Type = JsonObjectType.Object };
|
|
|
|
foreach (var field in fieldsByName.Values.Where(x => !x.IsHidden))
|
|
{
|
|
field.AddToJsonSchema(schema, partitionResolver, schemaName, schemaResolver);
|
|
}
|
|
|
|
return schema;
|
|
}
|
|
}
|
|
}
|