mirror of https://github.com/Squidex/squidex.git
24 changed files with 845 additions and 99 deletions
@ -0,0 +1,67 @@ |
|||
// ==========================================================================
|
|||
// ConstantVisitor.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
using System; |
|||
using Microsoft.OData.Edm; |
|||
using Microsoft.OData.UriParser; |
|||
using NodaTime; |
|||
using NodaTime.Text; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.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; |
|||
} |
|||
|
|||
var guidType = EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.Guid); |
|||
|
|||
if (nodeIn.TypeReference.Definition == guidType) |
|||
{ |
|||
return Guid.Parse(Visit(nodeIn.Source).ToString()); |
|||
} |
|||
|
|||
return base.Visit(nodeIn); |
|||
} |
|||
|
|||
public override object Visit(ConstantNode nodeIn) |
|||
{ |
|||
return nodeIn.Value; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
// ==========================================================================
|
|||
// 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; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,155 @@ |
|||
// ==========================================================================
|
|||
// 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); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
// ==========================================================================
|
|||
// FindExtensions.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Microsoft.OData.UriParser; |
|||
using MongoDB.Bson; |
|||
using MongoDB.Driver; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors |
|||
{ |
|||
public static class FindExtensions |
|||
{ |
|||
private static readonly FilterDefinitionBuilder<MongoAssetEntity> Filter = Builders<MongoAssetEntity>.Filter; |
|||
|
|||
public static IFindFluent<MongoAssetEntity, MongoAssetEntity> Sort(this IFindFluent<MongoAssetEntity, MongoAssetEntity> cursor, ODataUriParser query) |
|||
{ |
|||
return cursor.Sort(SortBuilder.BuildSort(query)); |
|||
} |
|||
|
|||
public static IFindFluent<MongoAssetEntity, MongoAssetEntity> Take(this IFindFluent<MongoAssetEntity, MongoAssetEntity> cursor, ODataUriParser query) |
|||
{ |
|||
var top = query.ParseTop(); |
|||
|
|||
if (top.HasValue) |
|||
{ |
|||
cursor = cursor.Limit(Math.Min((int)top.Value, 200)); |
|||
} |
|||
else |
|||
{ |
|||
cursor = cursor.Limit(20); |
|||
} |
|||
|
|||
return cursor; |
|||
} |
|||
|
|||
public static IFindFluent<MongoAssetEntity, MongoAssetEntity> Skip(this IFindFluent<MongoAssetEntity, MongoAssetEntity> cursor, ODataUriParser query) |
|||
{ |
|||
var skip = query.ParseSkip(); |
|||
|
|||
if (skip.HasValue) |
|||
{ |
|||
cursor = cursor.Skip((int)skip.Value); |
|||
} |
|||
else |
|||
{ |
|||
cursor = cursor.Skip(null); |
|||
} |
|||
|
|||
return cursor; |
|||
} |
|||
|
|||
public static IFindFluent<MongoAssetEntity, MongoAssetEntity> Find(this IMongoCollection<MongoAssetEntity> cursor, ODataUriParser query, Guid appId) |
|||
{ |
|||
var filter = BuildQuery(query, appId); |
|||
|
|||
return cursor.Find(filter); |
|||
} |
|||
|
|||
public static FilterDefinition<MongoAssetEntity> BuildQuery(ODataUriParser query, Guid appId) |
|||
{ |
|||
var filters = new List<FilterDefinition<MongoAssetEntity>> |
|||
{ |
|||
Filter.Eq(x => x.AppId, appId), |
|||
Filter.Eq(x => x.IsDeleted, false) |
|||
}; |
|||
|
|||
filters.AddRange(FilterBuilder.Build(query)); |
|||
|
|||
if (filters.Count > 1) |
|||
{ |
|||
return Filter.And(filters); |
|||
} |
|||
else if (filters.Count == 1) |
|||
{ |
|||
return filters[0]; |
|||
} |
|||
else |
|||
{ |
|||
return new BsonDocument(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
// ==========================================================================
|
|||
// PropertyVisitor.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
using System.Collections.Immutable; |
|||
using System.Linq; |
|||
using Microsoft.OData.UriParser; |
|||
using MongoDB.Driver; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors |
|||
{ |
|||
public sealed class PropertyVisitor : QueryNodeVisitor<ImmutableList<string>> |
|||
{ |
|||
private static readonly PropertyVisitor Instance = new PropertyVisitor(); |
|||
|
|||
public static StringFieldDefinition<MongoAssetEntity, object> Visit(QueryNode node) |
|||
{ |
|||
var propertyNames = node.Accept(Instance).ToArray(); |
|||
|
|||
return new StringFieldDefinition<MongoAssetEntity, object>(propertyNames.First()); |
|||
} |
|||
|
|||
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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
// ==========================================================================
|
|||
// 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; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
// ==========================================================================
|
|||
// SortBuilder.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
using System.Collections.Generic; |
|||
using Microsoft.OData.UriParser; |
|||
using MongoDB.Driver; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors |
|||
{ |
|||
public static class SortBuilder |
|||
{ |
|||
private static readonly SortDefinitionBuilder<MongoAssetEntity> Sort = Builders<MongoAssetEntity>.Sort; |
|||
|
|||
public static SortDefinition<MongoAssetEntity> BuildSort(ODataUriParser query) |
|||
{ |
|||
var orderBy = query.ParseOrderBy(); |
|||
|
|||
if (orderBy != null) |
|||
{ |
|||
var sorts = new List<SortDefinition<MongoAssetEntity>>(); |
|||
|
|||
while (orderBy != null) |
|||
{ |
|||
sorts.Add(OrderBy(orderBy)); |
|||
|
|||
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<MongoAssetEntity> OrderBy(OrderByClause clause) |
|||
{ |
|||
if (clause.Direction == OrderByDirection.Ascending) |
|||
{ |
|||
return Sort.Ascending(PropertyVisitor.Visit(clause.Expression)); |
|||
} |
|||
else |
|||
{ |
|||
return Sort.Descending(PropertyVisitor.Visit(clause.Expression)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
// ==========================================================================
|
|||
// EdmModelBuilder.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
using Microsoft.Extensions.Caching.Memory; |
|||
using Microsoft.OData.Edm; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Assets.Edm |
|||
{ |
|||
public class EdmModelBuilder : CachingProviderBase |
|||
{ |
|||
public EdmModelBuilder(IMemoryCache cache) |
|||
: base(cache) |
|||
{ |
|||
} |
|||
|
|||
public virtual IEdmModel BuildEdmModel(IAssetEntity asset) |
|||
{ |
|||
Guard.NotNull(asset, nameof(asset)); |
|||
|
|||
var cacheKey = $"Assets_EdmModel"; |
|||
|
|||
var result = Cache.GetOrCreate<IEdmModel>(cacheKey, entry => |
|||
{ |
|||
var model = new EdmModel(); |
|||
|
|||
var container = new EdmEntityContainer("Squidex", "Container"); |
|||
|
|||
var entityType = new EdmEntityType("Squidex", "Asset"); |
|||
entityType.AddStructuralProperty(nameof(asset.Id), EdmPrimitiveTypeKind.Guid); |
|||
entityType.AddStructuralProperty(nameof(asset.AppId), EdmPrimitiveTypeKind.Guid); |
|||
entityType.AddStructuralProperty(nameof(asset.Created), EdmPrimitiveTypeKind.DateTimeOffset); |
|||
entityType.AddStructuralProperty(nameof(asset.CreatedBy), EdmPrimitiveTypeKind.String); |
|||
entityType.AddStructuralProperty(nameof(asset.LastModified), EdmPrimitiveTypeKind.DateTimeOffset); |
|||
entityType.AddStructuralProperty(nameof(asset.LastModifiedBy), EdmPrimitiveTypeKind.String); |
|||
entityType.AddStructuralProperty(nameof(asset.Version), EdmPrimitiveTypeKind.Int64); |
|||
|
|||
entityType.AddStructuralProperty(nameof(asset.FileName), EdmPrimitiveTypeKind.String); |
|||
entityType.AddStructuralProperty(nameof(asset.FileSize), EdmPrimitiveTypeKind.Int64); |
|||
entityType.AddStructuralProperty(nameof(asset.FileVersion), EdmPrimitiveTypeKind.Int64); |
|||
entityType.AddStructuralProperty(nameof(asset.IsImage), EdmPrimitiveTypeKind.Boolean); |
|||
entityType.AddStructuralProperty(nameof(asset.MimeType), EdmPrimitiveTypeKind.String); |
|||
entityType.AddStructuralProperty(nameof(asset.PixelHeight), EdmPrimitiveTypeKind.Int32); |
|||
entityType.AddStructuralProperty(nameof(asset.PixelWidth), EdmPrimitiveTypeKind.Int32); |
|||
|
|||
model.AddElement(container); |
|||
model.AddElement(entityType); |
|||
|
|||
container.AddEntitySet("AssetSet", entityType); |
|||
|
|||
return model; |
|||
}); |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
// ==========================================================================
|
|||
// 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,34 @@ |
|||
// ==========================================================================
|
|||
// AddODataQueryParams.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using NJsonSchema; |
|||
using NSwag.SwaggerGeneration.Processors; |
|||
using NSwag.SwaggerGeneration.Processors.Contexts; |
|||
using Squidex.Infrastructure.Tasks; |
|||
using Squidex.Pipeline.Swagger; |
|||
|
|||
namespace Squidex.Docs |
|||
{ |
|||
public class AddODataQueryParams : IOperationProcessor |
|||
{ |
|||
public Task<bool> ProcessAsync(OperationProcessorContext context) |
|||
{ |
|||
if (context.OperationDescription.Path == "/apps/{app}/assets") |
|||
{ |
|||
context.OperationDescription.Operation.AddQueryParameter("$top", JsonObjectType.Number, "Optional number of contents to take."); |
|||
context.OperationDescription.Operation.AddQueryParameter("$skip", JsonObjectType.Number, "Optional number of contents to skip."); |
|||
context.OperationDescription.Operation.AddQueryParameter("$search", JsonObjectType.String, "Optional OData full text search."); |
|||
context.OperationDescription.Operation.AddQueryParameter("$orderby", JsonObjectType.String, "Optional OData order definition."); |
|||
context.OperationDescription.Operation.AddQueryParameter("$filter", JsonObjectType.String, "Optional OData filter definition."); |
|||
} |
|||
|
|||
return TaskHelper.True; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Infrastructure.Migrations; |
|||
|
|||
namespace Migrate_01 |
|||
{ |
|||
public class Migration04_FlattenAssetEntity : IMigration |
|||
{ |
|||
private readonly Rebuilder rebuilder; |
|||
|
|||
public int FromVersion { get; } = 3; |
|||
|
|||
public int ToVersion { get; } = 4; |
|||
|
|||
public Migration04_FlattenAssetEntity(Rebuilder rebuilder) |
|||
{ |
|||
this.rebuilder = rebuilder; |
|||
} |
|||
|
|||
public async Task UpdateAsync(IEnumerable<IMigration> previousMigrations) |
|||
{ |
|||
if (!previousMigrations.Any(x => x is Migration01_FromCqrs)) |
|||
{ |
|||
await rebuilder.RebuildAssetsAsync(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue