Browse Source

A lot more tests

pull/1/head
Sebastian 10 years ago
parent
commit
fd178e8e37
  1. 1
      Squidex.sln.DotSettings
  2. 1
      src/Squidex.Core/Schemas/FieldRegistry.cs
  3. 101
      src/Squidex.Core/Schemas/Json/SchemaJsonSerializer.cs
  4. 2
      src/Squidex.Core/Schemas/NumberFieldProperties.cs
  5. 6
      src/Squidex.Core/Schemas/StringField.cs
  6. 14
      src/Squidex.Core/Schemas/StringFieldProperties.cs
  7. 2
      src/Squidex.Core/Schemas/Validators/PatternValidator.cs
  8. 14
      src/Squidex.Infrastructure/TypeNameRegistry.cs
  9. 51
      src/Squidex.Store.MongoDb/Schemas/Models/FieldModel.cs
  10. 60
      src/Squidex.Store.MongoDb/Schemas/Models/SchemaModel.cs
  11. 18
      src/Squidex.Store.MongoDb/Schemas/MongoSchemaEntity.cs
  12. 24
      src/Squidex.Store.MongoDb/Schemas/MongoSchemaRepository.cs
  13. 10
      src/Squidex.Store.MongoDb/Utils/EntityMapper.cs
  14. 5
      src/Squidex/Config/Domain/InfrastructureModule.cs
  15. 68
      src/Squidex/Controllers/Api/Schemas/Models/Converters/SchemaConverter.cs
  16. 8
      src/Squidex/Controllers/Api/Schemas/Models/FieldDto.cs
  17. 8
      src/Squidex/Controllers/Api/Schemas/Models/Fields/NumberField.cs
  18. 15
      src/Squidex/Controllers/Api/Schemas/Models/Fields/StringField.cs
  19. 12
      src/Squidex/Controllers/Api/Schemas/SchemaFieldsController.cs
  20. 5
      src/Squidex/Controllers/Api/Schemas/SchemasController.cs
  21. 5
      tests/Squidex.Core.Tests/Schemas/FieldRegistryTests.cs
  22. 52
      tests/Squidex.Core.Tests/Schemas/Json/JsonSerializerTests.cs
  23. 1
      tests/Squidex.Core.Tests/Schemas/StringFieldPropertiesTests.cs
  24. 20
      tests/Squidex.Core.Tests/Schemas/StringFieldTests.cs
  25. 8
      tests/Squidex.Core.Tests/Schemas/Validators/PatternValidatorTests.cs
  26. 17
      tests/Squidex.Infrastructure.Tests/TypeNameRegistryTests.cs

1
Squidex.sln.DotSettings

@ -39,6 +39,7 @@
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Namespaces/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Namespaces"&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSUpdateFileHeader&gt;True&lt;/CSUpdateFileHeader&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Typescript/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Typescript"&gt;&lt;JsInsertSemicolon&gt;True&lt;/JsInsertSemicolon&gt;&lt;FormatAttributeQuoteDescriptor&gt;True&lt;/FormatAttributeQuoteDescriptor&gt;&lt;CorrectVariableKindsDescriptor&gt;True&lt;/CorrectVariableKindsDescriptor&gt;&lt;VariablesToInnerScopesDescriptor&gt;True&lt;/VariablesToInnerScopesDescriptor&gt;&lt;StringToTemplatesDescriptor&gt;True&lt;/StringToTemplatesDescriptor&gt;&lt;RemoveRedundantQualifiersTs&gt;True&lt;/RemoveRedundantQualifiersTs&gt;&lt;OptimizeImportsTs&gt;True&lt;/OptimizeImportsTs&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/SilentCleanupProfile/@EntryValue"></s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/QUOTE_STYLE/@EntryValue">SingleQuoted</s:String>
<s:String x:Key="/Default/CodeStyle/FileHeader/FileHeaderText/@EntryValue">==========================================================================&#xD;
$FILENAME$&#xD;

