Browse Source

Performance improvements and JSON converter

pull/141/head
Sebastian Stehle 9 years ago
parent
commit
e5adff13e6
  1. 55
      src/Squidex.Domain.Apps.Core/Schemas/Json/JsonSchemaModel.cs
  2. 41
      src/Squidex.Domain.Apps.Core/Schemas/Json/SchemaConverter.cs
  3. 89
      src/Squidex.Domain.Apps.Core/Schemas/Json/SchemaJsonSerializer.cs
  4. 72
      src/Squidex.Domain.Apps.Read.MongoDb/Contents/Extensions.cs
  5. 83
      src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentEntity.cs
  6. 26
      src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository_EventHandling.cs
  7. 41
      src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaEntity.cs
  8. 13
      src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository.cs
  9. 24
      src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs
  10. 109
      src/Squidex.Infrastructure.MongoDb/MongoDb/BsonConverter.cs
  11. 4
      src/Squidex/Config/Domain/InfrastructureModule.cs
  12. 5
      src/Squidex/Config/Domain/Serializers.cs
  13. 16
      tests/Squidex.Domain.Apps.Core.Tests/Schemas/Json/JsonSerializerTests.cs

55
src/Squidex.Domain.Apps.Core/Schemas/Json/JsonSchemaModel.cs

@ -7,6 +7,8 @@
// ========================================================================== // ==========================================================================
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Squidex.Domain.Apps.Core.Schemas.Json namespace Squidex.Domain.Apps.Core.Schemas.Json
@ -24,5 +26,58 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json
[JsonProperty] [JsonProperty]
public List<JsonFieldModel> Fields { get; set; } public List<JsonFieldModel> Fields { get; set; }
public JsonSchemaModel()
{
}
public JsonSchemaModel(Schema schema)
{
var model = new JsonSchemaModel { Name = schema.Name, IsPublished = schema.IsPublished, Properties = schema.Properties };
Fields =
schema.Fields.Select(x =>
new JsonFieldModel
{
Id = x.Id,
Name = x.Name,
IsHidden = x.IsHidden,
IsLocked = x.IsLocked,
IsDisabled = x.IsDisabled,
Partitioning = x.Partitioning.Key,
Properties = x.RawProperties
}).ToList();
}
public Schema ToSchema(FieldRegistry fieldRegistry)
{
var fields = Fields?.Select(fieldModel =>
{
var parititonKey = new Partitioning(fieldModel.Partitioning);
var field = fieldRegistry.CreateField(fieldModel.Id, fieldModel.Name, parititonKey, fieldModel.Properties);
if (fieldModel.IsDisabled)
{
field = field.Disable();
}
if (fieldModel.IsLocked)
{
field = field.Lock();
}
if (fieldModel.IsHidden)
{
field = field.Hide();
}
return field;
}).ToImmutableList() ?? ImmutableList<Field>.Empty;
var schema = new Schema(Name, IsPublished, Properties, fields);
return schema;
}
} }
} }

41
src/Squidex.Domain.Apps.Core/Schemas/Json/SchemaConverter.cs

@ -0,0 +1,41 @@
// ==========================================================================
// SchemaConverter.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Newtonsoft.Json;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Schemas.Json
{
public sealed class SchemaConverter : JsonConverter
{
private readonly FieldRegistry fieldRegistry;
public SchemaConverter(FieldRegistry fieldRegistry)
{
Guard.NotNull(fieldRegistry, nameof(fieldRegistry));
this.fieldRegistry = fieldRegistry;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, new JsonSchemaModel((Schema)value));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return serializer.Deserialize<JsonSchemaModel>(reader).ToSchema(fieldRegistry);
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Schema);
}
}
}

89
src/Squidex.Domain.Apps.Core/Schemas/Json/SchemaJsonSerializer.cs

@ -1,89 +0,0 @@
// ==========================================================================
// SchemaJsonSerializer.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Immutable;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Schemas.Json
{
public sealed class SchemaJsonSerializer
{
private readonly FieldRegistry fieldRegistry;
private readonly JsonSerializer serializer;
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 JsonSchemaModel { Name = schema.Name, IsPublished = schema.IsPublished, Properties = schema.Properties };
model.Fields =
schema.Fields.Select(x =>
new JsonFieldModel
{
Id = x.Id,
Name = x.Name,
IsHidden = x.IsHidden,
IsLocked = x.IsLocked,
IsDisabled = x.IsDisabled,
Partitioning = x.Partitioning.Key,
Properties = x.RawProperties
}).ToList();
return JToken.FromObject(model, serializer);
}
public Schema Deserialize(JToken token)
{
var model = token.ToObject<JsonSchemaModel>(serializer);
var fields =
model.Fields.Select(fieldModel =>
{
var parititonKey = new Partitioning(fieldModel.Partitioning);
var field = fieldRegistry.CreateField(fieldModel.Id, fieldModel.Name, parititonKey, fieldModel.Properties);
if (fieldModel.IsDisabled)
{
field = field.Disable();
}
if (fieldModel.IsLocked)
{
field = field.Lock();
}
if (fieldModel.IsHidden)
{
field = field.Hide();
}
return field;
}).ToImmutableList();
var schema =
new Schema(
model.Name,
model.IsPublished, model.Properties, fields);
return schema;
}
}
}

72
src/Squidex.Domain.Apps.Read.MongoDb/Contents/Extensions.cs

@ -0,0 +1,72 @@
// ==========================================================================
// Extensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Bson;
using Newtonsoft.Json.Linq;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure.MongoDb;
namespace Squidex.Domain.Apps.Read.MongoDb.Contents
{
public static class Extensions
{
private const int MaxLength = 1024 * 1024;
public static BsonDocument ToBsonDocument(this IdContentData data)
{
return (BsonDocument)JToken.FromObject(data).ToBson();
}
public static List<Guid> ToReferencedIds(this IdContentData data, Schema schema)
{
return data.GetReferencedIds(schema).ToList();
}
public static NamedContentData ToData(this BsonDocument document, Schema schema, List<Guid> deletedIds)
{
return document
.ToJson()
.ToObject<IdContentData>()
.ToCleanedReferences(schema, new HashSet<Guid>(deletedIds))
.ToNameModel(schema, true);
}
public static string ToFullText<T>(this ContentData<T> data)
{
var stringBuilder = new StringBuilder();
foreach (var text in data.Values.SelectMany(x => x.Values).Where(x => x != null).OfType<JValue>())
{
if (text.Type == JTokenType.String)
{
var value = text.ToString();
if (value.Length < 1000)
{
stringBuilder.Append(" ");
stringBuilder.Append(text);
}
}
}
var result = stringBuilder.ToString();
if (result.Length > MaxLength)
{
result = result.Substring(MaxLength);
}
return result;
}
}
}

83
src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentEntity.cs

@ -8,27 +8,22 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Bson.IO; using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using Newtonsoft.Json.Linq;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Read.Contents; using Squidex.Domain.Apps.Read.Contents;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.MongoDb;
using JsonConvert = Newtonsoft.Json.JsonConvert;
namespace Squidex.Domain.Apps.Read.MongoDb.Contents namespace Squidex.Domain.Apps.Read.MongoDb.Contents
{ {
public sealed class MongoContentEntity : IContentEntity, IMongoEntity public sealed class MongoContentEntity : IContentEntity, IMongoEntity
{ {
private const int MaxLength = 1024 * 1024;
private static readonly JsonWriterSettings Settings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict }; private static readonly JsonWriterSettings Settings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
private NamedContentData contentData; private NamedContentData data;
[BsonId] [BsonId]
[BsonElement] [BsonElement]
@ -74,7 +69,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
[BsonRequired] [BsonRequired]
[BsonElement("do")] [BsonElement("do")]
public BsonDocument DataObject { get; set; } public BsonDocument DataDocument { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement("rf")] [BsonElement("rf")]
@ -86,80 +81,22 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
NamedContentData IContentEntity.Data NamedContentData IContentEntity.Data
{ {
get get { return data; }
{
return contentData;
}
} }
public void ParseData(Schema schema) public void ParseData(Schema schema)
{ {
if (DataObject != null) data = DataDocument.ToData(schema, ReferencedIdsDeleted);
{
var jsonString = DataObject.ToJson(Settings);
contentData =
JsonConvert.DeserializeObject<IdContentData>(jsonString)
.ToCleanedReferences(schema, new HashSet<Guid>(ReferencedIdsDeleted))
.ToNameModel(schema, true);
}
else
{
contentData = null;
}
} }
public void SetData(Schema schema, NamedContentData newContentData) public void SetData(Schema schema, NamedContentData data)
{ {
if (newContentData != null) var idData = data?.ToIdModel(schema, true);
{
var idModel = newContentData.ToIdModel(schema, true);
var jsonString = JsonConvert.SerializeObject(idModel);
DataObject = BsonDocument.Parse(jsonString);
DataText = ExtractText(idModel);
ReferencedIds = idModel.GetReferencedIds(schema).ToList();
}
else
{
DataObject = null;
DataText = string.Empty;
}
}
private static string ExtractText(IdContentData data) DataText = idData?.ToFullText();
{ DataDocument = idData?.ToBsonDocument();
if (data == null)
{ ReferencedIds = idData?.ToReferencedIds(schema);
return string.Empty;
}
var stringBuilder = new StringBuilder();
foreach (var text in data.Values.SelectMany(x => x.Values).Where(x => x != null).OfType<JValue>())
{
if (text.Type == JTokenType.String)
{
var value = text.ToString();
if (value.Length < 1000)
{
stringBuilder.Append(" ");
stringBuilder.Append(text);
}
}
}
var result = stringBuilder.ToString();
if (result.Length > MaxLength)
{
result = result.Substring(MaxLength);
}
return result;
} }
} }
} }

26
src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository_EventHandling.cs

@ -85,10 +85,17 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
{ {
return ForSchemaAsync(@event.AppId.Id, @event.SchemaId.Id, (collection, schema) => return ForSchemaAsync(@event.AppId.Id, @event.SchemaId.Id, (collection, schema) =>
{ {
return collection.UpdateAsync(@event, headers, x => var idData = @event.Data.ToIdModel(schema.SchemaDef, true);
{
x.SetData(schema.SchemaDef, @event.Data); return collection.UpdateOneAsync(
}); Filter.Eq(x => x.Id, @event.ContentId),
Update
.Set(x => x.ReferencedIds, idData.ToReferencedIds(schema.SchemaDef))
.Set(x => x.DataText, idData.ToFullText())
.Set(x => x.DataDocument, idData.ToBsonDocument())
.Set(x => x.LastModified, headers.Timestamp())
.Set(x => x.LastModifiedBy, @event.Actor)
.Set(x => x.Version, headers.EventStreamNumber()));
}); });
} }
@ -96,10 +103,13 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
{ {
return ForAppIdAsync(@event.AppId.Id, collection => return ForAppIdAsync(@event.AppId.Id, collection =>
{ {
return collection.UpdateAsync(@event, headers, x => return collection.UpdateOneAsync(
{ Filter.Eq(x => x.Id, @event.ContentId),
x.Status = @event.Status; Update
}); .Set(x => x.Status, @event.Status)
.Set(x => x.LastModified, headers.Timestamp())
.Set(x => x.LastModifiedBy, @event.Actor)
.Set(x => x.Version, headers.EventStreamNumber()));
}); });
} }

41
src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaEntity.cs

@ -7,10 +7,10 @@
// ========================================================================== // ==========================================================================
using System; using System;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Schemas.Json;
using Squidex.Domain.Apps.Read.Schemas; using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.MongoDb;
@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
{ {
public sealed class MongoSchemaEntity : MongoEntity, ISchemaEntity public sealed class MongoSchemaEntity : MongoEntity, ISchemaEntity
{ {
private Lazy<Schema> schema; private Schema schema;
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
@ -27,7 +27,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
public string Schema { get; set; } public BsonDocument SchemaDocument { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
@ -73,31 +73,22 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
[BsonElement] [BsonElement]
public string ScriptChange { get; set; } public string ScriptChange { get; set; }
Schema ISchemaEntity.SchemaDef public Schema SchemaDef
{ {
get { return schema.Value; } get
} {
if (schema == null)
public void SerializeSchema(Schema newSchema, SchemaJsonSerializer serializer) {
{ schema = SchemaDocument.ToJson().ToObject<Schema>();
Schema = serializer.Serialize(newSchema).ToString(); }
schema = new Lazy<Schema>(() => newSchema);
IsPublished = newSchema.IsPublished;
}
public void UpdateSchema(SchemaJsonSerializer serializer, Func<Schema, Schema> updater)
{
DeserializeSchema(serializer);
SerializeSchema(updater(schema.Value), serializer);
}
public void DeserializeSchema(SchemaJsonSerializer serializer) return schema;
{ }
if (schema == null) set
{ {
schema = new Lazy<Schema>(() => Schema != null ? serializer.Deserialize(JObject.Parse(Schema)) : null); schema = value;
SchemaDocument = (BsonDocument)JToken.FromObject(schema).ToBson();
} }
} }
} }

13
src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository.cs

@ -12,7 +12,6 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Schemas.Json;
using Squidex.Domain.Apps.Read.Schemas; using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Domain.Apps.Read.Schemas.Repositories; using Squidex.Domain.Apps.Read.Schemas.Repositories;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -23,18 +22,14 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
{ {
public partial class MongoSchemaRepository : MongoRepositoryBase<MongoSchemaEntity>, ISchemaRepository, IEventConsumer public partial class MongoSchemaRepository : MongoRepositoryBase<MongoSchemaEntity>, ISchemaRepository, IEventConsumer
{ {
private readonly SchemaJsonSerializer serializer;
private readonly FieldRegistry registry; private readonly FieldRegistry registry;
public MongoSchemaRepository(IMongoDatabase database, SchemaJsonSerializer serializer, FieldRegistry registry) public MongoSchemaRepository(IMongoDatabase database, FieldRegistry registry)
: base(database) : base(database)
{ {
Guard.NotNull(registry, nameof(registry)); Guard.NotNull(registry, nameof(registry));
Guard.NotNull(serializer, nameof(serializer));
this.registry = registry; this.registry = registry;
this.serializer = serializer;
} }
protected override string CollectionName() protected override string CollectionName()
@ -55,8 +50,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
await Collection.Find(s => s.AppId == appId && !s.IsDeleted) await Collection.Find(s => s.AppId == appId && !s.IsDeleted)
.ToListAsync(); .ToListAsync();
schemaEntities.ForEach(x => x.DeserializeSchema(serializer));
return schemaEntities.OfType<ISchemaEntity>().ToList(); return schemaEntities.OfType<ISchemaEntity>().ToList();
} }
@ -66,8 +59,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
await Collection.Find(s => s.AppId == appId && !s.IsDeleted && s.Name == name) await Collection.Find(s => s.AppId == appId && !s.IsDeleted && s.Name == name)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
schemaEntity?.DeserializeSchema(serializer);
return schemaEntity; return schemaEntity;
} }
@ -77,8 +68,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
await Collection.Find(s => s.Id == schemaId) await Collection.Find(s => s.Id == schemaId)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
schemaEntity?.DeserializeSchema(serializer);
return schemaEntity; return schemaEntity;
} }
} }

24
src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs

@ -18,6 +18,8 @@ using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Dispatching; using Squidex.Infrastructure.Dispatching;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
#pragma warning disable CS0612 // Type or member is obsolete
namespace Squidex.Domain.Apps.Read.MongoDb.Schemas namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
{ {
public partial class MongoSchemaRepository public partial class MongoSchemaRepository
@ -114,31 +116,29 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
return Collection.UpdateAsync(@event, headers, e => e.IsDeleted = true); return Collection.UpdateAsync(@event, headers, e => e.IsDeleted = true);
} }
private Task UpdateSchema(SquidexEvent @event, EnvelopeHeaders headers, Func<Schema, Schema> updater) protected Task On(WebhookAdded @event, EnvelopeHeaders headers)
{ {
return Collection.UpdateAsync(@event, headers, e => UpdateSchema(e, updater)); return Collection.UpdateAsync(@event, headers, e => { });
} }
private void UpdateSchema(MongoSchemaEntity entity, Func<Schema, Schema> updater) protected Task On(WebhookDeleted @event, EnvelopeHeaders headers)
{ {
entity.UpdateSchema(serializer, updater); return Collection.UpdateAsync(@event, headers, e => { });
} }
private void UpdateSchema(MongoSchemaEntity entity, Schema schema) private Task UpdateSchema(SquidexEvent @event, EnvelopeHeaders headers, Func<Schema, Schema> updater)
{ {
entity.SerializeSchema(schema, serializer); return Collection.UpdateAsync(@event, headers, e => UpdateSchema(e, updater));
} }
#pragma warning disable CS0612 // Type or member is obsolete private void UpdateSchema(MongoSchemaEntity entity, Func<Schema, Schema> updater)
protected Task On(WebhookAdded @event, EnvelopeHeaders headers)
{ {
return Collection.UpdateAsync(@event, headers, e => { }); entity.SchemaDef = updater(entity.SchemaDef);
} }
protected Task On(WebhookDeleted @event, EnvelopeHeaders headers) private void UpdateSchema(MongoSchemaEntity entity, Schema schema)
{ {
return Collection.UpdateAsync(@event, headers, e => { }); entity.SchemaDef = schema;
} }
#pragma warning restore CS0612 // Type or member is obsolete
} }
} }

109
src/Squidex.Infrastructure.MongoDb/MongoDb/BsonConverter.cs

@ -0,0 +1,109 @@
// ==========================================================================
// BsonConverter.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using MongoDB.Bson;
using Newtonsoft.Json.Linq;
namespace Squidex.Infrastructure.MongoDb
{
public static class BsonConverter
{
public static BsonDocument ToBson(this JObject source)
{
var result = new BsonDocument();
foreach (var property in source)
{
result.Add(property.Key, property.Value.ToBson());
}
return result;
}
public static JObject ToJson(this BsonDocument source)
{
var result = new JObject();
foreach (var property in source)
{
result.Add(property.Name, property.Value.ToJson());
}
return result;
}
public static BsonArray ToBson(this JArray source)
{
var result = new BsonArray();
foreach (var item in source)
{
result.Add(item.ToBson());
}
return result;
}
public static JArray ToJson(this BsonArray source)
{
var result = new JArray();
foreach (var item in source)
{
result.Add(item.ToJson());
}
return result;
}
public static BsonValue ToBson(this JToken source)
{
switch (source)
{
case JObject jObject:
return jObject.ToBson();
case JArray jArray:
return jArray.ToBson();
case JValue jValue:
return BsonValue.Create(jValue.Value);
}
throw new NotSupportedException($"Cannot convert {source.GetType()} to Bson.");
}
public static JToken ToJson(this BsonValue source)
{
switch (source.BsonType)
{
case BsonType.Document:
return source.AsBsonDocument.ToJson();
case BsonType.Array:
return source.AsBsonArray.ToJson();
case BsonType.Double:
return new JValue(source.AsDouble);
case BsonType.String:
return new JValue(source.AsString);
case BsonType.Boolean:
return new JValue(source.AsBoolean);
case BsonType.DateTime:
return new JValue(source.ToUniversalTime());
case BsonType.Int32:
return new JValue(source.AsInt32);
case BsonType.Int64:
return new JValue(source.AsInt64);
case BsonType.Decimal128:
return new JValue(source.AsDecimal);
case BsonType.Null:
return JValue.CreateNull();
}
throw new NotSupportedException($"Cannot convert {source.GetType()} to Json.");
}
}
}

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

@ -153,10 +153,6 @@ namespace Squidex.Config.Domain
.AsSelf() .AsSelf()
.SingleInstance(); .SingleInstance();
builder.RegisterType<SchemaJsonSerializer>()
.AsSelf()
.SingleInstance();
builder.RegisterType<FieldRegistry>() builder.RegisterType<FieldRegistry>()
.AsSelf() .AsSelf()
.SingleInstance(); .SingleInstance();

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

@ -12,6 +12,8 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Converters;
using NodaTime; using NodaTime;
using NodaTime.Serialization.JsonNet; using NodaTime.Serialization.JsonNet;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Schemas.Json;
using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events; using Squidex.Infrastructure.CQRS.Events;
@ -35,6 +37,7 @@ namespace Squidex.Config.Domain
new NamedStringIdConverter(), new NamedStringIdConverter(),
new PropertiesBagConverter(), new PropertiesBagConverter(),
new RefTokenConverter(), new RefTokenConverter(),
new SchemaConverter(new FieldRegistry(TypeNameRegistry)),
new StringEnumConverter()); new StringEnumConverter());
settings.NullValueHandling = NullValueHandling.Ignore; settings.NullValueHandling = NullValueHandling.Ignore;
@ -46,6 +49,8 @@ namespace Squidex.Config.Domain
settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
JsonConvert.DefaultSettings = () => settings;
return settings; return settings;
} }

