Browse Source

Json2 (#884)

* Json2

* Fix tests, more tests and a lot of compiler fixes.

* Fix all code.

* Trim excess

* Build fix.

* Fix errors

* Fix model validation.

* Throw helper.

* More throw helpers.

* Get rid of a useless property.
pull/885/head
Sebastian Stehle 4 years ago
committed by GitHub
parent
commit
5309c37422
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 46
      backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs
  2. 2
      backend/extensions/Squidex.Extensions/Actions/Script/ScriptActionHandler.cs
  3. 2
      backend/extensions/Squidex.Extensions/Samples/Middleware/DoubleLinkedContentMiddleware.cs
  4. 31
      backend/extensions/Squidex.Extensions/Validation/CompositeUniqueValidator.cs
  5. 26
      backend/src/Squidex.Domain.Apps.Core.Model/Apps/Json/RolesSurrogate.cs
  6. 6
      backend/src/Squidex.Domain.Apps.Core.Model/Apps/Role.cs
  7. 10
      backend/src/Squidex.Domain.Apps.Core.Model/Apps/Roles.cs
  8. 30
      backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetMetadata.cs
  9. 16
      backend/src/Squidex.Domain.Apps.Core.Model/Contents/Component.cs
  10. 2
      backend/src/Squidex.Domain.Apps.Core.Model/Contents/ContentData.cs
  11. 42
      backend/src/Squidex.Domain.Apps.Core.Model/Contents/ContentFieldData.cs
  12. 2
      backend/src/Squidex.Domain.Apps.Core.Model/Contents/FlatContentData.cs
  13. 17
      backend/src/Squidex.Domain.Apps.Core.Model/Contents/GeoJsonValue.cs
  14. 2
      backend/src/Squidex.Domain.Apps.Core.Model/Contents/Json/ContentFieldDataConverter.cs
  15. 4
      backend/src/Squidex.Domain.Apps.Core.Model/Rules/Rule.cs
  16. 9
      backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs
  17. 3
      backend/src/Squidex.Domain.Apps.Core.Model/Schemas/NestedField{T}.cs
  18. 3
      backend/src/Squidex.Domain.Apps.Core.Model/Schemas/RootField{T}.cs
  19. 4
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs
  20. 21
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverterFlat.cs
  21. 82
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs
  22. 28
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/StringFormatter.cs
  23. 10
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs
  24. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueExtensions.cs
  25. 50
      backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueFactory.cs
  26. 19
      backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs
  27. 48
      backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs
  28. 51
      backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs
  29. 8
      backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleVariable.cs
  30. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/AssetEntityScriptVars.cs
  31. 10
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/ContentFieldProperty.cs
  32. 68
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/JsonMapper.cs
  33. 6
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs
  34. 8
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs
  35. 6
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs
  36. 36
      backend/src/Squidex.Domain.Apps.Core.Operations/Tags/TagNormalizer.cs
  37. 46
      backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/ContentFluidExtension.cs
  38. 4
      backend/src/Squidex.Domain.Apps.Core.Operations/Templates/Extensions/JsonArrayFluidValue.cs
  39. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs
  40. 4
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs
  41. 117
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs
  42. 72
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueValidator.cs
  43. 3
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/CollectionValidator.cs
  44. 4
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs
  45. 3
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/RangeValidator.cs
  46. 3
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringLengthValidator.cs
  47. 5
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/StringTextValidator.cs
  48. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueObjectValuesValidator.cs
  49. 7
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/LuceneQueryVisitor.cs
  50. 2
      backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettings.cs
  51. 13
      backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettingsGrain.cs
  52. 2
      backend/src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdateRole.cs
  53. 5
      backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/AppDomainObject.cs
  54. 2
      backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettings.cs
  55. 2
      backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettingsGrain.cs
  56. 5
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs
  57. 6
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetFolderDomainObject.cs
  58. 3
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetsBulkUpdateCommandMiddleware.cs
  59. 11
      backend/src/Squidex.Domain.Apps.Entities/Assets/FileTagAssetMetadataSource.cs
  60. 5
      backend/src/Squidex.Domain.Apps.Entities/Comments/DomainObject/CommentsGrain.cs
  61. 63
      backend/src/Squidex.Domain.Apps.Entities/Contents/BackupContents.cs
  62. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateJob.cs
  63. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs
  64. 5
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs
  65. 3
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentsBulkUpdateCommandMiddleware.cs
  66. 14
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs
  67. 7
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ComponentGraphType.cs
  68. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ComponentUnionGraphType.cs
  69. 1
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs
  70. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/DataInputGraphType.cs
  71. 79
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldVisitor.cs
  72. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedInputGraphType.cs
  73. 20
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonGraphType.cs
  74. 5
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonValueNode.cs
  75. 1
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/SharedTypes.cs
  76. 5
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs
  77. 10
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs
  78. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveReferences.cs
  79. 36
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Extensions.cs
  80. 4
      backend/src/Squidex.Domain.Apps.Entities/Q.cs
  81. 6
      backend/src/Squidex.Domain.Apps.Entities/Rules/DomainObject/RuleDomainObject.cs
  82. 5
      backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/SchemaDomainObject.cs
  83. 4
      backend/src/Squidex.Domain.Users/DefaultKeyStore.cs
  84. 3
      backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonReader.cs
  85. 6
      backend/src/Squidex.Infrastructure.MongoDb/MongoDb/DomainIdSerializer.cs
  86. 3
      backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs
  87. 3
      backend/src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/FilterVisitor.cs
  88. 126
      backend/src/Squidex.Infrastructure/Collections/ListDictionary.KeyCollection.cs
  89. 126
      backend/src/Squidex.Infrastructure/Collections/ListDictionary.ValueCollection.cs
  90. 269
      backend/src/Squidex.Infrastructure/Collections/ListDictionary.cs
  91. 2
      backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs
  92. 2
      backend/src/Squidex.Infrastructure/Diagnostics/Diagnoser.cs
  93. 28
      backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeExtensions.cs
  94. 4
      backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeHeaders.cs
  95. 60
      backend/src/Squidex.Infrastructure/Guard.cs
  96. 4
      backend/src/Squidex.Infrastructure/Json/JsonException.cs
  97. 70
      backend/src/Squidex.Infrastructure/Json/Newtonsoft/JsonValueConverter.cs
  98. 8
      backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs
  99. 3
      backend/src/Squidex.Infrastructure/Json/Newtonsoft/TypeConverterJsonConverter.cs
  100. 24
      backend/src/Squidex.Infrastructure/Json/Objects/IJsonValue.cs

46
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<string, object>();
@ -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<object>();
@ -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));
}

