Browse Source

Extracted schema generation.

pull/141/head
Sebastian Stehle 9 years ago
parent
commit
f6a58edc09
  1. 2
      src/Squidex.Domain.Apps.Core/ContentEnricher.cs
  2. 4
      src/Squidex.Domain.Apps.Core/ContentValidator.cs
  3. 2
      src/Squidex.Domain.Apps.Core/Contents/IdContentData.cs
  4. 4
      src/Squidex.Domain.Apps.Core/Contents/NamedContentData.cs
  5. 14
      src/Squidex.Domain.Apps.Core/Schemas/AssetsField.cs
  6. 12
      src/Squidex.Domain.Apps.Core/Schemas/BooleanField.cs
  7. 13
      src/Squidex.Domain.Apps.Core/Schemas/DateTimeField.cs
  8. 60
      src/Squidex.Domain.Apps.Core/Schemas/Edm/EdmSchemaExtensions.cs
  9. 62
      src/Squidex.Domain.Apps.Core/Schemas/Edm/EdmTypeVisitor.cs
  10. 90
      src/Squidex.Domain.Apps.Core/Schemas/Field.cs
  11. 34
      src/Squidex.Domain.Apps.Core/Schemas/GeolocationField.cs
  12. 28
      src/Squidex.Domain.Apps.Core/Schemas/IFieldVisitor.cs
  13. 2
      src/Squidex.Domain.Apps.Core/Schemas/Json/SchemaJsonSerializer.cs
  14. 12
      src/Squidex.Domain.Apps.Core/Schemas/JsonField.cs
  15. 71
      src/Squidex.Domain.Apps.Core/Schemas/JsonSchema/JsonSchemaExtensions.cs
  16. 151
      src/Squidex.Domain.Apps.Core/Schemas/JsonSchema/JsonTypeVisitor.cs
  17. 22
      src/Squidex.Domain.Apps.Core/Schemas/NumberField.cs
  18. 14
      src/Squidex.Domain.Apps.Core/Schemas/ReferencesField.cs
  19. 38
      src/Squidex.Domain.Apps.Core/Schemas/Schema.cs
  20. 26
      src/Squidex.Domain.Apps.Core/Schemas/StringField.cs
  21. 2
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/GraphQLModel.cs
  22. 34
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/AssetGraphType.cs
  23. 6
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/ContentDataGraphType.cs
  24. 16
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/ContentGraphType.cs
  25. 8
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/ContentQueryGraphType.cs
  26. 1
      src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs
  27. 4
      src/Squidex.Domain.Apps.Write/Schemas/Commands/AddField.cs
  28. 2
      src/Squidex.Domain.Apps.Write/Schemas/SchemaCommandMiddleware.cs
  29. 2
      src/Squidex.Domain.Apps.Write/Schemas/SchemaDomainObject.cs
  30. 4
      src/Squidex/Controllers/Api/Schemas/Models/AddFieldDto.cs
  31. 2
      src/Squidex/Controllers/Api/Schemas/Models/Converters/SchemaConverter.cs
  32. 4
      src/Squidex/Controllers/Api/Schemas/SchemaFieldsController.cs
  33. 1
      tests/Benchmarks/Tests/HandleEventsWithManyWriters.cs
  34. 50
      tests/Squidex.Domain.Apps.Core.Tests/Schemas/SchemaTests.cs
  35. 4
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaCommandMiddlewareTests.cs
  36. 16
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaDomainObjectTests.cs
  37. 1
      tests/Squidex.Infrastructure.Tests/Timers/CompletionTimerTests.cs

2
src/Squidex.Domain.Apps.Core/ContentEnricher.cs

@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Core
{ {
var fieldKey = data.GetKey(field); var fieldKey = data.GetKey(field);
var fieldData = data.GetOrCreate(fieldKey, k => new ContentFieldData()); var fieldData = data.GetOrCreate(fieldKey, k => new ContentFieldData());
var fieldPartition = partitionResolver(field.Paritioning); var fieldPartition = partitionResolver(field.Partitioning);
foreach (var partitionItem in fieldPartition) foreach (var partitionItem in fieldPartition)
{ {

4
src/Squidex.Domain.Apps.Core/ContentValidator.cs

@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Core
private Task ValidateFieldPartialAsync(Field field, ContentFieldData fieldData) private Task ValidateFieldPartialAsync(Field field, ContentFieldData fieldData)
{ {
var partitioning = field.Paritioning; var partitioning = field.Partitioning;
var partition = partitionResolver(partitioning); var partition = partitionResolver(partitioning);
var tasks = new List<Task>(); var tasks = new List<Task>();
@ -116,7 +116,7 @@ namespace Squidex.Domain.Apps.Core
private Task ValidateFieldAsync(Field field, ContentFieldData fieldData) private Task ValidateFieldAsync(Field field, ContentFieldData fieldData)
{ {
var partitioning = field.Paritioning; var partitioning = field.Partitioning;
var partition = partitionResolver(partitioning); var partition = partitionResolver(partitioning);
var tasks = new List<Task>(); var tasks = new List<Task>();

2
src/Squidex.Domain.Apps.Core/Contents/IdContentData.cs

@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Core.Contents
return Clean(this, new IdContentData()); return Clean(this, new IdContentData());
} }
public IdContentData Add(long id, ContentFieldData data) public IdContentData AddField(long id, ContentFieldData data)
{ {
Guard.GreaterThan(id, 0, nameof(id)); Guard.GreaterThan(id, 0, nameof(id));

4
src/Squidex.Domain.Apps.Core/Contents/NamedContentData.cs

@ -34,7 +34,7 @@ namespace Squidex.Domain.Apps.Core.Contents
return Clean(this, new NamedContentData()); return Clean(this, new NamedContentData());
} }
public NamedContentData Add(string name, ContentFieldData data) public NamedContentData AddField(string name, ContentFieldData data)
{ {
Guard.NotNullOrEmpty(name, nameof(name)); Guard.NotNullOrEmpty(name, nameof(name));
@ -107,7 +107,7 @@ namespace Squidex.Domain.Apps.Core.Contents
var fieldResult = new ContentFieldData(); var fieldResult = new ContentFieldData();
var fieldValues = fieldValue.Value; var fieldValues = fieldValue.Value;
if (field.Paritioning.Equals(Partitioning.Language)) if (field.Partitioning.Equals(Partitioning.Language))
{ {
foreach (var languageConfig in languagesConfig) foreach (var languageConfig in languagesConfig)
{ {

14
src/Squidex.Domain.Apps.Core/Schemas/AssetsField.cs

@ -9,9 +9,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.OData.Edm;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema;
using Squidex.Domain.Apps.Core.Schemas.Validators; using Squidex.Domain.Apps.Core.Schemas.Validators;
namespace Squidex.Domain.Apps.Core.Schemas namespace Squidex.Domain.Apps.Core.Schemas
@ -68,17 +66,9 @@ namespace Squidex.Domain.Apps.Core.Schemas
return new AssetsValue(value.ToObject<Guid[]>()); return new AssetsValue(value.ToObject<Guid[]>());
} }
protected override void PrepareJsonSchema(JsonProperty jsonProperty, Func<string, JsonSchema4, JsonSchema4> schemaResolver) public override T Visit<T>(IFieldVisitor<T> visitor)
{ {
var itemSchema = schemaResolver("AssetItem", new JsonSchema4 { Type = JsonObjectType.String }); return visitor.Visit(this);
jsonProperty.Type = JsonObjectType.Array;
jsonProperty.Item = itemSchema;
}
protected override IEdmTypeReference CreateEdmType()
{
return EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.String, !Properties.IsRequired);
} }
} }
} }

12
src/Squidex.Domain.Apps.Core/Schemas/BooleanField.cs

@ -6,11 +6,8 @@
// All rights reserved. // All rights reserved.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.OData.Edm;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema;
using Squidex.Domain.Apps.Core.Schemas.Validators; using Squidex.Domain.Apps.Core.Schemas.Validators;
namespace Squidex.Domain.Apps.Core.Schemas namespace Squidex.Domain.Apps.Core.Schemas
@ -40,14 +37,9 @@ namespace Squidex.Domain.Apps.Core.Schemas
return (bool?)value; return (bool?)value;
} }
protected override void PrepareJsonSchema(JsonProperty jsonProperty, Func<string, JsonSchema4, JsonSchema4> schemaResolver) public override T Visit<T>(IFieldVisitor<T> visitor)
{ {
jsonProperty.Type = JsonObjectType.Boolean; return visitor.Visit(this);
}
protected override IEdmTypeReference CreateEdmType()
{
return EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.Boolean, !Properties.IsRequired);
} }
} }
} }

13
src/Squidex.Domain.Apps.Core/Schemas/DateTimeField.cs

@ -8,9 +8,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.OData.Edm;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema;
using NodaTime; using NodaTime;
using NodaTime.Text; using NodaTime.Text;
using Squidex.Domain.Apps.Core.Schemas.Validators; using Squidex.Domain.Apps.Core.Schemas.Validators;
@ -59,16 +57,9 @@ namespace Squidex.Domain.Apps.Core.Schemas
throw new InvalidCastException("Invalid json type, expected string."); throw new InvalidCastException("Invalid json type, expected string.");
} }
protected override void PrepareJsonSchema(JsonProperty jsonProperty, Func<string, JsonSchema4, JsonSchema4> schemaResolver) public override T Visit<T>(IFieldVisitor<T> visitor)
{ {
jsonProperty.Type = JsonObjectType.String; return visitor.Visit(this);
jsonProperty.Format = JsonFormatStrings.DateTime;
}
protected override IEdmTypeReference CreateEdmType()
{
return EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.DateTimeOffset, !Properties.IsRequired);
} }
} }
} }

60
src/Squidex.Domain.Apps.Core/Schemas/Edm/EdmSchemaExtensions.cs

@ -0,0 +1,60 @@
// ==========================================================================
// EdmSchemaExtensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Linq;
using Microsoft.OData.Edm;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Schemas.Edm
{
public static class EdmSchemaExtensions
{
public static string EscapeEdmField(this string field)
{
return field.Replace("-", "_");
}
public static string UnescapeEdmField(this string field)
{
return field.Replace("_", "-");
}
public static EdmComplexType BuildEdmType(this Schema schema, PartitionResolver partitionResolver, Func<EdmComplexType, EdmComplexType> typeResolver)
{
Guard.NotNull(typeResolver, nameof(typeResolver));
Guard.NotNull(partitionResolver, nameof(partitionResolver));
var schemaName = schema.Name.ToPascalCase();
var edmType = new EdmComplexType("Squidex", schemaName);
foreach (var field in schema.FieldsByName.Values.Where(x => !x.IsHidden))
{
var edmValueType = field.Visit(EdmTypeVisitor.Instance);
if (edmValueType == null)
{
continue;
}
var partitionType = typeResolver(new EdmComplexType("Squidex", $"{schemaName}{field.Name.ToPascalCase()}Property"));
var partition = partitionResolver(field.Partitioning);
foreach (var partitionItem in partition)
{
partitionType.AddStructuralProperty(partitionItem.Key, edmValueType);
}
edmType.AddStructuralProperty(field.Name.EscapeEdmField(), new EdmComplexTypeReference(partitionType, false));
}
return edmType;
}
}
}

62
src/Squidex.Domain.Apps.Core/Schemas/Edm/EdmTypeVisitor.cs

@ -0,0 +1,62 @@
// ==========================================================================
// EdmTypeVisitor.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Microsoft.OData.Edm;
namespace Squidex.Domain.Apps.Core.Schemas.Edm
{
public sealed class EdmTypeVisitor : IFieldVisitor<IEdmTypeReference>
{
public static readonly EdmTypeVisitor Instance = new EdmTypeVisitor();
public IEdmTypeReference Visit(AssetsField field)
{
return CreatePrimitive(EdmPrimitiveTypeKind.String, field);
}
public IEdmTypeReference Visit(BooleanField field)
{
return CreatePrimitive(EdmPrimitiveTypeKind.Boolean, field);
}
public IEdmTypeReference Visit(DateTimeField field)
{
return CreatePrimitive(EdmPrimitiveTypeKind.DateTimeOffset, field);
}
public IEdmTypeReference Visit(GeolocationField field)
{
return null;
}
public IEdmTypeReference Visit(JsonField field)
{
return null;
}
public IEdmTypeReference Visit(NumberField field)
{
return CreatePrimitive(EdmPrimitiveTypeKind.Double, field);
}
public IEdmTypeReference Visit(ReferencesField field)
{
return CreatePrimitive(EdmPrimitiveTypeKind.String, field);
}
public IEdmTypeReference Visit(StringField field)
{
return CreatePrimitive(EdmPrimitiveTypeKind.String, field);
}
private static IEdmTypeReference CreatePrimitive(EdmPrimitiveTypeKind kind, Field field)
{
return EdmCoreModel.Instance.GetPrimitive(kind, !field.RawProperties.IsRequired);
}
}
}

90
src/Squidex.Domain.Apps.Core/Schemas/Field.cs

@ -8,9 +8,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.OData.Edm;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema;
using Squidex.Domain.Apps.Core.Schemas.Validators; using Squidex.Domain.Apps.Core.Schemas.Validators;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -51,7 +49,7 @@ namespace Squidex.Domain.Apps.Core.Schemas
get { return isDisabled; } get { return isDisabled; }
} }
public Partitioning Paritioning public Partitioning Partitioning
{ {
get { return partitioning; } get { return partitioning; }
} }
@ -65,9 +63,9 @@ namespace Squidex.Domain.Apps.Core.Schemas
protected Field(long id, string name, Partitioning partitioning) protected Field(long id, string name, Partitioning partitioning)
{ {
Guard.ValidPropertyName(name, nameof(name)); Guard.NotNullOrEmpty(name, nameof(name));
Guard.GreaterThan(id, 0, nameof(id));
Guard.NotNull(partitioning, nameof(partitioning)); Guard.NotNull(partitioning, nameof(partitioning));
Guard.GreaterThan(id, 0, nameof(id));
fieldId = id; fieldId = id;
fieldName = name; fieldName = name;
@ -79,6 +77,8 @@ namespace Squidex.Domain.Apps.Core.Schemas
protected abstract Field UpdateInternal(FieldProperties newProperties); protected abstract Field UpdateInternal(FieldProperties newProperties);
protected abstract IEnumerable<IValidator> CreateValidators();
public abstract object ConvertValue(JToken value); public abstract object ConvertValue(JToken value);
public Field Lock() public Field Lock()
@ -108,87 +108,9 @@ namespace Squidex.Domain.Apps.Core.Schemas
public Field Update(FieldProperties newProperties) public Field Update(FieldProperties newProperties)
{ {
if (isLocked)
{
throw new InvalidOperationException($"Field {fieldId} is locked.");
}
return UpdateInternal(newProperties); return UpdateInternal(newProperties);
} }
public void AddToEdmType(EdmStructuredType edmType, PartitionResolver partitionResolver, string schemaName, Func<EdmComplexType, EdmComplexType> typeResolver) public abstract T Visit<T>(IFieldVisitor<T> visitor);
{
Guard.NotNull(edmType, nameof(edmType));
Guard.NotNull(typeResolver, nameof(typeResolver));
Guard.NotNull(partitionResolver, nameof(partitionResolver));
var edmValueType = CreateEdmType();
if (edmValueType == null)
{
return;
}
var partitionType = typeResolver(new EdmComplexType("Squidex", $"{schemaName}{Name.ToPascalCase()}Property"));
var partition = partitionResolver(partitioning);
foreach (var partitionItem in partition)
{
partitionType.AddStructuralProperty(partitionItem.Key, edmValueType);
}
edmType.AddStructuralProperty(Name.EscapeEdmField(), new EdmComplexTypeReference(partitionType, false));
}
public void AddToJsonSchema(JsonSchema4 schema, PartitionResolver partitionResolver, string schemaName, Func<string, JsonSchema4, JsonSchema4> schemaResolver)
{
Guard.NotNull(schema, nameof(schema));
Guard.NotNull(schemaResolver, nameof(schemaResolver));
Guard.NotNull(partitionResolver, nameof(partitionResolver));
var partitionProperty = CreateProperty();
var partitionObject = new JsonSchema4 { Type = JsonObjectType.Object, AllowAdditionalProperties = false };
var partition = partitionResolver(partitioning);
foreach (var partitionItem in partition)
{
var partitionItemProperty = new JsonProperty { Description = partitionItem.Name, IsRequired = RawProperties.IsRequired };
PrepareJsonSchema(partitionItemProperty, schemaResolver);
partitionObject.Properties.Add(partitionItem.Key, partitionItemProperty);
}
partitionProperty.Reference = schemaResolver($"{schemaName}{Name.ToPascalCase()}Property", partitionObject);
schema.Properties.Add(Name, partitionProperty);
}
public JsonProperty CreateProperty()
{
var jsonProperty = new JsonProperty { IsRequired = RawProperties.IsRequired, Type = JsonObjectType.Object };
if (!string.IsNullOrWhiteSpace(RawProperties.Hints))
{
jsonProperty.Description = RawProperties.Hints;
}
else
{
jsonProperty.Description = Name;
}
if (!string.IsNullOrWhiteSpace(RawProperties.Hints))
{
jsonProperty.Description += $" ({RawProperties.Hints}).";
}
return jsonProperty;
}
protected abstract IEnumerable<IValidator> CreateValidators();
protected abstract IEdmTypeReference CreateEdmType();
protected abstract void PrepareJsonSchema(JsonProperty jsonProperty, Func<string, JsonSchema4, JsonSchema4> schemaResolver);
} }
} }

34
src/Squidex.Domain.Apps.Core/Schemas/GeolocationField.cs

@ -8,9 +8,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.OData.Edm;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema;
using Squidex.Domain.Apps.Core.Schemas.Validators; using Squidex.Domain.Apps.Core.Schemas.Validators;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -58,37 +56,9 @@ namespace Squidex.Domain.Apps.Core.Schemas
return value; return value;
} }
protected override void PrepareJsonSchema(JsonProperty jsonProperty, Func<string, JsonSchema4, JsonSchema4> schemaResolver) public override T Visit<T>(IFieldVisitor<T> visitor)
{ {
jsonProperty.Type = JsonObjectType.Object; return visitor.Visit(this);
var geolocationSchema = new JsonSchema4();
geolocationSchema.Properties.Add("latitude", new JsonProperty
{
Type = JsonObjectType.Number,
Minimum = -90,
Maximum = 90,
IsRequired = true
});
geolocationSchema.Properties.Add("longitude", new JsonProperty
{
Type = JsonObjectType.Number,
Minimum = -180,
Maximum = 180,
IsRequired = true
});
geolocationSchema.AllowAdditionalProperties = false;
var schemaReference = schemaResolver("GeolocationDto", geolocationSchema);
jsonProperty.Reference = schemaReference;
}
protected override IEdmTypeReference CreateEdmType()
{
return null;
} }
} }
} }

28
src/Squidex.Domain.Apps.Core/Schemas/EdmExtensions.cs → src/Squidex.Domain.Apps.Core/Schemas/IFieldVisitor.cs

@ -1,5 +1,5 @@
// ========================================================================== // ==========================================================================
// EdmExtensions.cs // IFieldVisitor.cs
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex Group // Copyright (c) Squidex Group
@ -8,16 +8,22 @@
namespace Squidex.Domain.Apps.Core.Schemas namespace Squidex.Domain.Apps.Core.Schemas
{ {
public static class EdmExtensions public interface IFieldVisitor<T>
{ {
public static string EscapeEdmField(this string field) T Visit(AssetsField field);
{
return field.Replace("-", "_"); T Visit(BooleanField field);
}
T Visit(DateTimeField field);
public static string UnescapeEdmField(this string field)
{ T Visit(GeolocationField field);
return field.Replace("_", "-");
} T Visit(JsonField field);
T Visit(NumberField field);
T Visit(ReferencesField field);
T Visit(StringField field);
} }
} }

2
src/Squidex.Domain.Apps.Core/Schemas/Json/SchemaJsonSerializer.cs

@ -42,7 +42,7 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json
IsHidden = x.IsHidden, IsHidden = x.IsHidden,
IsLocked = x.IsLocked, IsLocked = x.IsLocked,
IsDisabled = x.IsDisabled, IsDisabled = x.IsDisabled,
Partitioning = x.Paritioning.Key, Partitioning = x.Partitioning.Key,
Properties = x.RawProperties Properties = x.RawProperties
}).ToList(); }).ToList();

12
src/Squidex.Domain.Apps.Core/Schemas/JsonField.cs

@ -6,11 +6,8 @@
// All rights reserved. // All rights reserved.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.OData.Edm;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema;
using Squidex.Domain.Apps.Core.Schemas.Validators; using Squidex.Domain.Apps.Core.Schemas.Validators;
namespace Squidex.Domain.Apps.Core.Schemas namespace Squidex.Domain.Apps.Core.Schemas
@ -40,14 +37,9 @@ namespace Squidex.Domain.Apps.Core.Schemas
return value; return value;
} }
protected override void PrepareJsonSchema(JsonProperty jsonProperty, Func<string, JsonSchema4, JsonSchema4> schemaResolver) public override T Visit<T>(IFieldVisitor<T> visitor)
{ {
jsonProperty.Type = JsonObjectType.Object; return visitor.Visit(this);
}
protected override IEdmTypeReference CreateEdmType()
{
return null;
} }
} }
} }

71
src/Squidex.Domain.Apps.Core/Schemas/JsonSchema/JsonSchemaExtensions.cs

@ -0,0 +1,71 @@
// ==========================================================================
// JsonSchemaExtensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Linq;
using NJsonSchema;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Schemas.JsonSchema
{
public static class JsonSchemaExtensions
{
public static JsonSchema4 BuildJsonSchema(this Schema schema, PartitionResolver partitionResolver, Func<string, JsonSchema4, JsonSchema4> schemaResolver)
{
Guard.NotNull(schemaResolver, nameof(schemaResolver));
Guard.NotNull(partitionResolver, nameof(partitionResolver));
var schemaName = schema.Name.ToPascalCase();
var jsonTypeVisitor = new JsonTypeVisitor(schemaResolver);
var jsonSchema = new JsonSchema4 { Type = JsonObjectType.Object };
foreach (var field in schema.Fields.Where(x => !x.IsHidden))
{
var partitionProperty = CreateProperty(field);
var partitionObject = new JsonSchema4 { Type = JsonObjectType.Object, AllowAdditionalProperties = false };
var partition = partitionResolver(field.Partitioning);
foreach (var partitionItem in partition)
{
var partitionItemProperty = field.Visit(jsonTypeVisitor);
partitionItemProperty.Description = partitionItem.Name;
partitionObject.Properties.Add(partitionItem.Key, partitionItemProperty);
}
partitionProperty.Reference = schemaResolver($"{schemaName}{field.Name.ToPascalCase()}Property", partitionObject);
jsonSchema.Properties.Add(field.Name, partitionProperty);
}
return jsonSchema;
}
public static JsonProperty CreateProperty(Field field)
{
var jsonProperty = new JsonProperty { IsRequired = field.RawProperties.IsRequired, Type = JsonObjectType.Object };
if (!string.IsNullOrWhiteSpace(field.RawProperties.Hints))
{
jsonProperty.Description = field.RawProperties.Hints;
}
else
{
jsonProperty.Description = field.Name;
}
if (!string.IsNullOrWhiteSpace(field.RawProperties.Hints))
{
jsonProperty.Description += $" ({field.RawProperties.Hints}).";
}
return jsonProperty;
}
}
}

151
src/Squidex.Domain.Apps.Core/Schemas/JsonSchema/JsonTypeVisitor.cs

@ -0,0 +1,151 @@
// ==========================================================================
// JsonTypeVisitor.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.ObjectModel;
using NJsonSchema;
namespace Squidex.Domain.Apps.Core.Schemas.JsonSchema
{
public sealed class JsonTypeVisitor : IFieldVisitor<JsonProperty>
{
private readonly Func<string, JsonSchema4, JsonSchema4> schemaResolver;
public JsonTypeVisitor(Func<string, JsonSchema4, JsonSchema4> schemaResolver)
{
this.schemaResolver = schemaResolver;
}
public JsonProperty Visit(AssetsField field)
{
return CreateProperty(field, jsonProperty =>
{
var itemSchema = schemaResolver("AssetItem", new JsonSchema4 { Type = JsonObjectType.String });
jsonProperty.Type = JsonObjectType.Array;
jsonProperty.Item = itemSchema;
});
}
public JsonProperty Visit(BooleanField field)
{
return CreateProperty(field, jsonProperty =>
{
jsonProperty.Type = JsonObjectType.Boolean;
});
}
public JsonProperty Visit(DateTimeField field)
{
return CreateProperty(field, jsonProperty =>
{
jsonProperty.Type = JsonObjectType.String;
jsonProperty.Format = JsonFormatStrings.DateTime;
});
}
public JsonProperty Visit(GeolocationField field)
{
return CreateProperty(field, jsonProperty =>
{
var geolocationSchema = new JsonSchema4
{
AllowAdditionalProperties = false
};
geolocationSchema.Properties.Add("latitude", new JsonProperty
{
Type = JsonObjectType.Number,
Minimum = -90,
Maximum = 90,
IsRequired = true
});
geolocationSchema.Properties.Add("longitude", new JsonProperty
{
Type = JsonObjectType.Number,
Minimum = -180,
Maximum = 180,
IsRequired = true
});
var schemaReference = schemaResolver("GeolocationDto", geolocationSchema);
jsonProperty.Type = JsonObjectType.Object;
jsonProperty.Reference = schemaReference;
});
}
public JsonProperty Visit(JsonField field)
{
return CreateProperty(field, jsonProperty =>
{
jsonProperty.Type = JsonObjectType.Object;
});
}
public JsonProperty Visit(NumberField field)
{
return CreateProperty(field, jsonProperty =>
{
jsonProperty.Type = JsonObjectType.Number;
if (field.Properties.MinValue.HasValue)
{
jsonProperty.Minimum = (decimal)field.Properties.MinValue.Value;
}
if (field.Properties.MaxValue.HasValue)
{
jsonProperty.Maximum = (decimal)field.Properties.MaxValue.Value;
}
});
}
public JsonProperty Visit(ReferencesField field)
{
return CreateProperty(field, jsonProperty =>
{
var itemSchema = schemaResolver("ReferenceItem", new JsonSchema4 { Type = JsonObjectType.String });
jsonProperty.Type = JsonObjectType.Array;
jsonProperty.Item = itemSchema;
});
}
public JsonProperty Visit(StringField field)
{
return CreateProperty(field, jsonProperty =>
{
jsonProperty.Type = JsonObjectType.String;
jsonProperty.MinLength = field.Properties.MinLength;
jsonProperty.MaxLength = field.Properties.MaxLength;
if (field.Properties.AllowedValues != null)
{
var names = jsonProperty.EnumerationNames = jsonProperty.EnumerationNames ?? new Collection<string>();
foreach (var value in field.Properties.AllowedValues)
{
names.Add(value);
}
}
});
}
private static JsonProperty CreateProperty(Field field, Action<JsonProperty> updater)
{
var property = new JsonProperty { IsRequired = field.RawProperties.IsRequired };
updater(property);
return property;
}
}
}