16
tests/Squidex.Domain.Apps.Core.Tests/Schemas/Json/JsonSerializerTests.cs

@ -10,6 +10,7 @@ using System;
using System.Collections.Immutable; using System.Collections.Immutable;
using FluentAssertions; using FluentAssertions;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json;
using Xunit; using Xunit;
@ -20,14 +21,12 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json
{ {
private readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings(); private readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry(); private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry();
private readonly SchemaJsonSerializer sut;
public JsonSerializerTests() public JsonSerializerTests()
{ {
serializerSettings.TypeNameHandling = TypeNameHandling.Auto; serializerSettings.TypeNameHandling = TypeNameHandling.Auto;
serializerSettings.SerializationBinder = new TypeNameSerializationBinder(typeNameRegistry); serializerSettings.SerializationBinder = new TypeNameSerializationBinder(typeNameRegistry);
serializerSettings.Converters.Add(new SchemaConverter(new FieldRegistry(typeNameRegistry)));
sut = new SchemaJsonSerializer(new FieldRegistry(typeNameRegistry), serializerSettings);
} }
[Fact] [Fact]
@ -36,9 +35,9 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json
var schema = var schema =
Schema.Create("user", new SchemaProperties { Hints = "The User" }) Schema.Create("user", new SchemaProperties { Hints = "The User" })
.AddField(new JsonField(1, "my-json", Partitioning.Invariant, .AddField(new JsonField(1, "my-json", Partitioning.Invariant,
new JsonFieldProperties())) new JsonFieldProperties())).HideField(1)
.AddField(new AssetsField(2, "my-assets", Partitioning.Invariant, .AddField(new AssetsField(2, "my-assets", Partitioning.Invariant,
new AssetsFieldProperties())) new AssetsFieldProperties())).LockField(2)
.AddField(new StringField(3, "my-string1", Partitioning.Language, .AddField(new StringField(3, "my-string1", Partitioning.Language,
new StringFieldProperties { Label = "My String1", IsRequired = true, AllowedValues = ImmutableList.Create("a", "b") })) new StringFieldProperties { Label = "My String1", IsRequired = true, AllowedValues = ImmutableList.Create("a", "b") }))
.AddField(new StringField(4, "my-string2", Partitioning.Invariant, .AddField(new StringField(4, "my-string2", Partitioning.Invariant,
@ -46,7 +45,7 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json
.AddField(new NumberField(5, "my-number", Partitioning.Invariant, .AddField(new NumberField(5, "my-number", Partitioning.Invariant,
new NumberFieldProperties { MinValue = 1, MaxValue = 10 })) new NumberFieldProperties { MinValue = 1, MaxValue = 10 }))
.AddField(new BooleanField(6, "my-boolean", Partitioning.Invariant, .AddField(new BooleanField(6, "my-boolean", Partitioning.Invariant,
new BooleanFieldProperties())) new BooleanFieldProperties())).DisableField(3)
.AddField(new DateTimeField(7, "my-datetime", Partitioning.Invariant, .AddField(new DateTimeField(7, "my-datetime", Partitioning.Invariant,
new DateTimeFieldProperties { Editor = DateTimeFieldEditor.DateTime })) new DateTimeFieldProperties { Editor = DateTimeFieldEditor.DateTime }))
.AddField(new DateTimeField(8, "my-date", Partitioning.Invariant, .AddField(new DateTimeField(8, "my-date", Partitioning.Invariant,
@ -55,12 +54,9 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json
new ReferencesFieldProperties { SchemaId = Guid.NewGuid() })) new ReferencesFieldProperties { SchemaId = Guid.NewGuid() }))
.AddField(new GeolocationField(10, "my-geolocation", Partitioning.Invariant, .AddField(new GeolocationField(10, "my-geolocation", Partitioning.Invariant,
new GeolocationFieldProperties())) new GeolocationFieldProperties()))
.HideField(1)
.LockField(2)
.DisableField(3)
.Publish(); .Publish();
var deserialized = sut.Deserialize(sut.Serialize(schema)); var deserialized = JToken.FromObject(schema).ToObject<Schema>();
deserialized.ShouldBeEquivalentTo(schema); deserialized.ShouldBeEquivalentTo(schema);
} }

Loading…
Cancel
Save