2
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());
}
}

2
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<JsonArray>().SelectMany(x => x).SingleOrDefault()?.ToString();
return fieldData.Values.OfType<JsonArray>().SelectMany(x => x).SingleOrDefault().ToString();
}
return null;

31
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;

26
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<string, IJsonValue>, ISurrogate<Roles>
public sealed class RolesSurrogate : Dictionary<string, JsonValue>, ISurrogate<Roles>
{
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<JsonString>().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<JsonString>().Select(x => x.ToString()));
permissions = new PermissionSet(array.AsArray.Where(x => x.Type == JsonValueType.String).Select(x => x.AsString));
}
if (!obj.TryGetValue<JsonObject>("properties", out properties))
if (value.TryGetValue(JsonValueType.Object, "properties", out var obj))
{
properties = JsonValue.Object();
properties = obj.AsObject;
}
}

6
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)

10
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<string, Role>());
@ -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))
{

30
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<string, IJsonValue>
public sealed class AssetMetadata : Dictionary<string, JsonValue>
{
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;
}

16
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<JsonString>(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;
}

2
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;
}

42
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<string, IJsonValue>, IEquatable<ContentFieldData>
public sealed class ContentFieldData : ListDictionary<string, JsonValue>, IEquatable<ContentFieldData>
{
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}"))}}}";
}
}
}
}

2
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<string, IJsonValue?>
public sealed class FlatContentData : Dictionary<string, JsonValue>
{
}
}

17
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<JsonNumber>("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<JsonNumber>("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<string, JsonValue> 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;
}

2
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<IJsonValue>(reader)!;
var value = serializer.Deserialize<JsonValue>(reader)!;
if (Language.IsDefault(propertyName) || propertyName == InvariantPartitioning.Key)
{

4
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))

9
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<T>(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<T>(fieldsOrdered.Select(x => ReferenceEquals(x, field) ? newField : x));

3
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;

3
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;

4
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)
{

21
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;
}
}
}

82
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>(T field, IJsonValue? value, IArrayField? parent, ValueConverter[] converters,
private static JsonValue? ConvertByType<T>(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<JsonString>(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<T>(FieldCollection<T> fields, JsonObject source, IArrayField? parent, ValueConverter[] converters,
private static JsonValue ConvertNested<T>(FieldCollection<T> 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;
}
}

28
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<JsonNumber>("latitude", out var lat) &&
jsonObject.TryGetValue<JsonNumber>("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}";

10
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<AssetsFieldProperties> && value is JsonArray array && shouldHandle(field, parent))
if (field is IField<AssetsFieldProperties> && 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);
}
}

2
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;
}

50
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<IJsonValue, DefaultValueFactory.Args>
public sealed class DefaultValueFactory : IFieldPropertiesVisitor<JsonValue, DefaultValueFactory.Args>
{
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>(T value, LocalizedValue<T>? values, string partition)
@ -132,7 +134,7 @@ namespace Squidex.Domain.Apps.Core.DefaultValues
return value;
}
private static IJsonValue Array(IEnumerable<string>? values)
private static JsonValue Array(IEnumerable<string>? values)
{
if (values != null)
{
@ -140,7 +142,7 @@ namespace Squidex.Domain.Apps.Core.DefaultValues
}
else
{
return JsonValue.Array();
return new JsonArray();
}
}
}

19
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<DomainId> GetReferencedIds(this IField field, IJsonValue? value,
public static HashSet<DomainId> GetReferencedIds(this IField field, JsonValue value,
ResolvedComponents components, int referencesPerField = int.MaxValue)
{
Guard.NotNull(components);
var result = new HashSet<DomainId>();
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;

48
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<IJsonValue, ReferencesCleaner.Args>
internal sealed class ReferencesCleaner : IFieldVisitor<JsonValue, ReferencesCleaner.Args>
{
private static readonly ReferencesCleaner Instance = new ReferencesCleaner();
public record struct Args(IJsonValue Value, ISet<DomainId> ValidIds);
public record struct Args(JsonValue Value, ISet<DomainId> ValidIds);
private ReferencesCleaner()
{
}
public static IJsonValue Cleanup(IField field, IJsonValue? value, HashSet<DomainId> validIds)
public static JsonValue Cleanup(IField field, JsonValue value, HashSet<DomainId> validIds)
{
var args = new Args(value ?? JsonValue.Null, validIds);
var args = new Args(value, validIds);
return field.Accept(Instance, args);
}
public IJsonValue Visit(IField<AssetsFieldProperties> field, Args args)
public JsonValue Visit(IField<AssetsFieldProperties> field, Args args)
{
return CleanIds(args);
}
public IJsonValue Visit(IField<ReferencesFieldProperties> field, Args args)
public JsonValue Visit(IField<ReferencesFieldProperties> field, Args args)
{
return CleanIds(args);
}
public IJsonValue Visit(IField<BooleanFieldProperties> field, Args args)
public JsonValue Visit(IField<BooleanFieldProperties> field, Args args)
{
return args.Value;
}
public IJsonValue Visit(IField<ComponentFieldProperties> field, Args args)
public JsonValue Visit(IField<ComponentFieldProperties> field, Args args)
{
return args.Value;
}
public IJsonValue Visit(IField<ComponentsFieldProperties> field, Args args)
public JsonValue Visit(IField<ComponentsFieldProperties> field, Args args)
{
return args.Value;
}
public IJsonValue Visit(IField<DateTimeFieldProperties> field, Args args)
public JsonValue Visit(IField<DateTimeFieldProperties> field, Args args)
{
return args.Value;
}
public IJsonValue Visit(IField<GeolocationFieldProperties> field, Args args)
public JsonValue Visit(IField<GeolocationFieldProperties> field, Args args)
{
return args.Value;
}
public IJsonValue Visit(IField<JsonFieldProperties> field, Args args)
public JsonValue Visit(IField<JsonFieldProperties> field, Args args)
{
return args.Value;
}
public IJsonValue Visit(IField<NumberFieldProperties> field, Args args)
public JsonValue Visit(IField<NumberFieldProperties> field, Args args)
{
return args.Value;
}
public IJsonValue Visit(IField<StringFieldProperties> field, Args args)
public JsonValue Visit(IField<StringFieldProperties> field, Args args)
{
return args.Value;
}
public IJsonValue Visit(IField<TagsFieldProperties> field, Args args)
public JsonValue Visit(IField<TagsFieldProperties> field, Args args)
{
return args.Value;
}
public IJsonValue Visit(IField<UIFieldProperties> field, Args args)
public JsonValue Visit(IField<UIFieldProperties> 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));
}
}
}

51
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<DomainId> Result, int Take, ResolvedComponents Components);
public record struct Args(JsonValue Value, ISet<DomainId> Result, int Take, ResolvedComponents Components);
private ReferencesExtractor()
{
}
public static None Extract(IField field, IJsonValue? value, HashSet<DomainId> result, int take, ResolvedComponents components)
public static None Extract(IField field, JsonValue value, HashSet<DomainId> 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<ComponentsFieldProperties> 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<JsonString>(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++;

8
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());
}
}
}
}

2
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<string, IJsonValue>(value) : null);
set => SetValue(value != null ? new ReadOnlyDictionary<string, JsonValue>(value) : null);
}
[FieldDescription(nameof(FieldDescriptions.AssetTags))]

10
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;
}
}
}

68
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<JsonValue> 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<string, JsonValue> 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);
}
}
}

6
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs

@ -12,19 +12,19 @@ namespace Squidex.Domain.Apps.Core.Scripting
{
public interface IScriptEngine
{
Task<IJsonValue> ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default,
Task<JsonValue> ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default,
CancellationToken ct = default);
Task<ContentData> 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
{

8
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<IJintExtension>();
}
public async Task<IJsonValue> ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default,
public async Task<JsonValue> 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<IJsonValue>(options, combined.Token)
CreateEngine<JsonValue?>(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<T> CreateEngine<T>(ScriptOptions options, CancellationToken ct) where T : class
private ScriptExecutionContext<T> CreateEngine<T>(ScriptOptions options, CancellationToken ct)
{
if (Debugger.IsAttached)
{

6
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs

@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Core.Scripting
void Run<T>(Action<T>? action, T argument);
}
public sealed class ScriptExecutionContext<T> : ScriptExecutionContext, IScheduler where T : class
public sealed class ScriptExecutionContext<T> : ScriptExecutionContext, IScheduler
{
private readonly TaskCompletionSource<T?> tcs = new TaskCompletionSource<T?>();
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)

36
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<string>();
var newArrays = new List<JsonArray>();
var newArrays = new List<JsonValue>();
var oldValues = new HashSet<string>();
var oldArrays = new List<JsonArray>();
var oldArrays = new List<JsonValue>();
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<string>();
var tagsArrays = new List<JsonArray>();
var tagsArrays = new List<JsonValue>();
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<string> values, List<JsonArray> arrays, params ContentData[] datas)
private static void GetValues(Schema schema, HashSet<string> values, List<JsonValue> 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<string> values, ICollection<JsonArray> arrays)
private static void ExtractTags(JsonValue value, ISet<string> values, ICollection<JsonValue> 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);
}
}
}