1
src/Squidex.Core/Schemas/FieldRegistry.cs

@ -52,6 +52,7 @@ namespace Squidex.Core.Schemas
public FieldRegistry()
{
Add<NumberFieldProperties>((id, name, properties) => new NumberField(id, name, (NumberFieldProperties)properties));
Add<StringFieldProperties>((id, name, properties) => new StringField(id, name, (StringFieldProperties)properties));
}
public void Add<TFieldProperties>(FactoryFunction fieldFactory)

101
src/Squidex.Core/Schemas/Json/SchemaJsonSerializer.cs

@ -0,0 +1,101 @@
// ==========================================================================
// SchemaJsonSerializer.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Squidex.Infrastructure;
// ReSharper disable UseObjectOrCollectionInitializer
namespace Squidex.Core.Schemas.Json
{
public sealed class SchemaJsonSerializer
{
private readonly FieldRegistry fieldRegistry;
private readonly JsonSerializer serializer;
public class FieldModel
{
public string Name;
public bool IsHidden;
public bool IsDisabled;
public FieldProperties Properties;
}
public sealed class SchemaModel
{
public string Name;
public SchemaProperties Properties;
public Dictionary<long, FieldModel> Fields;
}
public SchemaJsonSerializer(FieldRegistry fieldRegistry, JsonSerializerSettings serializerSettings)
{
Guard.NotNull(fieldRegistry, nameof(fieldRegistry));
Guard.NotNull(serializerSettings, nameof(serializerSettings));
this.fieldRegistry = fieldRegistry;
serializer = JsonSerializer.Create(serializerSettings);
}
public JToken Serialize(Schema schema)
{
var model = new SchemaModel { Name = schema.Name, Properties = schema.Properties };
model.Fields =
schema.Fields
.Select(x =>
new KeyValuePair<long, FieldModel>(x.Key,
new FieldModel
{
Name = x.Value.Name,
IsHidden = x.Value.IsHidden,
IsDisabled = x.Value.IsDisabled,
Properties = x.Value.RawProperties
}))
.ToDictionary(x => x.Key, x => x.Value);
return JToken.FromObject(model, serializer);
}
public Schema Deserialize(JToken token)
{
var model = token.ToObject<SchemaModel>(serializer);
var schema = Schema.Create(model.Name, model.Properties);
foreach (var kvp in model.Fields)
{
var fieldModel = kvp.Value;
var field = fieldRegistry.CreateField(kvp.Key, fieldModel.Name, fieldModel.Properties);
if (fieldModel.IsDisabled)
{
field = field.Disable();
}
if (fieldModel.IsHidden)
{
field = field.Hide();
}
schema = schema.AddOrUpdateField(field);
}
return schema;
}
}
}

2
src/Squidex.Core/Schemas/NumberFieldProperties.cs

@ -12,7 +12,7 @@ using Squidex.Infrastructure;
namespace Squidex.Core.Schemas
{
[TypeName("number")]
[TypeName("NumberField")]
public sealed class NumberFieldProperties : FieldProperties
{
private double? maxValue;

6
src/Squidex.Core/Schemas/StringField.cs

@ -7,6 +7,7 @@
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using Squidex.Core.Schemas.Validators;
using Squidex.Infrastructure;
@ -35,6 +36,11 @@ namespace Squidex.Core.Schemas
{
yield return new PatternValidator(Properties.Pattern, Properties.PatternMessage);
}
if (Properties.AllowedValues != null)
{
yield return new AllowedValuesValidator<string>(Properties.AllowedValues.ToArray());
}
}
protected override object ConvertValue(PropertyValue property)

14
src/Squidex.Core/Schemas/StringFieldProperties.cs

@ -10,16 +10,19 @@ using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Squidex.Infrastructure;
using System.Collections.Immutable;
// ReSharper disable ObjectCreationAsStatement
namespace Squidex.Core.Schemas
{
[TypeName("StringField")]
public sealed class StringFieldProperties : FieldProperties
{
private int? minLength;
private int? maxLength;
private string pattern;
private string patternMessage;
private ImmutableList<string> allowedValues;
public int? MinLength
{
@ -65,6 +68,17 @@ namespace Squidex.Core.Schemas
}
}
public ImmutableList<string> AllowedValues
{
get { return allowedValues; }
set
{
ThrowIfFrozen();
allowedValues = value;
}
}
protected override IEnumerable<ValidationError> ValidateCore()
{
if (MaxLength.HasValue && MinLength.HasValue && MinLength.Value >= MaxLength.Value)

2
src/Squidex.Core/Schemas/Validators/PatternValidator.cs

@ -25,7 +25,7 @@ namespace Squidex.Core.Schemas.Validators
{
this.errorMessage = errorMessage;
regex = new Regex(pattern);
regex = new Regex("^" + pattern + "$");
}
public Task ValidateAsync(object value, ICollection<string> errors)

14
src/Squidex.Infrastructure/TypeNameRegistry.cs

@ -30,9 +30,12 @@ namespace Squidex.Infrastructure
}
catch (ArgumentException)
{
var message = $"The type '{type}' is already registered with name '{namesByType[type]}'";
if (namesByType[type] != name)
{
var message = $"The type '{type}' is already registered with name '{namesByType[type]}'";
throw new ArgumentException(message, nameof(type));
throw new ArgumentException(message, nameof(type));
}
}
try
@ -41,9 +44,12 @@ namespace Squidex.Infrastructure
}
catch (ArgumentException)
{
var message = $"The name '{name}' is already registered with type '{typesByName[name]}'";
if (typesByName[name] != type)
{
var message = $"The name '{name}' is already registered with type '{typesByName[name]}'";
throw new ArgumentException(message, nameof(type));
throw new ArgumentException(message, nameof(type));
}
}
}
}

51
src/Squidex.Store.MongoDb/Schemas/Models/FieldModel.cs

@ -1,51 +0,0 @@
// ==========================================================================
// FieldDto.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Core.Schemas;
namespace Squidex.Store.MongoDb.Schemas.Models
{
public class FieldModel
{
public string Name { get; set; }
public bool IsHidden { get; set; }
public bool IsDisabled { get; set; }
public FieldProperties Properties { get; set; }
public static FieldModel Create(Field field)
{
return new FieldModel
{
Name = field.Name,
IsHidden = field.IsHidden,
IsDisabled = field.IsDisabled,
Properties = field.RawProperties
};
}
public Field ToField(long id, FieldRegistry registry)
{
var field = registry.CreateField(id, Name, Properties);
if (IsHidden)
{
field = field.Hide();
}
if (IsDisabled)
{
field = field.Disable();
}
return field;
}
}
}

60
src/Squidex.Store.MongoDb/Schemas/Models/SchemaModel.cs

@ -1,60 +0,0 @@
// ==========================================================================
// SchemaDto.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
// ReSharper disable UseObjectOrCollectionInitializer
// ReSharper disable InvertIf
namespace Squidex.Store.MongoDb.Schemas.Models
{
public sealed class SchemaModel
{
public string Name { get; set; }
public Dictionary<long, FieldModel> Fields { get; set; }
public SchemaProperties Properties { get; set; }
public static SchemaModel Create(Schema schema)
{
Guard.NotNull(schema, nameof(schema));
var dto = new SchemaModel { Properties = schema.Properties, Name = schema.Name };
dto.Fields =
schema.Fields.ToDictionary(
kvp => kvp.Key,
kvp => FieldModel.Create(kvp.Value));
return dto;
}
public Schema ToSchema(FieldRegistry registry)
{
Guard.NotNull(registry, nameof(registry));
var schema = Schema.Create(Name, Properties);
if (Fields != null)
{
foreach (var kvp in Fields)
{
var field = kvp.Value;
schema = schema.AddOrUpdateField(field.ToField(kvp.Key, registry));
}
}
return schema;
}
}
}

18
src/Squidex.Store.MongoDb/Schemas/MongoSchemaEntity.cs

@ -9,17 +9,16 @@
using System;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using Newtonsoft.Json;
using Squidex.Core.Schemas;
using Squidex.Core.Schemas.Json;
using Squidex.Read.Schemas.Repositories;
using Squidex.Store.MongoDb.Schemas.Models;
using Squidex.Store.MongoDb.Utils;
namespace Squidex.Store.MongoDb.Schemas
{
public sealed class MongoSchemaEntity : MongoEntity, ISchemaEntityWithSchema
{
private Schema schema;
private Lazy<Schema> schema;
[BsonRequired]
[BsonElement]
@ -39,19 +38,14 @@ namespace Squidex.Store.MongoDb.Schemas
Schema ISchemaEntityWithSchema.Schema
{
get { return schema; }
get { return schema.Value; }
}
public void DeserializeSchema(JsonSerializerSettings serializerSettings, FieldRegistry fieldRegistry)
public Lazy<Schema> DeserializeSchema(SchemaJsonSerializer serializer)
{
if (schema != null)
{
return;
}
schema = new Lazy<Schema>(() => schema != null ? null : serializer.Deserialize(Schema.ToJToken()));
var dto = Schema.ToJsonObject<SchemaModel>(serializerSettings);
schema = dto?.ToSchema(fieldRegistry);
return schema;
}
}
}

24
src/Squidex.Store.MongoDb/Schemas/MongoSchemaRepository.cs

@ -11,8 +11,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MongoDB.Driver;
using Newtonsoft.Json;
using Squidex.Core.Schemas;
using Squidex.Core.Schemas.Json;
using Squidex.Events.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS;
@ -20,23 +20,23 @@ using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Dispatching;
using Squidex.Infrastructure.Reflection;
using Squidex.Read.Schemas.Repositories;
using Squidex.Store.MongoDb.Schemas.Models;
using Squidex.Store.MongoDb.Utils;
namespace Squidex.Store.MongoDb.Schemas
{
public sealed class MongoSchemaRepository : MongoRepositoryBase<MongoSchemaEntity>, ISchemaRepository, ICatchEventConsumer
{
private readonly JsonSerializerSettings serializerSettings;
private readonly SchemaJsonSerializer serializer;
private readonly FieldRegistry fieldRegistry;
public MongoSchemaRepository(IMongoDatabase database, JsonSerializerSettings serializerSettings, FieldRegistry fieldRegistry)
public MongoSchemaRepository(IMongoDatabase database, SchemaJsonSerializer serializer, FieldRegistry fieldRegistry)
: base(database)
{
Guard.NotNull(serializerSettings, nameof(serializerSettings));
Guard.NotNull(serializer, nameof(serializer));
Guard.NotNull(fieldRegistry, nameof(fieldRegistry));
this.serializerSettings = serializerSettings;
this.serializer = serializer;
this.fieldRegistry = fieldRegistry;
}
@ -63,7 +63,7 @@ namespace Squidex.Store.MongoDb.Schemas
await Collection.Find(s => s.Name == name && s.AppId == appId && !s.IsDeleted)
.FirstOrDefaultAsync();
entity?.DeserializeSchema(serializerSettings, fieldRegistry);
entity?.DeserializeSchema(serializer);
return entity;
}
@ -74,7 +74,7 @@ namespace Squidex.Store.MongoDb.Schemas
await Collection.Find(s => s.Id == schemaId && !s.IsDeleted)
.FirstOrDefaultAsync();
entity?.DeserializeSchema(serializerSettings, fieldRegistry);
entity?.DeserializeSchema(serializer);
return entity;
}
@ -161,16 +161,12 @@ namespace Squidex.Store.MongoDb.Schemas
private void Serialize(MongoSchemaEntity entity, Schema schema)
{
var dto = SchemaModel.Create(schema);
entity.Schema = dto.ToJsonBsonDocument(serializerSettings);
entity.Schema = serializer.Serialize(schema).ToBsonDocument();
}
private Schema Deserialize(MongoSchemaEntity entity)
{
var dto = entity?.Schema.ToJsonObject<SchemaModel>(serializerSettings);
return dto?.ToSchema(fieldRegistry);
return entity.DeserializeSchema(serializer).Value;
}
}
}

