Browse Source

Field reordering in schema.

pull/65/head
Sebastian Stehle 10 years ago
parent
commit
44c6aabb1c
  1. 4
      src/Squidex.Core/ContentExtensions.cs
  2. 2
      src/Squidex.Core/Contents/ContentData.cs
  3. 2
      src/Squidex.Core/Schemas/Json/JsonFieldModel.cs
  4. 2
      src/Squidex.Core/Schemas/Json/JsonSchemaModel.cs
  5. 31
      src/Squidex.Core/Schemas/Json/SchemaJsonSerializer.cs
  6. 61
      src/Squidex.Core/Schemas/Schema.cs
  7. 2
      src/Squidex.Write/Schemas/SchemaCommandHandler.cs
  8. 2
      src/Squidex.Write/Schemas/SchemaDomainObject.cs
  9. 8
      src/Squidex/Controllers/Api/Schemas/Models/Converters/SchemaConverter.cs
  10. 56
      tests/Squidex.Core.Tests/Schemas/SchemaTests.cs
  11. 14
      tests/Squidex.Write.Tests/Schemas/SchemaDomainObjectTests.cs

4
src/Squidex.Core/ContentExtensions.cs

@ -18,9 +18,9 @@ namespace Squidex.Core
{ {
public static ContentData Enrich(this ContentData data, Schema schema, HashSet<Language> languages) public static ContentData Enrich(this ContentData data, Schema schema, HashSet<Language> languages)
{ {
var validator = new ContentEnricher(languages, schema); var enricher = new ContentEnricher(languages, schema);
validator.Enrich(data); enricher.Enrich(data);
return data; return data;
} }

2
src/Squidex.Core/Contents/ContentData.cs

@ -111,7 +111,7 @@ namespace Squidex.Core.Contents
foreach (var fieldValue in this) foreach (var fieldValue in this)
{ {
if (!long.TryParse(fieldValue.Key, out long fieldId) || !schema.Fields.TryGetValue(fieldId, out Field field)) if (!long.TryParse(fieldValue.Key, out long fieldId) || !schema.FieldsById.TryGetValue(fieldId, out Field field))
{ {
continue; continue;
} }

2
src/Squidex.Core/Schemas/Json/JsonFieldModel.cs

@ -12,6 +12,8 @@ namespace Squidex.Core.Schemas.Json
{ {
public string Name { get; set; } public string Name { get; set; }
public long Id { get; set; }
public bool IsHidden { get; set; } public bool IsHidden { get; set; }
public bool IsDisabled { get; set; } public bool IsDisabled { get; set; }

2
src/Squidex.Core/Schemas/Json/JsonSchemaModel.cs

@ -18,6 +18,6 @@ namespace Squidex.Core.Schemas.Json
public SchemaProperties Properties { get; set; } public SchemaProperties Properties { get; set; }
public Dictionary<long, JsonFieldModel> Fields { get; set; } public List<JsonFieldModel> Fields { get; set; }
} }
} }

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

@ -6,7 +6,6 @@
// All rights reserved. // All rights reserved.
// ========================================================================== // ==========================================================================
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -36,18 +35,16 @@ namespace Squidex.Core.Schemas.Json
{ {
var model = new JsonSchemaModel { Name = schema.Name, IsPublished = schema.IsPublished, Properties = schema.Properties }; var model = new JsonSchemaModel { Name = schema.Name, IsPublished = schema.IsPublished, Properties = schema.Properties };
model.Fields = model.Fields =
schema.Fields schema.Fields.Select(x =>
.Select(x => new JsonFieldModel
new KeyValuePair<long, JsonFieldModel>(x.Key, {
new JsonFieldModel Id = x.Id,
{ Name = x.Name,
Name = x.Value.Name, IsHidden = x.IsHidden,
IsHidden = x.Value.IsHidden, IsDisabled = x.IsDisabled,
IsDisabled = x.Value.IsDisabled, Properties = x.RawProperties
Properties = x.Value.RawProperties }).ToList();
}))
.ToDictionary(x => x.Key, x => x.Value);
return JToken.FromObject(model, serializer); return JToken.FromObject(model, serializer);
} }
@ -57,11 +54,9 @@ namespace Squidex.Core.Schemas.Json
var model = token.ToObject<JsonSchemaModel>(serializer); var model = token.ToObject<JsonSchemaModel>(serializer);
var fields = var fields =
model.Fields.Select(kvp => model.Fields.Select(fieldModel =>
{ {
var fieldModel = kvp.Value; var field = fieldRegistry.CreateField(fieldModel.Id, fieldModel.Name, fieldModel.Properties);
var field = fieldRegistry.CreateField(kvp.Key, fieldModel.Name, fieldModel.Properties);
if (fieldModel.IsDisabled) if (fieldModel.IsDisabled)
{ {
@ -74,7 +69,7 @@ namespace Squidex.Core.Schemas.Json
} }
return field; return field;
}).ToImmutableDictionary(x => x.Id, x => x); }).ToImmutableList();
var schema = var schema =
new Schema( new Schema(

61
src/Squidex.Core/Schemas/Schema.cs

@ -23,6 +23,7 @@ namespace Squidex.Core.Schemas
{ {
private readonly string name; private readonly string name;
private readonly SchemaProperties properties; private readonly SchemaProperties properties;
private readonly ImmutableList<Field> fields;
private readonly ImmutableDictionary<long, Field> fieldsById; private readonly ImmutableDictionary<long, Field> fieldsById;
private readonly ImmutableDictionary<string, Field> fieldsByName; private readonly ImmutableDictionary<string, Field> fieldsByName;
private readonly bool isPublished; private readonly bool isPublished;
@ -37,7 +38,12 @@ namespace Squidex.Core.Schemas
get { return isPublished; } get { return isPublished; }
} }
public ImmutableDictionary<long, Field> Fields public ImmutableList<Field> Fields
{
get { return fields; }
}
public ImmutableDictionary<long, Field> FieldsById
{ {
get { return fieldsById; } get { return fieldsById; }
} }
@ -52,17 +58,19 @@ namespace Squidex.Core.Schemas
get { return properties; } get { return properties; }
} }
public Schema(string name, bool isPublished, SchemaProperties properties, ImmutableDictionary<long, Field> fields) public Schema(string name, bool isPublished, SchemaProperties properties, ImmutableList<Field> fields)
{ {
Guard.NotNull(fields, nameof(fields)); Guard.NotNull(fields, nameof(fields));
Guard.NotNull(properties, nameof(properties)); Guard.NotNull(properties, nameof(properties));
Guard.ValidSlug(name, nameof(name)); Guard.ValidSlug(name, nameof(name));
fieldsById = fields; fieldsById = fields.ToImmutableDictionary(x => x.Id);
fieldsByName = fields.Values.ToImmutableDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase); fieldsByName = fields.ToImmutableDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase);
this.name = name; this.name = name;
this.fields = fields;
this.properties = properties; this.properties = properties;
this.properties.Freeze(); this.properties.Freeze();
@ -78,14 +86,14 @@ namespace Squidex.Core.Schemas
throw new ValidationException("Cannot create a new schema", error); throw new ValidationException("Cannot create a new schema", error);
} }
return new Schema(name, false, newProperties, ImmutableDictionary<long, Field>.Empty); return new Schema(name, false, newProperties, ImmutableList<Field>.Empty);
} }
public Schema Update(SchemaProperties newProperties) public Schema Update(SchemaProperties newProperties)
{ {
Guard.NotNull(newProperties, nameof(newProperties)); Guard.NotNull(newProperties, nameof(newProperties));
return new Schema(name, isPublished, newProperties, fieldsById); return new Schema(name, isPublished, newProperties, fields);
} }
public Schema UpdateField(long fieldId, FieldProperties newProperties) public Schema UpdateField(long fieldId, FieldProperties newProperties)
@ -120,7 +128,7 @@ namespace Squidex.Core.Schemas
public Schema DeleteField(long fieldId) public Schema DeleteField(long fieldId)
{ {
return new Schema(name, isPublished, properties, fieldsById.Remove(fieldId)); return new Schema(name, isPublished, properties, fields.Where(x => x.Id != fieldId).ToImmutableList());
} }
public Schema Publish() public Schema Publish()
@ -130,7 +138,7 @@ namespace Squidex.Core.Schemas
throw new DomainException("Schema is already published"); throw new DomainException("Schema is already published");
} }
return new Schema(name, true, properties, fieldsById); return new Schema(name, true, properties, fields);
} }
public Schema Unpublish() public Schema Unpublish()
@ -140,19 +148,21 @@ namespace Squidex.Core.Schemas
throw new DomainException("Schema is not published"); throw new DomainException("Schema is not published");
} }
return new Schema(name, false, properties, fieldsById); return new Schema(name, false, properties, fields);
} }
public Schema AddOrUpdateField(Field field) public Schema ReorderFields(List<long> ids)
{ {
Guard.NotNull(field, nameof(field)); Guard.NotNull(ids, nameof(ids));
if (fieldsById.Values.Any(f => f.Name == field.Name && f.Id != field.Id)) if (ids.Count != fields.Count || ids.Any(x => !fieldsById.ContainsKey(x)))
{ {
throw new ValidationException($"A field with name '{field.Name}' already exists."); throw new ArgumentException("Ids must cover all fields.", nameof(ids));
} }
return new Schema(name, isPublished, properties, fieldsById.SetItem(field.Id, field)); var newFields = fields.OrderBy(f => ids.IndexOf(f.Id)).ToImmutableList();
return new Schema(name, isPublished, properties, newFields);
} }
public Schema UpdateField(long fieldId, Func<Field, Field> updater) public Schema UpdateField(long fieldId, Func<Field, Field> updater)
@ -169,6 +179,29 @@ namespace Squidex.Core.Schemas
return AddOrUpdateField(newField); return AddOrUpdateField(newField);
} }
public Schema AddOrUpdateField(Field field)
{
Guard.NotNull(field, nameof(field));
if (fieldsById.Values.Any(f => f.Name == field.Name && f.Id != field.Id))
{
throw new ValidationException($"A field with name '{field.Name}' already exists.");
}
ImmutableList<Field> newFields;
if (fieldsById.ContainsKey(field.Id))
{
newFields = fields.Select(f => f.Id == field.Id ? field : f).ToImmutableList();
}
else
{
newFields = fields.Add(field);
}
return new Schema(name, isPublished, properties, newFields);
}
public EdmComplexType BuildEdmType(HashSet<Language> languages, Func<EdmComplexType, EdmComplexType> typeResolver) public EdmComplexType BuildEdmType(HashSet<Language> languages, Func<EdmComplexType, EdmComplexType> typeResolver)
{ {
Guard.NotEmpty(languages, nameof(languages)); Guard.NotEmpty(languages, nameof(languages));

2
src/Squidex.Write/Schemas/SchemaCommandHandler.cs

@ -56,7 +56,7 @@ namespace Squidex.Write.Schemas
{ {
s.AddField(command); s.AddField(command);
context.Succeed(EntityCreatedResult.Create(s.Schema.Fields.Values.First(x => x.Name == command.Name).Id, s.Version)); context.Succeed(EntityCreatedResult.Create(s.Schema.FieldsById.Values.First(x => x.Name == command.Name).Id, s.Version));
}); });
} }

2
src/Squidex.Write/Schemas/SchemaDomainObject.cs

@ -240,7 +240,7 @@ namespace Squidex.Write.Schemas
{ {
SimpleMapper.Map(fieldCommand, @event); SimpleMapper.Map(fieldCommand, @event);
if (schema.Fields.TryGetValue(fieldCommand.FieldId, out Field field)) if (schema.FieldsById.TryGetValue(fieldCommand.FieldId, out Field field))
{ {
@event.FieldId = new NamedId<long>(field.Id, field.Name); @event.FieldId = new NamedId<long>(field.Id, field.Name);
} }

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

@ -55,12 +55,12 @@ namespace Squidex.Controllers.Api.Schemas.Models.Converters
dto.Fields = new List<FieldDto>(); dto.Fields = new List<FieldDto>();
foreach (var kvp in entity.Schema.Fields) foreach (var field in entity.Schema.Fields)
{ {
var fieldPropertiesDto = Factories[kvp.Value.RawProperties.GetType()](kvp.Value.RawProperties); var fieldPropertiesDto = Factories[field.RawProperties.GetType()](field.RawProperties);
var fieldDto = SimpleMapper.Map(kvp.Value, new FieldDto { FieldId = kvp.Key, Properties = fieldPropertiesDto }); var fieldInstanceDto = SimpleMapper.Map(field, new FieldDto { FieldId = field.Id, Properties = fieldPropertiesDto });
dto.Fields.Add(fieldDto); dto.Fields.Add(fieldInstanceDto);
} }
return dto; return dto;

56
tests/Squidex.Core.Tests/Schemas/SchemaTests.cs

@ -9,6 +9,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NJsonSchema; using NJsonSchema;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -65,7 +66,7 @@ namespace Squidex.Core.Schemas
{ {
var field = AddField(); var field = AddField();
Assert.Equal(field, sut.Fields[1]); Assert.Equal(field, sut.FieldsById[1]);
} }
[Fact] [Fact]
@ -84,7 +85,7 @@ namespace Squidex.Core.Schemas
sut = sut.HideField(1); sut = sut.HideField(1);
sut = sut.HideField(1); sut = sut.HideField(1);
Assert.True(sut.Fields[1].IsHidden); Assert.True(sut.FieldsById[1].IsHidden);
} }
[Fact] [Fact]
@ -102,7 +103,7 @@ namespace Squidex.Core.Schemas
sut = sut.ShowField(1); sut = sut.ShowField(1);
sut = sut.ShowField(1); sut = sut.ShowField(1);
Assert.False(sut.Fields[1].IsHidden); Assert.False(sut.FieldsById[1].IsHidden);
} }
[Fact] [Fact]
@ -119,7 +120,7 @@ namespace Squidex.Core.Schemas
sut = sut.DisableField(1); sut = sut.DisableField(1);
sut = sut.DisableField(1); sut = sut.DisableField(1);
Assert.True(sut.Fields[1].IsDisabled); Assert.True(sut.FieldsById[1].IsDisabled);
} }
[Fact] [Fact]
@ -137,7 +138,7 @@ namespace Squidex.Core.Schemas
sut = sut.EnableField(1); sut = sut.EnableField(1);
sut = sut.EnableField(1); sut = sut.EnableField(1);
Assert.False(sut.Fields[1].IsDisabled); Assert.False(sut.FieldsById[1].IsDisabled);
} }
[Fact] [Fact]
@ -153,7 +154,7 @@ namespace Squidex.Core.Schemas
sut = sut.RenameField(1, "new-name"); sut = sut.RenameField(1, "new-name");
Assert.Equal("new-name", sut.Fields[1].Name); Assert.Equal("new-name", sut.FieldsById[1].Name);
} }
[Fact] [Fact]
@ -187,7 +188,7 @@ namespace Squidex.Core.Schemas
sut = sut.DeleteField(1); sut = sut.DeleteField(1);
Assert.Equal(0, sut.Fields.Count); Assert.Equal(0, sut.FieldsById.Count);
} }
[Fact] [Fact]
@ -203,7 +204,7 @@ namespace Squidex.Core.Schemas
sut = sut.UpdateField(1, new NumberFieldProperties { Hints = "my-hints" }); sut = sut.UpdateField(1, new NumberFieldProperties { Hints = "my-hints" });
Assert.Equal("my-hints", sut.Fields[1].RawProperties.Hints); Assert.Equal("my-hints", sut.FieldsById[1].RawProperties.Hints);
} }
[Fact] [Fact]
@ -251,6 +252,45 @@ namespace Squidex.Core.Schemas
Assert.Throws<DomainException>(() => sut.Unpublish()); Assert.Throws<DomainException>(() => sut.Unpublish());
} }
[Fact]
public void Should_reorder_fields()
{
var field1 = new StringField(1, "1", new StringFieldProperties());
var field2 = new StringField(2, "2", new StringFieldProperties());
var field3 = new StringField(3, "3", new StringFieldProperties());
sut = sut.AddOrUpdateField(field1);
sut = sut.AddOrUpdateField(field2);
sut = sut.AddOrUpdateField(field3);
sut = sut.ReorderFields(new List<long> { 3, 2, 1 });
Assert.Equal(new List<Field> { field3, field2, field1 }, sut.Fields.ToList());
}
[Fact]
public void Should_throw_if_not_all_fields_are_covered_for_reordering()
{
var field1 = new StringField(1, "1", new StringFieldProperties());
var field2 = new StringField(2, "2", new StringFieldProperties());
sut = sut.AddOrUpdateField(field1);
sut = sut.AddOrUpdateField(field2);
Assert.Throws<ArgumentException>(() => sut.ReorderFields(new List<long> { 1 }));
}
[Fact]
public void Should_throw_if_field_to_reorder_does_not_exist()
{
var field1 = new StringField(1, "1", new StringFieldProperties());
var field2 = new StringField(2, "2", new StringFieldProperties());
sut = sut.AddOrUpdateField(field1);
sut = sut.AddOrUpdateField(field2);
Assert.Throws<ArgumentException>(() => sut.ReorderFields(new List<long> { 1, 4 }));
}
[Fact] [Fact]
public void Should_build_schema() public void Should_build_schema()
{ {

14
tests/Squidex.Write.Tests/Schemas/SchemaDomainObjectTests.cs

@ -265,7 +265,7 @@ namespace Squidex.Write.Schemas
sut.AddField(CreateCommand(new AddField { Name = fieldName, Properties = properties })); sut.AddField(CreateCommand(new AddField { Name = fieldName, Properties = properties }));
Assert.Equal(properties, sut.Schema.Fields[1].RawProperties); Assert.Equal(properties, sut.Schema.FieldsById[1].RawProperties);
sut.GetUncomittedEvents() sut.GetUncomittedEvents()
.ShouldHaveSameEvents( .ShouldHaveSameEvents(
@ -324,7 +324,7 @@ namespace Squidex.Write.Schemas
sut.UpdateField(CreateCommand(new UpdateField { FieldId = 1, Properties = properties })); sut.UpdateField(CreateCommand(new UpdateField { FieldId = 1, Properties = properties }));
Assert.Equal(properties, sut.Schema.Fields[1].RawProperties); Assert.Equal(properties, sut.Schema.FieldsById[1].RawProperties);
sut.GetUncomittedEvents() sut.GetUncomittedEvents()
.ShouldHaveSameEvents( .ShouldHaveSameEvents(
@ -372,7 +372,7 @@ namespace Squidex.Write.Schemas
sut.HideField(CreateCommand(new HideField { FieldId = 1 })); sut.HideField(CreateCommand(new HideField { FieldId = 1 }));
Assert.True(sut.Schema.Fields[1].IsHidden); Assert.True(sut.Schema.FieldsById[1].IsHidden);
sut.GetUncomittedEvents() sut.GetUncomittedEvents()
.ShouldHaveSameEvents( .ShouldHaveSameEvents(
@ -421,7 +421,7 @@ namespace Squidex.Write.Schemas
sut.HideField(CreateCommand(new HideField { FieldId = 1 })); sut.HideField(CreateCommand(new HideField { FieldId = 1 }));
sut.ShowField(CreateCommand(new ShowField { FieldId = 1 })); sut.ShowField(CreateCommand(new ShowField { FieldId = 1 }));
Assert.False(sut.Schema.Fields[1].IsHidden); Assert.False(sut.Schema.FieldsById[1].IsHidden);
sut.GetUncomittedEvents().Skip(1) sut.GetUncomittedEvents().Skip(1)
.ShouldHaveSameEvents( .ShouldHaveSameEvents(
@ -469,7 +469,7 @@ namespace Squidex.Write.Schemas
sut.DisableField(CreateCommand(new DisableField { FieldId = 1 })); sut.DisableField(CreateCommand(new DisableField { FieldId = 1 }));
Assert.True(sut.Schema.Fields[1].IsDisabled); Assert.True(sut.Schema.FieldsById[1].IsDisabled);
sut.GetUncomittedEvents() sut.GetUncomittedEvents()
.ShouldHaveSameEvents( .ShouldHaveSameEvents(
@ -518,7 +518,7 @@ namespace Squidex.Write.Schemas
sut.DisableField(CreateCommand(new DisableField { FieldId = 1 })); sut.DisableField(CreateCommand(new DisableField { FieldId = 1 }));
sut.EnableField(CreateCommand(new EnableField { FieldId = 1 })); sut.EnableField(CreateCommand(new EnableField { FieldId = 1 }));
Assert.False(sut.Schema.Fields[1].IsDisabled); Assert.False(sut.Schema.FieldsById[1].IsDisabled);
sut.GetUncomittedEvents().Skip(1) sut.GetUncomittedEvents().Skip(1)
.ShouldHaveSameEvents( .ShouldHaveSameEvents(
@ -555,7 +555,7 @@ namespace Squidex.Write.Schemas
sut.DeleteField(CreateCommand(new DeleteField { FieldId = 1 })); sut.DeleteField(CreateCommand(new DeleteField { FieldId = 1 }));
Assert.False(sut.Schema.Fields.ContainsKey(1)); Assert.False(sut.Schema.FieldsById.ContainsKey(1));
sut.GetUncomittedEvents() sut.GetUncomittedEvents()
.ShouldHaveSameEvents( .ShouldHaveSameEvents(

Loading…
Cancel
Save