From a293edb643ea9fed3fba48316ca75a336ea705b4 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Sat, 3 Jul 2021 16:05:08 +0200 Subject: [PATCH] Fixes/components (#733) * Fixes * Fix infinite loop. --- .../Schemas/FieldBase.cs | 32 +------ .../Schemas/FieldExtensions.cs | 30 +------ .../Schemas/IField.cs | 2 +- .../Schemas/IMetadataProvider.cs | 23 ----- .../Schemas/ResolvedComponents.cs | 32 +++++++ .../ConvertContent/FieldConverters.cs | 42 ++++++---- .../ConvertContent/StringFormatter.cs | 12 +-- .../DefaultValues/DefaultValueFactory.cs | 16 +--- .../ContentReferencesExtensions.cs | 30 ++++--- .../ExtractReferenceIds/ReferencesCleaner.cs | 16 +--- .../ReferencesExtractor.cs | 45 +++++----- .../GenerateEdmSchema/EdmSchemaExtensions.cs | 5 +- .../GenerateEdmSchema/EdmTypeVisitor.cs | 31 ++----- .../JsonSchemaExtensions.cs | 15 ++-- .../GenerateJsonSchema/JsonTypeVisitor.cs | 41 +++------ .../DefaultFieldValueValidatorsFactory.cs | 16 +--- .../ValidateContent/JsonValueConverter.cs | 36 ++++---- .../ValidateContent/JsonValueValidator.cs | 15 +--- .../ValidateContent/ValidationContext.cs | 4 + .../Validators/FieldValidator.cs | 4 +- .../AdaptIdVisitor.cs | 12 +-- .../MongoContentRepository_SnapshotStore.cs | 4 +- .../AppProvider.cs | 64 -------------- .../AppProviderExtensions.cs | 84 +++++++++++++++++++ .../Assets/Queries/FilterTagTransformer.cs | 16 +--- .../Guards/ValidationExtensions.cs | 1 + .../Contents/DomainObject/OperationContext.cs | 5 ++ .../Contents/GraphQL/Types/Builder.cs | 4 +- .../Types/Contents/ComponentGraphType.cs | 6 +- .../Types/Contents/ContentGraphType.cs | 4 +- .../Contents/Queries/ContentEnricher.cs | 31 ++++--- .../Contents/Queries/ContentQueryParser.cs | 57 ++++++++----- .../Contents/Queries/GeoQueryTransformer.cs | 18 +--- .../Contents/Queries/IContentEnricherStep.cs | 3 +- .../Contents/Queries/Steps/ConvertData.cs | 28 +++---- .../Queries/Steps/EnrichForCaching.cs | 2 +- .../Queries/Steps/EnrichWithSchema.cs | 2 +- .../Contents/Queries/Steps/ResolveAssets.cs | 17 ++-- .../Queries/Steps/ResolveReferences.cs | 20 ++--- .../Contents/Queries/Steps/ScriptContent.cs | 2 +- .../Queries/Json/JsonFilterVisitor.cs | 16 +--- .../Contents/ContentOpenApiController.cs | 4 +- .../Controllers/Contents/Generator/Builder.cs | 6 +- .../Generator/SchemasOpenApiGenerator.cs | 11 ++- .../Model/Schemas/SchemaTests.cs | 2 +- .../ConvertContent/ContentConversionTests.cs | 12 ++- .../ConvertContent/FieldConvertersTests.cs | 2 +- .../ReferenceExtractionTests.cs | 30 +++---- .../Operations/GenerateEdmSchema/EdmTests.cs | 3 +- .../GenerateJsonSchema/JsonSchemaTests.cs | 7 +- .../ValidateContent/ComponentFieldTests.cs | 43 +++++----- .../ValidateContent/ComponentsFieldTests.cs | 59 ++++++------- .../ValidationTestExtensions.cs | 31 ++++--- .../TestHelpers/TestUtils.cs | 8 +- .../Contents/Queries/ContentEnricherTests.cs | 18 ++-- .../Queries/ContentQueryParserTests.cs | 3 +- .../Contents/Queries/ConvertDataTests.cs | 2 +- .../Contents/Queries/EnrichForCachingTests.cs | 3 +- .../Contents/Queries/EnrichWithSchemaTests.cs | 3 +- .../Contents/Queries/ResolveAssetsTests.cs | 2 +- .../Queries/ResolveReferencesTests.cs | 6 +- .../Contents/Queries/ScriptContentTests.cs | 4 +- frontend/app/shared/state/contents.forms.ts | 2 - 63 files changed, 516 insertions(+), 588 deletions(-) delete mode 100644 backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IMetadataProvider.cs create mode 100644 backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ResolvedComponents.cs create mode 100644 backend/src/Squidex.Domain.Apps.Entities/AppProviderExtensions.cs diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldBase.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldBase.cs index 754cf734a..13b8da28b 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldBase.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldBase.cs @@ -5,25 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; -using System.Collections.Generic; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Schemas { - public abstract class FieldBase : IMetadataProvider + public abstract class FieldBase { - private Dictionary metadata; - public long Id { get; } public string Name { get; } - public IDictionary Metadata - { - get => metadata ??= new Dictionary(); - } - protected FieldBase(long id, string name) { Guard.NotNullOrEmpty(name, nameof(name)); @@ -33,26 +24,5 @@ namespace Squidex.Domain.Apps.Core.Schemas Name = name; } - - public T? GetMetadata(string key, T? defaultValue = default) - { - var local = metadata; - - return local != null && local.TryGetValue(key, out var item) ? (T)item : defaultValue; - } - - public T GetMetadata(string key, Func defaultValueFactory) - { - var local = metadata; - - return local != null && local.TryGetValue(key, out var item) ? (T)item : defaultValueFactory(); - } - - public bool HasMetadata(string key) - { - var local = metadata; - - return local?.ContainsKey(key) == true; - } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs index d9cbd7b21..f575e3a51 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs @@ -6,7 +6,6 @@ // ========================================================================== using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using Squidex.Infrastructure; using Squidex.Infrastructure.Collections; @@ -26,7 +25,7 @@ namespace Squidex.Domain.Apps.Core.Schemas return fields.Where(x => IsForApi(x, withHidden)); } - public static IEnumerable GetSharedFields(this IField field, ImmutableList? schemaIds, bool withHidden) + public static IEnumerable GetSharedFields(this ResolvedComponents components, ImmutableList? schemaIds, bool withHidden) { if (schemaIds == null || schemaIds.Count == 0) { @@ -35,7 +34,7 @@ namespace Squidex.Domain.Apps.Core.Schemas var allFields = schemaIds - .Select(x => field.GetResolvedSchema(x)).NotNull() + .Select(x => components.Get(x)).NotNull() .SelectMany(x => x.Fields.ForApi(withHidden)) .GroupBy(x => new { x.Name, Type = x.RawProperties.GetType() }).Where(x => x.Count() == 1) .Select(x => x.First()); @@ -43,31 +42,6 @@ namespace Squidex.Domain.Apps.Core.Schemas return allFields; } - public static T SetResolvedSchema(this T metadataProvider, DomainId id, Schema schema) where T : IMetadataProvider - { - var key = $"ResolvedSchema_{id}"; - - metadataProvider.Metadata[key] = schema; - - return metadataProvider; - } - - public static Schema? GetResolvedSchema(this T metadataProvider, object id) where T : IMetadataProvider - { - var key = $"ResolvedSchema_{id}"; - - return metadataProvider.GetMetadata(key); - } - - public static bool TryGetResolvedSchema(this T metadataProvider, object id, [MaybeNullWhen(false)] out Schema schema) where T : IMetadataProvider - { - var key = $"ResolvedSchema_{id}"; - - schema = metadataProvider.GetMetadata(key); - - return schema != null; - } - public static bool IsForApi(this T field, bool withHidden = false) where T : IField { return (withHidden || !field.IsHidden) && !field.RawProperties.IsUIProperty(); diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IField.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IField.cs index 9372b23a1..5428a5286 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IField.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IField.cs @@ -7,7 +7,7 @@ namespace Squidex.Domain.Apps.Core.Schemas { - public interface IField : IFieldSettings, IMetadataProvider + public interface IField : IFieldSettings { long Id { get; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IMetadataProvider.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IMetadataProvider.cs deleted file mode 100644 index 4d6f0e034..000000000 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IMetadataProvider.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using System.Collections.Generic; - -namespace Squidex.Domain.Apps.Core.Schemas -{ - public interface IMetadataProvider - { - IDictionary Metadata { get; } - - T? GetMetadata(string key, T? defaultValue = default); - - T GetMetadata(string key, Func defaultValueFactory); - - bool HasMetadata(string key); - } -} diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ResolvedComponents.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ResolvedComponents.cs new file mode 100644 index 000000000..c1706bc1e --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ResolvedComponents.cs @@ -0,0 +1,32 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Collections; + +namespace Squidex.Domain.Apps.Core.Schemas +{ + public sealed class ResolvedComponents : ImmutableDictionary + { + public static readonly ResolvedComponents Empty = new ResolvedComponents(); + + private ResolvedComponents() + { + } + + public ResolvedComponents(IDictionary inner) + : base(inner) + { + } + + public Schema? Get(DomainId schemaId) + { + return this.GetOrDefault(schemaId); + } + } +} diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs index 74ca1e282..d528202a3 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs @@ -176,7 +176,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent }; } - public static FieldConverter ForValues(params ValueConverter[] converters) + public static FieldConverter ForValues(ResolvedComponents components, params ValueConverter[] converters) { return (data, field) => { @@ -184,7 +184,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent foreach (var (key, value) in data) { - var newValue = ConvertByType(field, value, null, converters); + var newValue = ConvertByType(field, value, null, converters, components); if (newValue == null) { @@ -202,25 +202,27 @@ namespace Squidex.Domain.Apps.Core.ConvertContent }; } - private static IJsonValue? ConvertByType(T field, IJsonValue? value, IArrayField? parent, ValueConverter[] converters) where T : IField + private static IJsonValue? ConvertByType(T field, IJsonValue? value, IArrayField? parent, ValueConverter[] converters, + ResolvedComponents components) where T : IField { switch (field) { case IArrayField arrayField: - return ConvertArray(arrayField, value, converters); + return ConvertArray(arrayField, value, converters, components); case IField: - return ConvertComponent(field, value, converters); + return ConvertComponent(value, converters, components); case IField: - return ConvertComponents(field, value, converters); + return ConvertComponents(value, converters, components); default: return ConvertValue(field, value, parent, converters); } } - private static IJsonValue? ConvertArray(IArrayField field, IJsonValue? value, ValueConverter[] converters) + private static IJsonValue? ConvertArray(IArrayField field, IJsonValue? value, ValueConverter[] converters, + ResolvedComponents components) { if (value is JsonArray array) { @@ -228,7 +230,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent for (int i = 0, j = 0; i < array.Count; i++, j++) { - var newValue = ConvertArrayItem(field, array[i], converters); + var newValue = ConvertArrayItem(field, array[i], converters, components); if (newValue == null) { @@ -249,7 +251,8 @@ namespace Squidex.Domain.Apps.Core.ConvertContent return null; } - private static IJsonValue? ConvertComponents(IField field, IJsonValue? value, ValueConverter[] converters) + private static IJsonValue? ConvertComponents(IJsonValue? value, ValueConverter[] converters, + ResolvedComponents components) { if (value is JsonArray array) { @@ -257,7 +260,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent for (int i = 0, j = 0; i < array.Count; i++, j++) { - var newValue = ConvertComponent(field, array[i], converters); + var newValue = ConvertComponent(array[i], converters, components); if (newValue == null) { @@ -278,13 +281,16 @@ namespace Squidex.Domain.Apps.Core.ConvertContent return null; } - private static IJsonValue? ConvertComponent(IField field, IJsonValue? value, ValueConverter[] converters) + private static IJsonValue? ConvertComponent(IJsonValue? value, ValueConverter[] converters, + ResolvedComponents components) { if (value is JsonObject obj && obj.TryGetValue(Component.Discriminator, out var type)) { - if (field.TryGetResolvedSchema(type.Value, out var schema)) + var id = DomainId.Create(type.Value); + + if (components.TryGetValue(id, out var schema)) { - return ConvertNested(schema.FieldCollection, obj, null, converters); + return ConvertNested(schema.FieldCollection, obj, null, converters, components); } else { @@ -295,17 +301,19 @@ namespace Squidex.Domain.Apps.Core.ConvertContent return null; } - private static IJsonValue? ConvertArrayItem(IArrayField field, IJsonValue? value, ValueConverter[] converters) + private static IJsonValue? ConvertArrayItem(IArrayField field, IJsonValue? value, ValueConverter[] converters, + ResolvedComponents components) { if (value is JsonObject obj) { - return ConvertNested(field.FieldCollection, obj, field, converters); + return ConvertNested(field.FieldCollection, obj, field, converters, components); } return null; } - private static IJsonValue ConvertNested(FieldCollection fields, JsonObject source, IArrayField? parent, ValueConverter[] converters) where T : IField + private static IJsonValue ConvertNested(FieldCollection fields, JsonObject source, IArrayField? parent, ValueConverter[] converters, + ResolvedComponents components) where T : IField { JsonObject? result = null; @@ -315,7 +323,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent if (fields.ByName.TryGetValue(key, out var field)) { - newValue = ConvertByType(field, value, parent, converters); + newValue = ConvertByType(field, value, parent, converters, components); } else if (key != Component.Discriminator) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/StringFormatter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/StringFormatter.cs index fcab56a46..785b9a7b3 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/StringFormatter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/StringFormatter.cs @@ -9,21 +9,15 @@ using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Core.ConvertContent { public sealed class StringFormatter : IFieldPropertiesVisitor { private static readonly StringFormatter Instance = new StringFormatter(); - public readonly struct Args - { - public readonly IJsonValue Value; - - public Args(IJsonValue value) - { - Value = value; - } - } + public sealed record Args(IJsonValue Value); private StringFormatter() { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueFactory.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueFactory.cs index b1351c5b6..d87b77bc6 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueFactory.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueFactory.cs @@ -12,25 +12,15 @@ using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Core.DefaultValues { public sealed class DefaultValueFactory : IFieldPropertiesVisitor { private static readonly DefaultValueFactory Instance = new DefaultValueFactory(); - public readonly struct Args - { - public readonly Instant Now; - - public readonly string Partition; - - public Args(Instant now, string partition) - { - Now = now; - - Partition = partition; - } - } + public sealed record Args(Instant Now, string Partition); private DefaultValueFactory() { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs index a6c28a05c..3cff3719c 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs @@ -16,53 +16,63 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { public static class ContentReferencesExtensions { - public static HashSet GetReferencedIds(this ContentData source, Schema schema, int referencesPerField = int.MaxValue) + public static HashSet GetReferencedIds(this ContentData source, Schema schema, + ResolvedComponents components, int referencesPerField = int.MaxValue) { Guard.NotNull(schema, nameof(schema)); var ids = new HashSet(); - AddReferencedIds(source, schema, ids, referencesPerField); + AddReferencedIds(source, schema, ids, components, referencesPerField); return ids; } - public static void AddReferencedIds(this ContentData source, Schema schema, HashSet result, int referencesPerField = int.MaxValue) + public static void AddReferencedIds(this ContentData source, Schema schema, HashSet result, + ResolvedComponents components, int referencesPerField = int.MaxValue) { Guard.NotNull(schema, nameof(schema)); - AddReferencedIds(source, schema.Fields, result, referencesPerField); + AddReferencedIds(source, schema.Fields, result, components, referencesPerField); } - public static void AddReferencedIds(this ContentData source, IEnumerable fields, HashSet result, int referencesPerField = int.MaxValue) + public static void AddReferencedIds(this ContentData source, IEnumerable fields, HashSet result, + ResolvedComponents components, int referencesPerField = int.MaxValue) { Guard.NotNull(fields, nameof(fields)); Guard.NotNull(result, nameof(result)); + Guard.NotNull(components, nameof(components)); foreach (var field in fields) { - AddReferencedIds(source, result, referencesPerField, field); + AddReferencedIds(field, source, result, components, referencesPerField); } } - private static void AddReferencedIds(ContentData source, HashSet result, int referencesPerField, IField field) + private static void AddReferencedIds(IField field, ContentData source, HashSet result, + ResolvedComponents components, int referencesPerField = int.MaxValue) { + Guard.NotNull(components, nameof(components)); + if (source.TryGetValue(field.Name, out var fieldData) && fieldData != null) { foreach (var partitionValue in fieldData) { - ReferencesExtractor.Extract(field, partitionValue.Value, result, referencesPerField); + ReferencesExtractor.Extract(field, partitionValue.Value, result, referencesPerField, components); } } } - public static HashSet GetReferencedIds(this IField field, IJsonValue? value, int referencesPerField = int.MaxValue) + public static HashSet GetReferencedIds(this IField field, IJsonValue? value, + ResolvedComponents components, int referencesPerField = int.MaxValue) { + Guard.NotNull(components, nameof(components)); + var result = new HashSet(); if (value != null) { - ReferencesExtractor.Extract(field, value, result, referencesPerField); + ReferencesExtractor.Extract(field, value, result, referencesPerField, components); } return result; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs index 02404c39e..10bc6e510 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs @@ -10,25 +10,15 @@ using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { internal sealed class ReferencesCleaner : IFieldVisitor { private static readonly ReferencesCleaner Instance = new ReferencesCleaner(); - public readonly struct Args - { - public readonly IJsonValue Value; - - public readonly HashSet ValidIds; - - public Args(IJsonValue value, HashSet validIds) - { - Value = value; - - ValidIds = validIds; - } - } + public sealed record Args(IJsonValue Value, ISet ValidIds); private ReferencesCleaner() { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs index fdceae9af..60c2a7177 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs @@ -11,35 +11,23 @@ using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { internal sealed class ReferencesExtractor : IFieldVisitor { private static readonly ReferencesExtractor Instance = new ReferencesExtractor(); - public readonly struct Args - { - public readonly IJsonValue Value; - - public readonly HashSet Result; - - public readonly int ResultLimit; - - public Args(IJsonValue value, HashSet result, int take) - { - Value = value; - Result = result; - ResultLimit = take; - } - } + public sealed record Args(IJsonValue Value, ISet Result, int Take, ResolvedComponents Components); private ReferencesExtractor() { } - public static None Extract(IField field, IJsonValue? value, HashSet result, int take) + public static None Extract(IField field, IJsonValue? value, HashSet result, int take, ResolvedComponents components) { - var args = new Args(value ?? JsonValue.Null, result, take); + var args = new Args(value ?? JsonValue.Null, result, take, components); return field.Accept(Instance, args); } @@ -78,7 +66,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds public None Visit(IField field, Args args) { - ExtractFromComponent(field, args.Value, args); + ExtractFromComponent(args.Value, args); return None.Value; } @@ -89,7 +77,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { for (var i = 0; i < array.Count; i++) { - ExtractFromComponent(field, array[i], args); + ExtractFromComponent(array[i], args); } } @@ -139,21 +127,26 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { if (obj.TryGetValue(nestedField.Name, out var nestedValue)) { - nestedField.Accept(this, new Args(nestedValue, args.Result, args.ResultLimit)); + nestedField.Accept(this, args with { Value = nestedValue }); } } } } - private void ExtractFromComponent(IField field, IJsonValue value, Args args) + private void ExtractFromComponent(IJsonValue value, Args args) { - if (value is JsonObject obj && obj.TryGetValue(Component.Discriminator, out var type) && field.TryGetResolvedSchema(type.Value, out var schema)) + if (value is JsonObject obj && obj.TryGetValue(Component.Discriminator, out var type)) { - foreach (var componentField in schema.Fields) + var id = DomainId.Create(type.Value); + + if (args.Components.TryGetValue(id, out var schema)) { - if (obj.TryGetValue(componentField.Name, out var componentValue)) + foreach (var componentField in schema.Fields) { - componentField.Accept(this, new Args(componentValue, args.Result, args.ResultLimit)); + if (obj.TryGetValue(componentField.Name, out var componentValue)) + { + componentField.Accept(this, args with { Value = componentValue }); + } } } } @@ -173,7 +166,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds added++; - if (added >= args.ResultLimit) + if (added >= args.Take) { break; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmSchemaExtensions.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmSchemaExtensions.cs index 61d24dfce..2f98f6a7e 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmSchemaExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmSchemaExtensions.cs @@ -26,7 +26,8 @@ namespace Squidex.Domain.Apps.Core.GenerateEdmSchema return field.Replace("_", "-"); } - public static EdmComplexType BuildEdmType(this Schema schema, bool withHidden, PartitionResolver partitionResolver, EdmTypeFactory typeFactory) + public static EdmComplexType BuildEdmType(this Schema schema, bool withHidden, PartitionResolver partitionResolver, EdmTypeFactory typeFactory, + ResolvedComponents components) { Guard.NotNull(typeFactory, nameof(typeFactory)); Guard.NotNull(partitionResolver, nameof(partitionResolver)); @@ -40,7 +41,7 @@ namespace Squidex.Domain.Apps.Core.GenerateEdmSchema continue; } - var fieldEdmType = EdmTypeVisitor.BuildType(field, typeFactory); + var fieldEdmType = EdmTypeVisitor.BuildType(field, typeFactory, components); if (fieldEdmType == null) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmTypeVisitor.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmTypeVisitor.cs index 37cdbc4d3..4f5e2ca49 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmTypeVisitor.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateEdmSchema/EdmTypeVisitor.cs @@ -10,6 +10,8 @@ using Microsoft.OData.Edm; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Text; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Core.GenerateEdmSchema { internal sealed class EdmTypeVisitor : IFieldVisitor @@ -18,32 +20,15 @@ namespace Squidex.Domain.Apps.Core.GenerateEdmSchema private static readonly EdmComplexType JsonType = new EdmComplexType("Squidex", "Json", null, false, true); private static readonly EdmTypeVisitor Instance = new EdmTypeVisitor(); - public readonly struct Args - { - public readonly EdmTypeFactory Factory; - - public readonly int Level; - - public Args(EdmTypeFactory factory, int level) - { - Factory = factory; - - Level = level; - } - - public Args Increment() - { - return new Args(Factory, Level + 1); - } - } + public sealed record Args(EdmTypeFactory Factory, ResolvedComponents Components, int Level = 0); private EdmTypeVisitor() { } - public static IEdmTypeReference? BuildType(IField field, EdmTypeFactory factory) + public static IEdmTypeReference? BuildType(IField field, EdmTypeFactory factory, ResolvedComponents components) { - var args = new Args(factory, 0); + var args = new Args(factory, components); return field.Accept(Instance, args); } @@ -65,12 +50,12 @@ namespace Squidex.Domain.Apps.Core.GenerateEdmSchema public IEdmTypeReference? Visit(IField field, Args args) { - return CreateNestedType(field, field.GetSharedFields(field.Properties.SchemaIds, true), args); + return CreateNestedType(field, args.Components.GetSharedFields(field.Properties.SchemaIds, true), args); } public IEdmTypeReference? Visit(IField field, Args args) { - return CreateNestedType(field, field.GetSharedFields(field.Properties.SchemaIds, true), args); + return CreateNestedType(field, args.Components.GetSharedFields(field.Properties.SchemaIds, true), args); } public IEdmTypeReference? Visit(IField field, Args args) @@ -139,7 +124,7 @@ namespace Squidex.Domain.Apps.Core.GenerateEdmSchema if (created) { - var nestedArgs = args.Increment(); + var nestedArgs = args with { Level = args.Level + 1 }; foreach (var sharedField in nested) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonSchemaExtensions.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonSchemaExtensions.cs index 56d1504b8..0f8974a2e 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonSchemaExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonSchemaExtensions.cs @@ -14,7 +14,8 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema { public static class JsonSchemaExtensions { - public static JsonSchema BuildFlatJsonSchema(this Schema schema, SchemaResolver schemaResolver) + public static JsonSchema BuildFlatJsonSchema(this Schema schema, SchemaResolver schemaResolver, + ResolvedComponents components) { Guard.NotNull(schemaResolver, nameof(schemaResolver)); @@ -24,7 +25,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema foreach (var field in schema.Fields.ForApi()) { - var property = JsonTypeVisitor.BuildProperty(field); + var property = JsonTypeVisitor.BuildProperty(field, components); if (property != null) { @@ -37,7 +38,8 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema return jsonSchema; } - public static JsonSchema BuildDynamicJsonSchema(this Schema schema, SchemaResolver schemaResolver, bool withHidden = false) + public static JsonSchema BuildDynamicJsonSchema(this Schema schema, SchemaResolver schemaResolver, + ResolvedComponents components, bool withHidden = false) { Guard.NotNull(schemaResolver, nameof(schemaResolver)); @@ -45,7 +47,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema foreach (var field in schema.Fields.ForApi(withHidden)) { - var propertyItem = JsonTypeVisitor.BuildProperty(field, schemaResolver, withHidden); + var propertyItem = JsonTypeVisitor.BuildProperty(field, components, schemaResolver, withHidden); if (propertyItem != null) { @@ -61,7 +63,8 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema return jsonSchema; } - public static JsonSchema BuildJsonSchema(this Schema schema, PartitionResolver partitionResolver, bool withHidden = false) + public static JsonSchema BuildJsonSchema(this Schema schema, PartitionResolver partitionResolver, + ResolvedComponents components, bool withHidden = false) { Guard.NotNull(partitionResolver, nameof(partitionResolver)); @@ -75,7 +78,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema foreach (var partitionKey in partitioning.AllKeys) { - var propertyItem = JsonTypeVisitor.BuildProperty(field, withHiddenFields: withHidden); + var propertyItem = JsonTypeVisitor.BuildProperty(field, components, withHiddenFields: withHidden); if (propertyItem != null) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs index 793838280..6a4fd9949 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs @@ -15,6 +15,8 @@ using Squidex.Infrastructure; using Squidex.Infrastructure.Collections; using Squidex.Infrastructure.Json; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Core.GenerateJsonSchema { public delegate JsonSchema SchemaResolver(string name, Func schema); @@ -24,36 +26,15 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema private const int MaxDepth = 5; private static readonly JsonTypeVisitor Instance = new JsonTypeVisitor(); - public readonly struct Args - { - public readonly SchemaResolver? SchemaResolver; - - public readonly bool WithHiddenFields; - - public readonly int Level; - - public Args(SchemaResolver? schemaResolver, bool withHiddenFields, int level) - { - SchemaResolver = schemaResolver; - - WithHiddenFields = withHiddenFields; - - Level = level; - } - - public Args Increment() - { - return new Args(SchemaResolver, WithHiddenFields, Level + 1); - } - } + public sealed record Args(ResolvedComponents Components, SchemaResolver? SchemaResolver, bool WithHiddenFields, int Level = 0); private JsonTypeVisitor() { } - public static JsonSchemaProperty? BuildProperty(IField field, SchemaResolver? schemaResolver = null, bool withHiddenFields = false) + public static JsonSchemaProperty? BuildProperty(IField field, ResolvedComponents components, SchemaResolver? schemaResolver = null, bool withHiddenFields = false) { - var args = new Args(schemaResolver, withHiddenFields, 0); + var args = new Args(components, schemaResolver, withHiddenFields, 0); return field.Accept(Instance, args); } @@ -67,7 +48,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema var itemSchema = SchemaBuilder.Object(); - var nestedArgs = args.Increment(); + var nestedArgs = args with { Level = args.Level + 1 }; foreach (var nestedField in field.Fields.ForApi(args.WithHiddenFields)) { @@ -104,7 +85,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema var property = SchemaBuilder.ObjectProperty(); - BuildComponent(property, field, field.Properties.SchemaIds, args); + BuildComponent(property, field.Properties.SchemaIds, args); return property; } @@ -118,7 +99,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema var itemSchema = SchemaBuilder.Object(); - BuildComponent(itemSchema, field, field.Properties.SchemaIds, args); + BuildComponent(itemSchema, field.Properties.SchemaIds, args); return SchemaBuilder.ArrayProperty(itemSchema); } @@ -196,13 +177,13 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema return null; } - private void BuildComponent(JsonSchema jsonSchema, IField field, ImmutableList? schemaIds, Args args) + private void BuildComponent(JsonSchema jsonSchema, ImmutableList? schemaIds, Args args) { jsonSchema.Properties.Add(Component.Discriminator, SchemaBuilder.StringProperty(isRequired: true)); if (args.SchemaResolver != null) { - var schemas = schemaIds?.Select(x => field.GetResolvedSchema(x)).NotNull() ?? Enumerable.Empty(); + var schemas = schemaIds?.Select(x => args.Components.Get(x)).NotNull() ?? Enumerable.Empty(); var discriminator = new OpenApiDiscriminator { @@ -215,7 +196,7 @@ namespace Squidex.Domain.Apps.Core.GenerateJsonSchema var componentSchema = args.SchemaResolver(schemaName, () => { - var nestedArgs = args.Increment(); + var nestedArgs = args with { Level = args.Level + 1 }; var componentSchema = SchemaBuilder.Object(); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs index 727e9a2d0..f0528adde 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs @@ -13,25 +13,15 @@ using Squidex.Domain.Apps.Core.ValidateContent.Validators; using Squidex.Infrastructure.Json.Objects; using Squidex.Text; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Core.ValidateContent { internal sealed class DefaultFieldValueValidatorsFactory : IFieldVisitor, DefaultFieldValueValidatorsFactory.Args> { private static readonly DefaultFieldValueValidatorsFactory Instance = new DefaultFieldValueValidatorsFactory(); - public readonly struct Args - { - public readonly ValidatorContext Context; - - public readonly ValidatorFactory Factory; - - public Args(ValidatorContext context, ValidatorFactory factory) - { - Context = context; - - Factory = factory; - } - } + public sealed record Args(ValidatorContext Context, ValidatorFactory Factory); private DefaultFieldValueValidatorsFactory() { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs index b987798cf..34e05b913 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs @@ -14,35 +14,27 @@ using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Translations; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Core.ValidateContent { public sealed class JsonValueConverter : IFieldVisitor<(object? Result, JsonError? Error), JsonValueConverter.Args> { private static readonly JsonValueConverter Instance = new JsonValueConverter(); - public readonly struct Args - { - public readonly IJsonValue Value; - public readonly IJsonSerializer JsonSerializer; - - public Args(IJsonValue value, IJsonSerializer jsonSerializer) - { - Value = value; - - JsonSerializer = jsonSerializer; - } - } + public sealed record Args(IJsonValue Value, IJsonSerializer JsonSerializer, ResolvedComponents Components); private JsonValueConverter() { } - public static (object? Result, JsonError? Error) ConvertValue(IField field, IJsonValue value, IJsonSerializer jsonSerializer) + public static (object? Result, JsonError? Error) ConvertValue(IField field, IJsonValue value, IJsonSerializer jsonSerializer, + ResolvedComponents components) { Guard.NotNull(field, nameof(field)); Guard.NotNull(value, nameof(value)); - var args = new Args(value, jsonSerializer); + var args = new Args(value, jsonSerializer, components); return field.Accept(Instance, args); } @@ -59,12 +51,12 @@ namespace Squidex.Domain.Apps.Core.ValidateContent public (object? Result, JsonError? Error) Visit(IField field, Args args) { - return ConvertToComponent(field, args.Value); + return ConvertToComponent(args.Value, args.Components); } public (object? Result, JsonError? Error) Visit(IField field, Args args) { - return ConvertToComponentList(field, args.Value); + return ConvertToComponentList(args.Value, args.Components); } public (object? Result, JsonError? Error) Visit(IField field, Args args) @@ -199,7 +191,8 @@ namespace Squidex.Domain.Apps.Core.ValidateContent return (null, new JsonError(T.Get("contents.invalidArrayOfStrings"))); } - private static (object? Result, JsonError? Error) ConvertToComponentList(IField field, IJsonValue value) + private static (object? Result, JsonError? Error) ConvertToComponentList(IJsonValue value, + ResolvedComponents components) { if (value is JsonArray array) { @@ -207,7 +200,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent for (var i = 0; i < array.Count; i++) { - var (item, error) = ConvertToComponent(field, array[i]); + var (item, error) = ConvertToComponent(array[i], components); if (error != null) { @@ -250,7 +243,8 @@ namespace Squidex.Domain.Apps.Core.ValidateContent return (null, new JsonError(T.Get("contents.invalidArrayOfObjects"))); } - private static (object? Result, JsonError? Error) ConvertToComponent(IField field, IJsonValue value) + private static (object? Result, JsonError? Error) ConvertToComponent(IJsonValue value, + ResolvedComponents components) { if (value is not JsonObject obj) { @@ -262,7 +256,9 @@ namespace Squidex.Domain.Apps.Core.ValidateContent return (null, new JsonError(T.Get("contents.invalidComponentNoType"))); } - if (!field.TryGetResolvedSchema(type, out var schema)) + var id = DomainId.Create(type.Value); + + if (!components.TryGetValue(id, out var schema)) { return (null, new JsonError(T.Get("contents.invalidComponentUnknownSchema"))); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueValidator.cs index 47e7d7142..b5a72e472 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueValidator.cs @@ -12,24 +12,15 @@ using Squidex.Infrastructure; using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json.Objects; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Core.ValidateContent { public sealed class JsonValueValidator : IFieldVisitor { private static readonly JsonValueValidator Instance = new JsonValueValidator(); - public readonly struct Args - { - public readonly IJsonValue Value; - public readonly IJsonSerializer JsonSerializer; - - public Args(IJsonValue value, IJsonSerializer jsonSerializer) - { - Value = value; - - JsonSerializer = jsonSerializer; - } - } + public sealed record Args(IJsonValue Value, IJsonSerializer JsonSerializer); private JsonValueValidator() { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs index eb7b43213..46ab18845 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs @@ -19,6 +19,8 @@ namespace Squidex.Domain.Apps.Core.ValidateContent public IJsonSerializer JsonSerializer { get; } + public ResolvedComponents Components { get; } + public DomainId ContentId { get; } public bool IsOptional { get; private set; } @@ -28,11 +30,13 @@ namespace Squidex.Domain.Apps.Core.ValidateContent NamedId appId, NamedId schemaId, Schema schema, + ResolvedComponents components, DomainId contentId) : base(appId, schemaId, schema) { JsonSerializer = jsonSerializer; + Components = components; ContentId = contentId; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs index efab6fd81..5d7341621 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs @@ -1,4 +1,4 @@ -// ========================================================================== +// ========================================================================== // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschraenkt) @@ -41,7 +41,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators } else { - var (json, error) = JsonValueConverter.ConvertValue(field, jsonValue, context.JsonSerializer); + var (json, error) = JsonValueConverter.ConvertValue(field, jsonValue, context.JsonSerializer, context.Components); if (error != null) { diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/AdaptIdVisitor.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/AdaptIdVisitor.cs index eaa8b5feb..ba0ec1f6b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/AdaptIdVisitor.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/AdaptIdVisitor.cs @@ -12,21 +12,15 @@ using NodaTime; using Squidex.Infrastructure; using Squidex.Infrastructure.Queries; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Entities.MongoDb { internal sealed class AdaptIdVisitor : TransformVisitor { private static readonly AdaptIdVisitor Instance = new AdaptIdVisitor(); - public readonly struct Args - { - public readonly DomainId AppId; - - public Args(DomainId appId) - { - AppId = appId; - } - } + public sealed record Args(DomainId AppId); private AdaptIdVisitor() { diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs index 49d071264..bfe46f45e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs @@ -162,7 +162,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents if (schema != null) { - entity.ReferencedIds = entity.Data.GetReferencedIds(schema.SchemaDef); + var components = await appProvider.GetComponentsAsync(schema); + + entity.ReferencedIds = entity.Data.GetReferencedIds(schema.SchemaDef, components); } else { diff --git a/backend/src/Squidex.Domain.Apps.Entities/AppProvider.cs b/backend/src/Squidex.Domain.Apps.Entities/AppProvider.cs index 315961928..793a98e45 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/AppProvider.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/AppProvider.cs @@ -9,7 +9,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Squidex.Caching; -using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps.Indexes; using Squidex.Domain.Apps.Entities.Rules; @@ -17,7 +16,6 @@ using Squidex.Domain.Apps.Entities.Rules.Indexes; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas.Indexes; using Squidex.Infrastructure; -using Squidex.Infrastructure.Collections; using Squidex.Infrastructure.Security; namespace Squidex.Domain.Apps.Entities @@ -109,8 +107,6 @@ namespace Squidex.Domain.Apps.Entities if (schema != null) { - await ResolveSchemaAsync(appId, schema.SchemaDef); - localCache.Add(cacheKey, schema); localCache.Add(SchemaCacheKey(appId, schema.Id), schema); } @@ -131,8 +127,6 @@ namespace Squidex.Domain.Apps.Entities if (schema != null) { - await ResolveSchemaAsync(appId, schema.SchemaDef); - localCache.Add(cacheKey, schema); localCache.Add(SchemaCacheKey(appId, schema.SchemaDef.Name), schema); } @@ -163,11 +157,6 @@ namespace Squidex.Domain.Apps.Entities localCache.Add(SchemaCacheKey(appId, schema.SchemaDef.Name), schema); } - foreach (var schema in schemas) - { - await ResolveSchemaAsync(appId, schema.SchemaDef); - } - return schemas; } @@ -188,59 +177,6 @@ namespace Squidex.Domain.Apps.Entities return rules.Find(x => x.Id == id); } - private async Task ResolveSchemaAsync(DomainId appId, Schema schema) - { - async Task ResolveWithIdsAsync(IField field, ImmutableList? schemaIds) - { - if (schemaIds != null) - { - foreach (var schemaId in schemaIds) - { - if (!field.TryGetResolvedSchema(schemaId, out _)) - { - var resolvedEntity = await GetSchemaAsync(appId, schemaId, true); - - if (resolvedEntity != null) - { - field.SetResolvedSchema(schemaId, resolvedEntity.SchemaDef); - } - } - } - } - } - - async Task ResolveArrayAsync(IArrayField arrayField) - { - foreach (var nestedField in arrayField.Fields) - { - await ResolveAsync(nestedField); - } - } - - async Task ResolveAsync(IField field) - { - switch (field) - { - case IField component: - await ResolveWithIdsAsync(field, component.Properties.SchemaIds); - break; - - case IField components: - await ResolveWithIdsAsync(field, components.Properties.SchemaIds); - break; - - case IArrayField arrayField: - await ResolveArrayAsync(arrayField); - break; - } - } - - foreach (var field in schema.Fields) - { - await ResolveAsync(field); - } - } - private static string AppCacheKey(DomainId appId) { return $"APPS_ID_{appId}"; diff --git a/backend/src/Squidex.Domain.Apps.Entities/AppProviderExtensions.cs b/backend/src/Squidex.Domain.Apps.Entities/AppProviderExtensions.cs new file mode 100644 index 000000000..5562b58e4 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/AppProviderExtensions.cs @@ -0,0 +1,84 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using System.Threading.Tasks; +using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Entities.Schemas; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Collections; + +namespace Squidex.Domain.Apps.Entities +{ + public static class AppProviderExtensions + { + public static async Task GetComponentsAsync(this IAppProvider appProvider, ISchemaEntity schema) + { + Dictionary? result = null; + + var appId = schema.AppId.Id; + + async Task ResolveWithIdsAsync(IField field, ImmutableList? schemaIds) + { + if (schemaIds != null) + { + foreach (var schemaId in schemaIds) + { + if (result == null || !result.TryGetValue(schemaId, out _)) + { + var resolvedEntity = await appProvider.GetSchemaAsync(appId, schemaId, true); + + if (resolvedEntity != null) + { + result ??= new Dictionary(); + result[schemaId] = resolvedEntity.SchemaDef; + } + } + } + } + } + + async Task ResolveArrayAsync(IArrayField arrayField) + { + foreach (var nestedField in arrayField.Fields) + { + await ResolveAsync(nestedField); + } + } + + async Task ResolveAsync(IField field) + { + switch (field) + { + case IField component: + await ResolveWithIdsAsync(field, component.Properties.SchemaIds); + break; + + case IField components: + await ResolveWithIdsAsync(field, components.Properties.SchemaIds); + break; + + case IArrayField arrayField: + await ResolveArrayAsync(arrayField); + break; + } + } + + foreach (var field in schema.SchemaDef.Fields) + { + await ResolveAsync(field); + } + + if (result == null) + { + return ResolvedComponents.Empty; + } + + return new ResolvedComponents(result); + } + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs index 4fd4cce41..9d0a483f9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs @@ -11,25 +11,15 @@ using Squidex.Domain.Apps.Core.Tags; using Squidex.Infrastructure; using Squidex.Infrastructure.Queries; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Entities.Assets.Queries { internal sealed class FilterTagTransformer : AsyncTransformVisitor { private static readonly FilterTagTransformer Instance = new FilterTagTransformer(); - public readonly struct Args - { - public readonly DomainId AppId; - - public readonly ITagService TagService; - - public Args(DomainId appId, ITagService tagService) - { - AppId = appId; - - TagService = tagService; - } - } + public sealed record Args(DomainId AppId, ITagService TagService); private FilterTagTransformer() { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs index 3f57f0e02..3ab4b8ed1 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs @@ -109,6 +109,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards context.App.NamedId(), context.Schema.NamedId(), context.SchemaDef, + context.Components, context.ContentId) .Optimized(optimize).AsPublishing(published); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/OperationContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/OperationContext.cs index 5c1b16192..9609ccae4 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/OperationContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/OperationContext.cs @@ -34,6 +34,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject public DomainId ContentId { get; init; } + public ResolvedComponents Components { get; init; } + public Func ContentProvider { get; init; } public IContentEntity Content @@ -69,10 +71,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject throw new DomainObjectNotFoundException(command.SchemaId.Id.ToString()); } + var components = await appProvider.GetComponentsAsync(schema); + return new OperationContext(services) { App = app, Actor = command.Actor, + Components = components, ContentProvider = snapshot, ContentId = command.ContentId, Schema = schema, diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Builder.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Builder.cs index 8a1231c0d..de0646359 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Builder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Builder.cs @@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types foreach (var schemaInfo in schemaInfos) { - var contentType = new ContentGraphType(this, schemaInfo); + var contentType = new ContentGraphType(schemaInfo); contentTypes[schemaInfo] = contentType; contentResultTypes[schemaInfo] = new ContentResultGraphType(contentType, schemaInfo); @@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types foreach (var schemaInfo in allSchemas) { - var componentType = new ComponentGraphType(this, schemaInfo); + var componentType = new ComponentGraphType(schemaInfo); componentTypes[schemaInfo] = componentType; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ComponentGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ComponentGraphType.cs index 35aca2e1d..cd0b72186 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ComponentGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ComponentGraphType.cs @@ -15,17 +15,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents { internal sealed class ComponentGraphType : ObjectGraphType { - public ComponentGraphType(Builder builder, SchemaInfo schemaInfo) + public ComponentGraphType(SchemaInfo schemaInfo) { Name = schemaInfo.ComponentType; - Description = $"The structure of the {schemaInfo.DisplayName} component schema."; - IsTypeOf = CheckType(schemaInfo.Schema.Id.ToString()); } public void Initialize(Builder builder, SchemaInfo schemaInfo) { + Description = $"The structure of the {schemaInfo.DisplayName} component schema."; + AddField(ContentFields.SchemaId); foreach (var fieldInfo in schemaInfo.Fields) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentGraphType.cs index 8de789aa7..aeb86d7e0 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentGraphType.cs @@ -17,7 +17,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents { private readonly DomainId schemaId; - public ContentGraphType(Builder builder, SchemaInfo schemaInfo) + public ContentGraphType(SchemaInfo schemaInfo) { schemaId = schemaInfo.Schema.Id; @@ -31,7 +31,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents public void Initialize(Builder builder, SchemaInfo schemaInfo, IEnumerable allSchemas) { - Name = schemaInfo.ContentType; AddField(ContentFields.Id); @@ -83,6 +82,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents { AddReferencingQueries(builder, other); } + AddResolvedInterface(builder.SharedTypes.ContentInterface); Description = $"The structure of a {schemaInfo.DisplayName} content type."; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs index 67e605fed..d97bd59f8 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; @@ -20,18 +20,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries public sealed class ContentEnricher : IContentEnricher { private readonly IEnumerable steps; - private readonly Lazy contentQuery; + private readonly IAppProvider appProvider; - private IContentQueryService ContentQuery - { - get => contentQuery.Value; - } - - public ContentEnricher(IEnumerable steps, Lazy contentQuery) + public ContentEnricher(IEnumerable steps, IAppProvider appProvider) { this.steps = steps; - this.contentQuery = contentQuery; + this.appProvider = appProvider; } public async Task EnrichAsync(IContentEntity content, bool cloneData, Context context, @@ -84,11 +79,23 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries if (context.App != null) { - var schemaCache = new Dictionary>(); + var schemaCache = new Dictionary>(); - Task GetSchema(DomainId id) + Task<(ISchemaEntity, ResolvedComponents)> GetSchema(DomainId id) { - return schemaCache.GetOrAdd(id, x => ContentQuery.GetSchemaOrThrowAsync(context, x.ToString())); + return schemaCache.GetOrAdd(id, async x => + { + var schema = await appProvider.GetSchemaAsync(context.App.Id, x, false); + + if (schema == null) + { + throw new DomainObjectNotFoundException(x.ToString()); + } + + var components = await appProvider.GetComponentsAsync(schema); + + return (schema, components); + }); } foreach (var step in steps) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs index c56a577f3..6175508a4 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs @@ -40,12 +40,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries private readonly JsonSchema genericJsonSchema = ContentJsonSchemaBuilder.BuildSchema("Content", null, false, true); private readonly IMemoryCache cache; private readonly IJsonSerializer jsonSerializer; + private readonly IAppProvider appprovider; private readonly ITextIndex textIndex; private readonly ContentOptions options; - public ContentQueryParser(IMemoryCache cache, IJsonSerializer jsonSerializer, ITextIndex textIndex, IOptions options) + public ContentQueryParser(IAppProvider appprovider, ITextIndex textIndex, IOptions options, + IMemoryCache cache, IJsonSerializer jsonSerializer) { this.jsonSerializer = jsonSerializer; + this.appprovider = appprovider; this.textIndex = textIndex; this.cache = cache; this.options = options.Value; @@ -58,7 +61,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries using (Profiler.TraceMethod()) { - var query = ParseClrQuery(context, q, schema); + var query = await ParseClrQueryAsync(context, q, schema); await TransformFilterAsync(query, context, schema); @@ -113,21 +116,28 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries } } - private ClrQuery ParseClrQuery(Context context, Q q, ISchemaEntity? schema) + private async Task ParseClrQueryAsync(Context context, Q q, ISchemaEntity? schema) { + var components = ResolvedComponents.Empty; + + if (schema != null) + { + components = await appprovider.GetComponentsAsync(schema); + } + var query = q.Query; if (!string.IsNullOrWhiteSpace(q.JsonQueryString)) { - query = ParseJson(context, schema, q.JsonQueryString); + query = ParseJson(context, schema, q.JsonQueryString, components); } else if (q?.JsonQuery != null) { - query = ParseJson(context, schema, q.JsonQuery); + query = ParseJson(context, schema, q.JsonQuery, components); } else if (!string.IsNullOrWhiteSpace(q?.ODataQuery)) { - query = ParseOData(context, schema, q.ODataQuery); + query = ParseOData(context, schema, q.ODataQuery, components); } return query; @@ -158,25 +168,28 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries } } - private ClrQuery ParseJson(Context context, ISchemaEntity? schema, Query query) + private ClrQuery ParseJson(Context context, ISchemaEntity? schema, Query query, + ResolvedComponents components) { - var jsonSchema = BuildJsonSchema(context, schema); + var jsonSchema = BuildJsonSchema(context, schema, components); return jsonSchema.Convert(query); } - private ClrQuery ParseJson(Context context, ISchemaEntity? schema, string json) + private ClrQuery ParseJson(Context context, ISchemaEntity? schema, string json, + ResolvedComponents components) { - var jsonSchema = BuildJsonSchema(context, schema); + var jsonSchema = BuildJsonSchema(context, schema, components); return jsonSchema.Parse(json, jsonSerializer); } - private ClrQuery ParseOData(Context context, ISchemaEntity? schema, string odata) + private ClrQuery ParseOData(Context context, ISchemaEntity? schema, string odata, + ResolvedComponents components) { try { - var model = BuildEdmModel(context, schema); + var model = BuildEdmModel(context, schema, components); return model.ParseQuery(odata).ToQuery(); } @@ -196,7 +209,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries } } - private JsonSchema BuildJsonSchema(Context context, ISchemaEntity? schema) + private JsonSchema BuildJsonSchema(Context context, ISchemaEntity? schema, + ResolvedComponents components) { if (schema == null) { @@ -209,13 +223,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { entry.AbsoluteExpirationRelativeToNow = CacheTime; - return BuildJsonSchema(schema.SchemaDef, context.App, context.IsFrontendClient); + return BuildJsonSchema(schema.SchemaDef, context.App, components, context.IsFrontendClient); }); return result; } - private IEdmModel BuildEdmModel(Context context, ISchemaEntity? schema) + private IEdmModel BuildEdmModel(Context context, ISchemaEntity? schema, + ResolvedComponents components) { if (schema == null) { @@ -228,20 +243,22 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { entry.AbsoluteExpirationRelativeToNow = CacheTime; - return BuildEdmModel(schema.SchemaDef, context.App, context.IsFrontendClient); + return BuildEdmModel(schema.SchemaDef, context.App, components, context.IsFrontendClient); }); return result; } - private static JsonSchema BuildJsonSchema(Schema schema, IAppEntity app, bool withHiddenFields) + private static JsonSchema BuildJsonSchema(Schema schema, IAppEntity app, + ResolvedComponents components, bool withHiddenFields) { - var dataSchema = schema.BuildJsonSchema(app.PartitionResolver(), withHiddenFields); + var dataSchema = schema.BuildJsonSchema(app.PartitionResolver(), components, withHiddenFields); return ContentJsonSchemaBuilder.BuildSchema(schema.DisplayName(), dataSchema, false, true); } - private static EdmModel BuildEdmModel(Schema schema, IAppEntity app, bool withHiddenFields) + private static EdmModel BuildEdmModel(Schema schema, IAppEntity app, + ResolvedComponents components, bool withHiddenFields) { var model = new EdmModel(); @@ -272,7 +289,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries return (result, true); }); - var schemaType = schema.BuildEdmType(withHiddenFields, app.PartitionResolver(), typeFactory); + var schemaType = schema.BuildEdmType(withHiddenFields, app.PartitionResolver(), typeFactory, components); return BuildEdmModel(app.Name.ToPascalCase(), schema.Name, model, schemaType); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/GeoQueryTransformer.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/GeoQueryTransformer.cs index 7ea229677..5650fbc05 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/GeoQueryTransformer.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/GeoQueryTransformer.cs @@ -11,27 +11,15 @@ using Squidex.Domain.Apps.Entities.Contents.Text; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure.Queries; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Entities.Contents.Queries { internal sealed class GeoQueryTransformer : AsyncTransformVisitor { public static readonly GeoQueryTransformer Instance = new GeoQueryTransformer(); - public readonly struct Args - { - public readonly ITextIndex TextIndex; - - public readonly ISchemaEntity Schema; - - public readonly Context Context; - - public Args(Context context, ISchemaEntity schema, ITextIndex textIndex) - { - Context = context; - Schema = schema; - TextIndex = textIndex; - } - } + public sealed record Args(Context Context, ISchemaEntity Schema, ITextIndex TextIndex); private GeoQueryTransformer() { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricherStep.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricherStep.cs index e27033ada..b658fcfe5 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricherStep.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/IContentEnricherStep.cs @@ -8,12 +8,13 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Queries { - public delegate Task ProvideSchema(DomainId id); + public delegate Task<(ISchemaEntity Schema, ResolvedComponents Components)> ProvideSchema(DomainId id); public interface IContentEnricherStep { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs index b889aac8d..7f21fed21 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.ConvertContent; using Squidex.Domain.Apps.Core.ExtractReferenceIds; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Contents.Repositories; @@ -24,25 +25,22 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps public sealed class ConvertData : IContentEnricherStep { private readonly IUrlGenerator urlGenerator; + private readonly IJsonSerializer jsonSerializer; private readonly IAssetRepository assetRepository; private readonly IContentRepository contentRepository; private readonly FieldConverter excludedChangedField; - private readonly FieldConverter excludedChangedValue; private readonly FieldConverter excludedHiddenField; - private readonly FieldConverter excludedHiddenValue; public ConvertData(IUrlGenerator urlGenerator, IJsonSerializer jsonSerializer, IAssetRepository assetRepository, IContentRepository contentRepository) { this.urlGenerator = urlGenerator; + this.jsonSerializer = jsonSerializer; this.assetRepository = assetRepository; this.contentRepository = contentRepository; excludedChangedField = FieldConverters.ExcludeChangedTypes(jsonSerializer); - excludedChangedValue = FieldConverters.ForValues(ValueConverters.ExcludeChangedTypes(jsonSerializer)); - excludedHiddenField = FieldConverters.ExcludeHidden; - excludedHiddenValue = FieldConverters.ForValues(ValueConverters.ExcludeHidden); } public async Task EnrichAsync(Context context, IEnumerable contents, ProvideSchema schemas, @@ -50,13 +48,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { var referenceCleaner = await CleanReferencesAsync(context, contents, schemas, ct); - var converters = GenerateConverters(context, referenceCleaner).ToArray(); - foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) { ct.ThrowIfCancellationRequested(); - var schema = await schemas(group.Key); + var (schema, components) = await schemas(group.Key); + + var converters = GenerateConverters(context, components, referenceCleaner).ToArray(); foreach (var content in group) { @@ -74,11 +72,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) { - var schema = await schemas(group.Key); + var (schema, components) = await schemas(group.Key); foreach (var content in group) { - content.Data.AddReferencedIds(schema.SchemaDef, ids); + content.Data.AddReferencedIds(schema.SchemaDef, ids, components); } } @@ -113,20 +111,20 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps return result; } - private IEnumerable GenerateConverters(Context context, ValueConverter? cleanReferences) + private IEnumerable GenerateConverters(Context context, ResolvedComponents components, ValueConverter? cleanReferences) { if (!context.IsFrontendClient) { yield return excludedHiddenField; - yield return excludedHiddenValue; + yield return FieldConverters.ForValues(components, ValueConverters.ExcludeHidden); } yield return excludedChangedField; - yield return excludedChangedValue; + yield return FieldConverters.ForValues(components, ValueConverters.ExcludeChangedTypes(jsonSerializer)); if (cleanReferences != null) { - yield return FieldConverters.ForValues(cleanReferences); + yield return FieldConverters.ForValues(components, cleanReferences); } yield return FieldConverters.ResolveInvariant(context.App.Languages); @@ -154,7 +152,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps var resolveAssetUrls = ValueConverters.ResolveAssetUrls(appId, assetUrls, urlGenerator); - yield return FieldConverters.ForValues(resolveAssetUrls); + yield return FieldConverters.ForValues(components, resolveAssetUrls); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichForCaching.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichForCaching.cs index 1dc602d6d..bc99a2c45 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichForCaching.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichForCaching.cs @@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { ct.ThrowIfCancellationRequested(); - var schema = await schemas(group.Key); + var (schema, _) = await schemas(group.Key); foreach (var content in group) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithSchema.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithSchema.cs index 609b8bae5..03eb682b0 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithSchema.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/EnrichWithSchema.cs @@ -22,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { ct.ThrowIfCancellationRequested(); - var schema = await schemas(group.Key); + var (schema, _) = await schemas(group.Key); var schemaDisplayName = schema.SchemaDef.DisplayNameUnchanged(); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs index 7b9bd142f..2689c9533 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs @@ -46,23 +46,24 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) { - var schema = await schemas(group.Key); + var (schema, components) = await schemas(group.Key); - AddAssetIds(ids, schema, group); + AddAssetIds(ids, schema, components, group); } var assets = await GetAssetsAsync(context, ids, ct); foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) { - var schema = await schemas(group.Key); + var (schema, components) = await schemas(group.Key); - ResolveAssetsUrls(schema, group, assets); + ResolveAssetsUrls(schema, components, group, assets); } } } - private void ResolveAssetsUrls(ISchemaEntity schema, IGrouping contents, ILookup assets) + private void ResolveAssetsUrls(ISchemaEntity schema, ResolvedComponents components, + IGrouping contents, ILookup assets) { foreach (var field in schema.SchemaDef.ResolvingAssets()) { @@ -77,7 +78,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps foreach (var (partitionKey, partitionValue) in fieldData) { var referencedAsset = - field.GetReferencedIds(partitionValue) + field.GetReferencedIds(partitionValue, components) .Select(x => assets[x]) .SelectMany(x => x) .FirstOrDefault(); @@ -133,11 +134,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps return assets.ToLookup(x => x.Id); } - private static void AddAssetIds(HashSet ids, ISchemaEntity schema, IEnumerable contents) + private static void AddAssetIds(HashSet ids, ISchemaEntity schema, ResolvedComponents components, IEnumerable contents) { foreach (var content in contents) { - content.Data.AddReferencedIds(schema.SchemaDef.ResolvingAssets(), ids, 1); + content.Data.AddReferencedIds(schema.SchemaDef.ResolvingAssets(), ids, components, 1); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveReferences.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveReferences.cs index cbae70937..738bb0b1a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveReferences.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveReferences.cs @@ -48,24 +48,24 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) { - var schema = await schemas(group.Key); + var (schema, components) = await schemas(group.Key); - AddReferenceIds(ids, schema, group); + AddReferenceIds(ids, schema, components, group); } var references = await GetReferencesAsync(context, ids, ct); foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) { - var schema = await schemas(group.Key); + var (schema, components) = await schemas(group.Key); - await ResolveReferencesAsync(context, schema, group, references, schemas); + await ResolveReferencesAsync(context, schema, components, group, references, schemas); } } } - private async Task ResolveReferencesAsync(Context context, ISchemaEntity schema, IEnumerable contents, ILookup references, - ProvideSchema schemas) + private async Task ResolveReferencesAsync(Context context, ISchemaEntity schema, ResolvedComponents components, + IEnumerable contents, ILookup references, ProvideSchema schemas) { var formatted = new Dictionary(); @@ -84,7 +84,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps foreach (var (partition, partitionValue) in fieldData) { var referencedContents = - field.GetReferencedIds(partitionValue) + field.GetReferencedIds(partitionValue, components) .Select(x => references[x]) .SelectMany(x => x) .ToList(); @@ -93,7 +93,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { var reference = referencedContents[0]; - var referencedSchema = await schemas(reference.SchemaId.Id); + var (referencedSchema, _) = await schemas(reference.SchemaId.Id); requestCache.AddDependency(referencedSchema.UniqueId, referencedSchema.Version); requestCache.AddDependency(reference.UniqueId, reference.Version); @@ -138,11 +138,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps return value; } - private static void AddReferenceIds(HashSet ids, ISchemaEntity schema, IEnumerable contents) + private static void AddReferenceIds(HashSet ids, ISchemaEntity schema, ResolvedComponents components, IEnumerable contents) { foreach (var content in contents) { - content.Data.AddReferencedIds(schema.SchemaDef.ResolvingReferences(), ids); + content.Data.AddReferencedIds(schema.SchemaDef.ResolvingReferences(), ids, components); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs index b17db069b..da667e89e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs @@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) { - var schema = await schemas(group.Key); + var (schema, _) = await schemas(group.Key); var script = schema.SchemaDef.Scripts.Query; diff --git a/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterVisitor.cs b/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterVisitor.cs index b55eb42d7..d15e73af1 100644 --- a/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterVisitor.cs +++ b/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterVisitor.cs @@ -11,25 +11,15 @@ using NJsonSchema; using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Validation; +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Infrastructure.Queries.Json { public sealed class JsonFilterVisitor : FilterNodeVisitor, IJsonValue, JsonFilterVisitor.Args> { private static readonly JsonFilterVisitor Instance = new JsonFilterVisitor(); - public struct Args - { - public readonly List Errors; - - public JsonSchema Schema; - - public Args(JsonSchema schema, List errors) - { - Schema = schema; - - Errors = errors; - } - } + public sealed record Args(JsonSchema Schema, List Errors); private JsonFilterVisitor() { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentOpenApiController.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentOpenApiController.cs index 6cf4322ac..a63ba3147 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentOpenApiController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentOpenApiController.cs @@ -64,7 +64,7 @@ namespace Squidex.Areas.Api.Controllers.Contents { var schemas = await appProvider.GetSchemasAsync(AppId); - var openApiDocument = schemasOpenApiGenerator.Generate(HttpContext, App, schemas); + var openApiDocument = await schemasOpenApiGenerator.GenerateAsync(HttpContext, App, schemas); return Content(openApiDocument.ToJson(), "application/json"); } @@ -77,7 +77,7 @@ namespace Squidex.Areas.Api.Controllers.Contents { var schemas = await appProvider.GetSchemasAsync(AppId); - var openApiDocument = schemasOpenApiGenerator.Generate(HttpContext, App, schemas, true); + var openApiDocument = await schemasOpenApiGenerator.GenerateAsync(HttpContext, App, schemas, true); return Content(openApiDocument.ToJson(), "application/json"); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/Builder.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/Builder.cs index 6137f4a64..416072a73 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/Builder.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/Builder.cs @@ -79,7 +79,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Generator return builder; } - public OperationsBuilder Schema(Schema schema, bool flat) + public OperationsBuilder Schema(Schema schema, ResolvedComponents components, bool flat) { var typeName = schema.TypeName(); @@ -87,7 +87,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Generator var dataSchema = ResolveSchema($"{typeName}DataDto", () => { - return schema.BuildDynamicJsonSchema(ResolveSchema); + return schema.BuildDynamicJsonSchema(ResolveSchema, components); }); var contentSchema = ResolveSchema($"{typeName}ContentDto", () => @@ -98,7 +98,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Generator { contentDataSchema = ResolveSchema($"{typeName}FlatDataDto", () => { - return schema.BuildFlatJsonSchema(ResolveSchema); + return schema.BuildFlatJsonSchema(ResolveSchema, components); }); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemasOpenApiGenerator.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemasOpenApiGenerator.cs index 5cb72fdba..22eda976d 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemasOpenApiGenerator.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemasOpenApiGenerator.cs @@ -8,11 +8,13 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using NJsonSchema; using NSwag; using NSwag.Generation; using NSwag.Generation.Processors.Contexts; +using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Hosting; @@ -25,24 +27,27 @@ namespace Squidex.Areas.Api.Controllers.Contents.Generator { public sealed class SchemasOpenApiGenerator { + private readonly IAppProvider appProvider; private readonly IUrlGenerator urlGenerator; private readonly OpenApiDocumentGeneratorSettings schemaSettings; private readonly OpenApiSchemaGenerator schemaGenerator; private readonly IRequestCache requestCache; public SchemasOpenApiGenerator( + IAppProvider appProvider, IUrlGenerator urlGenerator, OpenApiDocumentGeneratorSettings schemaSettings, OpenApiSchemaGenerator schemaGenerator, IRequestCache requestCache) { + this.appProvider = appProvider; this.urlGenerator = urlGenerator; this.schemaSettings = schemaSettings; this.schemaGenerator = schemaGenerator; this.requestCache = requestCache; } - public OpenApiDocument Generate(HttpContext httpContext, IAppEntity app, IEnumerable schemas, bool flat = false) + public async Task GenerateAsync(HttpContext httpContext, IAppEntity app, IEnumerable schemas, bool flat = false) { var document = CreateApiDocument(httpContext, app); @@ -68,7 +73,9 @@ namespace Squidex.Areas.Api.Controllers.Contents.Generator foreach (var schema in validSchemas) { - GenerateSchemaOperations(builder.Schema(schema.SchemaDef, flat)); + var components = await appProvider.GetComponentsAsync(schema); + + GenerateSchemaOperations(builder.Schema(schema.SchemaDef, components, flat)); } GenerateSharedOperations(builder.Shared()); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs index 299b7b026..d975e1616 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs @@ -458,7 +458,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas public void Should_serialize_and_deserialize_schema() { var schemaSource = - TestUtils.MixedSchema(SchemaType.Singleton, false) + TestUtils.MixedSchema(SchemaType.Singleton) .ChangeCategory("Category") .SetFieldRules(FieldRule.Hide("2")) .SetFieldsInLists("field2") diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionTests.cs index 847b3c421..14e7a67fb 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionTests.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Collections.Generic; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.ConvertContent; using Squidex.Domain.Apps.Core.Schemas; @@ -17,6 +18,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent public class ContentConversionTests { private readonly Schema schema; + private readonly ResolvedComponents components; public ContentConversionTests() { @@ -30,8 +32,10 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent .AddArray(6, "array", Partitioning.Invariant, a => a .AddAssets(31, "nested")); - schema.FieldsById[1].SetResolvedSchema(DomainId.Empty, schema); - schema.FieldsById[2].SetResolvedSchema(DomainId.Empty, schema); + components = new ResolvedComponents(new Dictionary + { + [DomainId.Empty] = schema + }); } [Fact] @@ -113,9 +117,11 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent JsonValue.Object())) .Add(Component.Discriminator, DomainId.Empty)))); + var converter = new ValueConverter((data, field, parent) => field.Name != "assets1" ? null : data); + var actual = source.Convert(schema, - FieldConverters.ForValues((data, field, parent) => field.Name != "assets1" ? null : data)); + FieldConverters.ForValues(components, converter)); Assert.Equal(expected, actual); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs index ed75238c6..ba6210096 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs @@ -38,7 +38,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent new ContentFieldData() .AddInvariant(JsonValue.Object()); - var result = FieldConverters.ForValues((value, field, parent) => null)(source, field); + var result = FieldConverters.ForValues(ResolvedComponents.Empty, (value, field, parent) => null)(source, field); var expected = new ContentFieldData(); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs index c4ee00a6d..ccd469c43 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs @@ -20,6 +20,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds public class ReferenceExtractionTests { private readonly Schema schema; + private readonly ResolvedComponents components; public ReferenceExtractionTests() { @@ -35,11 +36,10 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds .AddComponent(32, "nestedComponent") .AddComponents(33, "nestedComponents")); - schema.FieldsById[1].SetResolvedSchema(DomainId.Empty, schema); - schema.FieldsById[2].SetResolvedSchema(DomainId.Empty, schema); - - ((IArrayField)schema.FieldsById[6]).FieldsById[32].SetResolvedSchema(DomainId.Empty, schema); - ((IArrayField)schema.FieldsById[6]).FieldsById[33].SetResolvedSchema(DomainId.Empty, schema); + components = new ResolvedComponents(new Dictionary + { + [DomainId.Empty] = schema + }); } [Fact] @@ -56,7 +56,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var ids = new HashSet(); - input.AddReferencedIds(schema, ids); + input.AddReferencedIds(schema, ids, components); Assert.Equal(new[] { id1, id2 }, ids); } @@ -75,7 +75,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var ids = new HashSet(); - input.AddReferencedIds(schema, ids, 1); + input.AddReferencedIds(schema, ids, components, 1); Assert.Equal(new[] { id1 }, ids); } @@ -193,7 +193,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds .Add(Component.Discriminator, DomainId.Empty)))); var converter = - FieldConverters.ForValues( + FieldConverters.ForValues(components, ValueReferencesConverter.CleanReferences(new HashSet { id2 })); var actual = source.Convert(schema, converter); @@ -206,7 +206,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds { var sut = Fields.String(1, "my-string", Partitioning.Invariant); - var result = sut.GetReferencedIds(JsonValue.Create("invalid")).ToArray(); + var result = sut.GetReferencedIds(JsonValue.Create("invalid"), components).ToArray(); Assert.Empty(result); } @@ -225,7 +225,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds JsonValue.Object() .Add(field.Name, CreateValue(id1, id2))); - var result = arrayField.GetReferencedIds(value).ToArray(); + var result = arrayField.GetReferencedIds(value, components).ToArray(); Assert.Equal(new[] { id1, id2 }, result); } @@ -234,7 +234,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds [MemberData(nameof(ReferencingFields))] public void Should_return_empty_list_from_field_if_value_item_is_invalid(IField field) { - var result = field.GetReferencedIds(JsonValue.Array(1)).ToArray(); + var result = field.GetReferencedIds(JsonValue.Array(1), components).ToArray(); Assert.Empty(result); } @@ -243,7 +243,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds [MemberData(nameof(ReferencingFields))] public void Should_return_empty_list_from_field_if_value_is_empty(IField field) { - var result = field.GetReferencedIds(JsonValue.Array()).ToArray(); + var result = field.GetReferencedIds(JsonValue.Array(), components).ToArray(); Assert.Empty(result); } @@ -252,7 +252,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds [MemberData(nameof(ReferencingFields))] public void Should_return_empty_list_from_field_if_value_is_json_null(IField field) { - var result = field.GetReferencedIds(null).ToArray(); + var result = field.GetReferencedIds(null, components).ToArray(); Assert.Empty(result); } @@ -261,7 +261,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds [MemberData(nameof(ReferencingFields))] public void Should_return_empty_list_from_field_if_value_is_null(IField field) { - var result = field.GetReferencedIds(null).ToArray(); + var result = field.GetReferencedIds(null, components).ToArray(); Assert.Empty(result); } @@ -275,7 +275,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var value = CreateValue(id1, id2); - var result = field.GetReferencedIds(value); + var result = field.GetReferencedIds(value, components); Assert.Equal(new HashSet { id1, id2 }, result); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/GenerateEdmSchema/EdmTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/GenerateEdmSchema/EdmTests.cs index 4e5693b70..14ecfe119 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/GenerateEdmSchema/EdmTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/GenerateEdmSchema/EdmTests.cs @@ -8,6 +8,7 @@ using Microsoft.OData.Edm; using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.GenerateEdmSchema; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Infrastructure; using Xunit; @@ -40,7 +41,7 @@ namespace Squidex.Domain.Apps.Core.Operations.GenerateEdmSchema var edmModel = TestUtils.MixedSchema() - .BuildEdmType(true, languagesConfig.ToResolver(), typeFactory); + .BuildEdmType(true, languagesConfig.ToResolver(), typeFactory, ResolvedComponents.Empty); Assert.NotNull(edmModel); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/GenerateJsonSchema/JsonSchemaTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/GenerateJsonSchema/JsonSchemaTests.cs index e903c5e0a..273cc211d 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/GenerateJsonSchema/JsonSchemaTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/GenerateJsonSchema/JsonSchemaTests.cs @@ -18,7 +18,6 @@ namespace Squidex.Domain.Apps.Core.Operations.GenerateJsonSchema { public class JsonSchemaTests { - private const int MaxDepth = 5; private readonly Schema schema = TestUtils.MixedSchema(); [Fact] @@ -26,7 +25,7 @@ namespace Squidex.Domain.Apps.Core.Operations.GenerateJsonSchema { var languagesConfig = LanguagesConfig.English.Set(Language.DE); - var jsonSchema = schema.BuildJsonSchema(languagesConfig.ToResolver()); + var jsonSchema = schema.BuildJsonSchema(languagesConfig.ToResolver(), ResolvedComponents.Empty); CheckFields(jsonSchema); } @@ -36,7 +35,7 @@ namespace Squidex.Domain.Apps.Core.Operations.GenerateJsonSchema { var schemaResolver = new SchemaResolver((name, action) => action()); - var jsonSchema = schema.BuildDynamicJsonSchema(schemaResolver); + var jsonSchema = schema.BuildDynamicJsonSchema(schemaResolver, ResolvedComponents.Empty); CheckFields(jsonSchema); } @@ -51,7 +50,7 @@ namespace Squidex.Domain.Apps.Core.Operations.GenerateJsonSchema return action(); }); - var jsonSchema = schema.BuildFlatJsonSchema(schemaResolver); + var jsonSchema = schema.BuildFlatJsonSchema(schemaResolver, ResolvedComponents.Empty); CheckFields(jsonSchema); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ComponentFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ComponentFieldTests.cs index 5981fc1c8..eae29365e 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ComponentFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ComponentFieldTests.cs @@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public void Should_instantiate_field() { - var (_, sut) = Field(new ComponentFieldProperties()); + var (_, sut, _) = Field(new ComponentFieldProperties()); Assert.Equal("my-component", sut.Name); } @@ -32,9 +32,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_not_add_error_if_component_is_null_and_valid() { - var (_, sut) = Field(new ComponentFieldProperties()); + var (_, sut, components) = Field(new ComponentFieldProperties()); - await sut.ValidateAsync(null, errors); + await sut.ValidateAsync(null, errors, components: components); Assert.Empty(errors); } @@ -42,9 +42,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_not_add_error_if_component_is_valid() { - var (id, sut) = Field(new ComponentFieldProperties()); + var (id, sut, components) = Field(new ComponentFieldProperties()); - await sut.ValidateAsync(CreateValue(id.ToString(), "component-field", 1), errors); + await sut.ValidateAsync(CreateValue(id.ToString(), "component-field", 1), errors, components: components); Assert.Empty(errors); } @@ -52,9 +52,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_component_is_required() { - var (_, sut) = Field(new ComponentFieldProperties { IsRequired = true }); + var (_, sut, components) = Field(new ComponentFieldProperties { IsRequired = true }); - await sut.ValidateAsync(null, errors); + await sut.ValidateAsync(null, errors, components: components); errors.Should().BeEquivalentTo( new[] { "Field is required." }); @@ -63,9 +63,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_component_value_is_required() { - var (id, sut) = Field(new ComponentFieldProperties { IsRequired = true }, true); + var (id, sut, components) = Field(new ComponentFieldProperties { IsRequired = true }, true); - await sut.ValidateAsync(CreateValue(id.ToString(), "component-field", null), errors); + await sut.ValidateAsync(CreateValue(id.ToString(), "component-field", null), errors, components: components); errors.Should().BeEquivalentTo( new[] { "component-field: Field is required." }); @@ -74,9 +74,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_value_is_not_valid() { - var (_, sut) = Field(new ComponentFieldProperties()); + var (_, sut, components) = Field(new ComponentFieldProperties()); - await sut.ValidateAsync(JsonValue.Create("Invalid"), errors); + await sut.ValidateAsync(JsonValue.Create("Invalid"), errors, components: components); errors.Should().BeEquivalentTo( new[] { "Invalid json object, expected object with 'schemaId' field." }); @@ -85,9 +85,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_value_has_no_discriminator() { - var (_, sut) = Field(new ComponentFieldProperties()); + var (_, sut, components) = Field(new ComponentFieldProperties()); - await sut.ValidateAsync(CreateValue(null, "field", 1), errors); + await sut.ValidateAsync(CreateValue(null, "field", 1), errors, components: components); errors.Should().BeEquivalentTo( new[] { "Invalid component. No 'schemaId' field found." }); @@ -96,9 +96,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_value_has_invalid_discriminator() { - var (_, sut) = Field(new ComponentFieldProperties()); + var (_, sut, components) = Field(new ComponentFieldProperties()); - await sut.ValidateAsync(CreateValue("invalid", "field", 1), errors); + await sut.ValidateAsync(CreateValue("invalid", "field", 1), errors, components: components); errors.Should().BeEquivalentTo( new[] { "Invalid component. Cannot find schema." }); @@ -118,7 +118,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return obj; } - private static (DomainId, RootField) Field(ComponentFieldProperties properties, bool isRequired = false) + private static (DomainId, RootField, ResolvedComponents) Field(ComponentFieldProperties properties, bool isRequired = false) { var schema = new Schema("my-component") @@ -127,11 +127,14 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent var id = DomainId.NewGuid(); - var field = - Fields.Component(1, "my-component", Partitioning.Invariant, properties) - .SetResolvedSchema(id, schema); + var field = Fields.Component(1, "my-component", Partitioning.Invariant, properties); - return (id, field); + var components = new ResolvedComponents(new Dictionary + { + [id] = schema + }); + + return (id, field, components); } } } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ComponentsFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ComponentsFieldTests.cs index eba1084c4..43d1abd23 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ComponentsFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ComponentsFieldTests.cs @@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public void Should_instantiate_field() { - var (_, sut) = Field(new ComponentsFieldProperties()); + var (_, sut, _) = Field(new ComponentsFieldProperties()); Assert.Equal("my-components", sut.Name); } @@ -32,9 +32,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_not_add_error_if_components_are_null_and_valid() { - var (_, sut) = Field(new ComponentsFieldProperties()); + var (_, sut, components) = Field(new ComponentsFieldProperties()); - await sut.ValidateAsync(null, errors); + await sut.ValidateAsync(null, errors, components: components); Assert.Empty(errors); } @@ -42,9 +42,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_not_add_error_if_components_is_valid() { - var (id, sut) = Field(new ComponentsFieldProperties()); + var (id, sut, components) = Field(new ComponentsFieldProperties()); - await sut.ValidateAsync(CreateValue(1, id.ToString(), "component-field", 1), errors); + await sut.ValidateAsync(CreateValue(1, id.ToString(), "component-field", 1), errors, components: components); Assert.Empty(errors); } @@ -52,9 +52,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_not_add_error_if_number_of_components_is_equal_to_min_and_max_components() { - var (id, sut) = Field(new ComponentsFieldProperties { MinItems = 2, MaxItems = 2 }); + var (id, sut, components) = Field(new ComponentsFieldProperties { MinItems = 2, MaxItems = 2 }); - await sut.ValidateAsync(CreateValue(2, id.ToString(), "component-field", 1), errors); + await sut.ValidateAsync(CreateValue(2, id.ToString(), "component-field", 1), errors, components: components); Assert.Empty(errors); } @@ -62,9 +62,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_components_are_required() { - var (_, sut) = Field(new ComponentsFieldProperties { IsRequired = true }); + var (_, sut, components) = Field(new ComponentsFieldProperties { IsRequired = true }); - await sut.ValidateAsync(null, errors); + await sut.ValidateAsync(null, errors, components: components); errors.Should().BeEquivalentTo( new[] { "Field is required." }); @@ -73,9 +73,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_components_value_is_required() { - var (id, sut) = Field(new ComponentsFieldProperties { IsRequired = true }, true); + var (id, sut, components) = Field(new ComponentsFieldProperties { IsRequired = true }, true); - await sut.ValidateAsync(CreateValue(1, id.ToString(), "component-field", null), errors); + await sut.ValidateAsync(CreateValue(1, id.ToString(), "component-field", null), errors, components: components); errors.Should().BeEquivalentTo( new[] { "[1].component-field: Field is required." }); @@ -84,9 +84,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_value_is_not_valid() { - var (_, sut) = Field(new ComponentsFieldProperties()); + var (_, sut, components) = Field(new ComponentsFieldProperties()); - await sut.ValidateAsync(JsonValue.Create("Invalid"), errors); + await sut.ValidateAsync(JsonValue.Create("Invalid"), errors, components: components); errors.Should().BeEquivalentTo( new[] { "Invalid json type, expected array of objects." }); @@ -95,9 +95,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_component_is_not_valid() { - var (_, sut) = Field(new ComponentsFieldProperties()); + var (_, sut, components) = Field(new ComponentsFieldProperties()); - await sut.ValidateAsync(JsonValue.Array(JsonValue.Create("Invalid")), errors); + await sut.ValidateAsync(JsonValue.Array(JsonValue.Create("Invalid")), errors, components: components); errors.Should().BeEquivalentTo( new[] { "Invalid json object, expected object with 'schemaId' field." }); @@ -106,9 +106,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_component_has_no_discriminator() { - var (_, sut) = Field(new ComponentsFieldProperties()); + var (_, sut, components) = Field(new ComponentsFieldProperties()); - await sut.ValidateAsync(CreateValue(1, null, "field", 1), errors); + await sut.ValidateAsync(CreateValue(1, null, "field", 1), errors, components: components); errors.Should().BeEquivalentTo( new[] { "Invalid component. No 'schemaId' field found." }); @@ -117,9 +117,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_value_has_invalid_discriminator() { - var (_, sut) = Field(new ComponentsFieldProperties()); + var (_, sut, components) = Field(new ComponentsFieldProperties()); - await sut.ValidateAsync(CreateValue(1, "invalid", "field", 1), errors); + await sut.ValidateAsync(CreateValue(1, "invalid", "field", 1), errors, components: components); errors.Should().BeEquivalentTo( new[] { "Invalid component. Cannot find schema." }); @@ -128,9 +128,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_value_has_not_enough_components() { - var (id, sut) = Field(new ComponentsFieldProperties { MinItems = 3 }); + var (id, sut, components) = Field(new ComponentsFieldProperties { MinItems = 3 }); - await sut.ValidateAsync(CreateValue(2, id.ToString(), "component-field", 1), errors); + await sut.ValidateAsync(CreateValue(2, id.ToString(), "component-field", 1), errors, components: components); errors.Should().BeEquivalentTo( new[] { "Must have at least 3 item(s)." }); @@ -139,9 +139,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent [Fact] public async Task Should_add_error_if_value_has_too_much_components() { - var (id, sut) = Field(new ComponentsFieldProperties { MaxItems = 1 }); + var (id, sut, components) = Field(new ComponentsFieldProperties { MaxItems = 1 }); - await sut.ValidateAsync(CreateValue(2, id.ToString(), "component-field", 1), errors); + await sut.ValidateAsync(CreateValue(2, id.ToString(), "component-field", 1), errors, components: components); errors.Should().BeEquivalentTo( new[] { "Must not have more than 1 item(s)." }); @@ -168,7 +168,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return result; } - private static (DomainId, RootField) Field(ComponentsFieldProperties properties, bool isRequired = false) + private static (DomainId, RootField, ResolvedComponents) Field(ComponentsFieldProperties properties, bool isRequired = false) { var schema = new Schema("my-component") @@ -177,11 +177,14 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent var id = DomainId.NewGuid(); - var field = - Fields.Components(1, "my-components", Partitioning.Invariant, properties) - .SetResolvedSchema(id, schema); + var field = Fields.Components(1, "my-components", Partitioning.Invariant, properties); - return (id, field); + var components = new ResolvedComponents(new Dictionary + { + [id] = schema + }); + + return (id, field, components); } } } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs index 7d9375d16..1731e039b 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs @@ -31,9 +31,11 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent Schema? schema = null, ValidationMode mode = ValidationMode.Default, ValidationUpdater? updater = null, - ValidationAction action = ValidationAction.Upsert) + ValidationAction action = ValidationAction.Upsert, + ResolvedComponents? components = null, + DomainId? contentId = null) { - var context = CreateContext(schema, mode, updater, action); + var context = CreateContext(schema, mode, updater, action, components, contentId); return validator.ValidateAsync(value, context, CreateFormatter(errors)); } @@ -43,9 +45,11 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent ValidationMode mode = ValidationMode.Default, ValidationUpdater? updater = null, IValidatorsFactory? factory = null, - ValidationAction action = ValidationAction.Upsert) + ValidationAction action = ValidationAction.Upsert, + ResolvedComponents? components = null, + DomainId? contentId = null) { - var context = CreateContext(schema, mode, updater, action); + var context = CreateContext(schema, mode, updater, action, components, contentId); var validator = new ValidatorBuilder(factory, context).ValueValidator(field); @@ -57,9 +61,11 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent ValidationMode mode = ValidationMode.Default, ValidationUpdater? updater = null, IValidatorsFactory? factory = null, - ValidationAction action = ValidationAction.Upsert) + ValidationAction action = ValidationAction.Upsert, + ResolvedComponents? components = null, + DomainId? contentId = null) { - var context = CreateContext(schema, mode, updater, action); + var context = CreateContext(schema, mode, updater, action, components, contentId); var validator = new ValidatorBuilder(factory, context).ContentValidator(partitionResolver); @@ -76,9 +82,11 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent ValidationMode mode = ValidationMode.Default, ValidationUpdater? updater = null, IValidatorsFactory? factory = null, - ValidationAction action = ValidationAction.Upsert) + ValidationAction action = ValidationAction.Upsert, + ResolvedComponents? components = null, + DomainId? contentId = null) { - var context = CreateContext(schema, mode, updater, action); + var context = CreateContext(schema, mode, updater, action, components, contentId); var validator = new ValidatorBuilder(factory, context).ContentValidator(partitionResolver); @@ -109,14 +117,17 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent Schema? schema = null, ValidationMode mode = ValidationMode.Default, ValidationUpdater? updater = null, - ValidationAction action = ValidationAction.Upsert) + ValidationAction action = ValidationAction.Upsert, + ResolvedComponents? components = null, + DomainId? contentId = null) { var context = new ValidationContext( TestUtils.DefaultSerializer, AppId, SchemaId, schema ?? new Schema(SchemaId.Name), - DomainId.NewGuid()); + components ?? ResolvedComponents.Empty, + contentId ?? DomainId.NewGuid()); context = context.WithMode(mode).WithAction(action); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs index 7eb7956fa..03b275a7e 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs @@ -82,7 +82,7 @@ namespace Squidex.Domain.Apps.Core.TestHelpers return new NewtonsoftJsonSerializer(serializerSettings); } - public static Schema MixedSchema(SchemaType type = SchemaType.Default, bool withMetadata = true) + public static Schema MixedSchema(SchemaType type = SchemaType.Default) { var componentId = DomainId.NewGuid(); @@ -135,12 +135,6 @@ namespace Squidex.Domain.Apps.Core.TestHelpers .DisableField(212, 101) .LockField(105); - if (withMetadata) - { - schema.FieldsById[114].SetResolvedSchema(componentId, schema); - schema.FieldsById[115].SetResolvedSchema(componentId, schema); - } - return schema; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs index 225d8bbc7..0320061f4 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { public class ContentEnricherTests { - private readonly IContentQueryService contentQuery = A.Fake(); + private readonly IAppProvider appProvider = A.Fake(); private readonly ISchemaEntity schema; private readonly Context requestContext; private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); @@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) { - Schema = await schemas(group.Key); + Schema = (await schemas(group.Key)).Schema; } } } @@ -47,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries schema = Mocks.Schema(appId, schemaId); - A.CallTo(() => contentQuery.GetSchemaOrThrowAsync(requestContext, schemaId.Id.ToString())) + A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false)) .Returns(schema); } @@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries var step1 = A.Fake(); var step2 = A.Fake(); - var sut = new ContentEnricher(new[] { step1, step2 }, new Lazy(() => contentQuery)); + var sut = new ContentEnricher(new[] { step1, step2 }, appProvider); await sut.EnrichAsync(source, requestContext, default); @@ -84,7 +84,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries var step1 = A.Fake(); var step2 = A.Fake(); - var sut = new ContentEnricher(new[] { step1, step2 }, new Lazy(() => contentQuery)); + var sut = new ContentEnricher(new[] { step1, step2 }, appProvider); await sut.EnrichAsync(source, false, requestContext, default); @@ -109,14 +109,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries var step1 = new ResolveSchema(); var step2 = new ResolveSchema(); - var sut = new ContentEnricher(new[] { step1, step2 }, new Lazy(() => contentQuery)); + var sut = new ContentEnricher(new[] { step1, step2 }, appProvider); await sut.EnrichAsync(source, false, requestContext, default); Assert.Same(schema, step1.Schema); Assert.Same(schema, step1.Schema); - A.CallTo(() => contentQuery.GetSchemaOrThrowAsync(requestContext, schemaId.Id.ToString())) + A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false)) .MustHaveHappenedOnceExactly(); } @@ -125,7 +125,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var source = CreateContent(new ContentData()); - var sut = new ContentEnricher(Enumerable.Empty(), new Lazy(() => contentQuery)); + var sut = new ContentEnricher(Enumerable.Empty(), appProvider); var result = await sut.EnrichAsync(source, true, requestContext, default); @@ -137,7 +137,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var source = CreateContent(new ContentData()); - var sut = new ContentEnricher(Enumerable.Empty(), new Lazy(() => contentQuery)); + var sut = new ContentEnricher(Enumerable.Empty(), appProvider); var result = await sut.EnrichAsync(source, false, requestContext, default); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs index 2cada6f86..22aa0d054 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs @@ -26,6 +26,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { public class ContentQueryParserTests { + private readonly IAppProvider appProvider = A.Fake(); private readonly ITextIndex textIndex = A.Fake(); private readonly ISchemaEntity schema; private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); @@ -48,7 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries var cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); - sut = new ContentQueryParser(cache, TestUtils.DefaultSerializer, textIndex, options); + sut = new ContentQueryParser(appProvider, textIndex, options, cache, TestUtils.DefaultSerializer); } [Fact] diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs index 4a35ff594..78da33de8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs @@ -47,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries .AddAssets(31, "nested")); schema = Mocks.Schema(appId, schemaId, schemaDef); - schemaProvider = x => Task.FromResult(schema); + schemaProvider = x => Task.FromResult((schema, ResolvedComponents.Empty)); sut = new ConvertData(urlGenerator, TestUtils.DefaultSerializer, assetRepository, contentRepository); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs index d06a3f327..0380b82f9 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using FakeItEasy; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Contents.Queries.Steps; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; @@ -34,7 +35,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries requestContext = new Context(Mocks.ApiUser(), Mocks.App(appId)); schema = Mocks.Schema(appId, schemaId); - schemaProvider = x => Task.FromResult(schema); + schemaProvider = x => Task.FromResult((schema, ResolvedComponents.Empty)); sut = new EnrichForCaching(requestCache); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs index 00cf1a315..b96879394 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading.Tasks; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Contents.Queries.Steps; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; @@ -26,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries public EnrichWithSchemaTests() { schema = Mocks.Schema(appId, schemaId); - schemaProvider = x => Task.FromResult(schema); + schemaProvider = x => Task.FromResult((schema, ResolvedComponents.Empty)); sut = new EnrichWithSchema(); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs index d814d252a..df891871d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs @@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { if (x == schemaId.Id) { - return Task.FromResult(Mocks.Schema(appId, schemaId, schemaDef)); + return Task.FromResult((Mocks.Schema(appId, schemaId, schemaDef), ResolvedComponents.Empty)); } else { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs index 7bf072584..0b770d671 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs @@ -69,15 +69,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { if (x == schemaId.Id) { - return Task.FromResult(Mocks.Schema(appId, schemaId, schemaDef)); + return Task.FromResult((Mocks.Schema(appId, schemaId, schemaDef), ResolvedComponents.Empty)); } else if (x == refSchemaId1.Id) { - return Task.FromResult(Mocks.Schema(appId, refSchemaId1, refSchemaDef)); + return Task.FromResult((Mocks.Schema(appId, refSchemaId1, refSchemaDef), ResolvedComponents.Empty)); } else if (x == refSchemaId2.Id) { - return Task.FromResult(Mocks.Schema(appId, refSchemaId2, refSchemaDef)); + return Task.FromResult((Mocks.Schema(appId, refSchemaId2, refSchemaDef), ResolvedComponents.Empty)); } else { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs index c074b384c..a2d6bc95b 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs @@ -42,11 +42,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { if (x == schemaId.Id) { - return Task.FromResult(Mocks.Schema(appId, schemaId, schemaDef)); + return Task.FromResult((Mocks.Schema(appId, schemaId, schemaDef), ResolvedComponents.Empty)); } else if (x == schemaWithScriptId.Id) { - return Task.FromResult(Mocks.Schema(appId, schemaWithScriptId, schemaDefWithScript)); + return Task.FromResult((Mocks.Schema(appId, schemaWithScriptId, schemaDefWithScript), ResolvedComponents.Empty)); } else { diff --git a/frontend/app/shared/state/contents.forms.ts b/frontend/app/shared/state/contents.forms.ts index 115e7363a..3016ff144 100644 --- a/frontend/app/shared/state/contents.forms.ts +++ b/frontend/app/shared/state/contents.forms.ts @@ -601,8 +601,6 @@ export class ComponentForm extends ObjectForm { if (schemaId) { this.selectSchema(schemaId); - } else if (this.properties.schemaIds?.length === 1) { - this.selectSchema(this.properties.schemaIds[0]); } }