10
src/Squidex.Store.MongoDb/Utils/EntityMapper.cs

@ -10,7 +10,7 @@ using System;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Squidex.Infrastructure.CQRS;
using Squidex.Read;
@ -34,18 +34,18 @@ namespace Squidex.Store.MongoDb.Utils
return Update(entity, headers);
}
public static BsonDocument ToJsonBsonDocument<T>(this T value, JsonSerializerSettings settings)
public static BsonDocument ToBsonDocument(this JToken value)
{
var json = JsonConvert.SerializeObject(value, settings).Replace("$type", "§type");
var json = value.ToString().Replace("$type", "§type");
return BsonDocument.Parse(json);
}
public static T ToJsonObject<T>(this BsonDocument document, JsonSerializerSettings settings)
public static JToken ToJToken(this BsonDocument document)
{
var json = document.ToJson().Replace("§type", "$type");
return JsonConvert.DeserializeObject<T>(json, settings);
return JToken.Parse(json);
}
public static T Update<T>(T entity, EnvelopeHeaders headers) where T : IEntity

5
src/Squidex/Config/Domain/InfrastructureModule.cs

@ -10,6 +10,7 @@ using Autofac;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Squidex.Core.Schemas;
using Squidex.Core.Schemas.Json;
using Squidex.Infrastructure.CQRS.Autofac;
using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Infrastructure.CQRS.EventStore;
@ -49,6 +50,10 @@ namespace Squidex.Config.Domain
.AsSelf()
.SingleInstance();
builder.RegisterType<SchemaJsonSerializer>()
.AsSelf()
.SingleInstance();
builder.RegisterType<FieldRegistry>()
.AsSelf()
.SingleInstance();

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

@ -0,0 +1,68 @@
// ==========================================================================
// SchemaConverter.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using Squidex.Core.Schemas;
using Squidex.Infrastructure.Reflection;
using Squidex.Read.Schemas.Repositories;
using Dtos = Squidex.Controllers.Api.Schemas.Models.Fields;
namespace Squidex.Controllers.Api.Schemas.Models.Converters
{
public static class SchemaConverter
{
private static readonly Dictionary<Type, Func<Field, FieldDto>> Factories = new Dictionary<Type, Func<Field, FieldDto>>
{
{
typeof(NumberField),
field =>
{
var dto = new Dtos.NumberField();
SimpleMapper.Map(field, dto);
SimpleMapper.Map((NumberFieldProperties)field.RawProperties, dto);
return dto;
}
},
{
typeof(StringField),
field =>
{
var dto = new Dtos.StringField();
SimpleMapper.Map(field, dto);
SimpleMapper.Map((StringFieldProperties)field.RawProperties, dto);
return dto;
}
}
};
public static SchemaDetailsDto ToModel(this ISchemaEntityWithSchema entity)
{
var dto = new SchemaDetailsDto();
SimpleMapper.Map(entity, dto);
SimpleMapper.Map(entity.Schema, dto);
SimpleMapper.Map(entity.Schema.Properties, dto);
dto.Fields = new List<FieldDto>();
foreach (var field in entity.Schema.Fields.Values)
{
var fieldDto = Factories[field.RawProperties.GetType()](field);
dto.Fields.Add(fieldDto);
}
return dto;
}
}
}

8
src/Squidex/Controllers/Api/Schemas/Models/FieldDto.cs