22
src/Squidex.Domain.Apps.Core/Schemas/NumberField.cs

@ -6,12 +6,9 @@
// All rights reserved. // All rights reserved.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.OData.Edm;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema;
using Squidex.Domain.Apps.Core.Schemas.Validators; using Squidex.Domain.Apps.Core.Schemas.Validators;
namespace Squidex.Domain.Apps.Core.Schemas namespace Squidex.Domain.Apps.Core.Schemas
@ -46,24 +43,9 @@ namespace Squidex.Domain.Apps.Core.Schemas
} }
} }
protected override void PrepareJsonSchema(JsonProperty jsonProperty, Func<string, JsonSchema4, JsonSchema4> schemaResolver) public override T Visit<T>(IFieldVisitor<T> visitor)
{ {
jsonProperty.Type = JsonObjectType.Number; return visitor.Visit(this);
if (Properties.MinValue.HasValue)
{
jsonProperty.Minimum = (decimal)Properties.MinValue.Value;
}
if (Properties.MaxValue.HasValue)
{
jsonProperty.Maximum = (decimal)Properties.MaxValue.Value;
}
}
protected override IEdmTypeReference CreateEdmType()
{
return EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.Double, !Properties.IsRequired);
} }
public override object ConvertValue(JToken value) public override object ConvertValue(JToken value)

14
src/Squidex.Domain.Apps.Core/Schemas/ReferencesField.cs

@ -9,9 +9,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.OData.Edm;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema;
using Squidex.Domain.Apps.Core.Schemas.Validators; using Squidex.Domain.Apps.Core.Schemas.Validators;
namespace Squidex.Domain.Apps.Core.Schemas namespace Squidex.Domain.Apps.Core.Schemas
@ -76,17 +74,9 @@ namespace Squidex.Domain.Apps.Core.Schemas
return new ReferencesValue(value.ToObject<Guid[]>()); return new ReferencesValue(value.ToObject<Guid[]>());
} }
protected override void PrepareJsonSchema(JsonProperty jsonProperty, Func<string, JsonSchema4, JsonSchema4> schemaResolver) public override T Visit<T>(IFieldVisitor<T> visitor)
{ {
var itemSchema = schemaResolver("ReferenceItem", new JsonSchema4 { Type = JsonObjectType.String }); return visitor.Visit(this);
jsonProperty.Type = JsonObjectType.Array;
jsonProperty.Item = itemSchema;
}
protected override IEdmTypeReference CreateEdmType()
{
return EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.String, !Properties.IsRequired);
} }
} }
} }

38
src/Squidex.Domain.Apps.Core/Schemas/Schema.cs

@ -10,8 +10,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Microsoft.OData.Edm;
using NJsonSchema;
using Squidex.Infrastructure; using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Schemas namespace Squidex.Domain.Apps.Core.Schemas
@ -160,7 +158,7 @@ namespace Squidex.Domain.Apps.Core.Schemas
{ {
Guard.NotNull(field, nameof(field)); Guard.NotNull(field, nameof(field));
if (fieldsById.Values.Any(f => f.Name == field.Name && f.Id != field.Id)) if (fieldsByName.ContainsKey(field.Name))
{ {
throw new ArgumentException($"A field with name '{field.Name}' already exists.", nameof(field)); throw new ArgumentException($"A field with name '{field.Name}' already exists.", nameof(field));
} }
@ -178,39 +176,5 @@ namespace Squidex.Domain.Apps.Core.Schemas
return new Schema(name, isPublished, properties, newFields); return new Schema(name, isPublished, properties, newFields);
} }
public EdmComplexType BuildEdmType(PartitionResolver partitionResolver, Func<EdmComplexType, EdmComplexType> typeResolver)
{
Guard.NotNull(typeResolver, nameof(typeResolver));
Guard.NotNull(partitionResolver, nameof(partitionResolver));
var schemaName = Name.ToPascalCase();
var edmType = new EdmComplexType("Squidex", schemaName);
foreach (var field in fieldsByName.Values.Where(x => !x.IsHidden))
{
field.AddToEdmType(edmType, partitionResolver, schemaName, typeResolver);
}
return edmType;
}
public JsonSchema4 BuildJsonSchema(PartitionResolver partitionResolver, Func<string, JsonSchema4, JsonSchema4> schemaResolver)
{
Guard.NotNull(schemaResolver, nameof(schemaResolver));
Guard.NotNull(partitionResolver, nameof(partitionResolver));
var schemaName = Name.ToPascalCase();
var schema = new JsonSchema4 { Type = JsonObjectType.Object };
foreach (var field in fieldsByName.Values.Where(x => !x.IsHidden))
{
field.AddToJsonSchema(schema, partitionResolver, schemaName, schemaResolver);
}
return schema;
}
} }
} }

26
src/Squidex.Domain.Apps.Core/Schemas/StringField.cs

@ -6,13 +6,9 @@
// All rights reserved. // All rights reserved.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Microsoft.OData.Edm;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema;
using Squidex.Domain.Apps.Core.Schemas.Validators; using Squidex.Domain.Apps.Core.Schemas.Validators;
namespace Squidex.Domain.Apps.Core.Schemas namespace Squidex.Domain.Apps.Core.Schemas
@ -57,27 +53,9 @@ namespace Squidex.Domain.Apps.Core.Schemas
return value.ToString(); return value.ToString();
} }
protected override void PrepareJsonSchema(JsonProperty jsonProperty, Func<string, JsonSchema4, JsonSchema4> schemaResolver) public override T Visit<T>(IFieldVisitor<T> visitor)
{ {
jsonProperty.Type = JsonObjectType.String; return visitor.Visit(this);
jsonProperty.MinLength = Properties.MinLength;
jsonProperty.MaxLength = Properties.MaxLength;
if (Properties.AllowedValues != null)
{
var names = jsonProperty.EnumerationNames = jsonProperty.EnumerationNames ?? new Collection<string>();
foreach (var value in Properties.AllowedValues)
{
names.Add(value);
}
}
}
protected override IEdmTypeReference CreateEdmType()
{
return EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.String, !Properties.IsRequired);
} }
} }
} }

