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.
174 lines
4.9 KiB
174 lines
4.9 KiB
// ==========================================================================
|
|
// 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.Diagnostics.Contracts;
|
|
using System.Linq;
|
|
using Squidex.Infrastructure;
|
|
|
|
namespace Squidex.Domain.Apps.Core.Schemas
|
|
{
|
|
public sealed class FieldCollection<T> : Cloneable<FieldCollection<T>> where T : IField
|
|
{
|
|
public static readonly FieldCollection<T> Empty = new FieldCollection<T>();
|
|
|
|
private static readonly Dictionary<long, T> EmptyById = new Dictionary<long, T>();
|
|
private static readonly Dictionary<string, T> EmptyByString = new Dictionary<string, T>();
|
|
|
|
private T[] fieldsOrdered;
|
|
private Dictionary<long, T>? fieldsById;
|
|
private Dictionary<string, T>? fieldsByName;
|
|
|
|
public IReadOnlyList<T> Ordered
|
|
{
|
|
get => fieldsOrdered;
|
|
}
|
|
|
|
public IReadOnlyDictionary<long, T> ById
|
|
{
|
|
get
|
|
{
|
|
if (fieldsById == null)
|
|
{
|
|
if (fieldsOrdered.Length == 0)
|
|
{
|
|
fieldsById = EmptyById;
|
|
}
|
|
else
|
|
{
|
|
fieldsById = fieldsOrdered.ToDictionary(x => x.Id);
|
|
}
|
|
}
|
|
|
|
return fieldsById;
|
|
}
|
|
}
|
|
|
|
public IReadOnlyDictionary<string, T> ByName
|
|
{
|
|
get
|
|
{
|
|
if (fieldsByName == null)
|
|
{
|
|
if (fieldsOrdered.Length == 0)
|
|
{
|
|
fieldsByName = EmptyByString;
|
|
}
|
|
else
|
|
{
|
|
fieldsByName = fieldsOrdered.ToDictionary(x => x.Name);
|
|
}
|
|
}
|
|
|
|
return fieldsByName;
|
|
}
|
|
}
|
|
|
|
private FieldCollection()
|
|
{
|
|
fieldsOrdered = Array.Empty<T>();
|
|
}
|
|
|
|
public FieldCollection(T[] fields)
|
|
{
|
|
Guard.NotNull(fields, nameof(fields));
|
|
|
|
fieldsOrdered = fields;
|
|
}
|
|
|
|
protected override void OnCloned()
|
|
{
|
|
fieldsById = null;
|
|
fieldsByName = null;
|
|
}
|
|
|
|
[Pure]
|
|
public FieldCollection<T> Remove(long fieldId)
|
|
{
|
|
if (!ById.TryGetValue(fieldId, out _))
|
|
{
|
|
return this;
|
|
}
|
|
|
|
return Clone(clone =>
|
|
{
|
|
clone.fieldsOrdered = fieldsOrdered.Where(x => x.Id != fieldId).ToArray();
|
|
});
|
|
}
|
|
|
|
[Pure]
|
|
public FieldCollection<T> Reorder(List<long> 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));
|
|
}
|
|
|
|
if (ids.SequenceEqual(fieldsOrdered.Select(x => x.Id)))
|
|
{
|
|
return this;
|
|
}
|
|
|
|
return Clone(clone =>
|
|
{
|
|
clone.fieldsOrdered = fieldsOrdered.OrderBy(f => ids.IndexOf(f.Id)).ToArray();
|
|
});
|
|
}
|
|
|
|
[Pure]
|
|
public FieldCollection<T> Add(T field)
|
|
{
|
|
Guard.NotNull(field, nameof(field));
|
|
|
|
if (ByName.ContainsKey(field.Name))
|
|
{
|
|
throw new ArgumentException($"A field with name '{field.Name}' already exists.", nameof(field));
|
|
}
|
|
|
|
if (ById.ContainsKey(field.Id))
|
|
{
|
|
throw new ArgumentException($"A field with id {field.Id} already exists.", nameof(field));
|
|
}
|
|
|
|
return Clone(clone =>
|
|
{
|
|
clone.fieldsOrdered = clone.fieldsOrdered.Union(Enumerable.Repeat(field, 1)).ToArray();
|
|
});
|
|
}
|
|
|
|
[Pure]
|
|
public FieldCollection<T> Update(long fieldId, Func<T, T> 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 not T)
|
|
{
|
|
throw new InvalidOperationException($"Field must be of type {typeof(T)}");
|
|
}
|
|
|
|
return Clone(clone =>
|
|
{
|
|
clone.fieldsOrdered = clone.fieldsOrdered.Select(x => ReferenceEquals(x, field) ? newField : x).ToArray();
|
|
});
|
|
}
|
|
}
|
|
}
|