mirror of https://github.com/Squidex/squidex.git
29 changed files with 424 additions and 742 deletions
@ -0,0 +1,47 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Microsoft.OData.Edm; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors |
||||
|
{ |
||||
|
public static class AssetModel |
||||
|
{ |
||||
|
public static readonly IEdmModel Edm; |
||||
|
|
||||
|
static AssetModel() |
||||
|
{ |
||||
|
var entityType = new EdmEntityType("Squidex", "Asset"); |
||||
|
|
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.Id), EdmPrimitiveTypeKind.Guid); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.AppId), EdmPrimitiveTypeKind.Guid); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.Created), EdmPrimitiveTypeKind.DateTimeOffset); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.CreatedBy), EdmPrimitiveTypeKind.String); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.LastModified), EdmPrimitiveTypeKind.DateTimeOffset); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.LastModifiedBy), EdmPrimitiveTypeKind.String); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.Version), EdmPrimitiveTypeKind.Int64); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.FileName), EdmPrimitiveTypeKind.String); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.FileSize), EdmPrimitiveTypeKind.Int64); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.FileVersion), EdmPrimitiveTypeKind.Int64); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.IsImage), EdmPrimitiveTypeKind.Boolean); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.MimeType), EdmPrimitiveTypeKind.String); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.PixelHeight), EdmPrimitiveTypeKind.Int32); |
||||
|
entityType.AddStructuralProperty(nameof(MongoAssetEntity.PixelWidth), EdmPrimitiveTypeKind.Int32); |
||||
|
|
||||
|
var container = new EdmEntityContainer("Squidex", "Container"); |
||||
|
|
||||
|
container.AddEntitySet("AssetSet", entityType); |
||||
|
|
||||
|
var model = new EdmModel(); |
||||
|
|
||||
|
model.AddElement(container); |
||||
|
model.AddElement(entityType); |
||||
|
|
||||
|
Edm = model; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,57 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// FilterBuilder.cs
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
using System.Collections.Generic; |
|
||||
using Microsoft.OData; |
|
||||
using Microsoft.OData.UriParser; |
|
||||
using MongoDB.Driver; |
|
||||
using Squidex.Infrastructure; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors |
|
||||
{ |
|
||||
public static class FilterBuilder |
|
||||
{ |
|
||||
private static readonly FilterDefinitionBuilder<MongoAssetEntity> Filter = Builders<MongoAssetEntity>.Filter; |
|
||||
|
|
||||
public static List<FilterDefinition<MongoAssetEntity>> Build(ODataUriParser query) |
|
||||
{ |
|
||||
List<FilterDefinition<MongoAssetEntity>> filters = new List<FilterDefinition<MongoAssetEntity>>(); |
|
||||
|
|
||||
SearchClause search; |
|
||||
try |
|
||||
{ |
|
||||
search = query.ParseSearch(); |
|
||||
} |
|
||||
catch (ODataException ex) |
|
||||
{ |
|
||||
throw new ValidationException("Query $search clause not valid.", new ValidationError(ex.Message)); |
|
||||
} |
|
||||
|
|
||||
if (search != null) |
|
||||
{ |
|
||||
filters.Add(Filter.Text(SearchTermVisitor.Visit(search.Expression).ToString())); |
|
||||
} |
|
||||
|
|
||||
FilterClause filter; |
|
||||
try |
|
||||
{ |
|
||||
filter = query.ParseFilter(); |
|
||||
} |
|
||||
catch (ODataException ex) |
|
||||
{ |
|
||||
throw new ValidationException("Query $filter clause not valid.", new ValidationError(ex.Message)); |
|
||||
} |
|
||||
|
|
||||
if (filter != null) |
|
||||
{ |
|
||||
filters.Add(FilterVisitor.Visit(filter.Expression)); |
|
||||
} |
|
||||
|
|
||||
return filters; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,155 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// FilterVisitor.cs
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
using System; |
|
||||
using System.Linq; |
|
||||
using Microsoft.OData.UriParser; |
|
||||
using MongoDB.Bson; |
|
||||
using MongoDB.Driver; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors |
|
||||
{ |
|
||||
public class FilterVisitor : QueryNodeVisitor<FilterDefinition<MongoAssetEntity>> |
|
||||
{ |
|
||||
private static readonly FilterDefinitionBuilder<MongoAssetEntity> Filter = Builders<MongoAssetEntity>.Filter; |
|
||||
|
|
||||
public static FilterDefinition<MongoAssetEntity> Visit(QueryNode node) |
|
||||
{ |
|
||||
var visitor = new FilterVisitor(); |
|
||||
|
|
||||
return node.Accept(visitor); |
|
||||
} |
|
||||
|
|
||||
public override FilterDefinition<MongoAssetEntity> Visit(ConvertNode nodeIn) |
|
||||
{ |
|
||||
return nodeIn.Source.Accept(this); |
|
||||
} |
|
||||
|
|
||||
public override FilterDefinition<MongoAssetEntity> Visit(UnaryOperatorNode nodeIn) |
|
||||
{ |
|
||||
if (nodeIn.OperatorKind == UnaryOperatorKind.Not) |
|
||||
{ |
|
||||
return Filter.Not(nodeIn.Operand.Accept(this)); |
|
||||
} |
|
||||
|
|
||||
throw new NotSupportedException(); |
|
||||
} |
|
||||
|
|
||||
public override FilterDefinition<MongoAssetEntity> Visit(SingleValueFunctionCallNode nodeIn) |
|
||||
{ |
|
||||
var fieldNode = nodeIn.Parameters.ElementAt(0); |
|
||||
var valueNode = nodeIn.Parameters.ElementAt(1); |
|
||||
|
|
||||
if (string.Equals(nodeIn.Name, "endswith", StringComparison.OrdinalIgnoreCase)) |
|
||||
{ |
|
||||
var value = BuildRegex(valueNode, v => v + "$"); |
|
||||
|
|
||||
return Filter.Regex(BuildFieldDefinition(fieldNode), value); |
|
||||
} |
|
||||
|
|
||||
if (string.Equals(nodeIn.Name, "startswith", StringComparison.OrdinalIgnoreCase)) |
|
||||
{ |
|
||||
var value = BuildRegex(valueNode, v => "^" + v); |
|
||||
|
|
||||
return Filter.Regex(BuildFieldDefinition(fieldNode), value); |
|
||||
} |
|
||||
|
|
||||
if (string.Equals(nodeIn.Name, "contains", StringComparison.OrdinalIgnoreCase)) |
|
||||
{ |
|
||||
var value = BuildRegex(valueNode, v => v); |
|
||||
|
|
||||
return Filter.Regex(BuildFieldDefinition(fieldNode), value); |
|
||||
} |
|
||||
|
|
||||
throw new NotSupportedException(); |
|
||||
} |
|
||||
|
|
||||
public override FilterDefinition<MongoAssetEntity> Visit(BinaryOperatorNode nodeIn) |
|
||||
{ |
|
||||
if (nodeIn.OperatorKind == BinaryOperatorKind.And) |
|
||||
{ |
|
||||
return Filter.And(nodeIn.Left.Accept(this), nodeIn.Right.Accept(this)); |
|
||||
} |
|
||||
|
|
||||
if (nodeIn.OperatorKind == BinaryOperatorKind.Or) |
|
||||
{ |
|
||||
return Filter.Or(nodeIn.Left.Accept(this), nodeIn.Right.Accept(this)); |
|
||||
} |
|
||||
|
|
||||
if (nodeIn.Left is SingleValueFunctionCallNode functionNode) |
|
||||
{ |
|
||||
var regexFilter = Visit(functionNode); |
|
||||
|
|
||||
var value = BuildValue(nodeIn.Right); |
|
||||
|
|
||||
if (value is bool booleanRight) |
|
||||
{ |
|
||||
if ((nodeIn.OperatorKind == BinaryOperatorKind.Equal && !booleanRight) || |
|
||||
(nodeIn.OperatorKind == BinaryOperatorKind.NotEqual && booleanRight)) |
|
||||
{ |
|
||||
regexFilter = Filter.Not(regexFilter); |
|
||||
} |
|
||||
|
|
||||
return regexFilter; |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
if (nodeIn.OperatorKind == BinaryOperatorKind.NotEqual) |
|
||||
{ |
|
||||
var field = BuildFieldDefinition(nodeIn.Left); |
|
||||
|
|
||||
return Filter.Or( |
|
||||
Filter.Not(Filter.Exists(field)), |
|
||||
Filter.Ne(field, BuildValue(nodeIn.Right))); |
|
||||
} |
|
||||
|
|
||||
if (nodeIn.OperatorKind == BinaryOperatorKind.Equal) |
|
||||
{ |
|
||||
return Filter.Eq(BuildFieldDefinition(nodeIn.Left), BuildValue(nodeIn.Right)); |
|
||||
} |
|
||||
|
|
||||
if (nodeIn.OperatorKind == BinaryOperatorKind.LessThan) |
|
||||
{ |
|
||||
return Filter.Lt(BuildFieldDefinition(nodeIn.Left), BuildValue(nodeIn.Right)); |
|
||||
} |
|
||||
|
|
||||
if (nodeIn.OperatorKind == BinaryOperatorKind.LessThanOrEqual) |
|
||||
{ |
|
||||
return Filter.Lte(BuildFieldDefinition(nodeIn.Left), BuildValue(nodeIn.Right)); |
|
||||
} |
|
||||
|
|
||||
if (nodeIn.OperatorKind == BinaryOperatorKind.GreaterThan) |
|
||||
{ |
|
||||
return Filter.Gt(BuildFieldDefinition(nodeIn.Left), BuildValue(nodeIn.Right)); |
|
||||
} |
|
||||
|
|
||||
if (nodeIn.OperatorKind == BinaryOperatorKind.GreaterThanOrEqual) |
|
||||
{ |
|
||||
return Filter.Gte(BuildFieldDefinition(nodeIn.Left), BuildValue(nodeIn.Right)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
throw new NotSupportedException(); |
|
||||
} |
|
||||
|
|
||||
private static BsonRegularExpression BuildRegex(QueryNode node, Func<string, string> formatter) |
|
||||
{ |
|
||||
return new BsonRegularExpression(formatter(BuildValue(node).ToString()), "i"); |
|
||||
} |
|
||||
|
|
||||
private FieldDefinition<MongoAssetEntity, object> BuildFieldDefinition(QueryNode nodeIn) |
|
||||
{ |
|
||||
return PropertyVisitor.Visit(nodeIn); |
|
||||
} |
|
||||
|
|
||||
private static object BuildValue(QueryNode nodeIn) |
|
||||
{ |
|
||||
return ConstantVisitor.Visit(nodeIn); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,41 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// SearchTermVisitor.cs
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
using System; |
|
||||
using Microsoft.OData.UriParser; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors |
|
||||
{ |
|
||||
public class SearchTermVisitor : QueryNodeVisitor<string> |
|
||||
{ |
|
||||
private static readonly SearchTermVisitor Instance = new SearchTermVisitor(); |
|
||||
|
|
||||
private SearchTermVisitor() |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public static object Visit(QueryNode node) |
|
||||
{ |
|
||||
return node.Accept(Instance); |
|
||||
} |
|
||||
|
|
||||
public override string Visit(BinaryOperatorNode nodeIn) |
|
||||
{ |
|
||||
if (nodeIn.OperatorKind == BinaryOperatorKind.And) |
|
||||
{ |
|
||||
return nodeIn.Left.Accept(this) + " " + nodeIn.Right.Accept(this); |
|
||||
} |
|
||||
|
|
||||
throw new NotSupportedException(); |
|
||||
} |
|
||||
|
|
||||
public override string Visit(SearchTermNode nodeIn) |
|
||||
{ |
|
||||
return nodeIn.Text; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,60 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using Microsoft.OData.Edm; |
|
||||
using Microsoft.OData.UriParser; |
|
||||
using NodaTime; |
|
||||
using NodaTime.Text; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Visitors |
|
||||
{ |
|
||||
public sealed class ConstantVisitor : QueryNodeVisitor<object> |
|
||||
{ |
|
||||
private static readonly ConstantVisitor Instance = new ConstantVisitor(); |
|
||||
|
|
||||
private ConstantVisitor() |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public static object Visit(QueryNode node) |
|
||||
{ |
|
||||
return node.Accept(Instance); |
|
||||
} |
|
||||
|
|
||||
public override object Visit(ConvertNode nodeIn) |
|
||||
{ |
|
||||
var booleanType = EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.Boolean); |
|
||||
|
|
||||
if (nodeIn.TypeReference.Definition == booleanType) |
|
||||
{ |
|
||||
return bool.Parse(Visit(nodeIn.Source).ToString()); |
|
||||
} |
|
||||
|
|
||||
var dateTimeType = EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.DateTimeOffset); |
|
||||
|
|
||||
if (nodeIn.TypeReference.Definition == dateTimeType) |
|
||||
{ |
|
||||
var value = Visit(nodeIn.Source); |
|
||||
|
|
||||
if (value is DateTimeOffset dateTimeOffset) |
|
||||
{ |
|
||||
return Instant.FromDateTimeOffset(dateTimeOffset); |
|
||||
} |
|
||||
|
|
||||
return InstantPattern.General.Parse(Visit(nodeIn.Source).ToString()).Value; |
|
||||
} |
|
||||
|
|
||||
return base.Visit(nodeIn); |
|
||||
} |
|
||||
|
|
||||
public override object Visit(ConstantNode nodeIn) |
|
||||
{ |
|
||||
return nodeIn.Value; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,72 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Immutable; |
|
||||
using System.Linq; |
|
||||
using Microsoft.OData.UriParser; |
|
||||
using MongoDB.Driver; |
|
||||
using Squidex.Domain.Apps.Core.GenerateEdmSchema; |
|
||||
using Squidex.Domain.Apps.Core.Schemas; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Visitors |
|
||||
{ |
|
||||
public sealed class PropertyVisitor : QueryNodeVisitor<ImmutableList<string>> |
|
||||
{ |
|
||||
private static readonly PropertyVisitor Instance = new PropertyVisitor(); |
|
||||
|
|
||||
public static StringFieldDefinition<MongoContentEntity, object> Visit(QueryNode node, Schema schema) |
|
||||
{ |
|
||||
var propertyNames = node.Accept(Instance).ToArray(); |
|
||||
|
|
||||
if (propertyNames.Length == 3) |
|
||||
{ |
|
||||
var edmName = propertyNames[1].UnescapeEdmField(); |
|
||||
|
|
||||
if (!schema.FieldsByName.TryGetValue(edmName, out var field)) |
|
||||
{ |
|
||||
throw new NotSupportedException(); |
|
||||
} |
|
||||
|
|
||||
propertyNames[1] = field.Id.ToString(); |
|
||||
} |
|
||||
|
|
||||
var propertyName = $"do.{string.Join(".", propertyNames.Skip(1))}"; |
|
||||
|
|
||||
return new StringFieldDefinition<MongoContentEntity, object>(propertyName); |
|
||||
} |
|
||||
|
|
||||
public override ImmutableList<string> Visit(ConvertNode nodeIn) |
|
||||
{ |
|
||||
return nodeIn.Source.Accept(this); |
|
||||
} |
|
||||
|
|
||||
public override ImmutableList<string> Visit(SingleComplexNode nodeIn) |
|
||||
{ |
|
||||
if (nodeIn.Source is SingleComplexNode) |
|
||||
{ |
|
||||
return nodeIn.Source.Accept(this).Add(nodeIn.Property.Name); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
return ImmutableList.Create(nodeIn.Property.Name); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public override ImmutableList<string> Visit(SingleValuePropertyAccessNode nodeIn) |
|
||||
{ |
|
||||
if (nodeIn.Source is SingleComplexNode) |
|
||||
{ |
|
||||
return nodeIn.Source.Accept(this).Add(nodeIn.Property.Name); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
return ImmutableList.Create(nodeIn.Property.Name); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,61 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.Collections.Generic; |
|
||||
using Microsoft.OData.UriParser; |
|
||||
using MongoDB.Driver; |
|
||||
using Squidex.Domain.Apps.Core.Schemas; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Visitors |
|
||||
{ |
|
||||
public static class SortBuilder |
|
||||
{ |
|
||||
private static readonly SortDefinitionBuilder<MongoContentEntity> Sort = Builders<MongoContentEntity>.Sort; |
|
||||
|
|
||||
public static SortDefinition<MongoContentEntity> BuildSort(ODataUriParser query, Schema schema) |
|
||||
{ |
|
||||
var orderBy = query.ParseOrderBy(); |
|
||||
|
|
||||
if (orderBy != null) |
|
||||
{ |
|
||||
var sorts = new List<SortDefinition<MongoContentEntity>>(); |
|
||||
|
|
||||
while (orderBy != null) |
|
||||
{ |
|
||||
sorts.Add(OrderBy(orderBy, schema)); |
|
||||
|
|
||||
orderBy = orderBy.ThenBy; |
|
||||
} |
|
||||
|
|
||||
if (sorts.Count > 1) |
|
||||
{ |
|
||||
return Sort.Combine(sorts); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
return sorts[0]; |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
return Sort.Descending(x => x.LastModified); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static SortDefinition<MongoContentEntity> OrderBy(OrderByClause clause, Schema schema) |
|
||||
{ |
|
||||
if (clause.Direction == OrderByDirection.Ascending) |
|
||||
{ |
|
||||
return Sort.Ascending(PropertyVisitor.Visit(clause.Expression, schema)); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
return Sort.Descending(PropertyVisitor.Visit(clause.Expression, schema)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,47 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Microsoft.OData.Edm; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Assets.Edm |
||||
|
{ |
||||
|
public static class EdmAssetModel |
||||
|
{ |
||||
|
public static readonly IEdmModel Edm; |
||||
|
|
||||
|
static EdmAssetModel() |
||||
|
{ |
||||
|
var entityType = new EdmEntityType("Squidex", "Asset"); |
||||
|
|
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.Id), EdmPrimitiveTypeKind.Guid); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.AppId), EdmPrimitiveTypeKind.Guid); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.Created), EdmPrimitiveTypeKind.DateTimeOffset); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.CreatedBy), EdmPrimitiveTypeKind.String); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.LastModified), EdmPrimitiveTypeKind.DateTimeOffset); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.LastModifiedBy), EdmPrimitiveTypeKind.String); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.Version), EdmPrimitiveTypeKind.Int64); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.FileName), EdmPrimitiveTypeKind.String); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.FileSize), EdmPrimitiveTypeKind.Int64); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.FileVersion), EdmPrimitiveTypeKind.Int64); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.IsImage), EdmPrimitiveTypeKind.Boolean); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.MimeType), EdmPrimitiveTypeKind.String); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.PixelHeight), EdmPrimitiveTypeKind.Int32); |
||||
|
entityType.AddStructuralProperty(nameof(IAssetEntity.PixelWidth), EdmPrimitiveTypeKind.Int32); |
||||
|
|
||||
|
var container = new EdmEntityContainer("Squidex", "Container"); |
||||
|
|
||||
|
container.AddEntitySet("AssetSet", entityType); |
||||
|
|
||||
|
var model = new EdmModel(); |
||||
|
|
||||
|
model.AddElement(container); |
||||
|
model.AddElement(entityType); |
||||
|
|
||||
|
Edm = model; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using Microsoft.OData; |
||||
|
using Microsoft.OData.Edm; |
||||
|
using Microsoft.OData.UriParser; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Assets.Edm |
||||
|
{ |
||||
|
public static class EdmAssetQuery |
||||
|
{ |
||||
|
public static ODataUriParser ParseQuery(string query) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var model = EdmAssetModel.Edm; |
||||
|
|
||||
|
if (!model.EntityContainer.EntitySets().Any()) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
query = query ?? string.Empty; |
||||
|
|
||||
|
var path = model.EntityContainer.EntitySets().First().Path.Path.Split('.').Last(); |
||||
|
|
||||
|
if (query.StartsWith("?", StringComparison.Ordinal)) |
||||
|
{ |
||||
|
query = query.Substring(1); |
||||
|
} |
||||
|
|
||||
|
var parser = new ODataUriParser(model, new Uri($"{path}?{query}", UriKind.Relative)); |
||||
|
|
||||
|
return parser; |
||||
|
} |
||||
|
catch (ODataException ex) |
||||
|
{ |
||||
|
throw new ValidationException($"Failed to parse query: {ex.Message}", ex); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,55 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// EdmModelBuilder.cs
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
using Microsoft.OData.Edm; |
|
||||
using Squidex.Domain.Apps.Entities.Assets.State; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.Assets.Edm |
|
||||
{ |
|
||||
public class EdmModelBuilder |
|
||||
{ |
|
||||
private readonly IEdmModel edmModel; |
|
||||
public EdmModelBuilder() |
|
||||
{ |
|
||||
edmModel = BuildEdmModel(); |
|
||||
} |
|
||||
|
|
||||
public virtual IEdmModel EdmModel |
|
||||
{ |
|
||||
get { return edmModel; } |
|
||||
} |
|
||||
|
|
||||
private IEdmModel BuildEdmModel() |
|
||||
{ |
|
||||
var model = new EdmModel(); |
|
||||
var container = new EdmEntityContainer("Squidex", "Container"); |
|
||||
var entityType = new EdmEntityType("Squidex", "Asset"); |
|
||||
|
|
||||
entityType.AddStructuralProperty(nameof(AssetState.Id), EdmPrimitiveTypeKind.Guid); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.AppId), EdmPrimitiveTypeKind.Guid); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.Created), EdmPrimitiveTypeKind.DateTimeOffset); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.CreatedBy), EdmPrimitiveTypeKind.String); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.LastModified), EdmPrimitiveTypeKind.DateTimeOffset); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.LastModifiedBy), EdmPrimitiveTypeKind.String); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.Version), EdmPrimitiveTypeKind.Int64); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.FileName), EdmPrimitiveTypeKind.String); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.FileSize), EdmPrimitiveTypeKind.Int64); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.FileVersion), EdmPrimitiveTypeKind.Int64); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.IsImage), EdmPrimitiveTypeKind.Boolean); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.MimeType), EdmPrimitiveTypeKind.String); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.PixelHeight), EdmPrimitiveTypeKind.Int32); |
|
||||
entityType.AddStructuralProperty(nameof(AssetState.PixelWidth), EdmPrimitiveTypeKind.Int32); |
|
||||
|
|
||||
model.AddElement(container); |
|
||||
model.AddElement(entityType); |
|
||||
|
|
||||
container.AddEntitySet("AssetSet", entityType); |
|
||||
|
|
||||
return model; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,38 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// EdmModelExtensions.cs
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
using System; |
|
||||
using System.Linq; |
|
||||
using Microsoft.OData.Edm; |
|
||||
using Microsoft.OData.UriParser; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.Assets.Edm |
|
||||
{ |
|
||||
public static class EdmModelExtensions |
|
||||
{ |
|
||||
public static ODataUriParser ParseQuery(this IEdmModel model, string query) |
|
||||
{ |
|
||||
if (!model.EntityContainer.EntitySets().Any()) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
query = query ?? string.Empty; |
|
||||
|
|
||||
var path = model.EntityContainer.EntitySets().First().Path.Path.Split('.').Last(); |
|
||||
|
|
||||
if (query.StartsWith("?", StringComparison.Ordinal)) |
|
||||
{ |
|
||||
query = query.Substring(1); |
|
||||
} |
|
||||
|
|
||||
var parser = new ODataUriParser(model, new Uri($"{path}?{query}", UriKind.Relative)); |
|
||||
|
|
||||
return parser; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,48 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Microsoft.OData.UriParser; |
||||
|
using MongoDB.Driver; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.MongoDb.OData |
||||
|
{ |
||||
|
public static class LimitExtensions |
||||
|
{ |
||||
|
public static IFindFluent<T, T> Take<T>(this IFindFluent<T, T> cursor, ODataUriParser query, int maxValue = 200, int defaultValue = 20) |
||||
|
{ |
||||
|
var top = query.ParseTop(); |
||||
|
|
||||
|
if (top.HasValue) |
||||
|
{ |
||||
|
cursor = cursor.Limit(Math.Min((int)top.Value, maxValue)); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
cursor = cursor.Limit(defaultValue); |
||||
|
} |
||||
|
|
||||
|
return cursor; |
||||
|
} |
||||
|
|
||||
|
public static IFindFluent<T, T> Skip<T>(this IFindFluent<T, T> cursor, ODataUriParser query) |
||||
|
{ |
||||
|
var skip = query.ParseSkip(); |
||||
|
|
||||
|
if (skip.HasValue) |
||||
|
{ |
||||
|
cursor = cursor.Skip((int)skip.Value); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
cursor = cursor.Skip(null); |
||||
|
} |
||||
|
|
||||
|
return cursor; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Linq; |
||||
|
using Microsoft.OData.UriParser; |
||||
|
using MongoDB.Driver; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.MongoDb.OData |
||||
|
{ |
||||
|
public delegate string PropertyCalculator(string[] parts); |
||||
|
|
||||
|
public static class PropertyBuilder |
||||
|
{ |
||||
|
private static readonly PropertyCalculator DefaultCalculator = parts => |
||||
|
{ |
||||
|
return string.Join(".", parts); |
||||
|
}; |
||||
|
|
||||
|
public static StringFieldDefinition<T, object> BuildFieldDefinition<T>(this QueryNode node, PropertyCalculator propertyCalculator) |
||||
|
{ |
||||
|
propertyCalculator = propertyCalculator ?? DefaultCalculator; |
||||
|
|
||||
|
var propertyParts = node.Accept(PropertyNameVisitor.Instance).ToArray(); |
||||
|
var propertyName = propertyCalculator(propertyParts); |
||||
|
|
||||
|
return new StringFieldDefinition<T, object>(propertyName); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,26 +1,23 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// PropertyVisitor.cs
|
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex Group
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
// All rights reserved.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
using System.Collections.Immutable; |
using System.Collections.Immutable; |
||||
using System.Linq; |
|
||||
using Microsoft.OData.UriParser; |
using Microsoft.OData.UriParser; |
||||
using MongoDB.Driver; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors |
#pragma warning disable RECS0108 // Warns about static fields in generic types
|
||||
|
|
||||
|
namespace Squidex.Infrastructure.MongoDb.OData |
||||
{ |
{ |
||||
public sealed class PropertyVisitor : QueryNodeVisitor<ImmutableList<string>> |
public sealed class PropertyNameVisitor : QueryNodeVisitor<ImmutableList<string>> |
||||
{ |
{ |
||||
private static readonly PropertyVisitor Instance = new PropertyVisitor(); |
public static readonly PropertyNameVisitor Instance = new PropertyNameVisitor(); |
||||
|
|
||||
public static StringFieldDefinition<MongoAssetEntity, object> Visit(QueryNode node) |
private PropertyNameVisitor() |
||||
{ |
{ |
||||
var propertyNames = node.Accept(Instance).ToArray(); |
|
||||
|
|
||||
return new StringFieldDefinition<MongoAssetEntity, object>(propertyNames.First()); |
|
||||
} |
} |
||||
|
|
||||
public override ImmutableList<string> Visit(ConvertNode nodeIn) |
public override ImmutableList<string> Visit(ConvertNode nodeIn) |
||||
@ -1,59 +1,57 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// SortBuilder.cs
|
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex Group
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
using Microsoft.OData.UriParser; |
using Microsoft.OData.UriParser; |
||||
using MongoDB.Driver; |
using MongoDB.Driver; |
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors |
namespace Squidex.Infrastructure.MongoDb.OData |
||||
{ |
{ |
||||
public static class SortBuilder |
public static class SortBuilder |
||||
{ |
{ |
||||
private static readonly SortDefinitionBuilder<MongoAssetEntity> Sort = Builders<MongoAssetEntity>.Sort; |
public static SortDefinition<T> BuildSort<T>(this ODataUriParser query, PropertyCalculator propertyCalculator = null) |
||||
|
|
||||
public static SortDefinition<MongoAssetEntity> BuildSort(ODataUriParser query) |
|
||||
{ |
{ |
||||
var orderBy = query.ParseOrderBy(); |
var orderBy = query.ParseOrderBy(); |
||||
|
|
||||
if (orderBy != null) |
if (orderBy != null) |
||||
{ |
{ |
||||
var sorts = new List<SortDefinition<MongoAssetEntity>>(); |
var sorts = new List<SortDefinition<T>>(); |
||||
|
|
||||
while (orderBy != null) |
while (orderBy != null) |
||||
{ |
{ |
||||
sorts.Add(OrderBy(orderBy)); |
sorts.Add(OrderBy<T>(orderBy, propertyCalculator)); |
||||
|
|
||||
orderBy = orderBy.ThenBy; |
orderBy = orderBy.ThenBy; |
||||
} |
} |
||||
|
|
||||
if (sorts.Count > 1) |
if (sorts.Count > 1) |
||||
{ |
{ |
||||
return Sort.Combine(sorts); |
return Builders<T>.Sort.Combine(sorts); |
||||
} |
} |
||||
else |
else |
||||
{ |
{ |
||||
return sorts[0]; |
return sorts[0]; |
||||
} |
} |
||||
} |
} |
||||
else |
|
||||
{ |
return null; |
||||
return Sort.Descending(x => x.LastModified); |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
public static SortDefinition<MongoAssetEntity> OrderBy(OrderByClause clause) |
public static SortDefinition<T> OrderBy<T>(OrderByClause clause, PropertyCalculator propertyCalculator = null) |
||||
{ |
{ |
||||
|
var propertyName = clause.Expression.BuildFieldDefinition<T>(propertyCalculator); |
||||
|
|
||||
if (clause.Direction == OrderByDirection.Ascending) |
if (clause.Direction == OrderByDirection.Ascending) |
||||
{ |
{ |
||||
return Sort.Ascending(PropertyVisitor.Visit(clause.Expression)); |
return Builders<T>.Sort.Ascending(propertyName); |
||||
} |
} |
||||
else |
else |
||||
{ |
{ |
||||
return Sort.Descending(PropertyVisitor.Visit(clause.Expression)); |
return Builders<T>.Sort.Descending(propertyName); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
Loading…
Reference in new issue