2
src/Squidex.Domain.Apps.Read/Contents/GraphQL/GraphQLModel.cs

@ -219,7 +219,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL
{ {
var schema = schemas.GetOrDefault(schemaId); var schema = schemas.GetOrDefault(schemaId);
return schema != null ? schemaTypes.GetOrAdd(schemaId, k => new ContentGraphType(schema, this)) : null; return schema != null ? schemaTypes.Add(schemaId, k => new ContentGraphType(schema, this)) : null;
} }
} }
} }

34
src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/AssetGraphType.cs

@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
{ {
Name = "AssetDto"; Name = "AssetDto";
Add(new FieldType AddField(new FieldType
{ {
Name = "id", Name = "id",
Resolver = Resolver(x => x.Id.ToString()), Resolver = Resolver(x => x.Id.ToString()),
@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The id of the asset." Description = "The id of the asset."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "version", Name = "version",
Resolver = Resolver(x => x.Version), Resolver = Resolver(x => x.Version),
@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The version of the asset." Description = "The version of the asset."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "created", Name = "created",
Resolver = Resolver(x => x.Created.ToDateTimeUtc()), Resolver = Resolver(x => x.Created.ToDateTimeUtc()),
@ -44,7 +44,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The date and time when the asset has been created." Description = "The date and time when the asset has been created."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "createdBy", Name = "createdBy",
Resolver = Resolver(x => x.CreatedBy.ToString()), Resolver = Resolver(x => x.CreatedBy.ToString()),
@ -52,7 +52,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The user that has created the asset." Description = "The user that has created the asset."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "lastModified", Name = "lastModified",
Resolver = Resolver(x => x.LastModified.ToDateTimeUtc()), Resolver = Resolver(x => x.LastModified.ToDateTimeUtc()),
@ -60,7 +60,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The date and time when the asset has been modified last." Description = "The date and time when the asset has been modified last."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "lastModifiedBy", Name = "lastModifiedBy",
Resolver = Resolver(x => x.LastModifiedBy.ToString()), Resolver = Resolver(x => x.LastModifiedBy.ToString()),
@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The user that has updated the asset last." Description = "The user that has updated the asset last."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "mimeType", Name = "mimeType",
Resolver = Resolver(x => x.MimeType), Resolver = Resolver(x => x.MimeType),
@ -76,7 +76,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The mime type." Description = "The mime type."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "url", Name = "url",
Resolver = context.ResolveAssetUrl(), Resolver = context.ResolveAssetUrl(),
@ -84,7 +84,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The url to the asset." Description = "The url to the asset."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "thumbnailUrl", Name = "thumbnailUrl",
Resolver = context.ResolveAssetThumbnailUrl(), Resolver = context.ResolveAssetThumbnailUrl(),
@ -92,7 +92,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The thumbnail url to the asset." Description = "The thumbnail url to the asset."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "fileName", Name = "fileName",
Resolver = Resolver(x => x.FileName), Resolver = Resolver(x => x.FileName),
@ -100,7 +100,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The file name." Description = "The file name."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "fileType", Name = "fileType",
Resolver = Resolver(x => x.FileName.FileType()), Resolver = Resolver(x => x.FileName.FileType()),
@ -108,7 +108,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The file type." Description = "The file type."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "fileSize", Name = "fileSize",
Resolver = Resolver(x => x.FileSize), Resolver = Resolver(x => x.FileSize),
@ -116,7 +116,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The size of the file in bytes." Description = "The size of the file in bytes."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "fileVersion", Name = "fileVersion",
Resolver = Resolver(x => x.FileVersion), Resolver = Resolver(x => x.FileVersion),
@ -124,7 +124,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The version of the file." Description = "The version of the file."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "isImage", Name = "isImage",
Resolver = Resolver(x => x.IsImage), Resolver = Resolver(x => x.IsImage),
@ -132,7 +132,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "Determines of the created file is an image." Description = "Determines of the created file is an image."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "pixelWidth", Name = "pixelWidth",
Resolver = Resolver(x => x.PixelWidth), Resolver = Resolver(x => x.PixelWidth),
@ -140,7 +140,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The width of the image in pixels if the asset is an image." Description = "The width of the image in pixels if the asset is an image."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "pixelHeight", Name = "pixelHeight",
Resolver = Resolver(x => x.PixelHeight), Resolver = Resolver(x => x.PixelHeight),
@ -150,7 +150,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
if (context.CanGenerateAssetSourceUrl) if (context.CanGenerateAssetSourceUrl)
{ {
Add(new FieldType AddField(new FieldType
{ {
Name = "sourceUrl", Name = "sourceUrl",
Resolver = context.ResolveAssetSourceUrl(), Resolver = context.ResolveAssetSourceUrl(),

6
src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/ContentDataGraphType.cs

@ -36,11 +36,11 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Name = $"{schema.Name.ToPascalCase()}Data{field.Name.ToPascalCase()}Dto" Name = $"{schema.Name.ToPascalCase()}Data{field.Name.ToPascalCase()}Dto"
}; };
var partition = context.ResolvePartition(field.Paritioning); var partition = context.ResolvePartition(field.Partitioning);
foreach (var partitionItem in partition) foreach (var partitionItem in partition)
{ {
fieldGraphType.Add(new FieldType fieldGraphType.AddField(new FieldType
{ {
Name = partitionItem.Key, Name = partitionItem.Key,
Resolver = fieldInfo.Resolver, Resolver = fieldInfo.Resolver,
@ -53,7 +53,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
var fieldResolver = new FuncFieldResolver<NamedContentData, ContentFieldData>(c => c.Source.GetOrDefault(field.Name)); var fieldResolver = new FuncFieldResolver<NamedContentData, ContentFieldData>(c => c.Source.GetOrDefault(field.Name));
Add(new FieldType AddField(new FieldType
{ {
Name = field.Name.ToCamelCase(), Name = field.Name.ToCamelCase(),
Resolver = fieldResolver, Resolver = fieldResolver,

16
src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/ContentGraphType.cs

@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
{ {
var schemaName = schema.SchemaDef.Properties.Label.WithFallback(schema.Name); var schemaName = schema.SchemaDef.Properties.Label.WithFallback(schema.Name);
Add(new FieldType AddField(new FieldType
{ {
Name = "id", Name = "id",
Resolver = Resolver(x => x.Id.ToString()), Resolver = Resolver(x => x.Id.ToString()),
@ -40,7 +40,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = $"The id of the {schemaName} content." Description = $"The id of the {schemaName} content."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "version", Name = "version",
Resolver = Resolver(x => x.Version), Resolver = Resolver(x => x.Version),
@ -48,7 +48,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = $"The version of the {schemaName} content." Description = $"The version of the {schemaName} content."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "created", Name = "created",
Resolver = Resolver(x => x.Created.ToDateTimeUtc()), Resolver = Resolver(x => x.Created.ToDateTimeUtc()),
@ -56,7 +56,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = $"The date and time when the {schemaName} content has been created." Description = $"The date and time when the {schemaName} content has been created."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "createdBy", Name = "createdBy",
Resolver = Resolver(x => x.CreatedBy.ToString()), Resolver = Resolver(x => x.CreatedBy.ToString()),
@ -64,7 +64,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = $"The user that has created the {schemaName} content." Description = $"The user that has created the {schemaName} content."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "lastModified", Name = "lastModified",
Resolver = Resolver(x => x.LastModified.ToDateTimeUtc()), Resolver = Resolver(x => x.LastModified.ToDateTimeUtc()),
@ -72,7 +72,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = $"The date and time when the {schemaName} content has been modified last." Description = $"The date and time when the {schemaName} content has been modified last."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "lastModifiedBy", Name = "lastModifiedBy",
Resolver = Resolver(x => x.LastModifiedBy.ToString()), Resolver = Resolver(x => x.LastModifiedBy.ToString()),
@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = $"The user that has updated the {schemaName} content last." Description = $"The user that has updated the {schemaName} content last."
}); });
Add(new FieldType AddField(new FieldType
{ {
Name = "url", Name = "url",
Resolver = context.ResolveContentUrl(schema), Resolver = context.ResolveContentUrl(schema),
@ -92,7 +92,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
if (dataType.Fields.Any()) if (dataType.Fields.Any())
{ {
Add(new FieldType AddField(new FieldType
{ {
Name = "data", Name = "data",
Resolver = Resolver(x => x.Data), Resolver = Resolver(x => x.Data),

8
src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/ContentQueryGraphType.cs

@ -37,7 +37,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
private void AddAssetFind(IGraphQLContext graphQLContext) private void AddAssetFind(IGraphQLContext graphQLContext)
{ {
Add(new FieldType AddField(new FieldType
{ {
Name = "findAsset", Name = "findAsset",
Arguments = new QueryArguments Arguments = new QueryArguments
@ -63,7 +63,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
private void AddContentFind(ISchemaEntity schema, IGraphType schemaType, string schemaName) private void AddContentFind(ISchemaEntity schema, IGraphType schemaType, string schemaName)
{ {
Add(new FieldType AddField(new FieldType
{ {
Name = $"find{schema.Name.ToPascalCase()}Content", Name = $"find{schema.Name.ToPascalCase()}Content",
Arguments = new QueryArguments Arguments = new QueryArguments
@ -89,7 +89,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
private void AddAssetsQuery(IGraphQLContext graphQLContext) private void AddAssetsQuery(IGraphQLContext graphQLContext)
{ {
Add(new FieldType AddField(new FieldType
{ {
Name = "queryAssets", Name = "queryAssets",
Arguments = new QueryArguments Arguments = new QueryArguments
@ -130,7 +130,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
private void AddContentQuery(ISchemaEntity schema, IGraphType schemaType, string schemaName) private void AddContentQuery(ISchemaEntity schema, IGraphType schemaType, string schemaName)
{ {
Add(new FieldType AddField(new FieldType
{ {
Name = $"query{schema.Name.ToPascalCase()}Contents", Name = $"query{schema.Name.ToPascalCase()}Contents",
Arguments = new QueryArguments Arguments = new QueryArguments

1
src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs

@ -11,7 +11,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Read.Apps; using Squidex.Domain.Apps.Read.Apps;

4
src/Squidex.Domain.Apps.Write/Schemas/Commands/AddField.cs

@ -1,5 +1,5 @@
// ========================================================================== // ==========================================================================
// Add.cs // AddField.cs
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex Group // Copyright (c) Squidex Group
@ -13,7 +13,7 @@ using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Write.Schemas.Commands namespace Squidex.Domain.Apps.Write.Schemas.Commands
{ {
public sealed class Add : FieldCommand, IValidatable public sealed class AddField : FieldCommand, IValidatable
{ {
public string Name { get; set; } public string Name { get; set; }

2
src/Squidex.Domain.Apps.Write/Schemas/SchemaCommandMiddleware.cs

@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
}); });
} }
protected Task On(Add command, CommandContext context) protected Task On(AddField command, CommandContext context)
{ {
return handler.UpdateAsync<SchemaDomainObject>(context, s => return handler.UpdateAsync<SchemaDomainObject>(context, s =>
{ {

2
src/Squidex.Domain.Apps.Write/Schemas/SchemaDomainObject.cs

@ -144,7 +144,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
return this; return this;
} }
public SchemaDomainObject Add(Add command) public SchemaDomainObject Add(AddField command)
{ {
Guard.Valid(command, nameof(command), () => $"Cannot add field to schema {Id}"); Guard.Valid(command, nameof(command), () => $"Cannot add field to schema {Id}");

4
src/Squidex/Controllers/Api/Schemas/Models/AddFieldDto.cs

@ -1,5 +1,5 @@
// ========================================================================== // ==========================================================================
// AddDto.cs // AddFieldDto.cs
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex Group // Copyright (c) Squidex Group
@ -10,7 +10,7 @@ using System.ComponentModel.DataAnnotations;
namespace Squidex.Controllers.Api.Schemas.Models namespace Squidex.Controllers.Api.Schemas.Models
{ {
public sealed class AddDto public sealed class AddFieldDto
{ {
/// <summary> /// <summary>
/// The name of the field. Must be unique within the schema. /// The name of the field. Must be unique within the schema.

2
src/Squidex/Controllers/Api/Schemas/Models/Converters/SchemaConverter.cs

@ -84,7 +84,7 @@ namespace Squidex.Controllers.Api.Schemas.Models.Converters
{ {
FieldId = field.Id, FieldId = field.Id,
Properties = fieldPropertiesDto, Properties = fieldPropertiesDto,
Partitioning = field.Paritioning.Key Partitioning = field.Partitioning.Key
}); });
dto.Fields.Add(fieldInstanceDto); dto.Fields.Add(fieldInstanceDto);

4
src/Squidex/Controllers/Api/Schemas/SchemaFieldsController.cs

@ -48,9 +48,9 @@ namespace Squidex.Controllers.Api.Schemas
[ProducesResponseType(typeof(ErrorDto), 409)] [ProducesResponseType(typeof(ErrorDto), 409)]
[ProducesResponseType(typeof(ErrorDto), 400)] [ProducesResponseType(typeof(ErrorDto), 400)]
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> PostField(string app, string name, [FromBody] AddDto request) public async Task<IActionResult> PostField(string app, string name, [FromBody] AddFieldDto request)
{ {
var command = new Add var command = new AddField
{ {
Name = request.Name, Name = request.Name,
Partitioning = request.Partitioning, Partitioning = request.Partitioning,

1
tests/Benchmarks/Tests/HandleEventsWithManyWriters.cs

@ -9,7 +9,6 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Benchmarks.Tests.TestData; using Benchmarks.Tests.TestData;
using Benchmarks.Utils;
using MongoDB.Driver; using MongoDB.Driver;
using Newtonsoft.Json; using Newtonsoft.Json;
using Squidex.Infrastructure; using Squidex.Infrastructure;

50
tests/Squidex.Domain.Apps.Core.Tests/Schemas/SchemaTests.cs

@ -12,6 +12,7 @@ using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema; using NJsonSchema;
using Squidex.Domain.Apps.Core.Schemas.Edm;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Xunit; using Xunit;
@ -27,11 +28,6 @@ namespace Squidex.Domain.Apps.Core.Schemas
{ {
return null; return null;
} }
protected override IEnumerable<ValidationError> ValidateCore()
{
yield break;
}
} }
[Fact] [Fact]
@ -173,16 +169,6 @@ namespace Squidex.Domain.Apps.Core.Schemas
Assert.Throws<DomainException>(() => sut.UpdateField(1, new NumberFieldProperties { IsRequired = true })); Assert.Throws<DomainException>(() => sut.UpdateField(1, new NumberFieldProperties { IsRequired = true }));
} }
[Fact]
public void Should_throw_exception_if_renaming_locked_field()
{
Add();
sut = sut.LockField(1);
Assert.Throws<DomainException>(() => sut.RenameField(1, "new-name"));
}
[Fact] [Fact]
public void Should_throw_exception_if_deleting_locked_field() public void Should_throw_exception_if_deleting_locked_field()
{ {
@ -193,40 +179,6 @@ namespace Squidex.Domain.Apps.Core.Schemas
Assert.Throws<DomainException>(() => sut.DeleteField(1)); Assert.Throws<DomainException>(() => sut.DeleteField(1));
} }
[Fact]
public void Should_rename_field()
{
Add();
sut = sut.RenameField(1, "new-name");
Assert.Equal("new-name", sut.FieldsById[1].Name);
}
[Fact]
public void Should_throw_exception_if_new_field_already_exists()
{
Add();
sut = sut.Add(new NumberField(2, "other-field", Partitioning.Invariant));
Assert.Throws<ValidationException>(() => sut.RenameField(2, "my-field"));
}
[Fact]
public void Should_throw_exception_if_new_field_name_is_not_valid()
{
Add();
Assert.Throws<ValidationException>(() => sut.RenameField(1, "new name"));
}
[Fact]
public void Should_throw_exception_if_field_to_rename_does_not_exist()
{
Assert.Throws<DomainObjectNotFoundException>(() => sut.RenameField(1, "new-name"));
}
[Fact] [Fact]
public void Should_delete_field() public void Should_delete_field()
{ {

4
tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaCommandMiddlewareTests.cs

@ -154,7 +154,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
{ {
CreateSchema(); CreateSchema();
var context = CreateContextForCommand(new Add { Name = fieldName, Properties = new NumberFieldProperties() }); var context = CreateContextForCommand(new AddField { Name = fieldName, Properties = new NumberFieldProperties() });
await TestUpdate(schema, async _ => await TestUpdate(schema, async _ =>
{ {
@ -274,7 +274,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
private void CreateField() private void CreateField()
{ {
schema.Add(CreateCommand(new Add { Name = fieldName, Properties = new NumberFieldProperties() })); schema.Add(CreateCommand(new AddField { Name = fieldName, Properties = new NumberFieldProperties() }));
} }
} }
} }

16
tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaDomainObjectTests.cs

@ -244,8 +244,8 @@ namespace Squidex.Domain.Apps.Write.Schemas
CreateSchema(); CreateSchema();
sut.Add(new Add { Name = "field1", Properties = new StringFieldProperties() }); sut.Add(new AddField { Name = "field1", Properties = new StringFieldProperties() });
sut.Add(new Add { Name = "field2", Properties = new StringFieldProperties() }); sut.Add(new AddField { Name = "field2", Properties = new StringFieldProperties() });
((IAggregate)sut).ClearUncommittedEvents(); ((IAggregate)sut).ClearUncommittedEvents();
@ -371,7 +371,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
{ {
Assert.Throws<DomainException>(() => Assert.Throws<DomainException>(() =>
{ {
sut.Add(CreateCommand(new Add { Name = fieldName, Properties = new NumberFieldProperties() })); sut.Add(CreateCommand(new AddField { Name = fieldName, Properties = new NumberFieldProperties() }));
}); });
} }
@ -380,7 +380,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
{ {
Assert.Throws<ValidationException>(() => Assert.Throws<ValidationException>(() =>
{ {
sut.Add(CreateCommand(new Add())); sut.Add(CreateCommand(new AddField()));
}); });
} }
@ -389,7 +389,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
{ {
Assert.Throws<ValidationException>(() => Assert.Throws<ValidationException>(() =>
{ {
sut.Add(CreateCommand(new Add { Name = fieldName, Partitioning = "invalid", Properties = new NumberFieldProperties() })); sut.Add(CreateCommand(new AddField { Name = fieldName, Partitioning = "invalid", Properties = new NumberFieldProperties() }));
}); });
} }
@ -401,7 +401,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
Assert.Throws<DomainException>(() => Assert.Throws<DomainException>(() =>
{ {
sut.Add(CreateCommand(new Add { Name = fieldName, Properties = new NumberFieldProperties() })); sut.Add(CreateCommand(new AddField { Name = fieldName, Properties = new NumberFieldProperties() }));
}); });
} }
@ -412,7 +412,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
CreateSchema(); CreateSchema();
sut.Add(CreateCommand(new Add { Name = fieldName, Properties = properties })); sut.Add(CreateCommand(new AddField { Name = fieldName, Properties = properties }));
Assert.Equal(properties, sut.Schema.FieldsById[1].RawProperties); Assert.Equal(properties, sut.Schema.FieldsById[1].RawProperties);
@ -762,7 +762,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
private void CreateField() private void CreateField()
{ {
sut.Add(new Add { Name = fieldName, Properties = new NumberFieldProperties() }); sut.Add(new AddField { Name = fieldName, Properties = new NumberFieldProperties() });
((IAggregate)sut).ClearUncommittedEvents(); ((IAggregate)sut).ClearUncommittedEvents();
} }

1
tests/Squidex.Infrastructure.Tests/Timers/CompletionTimerTests.cs

@ -6,7 +6,6 @@
// All rights reserved. // All rights reserved.
// ========================================================================== // ==========================================================================
using System.Threading;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Xunit; using Xunit;

Loading…
Cancel
Save