mirror of https://github.com/Squidex/squidex.git
37 changed files with 444 additions and 374 deletions
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue