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