diff --git a/backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs b/backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs index 245fbd16e..d770dc901 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs @@ -173,23 +173,23 @@ namespace Squidex.Extensions.Actions.Kafka avroProducer?.Dispose(); } - private static object GetValue(IJsonValue value, Schema schema) + private static object GetValue(JsonValue value, Schema schema) { - switch (value) + switch (value.Type) { - case JsonString s when IsTypeOrUnionWith(schema, Schema.Type.String): - return s.Value; - case JsonNumber n when IsTypeOrUnionWith(schema, Schema.Type.Long): - return (long)n.Value; - case JsonNumber n when IsTypeOrUnionWith(schema, Schema.Type.Float): - return (float)n.Value; - case JsonNumber n when IsTypeOrUnionWith(schema, Schema.Type.Int): - return (int)n.Value; - case JsonNumber n when IsTypeOrUnionWith(schema, Schema.Type.Double): - return n.Value; - case JsonBoolean b when IsTypeOrUnionWith(schema, Schema.Type.Boolean): - return b.Value; - case JsonObject o when IsTypeOrUnionWith(schema, Schema.Type.Map): + case JsonValueType.String when IsTypeOrUnionWith(schema, Schema.Type.String): + return value.AsString; + case JsonValueType.Number when IsTypeOrUnionWith(schema, Schema.Type.Long): + return (long)value.AsNumber; + case JsonValueType.Number when IsTypeOrUnionWith(schema, Schema.Type.Float): + return (float)value.AsNumber; + case JsonValueType.Number when IsTypeOrUnionWith(schema, Schema.Type.Int): + return (int)value.AsNumber; + case JsonValueType.Number when IsTypeOrUnionWith(schema, Schema.Type.Double): + return value.AsNumber; + case JsonValueType.Boolean when IsTypeOrUnionWith(schema, Schema.Type.Boolean): + return value.AsBoolean; + case JsonValueType.Object when IsTypeOrUnionWith(schema, Schema.Type.Map): { var mapResult = new Dictionary(); @@ -197,14 +197,14 @@ namespace Squidex.Extensions.Actions.Kafka { var map = (MapSchema)union.Schemas.FirstOrDefault(x => x.Tag == Schema.Type.Map); - foreach (var (key, childValue) in o) + foreach (var (key, childValue) in value.AsObject) { mapResult.Add(key, GetValue(childValue, map?.ValueSchema)); } } else if (schema is MapSchema map) { - foreach (var (key, childValue) in o) + foreach (var (key, childValue) in value.AsObject) { mapResult.Add(key, GetValue(childValue, map?.ValueSchema)); } @@ -213,7 +213,7 @@ namespace Squidex.Extensions.Actions.Kafka return mapResult; } - case JsonObject o when IsTypeOrUnionWith(schema, Schema.Type.Record): + case JsonValueType.Object when IsTypeOrUnionWith(schema, Schema.Type.Record): { GenericRecord result = null; @@ -223,7 +223,7 @@ namespace Squidex.Extensions.Actions.Kafka result = new GenericRecord(record); - foreach (var (key, childValue) in o) + foreach (var (key, childValue) in value.AsObject) { if (record != null && record.TryGetField(key, out var field)) { @@ -235,7 +235,7 @@ namespace Squidex.Extensions.Actions.Kafka { result = new GenericRecord(record); - foreach (var (key, childValue) in o) + foreach (var (key, childValue) in value.AsObject) { if (record.TryGetField(key, out var field)) { @@ -247,7 +247,7 @@ namespace Squidex.Extensions.Actions.Kafka return result; } - case JsonArray a when IsTypeOrUnionWith(schema, Schema.Type.Array): + case JsonValueType.Array when IsTypeOrUnionWith(schema, Schema.Type.Array): { var result = new List(); @@ -255,14 +255,14 @@ namespace Squidex.Extensions.Actions.Kafka { var arraySchema = (ArraySchema)union.Schemas.FirstOrDefault(x => x.Tag == Schema.Type.Array); - foreach (var item in a) + foreach (var item in value.AsArray) { result.Add(GetValue(item, arraySchema?.ItemSchema)); } } else if (schema is ArraySchema array) { - foreach (var item in a) + foreach (var item in value.AsArray) { result.Add(GetValue(item, array.ItemSchema)); } diff --git a/backend/extensions/Squidex.Extensions/Actions/Script/ScriptActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Script/ScriptActionHandler.cs index b7da1629a..6c3138079 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Script/ScriptActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Script/ScriptActionHandler.cs @@ -41,7 +41,7 @@ namespace Squidex.Extensions.Actions.Script var result = await scriptEngine.ExecuteAsync(vars, job.Script, ct: ct); - return Result.Success(result?.ToString()); + return Result.Success(result.ToString()); } } diff --git a/backend/extensions/Squidex.Extensions/Samples/Middleware/DoubleLinkedContentMiddleware.cs b/backend/extensions/Squidex.Extensions/Samples/Middleware/DoubleLinkedContentMiddleware.cs index 8f4b0747a..0c52bb75d 100644 --- a/backend/extensions/Squidex.Extensions/Samples/Middleware/DoubleLinkedContentMiddleware.cs +++ b/backend/extensions/Squidex.Extensions/Samples/Middleware/DoubleLinkedContentMiddleware.cs @@ -102,7 +102,7 @@ namespace Squidex.Extensions.Samples.Middleware { if (data != null && data.TryGetValue("reference", out ContentFieldData fieldData)) { - return fieldData.Values.OfType().SelectMany(x => x).SingleOrDefault()?.ToString(); + return fieldData.Values.OfType().SelectMany(x => x).SingleOrDefault().ToString(); } return null; diff --git a/backend/extensions/Squidex.Extensions/Validation/CompositeUniqueValidator.cs b/backend/extensions/Squidex.Extensions/Validation/CompositeUniqueValidator.cs index 18990457b..0f11299fb 100644 --- a/backend/extensions/Squidex.Extensions/Validation/CompositeUniqueValidator.cs +++ b/backend/extensions/Squidex.Extensions/Validation/CompositeUniqueValidator.cs @@ -65,7 +65,7 @@ namespace Squidex.Extensions.Validation if (data.TryGetValue(field.Name, out var fieldValue)) { - if (fieldValue.TryGetValue(InvariantPartitioning.Key, out var temp) && temp != null) + if (fieldValue.TryGetValue(InvariantPartitioning.Key, out var temp) && temp != default) { value = temp; } @@ -73,20 +73,27 @@ namespace Squidex.Extensions.Validation switch (field.RawProperties) { - case BooleanFieldProperties when value is JsonBoolean boolean: - return boolean.Value; - case BooleanFieldProperties when value is JsonNull: + case BooleanFieldProperties when value.Type == JsonValueType.Boolean: + return value.AsBoolean; + case BooleanFieldProperties when value.Type == JsonValueType.Null: return ClrValue.Null; - case NumberFieldProperties when value is JsonNumber number: - return number.Value; - case NumberFieldProperties when value is JsonNull: + case NumberFieldProperties when value.Type == JsonValueType.Number: + return value.AsNumber; + case NumberFieldProperties when value.Type == JsonValueType.Null: return ClrValue.Null; - case StringFieldProperties when value is JsonString @string: - return @string.Value; - case StringFieldProperties when value is JsonNull: + case StringFieldProperties when value.Type == JsonValueType.String: + return value.AsString; + case StringFieldProperties when value.Type == JsonValueType.Null: return ClrValue.Null; - case ReferencesFieldProperties when value is JsonArray array && array.FirstOrDefault() is JsonString @string: - return @string.Value; + case ReferencesFieldProperties when value.Type == JsonValueType.Array: + var first = value.AsArray.FirstOrDefault(); + + if (first.Type == JsonValueType.String) + { + return first.AsString; + } + + break; } return null; diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Json/RolesSurrogate.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Json/RolesSurrogate.cs index ad244a0ba..ce790f842 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Json/RolesSurrogate.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Json/RolesSurrogate.cs @@ -11,21 +11,21 @@ using Squidex.Infrastructure.Security; namespace Squidex.Domain.Apps.Core.Apps.Json { - public sealed class RolesSurrogate : Dictionary, ISurrogate + public sealed class RolesSurrogate : Dictionary, ISurrogate { public void FromSource(Roles source) { foreach (var customRole in source.Custom) { - var permissions = JsonValue.Array(); + var permissions = new JsonArray(); foreach (var permission in customRole.Permissions) { - permissions.Add(JsonValue.Create(permission.Id)); + permissions.Add(permission.Id); } var role = - JsonValue.Object() + new JsonObject() .Add("permissions", permissions) .Add("properties", customRole.Properties); @@ -44,26 +44,28 @@ namespace Squidex.Domain.Apps.Core.Apps.Json { var (key, value) = x; - var properties = JsonValue.Object(); + var properties = new JsonObject(); var permissions = PermissionSet.Empty; - if (value is JsonArray array) + if (value.Type == JsonValueType.Array) { + var array = value.AsArray; + if (array.Count > 0) { - permissions = new PermissionSet(array.OfType().Select(x => x.ToString())); + permissions = new PermissionSet(array.Where(x => x.Type == JsonValueType.String).Select(x => x.AsString)); } } - else if (value is JsonObject obj) + else if (value.Type == JsonValueType.Object) { - if (obj.TryGetValue("permissions", out array!) && array.Count > 0) + if (value.TryGetValue(JsonValueType.Array, "permissions", out var array)) { - permissions = new PermissionSet(array.OfType().Select(x => x.ToString())); + permissions = new PermissionSet(array.AsArray.Where(x => x.Type == JsonValueType.String).Select(x => x.AsString)); } - if (!obj.TryGetValue("properties", out properties)) + if (value.TryGetValue(JsonValueType.Object, "properties", out var obj)) { - properties = JsonValue.Object(); + properties = obj.AsObject; } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Role.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Role.cs index c23083106..7889796f0 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Role.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Role.cs @@ -37,10 +37,10 @@ namespace Squidex.Domain.Apps.Core.Apps public string Name { get; } = Guard.NotNullOrEmpty(Name); - public PermissionSet Permissions { get; } = Permissions ?? PermissionSet.Empty; - public JsonObject Properties { get; } = Properties ?? new JsonObject(); + public PermissionSet Permissions { get; } = Permissions ?? PermissionSet.Empty; + public bool IsDefault { get => Roles.IsDefault(this); @@ -48,7 +48,7 @@ namespace Squidex.Domain.Apps.Core.Apps public static Role WithPermissions(string name, params string[] permissions) { - return new Role(name, new PermissionSet(permissions), JsonValue.Object()); + return new Role(name, new PermissionSet(permissions), new JsonObject()); } public static Role WithProperties(string name, JsonObject properties) diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Roles.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Roles.cs index d65577ec5..a705f8838 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Roles.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Apps/Roles.cs @@ -25,13 +25,13 @@ namespace Squidex.Domain.Apps.Core.Apps new Role(Role.Owner, new PermissionSet( WithoutPrefix(Permissions.App)), - JsonValue.Object()), + new JsonObject()), [Role.Reader] = new Role(Role.Reader, new PermissionSet( WithoutPrefix(Permissions.AppAssetsRead), WithoutPrefix(Permissions.AppContentsRead)), - JsonValue.Object() + new JsonObject() .Add("ui.api.hide", true)), [Role.Editor] = new Role(Role.Editor, @@ -40,7 +40,7 @@ namespace Squidex.Domain.Apps.Core.Apps WithoutPrefix(Permissions.AppContents), WithoutPrefix(Permissions.AppRolesRead), WithoutPrefix(Permissions.AppWorkflowsRead)), - JsonValue.Object() + new JsonObject() .Add("ui.api.hide", true)), [Role.Developer] = new Role(Role.Developer, @@ -51,7 +51,7 @@ namespace Squidex.Domain.Apps.Core.Apps WithoutPrefix(Permissions.AppRules), WithoutPrefix(Permissions.AppSchemas), WithoutPrefix(Permissions.AppWorkflows)), - JsonValue.Object()) + new JsonObject()) }; public static readonly Roles Empty = new Roles(new ReadonlyDictionary()); @@ -105,7 +105,7 @@ namespace Squidex.Domain.Apps.Core.Apps return this; } - var newRole = new Role(name); + var newRole = new Role(name, null, new JsonObject()); if (!inner.TryAdd(name, newRole, out var updated)) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetMetadata.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetMetadata.cs index 80b7db170..7b5d346f4 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetMetadata.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetMetadata.cs @@ -10,7 +10,7 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Core.Assets { - public sealed class AssetMetadata : Dictionary + public sealed class AssetMetadata : Dictionary { private static readonly char[] PathSeparators = { '.', '[', ']' }; @@ -23,42 +23,42 @@ namespace Squidex.Domain.Apps.Core.Assets public AssetMetadata SetFocusX(float value) { - this[FocusX] = JsonValue.Create(value); + this[FocusX] = (double)value; return this; } public AssetMetadata SetFocusY(float value) { - this[FocusY] = JsonValue.Create(value); + this[FocusY] = (double)value; return this; } public AssetMetadata SetPixelWidth(int value) { - this[PixelWidth] = JsonValue.Create(value); + this[PixelWidth] = (double)value; return this; } public AssetMetadata SetPixelHeight(int value) { - this[PixelHeight] = JsonValue.Create(value); + this[PixelHeight] = (double)value; return this; } public AssetMetadata SetVideoWidth(int value) { - this[VideoWidth] = JsonValue.Create(value); + this[VideoWidth] = (double)value; return this; } public AssetMetadata SetVideoHeight(int value) { - this[VideoHeight] = JsonValue.Create(value); + this[VideoHeight] = (double)value; return this; } @@ -95,9 +95,9 @@ namespace Squidex.Domain.Apps.Core.Assets public int? GetIn32(string name) { - if (TryGetValue(name, out var n) && n is JsonNumber number) + if (TryGetValue(name, out var n) && n.Type == JsonValueType.Number) { - return (int)number.Value; + return (int)n.AsNumber; } return null; @@ -105,9 +105,9 @@ namespace Squidex.Domain.Apps.Core.Assets public float? GetSingle(string name) { - if (TryGetValue(name, out var n) && n is JsonNumber number) + if (TryGetValue(name, out var n) && n.Type == JsonValueType.Number) { - return (float)number.Value; + return (float)n.AsNumber; } return null; @@ -115,9 +115,9 @@ namespace Squidex.Domain.Apps.Core.Assets public bool TryGetNumber(string name, out double result) { - if (TryGetValue(name, out var v) && v is JsonNumber n) + if (TryGetValue(name, out var n) && n.Type == JsonValueType.Number) { - result = n.Value; + result = n.AsNumber; return true; } @@ -129,9 +129,9 @@ namespace Squidex.Domain.Apps.Core.Assets public bool TryGetString(string name, [MaybeNullWhen(false)] out string result) { - if (TryGetValue(name, out var v) && v is JsonString s) + if (TryGetValue(name, out var s) && s.Type == JsonValueType.String) { - result = s.Value; + result = s.AsString; return true; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Component.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Component.cs index 67a23a16b..d5e96ef7c 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Component.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Component.cs @@ -20,30 +20,32 @@ namespace Squidex.Domain.Apps.Core.Contents public string Type { get; } = Guard.NotNullOrEmpty(Type); - public JsonObject Data { get; } = Guard.NotNull(Data); - public Schema Schema { get; } = Guard.NotNull(Schema); - public static bool IsValid(IJsonValue? value, [MaybeNullWhen(false)] out string discriminator) + public JsonObject Data { get; } = Guard.NotNull(Data); + + public static bool IsValid(JsonValue value, [MaybeNullWhen(false)] out string discriminator) { discriminator = null!; - if (value is not JsonObject obj) + if (value.Type != JsonValueType.Object) { return false; } - if (!obj.TryGetValue(Discriminator, out var type)) + if (!value.AsObject.TryGetValue(Discriminator, out var type) || type.Type != JsonValueType.String) { return false; } - if (string.IsNullOrWhiteSpace(type.Value)) + var typed = type.AsString; + + if (string.IsNullOrWhiteSpace(typed)) { return false; } - discriminator = type.Value; + discriminator = typed; return true; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/ContentData.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/ContentData.cs index 3a9dad1b6..6eb518452 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/ContentData.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/ContentData.cs @@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Core.Contents { foreach (var (language, value) in fieldData.ToList()) { - if (!otherField.TryGetValue(language, out var otherValue) || otherValue == null) + if (!otherField.TryGetValue(language, out var otherValue)) { continue; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/ContentFieldData.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/ContentFieldData.cs index c22443b2e..c4f661de9 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/ContentFieldData.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/ContentFieldData.cs @@ -7,32 +7,37 @@ using System.Diagnostics.CodeAnalysis; using Squidex.Infrastructure; +using Squidex.Infrastructure.Collections; using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Core.Contents { - public sealed class ContentFieldData : Dictionary, IEquatable + public sealed class ContentFieldData : ListDictionary, IEquatable { public ContentFieldData() - : base(StringComparer.OrdinalIgnoreCase) + : base(0, StringComparer.OrdinalIgnoreCase) { } - public ContentFieldData(ContentFieldData source) - : base(source, StringComparer.OrdinalIgnoreCase) + public ContentFieldData(int capacity) + : base(capacity, StringComparer.OrdinalIgnoreCase) { } - public ContentFieldData(int capacity) - : base(capacity, StringComparer.OrdinalIgnoreCase) + public ContentFieldData(ContentFieldData source) + : base(source.Count, StringComparer.OrdinalIgnoreCase) { + foreach (var (key, value) in source) + { + this[key] = value; + } } - public bool TryGetNonNull(string key, [MaybeNullWhen(false)] out IJsonValue result) + public bool TryGetNonNull(string key, [MaybeNullWhen(false)] out JsonValue result) { - result = null!; + result = JsonValue.Null; - if (TryGetValue(key, out var found) && found != null && found.Type != JsonValueType.Null) + if (TryGetValue(key, out var found) && found.Type != JsonValueType.Null) { result = found; return true; @@ -41,19 +46,16 @@ namespace Squidex.Domain.Apps.Core.Contents return false; } - public ContentFieldData AddInvariant(object? value) + public ContentFieldData AddInvariant(JsonValue value) { - return AddValue(InvariantPartitioning.Key, JsonValue.Create(value)); - } + this[InvariantPartitioning.Key] = value; - public ContentFieldData AddLocalized(string key, object? value) - { - return AddValue(key, JsonValue.Create(value)); + return this; } - public ContentFieldData AddValue(string key, IJsonValue? value) + public ContentFieldData AddLocalized(string key, JsonValue value) { - this[key] = JsonValue.Create(value); + this[key] = value; return this; } @@ -64,7 +66,7 @@ namespace Squidex.Domain.Apps.Core.Contents foreach (var (key, value) in this) { - clone[key] = value?.Clone()!; + clone[key] = value.Clone()!; } return clone; @@ -87,7 +89,7 @@ namespace Squidex.Domain.Apps.Core.Contents public override string ToString() { - return $"{{{string.Join(", ", this.Select(x => $"\"{x.Key}\":{x.Value.ToJsonString()}"))}}}"; + return $"{{{string.Join(", ", this.Select(x => $"\"{x.Key}\":{x.Value}"))}}}"; } } -} \ No newline at end of file +} diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/FlatContentData.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/FlatContentData.cs index 774e9c622..ed53a9704 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/FlatContentData.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/FlatContentData.cs @@ -9,7 +9,7 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Core.Contents { - public sealed class FlatContentData : Dictionary + public sealed class FlatContentData : Dictionary { } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/GeoJsonValue.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/GeoJsonValue.cs index e07f71819..7dc6852df 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/GeoJsonValue.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/GeoJsonValue.cs @@ -8,6 +8,7 @@ using GeoJSON.Net; using GeoJSON.Net.Geometry; using Squidex.Infrastructure; +using Squidex.Infrastructure.Collections; using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.ObjectPool; @@ -17,31 +18,33 @@ namespace Squidex.Domain.Apps.Core.Contents { public static class GeoJsonValue { - public static GeoJsonParseResult TryParse(IJsonValue value, IJsonSerializer serializer, out GeoJSONObject? geoJSON) + public static GeoJsonParseResult TryParse(JsonValue value, IJsonSerializer serializer, out GeoJSONObject? geoJSON) { Guard.NotNull(serializer); Guard.NotNull(value); geoJSON = null; - if (value is JsonObject obj) + if (value.Type == JsonValueType.Object) { + var obj = value.AsObject; + if (TryParseGeoJson(obj, serializer, out geoJSON)) { return GeoJsonParseResult.Success; } - if (!obj.TryGetValue("latitude", out var lat) || !lat.Value.IsBetween(-90, 90)) + if (!obj.TryGetValue("latitude", out var lat) || lat.Type != JsonValueType.Number || !lat.AsNumber.IsBetween(-90, 90)) { return GeoJsonParseResult.InvalidLatitude; } - if (!obj.TryGetValue("longitude", out var lon) || !lon.Value.IsBetween(-180, 180)) + if (!obj.TryGetValue("longitude", out var lon) || lon.Type != JsonValueType.Number || !lon.AsNumber.IsBetween(-180, 180)) { return GeoJsonParseResult.InvalidLongitude; } - geoJSON = new Point(new Position(lat.Value, lon.Value)); + geoJSON = new Point(new Position(lat.AsNumber, lon.AsNumber)); return GeoJsonParseResult.Success; } @@ -49,11 +52,11 @@ namespace Squidex.Domain.Apps.Core.Contents return GeoJsonParseResult.InvalidValue; } - private static bool TryParseGeoJson(JsonObject obj, IJsonSerializer serializer, out GeoJSONObject? geoJSON) + private static bool TryParseGeoJson(ListDictionary obj, IJsonSerializer serializer, out GeoJSONObject? geoJSON) { geoJSON = null; - if (!obj.TryGetValue("type", out var type) || type is not JsonString) + if (!obj.TryGetValue("type", out var type) || type.Type != JsonValueType.String) { return false; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Json/ContentFieldDataConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Json/ContentFieldDataConverter.cs index 57b07a060..8ea045638 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Json/ContentFieldDataConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Json/ContentFieldDataConverter.cs @@ -44,7 +44,7 @@ namespace Squidex.Domain.Apps.Core.Contents.Json throw new JsonSerializationException("Unexpected end when reading Object."); } - var value = serializer.Deserialize(reader)!; + var value = serializer.Deserialize(reader)!; if (Language.IsDefault(propertyName) || propertyName == InvariantPartitioning.Key) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/Rule.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/Rule.cs index 41ca58bea..105784a1b 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Rules/Rule.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Rules/Rule.cs @@ -79,7 +79,7 @@ namespace Squidex.Domain.Apps.Core.Rules if (newTrigger.GetType() != Trigger.GetType()) { - throw new ArgumentException("New trigger has another type.", nameof(newTrigger)); + ThrowHelper.ArgumentException("New trigger has another type.", nameof(newTrigger)); } if (Trigger.Equals(newTrigger)) @@ -100,7 +100,7 @@ namespace Squidex.Domain.Apps.Core.Rules if (newAction.GetType() != Action.GetType()) { - throw new ArgumentException("New action has another type.", nameof(newAction)); + ThrowHelper.ArgumentException("New action has another type.", nameof(newAction)); } if (Action.Equals(newAction)) diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs index 424fa5a04..08a9efc2c 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs @@ -101,7 +101,7 @@ namespace Squidex.Domain.Apps.Core.Schemas if (ids.Count != fieldsOrdered.Length || ids.Any(x => !ById.ContainsKey(x))) { - throw new ArgumentException("Ids must cover all fields.", nameof(ids)); + ThrowHelper.ArgumentException("Ids must cover all fields.", nameof(ids)); } if (ids.SequenceEqual(fieldsOrdered.Select(x => x.Id))) @@ -119,12 +119,12 @@ namespace Squidex.Domain.Apps.Core.Schemas if (ByName.ContainsKey(field.Name)) { - throw new ArgumentException($"A field with name '{field.Name}' already exists.", nameof(field)); + ThrowHelper.ArgumentException($"A field with name '{field.Name}' already exists.", nameof(field)); } if (ById.ContainsKey(field.Id)) { - throw new ArgumentException($"A field with ID {field.Id} already exists.", nameof(field)); + ThrowHelper.ArgumentException($"A field with ID {field.Id} already exists.", nameof(field)); } return new FieldCollection(fieldsOrdered.Union(Enumerable.Repeat(field, 1))); @@ -149,7 +149,8 @@ namespace Squidex.Domain.Apps.Core.Schemas if (newField is null) { - throw new InvalidOperationException($"Field must be of type {typeof(T)}"); + ThrowHelper.InvalidOperationException($"Field must be of type {typeof(T)}"); + return default!; } return new FieldCollection(fieldsOrdered.Select(x => ReferenceEquals(x, field) ? newField : x)); diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs index 8978396c1..ddab3b06a 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs @@ -47,7 +47,8 @@ namespace Squidex.Domain.Apps.Core.Schemas if (newProperties is not T typedProperties) { - throw new ArgumentException($"Properties must be of type '{typeof(T)}", nameof(newProperties)); + ThrowHelper.ArgumentException($"Properties must be of type '{typeof(T)}", nameof(newProperties)); + return default!; } return typedProperties; diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs index f4b8f6ae0..13f83326a 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs @@ -47,7 +47,8 @@ namespace Squidex.Domain.Apps.Core.Schemas if (newProperties is not T typedProperties) { - throw new ArgumentException($"Properties must be of type '{typeof(T)}", nameof(newProperties)); + ThrowHelper.ArgumentException($"Properties must be of type '{typeof(T)}", nameof(newProperties)); + return default!; } return typedProperties; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs index 67e2eac22..6a2d25518 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs @@ -54,9 +54,9 @@ namespace Squidex.Domain.Apps.Core.ConvertContent return data; } - for (var i = 0; i < converters.Length; i++) + foreach (var converter in converters) { - data = converters[i](data!, field)!; + data = converter(data!, field)!; if (data == null) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverterFlat.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverterFlat.cs index f799baa12..2520abcb7 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverterFlat.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverterFlat.cs @@ -35,9 +35,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent foreach (var (key, value) in content) { - var first = GetFirst(value, fallback); - - if (first != null) + if (TryGetFirst(value, fallback, out var first)) { result[key] = first; } @@ -61,29 +59,34 @@ namespace Squidex.Domain.Apps.Core.ConvertContent return fieldData; } - private static IJsonValue? GetFirst(ContentFieldData? fieldData, string fallback) + private static bool TryGetFirst(ContentFieldData? fieldData, string fallback, out JsonValue result) { + result = JsonValue.Null; + if (fieldData == null) { - return null; + return false; } if (fieldData.Count == 1) { - return fieldData.Values.First(); + result = fieldData.Values.First(); + return true; } if (fieldData.TryGetValue(fallback, out var value)) { - return value; + result = value; + return true; } if (fieldData.Count > 1) { - return fieldData.Values.First(); + result = fieldData.Values.First(); + return true; } - return null; + return false; } } } 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 797426bde..5e46d199f 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs @@ -219,10 +219,10 @@ namespace Squidex.Domain.Apps.Core.ConvertContent newData ??= new ContentFieldData(data); newData.Remove(key); } - else if (!ReferenceEquals(newValue, value)) + else if (!ReferenceEquals(newValue.Value.Value, value.Value)) { newData ??= new ContentFieldData(data); - newData[key] = newValue; + newData[key] = newValue.Value; } } @@ -230,7 +230,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent }; } - private static IJsonValue? ConvertByType(T field, IJsonValue? value, IArrayField? parent, ValueConverter[] converters, + private static JsonValue? ConvertByType(T field, JsonValue value, IArrayField? parent, ValueConverter[] converters, ResolvedComponents components) where T : IField { switch (field) @@ -249,16 +249,20 @@ namespace Squidex.Domain.Apps.Core.ConvertContent } } - private static IJsonValue? ConvertArray(IArrayField field, IJsonValue? value, ValueConverter[] converters, + private static JsonValue? ConvertArray(IArrayField field, JsonValue value, ValueConverter[] converters, ResolvedComponents components) { - if (value is JsonArray array) + if (value.Type == JsonValueType.Array) { + var array = value.AsArray; + JsonArray? result = null; for (int i = 0, j = 0; i < array.Count; i++, j++) { - var newValue = ConvertArrayItem(field, array[i], converters, components); + var oldValue = array[i]; + + var newValue = ConvertArrayItem(field, oldValue, converters, components); if (newValue == null) { @@ -266,29 +270,33 @@ namespace Squidex.Domain.Apps.Core.ConvertContent result.RemoveAt(j); j--; } - else if (!ReferenceEquals(newValue, array[i])) + else if (!ReferenceEquals(newValue.Value.Value, oldValue.Value)) { result ??= new JsonArray(array); - result[j] = newValue; + result[j] = newValue.Value; } } - return result ?? array; + return result ?? value; } return null; } - private static IJsonValue? ConvertComponents(IJsonValue? value, ValueConverter[] converters, + private static JsonValue? ConvertComponents(JsonValue? value, ValueConverter[] converters, ResolvedComponents components) { - if (value is JsonArray array) + if (value?.Type == JsonValueType.Array) { + var array = value.Value.AsArray; + JsonArray? result = null; for (int i = 0, j = 0; i < array.Count; i++, j++) { - var newValue = ConvertComponent(array[i], converters, components); + var oldValue = array[i]; + + var newValue = ConvertComponent(oldValue, converters, components); if (newValue == null) { @@ -296,58 +304,60 @@ namespace Squidex.Domain.Apps.Core.ConvertContent result.RemoveAt(j); j--; } - else if (!ReferenceEquals(newValue, array[i])) + else if (!ReferenceEquals(newValue.Value.Value, array[i].Value)) { result ??= new JsonArray(array); - result[j] = newValue; + result[j] = newValue.Value; } } - return result ?? array; + return result ?? value; } return null; } - private static IJsonValue? ConvertComponent(IJsonValue? value, ValueConverter[] converters, + private static JsonValue? ConvertComponent(JsonValue? value, ValueConverter[] converters, ResolvedComponents components) { - if (value is JsonObject obj && obj.TryGetValue(Component.Discriminator, out var type)) + if (value.HasValue && value.Value.Type == JsonValueType.Object && value.Value.AsObject.TryGetValue(Component.Discriminator, out var type) && type.Type == JsonValueType.String) { - var id = DomainId.Create(type.Value); + var id = DomainId.Create(type.AsString); if (components.TryGetValue(id, out var schema)) { - return ConvertNested(schema.FieldCollection, obj, null, converters, components); + return ConvertNested(schema.FieldCollection, value.Value, null, converters, components); } else { - return obj; + return value; } } return null; } - private static IJsonValue? ConvertArrayItem(IArrayField field, IJsonValue? value, ValueConverter[] converters, + private static JsonValue? ConvertArrayItem(IArrayField field, JsonValue value, ValueConverter[] converters, ResolvedComponents components) { - if (value is JsonObject obj) + if (value.Type == JsonValueType.Object) { - return ConvertNested(field.FieldCollection, obj, field, converters, components); + return ConvertNested(field.FieldCollection, value, field, converters, components); } return null; } - private static IJsonValue ConvertNested(FieldCollection fields, JsonObject source, IArrayField? parent, ValueConverter[] converters, + private static JsonValue ConvertNested(FieldCollection fields, JsonValue source, IArrayField? parent, ValueConverter[] converters, ResolvedComponents components) where T : IField { JsonObject? result = null; - foreach (var (key, value) in source) + var obj = source.AsObject; + + foreach (var (key, value) in obj) { - var newValue = value; + JsonValue? newValue = value; if (fields.ByName.TryGetValue(key, out var field)) { @@ -360,30 +370,34 @@ namespace Squidex.Domain.Apps.Core.ConvertContent if (newValue == null) { - result ??= new JsonObject(source); + result ??= new JsonObject(obj); result.Remove(key); } - else if (!ReferenceEquals(newValue, value)) + else if (!ReferenceEquals(newValue.Value.Value, value.Value)) { - result ??= new JsonObject(source); - result[key] = newValue; + result ??= new JsonObject(obj); + result[key] = newValue.Value; } } return result ?? source; } - private static IJsonValue? ConvertValue(IField field, IJsonValue? value, IArrayField? parent, ValueConverter[] converters) + private static JsonValue? ConvertValue(IField field, JsonValue value, IArrayField? parent, ValueConverter[] converters) { var newValue = value; for (var i = 0; i < converters.Length; i++) { - newValue = converters[i](newValue!, field, parent); + var candidate = converters[i](newValue!, field, parent); - if (newValue == null) + if (candidate == null) + { + return null; + } + else { - break; + newValue = candidate.Value; } } 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 9422a7d71..12a51c5a5 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/StringFormatter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/StringFormatter.cs @@ -17,22 +17,22 @@ namespace Squidex.Domain.Apps.Core.ConvertContent { private static readonly StringFormatter Instance = new StringFormatter(); - public record struct Args(IJsonValue Value); + public record struct Args(JsonValue Value); private StringFormatter() { } - public static string Format(IField field, IJsonValue? value) + public static string Format(IField field, JsonValue value) { Guard.NotNull(field); - if (value == null || value is JsonNull) + if (value.Type == JsonValueType.Null) { return string.Empty; } - var args = new Args(value ?? JsonValue.Null); + var args = new Args(value); return field.RawProperties.Accept(Instance, args); } @@ -49,7 +49,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent public string Visit(BooleanFieldProperties properties, Args args) { - if (args.Value is JsonBoolean { Value: true }) + if (args.Value.Type == JsonValueType.Boolean && args.Value.AsBoolean) { return "Yes"; } @@ -76,11 +76,11 @@ namespace Squidex.Domain.Apps.Core.ConvertContent public string Visit(GeolocationFieldProperties properties, Args args) { - if (args.Value is JsonObject jsonObject && - jsonObject.TryGetValue("latitude", out var lat) && - jsonObject.TryGetValue("longitude", out var lon)) + if (args.Value.Type == JsonValueType.Object && + args.Value.TryGetValue(JsonValueType.Number, "latitude", out var lat) && + args.Value.TryGetValue(JsonValueType.Number, "longitude", out var lon)) { - return $"{lat}, {lon}"; + return $"{lat.AsNumber}, {lon.AsNumber}"; } else { @@ -117,9 +117,9 @@ namespace Squidex.Domain.Apps.Core.ConvertContent public string Visit(TagsFieldProperties properties, Args args) { - if (args.Value is JsonArray array) + if (args.Value.Type == JsonValueType.Array) { - return string.Join(", ", array); + return string.Join(", ", args.Value.AsArray); } else { @@ -132,10 +132,12 @@ namespace Squidex.Domain.Apps.Core.ConvertContent return string.Empty; } - private static string FormatArray(IJsonValue value, string singularName, string pluralName) + private static string FormatArray(JsonValue value, string singularName, string pluralName) { - if (value is JsonArray array) + if (value.Type == JsonValueType.Array) { + var array = value.AsArray; + if (array.Count > 1) { return $"{array.Count} {pluralName}"; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs index 269021ad9..325919666 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs @@ -15,7 +15,7 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Core.ConvertContent { - public delegate IJsonValue? ValueConverter(IJsonValue value, IField field, IArrayField? parent); + public delegate JsonValue? ValueConverter(JsonValue value, IField field, IArrayField? parent); public static class ValueConverters { @@ -23,7 +23,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent public static readonly ValueConverter ExcludeHidden = (value, field, parent) => { - return field.IsForApi() ? value : null; + return field.IsForApi() ? (JsonValue?)value : null; }; public static ValueConverter ExcludeChangedTypes(IJsonSerializer jsonSerializer) @@ -96,13 +96,15 @@ namespace Squidex.Domain.Apps.Core.ConvertContent return (value, field, parent) => { - if (field is IField && value is JsonArray array && shouldHandle(field, parent)) + if (field is IField && value.Type == JsonValueType.Array && shouldHandle(field, parent)) { + var array = value.AsArray; + for (var i = 0; i < array.Count; i++) { var id = array[i].ToString(); - array[i] = JsonValue.Create(urlGenerator.AssetContent(appId, id)); + array[i] = urlGenerator.AssetContent(appId, id); } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueExtensions.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueExtensions.cs index 9d6375598..0a6729987 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueExtensions.cs @@ -45,7 +45,7 @@ namespace Squidex.Domain.Apps.Core.DefaultValues { var defaultValue = DefaultValueFactory.CreateDefaultValue(field, SystemClock.Instance.GetCurrentInstant(), partitionKey); - if (field.RawProperties.IsRequired || defaultValue == null || defaultValue.Type == JsonValueType.Null) + if (field.RawProperties.IsRequired || defaultValue.Type == JsonValueType.Null) { return; } 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 1b4152d33..dfbad3f0b 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueFactory.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueFactory.cs @@ -15,7 +15,7 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Core.DefaultValues { - public sealed class DefaultValueFactory : IFieldPropertiesVisitor + public sealed class DefaultValueFactory : IFieldPropertiesVisitor { private static readonly DefaultValueFactory Instance = new DefaultValueFactory(); @@ -25,87 +25,89 @@ namespace Squidex.Domain.Apps.Core.DefaultValues { } - public static IJsonValue CreateDefaultValue(IField field, Instant now, string partition) + public static JsonValue CreateDefaultValue(IField field, Instant now, string partition) { Guard.NotNull(field); Guard.NotNull(partition); - return field.RawProperties.Accept(Instance, new Args(now, partition)); + var x = field.RawProperties.Accept(Instance, new Args(now, partition)); + + return x; } - public IJsonValue Visit(ArrayFieldProperties properties, Args args) + public JsonValue Visit(ArrayFieldProperties properties, Args args) { - return JsonValue.Array(); + return new JsonArray(); } - public IJsonValue Visit(AssetsFieldProperties properties, Args args) + public JsonValue Visit(AssetsFieldProperties properties, Args args) { var value = GetDefaultValue(properties.DefaultValue, properties.DefaultValues, args.Partition); return Array(value); } - public IJsonValue Visit(BooleanFieldProperties properties, Args args) + public JsonValue Visit(BooleanFieldProperties properties, Args args) { var value = GetDefaultValue(properties.DefaultValue, properties.DefaultValues, args.Partition); - return JsonValue.Create(value); + return value ?? JsonValue.Null; } - public IJsonValue Visit(ComponentFieldProperties properties, Args args) + public JsonValue Visit(ComponentFieldProperties properties, Args args) { return JsonValue.Null; } - public IJsonValue Visit(ComponentsFieldProperties properties, Args args) + public JsonValue Visit(ComponentsFieldProperties properties, Args args) { - return JsonValue.Array(); + return new JsonArray(); } - public IJsonValue Visit(GeolocationFieldProperties properties, Args args) + public JsonValue Visit(GeolocationFieldProperties properties, Args args) { return JsonValue.Null; } - public IJsonValue Visit(JsonFieldProperties properties, Args args) + public JsonValue Visit(JsonFieldProperties properties, Args args) { return JsonValue.Null; } - public IJsonValue Visit(NumberFieldProperties properties, Args args) + public JsonValue Visit(NumberFieldProperties properties, Args args) { var value = GetDefaultValue(properties.DefaultValue, properties.DefaultValues, args.Partition); - return JsonValue.Create(value); + return value ?? JsonValue.Null; } - public IJsonValue Visit(ReferencesFieldProperties properties, Args args) + public JsonValue Visit(ReferencesFieldProperties properties, Args args) { var value = GetDefaultValue(properties.DefaultValue, properties.DefaultValues, args.Partition); return Array(value); } - public IJsonValue Visit(StringFieldProperties properties, Args args) + public JsonValue Visit(StringFieldProperties properties, Args args) { var value = GetDefaultValue(properties.DefaultValue, properties.DefaultValues, args.Partition); - return JsonValue.Create(value); + return value; } - public IJsonValue Visit(TagsFieldProperties properties, Args args) + public JsonValue Visit(TagsFieldProperties properties, Args args) { var value = GetDefaultValue(properties.DefaultValue, properties.DefaultValues, args.Partition); return Array(value); } - public IJsonValue Visit(UIFieldProperties properties, Args args) + public JsonValue Visit(UIFieldProperties properties, Args args) { return JsonValue.Null; } - public IJsonValue Visit(DateTimeFieldProperties properties, Args args) + public JsonValue Visit(DateTimeFieldProperties properties, Args args) { if (properties.CalculatedDefaultValue == DateTimeCalculatedDefaultValue.Now) { @@ -119,7 +121,7 @@ namespace Squidex.Domain.Apps.Core.DefaultValues var value = GetDefaultValue(properties.DefaultValue, properties.DefaultValues, args.Partition); - return JsonValue.Create(value); + return value ?? JsonValue.Null; } private static T GetDefaultValue(T value, LocalizedValue? values, string partition) @@ -132,7 +134,7 @@ namespace Squidex.Domain.Apps.Core.DefaultValues return value; } - private static IJsonValue Array(IEnumerable? values) + private static JsonValue Array(IEnumerable? values) { if (values != null) { @@ -140,7 +142,7 @@ namespace Squidex.Domain.Apps.Core.DefaultValues } else { - return JsonValue.Array(); + return new JsonArray(); } } } 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 e1703b417..2da1a8a1a 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs @@ -22,16 +22,16 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds return false; } - static bool CanHaveReference(IJsonValue value) + static bool CanHaveReference(JsonValue value) { - if (value is JsonArray) + if (value.Type == JsonValueType.Array) { return true; } - if (value is JsonObject obj) + if (value.Type == JsonValueType.Object) { - foreach (var (_, nested) in obj) + foreach (var (_, nested) in value.AsObject) { if (CanHaveReference(nested)) { @@ -107,17 +107,14 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds } } - public static HashSet GetReferencedIds(this IField field, IJsonValue? value, + public static HashSet GetReferencedIds(this IField field, JsonValue value, ResolvedComponents components, int referencesPerField = int.MaxValue) { Guard.NotNull(components); var result = new HashSet(); - if (value != null) - { - ReferencesExtractor.Extract(field, value, result, referencesPerField, components); - } + ReferencesExtractor.Extract(field, value, result, referencesPerField, components); return result; } @@ -127,11 +124,11 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds Guard.NotNull(schema); Guard.NotNull(partitioning); - var result = JsonValue.Object(); + var result = new JsonObject(); foreach (var partitionKey in partitioning.AllKeys) { - result[partitionKey] = JsonValue.Create(data.FormatReferenceFields(schema, partitionKey, separator)); + result[partitionKey] = data.FormatReferenceFields(schema, partitionKey, separator); } 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 87fe18cb8..c9793e2d1 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs @@ -13,93 +13,95 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { - internal sealed class ReferencesCleaner : IFieldVisitor + internal sealed class ReferencesCleaner : IFieldVisitor { private static readonly ReferencesCleaner Instance = new ReferencesCleaner(); - public record struct Args(IJsonValue Value, ISet ValidIds); + public record struct Args(JsonValue Value, ISet ValidIds); private ReferencesCleaner() { } - public static IJsonValue Cleanup(IField field, IJsonValue? value, HashSet validIds) + public static JsonValue Cleanup(IField field, JsonValue value, HashSet validIds) { - var args = new Args(value ?? JsonValue.Null, validIds); + var args = new Args(value, validIds); return field.Accept(Instance, args); } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return CleanIds(args); } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return CleanIds(args); } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return args.Value; } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return args.Value; } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return args.Value; } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return args.Value; } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return args.Value; } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return args.Value; } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return args.Value; } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return args.Value; } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return args.Value; } - public IJsonValue Visit(IField field, Args args) + public JsonValue Visit(IField field, Args args) { return args.Value; } - public IJsonValue Visit(IArrayField field, Args args) + public JsonValue Visit(IArrayField field, Args args) { return args.Value; } - private static IJsonValue CleanIds(Args args) + private static JsonValue CleanIds(Args args) { - if (args.Value is JsonArray array) + if (args.Value.Type == JsonValueType.Array) { - var result = array; + var array = args.Value.AsArray; + + var result = args.Value.AsArray; for (var i = 0; i < result.Count; i++) { @@ -107,7 +109,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { if (ReferenceEquals(result, array)) { - result = new JsonArray(array); + result = array; } result.RemoveAt(i); @@ -121,9 +123,9 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds return args.Value; } - private static bool IsValidReference(IJsonValue item, Args args) + private static bool IsValidReference(JsonValue item, Args args) { - return item is JsonString s && args.ValidIds.Contains(DomainId.Create(s.Value)); + return item.Type == JsonValueType.String && args.ValidIds.Contains(DomainId.Create(item.AsString)); } } } 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 5fa368a1f..7183fdcc6 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs @@ -18,26 +18,26 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { private static readonly ReferencesExtractor Instance = new ReferencesExtractor(); - public record struct Args(IJsonValue Value, ISet Result, int Take, ResolvedComponents Components); + public record struct Args(JsonValue Value, ISet Result, int Take, ResolvedComponents Components); private ReferencesExtractor() { } - public static None Extract(IField field, IJsonValue? value, HashSet result, int take, ResolvedComponents components) + public static None Extract(IField field, JsonValue value, HashSet result, int take, ResolvedComponents components) { - var args = new Args(value ?? JsonValue.Null, result, take, components); + var args = new Args(value, result, take, components); return field.Accept(Instance, args); } public None Visit(IArrayField field, Args args) { - if (args.Value is JsonArray array) + if (args.Value.Type == JsonValueType.Array) { - for (var i = 0; i < array.Count; i++) + foreach (var value in args.Value.AsArray) { - ExtractFromArrayItem(field, array[i], args); + ExtractFromArrayItem(field, value, args); } } @@ -72,11 +72,11 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds public None Visit(IField field, Args args) { - if (args.Value is JsonArray array) + if (args.Value.Type == JsonValueType.Array) { - for (var i = 0; i < array.Count; i++) + foreach (var value in args.Value.AsArray) { - ExtractFromComponent(array[i], args); + ExtractFromComponent(value, args); } } @@ -118,10 +118,12 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds return None.Value; } - private void ExtractFromArrayItem(IArrayField field, IJsonValue value, Args args) + private void ExtractFromArrayItem(IArrayField field, JsonValue value, Args args) { - if (value is JsonObject obj) + if (value.Type == JsonValueType.Object) { + var obj = value.AsObject; + foreach (var nestedField in field.Fields) { if (obj.TryGetValue(nestedField.Name, out var nestedValue)) @@ -132,19 +134,24 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds } } - private void ExtractFromComponent(IJsonValue value, Args args) + private void ExtractFromComponent(JsonValue value, Args args) { - if (value is JsonObject obj && obj.TryGetValue(Component.Discriminator, out var type)) + if (value.Type == JsonValueType.Object) { - var id = DomainId.Create(type.Value); + var obj = value.AsObject; - if (args.Components.TryGetValue(id, out var schema)) + if (obj.TryGetValue(Component.Discriminator, out var type) && type.Type == JsonValueType.String) { - foreach (var componentField in schema.Fields) + var id = DomainId.Create(type.AsString); + + 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, args with { Value = componentValue }); + if (obj.TryGetValue(componentField.Name, out var componentValue)) + { + componentField.Accept(this, args with { Value = componentValue }); + } } } } @@ -155,13 +162,13 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { var added = 0; - if (args.Value is JsonArray array) + if (args.Value.Type == JsonValueType.Array) { - foreach (var id in array) + foreach (var id in args.Value.AsArray) { - if (id is JsonString s) + if (id.Type == JsonValueType.String) { - args.Result.Add(DomainId.Create(s.Value)); + args.Result.Add(DomainId.Create(id.AsString)); added++; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleVariable.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleVariable.cs index 821edc68e..942cfbc37 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleVariable.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleVariable.cs @@ -36,16 +36,16 @@ namespace Squidex.Domain.Apps.Core.HandleRules } else if (current is ContentFieldData field) { - if (!field.TryGetValue(segment, out var temp) || temp == null) + if (!field.TryGetValue(segment, out var temp)) { break; } current = temp; } - else if (current is IJsonValue json) + else if (current is JsonValue json) { - if (!json.TryGet(segment, out var temp) || temp == null || temp.Type == JsonValueType.Null) + if (!json.TryGetValue(segment, out var temp) || temp == JsonValue.Null) { break; } @@ -96,4 +96,4 @@ namespace Squidex.Domain.Apps.Core.HandleRules return (current, path.Skip(i).ToArray()); } } -} \ No newline at end of file +} diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/AssetEntityScriptVars.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/AssetEntityScriptVars.cs index e28d84ab2..de6c45223 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/AssetEntityScriptVars.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/AssetEntityScriptVars.cs @@ -53,7 +53,7 @@ namespace Squidex.Domain.Apps.Core.Scripting [FieldDescription(nameof(FieldDescriptions.AssetMetadata))] public AssetMetadata? Metadata { - set => SetValue(value != null ? new ReadOnlyDictionary(value) : null); + set => SetValue(value != null ? new ReadOnlyDictionary(value) : null); } [FieldDescription(nameof(FieldDescriptions.AssetTags))] diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/ContentFieldProperty.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/ContentFieldProperty.cs index 32aac695d..a2c575261 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/ContentFieldProperty.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/ContentFieldProperty.cs @@ -14,7 +14,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper public sealed class ContentFieldProperty : CustomProperty { private readonly ContentFieldObject contentField; - private IJsonValue contentValue; + private JsonValue contentValue; private JsValue? value; private bool isChanged; @@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper { if (value == null) { - if (contentValue != null) + if (contentValue != default) { value = JsonMapper.Map(contentValue, contentField.Engine); } @@ -49,7 +49,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper } } - public IJsonValue ContentValue + public JsonValue ContentValue { get => contentValue; } @@ -59,10 +59,10 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper get => isChanged; } - public ContentFieldProperty(ContentFieldObject contentField, IJsonValue? contentValue = null) + public ContentFieldProperty(ContentFieldObject contentField, JsonValue contentValue = default) { this.contentField = contentField; - this.contentValue = contentValue ?? JsonValue.Null; + this.contentValue = contentValue; } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/JsonMapper.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/JsonMapper.cs index 4c152ee44..7b5ab5b8d 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/JsonMapper.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/JsonMapper.cs @@ -9,39 +9,37 @@ using System.Globalization; using Jint; using Jint.Native; using Jint.Native.Object; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Collections; using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper { public static class JsonMapper { - public static JsValue Map(IJsonValue? value, Engine engine) + public static JsValue Map(JsonValue value, Engine engine) { - if (value == null) + switch (value.Type) { - return JsValue.Null; - } - - switch (value) - { - case JsonNull: + case JsonValueType.Null: return JsValue.Null; - case JsonString s: - return new JsString(s.Value); - case JsonBoolean b: - return new JsBoolean(b.Value); - case JsonNumber b: - return new JsNumber(b.Value); - case JsonObject obj: - return FromObject(obj, engine); - case JsonArray arr: - return FromArray(arr, engine); + case JsonValueType.String: + return new JsString(value.AsString); + case JsonValueType.Boolean: + return new JsBoolean(value.AsBoolean); + case JsonValueType.Number: + return new JsNumber(value.AsNumber); + case JsonValueType.Object: + return FromObject(value.AsObject, engine); + case JsonValueType.Array: + return FromArray(value.AsArray, engine); } - throw new ArgumentException("Invalid json type.", nameof(value)); + ThrowInvalidType(nameof(value)); + return JsValue.Null; } - private static JsValue FromArray(JsonArray arr, Engine engine) + private static JsValue FromArray(List arr, Engine engine) { var target = new JsValue[arr.Count]; @@ -53,7 +51,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper return engine.Realm.Intrinsics.Array.Construct(target); } - private static JsValue FromObject(JsonObject obj, Engine engine) + private static JsValue FromObject(ListDictionary obj, Engine engine) { var target = new ObjectInstance(engine); @@ -65,31 +63,31 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper return target; } - public static IJsonValue Map(JsValue? value) + public static JsonValue Map(JsValue? value) { if (value == null || value.IsNull() || value.IsUndefined()) { - return JsonValue.Null; + return default; } if (value.IsString()) { - return JsonValue.Create(value.AsString()); + return value.AsString(); } if (value.IsBoolean()) { - return JsonValue.Create(value.AsBoolean()); + return value.AsBoolean(); } if (value.IsDate()) { - return JsonValue.Create(value.AsDate().ToString()); + return value.AsDate().ToString(); } if (value.IsRegExp()) { - return JsonValue.Create(value.AsRegExp().Value?.ToString()); + return value.AsRegExp().Value?.ToString(); } if (value.IsNumber()) @@ -98,17 +96,17 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper if (double.IsNaN(number) || double.IsPositiveInfinity(number) || double.IsNegativeInfinity(number)) { - return JsonValue.Zero; + return 0; } - return JsonValue.Create(number); + return number; } if (value.IsArray()) { var arr = value.AsArray(); - var result = JsonValue.Array(); + var result = new JsonArray((int)arr.Length); for (var i = 0; i < arr.Length; i++) { @@ -122,7 +120,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper { var obj = value.AsObject(); - var result = JsonValue.Object(); + var result = new JsonObject((int)obj.Length); foreach (var (key, propertyDescriptor) in obj.GetOwnProperties()) { @@ -132,7 +130,13 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper return result; } - throw new ArgumentException("Invalid json type.", nameof(value)); + ThrowInvalidType(nameof(value)); + return default; + } + + private static void ThrowInvalidType(string argument) + { + ThrowHelper.ArgumentException("Invalid json type.", argument); } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs index b748fb797..a745eb9e6 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs @@ -12,19 +12,19 @@ namespace Squidex.Domain.Apps.Core.Scripting { public interface IScriptEngine { - Task ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default, + Task ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default, CancellationToken ct = default); Task TransformAsync(DataScriptVars vars, string script, ScriptOptions options = default, CancellationToken ct = default); - IJsonValue Execute(ScriptVars vars, string script, ScriptOptions options = default); + JsonValue Execute(ScriptVars vars, string script, ScriptOptions options = default); bool Evaluate(ScriptVars vars, string script, ScriptOptions options = default) { try { - return Execute(vars, script, options).Equals(JsonValue.True); + return Execute(vars, script, options).Equals(true); } catch { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs index 67c427afa..d0e3c82a8 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs @@ -40,7 +40,7 @@ namespace Squidex.Domain.Apps.Core.Scripting this.extensions = extensions?.ToArray() ?? Array.Empty(); } - public async Task ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default, + public async Task ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default, CancellationToken ct = default) { Guard.NotNull(vars); @@ -51,7 +51,7 @@ namespace Squidex.Domain.Apps.Core.Scripting using (var combined = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, ct)) { var context = - CreateEngine(options, combined.Token) + CreateEngine(options, combined.Token) .Extend(vars, options) .Extend(extensions) .ExtendAsync(extensions); @@ -109,7 +109,7 @@ namespace Squidex.Domain.Apps.Core.Scripting } } - public IJsonValue Execute(ScriptVars vars, string script, ScriptOptions options = default) + public JsonValue Execute(ScriptVars vars, string script, ScriptOptions options = default) { Guard.NotNull(vars); Guard.NotNullOrEmpty(script); @@ -124,7 +124,7 @@ namespace Squidex.Domain.Apps.Core.Scripting return JsonMapper.Map(result); } - private ScriptExecutionContext CreateEngine(ScriptOptions options, CancellationToken ct) where T : class + private ScriptExecutionContext CreateEngine(ScriptOptions options, CancellationToken ct) { if (Debugger.IsAttached) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs index d2435fe98..fdeea0b20 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs @@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Core.Scripting void Run(Action? action, T argument); } - public sealed class ScriptExecutionContext : ScriptExecutionContext, IScheduler where T : class + public sealed class ScriptExecutionContext : ScriptExecutionContext, IScheduler { private readonly TaskCompletionSource tcs = new TaskCompletionSource(); private readonly CancellationToken cancellationToken; @@ -53,7 +53,7 @@ namespace Squidex.Domain.Apps.Core.Scripting { if (pendingTasks <= 0) { - tcs.TrySetResult(null); + tcs.TrySetResult(default); } return tcs.Task.WithCancellation(cancellationToken); @@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Core.Scripting if (Interlocked.Decrement(ref pendingTasks) <= 0) { - tcs.TrySetResult(null); + tcs.TrySetResult(default); } } catch (Exception ex) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagNormalizer.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagNormalizer.cs index ae8ee9f5a..fd98e5258 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagNormalizer.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagNormalizer.cs @@ -21,10 +21,10 @@ namespace Squidex.Domain.Apps.Core.Tags Guard.NotNull(newData); var newValues = new HashSet(); - var newArrays = new List(); + var newArrays = new List(); var oldValues = new HashSet(); - var oldArrays = new List(); + var oldArrays = new List(); GetValues(schema, newValues, newArrays, newData); @@ -37,13 +37,15 @@ namespace Squidex.Domain.Apps.Core.Tags { var normalized = await tagService.NormalizeTagsAsync(appId, TagGroups.Schemas(schemaId), newValues, oldValues); - foreach (var array in newArrays) + foreach (var source in newArrays) { + var array = source.AsArray; + for (var i = 0; i < array.Count; i++) { if (normalized.TryGetValue(array[i].ToString(), out var result)) { - array[i] = JsonValue.Create(result); + array[i] = result; } } } @@ -56,7 +58,7 @@ namespace Squidex.Domain.Apps.Core.Tags Guard.NotNull(schema); var tagsValues = new HashSet(); - var tagsArrays = new List(); + var tagsArrays = new List(); GetValues(schema, tagsValues, tagsArrays, datas); @@ -64,20 +66,22 @@ namespace Squidex.Domain.Apps.Core.Tags { var denormalized = await tagService.DenormalizeTagsAsync(appId, TagGroups.Schemas(schemaId), tagsValues); - foreach (var array in tagsArrays) + foreach (var source in tagsArrays) { + var array = source.AsArray; + for (var i = 0; i < array.Count; i++) { if (denormalized.TryGetValue(array[i].ToString(), out var result)) { - array[i] = JsonValue.Create(result); + array[i] = result; } } } } } - private static void GetValues(Schema schema, HashSet values, List arrays, params ContentData[] datas) + private static void GetValues(Schema schema, HashSet values, List arrays, params ContentData[] datas) { foreach (var field in schema.Fields) { @@ -106,13 +110,13 @@ namespace Squidex.Domain.Apps.Core.Tags { foreach (var partition in fieldData) { - if (partition.Value is JsonArray array) + if (partition.Value.Type == JsonValueType.Array) { - foreach (var value in array) + foreach (var value in partition.Value.AsArray) { - if (value is JsonObject nestedObject) + if (value.Type == JsonValueType.Object) { - if (nestedObject.TryGetValue(nestedField.Name, out var nestedValue)) + if (value.AsObject.TryGetValue(nestedField.Name, out var nestedValue)) { ExtractTags(nestedValue, values, arrays); } @@ -128,11 +132,11 @@ namespace Squidex.Domain.Apps.Core.Tags } } - private static void ExtractTags(IJsonValue value, ISet values, ICollection arrays) + private static void ExtractTags(JsonValue value, ISet values, ICollection arrays) { - if (value is JsonArray array) + if (value.Type == JsonValueType.Array) { - foreach (var item in array) + foreach (var item in value.AsArray) { if (item.Type == JsonValueType.String) { @@ -140,7 +144,7 @@ namespace Squidex.Domain.Apps.Core.Tags } } - arrays.Add(array); + arrays.Add(value); } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/ContentFluidExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/ContentFluidExtension.cs index 894d69844..4fb4df268 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/ContentFluidExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/ContentFluidExtension.cs @@ -17,21 +17,51 @@ namespace Squidex.Domain.Apps.Core.Templates.Extensions { public void RegisterGlobalTypes(IMemberAccessStrategy memberAccessStrategy) { + FluidValue.SetTypeMapping(x => new ObjectValue(x)); + FluidValue.SetTypeMapping(x => new ObjectValue(x)); FluidValue.SetTypeMapping(x => new ObjectValue(x)); FluidValue.SetTypeMapping(x => new JsonArrayFluidValue(x)); - FluidValue.SetTypeMapping(x => FluidValue.Create(x.Value)); - FluidValue.SetTypeMapping(x => FluidValue.Create(x.Value)); - FluidValue.SetTypeMapping(x => FluidValue.Create(x.Value)); - FluidValue.SetTypeMapping(_ => FluidValue.Create(null)); - memberAccessStrategy.Register( - (value, name) => value.GetOrDefault(name)); + FluidValue.SetTypeMapping(source => + { + switch (source.Type) + { + case JsonValueType.Null: + return FluidValue.Create(null); + case JsonValueType.Boolean: + return FluidValue.Create(source.AsBoolean); + case JsonValueType.Number: + return FluidValue.Create(source.AsNumber); + case JsonValueType.String: + return FluidValue.Create(source.AsString); + case JsonValueType.Array: + return new JsonArrayFluidValue(source.AsArray); + case JsonValueType.Object: + return new ObjectValue(source.AsObject); + } - memberAccessStrategy.Register( + ThrowHelper.InvalidOperationException(); + return default!; + }); + + memberAccessStrategy.Register((value, name) => + { + if (value.Type == JsonValueType.Object) + { + return value.AsObject.GetOrDefault(name); + } + + return null; + }); + + memberAccessStrategy.Register( (value, name) => value.GetOrDefault(name)); memberAccessStrategy.Register( - (value, name) => value.GetOrDefault(name)); + (value, name) => value.GetOrDefault(name).Value); + + memberAccessStrategy.Register( + (value, name) => value.GetOrDefault(name).Value); } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/JsonArrayFluidValue.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/JsonArrayFluidValue.cs index b3af342b6..6984fa166 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/JsonArrayFluidValue.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/JsonArrayFluidValue.cs @@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Core.Templates.Extensions public override string ToStringValue() { - return value.ToString(); + return value.ToString()!; } protected override FluidValue GetValue(string name, TemplateContext context) @@ -98,7 +98,7 @@ namespace Squidex.Domain.Apps.Core.Templates.Extensions public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo) { - writer.Write(value.ToString()); + writer.Write(value); } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs index 04aed8c31..3d0331753 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs @@ -109,7 +109,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent return new AggregateValidator( CreateFieldValidators(field) .Union(Enumerable.Repeat( - new ObjectValidator(partitioningValidators, isPartial, typeName), 1)), log); + new ObjectValidator(partitioningValidators, isPartial, typeName), 1)), log); } private IValidator CreateValueValidator(IField field) 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 8a91e0897..51ccda914 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs @@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent nestedValidators[nestedField.Name] = (false, args.Factory(nestedField)); } - yield return new CollectionItemValidator(new ObjectValidator(nestedValidators, false, "field")); + yield return new CollectionItemValidator(new ObjectValidator(nestedValidators, false, "field")); } public IEnumerable Visit(IField field, Args args) @@ -277,7 +277,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent nestedValidators[nestedField.Name] = (false, factory(nestedField)); } - return new ObjectValidator(nestedValidators, false, "field"); + return new ObjectValidator(nestedValidators, false, "field"); }); } } 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 0e065bf51..8d842016f 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs @@ -22,13 +22,13 @@ namespace Squidex.Domain.Apps.Core.ValidateContent { private static readonly JsonValueConverter Instance = new JsonValueConverter(); - public record struct Args(IJsonValue Value, IJsonSerializer JsonSerializer, ResolvedComponents Components); + public record struct Args(JsonValue 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, JsonValue value, IJsonSerializer jsonSerializer, ResolvedComponents components) { Guard.NotNull(field); @@ -76,9 +76,9 @@ namespace Squidex.Domain.Apps.Core.ValidateContent public (object? Result, JsonError? Error) Visit(IField field, Args args) { - if (args.Value is JsonBoolean b) + if (args.Value.Type == JsonValueType.Boolean) { - return (b.Value, null); + return (args.Value.AsBoolean, null); } return (null, new JsonError(T.Get("contents.invalidBoolean"))); @@ -86,9 +86,9 @@ namespace Squidex.Domain.Apps.Core.ValidateContent public (object? Result, JsonError? Error) Visit(IField field, Args args) { - if (args.Value is JsonNumber n) + if (args.Value.Type == JsonValueType.Number) { - return (n.Value, null); + return (args.Value.AsNumber, null); } return (null, new JsonError(T.Get("contents.invalidNumber"))); @@ -96,9 +96,9 @@ namespace Squidex.Domain.Apps.Core.ValidateContent public (object? Result, JsonError? Error) Visit(IField field, Args args) { - if (args.Value is JsonString s) + if (args.Value.Type == JsonValueType.String) { - return (s.Value, null); + return (args.Value.AsString, null); } return (null, new JsonError(T.Get("contents.invalidString"))); @@ -143,22 +143,28 @@ namespace Squidex.Domain.Apps.Core.ValidateContent } } - private static (object? Result, JsonError? Error) ConvertToIdList(IJsonValue value) + private static (object? Result, JsonError? Error) ConvertToIdList(JsonValue value) { - if (value is JsonArray array) + if (value.Type == JsonValueType.Array) { + var array = value.AsArray; + var result = new List(array.Count); - for (var i = 0; i < array.Count; i++) + foreach (var item in array) { - if (array[i] is JsonString s && !string.IsNullOrWhiteSpace(s.Value)) + if (item.Type == JsonValueType.String) { - result.Add(DomainId.Create(s.Value)); - } - else - { - return (null, new JsonError(T.Get("contents.invalidArrayOfStrings"))); + var typed = item.AsString; + + if (!string.IsNullOrWhiteSpace(item.AsString)) + { + result.Add(DomainId.Create(typed)); + continue; + } } + + return (null, new JsonError(T.Get("contents.invalidArrayOfStrings"))); } return (result, null); @@ -167,22 +173,28 @@ namespace Squidex.Domain.Apps.Core.ValidateContent return (null, new JsonError(T.Get("contents.invalidArrayOfStrings"))); } - private static (object? Result, JsonError? Error) ConvertToStringList(IJsonValue value) + private static (object? Result, JsonError? Error) ConvertToStringList(JsonValue value) { - if (value is JsonArray array) + if (value.Type == JsonValueType.Array) { + var array = value.AsArray; + var result = new List(array.Count); - for (var i = 0; i < array.Count; i++) + foreach (var item in array) { - if (array[i] is JsonString s && !string.IsNullOrWhiteSpace(s.Value)) - { - result.Add(s.Value); - } - else + if (item.Type == JsonValueType.String) { - return (null, new JsonError(T.Get("contents.invalidArrayOfStrings"))); + var typed = item.AsString; + + if (!string.IsNullOrWhiteSpace(item.AsString)) + { + result.Add(typed); + continue; + } } + + return (null, new JsonError(T.Get("contents.invalidArrayOfStrings"))); } return (result, null); @@ -191,22 +203,23 @@ namespace Squidex.Domain.Apps.Core.ValidateContent return (null, new JsonError(T.Get("contents.invalidArrayOfStrings"))); } - private static (object? Result, JsonError? Error) ConvertToObjectList(IJsonValue value) + private static (object? Result, JsonError? Error) ConvertToObjectList(JsonValue value) { - if (value is JsonArray array) + if (value.Type == JsonValueType.Array) { + var array = value.AsArray; + var result = new List(array.Count); - for (var i = 0; i < array.Count; i++) + foreach (var item in array) { - if (array[i] is JsonObject obj) - { - result.Add(obj); - } - else + if (item.Type == JsonValueType.Object) { - return (null, new JsonError(T.Get("contents.invalidArrayOfObjects"))); + result.Add(item.AsObject); + continue; } + + return (null, new JsonError(T.Get("contents.invalidArrayOfObjects"))); } return (result, null); @@ -215,25 +228,27 @@ namespace Squidex.Domain.Apps.Core.ValidateContent return (null, new JsonError(T.Get("contents.invalidArrayOfObjects"))); } - private static (object? Result, JsonError? Error) ConvertToComponentList(IJsonValue value, + private static (object? Result, JsonError? Error) ConvertToComponentList(JsonValue value, ResolvedComponents components, ReadonlyList? allowedIds) { - if (value is JsonArray array) + if (value.Type == JsonValueType.Array) { + var array = value.AsArray; + var result = new List(array.Count); - for (var i = 0; i < array.Count; i++) + foreach (var item in array) { - var (item, error) = ConvertToComponent(array[i], components, allowedIds); + var (component, error) = ConvertToComponent(item, components, allowedIds); if (error != null) { return (null, error); } - if (item != null) + if (component != null) { - result.Add(item); + result.Add(component); } } @@ -243,32 +258,34 @@ namespace Squidex.Domain.Apps.Core.ValidateContent return (null, new JsonError(T.Get("contents.invalidArrayOfObjects"))); } - private static (Component? Result, JsonError? Error) ConvertToComponent(IJsonValue value, + private static (Component? Result, JsonError? Error) ConvertToComponent(JsonValue value, ResolvedComponents components, ReadonlyList? allowedIds) { - if (value is not JsonObject obj) + if (value.Type != JsonValueType.Object) { return (null, new JsonError(T.Get("contents.invalidComponentNoObject"))); } - var id = default(DomainId); + var id = DomainId.Empty; + + var obj = value.AsObject; - if (obj.TryGetValue("schemaName", out var schemaName)) + if (obj.TryGetValue("schemaName", out var schemaName) && schemaName.Type == JsonValueType.String) { - id = components.FirstOrDefault(x => x.Value.Name == schemaName.Value).Key; + id = components.FirstOrDefault(x => x.Value.Name == schemaName.AsString).Key; obj.Remove("schemaName"); - obj[Component.Discriminator] = JsonValue.Create(id); + obj[Component.Discriminator] = id; } - else if (obj.TryGetValue(Component.Discriminator, out var discriminator)) + else if (obj.TryGetValue(Component.Discriminator, out var discriminator) && discriminator.Type == JsonValueType.String) { - id = DomainId.Create(discriminator.Value); + id = DomainId.Create(discriminator.AsString); } else if (allowedIds?.Count == 1) { id = allowedIds[0]; - obj[Component.Discriminator] = JsonValue.Create(id); + obj[Component.Discriminator] = id; } if (id == default) 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 7bf3d1a4c..7d9373fea 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueValidator.cs @@ -20,13 +20,13 @@ namespace Squidex.Domain.Apps.Core.ValidateContent { private static readonly JsonValueValidator Instance = new JsonValueValidator(); - public record struct Args(IJsonValue Value, IJsonSerializer JsonSerializer); + public record struct Args(JsonValue Value, IJsonSerializer JsonSerializer); private JsonValueValidator() { } - public static bool IsValid(IField field, IJsonValue value, IJsonSerializer jsonSerializer) + public static bool IsValid(IField field, JsonValue value, IJsonSerializer jsonSerializer) { Guard.NotNull(field); Guard.NotNull(value); @@ -48,7 +48,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent public bool Visit(IField field, Args args) { - return args.Value is JsonBoolean; + return args.Value.Type == JsonValueType.Boolean; } public bool Visit(IField field, Args args) @@ -87,7 +87,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent public bool Visit(IField field, Args args) { - return args.Value is JsonNumber; + return args.Value.Type == JsonValueType.Number; } public bool Visit(IField field, Args args) @@ -97,7 +97,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent public bool Visit(IField field, Args args) { - return args.Value is JsonString; + return args.Value.Type == JsonValueType.String; } public bool Visit(IField field, Args args) @@ -110,61 +110,61 @@ namespace Squidex.Domain.Apps.Core.ValidateContent return true; } - private static bool IsValidStringList(IJsonValue value) + private static bool IsValidStringList(JsonValue value) { - if (value is JsonArray array) + if (value.Type != JsonValueType.Array) { - for (var i = 0; i < array.Count; i++) + return false; + } + + foreach (var item in value.AsArray) + { + if (item.Type != JsonValueType.String) { - if (array[i] is not JsonString) - { - return false; - } + return false; } - - return true; } - return false; + return true; } - private static bool IsValidObjectList(IJsonValue value) + private static bool IsValidObjectList(JsonValue value) { - if (value is JsonArray array) + if (value.Type != JsonValueType.Array) + { + return false; + } + + foreach (var item in value.AsArray) { - for (var i = 0; i < array.Count; i++) + if (item.Type != JsonValueType.Object) { - if (array[i] is not JsonObject) - { - return false; - } + return false; } - - return true; } - return false; + return true; } - private static bool IsValidComponentList(IJsonValue value) + private static bool IsValidComponentList(JsonValue value) { - if (value is JsonArray array) + if (value.Type != JsonValueType.Array) { - for (var i = 0; i < array.Count; i++) + return false; + } + + foreach (var item in value.AsArray) + { + if (!IsValidComponent(item)) { - if (!IsValidComponent(array[i])) - { - return false; - } + return false; } - - return true; } - return false; + return true; } - private static bool IsValidComponent(IJsonValue value) + private static bool IsValidComponent(JsonValue value) { return Component.IsValid(value, out _); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/CollectionValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/CollectionValidator.cs index fed65b9e4..4c13b52ac 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/CollectionValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/CollectionValidator.cs @@ -6,6 +6,7 @@ // ========================================================================== using System.Collections; +using Squidex.Infrastructure; using Squidex.Infrastructure.Translations; namespace Squidex.Domain.Apps.Core.ValidateContent.Validators @@ -20,7 +21,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators { if (minItems != null && minItems > maxItems) { - throw new ArgumentException("Min length must be greater than max length.", nameof(minItems)); + ThrowHelper.ArgumentException("Min length must be greater than max length.", nameof(minItems)); } this.isRequired = isRequired; 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 8d51467a6..5647aa973 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 @@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators try { - if (value is IJsonValue jsonValue) + if (value is JsonValue jsonValue) { if (jsonValue.Type == JsonValueType.Null) { @@ -40,6 +40,8 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators } else { + typedValue = jsonValue.Value; + var (json, error) = JsonValueConverter.ConvertValue(field, jsonValue, context.JsonSerializer, context.Components); if (error != null) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/RangeValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/RangeValidator.cs index 9cf153425..c73013713 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/RangeValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/RangeValidator.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using Squidex.Infrastructure; using Squidex.Infrastructure.Translations; namespace Squidex.Domain.Apps.Core.ValidateContent.Validators @@ -18,7 +19,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators { if (min != null && max != null && min.Value.CompareTo(max.Value) > 0) { - throw new ArgumentException("Min value must be greater than max value.", nameof(min)); + ThrowHelper.ArgumentException("Min value must be greater than max value.", nameof(min)); } this.min = min; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringLengthValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringLengthValidator.cs index a95efa452..1a068cd57 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringLengthValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringLengthValidator.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using Squidex.Infrastructure; using Squidex.Infrastructure.Translations; namespace Squidex.Domain.Apps.Core.ValidateContent.Validators @@ -18,7 +19,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators { if (minLength > maxLength) { - throw new ArgumentException("Min length must be greater than max length.", nameof(minLength)); + ThrowHelper.ArgumentException("Min length must be greater than max length.", nameof(minLength)); } this.minLength = minLength; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringTextValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringTextValidator.cs index 0f2de869f..fa9d95d4d 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringTextValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringTextValidator.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using Squidex.Infrastructure; using Squidex.Infrastructure.Translations; using Squidex.Text; @@ -26,12 +27,12 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators { if (minCharacters > maxCharacters) { - throw new ArgumentException("Min characters must be greater than max characters.", nameof(minCharacters)); + ThrowHelper.ArgumentException("Min characters must be greater than max characters.", nameof(minCharacters)); } if (minWords > maxWords) { - throw new ArgumentException("Min words must be greater than max words.", nameof(minWords)); + ThrowHelper.ArgumentException("Min words must be greater than max words.", nameof(minWords)); } this.transform = transform; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueObjectValuesValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueObjectValuesValidator.cs index 81b82d04f..dddfcc3d1 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueObjectValuesValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueObjectValuesValidator.cs @@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators private void Validate(ValidationContext context, AddError addError, IEnumerable items) { - var duplicates = new HashSet(10); + var duplicates = new HashSet(10); foreach (var field in fields) { diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/LuceneQueryVisitor.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/LuceneQueryVisitor.cs index d5c66c5dd..16b22c22a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/LuceneQueryVisitor.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/LuceneQueryVisitor.cs @@ -11,6 +11,7 @@ using Lucene.Net.Index; using Lucene.Net.Search; using Lucene.Net.Util; using MongoDB.Bson; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.MongoDb.Text { @@ -50,7 +51,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Text case TermRangeQuery termRangeQuery: return VisitTermRange(termRangeQuery); default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } @@ -59,7 +61,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Text if (!TryParseValue(termRangeQuery.LowerTerm, out var min) || !TryParseValue(termRangeQuery.UpperTerm, out var max)) { - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } var minField = termRangeQuery.IncludesLower ? "gte" : "gt"; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettings.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettings.cs index d5fa3ab50..8875f7a81 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettings.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettings.cs @@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Entities.Apps return GetGrain(appId, userId).RemoveAsync(path); } - public Task SetAsync(DomainId appId, string? userId, string path, IJsonValue value) + public Task SetAsync(DomainId appId, string? userId, string path, JsonValue value) { return GetGrain(appId, userId).SetAsync(path, value.AsJ()); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettingsGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettingsGrain.cs index cd1b88847..d7fb21f63 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettingsGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettingsGrain.cs @@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Apps [CollectionName("UISettings")] public sealed class State { - public JsonObject Settings { get; set; } = JsonValue.Object(); + public JsonObject Settings { get; set; } = new JsonObject(); } public AppUISettingsGrain(IGrainState state) @@ -46,13 +46,14 @@ namespace Squidex.Domain.Apps.Entities.Apps return state.WriteAsync(); } - public Task SetAsync(string path, J value) + public Task SetAsync(string path, J value) { var container = GetContainer(path, true, out var key); if (container == null) { - throw new InvalidOperationException("Path does not lead to an object."); + ThrowHelper.InvalidOperationException("Path does not lead to an object."); + return Task.CompletedTask; } container[key] = value.Value; @@ -90,7 +91,7 @@ namespace Squidex.Domain.Apps.Entities.Apps { if (add) { - temp = JsonValue.Object(); + temp = new JsonObject(); current[segment] = temp; } @@ -100,9 +101,9 @@ namespace Squidex.Domain.Apps.Entities.Apps } } - if (temp is JsonObject next) + if (temp.Type == JsonValueType.Object) { - current = next; + current = temp.AsObject; } else { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateRole.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateRole.cs index 518fb4dbc..d885d0eca 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateRole.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateRole.cs @@ -15,6 +15,6 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands public string[] Permissions { get; set; } - public JsonObject? Properties { get; set; } + public JsonObject Properties { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/AppDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/AppDomainObject.cs index 90b48cba5..d0a80b591 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/AppDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/AppDomainObject.cs @@ -19,6 +19,8 @@ using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.States; using Squidex.Shared.Users; +#pragma warning disable MA0022 // Return Task.FromResult instead of returning null + namespace Squidex.Domain.Apps.Entities.Apps.DomainObject { public sealed partial class AppDomainObject : DomainObject @@ -297,7 +299,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject }); default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettings.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettings.cs index 7e2f63448..243cdaddd 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettings.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettings.cs @@ -14,7 +14,7 @@ namespace Squidex.Domain.Apps.Entities.Apps { Task GetAsync(DomainId appId, string? userId); - Task SetAsync(DomainId appId, string? userId, string path, IJsonValue value); + Task SetAsync(DomainId appId, string? userId, string path, JsonValue value); Task SetAsync(DomainId appId, string? userId, JsonObject settings); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettingsGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettingsGrain.cs index 6007f0b7c..2ed13d581 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettingsGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettingsGrain.cs @@ -15,7 +15,7 @@ namespace Squidex.Domain.Apps.Entities.Apps { Task> GetAsync(); - Task SetAsync(string path, J value); + Task SetAsync(string path, J value); Task SetAsync(J settings); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs index 73f2e6568..193636283 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs @@ -16,6 +16,8 @@ using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.States; +#pragma warning disable MA0022 // Return Task.FromResult instead of returning null + namespace Squidex.Domain.Apps.Entities.Assets.DomainObject { public sealed partial class AssetDomainObject : DomainObject @@ -145,7 +147,8 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject await DeleteCore(c, operation); }); default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetFolderDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetFolderDomainObject.cs index bc888bafe..e0647cbfe 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetFolderDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetFolderDomainObject.cs @@ -10,11 +10,14 @@ using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards; using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events.Assets; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.States; +#pragma warning disable MA0022 // Return Task.FromResult instead of returning null + namespace Squidex.Domain.Apps.Entities.Assets.DomainObject { public sealed partial class AssetFolderDomainObject : DomainObject @@ -80,7 +83,8 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject }); default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetsBulkUpdateCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetsBulkUpdateCommandMiddleware.cs index bf311a6da..e3ee4d3f2 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetsBulkUpdateCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetsBulkUpdateCommandMiddleware.cs @@ -201,7 +201,8 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject } default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/FileTagAssetMetadataSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/FileTagAssetMetadataSource.cs index a03d1e6c8..9ad6fedfa 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/FileTagAssetMetadataSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/FileTagAssetMetadataSource.cs @@ -9,7 +9,6 @@ using Squidex.Assets; using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Infrastructure; -using Squidex.Infrastructure.Json.Objects; using TagLib; using TagLib.Image; using static TagLib.File; @@ -34,7 +33,7 @@ namespace Squidex.Domain.Apps.Entities.Assets public Stream WriteStream { - get { throw new NotSupportedException(); } + get => throw new NotSupportedException(); } public FileAbstraction(AssetFile file) @@ -87,7 +86,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { if (!string.IsNullOrWhiteSpace(value)) { - command.Metadata.Add(name, JsonValue.Create(value)); + command.Metadata.Add(name, value); } } @@ -95,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { if (value > 0) { - command.Metadata.Add(name, JsonValue.Create(value)); + command.Metadata.Add(name, (double)value.Value); } } @@ -103,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { if (value > 0) { - command.Metadata.Add(name, JsonValue.Create(value)); + command.Metadata.Add(name, value.Value); } } @@ -111,7 +110,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { if (value != TimeSpan.Zero) { - command.Metadata.Add(name, JsonValue.Create(value.ToString())); + command.Metadata.Add(name, value.ToString()); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Comments/DomainObject/CommentsGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Comments/DomainObject/CommentsGrain.cs index 17d633cd8..b842218ee 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Comments/DomainObject/CommentsGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Comments/DomainObject/CommentsGrain.cs @@ -14,6 +14,8 @@ using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Reflection; +#pragma warning disable MA0022 // Return Task.FromResult instead of returning null + namespace Squidex.Domain.Apps.Entities.Comments.DomainObject { public sealed class CommentsGrain : GrainOfString, ICommentsGrain @@ -88,7 +90,8 @@ namespace Squidex.Domain.Apps.Entities.Comments.DomainObject }); default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/BackupContents.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/BackupContents.cs index 2cd20b5bf..6ec9b6ddb 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/BackupContents.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/BackupContents.cs @@ -22,20 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Contents public sealed class BackupContents : IBackupHandler { private const int BatchSize = 100; - private delegate void ObjectSetter(IReadOnlyDictionary obj, string key, IJsonValue value); - private const string UrlsFile = "Urls.json"; - - private static readonly ObjectSetter JsonSetter = (obj, key, value) => - { - ((JsonObject)obj).Add(key, value); - }; - - private static readonly ObjectSetter FieldSetter = (obj, key, value) => - { - ((ContentFieldData)obj)[key] = value; - }; - private readonly Dictionary> contentIdsBySchemaId = new Dictionary>(); private readonly Rebuilder rebuilder; private readonly IUrlGenerator urlGenerator; @@ -109,26 +96,26 @@ namespace Squidex.Domain.Apps.Entities.Contents { if (field != null) { - ReplaceAssetUrl(field, FieldSetter); + ReplaceAssetUrl(field); } } } - private void ReplaceAssetUrl(IReadOnlyDictionary source, ObjectSetter setter) + private void ReplaceAssetUrl(IDictionary source) { List<(string, string)>? replacements = null; foreach (var (key, value) in source) { - switch (value) + switch (value.Type) { - case JsonString s: + case JsonValueType.String: { - var newValue = s.Value; + var oldValue = value.AsString; - newValue = newValue.Replace(assetsUrlOld!.AssetsApp, assetsUrlNew!.AssetsApp, StringComparison.Ordinal); + var newValue = oldValue.Replace(assetsUrlOld!.AssetsApp, assetsUrlNew!.AssetsApp, StringComparison.Ordinal); - if (!ReferenceEquals(newValue, s.Value)) + if (!ReferenceEquals(newValue, oldValue)) { replacements ??= new List<(string, string)>(); replacements.Add((key, newValue)); @@ -137,7 +124,7 @@ namespace Squidex.Domain.Apps.Entities.Contents newValue = newValue.Replace(assetsUrlOld!.Assets, assetsUrlNew!.Assets, StringComparison.Ordinal); - if (!ReferenceEquals(newValue, s.Value)) + if (!ReferenceEquals(newValue, oldValue)) { replacements ??= new List<(string, string)>(); replacements.Add((key, newValue)); @@ -147,12 +134,12 @@ namespace Squidex.Domain.Apps.Entities.Contents break; - case JsonArray arr: - ReplaceAssetUrl(arr); + case JsonValueType.Array: + ReplaceAssetUrl(value.AsArray); break; - case JsonObject obj: - ReplaceAssetUrl(obj, JsonSetter); + case JsonValueType.Object: + ReplaceAssetUrl(value.AsObject); break; } } @@ -161,47 +148,47 @@ namespace Squidex.Domain.Apps.Entities.Contents { foreach (var (key, newValue) in replacements) { - setter(source, key, JsonValue.Create(newValue)); + source[key] = newValue; } } } - private void ReplaceAssetUrl(JsonArray source) + private void ReplaceAssetUrl(List source) { for (var i = 0; i < source.Count; i++) { var value = source[i]; - switch (value) + switch (value.Type) { - case JsonString s: + case JsonValueType.String: { - var newValue = s.Value; + var oldValue = value.AsString; - newValue = newValue.Replace(assetsUrlOld!.AssetsApp, assetsUrlNew!.AssetsApp, StringComparison.Ordinal); + var newValue = oldValue.Replace(assetsUrlOld!.AssetsApp, assetsUrlNew!.AssetsApp, StringComparison.Ordinal); - if (!ReferenceEquals(newValue, s.Value)) + if (!ReferenceEquals(newValue, oldValue)) { - source[i] = JsonValue.Create(newValue); + source[i] = newValue; break; } newValue = newValue.Replace(assetsUrlOld!.Assets, assetsUrlNew!.Assets, StringComparison.Ordinal); - if (!ReferenceEquals(newValue, s.Value)) + if (!ReferenceEquals(newValue, oldValue)) { - source[i] = JsonValue.Create(newValue); + source[i] = newValue; break; } } break; - case JsonArray: + case JsonValueType.Array: break; - case JsonObject obj: - ReplaceAssetUrl(obj, JsonSetter); + case JsonValueType.Object: + ReplaceAssetUrl(value.AsObject); break; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateJob.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateJob.cs index b52748301..2e42d27e9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateJob.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateJob.cs @@ -15,7 +15,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Commands { public sealed class BulkUpdateJob { - public Query? Query { get; set; } + public Query? Query { get; set; } public DomainId? Id { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs index 164805e67..70493da5a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs @@ -95,7 +95,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { var sb = new StringBuilder(); - IJsonValue? GetValue(ContentData? data, RootField field) + JsonValue? GetValue(ContentData? data, RootField field) { if (data != null && data.TryGetValue(field.Name, out var fieldValue) && fieldValue != null) { @@ -121,7 +121,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { var value = GetValue(content.ReferenceData, field) ?? GetValue(content.Data, field); - var formatted = StringFormatter.Format(field, value); + var formatted = StringFormatter.Format(field, value ?? default); if (!string.IsNullOrWhiteSpace(formatted)) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs index 0f3565b81..58b51a776 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs @@ -20,6 +20,8 @@ using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.States; using Squidex.Shared; +#pragma warning disable MA0022 // Return Task.FromResult instead of returning null + namespace Squidex.Domain.Apps.Entities.Contents.DomainObject { public sealed partial class ContentDomainObject : DomainObject @@ -220,7 +222,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject }); default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentsBulkUpdateCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentsBulkUpdateCommandMiddleware.cs index 1ffd8bb2b..bf7194713 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentsBulkUpdateCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentsBulkUpdateCommandMiddleware.cs @@ -261,7 +261,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject } default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs index 17f1e7a3f..3887739e6 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs @@ -77,7 +77,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return content; } - public Task> GetReferencedAssetsAsync(IJsonValue value, TimeSpan cacheDuration, + public Task> GetReferencedAssetsAsync(JsonValue value, TimeSpan cacheDuration, CancellationToken ct) { var ids = ParseIds(value); @@ -113,7 +113,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return await LoadAsync(ids); } - public Task> GetReferencedContentsAsync(IJsonValue value, TimeSpan cacheDuration, + public Task> GetReferencedContentsAsync(JsonValue value, TimeSpan cacheDuration, CancellationToken ct) { var ids = ParseIds(value); @@ -182,20 +182,20 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL }); } - private static List? ParseIds(IJsonValue value) + private static List? ParseIds(JsonValue value) { try { List? result = null; - if (value is JsonArray array) + if (value.Type == JsonValueType.Array) { - foreach (var id in array) + foreach (var item in value.AsArray) { - if (id is JsonString jsonString) + if (item.Type == JsonValueType.String) { result ??= new List(); - result.Add(DomainId.Create(jsonString.Value)); + result.Add(DomainId.Create(item.AsString)); } } } 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 60945084a..f23bd3806 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 @@ -64,7 +64,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents { return value => { - return Component.IsValid(value as IJsonValue, out var discrimiator) && discrimiator == schemaId; + if (value is not JsonObject json) + { + return false; + } + + return Component.IsValid(json, out var discriminator) && discriminator == schemaId; }; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ComponentUnionGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ComponentUnionGraphType.cs index 39b3400e8..cdfc5fba5 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ComponentUnionGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ComponentUnionGraphType.cs @@ -46,9 +46,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents ResolveType = value => { - if (value is JsonObject component && component.TryGetValue(Component.Discriminator, out var schemaId)) + if (value is JsonObject json && Component.IsValid(json, out var schemaId)) { - return types.GetOrDefault(schemaId.Value); + return types.GetOrDefault(schemaId); } return null; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs index bfd319ad9..59c6c263d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs @@ -14,7 +14,6 @@ using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; -using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Translations; using Squidex.Shared; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataInputGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataInputGraphType.cs index 8dfa664a0..ee1ef9182 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataInputGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataInputGraphType.cs @@ -78,7 +78,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents foreach (var item in list) { - if (item is JsonObject nested) + if (item is JsonValue nested && nested.Type == JsonValueType.Object) { array.Add(nested); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldVisitor.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldVisitor.cs index b097d9068..7bc500a96 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldVisitor.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldVisitor.cs @@ -17,67 +17,84 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents { - public delegate T ValueResolver(IJsonValue value, IResolveFieldContext fieldContext, GraphQLExecutionContext context); + public delegate T ValueResolver(JsonValue value, IResolveFieldContext fieldContext, GraphQLExecutionContext context); - public delegate Task AsyncValueResolver(IJsonValue value, IResolveFieldContext fieldContext, GraphQLExecutionContext context); + public delegate Task AsyncValueResolver(JsonValue value, IResolveFieldContext fieldContext, GraphQLExecutionContext context); internal sealed class FieldVisitor : IFieldVisitor { - public static readonly IFieldResolver JsonNoop = CreateValueResolver((value, fieldContext, contex) => value); + public static readonly IFieldResolver JsonNoop = CreateValueResolver((value, fieldContext, contex) => value.Value); public static readonly IFieldResolver JsonPath = CreateValueResolver(ContentActions.Json.Resolver); private static readonly IFieldResolver JsonBoolean = CreateValueResolver((value, fieldContext, contex) => { - switch (value) + switch (value.Type) { - case JsonBoolean b: - return b.Value; + case JsonValueType.Boolean: + return value.AsBoolean; default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; + } + }); + + private static readonly IFieldResolver JsonComponents = CreateValueResolver((value, fieldContext, contex) => + { + switch (value.Type) + { + case JsonValueType.Array: + return value.AsArray.Select(x => x.AsObject).ToList(); + default: + ThrowHelper.NotSupportedException(); + return default!; } }); private static readonly IFieldResolver JsonDateTime = CreateValueResolver((value, fieldContext, contex) => { - switch (value) + switch (value.Type) { - case JsonString n: - return n.Value; + case JsonValueType.String: + return value.AsString; default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } }); private static readonly IFieldResolver JsonNumber = CreateValueResolver((value, fieldContext, contex) => { - switch (value) + switch (value.Type) { - case JsonNumber n: - return n.Value; + case JsonValueType.Number: + return value.AsNumber; default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } }); private static readonly IFieldResolver JsonString = CreateValueResolver((value, fieldContext, contex) => { - switch (value) + switch (value.Type) { - case JsonString s: - return s.Value; + case JsonValueType.String: + return value.AsString; default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } }); private static readonly IFieldResolver JsonStrings = CreateValueResolver((value, fieldContext, contex) => { - switch (value) + switch (value.Type) { - case JsonArray a: - return a.Select(x => x.ToString()).ToList(); + case JsonValueType.Array: + return value.AsArray.Select(x => x.ToString()).ToList(); default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } }); @@ -116,7 +133,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents return default; } - return new (new ListGraphType(new NonNullGraphType(type)), JsonNoop, null); + return new (new ListGraphType(new NonNullGraphType(type)), JsonComponents, null); } public FieldGraphSchema Visit(IField field, FieldInfo args) @@ -150,7 +167,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents return default; } - return new (new ListGraphType(new NonNullGraphType(type)), JsonNoop, null); + return new (new ListGraphType(new NonNullGraphType(type)), JsonComponents, null); } public FieldGraphSchema Visit(IField field, FieldInfo args) @@ -243,7 +260,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents if (!union.HasType) { - return default; + return null; } contentType = union; @@ -267,7 +284,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents if (!union.HasType) { - return default; + return null; } componentType = union; @@ -278,13 +295,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents private static IFieldResolver CreateValueResolver(ValueResolver valueResolver) { - return Resolvers.Sync, object?>((source, fieldContext, context) => + return Resolvers.Sync, object?>((source, fieldContext, context) => { var key = fieldContext.FieldDefinition.SourceName(); if (source.TryGetValue(key, out var value)) { - if (value is JsonNull) + if (value == JsonValue.Null) { return null; } @@ -298,13 +315,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents private static IFieldResolver CreateAsyncValueResolver(AsyncValueResolver valueResolver) { - return Resolvers.Async, object?>(async (source, fieldContext, context) => + return Resolvers.Async, object?>(async (source, fieldContext, context) => { var key = fieldContext.FieldDefinition.SourceName(); if (source.TryGetValue(key, out var value)) { - if (value is JsonNull) + if (value == JsonValue.Null) { return null; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedInputGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedInputGraphType.cs index e8b2214eb..b3fb8a818 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedInputGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedInputGraphType.cs @@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents public override object ParseDictionary(IDictionary value) { - var result = JsonValue.Object(); + var result = new JsonObject(); foreach (var field in Fields) { @@ -49,7 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents } } - return result; + return new JsonValue(result); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonGraphType.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonGraphType.cs index 14baf542c..389b16e83 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonGraphType.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonGraphType.cs @@ -23,28 +23,28 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives return ParseJson(value); } - public static IJsonValue ParseJson(object? input) + public static JsonValue ParseJson(object? input) { switch (input) { case GraphQLBooleanValue booleanValue: - return JsonValue.Create(booleanValue.BoolValue); + return booleanValue.BoolValue; case GraphQLFloatValue floatValue: - return JsonValue.Create(double.Parse((string)floatValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture)); + return double.Parse((string)floatValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture); case GraphQLIntValue intValue: - return JsonValue.Create(int.Parse((string)intValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture)); + return double.Parse((string)intValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture); case GraphQLNullValue: - return JsonValue.Null; + return default; case GraphQLStringValue stringValue: - return JsonValue.Create((string)stringValue.Value); + return (string)stringValue.Value; case GraphQLListValue listValue: { - var json = JsonValue.Array(); + var json = new JsonArray(); if (listValue.Values != null) { @@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives case GraphQLObjectValue objectValue: { - var json = JsonValue.Object(); + var json = new JsonObject(); if (objectValue.Fields != null) { @@ -74,7 +74,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives case IEnumerable list: { - var json = JsonValue.Array(); + var json = new JsonArray(); foreach (var item in list) { @@ -86,7 +86,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives case IDictionary obj: { - var json = JsonValue.Object(); + var json = new JsonObject(); foreach (var (key, value) in obj) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonValueNode.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonValueNode.cs index 1ff8e5b9c..285bfe99e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonValueNode.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonValueNode.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using GraphQLParser; using GraphQLParser.AST; using Squidex.Infrastructure.Json.Objects; @@ -15,9 +14,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives { public override ASTNodeKind Kind => ASTNodeKind.ObjectValue; - public IJsonValue Value { get; } + public JsonValue Value { get; } - public JsonValueNode(IJsonValue value) + public JsonValueNode(JsonValue value) { Value = value; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/SharedTypes.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/SharedTypes.cs index 637716fc4..8b7515191 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/SharedTypes.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/SharedTypes.cs @@ -7,7 +7,6 @@ using GraphQL.Types; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Assets; -using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Directives; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types 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 1d8cd9d07..182f605cb 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs @@ -80,7 +80,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { if (schema == null) { - throw new InvalidOperationException(); + ThrowHelper.InvalidOperationException(); + return; } var textQuery = new TextQuery(query.FullText, 1000) @@ -168,7 +169,7 @@ 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 queryModel = BuildQueryModel(context, schema, components); 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 4df832151..d0569960a 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 @@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps if (referencedAsset != null) { - IJsonValue array; + var array = new JsonArray(); if (IsImage(referencedAsset)) { @@ -89,13 +89,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps referencedAsset.AppId, referencedAsset.Id.ToString()); - array = JsonValue.Array(url, referencedAsset.FileName); - } - else - { - array = JsonValue.Array(referencedAsset.FileName); + array.Add(url); } + array.Add(referencedAsset.FileName); + requestCache.AddDependency(referencedAsset.UniqueId, referencedAsset.Version); fieldReference.AddLocalized(partitionKey, array); 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 c9805aa3f..54827075d 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 @@ -125,7 +125,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { var text = T.Get("contents.listReferences", new { count = referencedContents.Count }); - var value = JsonValue.Object(); + var value = new JsonObject(); foreach (var partitionKey in context.App.Languages.AllKeys) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Extensions.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Extensions.cs index 3066f9936..b864f38b0 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Extensions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Extensions.cs @@ -81,25 +81,27 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text return result; } - private static void AppendJsonText(Dictionary languages, string language, IJsonValue value) + private static void AppendJsonText(Dictionary languages, string language, JsonValue value) { - if (value.Type == JsonValueType.String) + switch (value.Type) { - AppendText(languages, language, value.ToString()); - } - else if (value is JsonArray array) - { - foreach (var item in array) - { - AppendJsonText(languages, language, item); - } - } - else if (value is JsonObject obj) - { - foreach (var (_, item) in obj) - { - AppendJsonText(languages, language, item); - } + case JsonValueType.String: + AppendText(languages, language, value.AsString); + break; + case JsonValueType.Array: + foreach (var item in value.AsArray) + { + AppendJsonText(languages, language, item); + } + + break; + case JsonValueType.Object: + foreach (var (_, item) in value.AsObject) + { + AppendJsonText(languages, language, item); + } + + break; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Q.cs b/backend/src/Squidex.Domain.Apps.Entities/Q.cs index f9d0be308..8f9318ca6 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Q.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Q.cs @@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Entities public Instant? ScheduledTo { get; init; } - public Query? JsonQuery { get; init; } + public Query? JsonQuery { get; init; } public RefToken? CreatedBy { get; init; } @@ -64,7 +64,7 @@ namespace Squidex.Domain.Apps.Entities return this with { QueryAsJson = query }; } - public Q WithJsonQuery(Query? query) + public Q WithJsonQuery(Query? query) { return this with { JsonQuery = query }; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Rules/DomainObject/RuleDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Rules/DomainObject/RuleDomainObject.cs index 9082eca84..71024dc95 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Rules/DomainObject/RuleDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Rules/DomainObject/RuleDomainObject.cs @@ -10,11 +10,14 @@ using Squidex.Domain.Apps.Entities.Rules.Commands; using Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards; using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events.Rules; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.States; +#pragma warning disable MA0022 // Return Task.FromResult instead of returning null + namespace Squidex.Domain.Apps.Entities.Rules.DomainObject { public sealed partial class RuleDomainObject : DomainObject @@ -102,7 +105,8 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject }); default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/SchemaDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/SchemaDomainObject.cs index c24f792ec..143e70bb4 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/SchemaDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/SchemaDomainObject.cs @@ -19,6 +19,8 @@ using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.States; +#pragma warning disable MA0022 // Return Task.FromResult instead of returning null + namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject { public sealed partial class SchemaDomainObject : DomainObject @@ -236,7 +238,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject }); default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } diff --git a/backend/src/Squidex.Domain.Users/DefaultKeyStore.cs b/backend/src/Squidex.Domain.Users/DefaultKeyStore.cs index 1ac5060a6..100c20329 100644 --- a/backend/src/Squidex.Domain.Users/DefaultKeyStore.cs +++ b/backend/src/Squidex.Domain.Users/DefaultKeyStore.cs @@ -10,6 +10,7 @@ using IdentityModel; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using OpenIddict.Server; +using Squidex.Infrastructure; using Squidex.Infrastructure.States; namespace Squidex.Domain.Users @@ -86,7 +87,8 @@ namespace Squidex.Domain.Users if (state == null) { - throw new InvalidOperationException("Cannot read key."); + ThrowHelper.InvalidOperationException("Cannot read key."); + return default!; } securityKey = new RsaSecurityKey(state.Parameters) diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonReader.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonReader.cs index fcb03602b..3e9e1d8e5 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonReader.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonReader.cs @@ -81,7 +81,8 @@ namespace Squidex.Infrastructure.MongoDb SetToken(NewtonsoftJsonToken.Float, Decimal128.ToDouble(bsonReader.ReadDecimal128())); break; default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + break; } } else if (bsonReader.State == BsonReaderState.EndOfDocument) diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/DomainIdSerializer.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/DomainIdSerializer.cs index 1d8183693..b76b0abbf 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/DomainIdSerializer.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/DomainIdSerializer.cs @@ -49,7 +49,8 @@ namespace Squidex.Infrastructure.MongoDb return DomainId.Create(binary.ToString()); default: - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } @@ -62,7 +63,8 @@ namespace Squidex.Infrastructure.MongoDb { if (representation != BsonType.String) { - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } return this; diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs index 30782fd12..b0e7f6b7e 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs @@ -38,7 +38,8 @@ namespace Squidex.Infrastructure.MongoDb { if (mongoCollection == null) { - throw new InvalidOperationException("Collection has not been initialized yet."); + ThrowHelper.InvalidOperationException("Collection has not been initialized yet."); + return default!; } return mongoCollection; diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/FilterVisitor.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/FilterVisitor.cs index 3eca4e2cc..bf6f95f63 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/FilterVisitor.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/FilterVisitor.cs @@ -86,7 +86,8 @@ namespace Squidex.Infrastructure.MongoDb.Queries return Filter.In(propertyName, ((IList)value!).OfType()); } - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } private static BsonRegularExpression BuildMatchRegex(CompareFilter node) diff --git a/backend/src/Squidex.Infrastructure/Collections/ListDictionary.KeyCollection.cs b/backend/src/Squidex.Infrastructure/Collections/ListDictionary.KeyCollection.cs new file mode 100644 index 000000000..20334ad9a --- /dev/null +++ b/backend/src/Squidex.Infrastructure/Collections/ListDictionary.KeyCollection.cs @@ -0,0 +1,126 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections; + +namespace Squidex.Infrastructure.Collections +{ + public partial class ListDictionary + { + private sealed class KeyCollection : ICollection + { + private readonly ListDictionary dictionary; + + public int Count + { + get => dictionary.Count; + } + + public bool IsReadOnly + { + get => false; + } + + public KeyCollection(ListDictionary dictionary) + { + this.dictionary = dictionary; + } + + public void Add(TKey item) + { + throw new NotSupportedException(); + } + + public void Clear() + { + throw new NotSupportedException(); + } + + public void CopyTo(TKey[] array, int arrayIndex) + { + var i = 0; + foreach (var (key, _) in dictionary.entries) + { + array[arrayIndex + i] = key; + i++; + } + } + + public bool Remove(TKey item) + { + throw new NotSupportedException(); + } + + public bool Contains(TKey item) + { + foreach (var entry in dictionary.entries) + { + if (dictionary.comparer.Equals(entry.Key, item)) + { + return true; + } + } + + return false; + } + + public IEnumerator GetEnumerator() + { + return new Enumerator(dictionary); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return new Enumerator(dictionary); + } + + private struct Enumerator : IEnumerator, IEnumerator + { + private readonly ListDictionary dictionary; + private int index = -1; + private TKey value = default!; + + readonly TKey IEnumerator.Current + { + get => value!; + } + + readonly object IEnumerator.Current + { + get => value!; + } + + public Enumerator(ListDictionary dictionary) + { + this.dictionary = dictionary; + } + + public readonly void Dispose() + { + } + + public bool MoveNext() + { + if (index >= dictionary.entries.Count - 1) + { + return false; + } + + index++; + + value = dictionary.entries[index].Key; + return true; + } + + public void Reset() + { + index = -1; + } + } + } + } +} diff --git a/backend/src/Squidex.Infrastructure/Collections/ListDictionary.ValueCollection.cs b/backend/src/Squidex.Infrastructure/Collections/ListDictionary.ValueCollection.cs new file mode 100644 index 000000000..cfc004140 --- /dev/null +++ b/backend/src/Squidex.Infrastructure/Collections/ListDictionary.ValueCollection.cs @@ -0,0 +1,126 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections; + +namespace Squidex.Infrastructure.Collections +{ + public partial class ListDictionary + { + private sealed class ValueCollection : ICollection + { + private readonly ListDictionary dictionary; + + public int Count + { + get => dictionary.Count; + } + + public bool IsReadOnly + { + get => false; + } + + public ValueCollection(ListDictionary dictionary) + { + this.dictionary = dictionary; + } + + public void Add(TValue item) + { + throw new NotSupportedException(); + } + + public void Clear() + { + throw new NotSupportedException(); + } + + public void CopyTo(TValue[] array, int arrayIndex) + { + var i = 0; + foreach (var (_, value) in dictionary.entries) + { + array[arrayIndex + i] = value; + i++; + } + } + + public bool Remove(TValue item) + { + throw new NotSupportedException(); + } + + public bool Contains(TValue item) + { + foreach (var entry in dictionary.entries) + { + if (Equals(entry.Value, item)) + { + return true; + } + } + + return false; + } + + public IEnumerator GetEnumerator() + { + return new Enumerator(dictionary); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return new Enumerator(dictionary); + } + + private struct Enumerator : IEnumerator, IEnumerator + { + private readonly ListDictionary dictionary; + private int index = -1; + private TValue value = default!; + + readonly TValue IEnumerator.Current + { + get => value!; + } + + readonly object IEnumerator.Current + { + get => value!; + } + + public Enumerator(ListDictionary dictionary) + { + this.dictionary = dictionary; + } + + public readonly void Dispose() + { + } + + public bool MoveNext() + { + if (index >= dictionary.entries.Count - 1) + { + return false; + } + + index++; + + value = dictionary.entries[index].Value; + return true; + } + + public void Reset() + { + index = -1; + } + } + } + } +} diff --git a/backend/src/Squidex.Infrastructure/Collections/ListDictionary.cs b/backend/src/Squidex.Infrastructure/Collections/ListDictionary.cs new file mode 100644 index 000000000..de75e1a7a --- /dev/null +++ b/backend/src/Squidex.Infrastructure/Collections/ListDictionary.cs @@ -0,0 +1,269 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections; +using System.Diagnostics.CodeAnalysis; + +namespace Squidex.Infrastructure.Collections +{ + public partial class ListDictionary : IDictionary, IReadOnlyDictionary where TKey : notnull + { + private readonly List> entries = new List>(); + private readonly IEqualityComparer comparer; + + private struct Enumerator : IEnumerator>, IEnumerator + { + private readonly ListDictionary dictionary; + private int index = -1; + private KeyValuePair value = default!; + + readonly KeyValuePair IEnumerator>.Current + { + get => value!; + } + + readonly object IEnumerator.Current + { + get => value!; + } + + public Enumerator(ListDictionary dictionary) + { + this.dictionary = dictionary; + } + + public readonly void Dispose() + { + } + + public bool MoveNext() + { + if (index >= dictionary.entries.Count - 1) + { + return false; + } + + index++; + + value = dictionary.entries[index]; + return true; + } + + public void Reset() + { + index = -1; + } + } + + public TValue this[TKey key] + { + get + { + if (!TryGetValue(key, out var result)) + { + ThrowHelper.KeyNotFoundException(); + return default!; + } + + return result; + } + set + { + var index = -1; + + for (var i = 0; i < entries.Count; i++) + { + if (comparer.Equals(entries[i].Key, key)) + { + index = i; + break; + } + } + + if (index >= 0) + { + entries[index] = new KeyValuePair(key, value); + } + else + { + entries.Add(new KeyValuePair(key, value)); + } + } + } + + public ICollection Keys + { + get => new KeyCollection(this); + } + + public ICollection Values + { + get => new ValueCollection(this); + } + + public int Count + { + get => entries.Count; + } + + public int Capacity + { + get => entries.Capacity; + } + + public bool IsReadOnly + { + get => false; + } + + IEnumerable IReadOnlyDictionary.Keys + { + get => new KeyCollection(this); + } + + IEnumerable IReadOnlyDictionary.Values + { + get => new ValueCollection(this); + } + + public ListDictionary() + : this(1, null) + { + } + + public ListDictionary(ListDictionary source, IEqualityComparer? comparer = null) + { + Guard.NotNull(source); + + entries = source.entries.ToList(); + + this.comparer = comparer ?? EqualityComparer.Default; + } + + public ListDictionary(int capacity, IEqualityComparer? comparer = null) + { + Guard.GreaterEquals(capacity, 0); + + entries = new List>(capacity); + + this.comparer = comparer ?? EqualityComparer.Default; + } + + public void Add(TKey key, TValue value) + { + if (ContainsKey(key)) + { + ThrowHelper.ArgumentException("Key already exists.", nameof(key)); + } + + entries.Add(new KeyValuePair(key, value)); + } + + public void Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + public void Clear() + { + entries.Clear(); + } + + public bool Contains(KeyValuePair item) + { + foreach (var entry in entries) + { + if (comparer.Equals(entry.Key, item.Key) && Equals(entry.Value, item.Value)) + { + return true; + } + } + + return false; + } + + public bool ContainsKey(TKey key) + { + foreach (var entry in entries) + { + if (comparer.Equals(entry.Key, key)) + { + return true; + } + } + + return false; + } + + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) + { + foreach (var entry in entries) + { + if (comparer.Equals(entry.Key, key)) + { + value = entry.Value; + return true; + } + } + + value = default; + return false; + } + + public bool Remove(TKey key) + { + for (var i = 0; i < entries.Count; i++) + { + var entry = entries[i]; + + if (comparer.Equals(entry.Key, key)) + { + entries.RemoveAt(i); + return true; + } + } + + return false; + } + + public bool Remove(KeyValuePair item) + { + for (var i = 0; i < entries.Count; i++) + { + var entry = entries[i]; + + if (comparer.Equals(entry.Key, item.Key) && Equals(entry.Value, item.Value)) + { + entries.RemoveAt(i); + return true; + } + } + + return false; + } + + public void TrimExcess() + { + entries.TrimExcess(); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + entries.CopyTo(array, arrayIndex); + } + + public IEnumerator> GetEnumerator() + { + return new Enumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return new Enumerator(this); + } + } +} diff --git a/backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs b/backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs index 8c3a21ab0..45a782a9e 100644 --- a/backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs +++ b/backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs @@ -165,7 +165,7 @@ namespace Squidex.Infrastructure.Commands if (errorRate > errorThreshold) { - throw new InvalidOperationException($"Error rate of {errorRate} is above threshold {errorThreshold}."); + ThrowHelper.InvalidOperationException($"Error rate of {errorRate} is above threshold {errorThreshold}."); } } diff --git a/backend/src/Squidex.Infrastructure/Diagnostics/Diagnoser.cs b/backend/src/Squidex.Infrastructure/Diagnostics/Diagnoser.cs index c5fba26fc..e9c63bbeb 100644 --- a/backend/src/Squidex.Infrastructure/Diagnostics/Diagnoser.cs +++ b/backend/src/Squidex.Infrastructure/Diagnostics/Diagnoser.cs @@ -125,7 +125,7 @@ namespace Squidex.Infrastructure.Diagnostics if (process.ExitCode != 0) { - throw new InvalidOperationException($"Failed to execute tool. Got exit code: {process.ExitCode}."); + ThrowHelper.InvalidOperationException($"Failed to execute tool. Got exit code: {process.ExitCode}."); } await using (var fs = new FileStream(writtenFile, FileMode.Open)) diff --git a/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeExtensions.cs b/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeExtensions.cs index e6c03509c..9c024539e 100644 --- a/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeExtensions.cs +++ b/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeExtensions.cs @@ -21,7 +21,7 @@ namespace Squidex.Infrastructure.EventSourcing public static Envelope SetEventPosition(this Envelope envelope, string value) where T : class, IEvent { - envelope.Headers[CommonHeaders.EventNumber] = JsonValue.Create(value); + envelope.Headers[CommonHeaders.EventNumber] = value; return envelope; } @@ -33,7 +33,7 @@ namespace Squidex.Infrastructure.EventSourcing public static Envelope SetEventStreamNumber(this Envelope envelope, long value) where T : class, IEvent { - envelope.Headers[CommonHeaders.EventStreamNumber] = JsonValue.Create(value); + envelope.Headers[CommonHeaders.EventStreamNumber] = (double)value; return envelope; } @@ -45,7 +45,7 @@ namespace Squidex.Infrastructure.EventSourcing public static Envelope SetCommitId(this Envelope envelope, Guid value) where T : class, IEvent { - envelope.Headers[CommonHeaders.CommitId] = JsonValue.Create(value); + envelope.Headers[CommonHeaders.CommitId] = value.ToString(); return envelope; } @@ -57,7 +57,7 @@ namespace Squidex.Infrastructure.EventSourcing public static Envelope SetAggregateId(this Envelope envelope, DomainId value) where T : class, IEvent { - envelope.Headers[CommonHeaders.AggregateId] = JsonValue.Create(value); + envelope.Headers[CommonHeaders.AggregateId] = value; return envelope; } @@ -69,7 +69,7 @@ namespace Squidex.Infrastructure.EventSourcing public static Envelope SetEventId(this Envelope envelope, Guid value) where T : class, IEvent { - envelope.Headers[CommonHeaders.EventId] = JsonValue.Create(value); + envelope.Headers[CommonHeaders.EventId] = value.ToString(); return envelope; } @@ -81,7 +81,7 @@ namespace Squidex.Infrastructure.EventSourcing public static Envelope SetTimestamp(this Envelope envelope, Instant value) where T : class, IEvent { - envelope.Headers[CommonHeaders.Timestamp] = JsonValue.Create(value); + envelope.Headers[CommonHeaders.Timestamp] = value; return envelope; } @@ -93,7 +93,7 @@ namespace Squidex.Infrastructure.EventSourcing public static Envelope SetRestored(this Envelope envelope, bool value = true) where T : class, IEvent { - envelope.Headers[CommonHeaders.Restored] = JsonValue.Create(value); + envelope.Headers[CommonHeaders.Restored] = value; return envelope; } @@ -102,11 +102,11 @@ namespace Squidex.Infrastructure.EventSourcing { if (obj.TryGetValue(key, out var v)) { - if (v is JsonNumber number) + if (v.Type == JsonValueType.Number) { - return (long)number.Value; + return (long)v.AsNumber; } - else if (v.Type == JsonValueType.String && double.TryParse(v.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + else if (v.Type == JsonValueType.String && double.TryParse(v.AsString, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return (long)result; } @@ -117,7 +117,7 @@ namespace Squidex.Infrastructure.EventSourcing public static Guid GetGuid(this EnvelopeHeaders obj, string key) { - if (obj.TryGetValue(key, out var v) && v is JsonString s && Guid.TryParse(s.ToString(), out var guid)) + if (obj.TryGetValue(key, out var v) && v.Type == JsonValueType.String && Guid.TryParse(v.AsString, out var guid)) { return guid; } @@ -127,7 +127,7 @@ namespace Squidex.Infrastructure.EventSourcing public static Instant GetInstant(this EnvelopeHeaders obj, string key) { - if (obj.TryGetValue(key, out var v) && v is JsonString s && InstantPattern.ExtendedIso.Parse(s.ToString()).TryGetValue(default, out var instant)) + if (obj.TryGetValue(key, out var v) && v.Type == JsonValueType.String && InstantPattern.ExtendedIso.Parse(v.AsString).TryGetValue(default, out var instant)) { return instant; } @@ -147,9 +147,9 @@ namespace Squidex.Infrastructure.EventSourcing public static bool GetBoolean(this EnvelopeHeaders obj, string key) { - if (obj.TryGetValue(key, out var v) && v is JsonBoolean boolean) + if (obj.TryGetValue(key, out var v) && v.Type == JsonValueType.Boolean) { - return boolean.Value; + return v.AsBoolean; } return false; diff --git a/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeHeaders.cs b/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeHeaders.cs index 08ad1acae..8c6b436fd 100644 --- a/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeHeaders.cs +++ b/backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeHeaders.cs @@ -9,13 +9,13 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Infrastructure.EventSourcing { - public sealed class EnvelopeHeaders : Dictionary + public sealed class EnvelopeHeaders : Dictionary { public EnvelopeHeaders() { } - public EnvelopeHeaders(IDictionary headers) + public EnvelopeHeaders(IDictionary headers) : base(headers) { } diff --git a/backend/src/Squidex.Infrastructure/Guard.cs b/backend/src/Squidex.Infrastructure/Guard.cs index 1f250d936..421dce6d7 100644 --- a/backend/src/Squidex.Infrastructure/Guard.cs +++ b/backend/src/Squidex.Infrastructure/Guard.cs @@ -21,7 +21,8 @@ namespace Squidex.Infrastructure { if (float.IsNaN(target) || float.IsPositiveInfinity(target) || float.IsNegativeInfinity(target)) { - throw new ArgumentException("Value must be a valid number.", parameterName); + ThrowHelper.ArgumentException("Value must be a valid number.", parameterName); + return default!; } return target; @@ -34,7 +35,8 @@ namespace Squidex.Infrastructure { if (double.IsNaN(target) || double.IsPositiveInfinity(target) || double.IsNegativeInfinity(target)) { - throw new ArgumentException("Value must be a valid number.", parameterName); + ThrowHelper.ArgumentException("Value must be a valid number.", parameterName); + return default!; } return target; @@ -49,7 +51,8 @@ namespace Squidex.Infrastructure if (!target!.IsSlug()) { - throw new ArgumentException("Target is not a valid slug.", parameterName); + ThrowHelper.ArgumentException("Target is not a valid slug.", parameterName); + return default!; } return target!; @@ -64,7 +67,8 @@ namespace Squidex.Infrastructure if (!target!.IsPropertyName()) { - throw new ArgumentException("Target is not a valid property name.", parameterName); + ThrowHelper.ArgumentException("Target is not a valid property name.", parameterName); + return default!; } return target!; @@ -77,7 +81,8 @@ namespace Squidex.Infrastructure { if (target != null && target.GetType() != typeof(T)) { - throw new ArgumentException($"The parameter must be of type {typeof(T)}", parameterName); + ThrowHelper.ArgumentException($"The parameter must be of type {typeof(T)}", parameterName); + return default!; } return target; @@ -90,7 +95,8 @@ namespace Squidex.Infrastructure { if (target != null && expectedType != null && target.GetType() != expectedType) { - throw new ArgumentException($"The parameter must be of type {expectedType}", parameterName); + ThrowHelper.ArgumentException($"The parameter must be of type {expectedType}", parameterName); + return default!; } return target; @@ -103,7 +109,8 @@ namespace Squidex.Infrastructure { if (!target.IsBetween(lower, upper)) { - throw new ArgumentException($"Value must be between {lower} and {upper}", parameterName); + ThrowHelper.ArgumentException($"Value must be between {lower} and {upper}", parameterName); + return default!; } return target; @@ -116,7 +123,8 @@ namespace Squidex.Infrastructure { if (!target.IsEnumValue()) { - throw new ArgumentException($"Value must be a valid enum type {typeof(TEnum)}", parameterName); + ThrowHelper.ArgumentException($"Value must be a valid enum type {typeof(TEnum)}", parameterName); + return default!; } return target; @@ -129,7 +137,8 @@ namespace Squidex.Infrastructure { if (target.CompareTo(lower) <= 0) { - throw new ArgumentException($"Value must be greater than {lower}", parameterName); + ThrowHelper.ArgumentException($"Value must be greater than {lower}", parameterName); + return default!; } return target; @@ -142,7 +151,8 @@ namespace Squidex.Infrastructure { if (target.CompareTo(lower) < 0) { - throw new ArgumentException($"Value must be greater or equal to {lower}", parameterName); + ThrowHelper.ArgumentException($"Value must be greater or equal to {lower}", parameterName); + return default!; } return target; @@ -155,7 +165,8 @@ namespace Squidex.Infrastructure { if (target.CompareTo(upper) >= 0) { - throw new ArgumentException($"Value must be less than {upper}", parameterName); + ThrowHelper.ArgumentException($"Value must be less than {upper}", parameterName); + return default!; } return target; @@ -168,7 +179,8 @@ namespace Squidex.Infrastructure { if (target.CompareTo(upper) > 0) { - throw new ArgumentException($"Value must be less or equal to {upper}", parameterName); + ThrowHelper.ArgumentException($"Value must be less or equal to {upper}", parameterName); + return default!; } return target; @@ -183,7 +195,8 @@ namespace Squidex.Infrastructure if (target != null && target.Count == 0) { - throw new ArgumentException("Collection does not contain an item.", parameterName); + ThrowHelper.ArgumentException("Collection does not contain an item.", parameterName); + return default!; } return target!; @@ -196,7 +209,8 @@ namespace Squidex.Infrastructure { if (target == Guid.Empty) { - throw new ArgumentException("Value cannot be empty.", parameterName); + ThrowHelper.ArgumentException("Value cannot be empty.", parameterName); + return default!; } return target; @@ -209,7 +223,8 @@ namespace Squidex.Infrastructure { if (target == DomainId.Empty) { - throw new ArgumentException("Value cannot be empty.", parameterName); + ThrowHelper.ArgumentException("Value cannot be empty.", parameterName); + return default!; } return target; @@ -222,7 +237,8 @@ namespace Squidex.Infrastructure { if (target == null) { - throw new ArgumentNullException(parameterName); + ThrowHelper.ArgumentNullException(parameterName); + return default!; } return target; @@ -235,7 +251,8 @@ namespace Squidex.Infrastructure { if (target == null) { - throw new ArgumentNullException(parameterName); + ThrowHelper.ArgumentNullException(parameterName); + return default!; } return target; @@ -248,7 +265,8 @@ namespace Squidex.Infrastructure { if (Equals(target, default(TValue)!)) { - throw new ArgumentException("Value cannot be an the default value.", parameterName); + ThrowHelper.ArgumentException("Value cannot be an the default value.", parameterName); + return default!; } return target; @@ -263,7 +281,8 @@ namespace Squidex.Infrastructure if (string.IsNullOrWhiteSpace(target)) { - throw new ArgumentException("String parameter cannot be null or empty and cannot contain only blanks.", parameterName); + ThrowHelper.ArgumentException("String parameter cannot be null or empty and cannot contain only blanks.", parameterName); + return default!; } return target; @@ -278,7 +297,8 @@ namespace Squidex.Infrastructure if (target != null && target.Intersect(Path.GetInvalidFileNameChars()).Any()) { - throw new ArgumentException("Value contains an invalid character.", parameterName); + ThrowHelper.ArgumentException("Value contains an invalid character.", parameterName); + return default!; } return target!; diff --git a/backend/src/Squidex.Infrastructure/Json/JsonException.cs b/backend/src/Squidex.Infrastructure/Json/JsonException.cs index 1383551e2..22a5ef10f 100644 --- a/backend/src/Squidex.Infrastructure/Json/JsonException.cs +++ b/backend/src/Squidex.Infrastructure/Json/JsonException.cs @@ -16,12 +16,12 @@ namespace Squidex.Infrastructure.Json { } - public JsonException(string message) + public JsonException(string? message) : base(message) { } - public JsonException(string message, Exception inner) + public JsonException(string? message, Exception? inner) : base(message, inner) { } diff --git a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/JsonValueConverter.cs b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/JsonValueConverter.cs index 6564c4a9f..bf1a075f4 100644 --- a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/JsonValueConverter.cs +++ b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/JsonValueConverter.cs @@ -16,13 +16,7 @@ namespace Squidex.Infrastructure.Json.Newtonsoft { private readonly HashSet supportedTypes = new HashSet { - typeof(IJsonValue), - typeof(JsonArray), - typeof(JsonBoolean), - typeof(JsonNull), - typeof(JsonNumber), - typeof(JsonObject), - typeof(JsonString) + typeof(JsonValue) }; public virtual IEnumerable SupportedTypes @@ -35,7 +29,7 @@ namespace Squidex.Infrastructure.Json.Newtonsoft return ReadJson(reader); } - private static IJsonValue ReadJson(JsonReader reader) + private static JsonValue ReadJson(JsonReader reader) { switch (reader.TokenType) { @@ -63,6 +57,8 @@ namespace Squidex.Infrastructure.Json.Newtonsoft result[propertyName] = value; break; case JsonToken.EndObject: + result.TrimExcess(); + return result; } } @@ -81,6 +77,8 @@ namespace Squidex.Infrastructure.Json.Newtonsoft case JsonToken.Comment: continue; case JsonToken.EndArray: + result.TrimExcess(); + return result; default: var value = ReadJson(reader); @@ -94,25 +92,27 @@ namespace Squidex.Infrastructure.Json.Newtonsoft } case JsonToken.Integer when reader.Value is int i: - return JsonValue.Create(i); + return i; case JsonToken.Integer when reader.Value is long l: - return JsonValue.Create(l); + return l; case JsonToken.Float when reader.Value is float f: - return JsonValue.Create(f); + return f; case JsonToken.Float when reader.Value is double d: - return JsonValue.Create(d); + return d; case JsonToken.Boolean when reader.Value is bool b: - return JsonValue.Create(b); + return b; case JsonToken.Date when reader.Value is DateTime d: - return JsonValue.Create(d.ToIso8601()); + return d.ToIso8601(); case JsonToken.String when reader.Value is string s: - return JsonValue.Create(s); + return s; case JsonToken.Null: + return default; case JsonToken.Undefined: - return JsonValue.Null; + return default; } - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default; } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) @@ -123,48 +123,50 @@ namespace Squidex.Infrastructure.Json.Newtonsoft return; } - WriteJson(writer, (IJsonValue)value); + WriteJson(writer, (JsonValue)value); } - private static void WriteJson(JsonWriter writer, IJsonValue value) + private static void WriteJson(JsonWriter writer, JsonValue value) { - switch (value) + switch (value.Type) { - case JsonNull: + case JsonValueType.Null: writer.WriteNull(); break; - case JsonBoolean s: - writer.WriteValue(s.Value); + case JsonValueType.Boolean: + writer.WriteValue(value.AsBoolean); break; - case JsonString s: - writer.WriteValue(s.Value); + case JsonValueType.String: + writer.WriteValue(value.AsString); break; - case JsonNumber s: - if (s.Value % 1 == 0) + case JsonValueType.Number: + var number = value.AsNumber; + + if (number % 1 == 0) { - writer.WriteValue((long)s.Value); + writer.WriteValue((long)number); } else { - writer.WriteValue(s.Value); + writer.WriteValue(number); } break; - case JsonArray array: + case JsonValueType.Array: writer.WriteStartArray(); - for (var i = 0; i < array.Count; i++) + foreach (var item in value.AsArray) { - WriteJson(writer, array[i]); + WriteJson(writer, item); } writer.WriteEndArray(); break; - case JsonObject obj: + case JsonValueType.Object: writer.WriteStartObject(); - foreach (var (key, jsonValue) in obj) + foreach (var (key, jsonValue) in value.AsObject) { writer.WritePropertyName(key); diff --git a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs index 59ec5fc2c..a5aec1eb3 100644 --- a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs +++ b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs @@ -44,7 +44,7 @@ namespace Squidex.Infrastructure.Json.Newtonsoft } catch (NewtonsoftException ex) { - throw new JsonException(ex.Message, ex); + ThrowHelper.JsonException(ex.Message, ex); } } @@ -64,7 +64,8 @@ namespace Squidex.Infrastructure.Json.Newtonsoft } catch (NewtonsoftException ex) { - throw new JsonException(ex.Message, ex); + ThrowHelper.JsonException(ex.Message, ex); + return default!; } } @@ -84,7 +85,8 @@ namespace Squidex.Infrastructure.Json.Newtonsoft } catch (NewtonsoftException ex) { - throw new JsonException(ex.Message, ex); + ThrowHelper.JsonException(ex.Message, ex); + return default!; } } diff --git a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/TypeConverterJsonConverter.cs b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/TypeConverterJsonConverter.cs index 5789907b0..a440a5de3 100644 --- a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/TypeConverterJsonConverter.cs +++ b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/TypeConverterJsonConverter.cs @@ -32,7 +32,8 @@ namespace Squidex.Infrastructure.Json.Newtonsoft } catch (Exception ex) { - throw new JsonException("Error while converting from string.", ex); + ThrowHelper.JsonException("Error while converting from string.", ex); + return default; } } diff --git a/backend/src/Squidex.Infrastructure/Json/Objects/IJsonValue.cs b/backend/src/Squidex.Infrastructure/Json/Objects/IJsonValue.cs deleted file mode 100644 index c47942ae1..000000000 --- a/backend/src/Squidex.Infrastructure/Json/Objects/IJsonValue.cs +++ /dev/null @@ -1,24 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Diagnostics.CodeAnalysis; - -namespace Squidex.Infrastructure.Json.Objects -{ - public interface IJsonValue : IEquatable - { - JsonValueType Type { get; } - - bool TryGet(string pathSegment, [MaybeNullWhen(false)] out IJsonValue result); - - IJsonValue Clone(); - - string ToJsonString(); - - string ToString(); - } -} diff --git a/backend/src/Squidex.Infrastructure/Json/Objects/JsonArray.cs b/backend/src/Squidex.Infrastructure/Json/Objects/JsonArray.cs index 52f0d678e..8aa4455d2 100644 --- a/backend/src/Squidex.Infrastructure/Json/Objects/JsonArray.cs +++ b/backend/src/Squidex.Infrastructure/Json/Objects/JsonArray.cs @@ -5,46 +5,43 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace Squidex.Infrastructure.Json.Objects { - public sealed class JsonArray : Collection, IJsonValue, IEquatable + public sealed class JsonArray : List, IEquatable { - public JsonValueType Type - { - get => JsonValueType.Array; - } - public JsonArray() { } public JsonArray(int capacity) - : base(new List(capacity)) + : base(capacity) { } public JsonArray(JsonArray source) - : base(source.ToList()) - { - } - - public JsonArray(List source) : base(source) { } - protected override void InsertItem(int index, IJsonValue item) + public JsonArray(IEnumerable? source) { - base.InsertItem(index, item ?? JsonValue.Null); + if (source != null) + { + foreach (var item in source) + { + Add(item); + } + } } - protected override void SetItem(int index, IJsonValue item) + public new JsonArray Add(JsonValue value) { - base.SetItem(index, item ?? JsonValue.Null); + base.Add(value); + + return this; } public override bool Equals(object? obj) @@ -52,49 +49,14 @@ namespace Squidex.Infrastructure.Json.Objects return Equals(obj as JsonArray); } - public bool Equals(IJsonValue? other) - { - return Equals(other as JsonArray); - } - public bool Equals(JsonArray? array) { - if (array == null || array.Count != Count) - { - return false; - } - - for (var i = 0; i < Count; i++) - { - if (!this[i].Equals(array[i])) - { - return false; - } - } - - return true; + return this.EqualsList(array); } public override int GetHashCode() { - var hashCode = 17; - - for (var i = 0; i < Count; i++) - { - hashCode = (hashCode * 23) + this[i].GetHashCode(); - } - - return hashCode; - } - - public IJsonValue Clone() - { - return new JsonArray(this.Select(x => x.Clone()).ToList()); - } - - public string ToJsonString() - { - return ToString(); + return this.SequentialHashCode(); } public override string ToString() @@ -102,10 +64,12 @@ namespace Squidex.Infrastructure.Json.Objects return $"[{string.Join(", ", this.Select(x => x.ToJsonString()))}]"; } - public bool TryGet(string pathSegment, [MaybeNullWhen(false)] out IJsonValue result) + public bool TryGetValue(string pathSegment, [MaybeNullWhen(false)] out JsonValue result) { Guard.NotNull(pathSegment); + result = default; + if (pathSegment != null && int.TryParse(pathSegment, NumberStyles.Integer, CultureInfo.InvariantCulture, out var index) && index >= 0 && index < Count) { result = this[index]; @@ -113,8 +77,6 @@ namespace Squidex.Infrastructure.Json.Objects return true; } - result = null!; - return false; } } diff --git a/backend/src/Squidex.Infrastructure/Json/Objects/JsonBoolean.cs b/backend/src/Squidex.Infrastructure/Json/Objects/JsonBoolean.cs deleted file mode 100644 index cbd1c4000..000000000 --- a/backend/src/Squidex.Infrastructure/Json/Objects/JsonBoolean.cs +++ /dev/null @@ -1,30 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -namespace Squidex.Infrastructure.Json.Objects -{ - public sealed class JsonBoolean : JsonScalar - { - public static readonly JsonBoolean True = new JsonBoolean(true); - public static readonly JsonBoolean False = new JsonBoolean(false); - - public override JsonValueType Type - { - get => JsonValueType.Boolean; - } - - private JsonBoolean(bool value) - : base(value) - { - } - - public override string ToString() - { - return Value ? "true" : "false"; - } - } -} diff --git a/backend/src/Squidex.Infrastructure/Json/Objects/JsonNull.cs b/backend/src/Squidex.Infrastructure/Json/Objects/JsonNull.cs deleted file mode 100644 index a1e02d040..000000000 --- a/backend/src/Squidex.Infrastructure/Json/Objects/JsonNull.cs +++ /dev/null @@ -1,67 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Diagnostics.CodeAnalysis; - -namespace Squidex.Infrastructure.Json.Objects -{ - public sealed class JsonNull : IJsonValue, IEquatable - { - public static readonly JsonNull Null = new JsonNull(); - - public JsonValueType Type - { - get => JsonValueType.Null; - } - - private JsonNull() - { - } - - public override bool Equals(object? obj) - { - return Equals(obj as JsonNull); - } - - public bool Equals(IJsonValue? other) - { - return Equals(other as JsonNull); - } - - public bool Equals(JsonNull? other) - { - return other != null; - } - - public override int GetHashCode() - { - return 0; - } - - public IJsonValue Clone() - { - return this; - } - - public string ToJsonString() - { - return ToString(); - } - - public override string ToString() - { - return "null"; - } - - public bool TryGet(string pathSegment, [MaybeNullWhen(false)] out IJsonValue result) - { - result = null!; - - return false; - } - } -} diff --git a/backend/src/Squidex.Infrastructure/Json/Objects/JsonNumber.cs b/backend/src/Squidex.Infrastructure/Json/Objects/JsonNumber.cs deleted file mode 100644 index 440398858..000000000 --- a/backend/src/Squidex.Infrastructure/Json/Objects/JsonNumber.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Globalization; - -namespace Squidex.Infrastructure.Json.Objects -{ - public sealed class JsonNumber : JsonScalar - { - public override JsonValueType Type - { - get => JsonValueType.Number; - } - - internal JsonNumber(double value) - : base(value) - { - } - - public override string ToString() - { - return Value.ToString(CultureInfo.InvariantCulture); - } - } -} diff --git a/backend/src/Squidex.Infrastructure/Json/Objects/JsonObject.cs b/backend/src/Squidex.Infrastructure/Json/Objects/JsonObject.cs index 2bef80079..6442f694d 100644 --- a/backend/src/Squidex.Infrastructure/Json/Objects/JsonObject.cs +++ b/backend/src/Squidex.Infrastructure/Json/Objects/JsonObject.cs @@ -5,127 +5,24 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Collections; -using System.Diagnostics.CodeAnalysis; +using Squidex.Infrastructure.Collections; namespace Squidex.Infrastructure.Json.Objects { - public class JsonObject : IReadOnlyDictionary, IJsonValue, IEquatable + public class JsonObject : ListDictionary, IEquatable { - private readonly Dictionary inner; - - public IJsonValue this[string key] - { - get - { - return inner[key]; - } - set - { - Guard.NotNull(key); - - inner[key] = value ?? JsonValue.Null; - } - } - - public IEnumerable Keys - { - get => inner.Keys; - } - - public IEnumerable Values - { - get => inner.Values; - } - - public int Count - { - get => inner.Count; - } - - public JsonValueType Type - { - get => JsonValueType.Object; - } - public JsonObject() { - inner = new Dictionary(); } public JsonObject(int capacity) + : base(capacity) { - inner = new Dictionary(capacity); - } - - public JsonObject(JsonObject obj) - { - Guard.NotNull(obj); - - inner = new Dictionary(obj.inner); } - public JsonObject(Dictionary source) + public JsonObject(JsonObject source) + : base(source) { - Guard.NotNull(source); - - inner = source; - } - - public JsonObject Add(string key, object? value) - { - return Add(key, JsonValue.Create(value)); - } - - public JsonObject Add(string key, IJsonValue? value) - { - inner[key] = value ?? JsonValue.Null; - - return this; - } - - public void Clear() - { - inner.Clear(); - } - - public bool Remove(string key) - { - return inner.Remove(key); - } - - public bool ContainsKey(string key) - { - return inner.ContainsKey(key); - } - - public bool TryGetValue(string key, [MaybeNullWhen(false)] out IJsonValue value) - { - return inner.TryGetValue(key, out value!); - } - - public bool TryGetValue(string key, [MaybeNullWhen(false)] out T value) where T : class, IJsonValue - { - if (inner.TryGetValue(key, out var temp) && temp is T typed) - { - value = typed; - return true; - } - else - { - value = null!; - return false; - } - } - - public IEnumerator> GetEnumerator() - { - return inner.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return inner.GetEnumerator(); } public override bool Equals(object? obj) @@ -133,29 +30,14 @@ namespace Squidex.Infrastructure.Json.Objects return Equals(obj as JsonObject); } - public bool Equals(IJsonValue? other) - { - return Equals(other as JsonObject); - } - public bool Equals(JsonObject? other) { - return other != null && inner.EqualsDictionary(other.inner); + return this.EqualsDictionary(other); } public override int GetHashCode() { - return inner.DictionaryHashCode(); - } - - public IJsonValue Clone() - { - return new JsonObject(this.ToDictionary(x => x.Key, x => x.Value.Clone())); - } - - public string ToJsonString() - { - return ToString(); + return this.DictionaryHashCode(); } public override string ToString() @@ -163,11 +45,11 @@ namespace Squidex.Infrastructure.Json.Objects return $"{{{string.Join(", ", this.Select(x => $"\"{x.Key}\":{x.Value.ToJsonString()}"))}}}"; } - public bool TryGet(string pathSegment, [MaybeNullWhen(false)] out IJsonValue result) + public new JsonObject Add(string key, JsonValue value) { - Guard.NotNull(pathSegment); + this[key] = value; - return TryGetValue(pathSegment, out result!); + return this; } } } diff --git a/backend/src/Squidex.Infrastructure/Json/Objects/JsonScalar.cs b/backend/src/Squidex.Infrastructure/Json/Objects/JsonScalar.cs deleted file mode 100644 index 500a8b6cc..000000000 --- a/backend/src/Squidex.Infrastructure/Json/Objects/JsonScalar.cs +++ /dev/null @@ -1,65 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Diagnostics.CodeAnalysis; - -namespace Squidex.Infrastructure.Json.Objects -{ - public abstract class JsonScalar : IJsonValue, IEquatable> where T : notnull - { - public abstract JsonValueType Type { get; } - - public T Value { get; } - - protected JsonScalar(T value) - { - Value = value; - } - - public override bool Equals(object? obj) - { - return Equals(obj as JsonScalar); - } - - public bool Equals(IJsonValue? other) - { - return Equals(other as JsonScalar); - } - - public bool Equals(JsonScalar? other) - { - return other != null && other.Type == Type && Equals(other.Value, Value); - } - - public IJsonValue Clone() - { - return this; - } - - public override int GetHashCode() - { - return Value.GetHashCode(); - } - - public override string ToString() - { - return Value.ToString()!; - } - - public virtual string ToJsonString() - { - return ToString(); - } - - public bool TryGet(string pathSegment, [MaybeNullWhen(false)] out IJsonValue result) - { - result = null!; - - return false; - } - } -} diff --git a/backend/src/Squidex.Infrastructure/Json/Objects/JsonString.cs b/backend/src/Squidex.Infrastructure/Json/Objects/JsonString.cs deleted file mode 100644 index ccb87180a..000000000 --- a/backend/src/Squidex.Infrastructure/Json/Objects/JsonString.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -namespace Squidex.Infrastructure.Json.Objects -{ - public sealed class JsonString : JsonScalar - { - public override JsonValueType Type - { - get => JsonValueType.String; - } - - internal JsonString(string value) - : base(value) - { - } - - public override string ToJsonString() - { - return $"\"{Value}\""; - } - } -} diff --git a/backend/src/Squidex.Infrastructure/Json/Objects/JsonValue.cs b/backend/src/Squidex.Infrastructure/Json/Objects/JsonValue.cs index bff46f454..4226edf63 100644 --- a/backend/src/Squidex.Infrastructure/Json/Objects/JsonValue.cs +++ b/backend/src/Squidex.Infrastructure/Json/Objects/JsonValue.cs @@ -6,71 +6,180 @@ // ========================================================================== using System.Diagnostics.CodeAnalysis; +using System.Globalization; using NodaTime; #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator namespace Squidex.Infrastructure.Json.Objects { - public static class JsonValue + public readonly struct JsonValue : IEquatable { private static readonly char[] PathSeparators = { '.', '[', ']' }; - public static readonly IJsonValue Empty = new JsonString(string.Empty); + public static readonly JsonValue Null; + public static readonly JsonValue True = new JsonValue(true); + public static readonly JsonValue False = new JsonValue(false); + public static readonly JsonValue Zero = new JsonValue(0); - public static readonly IJsonValue True = JsonBoolean.True; - public static readonly IJsonValue False = JsonBoolean.False; + public readonly object? Value; - public static readonly IJsonValue Null = JsonNull.Null; + public JsonValueType Type + { + get + { + switch (Value) + { + case null: + return JsonValueType.Null; + case bool: + return JsonValueType.Boolean; + case double: + return JsonValueType.Number; + case string: + return JsonValueType.String; + case JsonArray: + return JsonValueType.Array; + case JsonObject: + return JsonValueType.Object; + default: + ThrowInvalidType(); + return default!; + } + } + } - public static readonly IJsonValue Zero = new JsonNumber(0); + public bool AsBoolean + { + get + { + if (Value is bool typed) + { + return typed; + } - public static JsonArray Array() + ThrowInvalidType(); + return default!; + } + } + + public double AsNumber { - return new JsonArray(); + get + { + if (Value is double typed) + { + return typed; + } + + ThrowInvalidType(); + return default!; + } } - public static JsonArray Array(IEnumerable values) + public string AsString { - var source = values?.OfType().Select(Create).ToList() ?? new List(); + get + { + if (Value is string typed) + { + return typed; + } - return new JsonArray(source); + ThrowInvalidType(); + return default!; + } } - public static JsonArray Array(params T?[] values) + public JsonArray AsArray { - var source = values?.OfType().Select(Create).ToList() ?? new List(); + get + { + if (Value is JsonArray typed) + { + return typed; + } - return new JsonArray(source); + ThrowInvalidType(); + return default!; + } } - public static JsonObject Object() + public JsonObject AsObject { - return new JsonObject(); + get + { + if (Value is JsonObject typed) + { + return typed; + } + + ThrowInvalidType(); + return default!; + } + } + + public JsonValue(double value) + { + Guard.ValidNumber(value); + + this.Value = value; + } + + public JsonValue(bool value) + { + this.Value = value; } - public static JsonObject Object(IReadOnlyDictionary values) + public JsonValue(string? value) { - var source = values?.ToDictionary(x => x.Key, x => Create(x.Value)) ?? new Dictionary(); + this.Value = value; + } + + public JsonValue(JsonArray? value) + { + this.Value = value; + } + + public JsonValue(JsonObject? value) + { + this.Value = value; + } + + public static JsonValue Create(IReadOnlyDictionary? values) + { + var source = new JsonObject(values?.Count ?? 0); + + if (values != null) + { + foreach (var (key, value) in values) + { + source[key] = Create(value); + } + } - return new JsonObject(source); + return source; } - public static IJsonValue Create(object? value) + public static JsonValue Create(object? value) { if (value == null) { - return Null; + return default; } - if (value is IJsonValue v) + if (value is JsonValue v) { return v; } switch (value) { - case string typed: + case Guid typed: + return Create(typed.ToString()); + case DomainId typed: + return Create(typed); + case Instant typed: return Create(typed); case bool typed: return Create(typed); @@ -82,129 +191,346 @@ namespace Squidex.Infrastructure.Json.Objects return Create(typed); case long typed: return Create(typed); - case Guid typed: - return Create(typed); - case DomainId typed: - return Create(typed); - case Instant typed: + case string typed: return Create(typed); case object[] typed: return Array(typed); + case JsonArray typed: + return typed; + case JsonObject typed: + return typed; case IReadOnlyDictionary typed: - return Object(typed); + return Create(typed); } - throw new ArgumentException("Invalid json type", nameof(value)); + ThrowArgumentException(nameof(value)); + return default!; } - public static IJsonValue Create(Guid value) + public static JsonObject Object() { - return Create(value.ToString()); + return new JsonObject(); } - public static IJsonValue Create(DomainId value) + public static JsonArray Array() { - return Create(value.ToString()); + return new JsonArray(); } - public static IJsonValue Create(Guid? value) + public static JsonValue Array(IEnumerable values) { - if (value == null) - { - return Null; - } + return new JsonArray(values?.OfType().Select(Create)); + } - return Create(value.Value); + public static JsonValue Array(params T?[] values) + { + return new JsonArray(values?.OfType().Select(Create)); } - public static IJsonValue Create(Instant value) + public static JsonValue Create(DomainId value) { - return Create(value.ToString()); + return new JsonValue(value.ToString()); } - public static IJsonValue Create(Instant? value) + public static JsonValue Create(Instant value) { - if (value == null) - { - return Null; - } + return new JsonValue(value.ToString()); + } - return Create(value.Value); + public static JsonValue Create(double value) + { + return new JsonValue(value); } - public static IJsonValue Create(double value) + public static JsonValue Create(bool value) { - Guard.ValidNumber(value); + return new JsonValue(value); + } - if (value == 0) + public static JsonValue Create(string? value) + { + return new JsonValue(value); + } + + public static JsonValue Create(JsonArray? array) + { + return new JsonValue(array); + } + + public static JsonValue Create(JsonObject? @object) + { + return new JsonValue(@object); + } + + public static implicit operator JsonValue(DomainId value) + { + return Create(value); + } + + public static implicit operator JsonValue(Instant value) + { + return Create(value); + } + + public static implicit operator JsonValue(bool value) + { + return Create(value); + } + + public static implicit operator JsonValue(double value) + { + return Create(value); + } + + public static implicit operator JsonValue(string? value) + { + return Create(value); + } + + public static implicit operator JsonValue(JsonArray? value) + { + return Create(value); + } + + public static implicit operator JsonValue(JsonObject? value) + { + return Create(value); + } + + public static bool operator ==(JsonValue left, JsonValue right) + { + return left.Equals(right); + } + + public static bool operator !=(JsonValue left, JsonValue right) + { + return !(left == right); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + return obj is JsonValue typed && Equals(typed); + } + + public bool Equals(JsonValue other) + { + if (other.Type != Type) { - return Zero; + return false; } - return new JsonNumber(value); + switch (Value) + { + case null: + return true; + case bool b: + return b == (bool)other.Value!; + case double d: + return d == (double)other.Value!; + case string s: + return s == (string)other.Value!; + case JsonArray a: + return a.Equals((JsonArray)other.Value!); + case JsonObject o: + return o.Equals((JsonObject)other.Value!); + default: + ThrowInvalidType(); + return default!; + } } - public static IJsonValue Create(double? value) + public override int GetHashCode() { - if (value == null) + switch (Value) { - return Null; + case null: + return 0; + case bool b: + return b.GetHashCode(); + case double d: + return d.GetHashCode(); + case string s: + return s.GetHashCode(StringComparison.OrdinalIgnoreCase); + case JsonArray a: + return a.GetHashCode(); + case JsonObject o: + return o.GetHashCode(); + default: + ThrowInvalidType(); + return default!; } + } - return Create(value.Value); + public override string ToString() + { + switch (Value) + { + case null: + return "null"; + case bool b: + return b ? "true" : "false"; + case double d: + return d.ToString(CultureInfo.InvariantCulture); + case string s: + return s; + case JsonArray a: + return a.ToString(); + case JsonObject o: + return o.ToString(); + default: + ThrowInvalidType(); + return default!; + } } - public static IJsonValue Create(bool value) + public string ToJsonString() { - return value ? True : False; + switch (Value) + { + case null: + return "null"; + case bool b: + return b ? "true" : "false"; + case double d: + return d.ToString(CultureInfo.InvariantCulture); + case string s: + return $"\"{s}\""; + case JsonArray a: + return a.ToString(); + case JsonObject o: + return o.ToString(); + default: + ThrowInvalidType(); + return default!; + } } - public static IJsonValue Create(bool? value) + public JsonValue Clone() { - if (value == null) + switch (Value) { - return Null; + case null: + return this; + case bool: + return this; + case double: + return this; + case string: + return this; + case JsonArray a: + { + var result = new JsonArray(a.Count); + + foreach (var item in a) + { + result.Add(item.Clone()); + } + + return result; + } + + case JsonObject o: + { + var result = new JsonObject(o.Count); + + foreach (var (key, value) in o) + { + result.Add(key, value.Clone()); + } + + return result; + } + + default: + ThrowInvalidType(); + return default!; } + } - return Create(value.Value); + public bool TryGetByPath(string? path, out JsonValue result) + { + return TryGetByPath(path?.Split(PathSeparators, StringSplitOptions.RemoveEmptyEntries), out result!); } - public static IJsonValue Create(string? value) + public bool TryGetByPath(IEnumerable? path, [MaybeNullWhen(false)] out JsonValue result) { - if (value == null) + result = this; + + if (path == null) { - return Null; + return false; } - if (value.Length == 0) + var hasSegment = false; + + foreach (var pathSegment in path) { - return Empty; + hasSegment = true; + + if (!result.TryGetValue(pathSegment, out var found)) + { + result = default; + return false; + } + else + { + result = found; + } } - return new JsonString(value); + return hasSegment; } - public static bool TryGetByPath(this IJsonValue value, string? path, [MaybeNullWhen(false)] out IJsonValue result) + public bool TryGetValue(JsonValueType type, string pathSegment, out JsonValue result) { - return TryGetByPath(value, path?.Split(PathSeparators, StringSplitOptions.RemoveEmptyEntries), out result!); + result = default!; + + if (TryGetValue(pathSegment, out var temp) && temp.Type == type) + { + result = temp; + return true; + } + + return false; } - public static bool TryGetByPath(this IJsonValue? value, IEnumerable? path, [MaybeNullWhen(false)] out IJsonValue result) + public bool TryGetValue(string pathSegment, out JsonValue result) { - result = value!; + result = default!; - if (path != null) + if (pathSegment == null) { - foreach (var pathSegment in path) - { - if (result == null || !result.TryGet(pathSegment, out result!)) - { - break; - } - } + return false; + } + + switch (Value) + { + case null: + return false; + case bool: + return false; + case double: + return false; + case string: + return false; + case JsonArray a: + return a.TryGetValue(pathSegment, out result); + case JsonObject o: + return o.TryGetValue(pathSegment, out result); + default: + ThrowInvalidType(); + return default!; } + } - return result != null && !ReferenceEquals(result, value); + private static void ThrowInvalidType() + { + ThrowHelper.InvalidOperationException("Invalid type."); + } + + private static void ThrowArgumentException(string parameterName) + { + ThrowHelper.ArgumentException("Invalid type.", parameterName); } } } diff --git a/backend/src/Squidex.Infrastructure/NamedIdTypeConverter.cs b/backend/src/Squidex.Infrastructure/NamedIdTypeConverter.cs index 7e814def3..63883234c 100644 --- a/backend/src/Squidex.Infrastructure/NamedIdTypeConverter.cs +++ b/backend/src/Squidex.Infrastructure/NamedIdTypeConverter.cs @@ -54,7 +54,8 @@ namespace Squidex.Infrastructure { if (converter == null) { - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } return converter((string)value); diff --git a/backend/src/Squidex.Infrastructure/NamedId{T}.cs b/backend/src/Squidex.Infrastructure/NamedId{T}.cs index be4fb9c6c..7f922946d 100644 --- a/backend/src/Squidex.Infrastructure/NamedId{T}.cs +++ b/backend/src/Squidex.Infrastructure/NamedId{T}.cs @@ -81,7 +81,8 @@ namespace Squidex.Infrastructure { if (!TryParse(value, parser, out var result)) { - throw new ArgumentException("Named id must have at least 2 parts divided by commata.", nameof(value)); + ThrowHelper.ArgumentException("Named id must have at least 2 parts divided by commata.", nameof(value)); + return default!; } return result; diff --git a/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterSurrogate.cs b/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterSurrogate.cs index 1e22f1ee2..c86cfb6ba 100644 --- a/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterSurrogate.cs +++ b/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterSurrogate.cs @@ -5,53 +5,53 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json.Objects; namespace Squidex.Infrastructure.Queries.Json { - public sealed class JsonFilterSurrogate : ISurrogate> + public sealed class JsonFilterSurrogate : ISurrogate> { - public FilterNode[]? And { get; set; } + public FilterNode[]? And { get; set; } - public FilterNode[]? Or { get; set; } + public FilterNode[]? Or { get; set; } - public FilterNode? Not { get; set; } + public FilterNode? Not { get; set; } public CompareOperator? Op { get; set; } public string? Path { get; set; } - public IJsonValue? Value { get; set; } + public JsonValue Value { get; set; } - public void FromSource(FilterNode source) + public void FromSource(FilterNode source) { throw new NotSupportedException(); } - public FilterNode ToSource() + public FilterNode ToSource() { if (Not != null) { - return new NegateFilter(Not); + return new NegateFilter(Not); } if (And != null) { - return new LogicalFilter(LogicalFilterType.And, And); + return new LogicalFilter(LogicalFilterType.And, And); } if (Or != null) { - return new LogicalFilter(LogicalFilterType.Or, Or); + return new LogicalFilter(LogicalFilterType.Or, Or); } if (!string.IsNullOrWhiteSpace(Path)) { - return new CompareFilter(Path, Op ?? CompareOperator.Equals, Value ?? JsonValue.Null); + return new CompareFilter(Path, Op ?? CompareOperator.Equals, Value); } - throw new JsonException(Errors.InvalidJsonStructure()); + ThrowHelper.JsonException(Errors.InvalidJsonStructure()); + return default!; } } } diff --git a/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterVisitor.cs b/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterVisitor.cs index 326ea66be..ae2ab84d3 100644 --- a/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterVisitor.cs +++ b/backend/src/Squidex.Infrastructure/Queries/Json/JsonFilterVisitor.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure.Validation; namespace Squidex.Infrastructure.Queries.Json { - public sealed class JsonFilterVisitor : FilterNodeVisitor, IJsonValue, JsonFilterVisitor.Args> + public sealed class JsonFilterVisitor : FilterNodeVisitor, JsonValue, JsonFilterVisitor.Args> { private static readonly JsonFilterVisitor Instance = new JsonFilterVisitor(); @@ -22,7 +22,7 @@ namespace Squidex.Infrastructure.Queries.Json { } - public static FilterNode? Parse(FilterNode filter, QueryModel model, List errors) + public static FilterNode? Parse(FilterNode filter, QueryModel model, List errors) { var args = new Args(model, errors); @@ -38,17 +38,17 @@ namespace Squidex.Infrastructure.Queries.Json } } - public override FilterNode Visit(NegateFilter nodeIn, Args args) + public override FilterNode Visit(NegateFilter nodeIn, Args args) { return new NegateFilter(nodeIn.Accept(this, args)); } - public override FilterNode Visit(LogicalFilter nodeIn, Args args) + public override FilterNode Visit(LogicalFilter nodeIn, Args args) { return new LogicalFilter(nodeIn.Type, nodeIn.Filters.Select(x => x.Accept(this, args)).ToList()); } - public override FilterNode Visit(CompareFilter nodeIn, Args args) + public override FilterNode Visit(CompareFilter nodeIn, Args args) { var fieldMatches = nodeIn.Path.GetMatchingFields(args.Model.Schema, args.Errors); var fieldErrors = new List(); diff --git a/backend/src/Squidex.Infrastructure/Queries/Json/QueryParser.cs b/backend/src/Squidex.Infrastructure/Queries/Json/QueryParser.cs index 16707c9b4..e5f28b1ce 100644 --- a/backend/src/Squidex.Infrastructure/Queries/Json/QueryParser.cs +++ b/backend/src/Squidex.Infrastructure/Queries/Json/QueryParser.cs @@ -26,7 +26,7 @@ namespace Squidex.Infrastructure.Queries.Json return Convert(model, query); } - public static ClrQuery Convert(this QueryModel model, Query query) + public static ClrQuery Convert(this QueryModel model, Query query) { if (query == null) { @@ -48,7 +48,7 @@ namespace Squidex.Infrastructure.Queries.Json return result; } - private static void ConvertFilters(this QueryModel model, ClrQuery result, List errors, Query query) + private static void ConvertFilters(this QueryModel model, ClrQuery result, List errors, Query query) { if (query.Filter == null) { @@ -76,11 +76,11 @@ namespace Squidex.Infrastructure.Queries.Json } } - public static Query ParseFromJson(string json, IJsonSerializer jsonSerializer) + public static Query ParseFromJson(string json, IJsonSerializer jsonSerializer) { try { - return jsonSerializer.Deserialize>(json); + return jsonSerializer.Deserialize>(json); } catch (JsonException ex) { diff --git a/backend/src/Squidex.Infrastructure/Queries/Json/ValueConverter.cs b/backend/src/Squidex.Infrastructure/Queries/Json/ValueConverter.cs index 9640dc102..c68549ed0 100644 --- a/backend/src/Squidex.Infrastructure/Queries/Json/ValueConverter.cs +++ b/backend/src/Squidex.Infrastructure/Queries/Json/ValueConverter.cs @@ -13,7 +13,7 @@ namespace Squidex.Infrastructure.Queries.Json { public static class ValueConverter { - private delegate bool Parser(List errors, PropertyPath path, IJsonValue value, out T result); + private delegate bool Parser(List errors, PropertyPath path, JsonValue value, out T result); private static readonly InstantPattern[] InstantPatterns = { @@ -22,13 +22,13 @@ namespace Squidex.Infrastructure.Queries.Json InstantPattern.CreateWithInvariantCulture("yyyy-MM-dd") }; - public static ClrValue? Convert(FilterField field, IJsonValue value, PropertyPath path, List errors) + public static ClrValue? Convert(FilterField field, JsonValue value, PropertyPath path, List errors) { ClrValue? result = null; var type = field.Schema.Type; - if (value is JsonNull && type != FilterSchemaType.GeoObject && field.IsNullable) + if (value.Type == JsonValueType.Null && type != FilterSchemaType.GeoObject && field.IsNullable) { return ClrValue.Null; } @@ -47,9 +47,9 @@ namespace Squidex.Infrastructure.Queries.Json case FilterSchemaType.Any: { - if (value is JsonArray jsonArray) + if (value.Type == JsonValueType.Array) { - var array = ParseArray(errors, path, jsonArray, TryParseDynamic); + var array = ParseArray(errors, path, value.AsArray, TryParseDynamic); result = array.Select(x => x?.Value).ToList(); } @@ -63,9 +63,9 @@ namespace Squidex.Infrastructure.Queries.Json case FilterSchemaType.Boolean: { - if (value is JsonArray jsonArray) + if (value.Type == JsonValueType.Array) { - result = ParseArray(errors, path, jsonArray, TryParseBoolean); + result = ParseArray(errors, path, value.AsArray, TryParseBoolean); } else if (TryParseBoolean(errors, path, value, out var temp)) { @@ -77,9 +77,9 @@ namespace Squidex.Infrastructure.Queries.Json case FilterSchemaType.Number: { - if (value is JsonArray jsonArray) + if (value.Type == JsonValueType.Array) { - result = ParseArray(errors, path, jsonArray, TryParseNumber); + result = ParseArray(errors, path, value.AsArray, TryParseNumber); } else if (TryParseNumber(errors, path, value, out var temp)) { @@ -91,9 +91,9 @@ namespace Squidex.Infrastructure.Queries.Json case FilterSchemaType.Guid: { - if (value is JsonArray jsonArray) + if (value.Type == JsonValueType.Array) { - result = ParseArray(errors, path, jsonArray, TryParseGuid); + result = ParseArray(errors, path, value.AsArray, TryParseGuid); } else if (TryParseGuid(errors, path, value, out var temp)) { @@ -105,9 +105,9 @@ namespace Squidex.Infrastructure.Queries.Json case FilterSchemaType.DateTime: { - if (value is JsonArray jsonArray) + if (value.Type == JsonValueType.Array) { - result = ParseArray(errors, path, jsonArray, TryParseDateTime); + result = ParseArray(errors, path, value.AsArray, TryParseDateTime); } else if (TryParseDateTime(errors, path, value, out var temp)) { @@ -120,9 +120,9 @@ namespace Squidex.Infrastructure.Queries.Json case FilterSchemaType.StringArray: case FilterSchemaType.String: { - if (value is JsonArray jsonArray) + if (value.Type == JsonValueType.Array) { - result = ParseArray(errors, path, jsonArray, TryParseString!); + result = ParseArray(errors, path, value.AsArray, TryParseString!); } else if (TryParseString(errors, path, value, out var temp)) { @@ -157,18 +157,18 @@ namespace Squidex.Infrastructure.Queries.Json return items; } - private static bool TryParseGeoJson(List errors, PropertyPath path, IJsonValue value, out FilterSphere result) + private static bool TryParseGeoJson(List errors, PropertyPath path, JsonValue value, out FilterSphere result) { const string expected = "Object(geo-json)"; result = default!; - if (value is JsonObject geoObject && - geoObject.TryGetValue("latitude", out var lat) && - geoObject.TryGetValue("longitude", out var lon) && - geoObject.TryGetValue("distance", out var distance)) + if (value.Type == JsonValueType.Object && + value.TryGetValue("latitude", out var lat) && lat.Type == JsonValueType.Number && + value.TryGetValue("longitude", out var lon) && lon.Type == JsonValueType.Number && + value.TryGetValue("distance", out var distance) && distance.Type == JsonValueType.Number) { - result = new FilterSphere(lon.Value, lat.Value, distance.Value); + result = new FilterSphere(lon.AsNumber, lat.AsNumber, distance.AsNumber); return true; } @@ -178,15 +178,15 @@ namespace Squidex.Infrastructure.Queries.Json return false; } - private static bool TryParseBoolean(List errors, PropertyPath path, IJsonValue value, out bool result) + private static bool TryParseBoolean(List errors, PropertyPath path, JsonValue value, out bool result) { const string expected = "Boolean"; result = default; - if (value is JsonBoolean jsonBoolean) + if (value.Type == JsonValueType.Boolean) { - result = jsonBoolean.Value; + result = value.AsBoolean; return true; } @@ -196,15 +196,15 @@ namespace Squidex.Infrastructure.Queries.Json return false; } - private static bool TryParseNumber(List errors, PropertyPath path, IJsonValue value, out double result) + private static bool TryParseNumber(List errors, PropertyPath path, JsonValue value, out double result) { const string expected = "Number"; result = default; - if (value is JsonNumber jsonNumber) + if (value.Type == JsonValueType.Number) { - result = jsonNumber.Value; + result = value.AsNumber; return true; } @@ -214,15 +214,15 @@ namespace Squidex.Infrastructure.Queries.Json return false; } - private static bool TryParseString(List errors, PropertyPath path, IJsonValue value, out string? result) + private static bool TryParseString(List errors, PropertyPath path, JsonValue value, out string? result) { const string expected = "String"; result = default; - if (value is JsonString jsonString) + if (value.Type == JsonValueType.String) { - result = jsonString.Value; + result = value.AsString; return true; } @@ -232,15 +232,15 @@ namespace Squidex.Infrastructure.Queries.Json return false; } - private static bool TryParseGuid(List errors, PropertyPath path, IJsonValue value, out Guid result) + private static bool TryParseGuid(List errors, PropertyPath path, JsonValue value, out Guid result) { const string expected = "String (Guid)"; result = default; - if (value is JsonString jsonString) + if (value.Type == JsonValueType.String) { - if (Guid.TryParse(jsonString.Value, out result)) + if (Guid.TryParse(value.AsString, out result)) { return true; } @@ -255,17 +255,19 @@ namespace Squidex.Infrastructure.Queries.Json return false; } - private static bool TryParseDateTime(List errors, PropertyPath path, IJsonValue value, out Instant result) + private static bool TryParseDateTime(List errors, PropertyPath path, JsonValue value, out Instant result) { const string expected = "String (ISO8601 DateTime)"; result = default; - if (value is JsonString jsonString) + if (value.Type == JsonValueType.String) { + var typed = value.AsString; + foreach (var pattern in InstantPatterns) { - var parsed = pattern.Parse(jsonString.Value); + var parsed = pattern.Parse(typed); if (parsed.Success) { @@ -285,23 +287,25 @@ namespace Squidex.Infrastructure.Queries.Json return false; } - private static bool TryParseDynamic(List errors, PropertyPath path, IJsonValue value, out ClrValue? result) + private static bool TryParseDynamic(List errors, PropertyPath path, JsonValue value, out ClrValue? result) { result = null; - switch (value) + switch (value.Type) { - case JsonNull: + case JsonValueType.Null: return true; - case JsonNumber jsonNumber: - result = jsonNumber.Value; + case JsonValueType.Number: + result = value.AsNumber; return true; - case JsonBoolean jsonBoolean: - result = jsonBoolean.Value; + case JsonValueType.Boolean: + result = value.AsBoolean; return true; - case JsonString jsonString: + case JsonValueType.String: { - if (Guid.TryParse(jsonString.Value, out var guid)) + var typed = value.AsString; + + if (Guid.TryParse(typed, out var guid)) { result = guid; @@ -310,7 +314,7 @@ namespace Squidex.Infrastructure.Queries.Json foreach (var pattern in InstantPatterns) { - var parsed = pattern.Parse(jsonString.Value); + var parsed = pattern.Parse(typed); if (parsed.Success) { @@ -320,7 +324,7 @@ namespace Squidex.Infrastructure.Queries.Json } } - result = jsonString.Value; + result = typed; return true; } diff --git a/backend/src/Squidex.Infrastructure/Queries/OData/ConstantWithTypeVisitor.cs b/backend/src/Squidex.Infrastructure/Queries/OData/ConstantWithTypeVisitor.cs index 176a7cfa6..98b3fe0dc 100644 --- a/backend/src/Squidex.Infrastructure/Queries/OData/ConstantWithTypeVisitor.cs +++ b/backend/src/Squidex.Infrastructure/Queries/OData/ConstantWithTypeVisitor.cs @@ -83,7 +83,8 @@ namespace Squidex.Infrastructure.Queries.OData return nodeIn.Collection.Select(x => (string)x.Value).ToList(); } - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } public override ClrValue Visit(ConstantNode nodeIn) @@ -95,7 +96,8 @@ namespace Squidex.Infrastructure.Queries.OData if (nodeIn.TypeReference == null) { - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } if (nodeIn.TypeReference.Definition == DateTimeType || nodeIn.TypeReference.Definition == DateType) @@ -138,7 +140,8 @@ namespace Squidex.Infrastructure.Queries.OData return (string)nodeIn.Value; } - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } private static Instant ParseInstant(object value) diff --git a/backend/src/Squidex.Infrastructure/Queries/OData/FilterVisitor.cs b/backend/src/Squidex.Infrastructure/Queries/OData/FilterVisitor.cs index 57fe7465d..aaab0dcb6 100644 --- a/backend/src/Squidex.Infrastructure/Queries/OData/FilterVisitor.cs +++ b/backend/src/Squidex.Infrastructure/Queries/OData/FilterVisitor.cs @@ -35,7 +35,8 @@ namespace Squidex.Infrastructure.Queries.OData return ClrFilter.Not(nodeIn.Operand.Accept(this)); } - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } public override FilterNode Visit(InNode nodeIn) @@ -94,7 +95,8 @@ namespace Squidex.Infrastructure.Queries.OData return ClrFilter.Contains(PropertyPathVisitor.Visit(fieldNode), value); } - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } public override FilterNode Visit(BinaryOperatorNode nodeIn) @@ -117,12 +119,14 @@ namespace Squidex.Infrastructure.Queries.OData if (functionNode.Parameters.ElementAt(1) is not ConstantNode constantNode) { - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } if (constantNode.Value is not GeographyPoint geographyPoint) { - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } var property = PropertyPathVisitor.Visit(functionNode.Parameters.ElementAt(0)); @@ -192,7 +196,8 @@ namespace Squidex.Infrastructure.Queries.OData } } - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } } diff --git a/backend/src/Squidex.Infrastructure/Queries/OData/SearchTermVisitor.cs b/backend/src/Squidex.Infrastructure/Queries/OData/SearchTermVisitor.cs index da97f869c..fcad79031 100644 --- a/backend/src/Squidex.Infrastructure/Queries/OData/SearchTermVisitor.cs +++ b/backend/src/Squidex.Infrastructure/Queries/OData/SearchTermVisitor.cs @@ -29,7 +29,8 @@ namespace Squidex.Infrastructure.Queries.OData return nodeIn.Left.Accept(this) + " " + nodeIn.Right.Accept(this); } - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } public override string Visit(SearchTermNode nodeIn) diff --git a/backend/src/Squidex.Infrastructure/Queries/PropertyPath.cs b/backend/src/Squidex.Infrastructure/Queries/PropertyPath.cs index d79a9c9ab..b5e1070b0 100644 --- a/backend/src/Squidex.Infrastructure/Queries/PropertyPath.cs +++ b/backend/src/Squidex.Infrastructure/Queries/PropertyPath.cs @@ -18,7 +18,7 @@ namespace Squidex.Infrastructure.Queries { if (items.Count == 0) { - throw new ArgumentException("Path cannot be empty.", nameof(items)); + ThrowHelper.ArgumentException("Path cannot be empty.", nameof(items)); } } @@ -48,7 +48,8 @@ namespace Squidex.Infrastructure.Queries if (inner == null || inner.Count == 0) { - throw new ArgumentException("Path cannot be empty.", nameof(source)); + ThrowHelper.ArgumentException("Path cannot be empty.", nameof(source)); + return null!; } else { diff --git a/backend/src/Squidex.Infrastructure/RefToken.cs b/backend/src/Squidex.Infrastructure/RefToken.cs index e07002290..c4b90d9a3 100644 --- a/backend/src/Squidex.Infrastructure/RefToken.cs +++ b/backend/src/Squidex.Infrastructure/RefToken.cs @@ -88,7 +88,8 @@ namespace Squidex.Infrastructure { if (!TryParse(value, out var result)) { - throw new ArgumentException("Ref token cannot be null or empty.", nameof(value)); + ThrowHelper.ArgumentException("Ref token cannot be null or empty.", nameof(value)); + return default!; } return result; diff --git a/backend/src/Squidex.Infrastructure/Reflection/TypeNameRegistry.cs b/backend/src/Squidex.Infrastructure/Reflection/TypeNameRegistry.cs index cecaa1723..045e7dfb5 100644 --- a/backend/src/Squidex.Infrastructure/Reflection/TypeNameRegistry.cs +++ b/backend/src/Squidex.Infrastructure/Reflection/TypeNameRegistry.cs @@ -36,7 +36,7 @@ namespace Squidex.Infrastructure.Reflection { var message = $"The name '{name}' is already registered with type '{typesByName[name]}'"; - throw new ArgumentException(message, nameof(type)); + ThrowHelper.ArgumentException(message, nameof(type)); } typesByName[name] = type; @@ -79,7 +79,7 @@ namespace Squidex.Infrastructure.Reflection { var message = $"The type '{type}' is already registered with name '{namesByType[type]}'"; - throw new ArgumentException(message, nameof(type)); + ThrowHelper.ArgumentException(message, nameof(type)); } namesByType[type] = name; @@ -88,7 +88,7 @@ namespace Squidex.Infrastructure.Reflection { var message = $"The name '{name}' is already registered with type '{typesByName[name]}'"; - throw new ArgumentException(message, nameof(type)); + ThrowHelper.ArgumentException(message, nameof(type)); } typesByName[name] = type; diff --git a/backend/src/Squidex.Infrastructure/States/Persistence.cs b/backend/src/Squidex.Infrastructure/States/Persistence.cs index a35dcd0e7..10004f82d 100644 --- a/backend/src/Squidex.Infrastructure/States/Persistence.cs +++ b/backend/src/Squidex.Infrastructure/States/Persistence.cs @@ -144,7 +144,7 @@ namespace Squidex.Infrastructure.States if (@event.EventStreamNumber != newVersion) { - throw new InvalidOperationException("Events must follow the snapshot version in consecutive order with no gaps."); + ThrowHelper.InvalidOperationException("Events must follow the snapshot version in consecutive order with no gaps."); } if (!isStopped) diff --git a/backend/src/Squidex.Infrastructure/ThrowHelper.cs b/backend/src/Squidex.Infrastructure/ThrowHelper.cs new file mode 100644 index 000000000..5c1afad62 --- /dev/null +++ b/backend/src/Squidex.Infrastructure/ThrowHelper.cs @@ -0,0 +1,49 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Infrastructure.Json; + +namespace Squidex.Infrastructure +{ + public static class ThrowHelper + { + public static void ArgumentException(string message, string? paramName) + { + throw new ArgumentException(message, paramName); + } + + public static void ArgumentNullException(string? paramName) + { + throw new ArgumentNullException(paramName); + } + + public static void KeyNotFoundException(string? message = null) + { + throw new KeyNotFoundException(message); + } + + public static void InvalidOperationException(string? message = null) + { + throw new InvalidOperationException(message); + } + + public static void InvalidCastException(string? message = null) + { + throw new InvalidCastException(message); + } + + public static void JsonException(string? message = null, Exception? ex = null) + { + throw new JsonException(message, ex); + } + + public static void NotSupportedException(string? message = null) + { + throw new NotSupportedException(message); + } + } +} diff --git a/backend/src/Squidex.Web/ApiController.cs b/backend/src/Squidex.Web/ApiController.cs index 744f3faf8..edbfd6ec5 100644 --- a/backend/src/Squidex.Web/ApiController.cs +++ b/backend/src/Squidex.Web/ApiController.cs @@ -33,7 +33,8 @@ namespace Squidex.Web if (app == null) { - throw new InvalidOperationException("Not in a app context."); + ThrowHelper.InvalidOperationException("Not in a app context."); + return default!; } return app; @@ -48,7 +49,8 @@ namespace Squidex.Web if (schema == null) { - throw new InvalidOperationException("Not in a schema context."); + ThrowHelper.InvalidOperationException("Not in a schema context."); + return default!; } return schema; diff --git a/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs b/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs index 56e24b6e6..17ae3cb58 100644 --- a/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs +++ b/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs @@ -39,10 +39,11 @@ namespace Squidex.Web.CommandMiddlewares if (context.App == null) { - throw new InvalidOperationException("Cannot resolve app."); + ThrowHelper.InvalidOperationException("Cannot resolve app."); + return default!; } return context.App.NamedId(); } } -} \ No newline at end of file +} diff --git a/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs b/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs index 31c4c1a23..4a4cfcf9f 100644 --- a/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs +++ b/backend/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs @@ -45,7 +45,8 @@ namespace Squidex.Web.CommandMiddlewares if (feature == null) { - throw new InvalidOperationException("Cannot resolve schema."); + ThrowHelper.InvalidOperationException("Cannot resolve schema."); + return default!; } return feature.Schema.NamedId(); diff --git a/backend/src/Squidex.Web/Json/TypedJsonInheritanceConverter.cs b/backend/src/Squidex.Web/Json/TypedJsonInheritanceConverter.cs index cedbb08b0..56335c1cb 100644 --- a/backend/src/Squidex.Web/Json/TypedJsonInheritanceConverter.cs +++ b/backend/src/Squidex.Web/Json/TypedJsonInheritanceConverter.cs @@ -7,9 +7,9 @@ using System.Reflection; using System.Runtime.Serialization; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NJsonSchema.Converters; +using Squidex.Infrastructure; #pragma warning disable RECS0108 // Warns about static fields in generic types @@ -83,12 +83,14 @@ namespace Squidex.Web.Json { if (discriminatorValue == null) { - throw new JsonException("Cannot find discriminator."); + ThrowHelper.JsonException("Cannot find discriminator."); + return default!; } if (!mapping.TryGetValue(discriminatorValue, out var type)) { - throw new JsonException($"Could not find subtype of '{objectType.Name}' with discriminator '{discriminatorValue}'."); + ThrowHelper.JsonException($"Could not find subtype of '{objectType.Name}' with discriminator '{discriminatorValue}'."); + return default!; } return type; diff --git a/backend/src/Squidex.Web/Pipeline/UsageStream.cs b/backend/src/Squidex.Web/Pipeline/UsageStream.cs index 0207e8451..a5215be60 100644 --- a/backend/src/Squidex.Web/Pipeline/UsageStream.cs +++ b/backend/src/Squidex.Web/Pipeline/UsageStream.cs @@ -36,7 +36,7 @@ namespace Squidex.Web.Pipeline public override long Length { - get { throw new NotSupportedException(); } + get => throw new NotSupportedException(); } public override long Position diff --git a/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs b/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs index bf346f3ea..27e3bb519 100644 --- a/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs +++ b/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs @@ -119,8 +119,8 @@ namespace Squidex.Areas.Api.Config.OpenApi CreateObjectMap(), CreateObjectMap(), - CreateAnyMap(), - CreateAnyMap>() + CreateAnyMap(), + CreateAnyMap>() }; settings.SchemaType = SchemaType.OpenApi3; diff --git a/backend/src/Squidex/Areas/Api/Config/OpenApi/XmlResponseTypesProcessor.cs b/backend/src/Squidex/Areas/Api/Config/OpenApi/XmlResponseTypesProcessor.cs index e20924e55..dffc8d623 100644 --- a/backend/src/Squidex/Areas/Api/Config/OpenApi/XmlResponseTypesProcessor.cs +++ b/backend/src/Squidex/Areas/Api/Config/OpenApi/XmlResponseTypesProcessor.cs @@ -10,6 +10,7 @@ using Namotion.Reflection; using NSwag; using NSwag.Generation.Processors; using NSwag.Generation.Processors.Contexts; +using Squidex.Infrastructure; namespace Squidex.Areas.Api.Config.OpenApi { @@ -40,7 +41,8 @@ namespace Squidex.Areas.Api.Config.OpenApi if (description.Contains("=>", StringComparison.Ordinal)) { - throw new InvalidOperationException("Description not formatted correcly."); + ThrowHelper.InvalidOperationException("Description not formatted correcly."); + return default!; } response.Description = description; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs index 2c13c3a68..48d6b7e3c 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs @@ -26,8 +26,6 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models { public sealed class AppDto : Resource { - private static readonly JsonObject EmptyObject = JsonValue.Object(); - /// /// The name of the app. /// @@ -90,7 +88,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// The properties from the role. /// [LocalizedRequired] - public JsonObject RoleProperties { get; set; } = EmptyObject; + public JsonValue RoleProperties { get; set; } public static AppDto FromDomain(IAppEntity app, string userId, bool isFrontend, Resources resources) { @@ -118,6 +116,10 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models permissions = role.Permissions; } + else + { + result.RoleProperties = new JsonObject(); + } if (resources.Includes(Shared.Permissions.ForApp(Shared.Permissions.AppContents, app.Name), permissions)) { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateRoleDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateRoleDto.cs index 0f72527a4..c45b1387a 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateRoleDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateRoleDto.cs @@ -23,7 +23,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// /// Associated list of UI properties. /// - public JsonObject? Properties { get; set; } + public JsonObject Properties { get; set; } public UpdateRole ToCommand(string name) { diff --git a/backend/src/Squidex/Areas/Api/Controllers/JsonQueryDto.cs b/backend/src/Squidex/Areas/Api/Controllers/JsonQueryDto.cs index fff98883e..098f655fa 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/JsonQueryDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/JsonQueryDto.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure.Queries; namespace Squidex.Areas.Api.Controllers { [JsonSchemaFlatten] - public sealed class JsonQueryDto : Query + public sealed class JsonQueryDto : Query { } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/UI/Models/UpdateSettingDto.cs b/backend/src/Squidex/Areas/Api/Controllers/UI/Models/UpdateSettingDto.cs index b6c3f5f53..5932be9a6 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/UI/Models/UpdateSettingDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/UI/Models/UpdateSettingDto.cs @@ -14,6 +14,6 @@ namespace Squidex.Areas.Api.Controllers.UI.Models /// /// The value for the setting. /// - public IJsonValue Value { get; set; } + public JsonValue Value { get; set; } } } diff --git a/backend/src/Squidex/Areas/IdentityServer/Controllers/Connect/AuthorizationController.cs b/backend/src/Squidex/Areas/IdentityServer/Controllers/Connect/AuthorizationController.cs index 25ad0880f..4edfbea42 100644 --- a/backend/src/Squidex/Areas/IdentityServer/Controllers/Connect/AuthorizationController.cs +++ b/backend/src/Squidex/Areas/IdentityServer/Controllers/Connect/AuthorizationController.cs @@ -16,6 +16,7 @@ using OpenIddict.Server.AspNetCore; using Squidex.Areas.IdentityServer.Config; using Squidex.Areas.IdentityServer.Controllers; using Squidex.Domain.Users; +using Squidex.Infrastructure; using Squidex.Shared.Identity; using Squidex.Shared.Users; using Squidex.Web; @@ -46,7 +47,8 @@ namespace Notifo.Areas.Account.Controllers var request = HttpContext.GetOpenIddictServerRequest(); if (request == null) { - throw new InvalidOperationException("The OpenID Connect request cannot be retrieved."); + ThrowHelper.InvalidOperationException("The OpenID Connect request cannot be retrieved."); + return default!; } if (request.IsAuthorizationCodeGrantType() || request.IsRefreshTokenGrantType() || request.IsImplicitFlow()) @@ -54,7 +56,8 @@ namespace Notifo.Areas.Account.Controllers var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal; if (principal == null) { - throw new InvalidOperationException("The user details cannot be retrieved."); + ThrowHelper.InvalidOperationException("The user details cannot be retrieved."); + return default!; } var user = await userService.GetAsync(principal, HttpContext.RequestAborted); @@ -92,13 +95,15 @@ namespace Notifo.Areas.Account.Controllers { if (request.ClientId == null) { - throw new InvalidOperationException("The OpenID Connect request cannot be retrieved."); + ThrowHelper.InvalidOperationException("The OpenID Connect request cannot be retrieved."); + return default!; } var application = await applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted); if (application == null) { - throw new InvalidOperationException("The application details cannot be found in the database."); + ThrowHelper.InvalidOperationException("The application details cannot be found in the database."); + return default!; } var principal = await CreateApplicationPrincipalAsync(request, application); @@ -106,7 +111,8 @@ namespace Notifo.Areas.Account.Controllers return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); } - throw new InvalidOperationException("The specified grant type is not supported."); + ThrowHelper.InvalidOperationException("The specified grant type is not supported."); + return default!; } [HttpGet("connect/authorize")] @@ -115,7 +121,8 @@ namespace Notifo.Areas.Account.Controllers var request = HttpContext.GetOpenIddictServerRequest(); if (request == null) { - throw new InvalidOperationException("The OpenID Connect request cannot be retrieved."); + ThrowHelper.InvalidOperationException("The OpenID Connect request cannot be retrieved."); + return default!; } if (User.Identity?.IsAuthenticated != true) @@ -149,7 +156,8 @@ namespace Notifo.Areas.Account.Controllers if (user == null) { - throw new InvalidOperationException("The user details cannot be retrieved."); + ThrowHelper.InvalidOperationException("The user details cannot be retrieved."); + return default!; } var principal = await CreatePrincipalAsync(request, user); diff --git a/backend/src/Squidex/Areas/IdentityServer/Controllers/Extensions.cs b/backend/src/Squidex/Areas/IdentityServer/Controllers/Extensions.cs index c8ed1a3e0..c354b4cfb 100644 --- a/backend/src/Squidex/Areas/IdentityServer/Controllers/Extensions.cs +++ b/backend/src/Squidex/Areas/IdentityServer/Controllers/Extensions.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Identity; +using Squidex.Infrastructure; using Squidex.Infrastructure.Security; using Squidex.Web; @@ -20,14 +21,16 @@ namespace Squidex.Areas.IdentityServer.Controllers if (login == null) { - throw new InvalidOperationException("Request from external provider cannot be handled."); + ThrowHelper.InvalidOperationException("Request from external provider cannot be handled."); + return default!; } var email = login.Principal.GetEmail(); if (string.IsNullOrWhiteSpace(email)) { - throw new InvalidOperationException("External provider does not provide email claim."); + ThrowHelper.InvalidOperationException("External provider does not provide email claim."); + return default!; } login.ProviderDisplayName = email; diff --git a/backend/src/Squidex/Config/Domain/SerializationServices.cs b/backend/src/Squidex/Config/Domain/SerializationServices.cs index 3fe76d62d..9bdf71f2e 100644 --- a/backend/src/Squidex/Config/Domain/SerializationServices.cs +++ b/backend/src/Squidex/Config/Domain/SerializationServices.cs @@ -41,7 +41,7 @@ namespace Squidex.Config.Domain new JsonValueConverter(), new StringEnumConverter(), new SurrogateConverter(), - new SurrogateConverter, JsonFilterSurrogate>(), + new SurrogateConverter, JsonFilterSurrogate>(), new SurrogateConverter(), new SurrogateConverter(), new SurrogateConverter(), diff --git a/backend/src/Squidex/Config/Web/WebServices.cs b/backend/src/Squidex/Config/Web/WebServices.cs index 3ccbcf83b..0ad5d1481 100644 --- a/backend/src/Squidex/Config/Web/WebServices.cs +++ b/backend/src/Squidex/Config/Web/WebServices.cs @@ -11,17 +11,19 @@ using GraphQL.DI; using GraphQL.Execution; using GraphQL.MicrosoftDI; using GraphQL.NewtonsoftJson; -using GraphQL.Server; using GraphQL.Server.Transports.AspNetCore; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; using Squidex.Config.Domain; +using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Contents.GraphQL; using Squidex.Infrastructure.Caching; using Squidex.Infrastructure.Json.Newtonsoft; +using Squidex.Infrastructure.Json.Objects; using Squidex.Pipeline.Plugins; using Squidex.Web; using Squidex.Web.GraphQL; @@ -77,11 +79,19 @@ namespace Squidex.Config.Web services.AddMvc(options => { + // Never change this order here. options.Filters.Add(); options.Filters.Add(); options.Filters.Add(); options.Filters.Add(); options.Filters.Add(); + + // Ingore all values that could have JsonValue somewhere. + options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(ContentData))); + options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(ContentFieldData))); + options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(JsonArray))); + options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(JsonObject))); + options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(JsonValue))); }) .AddDataAnnotationsLocalization() .AddRazorRuntimeCompilation() diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesJsonTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesJsonTests.cs index 56be28a7f..78231b9b7 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesJsonTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesJsonTests.cs @@ -51,7 +51,7 @@ namespace Squidex.Domain.Apps.Core.Model.Apps new PermissionSet( "Permission1", "Permission2"), - JsonValue.Object() + new JsonObject() .Add("Property1", true) .Add("Property2", true)); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesTests.cs index 0fd89d392..87f813eb2 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesTests.cs @@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Core.Model.Apps { var roles_1 = roles_0.Add(role); - Assert.Equal(new Role(role), roles_1[role]); + Assert.Equal(new Role(role, null, new JsonObject()), roles_1[role]); } [Fact] @@ -70,9 +70,9 @@ namespace Squidex.Domain.Apps.Core.Model.Apps [Fact] public void Should_update_role_properties() { - var roles_1 = roles_0.Update(firstRole, properties: JsonValue.Object().Add("P1", true)); + var roles_1 = roles_0.Update(firstRole, properties: new JsonObject().Add("P1", true)); - roles_1[firstRole].Should().BeEquivalentTo(Role.WithProperties(firstRole, JsonValue.Object().Add("P1", true))); + roles_1[firstRole].Should().BeEquivalentTo(Role.WithProperties(firstRole, new JsonObject().Add("P1", true))); } [Fact] diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetMetadataTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetMetadataTests.cs index a70071850..2a8da892d 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetMetadataTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetMetadataTests.cs @@ -97,9 +97,9 @@ namespace Squidex.Domain.Apps.Core.Model.Assets var sut = new AssetMetadata { ["meta"] = - JsonValue.Object() + new JsonObject() .Add("nested1", - JsonValue.Object() + new JsonObject() .Add("nested2", 12)) }; diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/ContentDataTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/ContentDataTests.cs index 85faeac76..663491eec 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/ContentDataTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/ContentDataTests.cs @@ -205,8 +205,8 @@ namespace Squidex.Domain.Apps.Core.Model.Contents newData.UseSameFields(oldData); - Assert.Same(newData["field1"]!["en"], oldData["field1"]!["en"]); - Assert.NotSame(newData["field1"]!["de"], oldData["field1"]!["de"]); + Assert.Same(newData["field1"]!["en"].Value, oldData["field1"]!["en"].Value); + Assert.NotSame(newData["field1"]!["de"].Value, oldData["field1"]!["de"].Value); Assert.NotSame(newData["field1"], oldData["field1"]); } } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/ContentFieldDataTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/ContentFieldDataTests.cs index b3b30bbba..a300b9f55 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/ContentFieldDataTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/ContentFieldDataTests.cs @@ -67,8 +67,8 @@ namespace Squidex.Domain.Apps.Core.Model.Contents { var source = new ContentFieldData { - ["en"] = JsonValue.Array(), - ["de"] = JsonValue.Array() + ["en"] = new JsonArray(), + ["de"] = new JsonArray() }; var clone = source.Clone(); @@ -77,7 +77,7 @@ namespace Squidex.Domain.Apps.Core.Model.Contents foreach (var (key, value) in clone) { - Assert.NotSame(value, source[key]); + Assert.NotSame(value.Value, source[key].Value); } } } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionFlatTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionFlatTests.cs index 9f5b73b6a..6a7f8b7f1 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionFlatTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionFlatTests.cs @@ -23,7 +23,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent .AddLocalized("en", 2)) .AddField("field2", new ContentFieldData() - .AddLocalized("de", null) + .AddLocalized("de", JsonValue.Null) .AddLocalized("it", 4)) .AddField("field3", new ContentFieldData() @@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent { "field2", new ContentFieldData() - .AddLocalized("de", null) + .AddLocalized("de", JsonValue.Null) .AddLocalized("it", 4) }, { "field3", JsonValue.Create(6) }, 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 1abaf6572..ca08b8cd4 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 @@ -52,33 +52,33 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nested", JsonValue.Array(1, 2))))) .AddField("component", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("references", JsonValue.Array(1, 2)) .Add("assets1", JsonValue.Array(1)) .Add("array", JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nested", JsonValue.Array(1, 2)))) .Add(Component.Discriminator, DomainId.Empty))) .AddField("components", new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("references", JsonValue.Array(1, 2)) .Add("assets1", JsonValue.Array(1)) .Add("array", JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nested", JsonValue.Array(1, 2)))) .Add(Component.Discriminator, DomainId.Empty)))); @@ -93,30 +93,30 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object()))) + new JsonObject()))) .AddField("component", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("assets1", JsonValue.Array(1)) .Add("array", JsonValue.Array( - JsonValue.Object())) + new JsonObject())) .Add(Component.Discriminator, DomainId.Empty))) .AddField("components", new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("assets1", JsonValue.Array(1)) .Add("array", JsonValue.Array( - JsonValue.Object())) + new JsonObject())) .Add(Component.Discriminator, DomainId.Empty)))); - var converter = new ValueConverter((data, field, parent) => field.Name != "assets1" ? null : data); + var converter = new ValueConverter((data, field, parent) => field.Name != "assets1" ? (JsonValue?)null : data); var actual = source.Convert(schema, 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 d1a737389..659f98fee 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 @@ -22,9 +22,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent private static IEnumerable InvalidValues() { - yield return new object?[] { null }; yield return new object?[] { JsonValue.Null }; - yield return new object?[] { JsonValue.False }; // Undefined + yield return new object?[] { JsonValue.Create(false) }; // Undefined } [Fact] @@ -34,7 +33,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent var source = new ContentFieldData() - .AddInvariant(JsonValue.Object()); + .AddInvariant(new JsonObject()); var result = FieldConverters.ForValues(ResolvedComponents.Empty, (value, field, parent) => null)(source, field); @@ -50,7 +49,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent var source = new ContentFieldData() - .AddLocalized("en", null) + .AddLocalized("en", JsonValue.Null) .AddLocalized("de", 1); var result = FieldConverters.ExcludeChangedTypes(TestUtils.DefaultSerializer)(source, field); @@ -118,7 +117,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Theory] [MemberData(nameof(InvalidValues))] - public void Should_resolve_master_language_from_invariant(IJsonValue? value) + public void Should_resolve_master_language_from_invariant(JsonValue value) { var field = Fields.String(1, "string", Partitioning.Language); @@ -127,7 +126,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent .AddLocalized("iv", "A") .AddLocalized("it", "B"); - if (value != JsonValue.False) + if (value != false) { source["en"] = value!; } @@ -173,7 +172,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Theory] [MemberData(nameof(InvalidValues))] - public void Should_resolve_invariant_from_master_language(IJsonValue? value) + public void Should_resolve_invariant_from_master_language(JsonValue value) { var field = Fields.String(1, "string", Partitioning.Invariant); @@ -182,7 +181,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent .AddLocalized("de", "DE") .AddLocalized("en", "EN"); - if (value != JsonValue.False) + if (value != false) { source[InvariantPartitioning.Key] = value!; } @@ -229,7 +228,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Theory] [MemberData(nameof(InvalidValues))] - public void Should_resolve_from_fallback_language_if_found(IJsonValue? value) + public void Should_resolve_from_fallback_language_if_found(JsonValue value) { var field = Fields.String(1, "string", Partitioning.Language); @@ -244,7 +243,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent .AddLocalized("en", "EN") .AddLocalized("it", "IT"); - if (value != JsonValue.False) + if (value != false) { source["de"] = value!; } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/StringFormatterTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/StringFormatterTests.cs index 1f10cb003..2df9b5932 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/StringFormatterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/StringFormatterTests.cs @@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent { var field = Fields.Array(1, "field", Partitioning.Invariant); - var formatted = StringFormatter.Format(field, null); + var formatted = StringFormatter.Format(field, default); Assert.Empty(formatted); } @@ -37,7 +37,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_array_field_without_items() { - var value = JsonValue.Array(); + var value = new JsonArray(); var field = Fields.Array(1, "field", Partitioning.Invariant); @@ -49,7 +49,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_array_field_with_single_item() { - var value = JsonValue.Array(JsonValue.Object()); + var value = JsonValue.Array(new JsonObject()); var field = Fields.Array(1, "field", Partitioning.Invariant); @@ -61,7 +61,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_array_field_with_multiple_items() { - var value = JsonValue.Array(JsonValue.Object(), JsonValue.Object()); + var value = JsonValue.Array(new JsonObject(), new JsonObject()); var field = Fields.Array(1, "field", Partitioning.Invariant); @@ -85,7 +85,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_assets_field_without_items() { - var value = JsonValue.Array(); + var value = new JsonArray(); var field = Fields.Assets(1, "field", Partitioning.Invariant); @@ -97,7 +97,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_assets_field_with_single_item() { - var value = JsonValue.Array(JsonValue.Object()); + var value = JsonValue.Array(new JsonObject()); var field = Fields.Assets(1, "field", Partitioning.Invariant); @@ -109,7 +109,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_assets_field_with_multiple_items() { - var value = JsonValue.Array(JsonValue.Object(), JsonValue.Object()); + var value = JsonValue.Array(new JsonObject(), new JsonObject()); var field = Fields.Assets(1, "field", Partitioning.Invariant); @@ -169,7 +169,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_component_field() { - var value = JsonValue.Object(); + var value = new JsonObject(); var field = Fields.Component(1, "field", Partitioning.Invariant); @@ -181,7 +181,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_components_field_without_items() { - var value = JsonValue.Array(); + var value = new JsonArray(); var field = Fields.Components(1, "field", Partitioning.Invariant); @@ -193,7 +193,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_components_field_with_single_item() { - var value = JsonValue.Array(JsonValue.Object()); + var value = JsonValue.Array(new JsonObject()); var field = Fields.Components(1, "field", Partitioning.Invariant); @@ -205,7 +205,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_components_field_with_multiple_items() { - var value = JsonValue.Array(JsonValue.Object(), JsonValue.Object()); + var value = JsonValue.Array(new JsonObject(), new JsonObject()); var field = Fields.Components(1, "field", Partitioning.Invariant); @@ -229,7 +229,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_geolocation_field_with_correct_data() { - var value = JsonValue.Object().Add("latitude", 18.9).Add("longitude", 10.9); + var value = new JsonObject().Add("latitude", 18.9).Add("longitude", 10.9); var field = Fields.Geolocation(1, "field", Partitioning.Invariant); @@ -241,7 +241,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_geolocation_field_with_missing_property() { - var value = JsonValue.Object().Add("latitude", 18.9); + var value = new JsonObject().Add("latitude", 18.9); var field = Fields.Geolocation(1, "field", Partitioning.Invariant); @@ -265,7 +265,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_json_field() { - var value = JsonValue.Object(); + var value = new JsonObject(); var field = Fields.Json(1, "field", Partitioning.Invariant); @@ -289,7 +289,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_references_field_without_items() { - var value = JsonValue.Array(); + var value = new JsonArray(); var field = Fields.References(1, "field", Partitioning.Invariant); @@ -301,7 +301,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_references_field_with_single_item() { - var value = JsonValue.Array(JsonValue.Object()); + var value = JsonValue.Array(new JsonObject()); var field = Fields.References(1, "field", Partitioning.Invariant); @@ -313,7 +313,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent [Fact] public void Should_format_references_field_with_multiple_items() { - var value = JsonValue.Array(JsonValue.Object(), JsonValue.Object()); + var value = JsonValue.Array(new JsonObject(), new JsonObject()); var field = Fields.References(1, "field", Partitioning.Invariant); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/DefaultValues/DefaultValuesTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/DefaultValues/DefaultValuesTests.cs index 229848947..2d21abdb8 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/DefaultValues/DefaultValuesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/DefaultValues/DefaultValuesTests.cs @@ -52,14 +52,14 @@ namespace Squidex.Domain.Apps.Core.Operations.DefaultValues data.GenerateDefaultValues(schema, languagesConfig.ToResolver()); - Assert.Equal(456, ((JsonNumber)data["myNumber"]!["iv"]).Value); + Assert.Equal(456, data["myNumber"]!["iv"].AsNumber); - Assert.Equal("de-string", data["myString"]!["de"].ToString()); - Assert.Equal("en-string", data["myString"]!["en"].ToString()); + Assert.Equal("de-string", data["myString"]!["de"].AsString); + Assert.Equal("en-string", data["myString"]!["en"].AsString); - Assert.Equal(now.ToString(), data["myDatetime"]!["iv"].ToString()); + Assert.Equal(now.ToString(), data["myDatetime"]!["iv"].AsString); - Assert.True(((JsonBoolean)data["myBoolean"]!["iv"]).Value); + Assert.True(data["myBoolean"]!["iv"].AsBoolean); } [Fact] @@ -76,8 +76,8 @@ namespace Squidex.Domain.Apps.Core.Operations.DefaultValues data.GenerateDefaultValues(schema, languagesConfig.ToResolver()); - Assert.Equal(string.Empty, data["myString"]!["de"].ToString()); - Assert.Equal("en-string", data["myString"]!["en"].ToString()); + Assert.Equal(string.Empty, data["myString"]!["de"].AsString); + Assert.Equal("en-string", data["myString"]!["en"].AsString); } [Fact] @@ -87,7 +87,7 @@ namespace Squidex.Domain.Apps.Core.Operations.DefaultValues Fields.Assets(1, "1", Partitioning.Invariant, new AssetsFieldProperties()); - Assert.Equal(JsonValue.Array(), DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); + Assert.Equal(new JsonArray(), DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); } [Fact] @@ -114,7 +114,7 @@ namespace Squidex.Domain.Apps.Core.Operations.DefaultValues DefaultValue = ReadonlyList.Create("1", "2") }); - Assert.Equal(JsonValue.Array(), DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); + Assert.Equal(new JsonArray(), DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); } [Fact] @@ -245,7 +245,7 @@ namespace Squidex.Domain.Apps.Core.Operations.DefaultValues Fields.References(1, "1", Partitioning.Invariant, new ReferencesFieldProperties()); - Assert.Equal(JsonValue.Array(), DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); + Assert.Equal(new JsonArray(), DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); } [Fact] @@ -272,7 +272,7 @@ namespace Squidex.Domain.Apps.Core.Operations.DefaultValues DefaultValue = ReadonlyList.Create("1", "2") }); - Assert.Equal(JsonValue.Array(), DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); + Assert.Equal(new JsonArray(), DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); } [Fact] @@ -326,7 +326,7 @@ namespace Squidex.Domain.Apps.Core.Operations.DefaultValues DefaultValue = ReadonlyList.Create("tag1", "tag2") }); - Assert.Equal(JsonValue.Array(), DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); + Assert.Equal(new JsonArray(), DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); } private Instant FutureDays(int days) 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 c57806385..c4c7ea53f 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 @@ -96,44 +96,44 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nestedAssets", JsonValue.Array(id1, id2)) .Add("nestedComponent", - JsonValue.Object() + new JsonObject() .Add("references", JsonValue.Array(id1, id2)) .Add(Component.Discriminator, DomainId.Empty)) .Add("nestedComponents", JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("references", JsonValue.Array(id1, id2)) .Add(Component.Discriminator, DomainId.Empty)))))) .AddField("component", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("references", JsonValue.Array(id1, id2)) .Add("assets1", JsonValue.Array(id1)) .Add("array", JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nestedAssets", JsonValue.Array(id1, id2)))) .Add(Component.Discriminator, DomainId.Empty))) .AddField("components", new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("references", JsonValue.Array(id1, id2)) .Add("assets1", JsonValue.Array(id1)) .Add("array", JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nestedAssets", JsonValue.Array(id1, id2)))) .Add(Component.Discriminator, DomainId.Empty)))); @@ -144,49 +144,49 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds .AddInvariant(JsonValue.Array(id2))) .AddField("assets1", new ContentFieldData() - .AddInvariant(JsonValue.Array())) + .AddInvariant(new JsonArray())) .AddField("array", new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nestedAssets", JsonValue.Array(id2)) .Add("nestedComponent", - JsonValue.Object() + new JsonObject() .Add("references", JsonValue.Array(id2)) .Add(Component.Discriminator, DomainId.Empty)) .Add("nestedComponents", JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("references", JsonValue.Array(id2)) .Add(Component.Discriminator, DomainId.Empty)))))) .AddField("component", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("references", JsonValue.Array(id2)) .Add("assets1", - JsonValue.Array()) + new JsonArray()) .Add("array", JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nestedAssets", JsonValue.Array(id2)))) .Add(Component.Discriminator, DomainId.Empty))) .AddField("components", new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("references", JsonValue.Array(id2)) .Add("assets1", - JsonValue.Array()) + new JsonArray()) .Add("array", JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nestedAssets", JsonValue.Array(id2)))) .Add(Component.Discriminator, DomainId.Empty)))); @@ -220,7 +220,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var value = JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add(field.Name, CreateValue(id1, id2))); var result = arrayField.GetReferencedIds(value, components).ToArray(); @@ -241,7 +241,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(), components).ToArray(); + var result = field.GetReferencedIds(new JsonArray(), components).ToArray(); Assert.Empty(result); } @@ -250,7 +250,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, components).ToArray(); + var result = field.GetReferencedIds(default, components).ToArray(); Assert.Empty(result); } @@ -259,7 +259,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, components).ToArray(); + var result = field.GetReferencedIds(default, components).ToArray(); Assert.Empty(result); } @@ -318,7 +318,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds return HashSet.Of(DomainId.NewGuid()); } - private static IJsonValue CreateValue(params object[] ids) + private static JsonValue CreateValue(params object[] ids) { return JsonValue.Array(ids); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceFormattingTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceFormattingTests.cs index 8725205e8..3591c73f3 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceFormattingTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceFormattingTests.cs @@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var formatted = data.FormatReferences(schema, languages); var expected = - JsonValue.Object() + new JsonObject() .Add("en", "EN, 12") .Add("de", "DE, 12"); @@ -53,7 +53,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var formatted = data.FormatReferences(schema, languages); var expected = - JsonValue.Object() + new JsonObject() .Add("en", "EN") .Add("de", "DE"); @@ -70,7 +70,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var formatted = data.FormatReferences(schema, languages); var expected = - JsonValue.Object() + new JsonObject() .Add("en", string.Empty) .Add("de", string.Empty); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs index 0eeca3751..5ee34107b 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterCompareTests.cs @@ -577,7 +577,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules new ContentData() .AddField("city", new ContentFieldData() - .AddInvariant(JsonValue.Array())) + .AddInvariant(new JsonArray())) }; var result = await sut.FormatAsync(script, @event); @@ -601,7 +601,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules new ContentData() .AddField("city", new ContentFieldData() - .AddInvariant(JsonValue.Object().Add("name", "Berlin"))) + .AddInvariant(new JsonObject().Add("name", "Berlin"))) }; var result = await sut.FormatAsync(script, @event); @@ -673,7 +673,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules new ContentData() .AddField("city", new ContentFieldData() - .AddInvariant(JsonValue.Object().Add("name", "Berlin"))) + .AddInvariant(new JsonObject().Add("name", "Berlin"))) }; var result = await sut.FormatAsync(script, @event); @@ -697,7 +697,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules new ContentData() .AddField("city", new ContentFieldData() - .AddInvariant(JsonValue.Object().Add("name", "Berlin"))) + .AddInvariant(new JsonObject().Add("name", "Berlin"))) }; var result = await sut.FormatAsync(script, @event); @@ -745,7 +745,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules new ContentData() .AddField("city", new ContentFieldData() - .AddInvariant(JsonValue.Object().Add("name", "Berlin"))) + .AddInvariant(new JsonObject().Add("name", "Berlin"))) }; var result = await sut.FormatAsync(script, @event); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs index 149a45271..59d0442e3 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs @@ -42,7 +42,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules { public (bool Match, ValueTask) Format(EnrichedEvent @event, object value, string[] path) { - if (path[0] == "data" && value is JsonArray) + if (path[0] == "data" && value is JsonValue jsonValue && jsonValue.Type == JsonValueType.Array) { return (true, GetValueAsync()); } @@ -142,7 +142,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules new ContentData() .AddField("city", new ContentFieldData() - .AddInvariant(JsonValue.Array())) + .AddInvariant(new JsonArray())) }; var result = await sut.FormatAsync("${CONTENT_DATA.city.iv.data.name}", @event); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/ContentDataObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/ContentDataObjectTests.cs index edb196750..5961a93e4 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/ContentDataObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/ContentDataObjectTests.cs @@ -211,13 +211,13 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting new ContentData() .AddField("geo", new ContentFieldData() - .AddInvariant(JsonValue.Object().Add("lat", 1.0))); + .AddInvariant(new JsonObject().Add("lat", 1.0))); var expected = new ContentData() .AddField("geo", new ContentFieldData() - .AddInvariant(JsonValue.Object().Add("lat", 1.0).Add("lon", 4.0))); + .AddInvariant(new JsonObject().Add("lat", 1.0).Add("lon", 4.0))); const string script = @" data.geo.iv = { lat: data.geo.iv.lat, lon: data.geo.iv.lat + 3 } @@ -235,13 +235,13 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting new ContentData() .AddField("geo", new ContentFieldData() - .AddInvariant(JsonValue.Object().Add("lat", 1.0))); + .AddInvariant(new JsonObject().Add("lat", 1.0))); var expected = new ContentData() .AddField("geo", new ContentFieldData() - .AddInvariant(JsonValue.Object().Add("lat", 2.0).Add("lon", 4.0))); + .AddInvariant(new JsonObject().Add("lat", 2.0).Add("lon", 4.0))); const string script = @" var nested = data.geo.iv; @@ -262,7 +262,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting new ContentData() .AddField("geo", new ContentFieldData() - .AddInvariant(JsonValue.Object().Add("lat", 2.0).Add("lon", 4.0))); + .AddInvariant(new JsonObject().Add("lat", 2.0).Add("lon", 4.0))); const string script = @" var nested = data.geo.iv; @@ -364,7 +364,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting new ContentData() .AddField("obj", new ContentFieldData() - .AddInvariant(JsonValue.Array())); + .AddInvariant(new JsonArray())); const string script = @" data.obj.iv[0] = 1 @@ -383,7 +383,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting new ContentData() .AddField("number", new ContentFieldData() - .AddInvariant(JsonValue.Array())); + .AddInvariant(new JsonArray())); var expected = new ContentData() diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs index 9e8950e09..cbb900407 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs @@ -56,7 +56,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return html2Text(value); "; - var result = sut.Execute(vars, script).ToString(); + var result = sut.Execute(vars, script).AsString; Assert.Equal("Hello World", result); } @@ -73,7 +73,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return markdown2Text(value); "; - var result = sut.Execute(vars, script).ToString(); + var result = sut.Execute(vars, script).AsString; Assert.Equal("Hello World", result); } @@ -90,7 +90,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return wordCount(value); "; - var result = ((JsonNumber)sut.Execute(vars, script)).Value; + var result = sut.Execute(vars, script).AsNumber; Assert.Equal(2, result); } @@ -107,7 +107,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return characterCount(value); "; - var result = ((JsonNumber)sut.Execute(vars, script)).Value; + var result = sut.Execute(vars, script).AsNumber; Assert.Equal(10, result); } @@ -124,7 +124,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return toCamelCase(value); "; - var result = sut.Execute(vars, script).ToString(); + var result = sut.Execute(vars, script).AsString; Assert.Equal("helloWorld", result); } @@ -141,7 +141,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return toPascalCase(value); "; - var result = sut.Execute(vars, script).ToString(); + var result = sut.Execute(vars, script).AsString; Assert.Equal("HelloWorld", result); } @@ -158,7 +158,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return slugify(value); "; - var result = sut.Execute(vars, script).ToString(); + var result = sut.Execute(vars, script).AsString; Assert.Equal("4-haeuser", result); } @@ -175,7 +175,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return slugify(value, true); "; - var result = sut.Execute(vars, script).ToString(); + var result = sut.Execute(vars, script).AsString; Assert.Equal("4-hauser", result); } @@ -192,7 +192,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return sha256(value); "; - var result = sut.Execute(vars, script).ToString(); + var result = sut.Execute(vars, script).AsString; Assert.Equal("HelloWorld".ToSha256(), result); } @@ -209,7 +209,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return sha512(value); "; - var result = sut.Execute(vars, script).ToString(); + var result = sut.Execute(vars, script).AsString; Assert.Equal("HelloWorld".ToSha512(), result); } @@ -226,7 +226,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return md5(value); "; - var result = sut.Execute(vars, script).ToString(); + var result = sut.Execute(vars, script).AsString; Assert.Equal("HelloWorld".ToMD5(), result); } @@ -242,7 +242,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting return guid(); "; - var result = sut.Execute(vars, script).ToString(); + var result = sut.Execute(vars, script).AsString; Assert.True(Guid.TryParse(result, out _)); } @@ -385,7 +385,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting httpHandler.ShouldBeMethod(HttpMethod.Get); httpHandler.ShouldBeUrl("http://squidex.io/"); - var expectedResult = JsonValue.Object().Add("key", 42); + var expectedResult = new JsonObject().Add("key", 42); Assert.Equal(expectedResult, result); } @@ -419,7 +419,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting httpHandler.ShouldBeHeader("X-Header1", "1"); httpHandler.ShouldBeHeader("X-Header2", "2"); - var expectedResult = JsonValue.Object().Add("key", 42); + var expectedResult = new JsonObject().Add("key", 42); Assert.Equal(expectedResult, result); } @@ -446,7 +446,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting httpHandler.ShouldBeMethod(HttpMethod.Delete); httpHandler.ShouldBeUrl("http://squidex.io/"); - var expectedResult = JsonValue.Object().Add("key", 42); + var expectedResult = new JsonObject().Add("key", 42); Assert.Equal(expectedResult, result); } @@ -476,7 +476,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting httpHandler.ShouldBeUrl("http://squidex.io/"); httpHandler.ShouldBeBody("{\"key\":42}", "text/json"); - var expectedResult = JsonValue.Object().Add("key", 42); + var expectedResult = new JsonObject().Add("key", 42); Assert.Equal(expectedResult, result); } @@ -506,7 +506,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting httpHandler.ShouldBeUrl("http://squidex.io/"); httpHandler.ShouldBeBody("{\"key\":42}", "text/json"); - var expectedResult = JsonValue.Object().Add("key", 42); + var expectedResult = new JsonObject().Add("key", 42); Assert.Equal(expectedResult, result); } @@ -536,7 +536,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting httpHandler.ShouldBeUrl("http://squidex.io/"); httpHandler.ShouldBeBody("{\"key\":42}", "text/json"); - var expectedResult = JsonValue.Object().Add("key", 42); + var expectedResult = new JsonObject().Add("key", 42); Assert.Equal(expectedResult, result); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Tags/TagNormalizerTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Tags/TagNormalizerTests.cs index 91fd7f245..22727a0c0 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Tags/TagNormalizerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Tags/TagNormalizerTests.cs @@ -100,10 +100,10 @@ namespace Squidex.Domain.Apps.Core.Operations.Tags Assert.Equal(JsonValue.Array("name4"), GetNestedTags(newData)); } - private static IJsonValue GetNestedTags(ContentData newData) + private static JsonValue GetNestedTags(ContentData newData) { - var array = (JsonArray)newData["array"]!["iv"]; - var arrayItem = (JsonObject)array[0]; + var arrayValue = newData["array"]!["iv"].AsArray; + var arrayItem = arrayValue[0].AsObject; return arrayItem["nestedTags2"]; } @@ -124,7 +124,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Tags new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nestedTags1", JsonValue.Array($"{prefix}3")) .Add("nestedTags2", JsonValue.Array($"{prefix}4")) .Add("string", $"{prefix}nestedStringValue")))); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Templates/FluidTemplateEngineTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Templates/FluidTemplateEngineTests.cs index bda5b4f50..68e65f413 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Templates/FluidTemplateEngineTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Templates/FluidTemplateEngineTests.cs @@ -22,6 +22,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Templates { var extensions = new IFluidExtension[] { + new ContentFluidExtension(), new DateTimeFluidExtension(), new StringFluidExtension(), new StringWordsFluidExtension() diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ArrayFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ArrayFieldTests.cs index 6b10338e2..39d1b8d69 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ArrayFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ArrayFieldTests.cs @@ -132,19 +132,19 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Must not contain items with duplicate 'myString' fields." }); } - private static IJsonValue CreateValue(params JsonObject[]? objects) + private static JsonValue CreateValue(params JsonObject[]? objects) { - return objects == null ? JsonValue.Null : JsonValue.Array(objects); + return objects == null ? default : JsonValue.Array(objects); } private static JsonObject Object() { - return JsonValue.Object(); + return new JsonObject(); } - private static JsonObject Object(string key, object value) + private static JsonObject Object(string key, JsonValue value) { - return JsonValue.Object().Add(key, value); + return new JsonObject().Add(key, value); } private static RootField Field(ArrayFieldProperties properties) diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs index f7f11f457..6faacf21d 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/AssetsFieldTests.cs @@ -152,7 +152,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Must not contain duplicate values." }); } - private static IJsonValue CreateValue(params DomainId[]? ids) + private static JsonValue CreateValue(params DomainId[]? ids) { return ids == null ? JsonValue.Null : diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/BooleanFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/BooleanFieldTests.cs index a8899197d..2b85d495c 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/BooleanFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/BooleanFieldTests.cs @@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Invalid json type, expected boolean." }); } - private static IJsonValue CreateValue(bool? v) + private static JsonValue CreateValue(bool? v) { return JsonValue.Create(v); } 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 9d6718621..1b5152787 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 @@ -66,7 +66,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent { var (id, sut, components) = Field(new ComponentFieldProperties { SchemaId = schemaId1, IsRequired = true }, true); - await sut.ValidateAsync(CreateValue(id.ToString(), "componentField", null), errors, components: components); + await sut.ValidateAsync(CreateValue(id.ToString(), "componentField", default), errors, components: components); errors.Should().BeEquivalentTo( new[] { "componentField: Field is required." }); @@ -126,7 +126,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent await sut.ValidateAsync(value, errors, components: components); Assert.Empty(errors); - Assert.Equal(value[Component.Discriminator].ToString(), schemaId1.ToString()); + Assert.Equal(value.AsObject[Component.Discriminator].AsString, schemaId1.ToString()); } [Fact] @@ -139,12 +139,12 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent await sut.ValidateAsync(value, errors, components: components); Assert.Empty(errors); - Assert.Equal(value[Component.Discriminator].ToString(), schemaId1.ToString()); + Assert.Equal(value.AsObject[Component.Discriminator].AsString, schemaId1.ToString()); } - private static JsonObject CreateValue(string? type, string key, object? value, string? discriminator = null) + private static JsonValue CreateValue(string? type, string key, JsonValue value, string? discriminator = null) { - var obj = JsonValue.Object(); + var obj = new JsonObject(); if (type != null) { 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 3b8c554ec..a8cf97b22 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 @@ -76,7 +76,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent { var (id, sut, components) = Field(new ComponentsFieldProperties { SchemaId = schemaId1, IsRequired = true }, true); - await sut.ValidateAsync(CreateValue(1, id.ToString(), "componentField", null), errors, components: components); + await sut.ValidateAsync(CreateValue(1, id.ToString(), "componentField", default), errors, components: components); errors.Should().BeEquivalentTo( new[] { "[1].componentField: Field is required." }); @@ -98,7 +98,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent { var (_, sut, components) = Field(new ComponentsFieldProperties { SchemaId = schemaId1 }); - await sut.ValidateAsync(JsonValue.Array(JsonValue.Create("Invalid")), errors, components: components); + await sut.ValidateAsync((JsonValue)JsonValue.Array(JsonValue.Create("Invalid")), errors, components: components); errors.Should().BeEquivalentTo( new[] { "Invalid json object, expected object with 'schemaId' field." }); @@ -180,7 +180,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent await sut.ValidateAsync(value, errors, components: components); Assert.Empty(errors); - Assert.Equal(((JsonObject)value[0])[Component.Discriminator].ToString(), schemaId1.ToString()); + Assert.Equal(value.AsArray[0].AsObject[Component.Discriminator].AsString, schemaId1.ToString()); } [Fact] @@ -193,16 +193,16 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent await sut.ValidateAsync(value, errors, components: components); Assert.Empty(errors); - Assert.Equal(((JsonObject)value[0])[Component.Discriminator].ToString(), schemaId1.ToString()); + Assert.Equal(value.AsArray[0].AsObject[Component.Discriminator].AsString, schemaId1.ToString()); } - private static JsonArray CreateValue(int count, string? type, string key, object? value, string? discriminator = null) + private static JsonValue CreateValue(int count, string? type, string key, JsonValue value, string? discriminator = null) { - var result = JsonValue.Array(); + var result = new JsonArray(); for (var i = 0; i < count; i++) { - var obj = JsonValue.Object(); + var obj = new JsonObject(); if (type != null) { diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ContentValidationTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ContentValidationTests.cs index e13948690..f07503845 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ContentValidationTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ContentValidationTests.cs @@ -411,9 +411,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object(), - JsonValue.Object().Add("myNested", 1), - JsonValue.Object()))); + new JsonObject(), + new JsonObject().Add("myNested", 1), + new JsonObject()))); await data.ValidatePartialAsync(languagesConfig.ToResolver(), errors, schema); @@ -450,7 +450,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object()))); + new JsonObject()))); await data.ValidateAsync(languagesConfig.ToResolver(), errors, schema); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/DateTimeFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/DateTimeFieldTests.cs index 0ad914ea4..34ec7fef1 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/DateTimeFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/DateTimeFieldTests.cs @@ -97,7 +97,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent return SystemClock.Instance.GetCurrentInstant().WithoutMs().Plus(Duration.FromDays(days)); } - private static IJsonValue CreateValue(Instant v) + private static JsonValue CreateValue(Instant v) { return JsonValue.Create(v); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs index 0bad77500..41ccb2321 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs @@ -40,7 +40,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent { var sut = Field(new GeolocationFieldProperties()); - var geolocation = JsonValue.Object() + var geolocation = new JsonObject() .Add("coordinates", JsonValue.Array( JsonValue.Create(12), @@ -96,9 +96,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Field is required." }); } - private static JsonObject CreateValue(double lat, double lon) + private static JsonValue CreateValue(double lat, double lon) { - return JsonValue.Object().Add("latitude", lat).Add("longitude", lon); + return new JsonObject().Add("latitude", lat).Add("longitude", lon); } private static RootField Field(GeolocationFieldProperties properties) diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/JsonFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/JsonFieldTests.cs index 18157230c..5a2bc54b2 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/JsonFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/JsonFieldTests.cs @@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Field is required." }); } - private static IJsonValue CreateValue(IJsonValue v) + private static JsonValue CreateValue(JsonValue v) { return v; } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/NumberFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/NumberFieldTests.cs index 62c23d7f6..0aa42106c 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/NumberFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/NumberFieldTests.cs @@ -91,7 +91,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Invalid json type, expected number." }); } - private static IJsonValue CreateValue(double v) + private static JsonValue CreateValue(double v) { return JsonValue.Create(v); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs index d0d54d823..e5f305522 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ReferencesFieldTests.cs @@ -161,7 +161,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Must not contain duplicate values." }); } - private static IJsonValue CreateValue(params DomainId[]? ids) + private static JsonValue CreateValue(params DomainId[]? ids) { return ids == null ? JsonValue.Null : diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/StringFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/StringFieldTests.cs index fba93187d..11b6a8fa2 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/StringFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/StringFieldTests.cs @@ -135,7 +135,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Custom Error Message." }); } - private static IJsonValue CreateValue(string? v) + private static JsonValue CreateValue(string? v) { return JsonValue.Create(v); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/TagsFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/TagsFieldTests.cs index e38dee5a5..aea73ca34 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/TagsFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/TagsFieldTests.cs @@ -83,7 +83,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent { var sut = Field(new TagsFieldProperties { IsRequired = true }); - await sut.ValidateAsync(JsonValue.Array(JsonValue.Null), errors); + await sut.ValidateAsync((JsonValue)JsonValue.Array(JsonValue.Null), errors); errors.Should().BeEquivalentTo( new[] { "Invalid json type, expected array of strings." }); @@ -144,9 +144,9 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "[1]: Not an allowed value." }); } - private static IJsonValue CreateValue(params string?[]? ids) + private static JsonValue CreateValue(params string?[]? ids) { - return ids == null ? JsonValue.Null : JsonValue.Array(ids.OfType().ToArray()); + return ids == null ? JsonValue.Null : JsonValue.Array(ids); } private static RootField Field(TagsFieldProperties properties) diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/UIFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/UIFieldTests.cs index 0caadb330..ecc4ef92e 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/UIFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/UIFieldTests.cs @@ -72,7 +72,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new ContentData() .AddField("myUI1", new ContentFieldData()) .AddField("myUI2", new ContentFieldData() - .AddInvariant(null)); + .AddInvariant(JsonValue.Null)); var dataErrors = new List(); @@ -99,8 +99,8 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent .AddField("myArray", new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() - .Add("myUI", null)))); + new JsonObject() + .Add("myUI", default)))); var dataErrors = new List(); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/ComponentValidatorTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/ComponentValidatorTests.cs index 5e6e09a6a..0faa9ff95 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/ComponentValidatorTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/Validators/ComponentValidatorTests.cs @@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent.Validators { var validator = A.Fake(); - var componentData = JsonValue.Object(); + var componentData = new JsonObject(); var componentObject = new Component("type", componentData, new Schema("my-schema")); var isFactoryCalled = false; 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 841b002d6..77966fb17 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs @@ -54,7 +54,7 @@ namespace Squidex.Domain.Apps.Core.TestHelpers new JsonValueConverter(), new StringEnumConverter(), new SurrogateConverter(), - new SurrogateConverter, JsonFilterSurrogate>(), + new SurrogateConverter, JsonFilterSurrogate>(), new SurrogateConverter(), new SurrogateConverter(), new SurrogateConverter(), diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsGrainTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsGrainTests.cs index ef592115e..c2897ffdd 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsGrainTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsGrainTests.cs @@ -25,12 +25,12 @@ namespace Squidex.Domain.Apps.Entities.Apps [Fact] public async Task Should_set_setting() { - await sut.SetAsync(JsonValue.Object().Add("key", 15).AsJ()); + await sut.SetAsync(new JsonObject().Add("key", 15).AsJ()); var actual = await sut.GetAsync(); var expected = - JsonValue.Object().Add("key", 15); + new JsonObject().Add("key", 15); Assert.Equal(expected.ToString(), actual.Value.ToString()); @@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.Apps var actual = await sut.GetAsync(); var expected = - JsonValue.Object().Add("key", 123); + new JsonObject().Add("key", 123); Assert.Equal(expected.ToString(), actual.Value.ToString()); @@ -63,7 +63,7 @@ namespace Squidex.Domain.Apps.Entities.Apps var actual = await sut.GetAsync(); - var expected = JsonValue.Object(); + var expected = new JsonObject(); Assert.Equal(expected.ToString(), actual.Value.ToString()); @@ -79,8 +79,8 @@ namespace Squidex.Domain.Apps.Entities.Apps var actual = await sut.GetAsync(); var expected = - JsonValue.Object().Add("root", - JsonValue.Object().Add("nested", 123)); + new JsonObject().Add("root", + new JsonObject().Add("nested", 123)); Assert.Equal(expected.ToString(), actual.Value.ToString()); @@ -98,8 +98,8 @@ namespace Squidex.Domain.Apps.Entities.Apps var actual = await sut.GetAsync(); var expected = - JsonValue.Object().Add("root", - JsonValue.Object()); + new JsonObject().Add("root", + new JsonObject()); Assert.Equal(expected.ToString(), actual.Value.ToString()); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs index 36665238c..2c767f22a 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs @@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Entities.Apps [Fact] public async Task Should_call_grain_if_retrieving_settings() { - var settings = JsonValue.Object(); + var settings = new JsonObject(); A.CallTo(() => grain.GetAsync()) .Returns(settings.AsJ()); @@ -45,18 +45,18 @@ namespace Squidex.Domain.Apps.Entities.Apps [Fact] public async Task Should_call_grain_if_setting_value() { - var value = JsonValue.Object(); + var value = new JsonObject(); await sut.SetAsync(DomainId.NewGuid(), "user", "the.path", value); - A.CallTo(() => grain.SetAsync("the.path", A>.That.Matches(x => x.Value == value))) + A.CallTo(() => grain.SetAsync("the.path", A>.That.Matches(x => x.Value == value))) .MustHaveHappened(); } [Fact] public async Task Should_call_grain_if_replacing_settings() { - var value = JsonValue.Object(); + var value = new JsonObject(); await sut.SetAsync(DomainId.NewGuid(), "user", value); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs index 776c093f7..fe6a823ec 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs @@ -142,7 +142,7 @@ namespace Squidex.Domain.Apps.Entities.Apps [Fact] public async Task Should_writer_user_settings() { - var settings = JsonValue.Object(); + var settings = new JsonObject(); var context = CreateBackupContext(); @@ -158,7 +158,7 @@ namespace Squidex.Domain.Apps.Entities.Apps [Fact] public async Task Should_read_user_settings() { - var settings = JsonValue.Object(); + var settings = new JsonObject(); var context = CreateRestoreContext(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs index c49936888..8d4062283 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs @@ -614,7 +614,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject [Fact] public async Task UpdateRole_should_create_events_and_update_role() { - var command = new UpdateRole { Name = roleName, Permissions = new[] { "clients.read" }, Properties = JsonValue.Object() }; + var command = new UpdateRole { Name = roleName, Permissions = new[] { "clients.read" }, Properties = new JsonObject() }; await ExecuteCreateAsync(); await ExecuteAddRoleAsync(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs index 7688aece7..01789b514 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs @@ -13,6 +13,7 @@ using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Core.Templates; +using Squidex.Domain.Apps.Core.Templates.Extensions; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; @@ -41,6 +42,7 @@ namespace Squidex.Domain.Apps.Entities.Assets var extensions = new IFluidExtension[] { + new ContentFluidExtension(), new AssetsFluidExtension(services) }; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs index a63baadc6..7b4101e53 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs @@ -113,7 +113,7 @@ namespace Squidex.Domain.Apps.Entities.Contents .AddField("assetsInObj", new ContentFieldData() .AddLocalized("iv", - JsonValue.Object() + new JsonObject() .Add("asset", $"Asset: {oldAssetsUrlApp}/my-asset.jpg."))); var updateData = @@ -130,7 +130,7 @@ namespace Squidex.Domain.Apps.Entities.Contents .AddField("assetsInObj", new ContentFieldData() .AddLocalized("iv", - JsonValue.Object() + new JsonObject() .Add("asset", $"Asset: {newAssetsUrlApp}/my-asset.jpg."))); var context = new RestoreContext(appId.Id, new UserMapping(me), reader, DomainId.NewGuid()); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs index 24cacb6a3..3e5fb8a86 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs @@ -22,6 +22,7 @@ using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Contents; using Squidex.Infrastructure; +using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Validation; using Xunit; @@ -41,7 +42,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject new ContentData() .AddField("my-field1", new ContentFieldData() - .AddInvariant(null)) + .AddInvariant(JsonValue.Null)) .AddField("my-field2", new ContentFieldData() .AddInvariant(1)); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs index 5fde2a6ae..b94227abc 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs @@ -493,7 +493,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject return (context.PlainResult as BulkUpdateResult)!; } - private BulkUpdateContents BulkCommand(BulkUpdateContentType type, Query? query = null, + private BulkUpdateContents BulkCommand(BulkUpdateContentType type, Query? query = null, DomainId? id = null, ContentData? data = null, Instant? dueTime = null) { return new BulkUpdateContents @@ -531,9 +531,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject return requestContext; } - private static (DomainId Id, ContentData Data, Query? Query) CreateTestData(bool withQuery) + private static (DomainId Id, ContentData Data, Query? Query) CreateTestData(bool withQuery) { - Query? query = withQuery ? new Query() : null; + Query? query = withQuery ? new Query() : null; var data = new ContentData() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs index c79c1f104..54db2e6b3 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs @@ -8,7 +8,6 @@ using System.Text.RegularExpressions; using FakeItEasy; using GraphQL; -using GraphQL.NewtonsoftJson; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NodaTime.Text; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs index 0ed5d35e6..44c063462 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs @@ -171,7 +171,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL .AddLocalized("de-DE", "de-DE")) .AddField("my-string", new ContentFieldData() - .AddInvariant(null)) + .AddInvariant(JsonValue.Null)) .AddField("my-string-enum", new ContentFieldData() .AddInvariant("EnumA")) @@ -202,37 +202,37 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL .AddField("my-geolocation", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("latitude", 10) .Add("longitude", 20))) .AddField("my-component", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add(Component.Discriminator, TestSchemas.Ref1.Id) .Add("schemaRef1Field", "Component1"))) .AddField("my-components", new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add(Component.Discriminator, TestSchemas.Ref1.Id) .Add("schemaRef1Field", "Component1"), - JsonValue.Object() + new JsonObject() .Add(Component.Discriminator, TestSchemas.Ref2.Id) .Add("schemaRef2Field", "Component2")))) .AddField("my-json", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("value", 1))) .AddField("my-array", new ContentFieldData() .AddInvariant(JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nested-number", 10) .Add("nested-boolean", true), - JsonValue.Object() + new JsonObject() .Add("nested-number", 20) .Add("nested-boolean", false)))); 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 5b495b5b1..cf6094d82 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 @@ -299,9 +299,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries public async Task Should_convert_json_query_and_enrich_with_defaults() { var query = Q.Empty.WithJsonQuery( - new Query + new Query { - Filter = new CompareFilter("data.firstName.iv", CompareOperator.Equals, JsonValue.Create("ABC")) + Filter = new CompareFilter("data.firstName.iv", CompareOperator.Equals, JsonValue.Create("ABC")) }); var q = await sut.ParseAsync(requestContext, query, schema); 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 118f5ec0b..432b16d34 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 @@ -82,7 +82,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nested", JsonValue.Array(id2))))); A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2), A._)) @@ -120,7 +120,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nested", JsonValue.Array())))); A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2), A._)) @@ -149,7 +149,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries new ContentFieldData() .AddInvariant( JsonValue.Array( - JsonValue.Object() + new JsonObject() .Add("nested", JsonValue.Array(id1, id2))))); } 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 8c5aebeee..179e4b2da 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 @@ -148,13 +148,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries .AddField("ref1", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("en", "ref1_1, 13") .Add("de", "ref1_1, 13"))) .AddField("ref2", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("en", "ref2_1, 23") .Add("de", "ref2_1, 23"))), contents[0].ReferenceData); @@ -164,13 +164,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries .AddField("ref1", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("en", "ref1_2, 17") .Add("de", "ref1_2, 17"))) .AddField("ref2", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("en", "ref2_2, 29") .Add("de", "ref2_2, 29"))), contents[1].ReferenceData); @@ -201,13 +201,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries .AddField("ref1", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("en", "ref1_1, 13") .Add("de", "ref1_1, 13"))) .AddField("ref2", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("en", "2 Reference(s)") .Add("de", "2 Reference(s)"))), contents[0].ReferenceData); @@ -217,13 +217,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries .AddField("ref1", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("en", "ref1_2, 17") .Add("de", "ref1_2, 17"))) .AddField("ref2", new ContentFieldData() .AddInvariant( - JsonValue.Object() + new JsonObject() .Add("en", "2 Reference(s)") .Add("de", "2 Reference(s)"))), contents[1].ReferenceData); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesFluidExtensionTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesFluidExtensionTests.cs index e1b7f9f89..29df914c0 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesFluidExtensionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesFluidExtensionTests.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.DependencyInjection; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Core.Templates; +using Squidex.Domain.Apps.Core.Templates.Extensions; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; @@ -34,6 +35,7 @@ namespace Squidex.Domain.Apps.Entities.Contents var extensions = new IFluidExtension[] { + new ContentFluidExtension(), new ReferencesFluidExtension(services) }; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs index 320a90fc0..755cd71a9 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs @@ -381,7 +381,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text return new ContentData() .AddField(field, new ContentFieldData() - .AddInvariant(JsonValue.Object().Add("latitude", latitude).Add("longitude", longitude))); + .AddInvariant(new JsonObject().Add("latitude", latitude).Add("longitude", longitude))); } protected async Task SearchGeo(List? expected, string field, double latitude, double longitude, SearchScope target = SearchScope.All) diff --git a/backend/tests/Squidex.Infrastructure.Tests/Collections/ListDictionaryTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Collections/ListDictionaryTests.cs new file mode 100644 index 000000000..11de228b6 --- /dev/null +++ b/backend/tests/Squidex.Infrastructure.Tests/Collections/ListDictionaryTests.cs @@ -0,0 +1,452 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections; +using Xunit; + +#pragma warning disable xUnit2017 // Do not use Contains() to check if a value exists in a collection +#pragma warning disable IDE0028 // Simplify collection initialization + +namespace Squidex.Infrastructure.Collections +{ + public class ListDictionaryTests + { + [Fact] + public void Should_create_empty() + { + var sut = new ListDictionary(); + + Assert.Empty(sut); + Assert.Equal(1, sut.Capacity); + } + + [Fact] + public void Should_create_with_capacity() + { + var sut = new ListDictionary(20); + + Assert.Empty(sut); + Assert.Equal(20, sut.Capacity); + } + + [Fact] + public void Should_create_as_copy() + { + var source = new ListDictionary(); + + source.Add(1, 10); + source.Add(2, 20); + + var sut = new ListDictionary(source); + + Assert.Equal(2, sut.Count); + } + + [Fact] + public void Should_not_be_readonly() + { + var sut = new ListDictionary(); + + Assert.False(sut.IsReadOnly); + Assert.False(sut.Keys.IsReadOnly); + Assert.False(sut.Values.IsReadOnly); + } + + [Fact] + public void Should_add_item() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + + Assert.Single(sut); + Assert.Equal(10, sut[1]); + } + + [Fact] + public void Should_add_item_as_pair() + { + var sut = new ListDictionary(); + + sut.Add(new KeyValuePair(1, 10)); + + Assert.Single(sut); + Assert.Equal(10, sut[1]); + } + + [Fact] + public void Should_throw_exception_if_adding_existing_key() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + + Assert.Throws(() => sut.Add(1, 20)); + } + + [Fact] + public void Should_throw_exception_if_adding_pair_with_existing_key() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + + Assert.Throws(() => sut.Add(new KeyValuePair(1, 20))); + } + + [Fact] + public void Should_set_item() + { + var sut = new ListDictionary(); + + sut[1] = 10; + + Assert.Single(sut); + Assert.Equal(10, sut[1]); + } + + [Fact] + public void Should_override_item() + { + var sut = new ListDictionary(); + + sut[1] = 20; + + Assert.Single(sut); + Assert.Equal(20, sut[1]); + } + + [Fact] + public void Should_return_true_when_dictionary_contains_value() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + + Assert.True(sut.Contains(new KeyValuePair(1, 10))); + Assert.True(sut.ContainsKey(1)); + Assert.True(sut.Keys.Contains(1)); + Assert.True(sut.Values.Contains(10)); + } + + [Fact] + public void Should_return_false_when_dictionary_does_not_contains_value() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + + Assert.False(sut.Contains(new KeyValuePair(1, 20))); + Assert.False(sut.ContainsKey(2)); + Assert.False(sut.Keys.Contains(2)); + Assert.False(sut.Values.Contains(20)); + } + + [Fact] + public void Should_get_count() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + sut.Add(3, 30); + + Assert.Equal(3, sut.Count); + Assert.Equal(3, sut.Keys.Count); + Assert.Equal(3, sut.Values.Count); + } + + [Fact] + public void Should_clear() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + sut.Add(3, 30); + sut.Clear(); + + Assert.Empty(sut); + } + + [Fact] + public void Should_remove_key() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + sut.Add(3, 30); + + Assert.True(sut.Remove(2)); + Assert.False(sut.ContainsKey(2)); + } + + [Fact] + public void Should_not_remove_key_if_not_found() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + sut.Add(3, 30); + + Assert.False(sut.Remove(4)); + } + + [Fact] + public void Should_remove_item() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + sut.Add(3, 30); + + Assert.True(sut.Remove(new KeyValuePair(2, 20))); + Assert.False(sut.ContainsKey(2)); + } + + [Fact] + public void Should_not_remove_item_if_key_not_found() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + sut.Add(3, 30); + + Assert.False(sut.Remove(new KeyValuePair(4, 40))); + } + + [Fact] + public void Should_not_remove_item_if_value_not_equal() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + sut.Add(3, 30); + + Assert.False(sut.Remove(new KeyValuePair(2, 40))); + } + + [Fact] + public void Should_get_value_by_method_if_found() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + Assert.True(sut.TryGetValue(2, out var found)); + Assert.Equal(20, found); + } + + [Fact] + public void Should_not_get_value_by_method_if_not_found() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(3, 30); + + Assert.False(sut.TryGetValue(4, out var found)); + Assert.Equal(0, found); + } + + [Fact] + public void Should_get_value_by_indexer_if_found() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + Assert.Equal(20, sut[2]); + } + + [Fact] + public void Should_not_get_value_by_indexer_if_not_found() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + Assert.Throws(() => sut[4]); + } + + [Fact] + public void Should_loop_over_entries() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + var result = new List>(); + + foreach (var entry in sut) + { + result.Add(entry); + } + + Assert.Equal(new[] + { + new KeyValuePair(1, 10), + new KeyValuePair(2, 20), + }, result.ToArray()); + } + + [Fact] + public void Should_loop_over_entries_with_old_enumerator() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + var result = new List>(); + + foreach (KeyValuePair entry in (IEnumerable)sut) + { + result.Add(entry); + } + + Assert.Equal(new[] + { + new KeyValuePair(1, 10), + new KeyValuePair(2, 20), + }, result.ToArray()); + } + + [Fact] + public void Should_copy_entries_to_array() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + Assert.Equal(new[] + { + new KeyValuePair(1, 10), + new KeyValuePair(2, 20), + }, sut.ToArray()); + } + + [Fact] + public void Should_loop_over_keys() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + var result = new List(); + + foreach (var entry in sut.Keys) + { + result.Add(entry); + } + + Assert.Equal(new[] { 1, 2 }, result.ToArray()); + } + + [Fact] + public void Should_loop_over_keys_with_old_enumerator() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + var result = new List(); + + foreach (int entry in (IEnumerable)sut.Keys) + { + result.Add(entry); + } + + Assert.Equal(new[] { 1, 2 }, result.ToArray()); + } + + [Fact] + public void Should_copy_keys_to_array() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + Assert.Equal(new[] { 1, 2 }, sut.Keys.ToArray()); + } + + [Fact] + public void Should_loop_over_values() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + var result = new List(); + + foreach (var entry in sut.Values) + { + result.Add(entry); + } + + Assert.Equal(new[] { 10, 20 }, result.ToArray()); + } + + [Fact] + public void Should_loop_over_values_with_old_enumerator() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + var result = new List(); + + foreach (int entry in (IEnumerable)sut.Values) + { + result.Add(entry); + } + + Assert.Equal(new[] { 10, 20 }, result.ToArray()); + } + + [Fact] + public void Should_copy_values_to_array() + { + var sut = new ListDictionary(); + + sut.Add(1, 10); + sut.Add(2, 20); + + Assert.Equal(new[] { 10, 20 }, sut.Values.ToArray()); + } + + [Fact] + public void Should_trim() + { + var sut = new ListDictionary(20); + + sut.Add(1, 10); + sut.Add(2, 20); + + Assert.Equal(20, sut.Capacity); + + sut.TrimExcess(); + + Assert.Equal(2, sut.Capacity); + } + } +} diff --git a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/MongoParallelInsertTests.cs b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/MongoParallelInsertTests.cs index fd067d8f5..3b95bf989 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/MongoParallelInsertTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/MongoParallelInsertTests.cs @@ -131,7 +131,8 @@ namespace Squidex.Infrastructure.EventSourcing } else { - throw new NotSupportedException(); + ThrowHelper.NotSupportedException(); + return default!; } } finally diff --git a/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonObjectTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonObjectTests.cs index 7cc8b9fb8..75f36a6fc 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonObjectTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonObjectTests.cs @@ -5,10 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Collections; using NodaTime; using Xunit; +#pragma warning disable xUnit2004 // Do not use equality check to test for boolean conditions + namespace Squidex.Infrastructure.Json.Objects { public class JsonObjectTests @@ -16,13 +17,13 @@ namespace Squidex.Infrastructure.Json.Objects [Fact] public void Should_make_correct_object_equal_comparisons() { - var obj1a = JsonValue.Object().Add("key1", 1); - var obj1b = JsonValue.Object().Add("key1", 1); + var obj1a = new JsonObject().Add("key1", 1); + var obj1b = new JsonObject().Add("key1", 1); - var objOtherValue = JsonValue.Object().Add("key1", 2); - var objOtherKey = JsonValue.Object().Add("key2", 1); + var objOtherValue = new JsonObject().Add("key1", 2); + var objOtherKey = new JsonObject().Add("key2", 1); - var objOtherCount = JsonValue.Object().Add("key1", 1).Add("key2", 2); + var objOtherCount = new JsonObject().Add("key1", 1).Add("key2", 2); var number = JsonValue.Create(1); @@ -116,156 +117,237 @@ namespace Squidex.Infrastructure.Json.Objects } [Fact] - public void Should_cache_null() - { - Assert.Same(JsonValue.Null, JsonValue.Create((string?)null)); - Assert.Same(JsonValue.Null, JsonValue.Create((bool?)null)); - Assert.Same(JsonValue.Null, JsonValue.Create((double?)null)); - Assert.Same(JsonValue.Null, JsonValue.Create((object?)null)); - Assert.Same(JsonValue.Null, JsonValue.Create((Instant?)null)); - } - - [Fact] - public void Should_cache_true() - { - Assert.Same(JsonValue.True, JsonValue.Create(true)); - } - - [Fact] - public void Should_cache_false() - { - Assert.Same(JsonValue.False, JsonValue.Create(false)); - } - - [Fact] - public void Should_cache_empty() - { - Assert.Same(JsonValue.Empty, JsonValue.Create(string.Empty)); - } - - [Fact] - public void Should_cache_zero() + public void Should_create_null() { - Assert.Same(JsonValue.Zero, JsonValue.Create(0)); - } + var jsons = new[] + { + new JsonValue((string?)null), + JsonValue.Create((string?)null), + JsonValue.Create((object?)null), + default + }; - [Fact] - public void Should_create_boolean_from_object() - { - Assert.Equal(JsonValue.True, JsonValue.Create((object)true)); + foreach (var json in jsons) + { + Assert.Null(json.Value); + Assert.Equal(JsonValueType.Null, json.Type); + + Assert.Throws(() => json.AsBoolean); + Assert.Throws(() => json.AsNumber); + Assert.Throws(() => json.AsString); + Assert.Throws(() => json.AsArray); + Assert.Throws(() => json.AsObject); + } } [Fact] - public void Should_create_value_from_instant() + public void Should_create_booleans() { - var instant = Instant.FromUnixTimeSeconds(4123125455); + var jsons = new[] + { + new JsonValue(true), + JsonValue.Create(true), + JsonValue.Create((object?)true), + true + }; - Assert.Equal(instant.ToString(), JsonValue.Create(instant).ToString()); + foreach (var json in jsons) + { + Assert.Equal(true, json.Value); + Assert.Equal(true, json.AsBoolean); + Assert.Equal(JsonValueType.Boolean, json.Type); + + Assert.Throws(() => json.AsNumber); + Assert.Throws(() => json.AsString); + Assert.Throws(() => json.AsArray); + Assert.Throws(() => json.AsObject); + } } [Fact] - public void Should_create_value_from_instant_object() + public void Should_create_floats() { - var instant = Instant.FromUnixTimeSeconds(4123125455); + var jsons = new[] + { + new JsonValue(12.5), + JsonValue.Create(12.5), + JsonValue.Create((object?)12.5), + JsonValue.Create((object?)12.5f), + 12.5 + }; - Assert.Equal(instant.ToString(), JsonValue.Create((object)instant).ToString()); + foreach (var json in jsons) + { + Assert.Equal(12.5, json.Value); + Assert.Equal(12.5, json.AsNumber); + Assert.Equal(JsonValueType.Number, json.Type); + + Assert.Throws(() => json.AsBoolean); + Assert.Throws(() => json.AsString); + Assert.Throws(() => json.AsArray); + Assert.Throws(() => json.AsObject); + } } [Fact] - public void Should_create_array() + public void Should_create_more_integers() { - var json = JsonValue.Array(1, "2"); + var jsons = new[] + { + new JsonValue(12), + JsonValue.Create(12), + JsonValue.Create((object?)12L), + JsonValue.Create((object?)12), + 12 + }; - Assert.Equal("[1, \"2\"]", json.ToJsonString()); - Assert.Equal("[1, \"2\"]", json.ToString()); + foreach (var json in jsons) + { + Assert.Equal(12d, json.Value); + Assert.Equal(12d, json.AsNumber); + Assert.Equal(JsonValueType.Number, json.Type); + + Assert.Throws(() => json.AsBoolean); + Assert.Throws(() => json.AsString); + Assert.Throws(() => json.AsArray); + Assert.Throws(() => json.AsObject); + } } [Fact] - public void Should_create_array_from_object_source() + public void Should_create_strings() { - var json = JsonValue.Create(new object[] { 1, "2" }); + var jsons = new[] + { + new JsonValue("text"), + JsonValue.Create("text"), + JsonValue.Create((object?)"text"), + "text" + }; - Assert.Equal("[1, \"2\"]", json.ToJsonString()); - Assert.Equal("[1, \"2\"]", json.ToString()); + foreach (var json in jsons) + { + Assert.Equal("text", json.Value); + Assert.Equal("text", json.AsString); + Assert.Equal(JsonValueType.String, json.Type); + + Assert.Throws(() => json.AsBoolean); + Assert.Throws(() => json.AsNumber); + Assert.Throws(() => json.AsArray); + Assert.Throws(() => json.AsObject); + } } [Fact] - public void Should_create_array_from_source() + public void Should_create_instants() { - var json = JsonValue.Array(1, "2"); - - var copy = new JsonArray(json); - - Assert.Equal("[1, \"2\"]", copy.ToJsonString()); - Assert.Equal("[1, \"2\"]", copy.ToString()); - - copy.Clear(); - - Assert.Empty(copy); - Assert.NotEmpty(json); - } + var instant = Instant.FromUnixTimeSeconds(4123125455); - [Fact] - public void Should_create_object() - { - var json = JsonValue.Object().Add("key1", 1).Add("key2", "2"); + var jsons = new[] + { + JsonValue.Create(instant), + JsonValue.Create((object?)instant), + instant + }; - Assert.Equal("{\"key1\":1, \"key2\":\"2\"}", json.ToJsonString()); - Assert.Equal("{\"key1\":1, \"key2\":\"2\"}", json.ToString()); + foreach (var json in jsons) + { + Assert.Equal(instant.ToString(), json.Value); + Assert.Equal(instant.ToString(), json.AsString); + Assert.Equal(JsonValueType.String, json.Type); + + Assert.Throws(() => json.AsBoolean); + Assert.Throws(() => json.AsNumber); + Assert.Throws(() => json.AsArray); + Assert.Throws(() => json.AsObject); + } } [Fact] - public void Should_create_object_from_clr_source() + public void Should_create_ids() { - var json = JsonValue.Create(new Dictionary { ["key1"] = 1, ["key2"] = "2" }); + var id = DomainId.NewGuid(); - Assert.Equal("{\"key1\":1, \"key2\":\"2\"}", json.ToJsonString()); - Assert.Equal("{\"key1\":1, \"key2\":\"2\"}", json.ToString()); - } + var jsons = new[] + { + JsonValue.Create(id), + JsonValue.Create((object?)id), + id + }; - [Fact] - public void Should_create_number() - { - var json = JsonValue.Create(123); + var result = id.ToString(); - Assert.Equal("123", json.ToJsonString()); - Assert.Equal("123", json.ToString()); + foreach (var json in jsons) + { + Assert.Equal(result, json.Value); + Assert.Equal(result, json.AsString); + Assert.Equal(JsonValueType.String, json.Type); + + Assert.Throws(() => json.AsBoolean); + Assert.Throws(() => json.AsNumber); + Assert.Throws(() => json.AsArray); + Assert.Throws(() => json.AsObject); + } } [Fact] - public void Should_create_boolean_true() + public void Should_create_arrays() { - var json = JsonValue.Create(true); + var input = new JsonArray { 1, 2 }; - Assert.Equal("true", json.ToJsonString()); - Assert.Equal("true", json.ToString()); - } + var jsons = new[] + { + new JsonValue(input), + JsonValue.Array(1, 2), + JsonValue.Array(new int[] { 1, 2 }), + JsonValue.Create(input), + JsonValue.Create((object?)input), + JsonValue.Create(new object[] { 1, 2 }), + input + }; - [Fact] - public void Should_create_boolean_false() - { - var json = JsonValue.Create(false); + var result = new JsonArray { 1, 2 }; - Assert.Equal("false", json.ToJsonString()); - Assert.Equal("false", json.ToString()); + foreach (var json in jsons) + { + Assert.Equal(result, json.Value); + Assert.Equal(result, json.AsArray); + Assert.Equal(JsonValueType.Array, json.Type); + + Assert.Throws(() => json.AsBoolean); + Assert.Throws(() => json.AsNumber); + Assert.Throws(() => json.AsString); + Assert.Throws(() => json.AsObject); + } } [Fact] - public void Should_create_string() + public void Should_create_objects() { - var json = JsonValue.Create("hi"); + var input = new JsonObject().Add("1", 1).Add("2", 2); - Assert.Equal("\"hi\"", json.ToJsonString()); - Assert.Equal("hi", json.ToString()); - } + var jsons = new[] + { + new JsonValue(input), + JsonValue.Create(input), + JsonValue.Create((object?)input), + JsonValue.Create(input.ToDictionary(x => x.Key, x => x.Value.Value)), + input, + }; - [Fact] - public void Should_create_null() - { - var json = JsonValue.Create((object?)null); + var result = new JsonObject().Add("1", 1).Add("2", 2); - Assert.Equal("null", json.ToJsonString()); - Assert.Equal("null", json.ToString()); + foreach (var json in jsons) + { + Assert.Equal(result, json.Value); + Assert.Equal(result, json.AsObject); + Assert.Equal(JsonValueType.Object, json.Type); + + Assert.Throws(() => json.AsBoolean); + Assert.Throws(() => json.AsNumber); + Assert.Throws(() => json.AsString); + Assert.Throws(() => json.AsArray); + } } [Fact] @@ -275,7 +357,7 @@ namespace Squidex.Infrastructure.Json.Objects var clone = source.Clone(); - Assert.Same(source, clone); + Assert.Same(source.Value, clone.Value); } [Fact] @@ -285,7 +367,7 @@ namespace Squidex.Infrastructure.Json.Objects var clone = source.Clone(); - Assert.Same(source, clone); + Assert.Same(source.Value, clone.Value); } [Fact] @@ -295,7 +377,7 @@ namespace Squidex.Infrastructure.Json.Objects var clone = source.Clone(); - Assert.Same(source, clone); + Assert.Same(source.Value, clone.Value); } [Fact] @@ -305,151 +387,39 @@ namespace Squidex.Infrastructure.Json.Objects var clone = source.Clone(); - Assert.Same(source, clone); + Assert.Same(source.Value, clone.Value); } [Fact] public void Should_clone_array_and_also_children() { - var source = JsonValue.Array(JsonValue.Array(), JsonValue.Array()); + var source = JsonValue.Array(new JsonArray(), new JsonArray()).AsArray; - var clone = (JsonArray)source.Clone(); + var clone = ((JsonValue)source).Clone().AsArray; Assert.NotSame(source, clone); for (var i = 0; i < source.Count; i++) { - Assert.NotSame(clone[i], source[i]); + Assert.NotSame(clone[i].Value, source[i].Value); } } [Fact] public void Should_clone_object_and_also_children() { - var source = JsonValue.Object().Add("1", JsonValue.Array()).Add("2", JsonValue.Array()); + var source = new JsonObject().Add("1", new JsonArray()).Add("2", new JsonArray()); - var clone = (JsonObject)source.Clone(); + var clone = ((JsonValue)source).Clone().AsObject; Assert.NotSame(source, clone); foreach (var (key, value) in clone) { - Assert.NotSame(value, source[key]); + Assert.NotSame(value.Value, source[key].Value); } } - [Fact] - public void Should_create_arrays_in_different_ways() - { - var numbers = new[] - { - JsonValue.Array(1.0f, 2.0f), - JsonValue.Array(JsonValue.Create(1.0f), JsonValue.Create(2.0f)) - }; - - Assert.Single(numbers.Distinct()); - Assert.Single(numbers.Select(x => x.GetHashCode()).Distinct()); - } - - [Fact] - public void Should_create_number_from_types() - { - var numbers = new[] - { - JsonValue.Create(12.0f), - JsonValue.Create(12.0), - JsonValue.Create(12L), - JsonValue.Create(12), - JsonValue.Create((object)12.0d), - JsonValue.Create((double?)12.0d) - }; - - Assert.Single(numbers.Distinct()); - Assert.Single(numbers.Select(x => x.GetHashCode()).Distinct()); - } - - [Fact] - public void Should_create_null_if_adding_null_to_array() - { - var array = JsonValue.Array(); - - array.Add(null!); - - Assert.Same(JsonValue.Null, array[0]); - } - - [Fact] - public void Should_create_null_if_replacing_to_null_in_array() - { - var array = JsonValue.Array(1); - - array[0] = null!; - - Assert.Same(JsonValue.Null, array[0]); - } - - [Fact] - public void Should_create_null_if_adding_null_to_object() - { - var obj = JsonValue.Object(); - - obj.Add("key", null!); - - Assert.Same(JsonValue.Null, obj["key"]); - } - - [Fact] - public void Should_create_null_if_replacing_to_null_object() - { - var obj = JsonValue.Object(); - - obj["key"] = null!; - - Assert.Same(JsonValue.Null, obj["key"]); - } - - [Fact] - public void Should_remove_value_from_object() - { - var obj = JsonValue.Object().Add("key", 1); - - obj.Remove("key"); - - Assert.False(obj.TryGetValue("key", out _)); - Assert.False(obj.ContainsKey("key")); - } - - [Fact] - public void Should_clear_values_from_object() - { - var obj = JsonValue.Object().Add("key", 1); - - obj.Clear(); - - Assert.False(obj.TryGetValue("key", out _)); - Assert.False(obj.ContainsKey("key")); - } - - [Fact] - public void Should_provide_collection_values_from_object() - { - var obj = JsonValue.Object().Add("11", "44").Add("22", "88"); - - var kvps = new[] - { - new KeyValuePair("11", JsonValue.Create("44")), - new KeyValuePair("22", JsonValue.Create("88")) - }; - - Assert.Equal(2, obj.Count); - - Assert.Equal(new[] { "11", "22" }, obj.Keys); - Assert.Equal(new[] { "44", "88" }, obj.Values.Select(x => x.ToString())); - - Assert.Equal(kvps, obj.ToArray()); - Assert.Equal(kvps, ((IEnumerable)obj).OfType>().ToArray()); - } - [Fact] public void Should_throw_exception_if_creation_value_from_invalid_type() { @@ -461,10 +431,10 @@ namespace Squidex.Infrastructure.Json.Objects { var json = JsonValue.Null; - var found = json.TryGet("path", out var result); + var found = json.TryGetByPath("path", out var result); Assert.False(found); - Assert.Null(result); + Assert.Equal(default, result); } [Fact] @@ -472,10 +442,10 @@ namespace Squidex.Infrastructure.Json.Objects { var json = JsonValue.Create("string"); - var found = json.TryGet("path", out var result); + var found = json.TryGetByPath("path", out var result); Assert.False(found); - Assert.Null(result); + Assert.Equal(default, result); } [Fact] @@ -483,10 +453,10 @@ namespace Squidex.Infrastructure.Json.Objects { var json = JsonValue.True; - var found = json.TryGet("path", out var result); + var found = json.TryGetByPath("path", out var result); Assert.False(found); - Assert.Null(result); + Assert.Equal(default, result); } [Fact] @@ -494,43 +464,43 @@ namespace Squidex.Infrastructure.Json.Objects { var json = JsonValue.Create(12); - var found = json.TryGet("path", out var result); + var found = json.TryGetByPath("path", out var result); Assert.False(found); - Assert.Null(result); + Assert.Equal(default, result); } [Fact] public void Should_return_same_object_if_path_is_null() { - var json = JsonValue.Object().Add("property", 12); + JsonValue json = new JsonObject().Add("property", 12); var found = json.TryGetByPath((string?)null, out var result); Assert.False(found); - Assert.Same(json, result); + Assert.Equal(json, result); } [Fact] public void Should_return_same_object_if_path_is_empty() { - var json = JsonValue.Object().Add("property", 12); + JsonValue json = new JsonObject().Add("property", 12); var found = json.TryGetByPath(string.Empty, out var result); Assert.False(found); - Assert.Same(json, result); + Assert.Equal(json, result); } [Fact] public void Should_return_from_nested_array() { - var json = - JsonValue.Object() + JsonValue json = + new JsonObject() .Add("property", JsonValue.Array( JsonValue.Create(12), - JsonValue.Object() + new JsonObject() .Add("nested", 13))); var found = json.TryGetByPath("property[1].nested", out var result); @@ -542,36 +512,36 @@ namespace Squidex.Infrastructure.Json.Objects [Fact] public void Should_return_null_if_property_not_found() { - var json = - JsonValue.Object() + JsonValue json = + new JsonObject() .Add("property", 12); var found = json.TryGetByPath("notfound", out var result); Assert.False(found); - Assert.Null(result); + Assert.Equal(default, result); } [Fact] public void Should_return_null_if_out_of_index1() { - var json = JsonValue.Array(12, 14); + JsonValue json = JsonValue.Array(12, 14); var found = json.TryGetByPath("-1", out var result); Assert.False(found); - Assert.Null(result); + Assert.Equal(default, result); } [Fact] public void Should_return_null_if_out_of_index2() { - var json = JsonValue.Array(12, 14); + JsonValue json = JsonValue.Array(12, 14); var found = json.TryGetByPath("2", out var result); Assert.False(found); - Assert.Null(result); + Assert.Equal(default, result); } } } diff --git a/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonValuesSerializationTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonValuesSerializationTests.cs index 491d2fd1b..830f34d0a 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonValuesSerializationTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonValuesSerializationTests.cs @@ -15,7 +15,7 @@ namespace Squidex.Infrastructure.Json.Objects [Fact] public void Should_deserialize_integer() { - var serialized = TestUtils.Deserialize(123); + var serialized = TestUtils.Deserialize(123); Assert.Equal(JsonValue.Create(123), serialized); } @@ -94,7 +94,7 @@ namespace Squidex.Infrastructure.Json.Objects public void Should_serialize_and_deserialize_object() { var value = - JsonValue.Object() + new JsonObject() .Add("1", 1) .Add("2", 1); @@ -107,13 +107,13 @@ namespace Squidex.Infrastructure.Json.Objects public void Should_serialize_and_deserialize_complex_object() { var value = - JsonValue.Object() + new JsonObject() .Add("1", JsonValue.Array( - JsonValue.Object().Add("1_1", 11), - JsonValue.Object().Add("1_2", 12))) + new JsonObject().Add("1_1", 11), + new JsonObject().Add("1_2", 12))) .Add("2", - JsonValue.Object().Add("2_1", 11)); + new JsonObject().Add("2_1", 11)); var serialized = value.SerializeAndDeserialize(); diff --git a/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryFromJsonTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryFromJsonTests.cs index 1dffd7da3..076a89bfe 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryFromJsonTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryFromJsonTests.cs @@ -649,7 +649,7 @@ namespace Squidex.Infrastructure.Queries { var json = TestUtils.DefaultSerializer.Serialize(value, true); - var jsonFilter = TestUtils.DefaultSerializer.Deserialize>(json); + var jsonFilter = TestUtils.DefaultSerializer.Deserialize>(json); return JsonFilterVisitor.Parse(jsonFilter, Model, errors)?.ToString(); } diff --git a/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryJsonTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryJsonTests.cs index 0ea373dc9..0a81e4b06 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryJsonTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Queries/QueryJsonTests.cs @@ -175,11 +175,11 @@ namespace Squidex.Infrastructure.Queries SerializeAndDeserialize(json); } - private static FilterNode SerializeAndDeserialize(T value) + private static FilterNode SerializeAndDeserialize(T value) { var json = TestUtils.DefaultSerializer.Serialize(value, true); - return TestUtils.DefaultSerializer.Deserialize>(json); + return TestUtils.DefaultSerializer.Deserialize>(json); } } } diff --git a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/TestUtils.cs b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/TestUtils.cs index b3ca95c31..0147cca5c 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/TestUtils.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/TestUtils.cs @@ -40,7 +40,7 @@ namespace Squidex.Infrastructure.TestHelpers new JsonValueConverter(), new StringEnumConverter(), new SurrogateConverter(), - new SurrogateConverter, JsonFilterSurrogate>(), + new SurrogateConverter, JsonFilterSurrogate>(), new TypeConverterJsonConverter()), TypeNameHandling = TypeNameHandling.Auto