@ -10,14 +10,14 @@ using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using NJsonSchema.Converters;
using Squidex.Controllers.Api.Schemas.Models.Fields;
using Squidex.Core.Schemas;
namespace Squidex.Controllers.Api.Schemas.Models
{
[JsonConverter(typeof(JsonInheritanceConverter), "fieldType")]
[JsonConverter(typeof(JsonInheritanceConverter), "$type")]
[KnownType(typeof(NumberField))]
[KnownType(typeof(StringField))]
public class FieldDto
public abstract class FieldDto
{
/// <summary>
/// The name of the field. Must be unique within the schema.
@ -48,5 +48,7 @@ namespace Squidex.Controllers.Api.Schemas.Models
/// Indicates if the field is required.
/// </summary>
public bool IsRequired { get; set; }
public abstract FieldProperties ToProperties();
}
}

8
src/Squidex/Controllers/Api/Schemas/Models/Fields/NumberField.cs

@ -6,6 +6,9 @@
// All rights reserved.
// ==========================================================================
using Squidex.Core.Schemas;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Controllers.Api.Schemas.Models.Fields
{
public class NumberField : FieldDto
@ -29,5 +32,10 @@ namespace Squidex.Controllers.Api.Schemas.Models.Fields
/// The allowed values for the field value.
/// </summary>
public double[] AllowedValues { get; set; }
public override FieldProperties ToProperties()
{
return SimpleMapper.Map(this, new NumberFieldProperties());
}
}
}

15
src/Squidex/Controllers/Api/Schemas/Models/Fields/StringField.cs

@ -6,6 +6,9 @@
// All rights reserved.
// ==========================================================================
using Squidex.Core.Schemas;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Controllers.Api.Schemas.Models.Fields
{
public sealed class StringField : FieldDto
@ -20,6 +23,11 @@ namespace Squidex.Controllers.Api.Schemas.Models.Fields
/// </summary>
public string Pattern { get; set; }
/// <summary>
/// The validation message for the pattern.
/// </summary>
public string PatternMessage { get; set; }
/// <summary>
/// The minimum allowed length for the field value.
/// </summary>
@ -33,6 +41,11 @@ namespace Squidex.Controllers.Api.Schemas.Models.Fields
/// <summary>
/// The allowed values for the field value.
/// </summary>
public double[] AllowedValues { get; set; }
public string[] AllowedValues { get; set; }
public override FieldProperties ToProperties()
{
return SimpleMapper.Map(this, new StringFieldProperties());
}
}
}

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

@ -9,10 +9,11 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using NSwag.Annotations;
using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Controllers.Api.Schemas.Models;
using Squidex.Infrastructure;
using Squidex.Pipeline;
using Squidex.Write.Schemas.Commands;
@ -51,7 +52,12 @@ namespace Squidex.Controllers.Api.Schemas
[ProducesResponseType(typeof(ErrorDto), 400)]
public async Task<IActionResult> PostField(string app, string name, [FromBody] FieldDto model)
{
var command = SimpleMapper.Map(model, new AddField());
var properties = model.ToProperties();
var fieldName = model.Name;
var fieldType = TypeNameRegistry.GetName(properties.GetType());
var command = new AddField { Name = fieldName, Type = fieldType, Properties = JToken.FromObject(properties) };
var context = await CommandBus.PublishAsync(command);
var result = context.Result<long>();
@ -77,7 +83,7 @@ namespace Squidex.Controllers.Api.Schemas
[ProducesResponseType(typeof(ErrorDto), 400)]
public async Task<IActionResult> PutField(string app, string name, long id, [FromBody] FieldDto model)
{
var command = SimpleMapper.Map(model, new UpdateField());
var command = new UpdateField { FieldId = id, Properties = JToken.FromObject(model) };
await CommandBus.PublishAsync(command);

5
src/Squidex/Controllers/Api/Schemas/SchemasController.cs

@ -15,6 +15,7 @@ using NSwag.Annotations;
using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Controllers.Api.Schemas.Models;
using Squidex.Controllers.Api.Schemas.Models.Converters;
using Squidex.Pipeline;
using Squidex.Read.Schemas.Repositories;
using Squidex.Write.Schemas.Commands;
@ -76,7 +77,9 @@ namespace Squidex.Controllers.Api.Schemas
return NotFound();
}
return Ok(null);
var model = entity.ToModel();
return Ok(model);
}
/// <summary>

5
tests/Squidex.Core.Tests/Schemas/FieldRegistryTests.cs

@ -28,7 +28,8 @@ namespace Squidex.Core.Tests.Schemas
static FieldRegistryTests()
{
TypeNameRegistry.Map(typeof(NumberFieldProperties), "number");
TypeNameRegistry.Map(typeof(NumberFieldProperties), "NumberField");
TypeNameRegistry.Map(typeof(StringFieldProperties), "StringField");
TypeNameRegistry.Map(typeof(InvalidProperties), "invalid");
}
@ -71,7 +72,7 @@ namespace Squidex.Core.Tests.Schemas
[Fact]
public void Should_find_registration_by_name()
{
var registry = sut.FindByTypeName("number");
var registry = sut.FindByTypeName("NumberField");
Assert.Equal(typeof(NumberFieldProperties), registry.PropertiesType);
}

52
tests/Squidex.Core.Tests/Schemas/Json/JsonSerializerTests.cs

@ -0,0 +1,52 @@
// ==========================================================================
// JsonSerializerTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Reflection;
using FluentAssertions;
using Newtonsoft.Json;
using Squidex.Core.Schemas;
using Squidex.Core.Schemas.Json;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json;
using Xunit;
namespace Squidex.Core.Tests.Schemas.Json
{
public class JsonSerializerTests
{
private static readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
static JsonSerializerTests()
{
TypeNameRegistry.Map(typeof(FieldRegistry).GetTypeInfo().Assembly);
serializerSettings.TypeNameHandling = TypeNameHandling.Auto;
serializerSettings.SerializationBinder = new TypeNameSerializationBinder();
}
[Fact]
public void Should_serialize_and_deserialize_schema()
{
var schema =
Schema.Create("my-schema", new SchemaProperties())
.AddOrUpdateField(new StringField(1, "field1", new StringFieldProperties { Label = "Field1", Pattern = "[0-9]{3}" }))
.AddOrUpdateField(new NumberField(2, "field2", new NumberFieldProperties { Hints = "Hints" }))
.DisableField(1)
.HideField(2);
var sut = new SchemaJsonSerializer(new FieldRegistry(), serializerSettings);
var token = sut.Serialize(schema);
var deserialized = sut.Deserialize(token);
deserialized.ShouldBeEquivalentTo(schema);
}
}
}

1
tests/Squidex.Core.Tests/Schemas/StringFieldPropertiesTests.cs

@ -12,7 +12,6 @@ using System.Linq;
using System.Reflection;
using FluentAssertions;
using Squidex.Core.Schemas;
using Squidex.Core.Schemas.Validators;
using Squidex.Infrastructure;
using Xunit;

20
tests/Squidex.Core.Tests/Schemas/StringFieldTests.cs

@ -7,6 +7,7 @@
// ==========================================================================
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
@ -47,7 +48,7 @@ namespace Squidex.Core.Tests.Schemas
}
[Fact]
public async Task Should_add_errors_if_string_shorter_than_max()
public async Task Should_add_errors_if_string_is_shorter_than_min_length()
{
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", MinLength = 10 });
@ -58,7 +59,7 @@ namespace Squidex.Core.Tests.Schemas
}
[Fact]
public async Task Should_add_errors_if_number_is_greater_than_max()
public async Task Should_add_errors_if_string_is_longer_than_max_length()
{
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", MaxLength = 5 });
@ -68,10 +69,21 @@ namespace Squidex.Core.Tests.Schemas
new[] { "Name must have less than '5' characters" });
}
[Fact]
public async Task Should_add_errors_if_string_not_allowed()
{
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", AllowedValues = ImmutableList.Create("Foo") });
await sut.ValidateAsync(CreateValue("Bar"), errors);
errors.ShouldBeEquivalentTo(
new[] { "Name is not an allowed value" });
}
[Fact]
public async Task Should_add_errors_if_number_is_not_valid_pattern()
{
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", Pattern = "^[0-9]{3}$" });
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", Pattern = "[0-9]{3}" });
await sut.ValidateAsync(CreateValue("abc"), errors);
@ -82,7 +94,7 @@ namespace Squidex.Core.Tests.Schemas
[Fact]
public async Task Should_add_errors_if_number_is_not_valid_pattern_with_message()
{
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", Pattern = "^[0-9]{3}$", PatternMessage = "Custom Error Message" });
var sut = new StringField(1, "name", new StringFieldProperties { Label = "Name", Pattern = "[0-9]{3}", PatternMessage = "Custom Error Message" });
await sut.ValidateAsync(CreateValue("abc"), errors);

8
tests/Squidex.Core.Tests/Schemas/Validators/PatternValidatorTests.cs

@ -21,7 +21,7 @@ namespace Squidex.Core.Tests.Schemas.Validators
[Fact]
public async Task Should_not_add_error_if_value_is_valid()
{
var sut = new PatternValidator("^[a-z]{3}:[0-9]{2}$");
var sut = new PatternValidator("[a-z]{3}:[0-9]{2}");
await sut.ValidateAsync("abc:12", errors);
@ -31,7 +31,7 @@ namespace Squidex.Core.Tests.Schemas.Validators
[Fact]
public async Task Should_not_add_error_if_value_is_null()
{
var sut = new PatternValidator("^[a-z]{3}:[0-9]{2}$");
var sut = new PatternValidator("[a-z]{3}:[0-9]{2}");
await sut.ValidateAsync(null, errors);
@ -41,7 +41,7 @@ namespace Squidex.Core.Tests.Schemas.Validators
[Fact]
public async Task Should_add_error_with_default_message_if_value_is_not_valid()
{
var sut = new PatternValidator("^[a-z]{3}:[0-9]{2}$");
var sut = new PatternValidator("[a-z]{3}:[0-9]{2}");
await sut.ValidateAsync("foo", errors);
@ -52,7 +52,7 @@ namespace Squidex.Core.Tests.Schemas.Validators
[Fact]
public async Task Should_add_error_with_custom_message_if_value_is_not_valid()
{
var sut = new PatternValidator("^[a-z]{3}:[0-9]{2}$", "Custom Error Message");
var sut = new PatternValidator("[a-z]{3}:[0-9]{2}", "Custom Error Message");
await sut.ValidateAsync("foo", errors);

17
tests/Squidex.Infrastructure.Tests/TypeNameRegistryTests.cs

@ -22,13 +22,13 @@ namespace Squidex.Infrastructure
[Fact]
public void Should_register_and_retrieve_types()
{
TypeNameRegistry.Map(typeof(int), "number");
TypeNameRegistry.Map(typeof(int), "NumberField");
Assert.Equal("number", TypeNameRegistry.GetName<int>());
Assert.Equal("number", TypeNameRegistry.GetName(typeof(int)));
Assert.Equal("NumberField", TypeNameRegistry.GetName<int>());
Assert.Equal("NumberField", TypeNameRegistry.GetName(typeof(int)));
Assert.Equal(typeof(int), TypeNameRegistry.GetType("number"));
Assert.Equal(typeof(int), TypeNameRegistry.GetType("Number"));
Assert.Equal(typeof(int), TypeNameRegistry.GetType("NumberField"));
Assert.Equal(typeof(int), TypeNameRegistry.GetType("NumberField"));
}
[Fact]
@ -43,6 +43,13 @@ namespace Squidex.Infrastructure
Assert.Equal(typeof(MyType), TypeNameRegistry.GetType("My"));
}
[Fact]
public void Should_not_throw_if_type_is_already_registered_with_same_name()
{
TypeNameRegistry.Map(typeof(long), "long");
TypeNameRegistry.Map(typeof(long), "long");
}
[Fact]
public void Should_throw_if_type_is_already_registered()
{

Loading…
Cancel
Save