46
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<ContentData>(x => new ObjectValue(x));
FluidValue.SetTypeMapping<ContentFieldData>(x => new ObjectValue(x));
FluidValue.SetTypeMapping<JsonObject>(x => new ObjectValue(x));
FluidValue.SetTypeMapping<JsonArray>(x => new JsonArrayFluidValue(x));
FluidValue.SetTypeMapping<JsonString>(x => FluidValue.Create(x.Value));
FluidValue.SetTypeMapping<JsonBoolean>(x => FluidValue.Create(x.Value));
FluidValue.SetTypeMapping<JsonNumber>(x => FluidValue.Create(x.Value));
FluidValue.SetTypeMapping<JsonNull>(_ => FluidValue.Create(null));
memberAccessStrategy.Register<ContentData, object?>(
(value, name) => value.GetOrDefault(name));
FluidValue.SetTypeMapping<JsonValue>(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<JsonObject, object?>(
ThrowHelper.InvalidOperationException();
return default!;
});
memberAccessStrategy.Register<JsonValue, object?>((value, name) =>
{
if (value.Type == JsonValueType.Object)
{
return value.AsObject.GetOrDefault(name);
}
return null;
});
memberAccessStrategy.Register<ContentData, object?>(
(value, name) => value.GetOrDefault(name));
memberAccessStrategy.Register<ContentFieldData, object?>(
(value, name) => value.GetOrDefault(name));
(value, name) => value.GetOrDefault(name).Value);
memberAccessStrategy.Register<JsonObject, object?>(
(value, name) => value.GetOrDefault(name).Value);
}
}
}

4
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);
}
}
}

2
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<IJsonValue>(partitioningValidators, isPartial, typeName), 1)), log);
new ObjectValidator<JsonValue>(partitioningValidators, isPartial, typeName), 1)), log);
}
private IValidator CreateValueValidator(IField field)

4
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<IJsonValue>(nestedValidators, false, "field"));
yield return new CollectionItemValidator(new ObjectValidator<JsonValue>(nestedValidators, false, "field"));
}
public IEnumerable<IValidator> Visit(IField<AssetsFieldProperties> field, Args args)
@ -277,7 +277,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
nestedValidators[nestedField.Name] = (false, factory(nestedField));
}
return new ObjectValidator<IJsonValue>(nestedValidators, false, "field");
return new ObjectValidator<JsonValue>(nestedValidators, false, "field");
});
}
}

117
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<BooleanFieldProperties> 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<NumberFieldProperties> 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<StringFieldProperties> 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<DomainId>(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<string?>(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<JsonObject>(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<DomainId>? allowedIds)
{
if (value is JsonArray array)
if (value.Type == JsonValueType.Array)
{
var array = value.AsArray;
var result = new List<Component>(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<DomainId>? 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<JsonString>("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<JsonString>(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)

72
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<BooleanFieldProperties> field, Args args)
{
return args.Value is JsonBoolean;
return args.Value.Type == JsonValueType.Boolean;
}
public bool Visit(IField<ComponentFieldProperties> field, Args args)
@ -87,7 +87,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
public bool Visit(IField<NumberFieldProperties> field, Args args)
{
return args.Value is JsonNumber;
return args.Value.Type == JsonValueType.Number;
}
public bool Visit(IField<ReferencesFieldProperties> field, Args args)
@ -97,7 +97,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
public bool Visit(IField<StringFieldProperties> field, Args args)
{
return args.Value is JsonString;
return args.Value.Type == JsonValueType.String;
}
public bool Visit(IField<TagsFieldProperties> 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 _);
}

3
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;

4
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)

3
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;

3
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;

5
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;

2
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<JsonObject> items)
{
var duplicates = new HashSet<IJsonValue>(10);
var duplicates = new HashSet<JsonValue>(10);
foreach (var field in fields)
{

7
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";

2
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());
}

13
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> state)
@ -46,13 +46,14 @@ namespace Squidex.Domain.Apps.Entities.Apps
return state.WriteAsync();
}
public Task SetAsync(string path, J<IJsonValue> value)
public Task SetAsync(string path, J<JsonValue> 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
{

2
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; }
}
}

5
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<AppDomainObject.State>
@ -297,7 +299,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
});
default:
throw new NotSupportedException();
ThrowHelper.NotSupportedException();
return default!;
}
}

2
backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettings.cs

@ -14,7 +14,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{
Task<JsonObject> 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);

2
backend/src/Squidex.Domain.Apps.Entities/Apps/IAppUISettingsGrain.cs

@ -15,7 +15,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{
Task<J<JsonObject>> GetAsync();
Task SetAsync(string path, J<IJsonValue> value);
Task SetAsync(string path, J<JsonValue> value);
Task SetAsync(J<JsonObject> settings);

5
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<AssetDomainObject.State>
@ -145,7 +147,8 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
await DeleteCore(c, operation);
});
default:
throw new NotSupportedException();
ThrowHelper.NotSupportedException();
return default!;
}
}

6
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<AssetFolderDomainObject.State>
@ -80,7 +83,8 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
});
default:
throw new NotSupportedException();
ThrowHelper.NotSupportedException();
return default!;
}
}

3
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!;
}
}

11
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());
}
}

5
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!;
}
}

63
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<string, IJsonValue> 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<DomainId, HashSet<DomainId>> contentIdsBySchemaId = new Dictionary<DomainId, HashSet<DomainId>>();
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<string, IJsonValue> source, ObjectSetter setter)
private void ReplaceAssetUrl(IDictionary<string, JsonValue> 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<JsonValue> 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;
}
}

2
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<IJsonValue>? Query { get; set; }
public Query<JsonValue>? Query { get; set; }
public DomainId? Id { get; set; }

4
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))
{

5
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<ContentDomainObject.State>
@ -220,7 +222,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
});
default:
throw new NotSupportedException();
ThrowHelper.NotSupportedException();
return default!;
}
}

3
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!;
}
}

14
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<IReadOnlyList<IEnrichedAssetEntity>> GetReferencedAssetsAsync(IJsonValue value, TimeSpan cacheDuration,
public Task<IReadOnlyList<IEnrichedAssetEntity>> 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<IReadOnlyList<IEnrichedContentEntity>> GetReferencedContentsAsync(IJsonValue value, TimeSpan cacheDuration,
public Task<IReadOnlyList<IEnrichedContentEntity>> 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<DomainId>? ParseIds(IJsonValue value)
private static List<DomainId>? ParseIds(JsonValue value)
{
try
{
List<DomainId>? 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<DomainId>();
result.Add(DomainId.Create(jsonString.Value));
result.Add(DomainId.Create(item.AsString));
}
}
}

7
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;
};
}
}

4
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<JsonString>(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;

1
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;

2
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);
}

79
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<T>(IJsonValue value, IResolveFieldContext fieldContext, GraphQLExecutionContext context);
public delegate T ValueResolver<T>(JsonValue value, IResolveFieldContext fieldContext, GraphQLExecutionContext context);
public delegate Task<T> AsyncValueResolver<T>(IJsonValue value, IResolveFieldContext fieldContext, GraphQLExecutionContext context);
public delegate Task<T> AsyncValueResolver<T>(JsonValue value, IResolveFieldContext fieldContext, GraphQLExecutionContext context);
internal sealed class FieldVisitor : IFieldVisitor<FieldGraphSchema, FieldInfo>
{
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<AssetsFieldProperties> 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<DateTimeFieldProperties> 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<T>(ValueResolver<T> valueResolver)
{
return Resolvers.Sync<IReadOnlyDictionary<string, IJsonValue>, object?>((source, fieldContext, context) =>
return Resolvers.Sync<IReadOnlyDictionary<string, JsonValue>, 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<T>(AsyncValueResolver<T> valueResolver)
{
return Resolvers.Async<IReadOnlyDictionary<string, IJsonValue>, object?>(async (source, fieldContext, context) =>
return Resolvers.Async<IReadOnlyDictionary<string, JsonValue>, 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;
}

4
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<string, object?> 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);
}
}
}

20
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<object> 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<string, object> obj:
{
var json = JsonValue.Object();
var json = new JsonObject();
foreach (var (key, value) in obj)
{

5
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;
}

1
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

5
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<IJsonValue> query,
private ClrQuery ParseJson(Context context, ISchemaEntity? schema, Query<JsonValue> query,
ResolvedComponents components)
{
var queryModel = BuildQueryModel(context, schema, components);

10
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);

2
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)
{

36
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<string, StringBuilder> languages, string language, IJsonValue value)
private static void AppendJsonText(Dictionary<string, StringBuilder> 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;
}
}

4
backend/src/Squidex.Domain.Apps.Entities/Q.cs

@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Entities
public Instant? ScheduledTo { get; init; }
public Query<IJsonValue>? JsonQuery { get; init; }
public Query<JsonValue>? 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<IJsonValue>? query)
public Q WithJsonQuery(Query<JsonValue>? query)
{
return this with { JsonQuery = query };
}

6
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<RuleDomainObject.State>
@ -102,7 +105,8 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
});
default:
throw new NotSupportedException();
ThrowHelper.NotSupportedException();
return default!;
}
}

5
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<SchemaDomainObject.State>
@ -236,7 +238,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject
});
default:
throw new NotSupportedException();
ThrowHelper.NotSupportedException();
return default!;
}
}

4
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)

3
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)

6
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;

3
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;

3
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<object>());
}
throw new NotSupportedException();
ThrowHelper.NotSupportedException();
return default!;
}
private static BsonRegularExpression BuildMatchRegex(CompareFilter<ClrValue> node)

126
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<TKey, TValue>
{
private sealed class KeyCollection : ICollection<TKey>
{
private readonly ListDictionary<TKey, TValue> dictionary;
public int Count
{
get => dictionary.Count;
}
public bool IsReadOnly
{
get => false;
}
public KeyCollection(ListDictionary<TKey, TValue> 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<TKey> GetEnumerator()
{
return new Enumerator(dictionary);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new Enumerator(dictionary);
}
private struct Enumerator : IEnumerator<TKey>, IEnumerator
{
private readonly ListDictionary<TKey, TValue> dictionary;
private int index = -1;
private TKey value = default!;
readonly TKey IEnumerator<TKey>.Current
{
get => value!;
}
readonly object IEnumerator.Current
{
get => value!;
}
public Enumerator(ListDictionary<TKey, TValue> 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;
}
}
}
}
}

126
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<TKey, TValue>
{
private sealed class ValueCollection : ICollection<TValue>
{
private readonly ListDictionary<TKey, TValue> dictionary;
public int Count
{
get => dictionary.Count;
}
public bool IsReadOnly
{
get => false;
}
public ValueCollection(ListDictionary<TKey, TValue> 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<TValue> GetEnumerator()
{
return new Enumerator(dictionary);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new Enumerator(dictionary);
}
private struct Enumerator : IEnumerator<TValue>, IEnumerator
{
private readonly ListDictionary<TKey, TValue> dictionary;
private int index = -1;
private TValue value = default!;
readonly TValue IEnumerator<TValue>.Current
{
get => value!;
}
readonly object IEnumerator.Current
{
get => value!;
}
public Enumerator(ListDictionary<TKey, TValue> 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;
}
}
}
}
}

269
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<TKey, TValue> : IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue> where TKey : notnull
{
private readonly List<KeyValuePair<TKey, TValue>> entries = new List<KeyValuePair<TKey, TValue>>();
private readonly IEqualityComparer<TKey> comparer;
private struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IEnumerator
{
private readonly ListDictionary<TKey, TValue> dictionary;
private int index = -1;
private KeyValuePair<TKey, TValue> value = default!;
readonly KeyValuePair<TKey, TValue> IEnumerator<KeyValuePair<TKey, TValue>>.Current
{
get => value!;
}
readonly object IEnumerator.Current
{
get => value!;
}
public Enumerator(ListDictionary<TKey, TValue> 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<TKey, TValue>(key, value);
}
else
{
entries.Add(new KeyValuePair<TKey, TValue>(key, value));
}
}
}
public ICollection<TKey> Keys
{
get => new KeyCollection(this);
}
public ICollection<TValue> Values
{
get => new ValueCollection(this);
}
public int Count
{
get => entries.Count;
}
public int Capacity
{
get => entries.Capacity;
}
public bool IsReadOnly
{
get => false;
}
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys
{
get => new KeyCollection(this);
}
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values
{
get => new ValueCollection(this);
}
public ListDictionary()
: this(1, null)
{
}
public ListDictionary(ListDictionary<TKey, TValue> source, IEqualityComparer<TKey>? comparer = null)
{
Guard.NotNull(source);
entries = source.entries.ToList();
this.comparer = comparer ?? EqualityComparer<TKey>.Default;
}
public ListDictionary(int capacity, IEqualityComparer<TKey>? comparer = null)
{
Guard.GreaterEquals(capacity, 0);
entries = new List<KeyValuePair<TKey, TValue>>(capacity);
this.comparer = comparer ?? EqualityComparer<TKey>.Default;
}
public void Add(TKey key, TValue value)
{
if (ContainsKey(key))
{
ThrowHelper.ArgumentException("Key already exists.", nameof(key));
}
entries.Add(new KeyValuePair<TKey, TValue>(key, value));
}
public void Add(KeyValuePair<TKey, TValue> item)
{
Add(item.Key, item.Value);
}
public void Clear()
{
entries.Clear();
}
public bool Contains(KeyValuePair<TKey, TValue> 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<TKey, TValue> 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<TKey, TValue>[] array, int arrayIndex)
{
entries.CopyTo(array, arrayIndex);
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return new Enumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new Enumerator(this);
}
}
}

2
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}.");
}
}

2
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))

28
backend/src/Squidex.Infrastructure/EventSourcing/EnvelopeExtensions.cs

@ -21,7 +21,7 @@ namespace Squidex.Infrastructure.EventSourcing
public static Envelope<T> SetEventPosition<T>(this Envelope<T> 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<T> SetEventStreamNumber<T>(this Envelope<T> 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<T> SetCommitId<T>(this Envelope<T> 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<T> SetAggregateId<T>(this Envelope<T> 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<T> SetEventId<T>(this Envelope<T> 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<T> SetTimestamp<T>(this Envelope<T> 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<T> SetRestored<T>(this Envelope<T> 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;

4
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<string, IJsonValue>
public sealed class EnvelopeHeaders : Dictionary<string, JsonValue>
{
public EnvelopeHeaders()
{
}
public EnvelopeHeaders(IDictionary<string, IJsonValue> headers)
public EnvelopeHeaders(IDictionary<string, JsonValue> headers)
: base(headers)
{
}

60
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!;

4
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)
{
}

70
backend/src/Squidex.Infrastructure/Json/Newtonsoft/JsonValueConverter.cs

@ -16,13 +16,7 @@ namespace Squidex.Infrastructure.Json.Newtonsoft
{
private readonly HashSet<Type> supportedTypes = new HashSet<Type>
{
typeof(IJsonValue),
typeof(JsonArray),
typeof(JsonBoolean),
typeof(JsonNull),
typeof(JsonNumber),
typeof(JsonObject),
typeof(JsonString)
typeof(JsonValue)
};
public virtual IEnumerable<Type> 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);

8
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!;
}
}

3
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;
}
}

24
backend/src/Squidex.Infrastructure/Json/Objects/IJsonValue.cs

@ -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<IJsonValue>
{
JsonValueType Type { get; }
bool TryGet(string pathSegment, [MaybeNullWhen(false)] out IJsonValue result);
IJsonValue Clone();
string ToJsonString();
string ToString();
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save