From 255aeeb056d6f47a413096c9f1c5ffe82d0b6b90 Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 18 May 2023 01:58:18 +0100 Subject: [PATCH 01/24] - checkin - 01 --- .merge_file_6QqZc3 | 27 ++++++++++ .merge_file_MaViKi | 11 ++++ src/Schemio.Object/BaseEntity.cs | 9 ++++ src/Schemio.Object/BaseQuery.cs | 54 +++++++++++++++++++ src/Schemio.Object/BaseTransformer.cs | 21 ++++++++ src/Schemio.Object/IDataContext.cs | 2 +- src/Schemio.Object/IEntity.cs | 2 +- src/Schemio.Object/IEntitySchema.cs | 4 +- src/Schemio.Object/IQuery.cs | 6 +-- src/Schemio.Object/IQueryParameter.cs | 6 +++ src/Schemio.Object/ITransformExecutor.cs | 4 +- src/Schemio.Object/ITransformer.cs | 23 +++++--- src/Schemio.Object/Impl/EventSubscriber.cs | 4 +- src/Schemio.Object/Impl/QueryBuilder.cs | 6 +-- src/Schemio.Object/Impl/TransformExecutor.cs | 4 +- src/Schemio.Object/QueryList.cs | 7 +-- .../DataProvider/CustomerContext.cs | 11 ++++ .../Schemio.Object.Tests/Entities/Address.cs | 12 +++++ .../Schemio.Object.Tests/Entities/Customer.cs | 13 +++++ .../Entities/EmailAddress.cs | 8 +++ .../Entities/Ethnicity.cs | 8 +++ tests/Schemio.Object.Tests/Entities/Order.cs | 10 ++++ .../Entities/OrderItem.cs | 9 ++++ tests/Schemio.Object.Tests/Entities/Person.cs | 9 ++++ .../Entities/PhoneNumber.cs | 8 +++ .../EntitySchemas/CustomerSchema.cs | 22 ++++++++ .../Queries/AddressQuery.cs | 31 +++++++++++ .../Queries/CustomerQuery.cs | 35 ++++++++++++ .../Queries/EmailAddressQuery.cs | 28 ++++++++++ .../Queries/EthnicityQuery.cs | 28 ++++++++++ .../Queries/OrderItemQuery.cs | 34 ++++++++++++ .../Queries/OrderQuery.cs | 30 +++++++++++ .../Queries/PersonQuery.cs | 34 ++++++++++++ .../Queries/PhoneNumberQuery.cs | 28 ++++++++++ .../Schemio.Object.Tests.csproj | 7 +-- .../Transforms/CustomerTransform.cs | 16 ++++++ 36 files changed, 540 insertions(+), 31 deletions(-) create mode 100644 .merge_file_6QqZc3 create mode 100644 .merge_file_MaViKi create mode 100644 src/Schemio.Object/BaseEntity.cs create mode 100644 src/Schemio.Object/BaseQuery.cs create mode 100644 src/Schemio.Object/BaseTransformer.cs create mode 100644 src/Schemio.Object/IQueryParameter.cs create mode 100644 tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs create mode 100644 tests/Schemio.Object.Tests/Entities/Address.cs create mode 100644 tests/Schemio.Object.Tests/Entities/Customer.cs create mode 100644 tests/Schemio.Object.Tests/Entities/EmailAddress.cs create mode 100644 tests/Schemio.Object.Tests/Entities/Ethnicity.cs create mode 100644 tests/Schemio.Object.Tests/Entities/Order.cs create mode 100644 tests/Schemio.Object.Tests/Entities/OrderItem.cs create mode 100644 tests/Schemio.Object.Tests/Entities/Person.cs create mode 100644 tests/Schemio.Object.Tests/Entities/PhoneNumber.cs create mode 100644 tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs create mode 100644 tests/Schemio.Object.Tests/Queries/AddressQuery.cs create mode 100644 tests/Schemio.Object.Tests/Queries/CustomerQuery.cs create mode 100644 tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs create mode 100644 tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs create mode 100644 tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs create mode 100644 tests/Schemio.Object.Tests/Queries/OrderQuery.cs create mode 100644 tests/Schemio.Object.Tests/Queries/PersonQuery.cs create mode 100644 tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs create mode 100644 tests/Schemio.Object.Tests/Transforms/CustomerTransform.cs diff --git a/.merge_file_6QqZc3 b/.merge_file_6QqZc3 new file mode 100644 index 0000000..4d140f4 --- /dev/null +++ b/.merge_file_6QqZc3 @@ -0,0 +1,27 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + + + + + + + + + + + diff --git a/.merge_file_MaViKi b/.merge_file_MaViKi new file mode 100644 index 0000000..8e7183f --- /dev/null +++ b/.merge_file_MaViKi @@ -0,0 +1,11 @@ + + + + netstandard2.1 + + + + + + + diff --git a/src/Schemio.Object/BaseEntity.cs b/src/Schemio.Object/BaseEntity.cs new file mode 100644 index 0000000..cb49c08 --- /dev/null +++ b/src/Schemio.Object/BaseEntity.cs @@ -0,0 +1,9 @@ +using Schemio.Data.Core; + +namespace Schemio.Object.Tests.Entities +{ + public class BaseEntity : IEntity + { + public decimal Version { get; set; } = 1; + } +} \ No newline at end of file diff --git a/src/Schemio.Object/BaseQuery.cs b/src/Schemio.Object/BaseQuery.cs new file mode 100644 index 0000000..1f2e212 --- /dev/null +++ b/src/Schemio.Object/BaseQuery.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; + +namespace Schemio.Data.Core +{ + /// + /// Implement this base class to create a data provider query. + /// + /// + /// + public abstract class BaseQuery : IQuery + where TQueryParameter : IQueryParameter + where TQueryResult : IQueryResult + { + /// + /// Parameter values for query to execute. + /// + protected IQueryParameter QueryParameter; + + /// + /// Children queries of this query. + /// + public List Children { get; set; } + + /// + /// Get the result type for the query + /// + public Type GetResultType + { + get { return typeof(TQueryResult); } + } + + /// + /// Determines whether the parameter for query is resolved. + /// + /// + public bool IsContextResolved() => QueryParameter != null; + + /// + /// Override this method to resolve query parameter to execute query in parent mode. + /// + /// DataContext object passed to dataprovider. + public virtual void ResolveRootQueryParameter(IDataContext context) + { } + + /// + /// Override this method to resolve query parameter to execute query in child mode to a parent query. + /// + /// DataContext object passed to dataprovider. + /// Query result of parent query. + public virtual void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + { } + } +} \ No newline at end of file diff --git a/src/Schemio.Object/BaseTransformer.cs b/src/Schemio.Object/BaseTransformer.cs new file mode 100644 index 0000000..ce94180 --- /dev/null +++ b/src/Schemio.Object/BaseTransformer.cs @@ -0,0 +1,21 @@ +using Schemio.Data.Core; + +namespace Schemio.Object +{ + public abstract class BaseTransformer : ITransformer, IEntityTransform + where TQueryResult : IQueryResult + where TEntity : IEntity + { + public IDataContext Context { get; private set; } + + public void ResolveContext(IDataContext context) => Context = context; + + public TEntity Run(TQueryResult queryResult, TEntity entity) + { + return queryResult.GetType() == typeof(TQueryResult) || queryResult is TQueryResult + ? Transform((TQueryResult)queryResult, entity) : entity; + } + + public abstract TEntity Transform(TQueryResult queryResult, TEntity entity); + } +} \ No newline at end of file diff --git a/src/Schemio.Object/IDataContext.cs b/src/Schemio.Object/IDataContext.cs index 2527a7b..0eacc1f 100644 --- a/src/Schemio.Object/IDataContext.cs +++ b/src/Schemio.Object/IDataContext.cs @@ -3,6 +3,6 @@ namespace Schemio.Data.Core public interface IDataContext { public string[] Paths { get; set; } - string CurrentVersion { get; } + decimal CurrentVersion { get; } } } \ No newline at end of file diff --git a/src/Schemio.Object/IEntity.cs b/src/Schemio.Object/IEntity.cs index 8e7310b..afcb8b6 100644 --- a/src/Schemio.Object/IEntity.cs +++ b/src/Schemio.Object/IEntity.cs @@ -1,7 +1,7 @@ namespace Schemio.Data.Core { /// - /// Implement Entity required to be hydrated (with data using query/transformer). + /// Implement Entity required to be hydrated (using query/transformer). /// public interface IEntity { diff --git a/src/Schemio.Object/IEntitySchema.cs b/src/Schemio.Object/IEntitySchema.cs index 885b45b..38a34cb 100644 --- a/src/Schemio.Object/IEntitySchema.cs +++ b/src/Schemio.Object/IEntitySchema.cs @@ -6,9 +6,9 @@ namespace Schemio.Data.Core /// Implement to configure entity schema path mappings (using Query/Trasformer pairs). /// /// - public interface IEntitySchema where T : IEntity + public interface IEntitySchema where TEntity : IEntity { - IEnumerable> Mappings { get; } + IEnumerable> Mappings { get; } decimal Version { get; } } } \ No newline at end of file diff --git a/src/Schemio.Object/IQuery.cs b/src/Schemio.Object/IQuery.cs index e8f8c8c..28997d8 100644 --- a/src/Schemio.Object/IQuery.cs +++ b/src/Schemio.Object/IQuery.cs @@ -8,13 +8,13 @@ namespace Schemio.Data.Core /// public interface IQuery { - List ChildQueries { get; set; } + List Children { get; set; } Type GetResultType { get; } - void ResolveContextAsPrimary(IDataContext context); + void ResolveRootQueryParameter(IDataContext context); - void ResolveContextAsChild(IDataContext context, IQueryResult parentQueryResult); + void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult); bool IsContextResolved(); } diff --git a/src/Schemio.Object/IQueryParameter.cs b/src/Schemio.Object/IQueryParameter.cs new file mode 100644 index 0000000..6ac4932 --- /dev/null +++ b/src/Schemio.Object/IQueryParameter.cs @@ -0,0 +1,6 @@ +namespace Schemio.Data.Core +{ + public interface IQueryParameter + { + } +} \ No newline at end of file diff --git a/src/Schemio.Object/ITransformExecutor.cs b/src/Schemio.Object/ITransformExecutor.cs index 58d2c02..7117297 100644 --- a/src/Schemio.Object/ITransformExecutor.cs +++ b/src/Schemio.Object/ITransformExecutor.cs @@ -2,8 +2,8 @@ namespace Schemio.Data.Core { - public interface ITransformExecutor where T : IEntity + public interface ITransformExecutor where TEntity : IEntity { - T Execute(IDataContext context, IList dtos); + TEntity Execute(IDataContext context, IList results); } } \ No newline at end of file diff --git a/src/Schemio.Object/ITransformer.cs b/src/Schemio.Object/ITransformer.cs index f2b1b42..6cf662c 100644 --- a/src/Schemio.Object/ITransformer.cs +++ b/src/Schemio.Object/ITransformer.cs @@ -3,14 +3,23 @@ namespace Schemio.Data.Core /// /// Implement transformer to map data to entity using query result. /// - /// - /// - public interface ITransformer - where TR : IQueryResult - where T : IEntity + /// + /// + public interface ITransformer + where TQueryResult : IQueryResult + where TEntity : IEntity { - void ResovleContext(IDataContext context); + IDataContext Context { get; } - T TransformToDataEntity(TR queryResult, T entity); + void ResolveContext(IDataContext context); + + TEntity Run(TQueryResult queryResult, TEntity entity); + } + + internal interface IEntityTransform + where TQueryResult : IQueryResult + where TEntity : IEntity + { + TEntity Transform(TQueryResult queryResult, TEntity entity); } } \ No newline at end of file diff --git a/src/Schemio.Object/Impl/EventSubscriber.cs b/src/Schemio.Object/Impl/EventSubscriber.cs index 4f61bc3..34d3b73 100644 --- a/src/Schemio.Object/Impl/EventSubscriber.cs +++ b/src/Schemio.Object/Impl/EventSubscriber.cs @@ -33,7 +33,7 @@ public void OnEventHandler(IDataContext context, ExecutorResultArgs args) foreach (var query in unresolved.Queries) { - query.ResolveContextAsChild(context, queryResult); + query.ResolveChildQueryParameter(context, queryResult); } } } @@ -55,7 +55,7 @@ public void OnEventHandler(IDataContext context, ExecutorResultArgs args) foreach (var query in unresolved.Queries) { - query.ResolveContextAsChild(context, queryResult); + query.ResolveChildQueryParameter(context, queryResult); } } } diff --git a/src/Schemio.Object/Impl/QueryBuilder.cs b/src/Schemio.Object/Impl/QueryBuilder.cs index 0ca15d9..1974049 100644 --- a/src/Schemio.Object/Impl/QueryBuilder.cs +++ b/src/Schemio.Object/Impl/QueryBuilder.cs @@ -24,7 +24,7 @@ public IQueryList Build(IDataContext context) var queries = GetMappedQueries(entitySchema.Mappings.ToList(), context); foreach (var query in queries.Queries) - query.ResolveContextAsPrimary(context); + query.ResolveRootQueryParameter(context); return new QueryList(queries.Queries); } @@ -42,9 +42,9 @@ private QueryList GetMappedQueries(IReadOnlyCollection> var dependentQueries = mappings.Where(x => x.Order == (index + 1) && x.DependentOn != null && x.DependentOn.GetType() == map.Query.GetType()).ToList(); - map.Query.ChildQueries ??= new List(); + map.Query.Children ??= new List(); - map.Query.ChildQueries.AddRange(FilterByPaths(context, dependentQueries)); + map.Query.Children.AddRange(FilterByPaths(context, dependentQueries)); } } diff --git a/src/Schemio.Object/Impl/TransformExecutor.cs b/src/Schemio.Object/Impl/TransformExecutor.cs index c834853..2dcd4a8 100644 --- a/src/Schemio.Object/Impl/TransformExecutor.cs +++ b/src/Schemio.Object/Impl/TransformExecutor.cs @@ -28,7 +28,7 @@ public T Execute(IDataContext context, IList queryResults) var mappings = entitySchemaMapping.Mappings.ToList(); // resolve context of each transformer so it is available inside for transformation if required. - mappings.ForEach(mapping => mapping.Transformer.ResovleContext(context)); + mappings.ForEach(mapping => mapping.Transformer.ResolveContext(context)); var queryDependencyDepth = mappings.Max(x => x.Order); @@ -42,7 +42,7 @@ public T Execute(IDataContext context, IList queryResults) .ToList(); foreach (var queryResult in queryResults) - transformers.ForEach(transformer => transformer.TransformToDataEntity(queryResult, entity)); + transformers.ForEach(transformer => transformer.Run(queryResult, entity)); } return entity; diff --git a/src/Schemio.Object/QueryList.cs b/src/Schemio.Object/QueryList.cs index 088fb73..b83371d 100644 --- a/src/Schemio.Object/QueryList.cs +++ b/src/Schemio.Object/QueryList.cs @@ -1,18 +1,19 @@ using System.Collections.Generic; using System.Linq; - namespace Schemio.Data.Core { public class QueryList : IQueryList { private readonly List queryList; + public QueryList() { queryList = new List(); } - public IEnumerable Queries { get { return queryList; } } + public IEnumerable Queries + { get { return queryList; } } public QueryList(IEnumerable collection) { @@ -32,7 +33,7 @@ public IQueryList GetByType() where T : class public List GetChildrenQueries() { var childrenQueries = queryList - .Select(x => new ChildrenQueries { ParentQueryResultType = x.GetResultType, Queries = x.ChildQueries }) + .Select(x => new ChildrenQueries { ParentQueryResultType = x.GetResultType, Queries = x.Children }) .Where(x => x.Queries.Any()) .ToList(); diff --git a/tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs b/tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs new file mode 100644 index 0000000..cdcfcbc --- /dev/null +++ b/tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs @@ -0,0 +1,11 @@ +using Schemio.Data.Core; + +namespace Schemio.Object.Tests.DataProvider +{ + internal class CustomerContext : IDataContext + { + public string[] Paths { get; set; } + public decimal CurrentVersion => 1; + public int CustomerId { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/Address.cs b/tests/Schemio.Object.Tests/Entities/Address.cs new file mode 100644 index 0000000..7a57ebd --- /dev/null +++ b/tests/Schemio.Object.Tests/Entities/Address.cs @@ -0,0 +1,12 @@ +namespace Schemio.Object.Tests.Entities +{ + internal class Address : BaseEntity + { + public int Id { get; set; } + public string HouseNo { get; set; } + public string City { get; set; } + public string Region { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/Customer.cs b/tests/Schemio.Object.Tests/Entities/Customer.cs new file mode 100644 index 0000000..162d189 --- /dev/null +++ b/tests/Schemio.Object.Tests/Entities/Customer.cs @@ -0,0 +1,13 @@ +namespace Schemio.Object.Tests.Entities +{ + internal class Customer : BaseEntity + { + public int Id { get; set; } + public string CustomerCode { get; set; } + public Person Person { get; set; } + public Address Address { get; set; } + public PhoneNumber PhoneNumber { get; set; } + public EmailAddress EmailAddress { get; set; } + public Order[] Orders { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/EmailAddress.cs b/tests/Schemio.Object.Tests/Entities/EmailAddress.cs new file mode 100644 index 0000000..333e26d --- /dev/null +++ b/tests/Schemio.Object.Tests/Entities/EmailAddress.cs @@ -0,0 +1,8 @@ +namespace Schemio.Object.Tests.Entities +{ + internal class EmailAddress : BaseEntity + { + public int Id { get; set; } + public string Email { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/Ethnicity.cs b/tests/Schemio.Object.Tests/Entities/Ethnicity.cs new file mode 100644 index 0000000..99001c5 --- /dev/null +++ b/tests/Schemio.Object.Tests/Entities/Ethnicity.cs @@ -0,0 +1,8 @@ +namespace Schemio.Object.Tests.Entities +{ + internal class Ethnicity : BaseEntity + { + public int Id { get; set; } + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/Order.cs b/tests/Schemio.Object.Tests/Entities/Order.cs new file mode 100644 index 0000000..484e14a --- /dev/null +++ b/tests/Schemio.Object.Tests/Entities/Order.cs @@ -0,0 +1,10 @@ +namespace Schemio.Object.Tests.Entities +{ + public class Order + { + public int Id { get; set; } + public string OrderNo { get; set; } + public DateTime Date { get; set; } + public OrderItem[] Items { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/OrderItem.cs b/tests/Schemio.Object.Tests/Entities/OrderItem.cs new file mode 100644 index 0000000..b755ce3 --- /dev/null +++ b/tests/Schemio.Object.Tests/Entities/OrderItem.cs @@ -0,0 +1,9 @@ +namespace Schemio.Object.Tests.Entities +{ + public class OrderItem + { + public int Id { get; set; } + public string Name { get; set; } + public decimal Cost { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/Person.cs b/tests/Schemio.Object.Tests/Entities/Person.cs new file mode 100644 index 0000000..5bd952a --- /dev/null +++ b/tests/Schemio.Object.Tests/Entities/Person.cs @@ -0,0 +1,9 @@ +namespace Schemio.Object.Tests.Entities +{ + internal class Person : BaseEntity + { + public int Id { get; set; } + public string Name { get; set; } + public Ethnicity Ethnicity { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/PhoneNumber.cs b/tests/Schemio.Object.Tests/Entities/PhoneNumber.cs new file mode 100644 index 0000000..ec16562 --- /dev/null +++ b/tests/Schemio.Object.Tests/Entities/PhoneNumber.cs @@ -0,0 +1,8 @@ +namespace Schemio.Object.Tests.Entities +{ + internal class PhoneNumber : BaseEntity + { + public int Id { get; set; } + public string Phone { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs b/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs new file mode 100644 index 0000000..467a6c4 --- /dev/null +++ b/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs @@ -0,0 +1,22 @@ +using Schemio.Data.Core; +using Schemio.Object.Tests.Entities; + +namespace Schemio.Object.Tests.EntitySchemas +{ + internal class CustomerSchema : IEntitySchema + { + public IEnumerable> Mappings { get; } + public decimal Version => 1; + + public CustomerSchema() + { + //Mappings = CreateSchema.For() + // .Map(For.Paths("clients/common/context"), dependantQuery => + // dependantQuery.Dependents + // .Map(For.XPath("clients/common/context/currentuserdetails/groupdetails/organisationlogo")) + // .Map(For.XPath("clients/common/context/currentuserdetails/groupdetails/grouplogo")) + // .Map(For.XPath("clients/common/context/currentuserdetails/photo")) + // ); + } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/AddressQuery.cs b/tests/Schemio.Object.Tests/Queries/AddressQuery.cs new file mode 100644 index 0000000..2d593c8 --- /dev/null +++ b/tests/Schemio.Object.Tests/Queries/AddressQuery.cs @@ -0,0 +1,31 @@ +using Schemio.Data.Core; + +namespace Schemio.Object.Tests.Queries +{ + internal class AddressQuery : BaseQuery + { + public override void ResolveRootQueryParameter(IDataContext context) + { + // Does not execute as root or level 1 queries. + } + + public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + { + // Execute as child to customer query. + var customer = (CustomerResult)parentQueryResult; + QueryParameter = new CustomerParameter + { + CustomerId = customer.Id + }; + } + } + + internal class AddressResult : IQueryResult + { + public string HouseNo { get; set; } + public string City { get; set; } + public string Region { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs b/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs new file mode 100644 index 0000000..5a859c1 --- /dev/null +++ b/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs @@ -0,0 +1,35 @@ +using Schemio.Data.Core; +using Schemio.Object.Tests.DataProvider; + +namespace Schemio.Object.Tests.Queries +{ + internal class CustomerQuery : BaseQuery + { + public override void ResolveRootQueryParameter(IDataContext context) + { + // Executes as root or level 1 query. + var customer = (CustomerContext)context; + QueryParameter = new CustomerParameter + { + CustomerId = customer.CustomerId + }; + } + + public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + { + // Does not execute as child to any query. + } + } + + internal class CustomerResult : IQueryResult + { + public int Id { get; set; } + public string CustomerCode { get; set; } + public int PersonId { get; set; } + } + + internal class CustomerParameter : IQueryParameter + { + public int CustomerId { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs b/tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs new file mode 100644 index 0000000..bbd7835 --- /dev/null +++ b/tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs @@ -0,0 +1,28 @@ +using Schemio.Data.Core; + +namespace Schemio.Object.Tests.Queries +{ + internal class EmailAddressQuery : BaseQuery + { + public override void ResolveRootQueryParameter(IDataContext context) + { + // Does not execute as root or level 1 queries. + } + + public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + { + // Execute as child to customer query. + var customer = (CustomerResult)parentQueryResult; + QueryParameter = new CustomerParameter + { + CustomerId = customer.Id + }; + } + } + + internal class EmailAddressResult : IQueryResult + { + public int Id { get; set; } + public string Email { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs b/tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs new file mode 100644 index 0000000..b1d0239 --- /dev/null +++ b/tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs @@ -0,0 +1,28 @@ +using Schemio.Data.Core; + +namespace Schemio.Object.Tests.Queries +{ + internal class EthnicityQuery : BaseQuery + { + public override void ResolveRootQueryParameter(IDataContext context) + { + // Does not execute as root or level 1 queries. + } + + public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + { + // Execute as child to person query. + var person = (PersonResult)parentQueryResult; + QueryParameter = new PersonParameter + { + PersonId = person.Id + }; + } + } + + internal class EthnicityResult : IQueryResult + { + public int Id { get; set; } + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs b/tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs new file mode 100644 index 0000000..409cf0a --- /dev/null +++ b/tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs @@ -0,0 +1,34 @@ +using Schemio.Data.Core; + +namespace Schemio.Object.Tests.Queries +{ + internal class OrderItemQuery : BaseQuery + { + public override void ResolveRootQueryParameter(IDataContext context) + { + // Does not execute as root or level 1 queries. + } + + public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + { + // Execute as child to order query. + var order = (OrderResult)parentQueryResult; + QueryParameter = new OrderItemParameter + { + OrderId = order.Id + }; + } + } + + internal class OrderItemResult : IQueryResult + { + public int Id { get; set; } + public string Name { get; set; } + public decimal Cost { get; set; } + } + + internal class OrderItemParameter : IQueryParameter + { + public int OrderId { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/OrderQuery.cs b/tests/Schemio.Object.Tests/Queries/OrderQuery.cs new file mode 100644 index 0000000..25acce6 --- /dev/null +++ b/tests/Schemio.Object.Tests/Queries/OrderQuery.cs @@ -0,0 +1,30 @@ +using Schemio.Data.Core; +using Schemio.Object.Tests.DataProvider; + +namespace Schemio.Object.Tests.Queries +{ + internal class OrderQuery : BaseQuery + { + public override void ResolveRootQueryParameter(IDataContext context) + { + // Executes as root or level 1 query. + var customer = (CustomerContext)context; + QueryParameter = new CustomerParameter + { + CustomerId = customer.CustomerId + }; + } + + public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + { + // Does not execute as child to any query. + } + } + + internal class OrderResult : IQueryResult + { + public int Id { get; set; } + public string OrderNo { get; set; } + public DateTime Date { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/PersonQuery.cs b/tests/Schemio.Object.Tests/Queries/PersonQuery.cs new file mode 100644 index 0000000..7302001 --- /dev/null +++ b/tests/Schemio.Object.Tests/Queries/PersonQuery.cs @@ -0,0 +1,34 @@ +using Schemio.Data.Core; + +namespace Schemio.Object.Tests.Queries +{ + internal class PersonQuery : BaseQuery + { + public override void ResolveRootQueryParameter(IDataContext context) + { + // Does not execute as root or level 1 queries. + } + + public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + { + // Execute as child to customer query. + var customer = (CustomerResult)parentQueryResult; + QueryParameter = new PersonParameter + { + PersonId = customer.PersonId + }; + } + } + + internal class PersonResult : IQueryResult + { + public int Id { get; set; } + public string Name { get; set; } + public int EthnicityId { get; set; } + } + + internal class PersonParameter : IQueryParameter + { + public int PersonId { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs b/tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs new file mode 100644 index 0000000..bcd4d6f --- /dev/null +++ b/tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs @@ -0,0 +1,28 @@ +using Schemio.Data.Core; + +namespace Schemio.Object.Tests.Queries +{ + internal class PhoneNumberQuery : BaseQuery + { + public override void ResolveRootQueryParameter(IDataContext context) + { + // Does not execute as root or level 1 queries. + } + + public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + { + // Execute as child to customer query. + var customer = (CustomerResult)parentQueryResult; + QueryParameter = new CustomerParameter + { + CustomerId = customer.Id + }; + } + } + + internal class PhoneNumberResult : IQueryResult + { + public int Id { get; set; } + public string Phone { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Schemio.Object.Tests.csproj b/tests/Schemio.Object.Tests/Schemio.Object.Tests.csproj index 4d140f4..c9fabde 100644 --- a/tests/Schemio.Object.Tests/Schemio.Object.Tests.csproj +++ b/tests/Schemio.Object.Tests/Schemio.Object.Tests.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -17,11 +17,8 @@ - + - - - diff --git a/tests/Schemio.Object.Tests/Transforms/CustomerTransform.cs b/tests/Schemio.Object.Tests/Transforms/CustomerTransform.cs new file mode 100644 index 0000000..ad1a09a --- /dev/null +++ b/tests/Schemio.Object.Tests/Transforms/CustomerTransform.cs @@ -0,0 +1,16 @@ +using Schemio.Object.Tests.Entities; +using Schemio.Object.Tests.Queries; + +namespace Schemio.Object.Tests.Transforms +{ + internal class CustomerTransform : BaseTransformer + { + public override Customer Transform(CustomerResult queryResult, Customer entity) + { + entity ??= new Customer(); + entity.Id = queryResult.Id; + entity.CustomerCode = queryResult.CustomerCode; + return entity; + } + } +} \ No newline at end of file From ed995150efb25aea48b3f7b34aea060d1e541008 Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 18 May 2023 02:00:51 +0100 Subject: [PATCH 02/24] - add GitVersion.yml --- .merge_file_6QqZc3 | 27 --------------------------- .merge_file_MaViKi | 11 ----------- GitVersion.yml | 15 +++++++++++++++ Schemio.Object.sln | 3 ++- 4 files changed, 17 insertions(+), 39 deletions(-) delete mode 100644 .merge_file_6QqZc3 delete mode 100644 .merge_file_MaViKi create mode 100644 GitVersion.yml diff --git a/.merge_file_6QqZc3 b/.merge_file_6QqZc3 deleted file mode 100644 index 4d140f4..0000000 --- a/.merge_file_6QqZc3 +++ /dev/null @@ -1,27 +0,0 @@ - - - - net6.0 - enable - enable - - false - - - - - - - - - - - - - - - - - - - diff --git a/.merge_file_MaViKi b/.merge_file_MaViKi deleted file mode 100644 index 8e7183f..0000000 --- a/.merge_file_MaViKi +++ /dev/null @@ -1,11 +0,0 @@ - - - - netstandard2.1 - - - - - - - diff --git a/GitVersion.yml b/GitVersion.yml new file mode 100644 index 0000000..3f9ebba --- /dev/null +++ b/GitVersion.yml @@ -0,0 +1,15 @@ +next-version: 1.0.1 +tag-prefix: '[vV]' +mode: ContinuousDeployment +branches: + master: + regex: ^master$ + release: + regex: ^release$ + develop: + regex: ^develop$|^dev$ + tag: beta + pull-request: + tag: beta +ignore: + sha: [] \ No newline at end of file diff --git a/Schemio.Object.sln b/Schemio.Object.sln index 313db86..78a1c4e 100644 --- a/Schemio.Object.sln +++ b/Schemio.Object.sln @@ -16,8 +16,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution", "solution", "{AF .gitignore = .gitignore .github\workflows\CI.yml = .github\workflows\CI.yml .github\workflows\CodeQL.yml = .github\workflows\CodeQL.yml - README.md = README.md + GitVersion.yml = GitVersion.yml LICENSE.md = LICENSE.md + README.md = README.md EndProjectSection EndProject Global From 610c57293ad09a783913a2c389cfcd95dff0f1df Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 18 May 2023 02:03:08 +0100 Subject: [PATCH 03/24] - refactor --- README.md | 6 +++--- src/Schemio.Object/BaseEntity.cs | 2 +- src/Schemio.Object/BaseQuery.cs | 2 +- src/Schemio.Object/BaseTransformer.cs | 2 +- src/Schemio.Object/ChildrenQueries.cs | 2 +- src/Schemio.Object/CreateSchema.cs | 3 +-- src/Schemio.Object/DataProvider.cs | 2 +- src/Schemio.Object/Helpers/ExtentionMethods.cs | 2 +- src/Schemio.Object/Helpers/Xml/XDocumentExts.cs | 2 +- src/Schemio.Object/Helpers/Xml/XmlHelper.cs | 2 +- src/Schemio.Object/Helpers/Xml/XmlSanitizer.cs | 2 +- src/Schemio.Object/IDataContext.cs | 2 +- src/Schemio.Object/IDataContextValidator.cs | 2 +- src/Schemio.Object/IDataProvider.cs | 2 +- src/Schemio.Object/IEntity.cs | 2 +- src/Schemio.Object/IEntitySchema.cs | 2 +- src/Schemio.Object/IPolymorphicQueryResult.cs | 2 +- src/Schemio.Object/IQuery.cs | 2 +- src/Schemio.Object/IQueryBuilder.cs | 2 +- src/Schemio.Object/IQueryEngine.cs | 2 +- src/Schemio.Object/IQueryExecutor.cs | 2 +- src/Schemio.Object/IQueryList.cs | 2 +- src/Schemio.Object/IQueryParameter.cs | 2 +- src/Schemio.Object/IQueryResult.cs | 2 +- src/Schemio.Object/ISchemaPathMatcher.cs | 2 +- src/Schemio.Object/ITransformExecutor.cs | 2 +- src/Schemio.Object/ITransformer.cs | 2 +- src/Schemio.Object/Impl/EventAggregator.cs | 2 +- src/Schemio.Object/Impl/EventSubscriber.cs | 2 +- src/Schemio.Object/Impl/QueryBuilder.cs | 2 +- src/Schemio.Object/Impl/QueryExecutor.cs | 2 +- src/Schemio.Object/Impl/TransformExecutor.cs | 2 +- src/Schemio.Object/JSON/JPathMatcher.cs | 4 ++-- src/Schemio.Object/QueryComparer.cs | 2 +- src/Schemio.Object/QueryList.cs | 2 +- src/Schemio.Object/XML/XMLDataProvider.cs | 4 ++-- src/Schemio.Object/XML/XPathMatcher.cs | 4 ++-- tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs | 2 +- tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs | 2 +- tests/Schemio.Object.Tests/Queries/AddressQuery.cs | 2 +- tests/Schemio.Object.Tests/Queries/CustomerQuery.cs | 2 +- tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs | 2 +- tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs | 2 +- tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs | 2 +- tests/Schemio.Object.Tests/Queries/OrderQuery.cs | 2 +- tests/Schemio.Object.Tests/Queries/PersonQuery.cs | 2 +- tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs | 2 +- 47 files changed, 52 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index a4ca7ba..f85412f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# Schemio.Data -[![NuGet version](https://badge.fury.io/nu/Schemio.Data.svg)](https://badge.fury.io/nu/Schemio.Data) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/NinjaRocks/Schemio.Data/blob/master/License.md) [![CI](https://github.com/NinjaRocks/Data2Xml/actions/workflows/CI.yml/badge.svg)](https://github.com/NinjaRocks/Data2Xml/actions/workflows/CI.yml) [![GitHub Release](https://img.shields.io/github/v/release/ninjarocks/Data2Xml?logo=github&sort=semver)](https://github.com/ninjarocks/Data2Xml/releases/latest) -[![CodeQL](https://github.com/NinjaRocks/Schemio.Data/actions/workflows/CodeQL.yml/badge.svg)](https://github.com/NinjaRocks/Schemio.Data/actions/workflows/CodeQL.yml) [![.Net Stardard](https://img.shields.io/badge/.Net%20Standard-2.1-blue)](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) +# Schemio.Object +[![NuGet version](https://badge.fury.io/nu/Schemio.Object.svg)](https://badge.fury.io/nu/Schemio.Object) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/NinjaRocks/Schemio.Object/blob/master/License.md) [![CI](https://github.com/NinjaRocks/Data2Xml/actions/workflows/CI.yml/badge.svg)](https://github.com/NinjaRocks/Data2Xml/actions/workflows/CI.yml) [![GitHub Release](https://img.shields.io/github/v/release/ninjarocks/Data2Xml?logo=github&sort=semver)](https://github.com/ninjarocks/Data2Xml/releases/latest) +[![CodeQL](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml/badge.svg)](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml) [![.Net Stardard](https://img.shields.io/badge/.Net%20Standard-2.1-blue)](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) -- ### .Net Standard 2.1 Library to map data to Entity using Schema Paths (Like XPath or JsonPath). diff --git a/src/Schemio.Object/BaseEntity.cs b/src/Schemio.Object/BaseEntity.cs index cb49c08..82ba905 100644 --- a/src/Schemio.Object/BaseEntity.cs +++ b/src/Schemio.Object/BaseEntity.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; namespace Schemio.Object.Tests.Entities { diff --git a/src/Schemio.Object/BaseQuery.cs b/src/Schemio.Object/BaseQuery.cs index 1f2e212..d434215 100644 --- a/src/Schemio.Object/BaseQuery.cs +++ b/src/Schemio.Object/BaseQuery.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Schemio.Data.Core +namespace Schemio.Object.Core { /// /// Implement this base class to create a data provider query. diff --git a/src/Schemio.Object/BaseTransformer.cs b/src/Schemio.Object/BaseTransformer.cs index ce94180..e12e8e7 100644 --- a/src/Schemio.Object/BaseTransformer.cs +++ b/src/Schemio.Object/BaseTransformer.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; namespace Schemio.Object { diff --git a/src/Schemio.Object/ChildrenQueries.cs b/src/Schemio.Object/ChildrenQueries.cs index b1d8dcf..2427810 100644 --- a/src/Schemio.Object/ChildrenQueries.cs +++ b/src/Schemio.Object/ChildrenQueries.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public class ChildrenQueries { diff --git a/src/Schemio.Object/CreateSchema.cs b/src/Schemio.Object/CreateSchema.cs index c7233a7..ef4f1ac 100644 --- a/src/Schemio.Object/CreateSchema.cs +++ b/src/Schemio.Object/CreateSchema.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Schemio.Data.Core +namespace Schemio.Object.Core { #region Helpers @@ -140,5 +140,4 @@ public interface IWithDependents } #endregion Fluent Interfaces - } \ No newline at end of file diff --git a/src/Schemio.Object/DataProvider.cs b/src/Schemio.Object/DataProvider.cs index c62d7f7..8148ec6 100644 --- a/src/Schemio.Object/DataProvider.cs +++ b/src/Schemio.Object/DataProvider.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Logging; -namespace Schemio.Data.Core.Impl +namespace Schemio.Object.Core.Impl { public class DataProvider : IDataProvider where T : IEntity { diff --git a/src/Schemio.Object/Helpers/ExtentionMethods.cs b/src/Schemio.Object/Helpers/ExtentionMethods.cs index 8d7bb7d..42a9745 100644 --- a/src/Schemio.Object/Helpers/ExtentionMethods.cs +++ b/src/Schemio.Object/Helpers/ExtentionMethods.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core.Helpers +namespace Schemio.Object.Core.Helpers { public static class ExtentionMethods { diff --git a/src/Schemio.Object/Helpers/Xml/XDocumentExts.cs b/src/Schemio.Object/Helpers/Xml/XDocumentExts.cs index 948ea50..a12258b 100644 --- a/src/Schemio.Object/Helpers/Xml/XDocumentExts.cs +++ b/src/Schemio.Object/Helpers/Xml/XDocumentExts.cs @@ -1,7 +1,7 @@ using System.Linq; using System.Xml.Linq; -namespace Schemio.Data.Core.Helpers.Xml +namespace Schemio.Object.Core.Helpers.Xml { public static class XDocumentExts { diff --git a/src/Schemio.Object/Helpers/Xml/XmlHelper.cs b/src/Schemio.Object/Helpers/Xml/XmlHelper.cs index d79b7d0..85b3330 100644 --- a/src/Schemio.Object/Helpers/Xml/XmlHelper.cs +++ b/src/Schemio.Object/Helpers/Xml/XmlHelper.cs @@ -2,7 +2,7 @@ using System.Xml; using System.Xml.Serialization; -namespace Schemio.Data.Core.Helpers.Xml +namespace Schemio.Object.Core.Helpers.Xml { public static class XmlHelper { diff --git a/src/Schemio.Object/Helpers/Xml/XmlSanitizer.cs b/src/Schemio.Object/Helpers/Xml/XmlSanitizer.cs index 72b9ffa..0717d48 100644 --- a/src/Schemio.Object/Helpers/Xml/XmlSanitizer.cs +++ b/src/Schemio.Object/Helpers/Xml/XmlSanitizer.cs @@ -2,7 +2,7 @@ using System.Text.RegularExpressions; using System.Xml; -namespace Schemio.Data.Core.Helpers.Xml +namespace Schemio.Object.Core.Helpers.Xml { public static class XmlSanitizer { diff --git a/src/Schemio.Object/IDataContext.cs b/src/Schemio.Object/IDataContext.cs index 0eacc1f..5dcd921 100644 --- a/src/Schemio.Object/IDataContext.cs +++ b/src/Schemio.Object/IDataContext.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface IDataContext { diff --git a/src/Schemio.Object/IDataContextValidator.cs b/src/Schemio.Object/IDataContextValidator.cs index a510eac..9a434cc 100644 --- a/src/Schemio.Object/IDataContextValidator.cs +++ b/src/Schemio.Object/IDataContextValidator.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface IDataContextValidator { diff --git a/src/Schemio.Object/IDataProvider.cs b/src/Schemio.Object/IDataProvider.cs index 9560c8f..53bee01 100644 --- a/src/Schemio.Object/IDataProvider.cs +++ b/src/Schemio.Object/IDataProvider.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface IDataProvider where T : IEntity { diff --git a/src/Schemio.Object/IEntity.cs b/src/Schemio.Object/IEntity.cs index afcb8b6..8749634 100644 --- a/src/Schemio.Object/IEntity.cs +++ b/src/Schemio.Object/IEntity.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core +namespace Schemio.Object.Core { /// /// Implement Entity required to be hydrated (using query/transformer). diff --git a/src/Schemio.Object/IEntitySchema.cs b/src/Schemio.Object/IEntitySchema.cs index 38a34cb..21c493b 100644 --- a/src/Schemio.Object/IEntitySchema.cs +++ b/src/Schemio.Object/IEntitySchema.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Schemio.Data.Core +namespace Schemio.Object.Core { /// /// Implement to configure entity schema path mappings (using Query/Trasformer pairs). diff --git a/src/Schemio.Object/IPolymorphicQueryResult.cs b/src/Schemio.Object/IPolymorphicQueryResult.cs index b4955ef..c73eaa7 100644 --- a/src/Schemio.Object/IPolymorphicQueryResult.cs +++ b/src/Schemio.Object/IPolymorphicQueryResult.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface IPolymorphicQueryResult : IQueryResult { diff --git a/src/Schemio.Object/IQuery.cs b/src/Schemio.Object/IQuery.cs index 28997d8..8b618b2 100644 --- a/src/Schemio.Object/IQuery.cs +++ b/src/Schemio.Object/IQuery.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Schemio.Data.Core +namespace Schemio.Object.Core { /// /// Implement IQuery to fetch data using API or database. diff --git a/src/Schemio.Object/IQueryBuilder.cs b/src/Schemio.Object/IQueryBuilder.cs index e252fcb..ebaa4e6 100644 --- a/src/Schemio.Object/IQueryBuilder.cs +++ b/src/Schemio.Object/IQueryBuilder.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface IQueryBuilder { diff --git a/src/Schemio.Object/IQueryEngine.cs b/src/Schemio.Object/IQueryEngine.cs index 65884f4..57faf4f 100644 --- a/src/Schemio.Object/IQueryEngine.cs +++ b/src/Schemio.Object/IQueryEngine.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface IQueryEngine { diff --git a/src/Schemio.Object/IQueryExecutor.cs b/src/Schemio.Object/IQueryExecutor.cs index d655120..fa636b0 100644 --- a/src/Schemio.Object/IQueryExecutor.cs +++ b/src/Schemio.Object/IQueryExecutor.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface IQueryExecutor { diff --git a/src/Schemio.Object/IQueryList.cs b/src/Schemio.Object/IQueryList.cs index eb5db9a..ea37d18 100644 --- a/src/Schemio.Object/IQueryList.cs +++ b/src/Schemio.Object/IQueryList.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface IQueryList { diff --git a/src/Schemio.Object/IQueryParameter.cs b/src/Schemio.Object/IQueryParameter.cs index 6ac4932..43d599f 100644 --- a/src/Schemio.Object/IQueryParameter.cs +++ b/src/Schemio.Object/IQueryParameter.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface IQueryParameter { diff --git a/src/Schemio.Object/IQueryResult.cs b/src/Schemio.Object/IQueryResult.cs index a728f21..03bc6ec 100644 --- a/src/Schemio.Object/IQueryResult.cs +++ b/src/Schemio.Object/IQueryResult.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface IQueryResult { diff --git a/src/Schemio.Object/ISchemaPathMatcher.cs b/src/Schemio.Object/ISchemaPathMatcher.cs index 40fb83d..ae3893d 100644 --- a/src/Schemio.Object/ISchemaPathMatcher.cs +++ b/src/Schemio.Object/ISchemaPathMatcher.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface ISchemaPathMatcher { diff --git a/src/Schemio.Object/ITransformExecutor.cs b/src/Schemio.Object/ITransformExecutor.cs index 7117297..10aab20 100644 --- a/src/Schemio.Object/ITransformExecutor.cs +++ b/src/Schemio.Object/ITransformExecutor.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public interface ITransformExecutor where TEntity : IEntity { diff --git a/src/Schemio.Object/ITransformer.cs b/src/Schemio.Object/ITransformer.cs index 6cf662c..65e7326 100644 --- a/src/Schemio.Object/ITransformer.cs +++ b/src/Schemio.Object/ITransformer.cs @@ -1,4 +1,4 @@ -namespace Schemio.Data.Core +namespace Schemio.Object.Core { /// /// Implement transformer to map data to entity using query result. diff --git a/src/Schemio.Object/Impl/EventAggregator.cs b/src/Schemio.Object/Impl/EventAggregator.cs index c74fbc3..95c4c87 100644 --- a/src/Schemio.Object/Impl/EventAggregator.cs +++ b/src/Schemio.Object/Impl/EventAggregator.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Schemio.Data.Core.Impl +namespace Schemio.Object.Core.Impl { public class EventAggregator { diff --git a/src/Schemio.Object/Impl/EventSubscriber.cs b/src/Schemio.Object/Impl/EventSubscriber.cs index 34d3b73..5d76755 100644 --- a/src/Schemio.Object/Impl/EventSubscriber.cs +++ b/src/Schemio.Object/Impl/EventSubscriber.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace Schemio.Data.Core.Impl +namespace Schemio.Object.Core.Impl { public class EventSubscriber : ISubscriber { diff --git a/src/Schemio.Object/Impl/QueryBuilder.cs b/src/Schemio.Object/Impl/QueryBuilder.cs index 1974049..3e042f7 100644 --- a/src/Schemio.Object/Impl/QueryBuilder.cs +++ b/src/Schemio.Object/Impl/QueryBuilder.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace Schemio.Data.Core.Impl +namespace Schemio.Object.Core.Impl { public class QueryBuilder : IQueryBuilder where T : IEntity { diff --git a/src/Schemio.Object/Impl/QueryExecutor.cs b/src/Schemio.Object/Impl/QueryExecutor.cs index d9e1af6..a4bec3c 100644 --- a/src/Schemio.Object/Impl/QueryExecutor.cs +++ b/src/Schemio.Object/Impl/QueryExecutor.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace Schemio.Data.Core.Impl +namespace Schemio.Object.Core.Impl { public class QueryExecutor : IQueryExecutor { diff --git a/src/Schemio.Object/Impl/TransformExecutor.cs b/src/Schemio.Object/Impl/TransformExecutor.cs index 2dcd4a8..a36d4f4 100644 --- a/src/Schemio.Object/Impl/TransformExecutor.cs +++ b/src/Schemio.Object/Impl/TransformExecutor.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace Schemio.Data.Core.Impl +namespace Schemio.Object.Core.Impl { public class TransformExecutor : ITransformExecutor where T : IEntity, new() { diff --git a/src/Schemio.Object/JSON/JPathMatcher.cs b/src/Schemio.Object/JSON/JPathMatcher.cs index 0f18bc3..0c1d0bf 100644 --- a/src/Schemio.Object/JSON/JPathMatcher.cs +++ b/src/Schemio.Object/JSON/JPathMatcher.cs @@ -1,8 +1,8 @@ -using Schemio.Data.Core.Helpers; +using Schemio.Object.Core.Helpers; using System.Linq; using System.Text.RegularExpressions; -namespace Schemio.Data.Core.JSON +namespace Schemio.Object.Core.JSON { public class JPathMatcher : ISchemaPathMatcher { diff --git a/src/Schemio.Object/QueryComparer.cs b/src/Schemio.Object/QueryComparer.cs index bb2277a..c011602 100644 --- a/src/Schemio.Object/QueryComparer.cs +++ b/src/Schemio.Object/QueryComparer.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public class QueryComparer : IEqualityComparer { diff --git a/src/Schemio.Object/QueryList.cs b/src/Schemio.Object/QueryList.cs index b83371d..7891334 100644 --- a/src/Schemio.Object/QueryList.cs +++ b/src/Schemio.Object/QueryList.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace Schemio.Data.Core +namespace Schemio.Object.Core { public class QueryList : IQueryList { diff --git a/src/Schemio.Object/XML/XMLDataProvider.cs b/src/Schemio.Object/XML/XMLDataProvider.cs index 7c02cd2..9487554 100644 --- a/src/Schemio.Object/XML/XMLDataProvider.cs +++ b/src/Schemio.Object/XML/XMLDataProvider.cs @@ -1,10 +1,10 @@ using Microsoft.Extensions.Logging; -using Schemio.Data.Core.Helpers.Xml; +using Schemio.Object.Core.Helpers.Xml; using System.Xml; using System.Xml.Linq; using System.Xml.Serialization; -namespace Schemio.Data.Core.XML +namespace Schemio.Object.Core.XML { internal class XMLDataProvider where T : IEntity { diff --git a/src/Schemio.Object/XML/XPathMatcher.cs b/src/Schemio.Object/XML/XPathMatcher.cs index b4942a1..c8174d3 100644 --- a/src/Schemio.Object/XML/XPathMatcher.cs +++ b/src/Schemio.Object/XML/XPathMatcher.cs @@ -1,7 +1,7 @@ -using Schemio.Data.Core.Helpers; +using Schemio.Object.Core.Helpers; using System.Linq; -namespace Schemio.Data.Core.XML +namespace Schemio.Object.Core.XML { public class XPathMatcher : ISchemaPathMatcher { diff --git a/tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs b/tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs index cdcfcbc..9411b34 100644 --- a/tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs +++ b/tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; namespace Schemio.Object.Tests.DataProvider { diff --git a/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs b/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs index 467a6c4..3489885 100644 --- a/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs +++ b/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; using Schemio.Object.Tests.Entities; namespace Schemio.Object.Tests.EntitySchemas diff --git a/tests/Schemio.Object.Tests/Queries/AddressQuery.cs b/tests/Schemio.Object.Tests/Queries/AddressQuery.cs index 2d593c8..c5d6769 100644 --- a/tests/Schemio.Object.Tests/Queries/AddressQuery.cs +++ b/tests/Schemio.Object.Tests/Queries/AddressQuery.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; namespace Schemio.Object.Tests.Queries { diff --git a/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs b/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs index 5a859c1..871666a 100644 --- a/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs +++ b/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; using Schemio.Object.Tests.DataProvider; namespace Schemio.Object.Tests.Queries diff --git a/tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs b/tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs index bbd7835..9e83c1c 100644 --- a/tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs +++ b/tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; namespace Schemio.Object.Tests.Queries { diff --git a/tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs b/tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs index b1d0239..4f554c5 100644 --- a/tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs +++ b/tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; namespace Schemio.Object.Tests.Queries { diff --git a/tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs b/tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs index 409cf0a..21ab42c 100644 --- a/tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs +++ b/tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; namespace Schemio.Object.Tests.Queries { diff --git a/tests/Schemio.Object.Tests/Queries/OrderQuery.cs b/tests/Schemio.Object.Tests/Queries/OrderQuery.cs index 25acce6..6f8bca0 100644 --- a/tests/Schemio.Object.Tests/Queries/OrderQuery.cs +++ b/tests/Schemio.Object.Tests/Queries/OrderQuery.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; using Schemio.Object.Tests.DataProvider; namespace Schemio.Object.Tests.Queries diff --git a/tests/Schemio.Object.Tests/Queries/PersonQuery.cs b/tests/Schemio.Object.Tests/Queries/PersonQuery.cs index 7302001..a91ddbd 100644 --- a/tests/Schemio.Object.Tests/Queries/PersonQuery.cs +++ b/tests/Schemio.Object.Tests/Queries/PersonQuery.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; namespace Schemio.Object.Tests.Queries { diff --git a/tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs b/tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs index bcd4d6f..f8fd57e 100644 --- a/tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs +++ b/tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs @@ -1,4 +1,4 @@ -using Schemio.Data.Core; +using Schemio.Object.Core; namespace Schemio.Object.Tests.Queries { From 7a3fec7a654dc6ce4db210a9cfcf749b0062066f Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 18 May 2023 02:04:24 +0100 Subject: [PATCH 04/24] - refactor --- .github/workflows/CI.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 2329ba4..f597a18 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -30,7 +30,7 @@ jobs: beta_Version: ${{ steps.gitversion.outputs.nuGetVersion }} branchName: ${{ steps.gitversion.outputs.branchName }} env: - working-directory: /home/runner/work/Schemio.Data/Schemio.Data + working-directory: /home/runner/work/Schemio.Object/Schemio.Object steps: - name: Step-01 Install GitVersion @@ -87,7 +87,7 @@ jobs: env: github-token: '${{ secrets.GITHUB_TOKEN }}' nuget-token: '${{ secrets.NUGET_API_KEY }}' - working-directory: /home/runner/work/Schemio.Data/Schemio.Data + working-directory: /home/runner/work/Schemio.Object/Schemio.Object steps: - name: Step-01 Retrieve Build Artifacts uses: actions/download-artifact@v3 @@ -103,7 +103,7 @@ jobs: - name: Step-03 Release to Nuget Org if: ${{ startsWith(github.head_ref, 'release/')}} - run: dotnet nuget push ${{env.working-directory}}/src/Schemio.Data/bin/Release/*.nupkg --skip-duplicate --api-key ${{ env.nuget-token }} --source https://api.nuget.org/v3/index.json + run: dotnet nuget push ${{env.working-directory}}/src/Schemio.Object/bin/Release/*.nupkg --skip-duplicate --api-key ${{ env.nuget-token }} --source https://api.nuget.org/v3/index.json Release: name: Release to Nuget @@ -119,15 +119,15 @@ jobs: # dotnet-version: '6.0.x' # Publish - - name: publish Schemio.Data package + - name: publish Schemio.Object package id: publish_nuget uses: Rebel028/publish-nuget@v2.8.0 with: # Filepath of the project to be packaged, relative to root of repository - PROJECT_FILE_PATH: Schemio.Data/Schemio.Data.csproj + PROJECT_FILE_PATH: Schemio.Object/Schemio.Object.csproj # NuGet package id, used for version detection & defaults to project name - PACKAGE_NAME: Schemio.Data + PACKAGE_NAME: Schemio.Object # Filepath with version info, relative to root of repository & defaults to PROJECT_FILE_PATH # VERSION_FILE_PATH: Directory.Build.props From f6ea65f129db8402df84e28c0c92ecd4ccfaf3ce Mon Sep 17 00:00:00 2001 From: Ninja Date: Wed, 1 Nov 2023 01:46:43 +0000 Subject: [PATCH 05/24] - Commit version 1.0 --- Schemio.Object.sln | 7 +++ src/Schemio.Object.SQL/ISQLQuery.cs | 11 +++++ src/Schemio.Object.SQL/SQLEngine.cs | 9 ++++ src/Schemio.Object.SQL/SQLQuery.cs | 18 +++++++ src/Schemio.Object.SQL/SQLQueryEngine.cs | 47 +++++++++++++++++++ .../Schemio.Object.SQL.csproj | 19 ++++++++ src/Schemio.Object.SQL/SqlConfiguration.cs | 15 ++++++ src/Schemio.Object/BaseEntity.cs | 10 ++-- src/Schemio.Object/BaseEntitySchema.cs | 22 +++++++++ src/Schemio.Object/BaseQuery.cs | 16 +++---- src/Schemio.Object/BaseTransformer.cs | 14 +++--- src/Schemio.Object/CreateSchema.cs | 16 ++++--- src/Schemio.Object/IEntity.cs | 2 +- src/Schemio.Object/IEntitySchema.cs | 8 ++-- src/Schemio.Object/IQuery.cs | 30 +++++++++++- src/Schemio.Object/ITransformer.cs | 18 +++---- src/Schemio.Object/Impl/EventSubscriber.cs | 4 +- src/Schemio.Object/Impl/QueryBuilder.cs | 2 +- src/Schemio.Object/Impl/TransformExecutor.cs | 2 +- .../PathMatchers/JPathMatcher.cs | 13 +++++ .../XPathMatcher.cs} | 10 ++-- src/Schemio.Object/Schemio.Object.csproj | 8 +++- src/Schemio.Object/XML/XPathMatcher.cs | 13 ----- .../Schemio.Object.Tests/Entities/Address.cs | 6 ++- .../Entities/Communication.cs | 12 +++++ .../Schemio.Object.Tests/Entities/Customer.cs | 12 ++--- .../Entities/EmailAddress.cs | 8 ---- .../Entities/Ethnicity.cs | 8 ---- tests/Schemio.Object.Tests/Entities/Order.cs | 4 +- .../Entities/OrderItem.cs | 4 +- tests/Schemio.Object.Tests/Entities/Person.cs | 9 ---- .../Entities/PhoneNumber.cs | 8 ---- .../EntitySchemas/CustomerSchema.cs | 28 +++++++---- ...Query.cs => CustomerCommunicationQuery.cs} | 11 +++-- .../Queries/CustomerOrderItemsQuery.cs | 38 +++++++++++++++ .../{OrderQuery.cs => CustomerOrdersQuery.cs} | 16 +++++-- .../Queries/CustomerQuery.cs | 12 ++--- .../Queries/EmailAddressQuery.cs | 28 ----------- .../Queries/EthnicityQuery.cs | 28 ----------- .../Queries/OrderItemQuery.cs | 34 -------------- .../Queries/PersonQuery.cs | 34 -------------- .../Queries/PhoneNumberQuery.cs | 28 ----------- .../CustomerCommunicationTransform.cs | 31 ++++++++++++ .../Transforms/CustomerOrderItemsTransform.cs | 30 ++++++++++++ .../Transforms/CustomerOrdersTransform.cs | 24 ++++++++++ .../Transforms/CustomerTransform.cs | 12 +++-- 46 files changed, 447 insertions(+), 292 deletions(-) create mode 100644 src/Schemio.Object.SQL/ISQLQuery.cs create mode 100644 src/Schemio.Object.SQL/SQLEngine.cs create mode 100644 src/Schemio.Object.SQL/SQLQuery.cs create mode 100644 src/Schemio.Object.SQL/SQLQueryEngine.cs create mode 100644 src/Schemio.Object.SQL/Schemio.Object.SQL.csproj create mode 100644 src/Schemio.Object.SQL/SqlConfiguration.cs create mode 100644 src/Schemio.Object/BaseEntitySchema.cs create mode 100644 src/Schemio.Object/PathMatchers/JPathMatcher.cs rename src/Schemio.Object/{JSON/JPathMatcher.cs => PathMatchers/XPathMatcher.cs} (64%) delete mode 100644 src/Schemio.Object/XML/XPathMatcher.cs create mode 100644 tests/Schemio.Object.Tests/Entities/Communication.cs delete mode 100644 tests/Schemio.Object.Tests/Entities/EmailAddress.cs delete mode 100644 tests/Schemio.Object.Tests/Entities/Ethnicity.cs delete mode 100644 tests/Schemio.Object.Tests/Entities/Person.cs delete mode 100644 tests/Schemio.Object.Tests/Entities/PhoneNumber.cs rename tests/Schemio.Object.Tests/Queries/{AddressQuery.cs => CustomerCommunicationQuery.cs} (58%) create mode 100644 tests/Schemio.Object.Tests/Queries/CustomerOrderItemsQuery.cs rename tests/Schemio.Object.Tests/Queries/{OrderQuery.cs => CustomerOrdersQuery.cs} (51%) delete mode 100644 tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs delete mode 100644 tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs delete mode 100644 tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs delete mode 100644 tests/Schemio.Object.Tests/Queries/PersonQuery.cs delete mode 100644 tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs create mode 100644 tests/Schemio.Object.Tests/Transforms/CustomerCommunicationTransform.cs create mode 100644 tests/Schemio.Object.Tests/Transforms/CustomerOrderItemsTransform.cs create mode 100644 tests/Schemio.Object.Tests/Transforms/CustomerOrdersTransform.cs diff --git a/Schemio.Object.sln b/Schemio.Object.sln index 78a1c4e..53f04b3 100644 --- a/Schemio.Object.sln +++ b/Schemio.Object.sln @@ -21,6 +21,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution", "solution", "{AF README.md = README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schemio.Object.SQL", "src\Schemio.Object.SQL\Schemio.Object.SQL.csproj", "{1A0CB973-23C9-4A17-905E-59510CD18932}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -35,6 +37,10 @@ Global {FDB00281-8B65-4A17-9F1F-B97865544BEF}.Debug|Any CPU.Build.0 = Debug|Any CPU {FDB00281-8B65-4A17-9F1F-B97865544BEF}.Release|Any CPU.ActiveCfg = Release|Any CPU {FDB00281-8B65-4A17-9F1F-B97865544BEF}.Release|Any CPU.Build.0 = Release|Any CPU + {1A0CB973-23C9-4A17-905E-59510CD18932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A0CB973-23C9-4A17-905E-59510CD18932}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A0CB973-23C9-4A17-905E-59510CD18932}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A0CB973-23C9-4A17-905E-59510CD18932}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -42,6 +48,7 @@ Global GlobalSection(NestedProjects) = preSolution {6F017146-B95A-4081-9CC0-B0245F78D72B} = {F41DA3D8-A0E9-4A05-8A35-78313C0F5804} {FDB00281-8B65-4A17-9F1F-B97865544BEF} = {07BAE427-96CF-4F9B-80A9-48CFB0A89CF3} + {1A0CB973-23C9-4A17-905E-59510CD18932} = {F41DA3D8-A0E9-4A05-8A35-78313C0F5804} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C0FF62D6-1374-4939-A546-432862338528} diff --git a/src/Schemio.Object.SQL/ISQLQuery.cs b/src/Schemio.Object.SQL/ISQLQuery.cs new file mode 100644 index 0000000..426079d --- /dev/null +++ b/src/Schemio.Object.SQL/ISQLQuery.cs @@ -0,0 +1,11 @@ +using Schemio.Object.Core; + +namespace Schemio.Object.SQL +{ + public interface ISQLQuery + { + IQueryResult Run(SQLEngine engine); + + string GetSQL(); + } +} \ No newline at end of file diff --git a/src/Schemio.Object.SQL/SQLEngine.cs b/src/Schemio.Object.SQL/SQLEngine.cs new file mode 100644 index 0000000..e5f1abf --- /dev/null +++ b/src/Schemio.Object.SQL/SQLEngine.cs @@ -0,0 +1,9 @@ +using Schemio.Object.Core; + +namespace Schemio.Object.SQL +{ + public interface SQLEngine + { + T Run(ISQLQuery query) where T : IQueryResult; + } +} \ No newline at end of file diff --git a/src/Schemio.Object.SQL/SQLQuery.cs b/src/Schemio.Object.SQL/SQLQuery.cs new file mode 100644 index 0000000..aab89c0 --- /dev/null +++ b/src/Schemio.Object.SQL/SQLQuery.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Schemio.Object.Core; + +namespace Schemio.Object.SQL +{ + //internal abstract class SQLQuery : IQuery + // where T : class, IQueryResult, ISQLQuery + //{ + // protected abstract string Query(); + + // public IQueryResult Run(SQLEngine engine) + // { + // return engine.Run((ISQLQuery)this); + // } + //} +} \ No newline at end of file diff --git a/src/Schemio.Object.SQL/SQLQueryEngine.cs b/src/Schemio.Object.SQL/SQLQueryEngine.cs new file mode 100644 index 0000000..57ade88 --- /dev/null +++ b/src/Schemio.Object.SQL/SQLQueryEngine.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Data; +using System.Linq; +using Schemio.Object.Core; +using Dapper; + +namespace Schemio.Object.SQL +{ + public class SQLQueryEngine : IQueryEngine, SQLEngine + { + public IQueryResult[] Run(IQueryList queries, IDataContext context) + { + var results = new List(); + if (queries?.Queries != null) + foreach (var query in queries.Queries.Cast()) + { + var result = query.Run((SQLEngine)this); + if (result != null) + results.Add(result); + } + + return results.ToArray(); + } + + public T Run(ISQLQuery query) where T : IQueryResult + { + var sql = query.GetSQL(); + + var factory = DbProviderFactories.GetFactory(SqlConfiguration.ConnectionSettings.ProviderName); + + if (factory == null) + throw new InvalidOperationException($"Provider: {SqlConfiguration.ConnectionSettings.ProviderName} is not supported. Please register entry in DbProviderFactories "); + + using (var connection = factory.CreateConnection()) + { + connection.ConnectionString = SqlConfiguration.ConnectionSettings.ConnectionString; + + connection.Open(); + var list = connection.Query(sql); + + return list.FirstOrDefault(); + } + } + } +} \ No newline at end of file diff --git a/src/Schemio.Object.SQL/Schemio.Object.SQL.csproj b/src/Schemio.Object.SQL/Schemio.Object.SQL.csproj new file mode 100644 index 0000000..72b3e02 --- /dev/null +++ b/src/Schemio.Object.SQL/Schemio.Object.SQL.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + + + diff --git a/src/Schemio.Object.SQL/SqlConfiguration.cs b/src/Schemio.Object.SQL/SqlConfiguration.cs new file mode 100644 index 0000000..31ed09b --- /dev/null +++ b/src/Schemio.Object.SQL/SqlConfiguration.cs @@ -0,0 +1,15 @@ +using System.Data.Common; + +namespace Schemio.Object.SQL +{ + internal class SqlConfiguration + { + public static ConnectionSettings ConnectionSettings { get; internal set; } + } + + public class ConnectionSettings + { + public DbConnection ProviderName { get; internal set; } + public string ConnectionString { get; internal set; } + } +} \ No newline at end of file diff --git a/src/Schemio.Object/BaseEntity.cs b/src/Schemio.Object/BaseEntity.cs index 82ba905..3764800 100644 --- a/src/Schemio.Object/BaseEntity.cs +++ b/src/Schemio.Object/BaseEntity.cs @@ -1,9 +1,9 @@ using Schemio.Object.Core; -namespace Schemio.Object.Tests.Entities +namespace Schemio.Object { - public class BaseEntity : IEntity - { - public decimal Version { get; set; } = 1; - } + //public abstract class BaseEntity : IEntity + //{ + // public decimal Version { get; set; } = 1; + //} } \ No newline at end of file diff --git a/src/Schemio.Object/BaseEntitySchema.cs b/src/Schemio.Object/BaseEntitySchema.cs new file mode 100644 index 0000000..e5d8bf7 --- /dev/null +++ b/src/Schemio.Object/BaseEntitySchema.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + +namespace Schemio.Object.Core +{ + /// + /// Implement to configure schema path mappings for an Entity. + /// + /// Entity type + public abstract class BaseEntitySchema : IEntitySchema where TEntity : IEntity + { + public IEnumerable> Mappings { get; } + public decimal Version { get; } + + public BaseEntitySchema() + { + Mappings = ConfigureSchema(); + } + + public abstract Mapping[] ConfigureSchema(); + } +} \ No newline at end of file diff --git a/src/Schemio.Object/BaseQuery.cs b/src/Schemio.Object/BaseQuery.cs index d434215..d3343bf 100644 --- a/src/Schemio.Object/BaseQuery.cs +++ b/src/Schemio.Object/BaseQuery.cs @@ -15,10 +15,10 @@ public abstract class BaseQuery : IQuery /// /// Parameter values for query to execute. /// - protected IQueryParameter QueryParameter; + protected TQueryParameter QueryParameter; /// - /// Children queries of this query. + /// Children queries dependent on this query. /// public List Children { get; set; } @@ -37,18 +37,16 @@ public Type GetResultType public bool IsContextResolved() => QueryParameter != null; /// - /// Override this method to resolve query parameter to execute query in parent mode. + /// Implement this method to resolve query parameter to execute query in child mode to a parent query. /// /// DataContext object passed to dataprovider. - public virtual void ResolveRootQueryParameter(IDataContext context) - { } + /// Query result of parent query. + public abstract void ResolveParameterInChildMode(IDataContext context, IQueryResult parentQueryResult); /// - /// Override this method to resolve query parameter to execute query in child mode to a parent query. + /// Implement this method to resolve query parameter to execute query in parent mode. /// /// DataContext object passed to dataprovider. - /// Query result of parent query. - public virtual void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) - { } + public abstract void ResolveParameterInParentMode(IDataContext context); } } \ No newline at end of file diff --git a/src/Schemio.Object/BaseTransformer.cs b/src/Schemio.Object/BaseTransformer.cs index e12e8e7..2544a61 100644 --- a/src/Schemio.Object/BaseTransformer.cs +++ b/src/Schemio.Object/BaseTransformer.cs @@ -2,20 +2,20 @@ namespace Schemio.Object { - public abstract class BaseTransformer : ITransformer, IEntityTransform - where TQueryResult : IQueryResult - where TEntity : IEntity + public abstract class BaseTransformer : ITransformer + where T : IEntity + where TD : IQueryResult { public IDataContext Context { get; private set; } public void ResolveContext(IDataContext context) => Context = context; - public TEntity Run(TQueryResult queryResult, TEntity entity) + public IEntity Run(IQueryResult queryResult, IEntity entity) { - return queryResult.GetType() == typeof(TQueryResult) || queryResult is TQueryResult - ? Transform((TQueryResult)queryResult, entity) : entity; + return queryResult.GetType() == typeof(TD) || queryResult is TD + ? Transform((TD)queryResult, (T)entity) : entity; } - public abstract TEntity Transform(TQueryResult queryResult, TEntity entity); + public abstract T Transform(TD queryResult, T entity); } } \ No newline at end of file diff --git a/src/Schemio.Object/CreateSchema.cs b/src/Schemio.Object/CreateSchema.cs index ef4f1ac..105fecd 100644 --- a/src/Schemio.Object/CreateSchema.cs +++ b/src/Schemio.Object/CreateSchema.cs @@ -7,12 +7,14 @@ namespace Schemio.Object.Core public class CreateSchema { - public static IMappings For() where T : IEntity => new Mappings { Order = 1 }; + public static IMappings For() where T : IEntity + => new Mappings { Order = 1 }; } public class For { - public static ISchemaPaths Paths(params string[] paths) => new SchemaPaths { Paths = paths }; + public static ISchemaPaths Paths(params string[] paths) + => new SchemaPaths { Paths = paths }; } public class SchemaPaths : ISchemaPaths @@ -40,7 +42,7 @@ public class Mappings : /// public IMapOrComplete Map(ISchemaPaths paths) where TQ : IQuery, new() - where TR : ITransformer, new() => + where TR : ITransformer, new() => Map(paths, null); /// @@ -53,7 +55,7 @@ public IMapOrComplete Map(ISchemaPaths paths) /// public IMapOrComplete Map(ISchemaPaths paths, Func, IMap> dependents) where TQ : IQuery, new() - where TR : ITransformer, new() + where TR : ITransformer, new() { var mapping = new Mapping { @@ -90,7 +92,7 @@ public class Mapping : public int Order { get; set; } public ISchemaPaths SchemaPaths { get; set; } public IQuery Query { get; set; } - public ITransformer Transformer { get; set; } + public ITransformer Transformer { get; set; } public IQuery DependentOn { get; set; } public IMappings Dependents => new Mappings { Order = Order + 1 }; @@ -109,11 +111,11 @@ public interface IMap { IMapOrComplete Map(ISchemaPaths paths) where TQ : IQuery, new() - where TR : ITransformer, new(); + where TR : ITransformer, new(); IMapOrComplete Map(ISchemaPaths paths, Func, IMap> dependents) where TQ : IQuery, new() - where TR : ITransformer, new(); + where TR : ITransformer, new(); } public interface IMappings : IMap diff --git a/src/Schemio.Object/IEntity.cs b/src/Schemio.Object/IEntity.cs index 8749634..f6c12fa 100644 --- a/src/Schemio.Object/IEntity.cs +++ b/src/Schemio.Object/IEntity.cs @@ -5,6 +5,6 @@ namespace Schemio.Object.Core /// public interface IEntity { - decimal Version { get; set; } + //decimal Version { get; set; } } } \ No newline at end of file diff --git a/src/Schemio.Object/IEntitySchema.cs b/src/Schemio.Object/IEntitySchema.cs index 21c493b..5a2ccba 100644 --- a/src/Schemio.Object/IEntitySchema.cs +++ b/src/Schemio.Object/IEntitySchema.cs @@ -3,12 +3,12 @@ namespace Schemio.Object.Core { /// - /// Implement to configure entity schema path mappings (using Query/Trasformer pairs). + /// Implement to configure schema path mappings for an Entity. /// - /// + /// Entity type public interface IEntitySchema where TEntity : IEntity { - IEnumerable> Mappings { get; } - decimal Version { get; } + public IEnumerable> Mappings { get; } + public decimal Version { get; } } } \ No newline at end of file diff --git a/src/Schemio.Object/IQuery.cs b/src/Schemio.Object/IQuery.cs index 8b618b2..3d4335b 100644 --- a/src/Schemio.Object/IQuery.cs +++ b/src/Schemio.Object/IQuery.cs @@ -12,10 +12,36 @@ public interface IQuery Type GetResultType { get; } - void ResolveRootQueryParameter(IDataContext context); + void ResolveParameterInParentMode(IDataContext context); - void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult); + void ResolveParameterInChildMode(IDataContext context, IQueryResult parentQueryResult); bool IsContextResolved(); } + + //public interface IParentQuery : IQuery + //{ + // //List Children { get; set; } + + // //Type GetResultType { get; } + + // void ResolveRootQueryParameter(IDataContext context); + + // //void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult); + + // //bool IsContextResolved(); + //} + + //public interface IChildQuery : IQuery + //{ + // //List Children { get; set; } + + // //Type GetResultType { get; } + + // //void ResolveRootQueryParameter(IDataContext context); + + // void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult); + + // //bool IsContextResolved(); + //} } \ No newline at end of file diff --git a/src/Schemio.Object/ITransformer.cs b/src/Schemio.Object/ITransformer.cs index 65e7326..13c8f8f 100644 --- a/src/Schemio.Object/ITransformer.cs +++ b/src/Schemio.Object/ITransformer.cs @@ -5,21 +5,23 @@ namespace Schemio.Object.Core /// /// /// - public interface ITransformer + public interface ITransformer : ITransformer where TQueryResult : IQueryResult where TEntity : IEntity { - IDataContext Context { get; } + //IDataContext Context { get; } - void ResolveContext(IDataContext context); + //void ResolveContext(IDataContext context); - TEntity Run(TQueryResult queryResult, TEntity entity); + // TEntity Run(TQueryResult queryResult, TEntity entity); } - internal interface IEntityTransform - where TQueryResult : IQueryResult - where TEntity : IEntity + public interface ITransformer { - TEntity Transform(TQueryResult queryResult, TEntity entity); + IDataContext Context { get; } + + void ResolveContext(IDataContext context); + + IEntity Run(IQueryResult queryResult, IEntity entity); } } \ No newline at end of file diff --git a/src/Schemio.Object/Impl/EventSubscriber.cs b/src/Schemio.Object/Impl/EventSubscriber.cs index 5d76755..5ee650d 100644 --- a/src/Schemio.Object/Impl/EventSubscriber.cs +++ b/src/Schemio.Object/Impl/EventSubscriber.cs @@ -33,7 +33,7 @@ public void OnEventHandler(IDataContext context, ExecutorResultArgs args) foreach (var query in unresolved.Queries) { - query.ResolveChildQueryParameter(context, queryResult); + query.ResolveParameterInChildMode(context, queryResult); } } } @@ -55,7 +55,7 @@ public void OnEventHandler(IDataContext context, ExecutorResultArgs args) foreach (var query in unresolved.Queries) { - query.ResolveChildQueryParameter(context, queryResult); + query.ResolveParameterInChildMode(context, queryResult); } } } diff --git a/src/Schemio.Object/Impl/QueryBuilder.cs b/src/Schemio.Object/Impl/QueryBuilder.cs index 3e042f7..5a111a4 100644 --- a/src/Schemio.Object/Impl/QueryBuilder.cs +++ b/src/Schemio.Object/Impl/QueryBuilder.cs @@ -24,7 +24,7 @@ public IQueryList Build(IDataContext context) var queries = GetMappedQueries(entitySchema.Mappings.ToList(), context); foreach (var query in queries.Queries) - query.ResolveRootQueryParameter(context); + query.ResolveParameterInParentMode(context); return new QueryList(queries.Queries); } diff --git a/src/Schemio.Object/Impl/TransformExecutor.cs b/src/Schemio.Object/Impl/TransformExecutor.cs index a36d4f4..df5e6f3 100644 --- a/src/Schemio.Object/Impl/TransformExecutor.cs +++ b/src/Schemio.Object/Impl/TransformExecutor.cs @@ -20,7 +20,7 @@ public TransformExecutor(IEntitySchema entitySchemaMapping) /// public T Execute(IDataContext context, IList queryResults) { - var entity = new T { Version = entitySchemaMapping.Version }; + var entity = new T { /*Version = entitySchemaMapping.Version*/ }; if (queryResults == null || !queryResults.Any()) return entity; diff --git a/src/Schemio.Object/PathMatchers/JPathMatcher.cs b/src/Schemio.Object/PathMatchers/JPathMatcher.cs new file mode 100644 index 0000000..eb0fb6a --- /dev/null +++ b/src/Schemio.Object/PathMatchers/JPathMatcher.cs @@ -0,0 +1,13 @@ +using Schemio.Object.Core; +using Schemio.Object.Core.Helpers; + +namespace Schemio.Object.Pathmatchers +{ + public class JPathMatcher : ISchemaPathMatcher + { + public bool IsMatch(string inputXPath, ISchemaPaths configuredXPaths) => + // Does the template jsonpath contain any of the mapping jsonpaths? + inputXPath.IsNotNullOrEmpty() + && configuredXPaths.Paths.Any(x => inputXPath.ToLower().Contains(x.ToLower())); + } +} \ No newline at end of file diff --git a/src/Schemio.Object/JSON/JPathMatcher.cs b/src/Schemio.Object/PathMatchers/XPathMatcher.cs similarity index 64% rename from src/Schemio.Object/JSON/JPathMatcher.cs rename to src/Schemio.Object/PathMatchers/XPathMatcher.cs index 0c1d0bf..ec4c44d 100644 --- a/src/Schemio.Object/JSON/JPathMatcher.cs +++ b/src/Schemio.Object/PathMatchers/XPathMatcher.cs @@ -1,13 +1,11 @@ -using Schemio.Object.Core.Helpers; +using Schemio.Object.Core; +using Schemio.Object.Core.Helpers; using System.Linq; -using System.Text.RegularExpressions; -namespace Schemio.Object.Core.JSON +namespace Schemio.Object.PathMatchers { - public class JPathMatcher : ISchemaPathMatcher + public class XPathMatcher : ISchemaPathMatcher { - private static readonly Regex ancestorRegex = new Regex(@"=ancestor::(?'path'.*?)(/@|\[.*\]/@)", RegexOptions.Compiled); - public bool IsMatch(string inputXPath, ISchemaPaths configuredXPaths) => // Does the template xpath contain any of the mapping xpaths? inputXPath.IsNotNullOrEmpty() diff --git a/src/Schemio.Object/Schemio.Object.csproj b/src/Schemio.Object/Schemio.Object.csproj index 8e7183f..46c8ba1 100644 --- a/src/Schemio.Object/Schemio.Object.csproj +++ b/src/Schemio.Object/Schemio.Object.csproj @@ -1,7 +1,11 @@ - + - netstandard2.1 + net6.0 + enable + enable + + false diff --git a/src/Schemio.Object/XML/XPathMatcher.cs b/src/Schemio.Object/XML/XPathMatcher.cs deleted file mode 100644 index c8174d3..0000000 --- a/src/Schemio.Object/XML/XPathMatcher.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Schemio.Object.Core.Helpers; -using System.Linq; - -namespace Schemio.Object.Core.XML -{ - public class XPathMatcher : ISchemaPathMatcher - { - public bool IsMatch(string inputXPath, ISchemaPaths configuredXPaths) => - // Does the template xpath contain any of the mapping xpaths? - inputXPath.IsNotNullOrEmpty() - && configuredXPaths.Paths.Any(x => inputXPath.ToLower().Contains(x.ToLower())); - } -} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/Address.cs b/tests/Schemio.Object.Tests/Entities/Address.cs index 7a57ebd..ec724e4 100644 --- a/tests/Schemio.Object.Tests/Entities/Address.cs +++ b/tests/Schemio.Object.Tests/Entities/Address.cs @@ -1,8 +1,10 @@ +using Schemio.Object.Core; + namespace Schemio.Object.Tests.Entities { - internal class Address : BaseEntity + public class Address { - public int Id { get; set; } + public int AddressId { get; set; } public string HouseNo { get; set; } public string City { get; set; } public string Region { get; set; } diff --git a/tests/Schemio.Object.Tests/Entities/Communication.cs b/tests/Schemio.Object.Tests/Entities/Communication.cs new file mode 100644 index 0000000..ac3b404 --- /dev/null +++ b/tests/Schemio.Object.Tests/Entities/Communication.cs @@ -0,0 +1,12 @@ +using Schemio.Object.Core; + +namespace Schemio.Object.Tests.Entities +{ + public class Communication + { + public int ContactId { get; set; } + public string Phone { get; set; } + public string Email { get; set; } + public Address Address { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/Customer.cs b/tests/Schemio.Object.Tests/Entities/Customer.cs index 162d189..3e88f20 100644 --- a/tests/Schemio.Object.Tests/Entities/Customer.cs +++ b/tests/Schemio.Object.Tests/Entities/Customer.cs @@ -1,13 +1,13 @@ +using Schemio.Object.Core; + namespace Schemio.Object.Tests.Entities { - internal class Customer : BaseEntity + public class Customer : IEntity { - public int Id { get; set; } + public int CustomerId { get; set; } public string CustomerCode { get; set; } - public Person Person { get; set; } - public Address Address { get; set; } - public PhoneNumber PhoneNumber { get; set; } - public EmailAddress EmailAddress { get; set; } + public string CustomerName { get; set; } + public Communication Communication { get; set; } public Order[] Orders { get; set; } } } \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/EmailAddress.cs b/tests/Schemio.Object.Tests/Entities/EmailAddress.cs deleted file mode 100644 index 333e26d..0000000 --- a/tests/Schemio.Object.Tests/Entities/EmailAddress.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Schemio.Object.Tests.Entities -{ - internal class EmailAddress : BaseEntity - { - public int Id { get; set; } - public string Email { get; set; } - } -} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/Ethnicity.cs b/tests/Schemio.Object.Tests/Entities/Ethnicity.cs deleted file mode 100644 index 99001c5..0000000 --- a/tests/Schemio.Object.Tests/Entities/Ethnicity.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Schemio.Object.Tests.Entities -{ - internal class Ethnicity : BaseEntity - { - public int Id { get; set; } - public string Value { get; set; } - } -} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/Order.cs b/tests/Schemio.Object.Tests/Entities/Order.cs index 484e14a..f1be999 100644 --- a/tests/Schemio.Object.Tests/Entities/Order.cs +++ b/tests/Schemio.Object.Tests/Entities/Order.cs @@ -1,8 +1,10 @@ +using Schemio.Object.Core; + namespace Schemio.Object.Tests.Entities { public class Order { - public int Id { get; set; } + public int OrderId { get; set; } public string OrderNo { get; set; } public DateTime Date { get; set; } public OrderItem[] Items { get; set; } diff --git a/tests/Schemio.Object.Tests/Entities/OrderItem.cs b/tests/Schemio.Object.Tests/Entities/OrderItem.cs index b755ce3..cd52fc2 100644 --- a/tests/Schemio.Object.Tests/Entities/OrderItem.cs +++ b/tests/Schemio.Object.Tests/Entities/OrderItem.cs @@ -1,8 +1,10 @@ +using Schemio.Object.Core; + namespace Schemio.Object.Tests.Entities { public class OrderItem { - public int Id { get; set; } + public int ItemId { get; set; } public string Name { get; set; } public decimal Cost { get; set; } } diff --git a/tests/Schemio.Object.Tests/Entities/Person.cs b/tests/Schemio.Object.Tests/Entities/Person.cs deleted file mode 100644 index 5bd952a..0000000 --- a/tests/Schemio.Object.Tests/Entities/Person.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Schemio.Object.Tests.Entities -{ - internal class Person : BaseEntity - { - public int Id { get; set; } - public string Name { get; set; } - public Ethnicity Ethnicity { get; set; } - } -} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/PhoneNumber.cs b/tests/Schemio.Object.Tests/Entities/PhoneNumber.cs deleted file mode 100644 index ec16562..0000000 --- a/tests/Schemio.Object.Tests/Entities/PhoneNumber.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Schemio.Object.Tests.Entities -{ - internal class PhoneNumber : BaseEntity - { - public int Id { get; set; } - public string Phone { get; set; } - } -} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs b/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs index 3489885..909617a 100644 --- a/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs +++ b/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs @@ -1,22 +1,32 @@ using Schemio.Object.Core; using Schemio.Object.Tests.Entities; +using Schemio.Object.Tests.Queries; +using Schemio.Object.Tests.Transforms; namespace Schemio.Object.Tests.EntitySchemas { internal class CustomerSchema : IEntitySchema { - public IEnumerable> Mappings { get; } - public decimal Version => 1; + private IEnumerable> mappings; + + private decimal version; + + public IEnumerable> Mappings => mappings; + public decimal Version => version; public CustomerSchema() { - //Mappings = CreateSchema.For() - // .Map(For.Paths("clients/common/context"), dependantQuery => - // dependantQuery.Dependents - // .Map(For.XPath("clients/common/context/currentuserdetails/groupdetails/organisationlogo")) - // .Map(For.XPath("clients/common/context/currentuserdetails/groupdetails/grouplogo")) - // .Map(For.XPath("clients/common/context/currentuserdetails/photo")) - // ); + version = 1; + + // Create an object mapping graph of query and transformer pairs using xpaths. + mappings = CreateSchema.For() + .Map(For.Paths("customer/id", "customer/customercode", "customer/customername"), + customer => customer.Dependents + .Map(For.Paths("customer/communication")) + .Map(For.Paths("customer/orders"), + customerOrders => customerOrders.Dependents + .Map(For.Paths("customer/orders/order/Items"))) + ).Complete(); } } } \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/AddressQuery.cs b/tests/Schemio.Object.Tests/Queries/CustomerCommunicationQuery.cs similarity index 58% rename from tests/Schemio.Object.Tests/Queries/AddressQuery.cs rename to tests/Schemio.Object.Tests/Queries/CustomerCommunicationQuery.cs index c5d6769..73ecaa7 100644 --- a/tests/Schemio.Object.Tests/Queries/AddressQuery.cs +++ b/tests/Schemio.Object.Tests/Queries/CustomerCommunicationQuery.cs @@ -2,14 +2,14 @@ namespace Schemio.Object.Tests.Queries { - internal class AddressQuery : BaseQuery + internal class CustomerCommunicationQuery : BaseQuery { - public override void ResolveRootQueryParameter(IDataContext context) + public override void ResolveParameterInParentMode(IDataContext context) { // Does not execute as root or level 1 queries. } - public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + public override void ResolveParameterInChildMode(IDataContext context, IQueryResult parentQueryResult) { // Execute as child to customer query. var customer = (CustomerResult)parentQueryResult; @@ -20,8 +20,11 @@ public override void ResolveChildQueryParameter(IDataContext context, IQueryResu } } - internal class AddressResult : IQueryResult + public class CommunicationResult : IQueryResult { + public int Id { get; set; } + public string Telephone { get; set; } + public string Email { get; set; } public string HouseNo { get; set; } public string City { get; set; } public string Region { get; set; } diff --git a/tests/Schemio.Object.Tests/Queries/CustomerOrderItemsQuery.cs b/tests/Schemio.Object.Tests/Queries/CustomerOrderItemsQuery.cs new file mode 100644 index 0000000..1e46ce6 --- /dev/null +++ b/tests/Schemio.Object.Tests/Queries/CustomerOrderItemsQuery.cs @@ -0,0 +1,38 @@ +using Schemio.Object.Core; + +namespace Schemio.Object.Tests.Queries +{ + internal class CustomerOrderItemsQuery : BaseQuery + { + public override void ResolveParameterInParentMode(IDataContext context) + { + // Does not execute as root or level 1 queries. + } + + public override void ResolveParameterInChildMode(IDataContext context, IQueryResult parentQueryResult) + { + // Execute as child to order query. + var ordersResult = (OrderCollectionResult)parentQueryResult; + QueryParameter = new OrderItemParameter + { + OrderIds = new List(ordersResult.Orders.Select(x => x.OrderId)) + }; + } + } + + public class OrderItemCollectionResult : IQueryResult + { + public List OrderItems { get; set; } + } + + public class OrderItemValue + { + public int OrderId { get; set; } + public (int ItemId, string Name, decimal Cost)[] Items { get; set; } + } + + internal class OrderItemParameter : IQueryParameter + { + public List OrderIds { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/OrderQuery.cs b/tests/Schemio.Object.Tests/Queries/CustomerOrdersQuery.cs similarity index 51% rename from tests/Schemio.Object.Tests/Queries/OrderQuery.cs rename to tests/Schemio.Object.Tests/Queries/CustomerOrdersQuery.cs index 6f8bca0..aeaf1d4 100644 --- a/tests/Schemio.Object.Tests/Queries/OrderQuery.cs +++ b/tests/Schemio.Object.Tests/Queries/CustomerOrdersQuery.cs @@ -3,9 +3,9 @@ namespace Schemio.Object.Tests.Queries { - internal class OrderQuery : BaseQuery + internal class CustomerOrdersQuery : BaseQuery { - public override void ResolveRootQueryParameter(IDataContext context) + public override void ResolveParameterInParentMode(IDataContext context) { // Executes as root or level 1 query. var customer = (CustomerContext)context; @@ -15,15 +15,21 @@ public override void ResolveRootQueryParameter(IDataContext context) }; } - public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + public override void ResolveParameterInChildMode(IDataContext context, IQueryResult parentQueryResult) { // Does not execute as child to any query. } } - internal class OrderResult : IQueryResult + public class OrderCollectionResult : IQueryResult { - public int Id { get; set; } + public int CustomerId { get; set; } + public OrderValue[] Orders { get; set; } + } + + public class OrderValue + { + public int OrderId { get; set; } public string OrderNo { get; set; } public DateTime Date { get; set; } } diff --git a/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs b/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs index 871666a..55400a7 100644 --- a/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs +++ b/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs @@ -3,9 +3,9 @@ namespace Schemio.Object.Tests.Queries { - internal class CustomerQuery : BaseQuery + public class CustomerQuery : BaseQuery { - public override void ResolveRootQueryParameter(IDataContext context) + public override void ResolveParameterInParentMode(IDataContext context) { // Executes as root or level 1 query. var customer = (CustomerContext)context; @@ -15,20 +15,20 @@ public override void ResolveRootQueryParameter(IDataContext context) }; } - public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) + public override void ResolveParameterInChildMode(IDataContext context, IQueryResult parentQueryResult) { // Does not execute as child to any query. } } - internal class CustomerResult : IQueryResult + public class CustomerResult : IQueryResult { public int Id { get; set; } public string CustomerCode { get; set; } - public int PersonId { get; set; } + public string CustomerName { get; set; } } - internal class CustomerParameter : IQueryParameter + public class CustomerParameter : IQueryParameter { public int CustomerId { get; set; } } diff --git a/tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs b/tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs deleted file mode 100644 index 9e83c1c..0000000 --- a/tests/Schemio.Object.Tests/Queries/EmailAddressQuery.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Queries -{ - internal class EmailAddressQuery : BaseQuery - { - public override void ResolveRootQueryParameter(IDataContext context) - { - // Does not execute as root or level 1 queries. - } - - public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) - { - // Execute as child to customer query. - var customer = (CustomerResult)parentQueryResult; - QueryParameter = new CustomerParameter - { - CustomerId = customer.Id - }; - } - } - - internal class EmailAddressResult : IQueryResult - { - public int Id { get; set; } - public string Email { get; set; } - } -} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs b/tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs deleted file mode 100644 index 4f554c5..0000000 --- a/tests/Schemio.Object.Tests/Queries/EthnicityQuery.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Queries -{ - internal class EthnicityQuery : BaseQuery - { - public override void ResolveRootQueryParameter(IDataContext context) - { - // Does not execute as root or level 1 queries. - } - - public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) - { - // Execute as child to person query. - var person = (PersonResult)parentQueryResult; - QueryParameter = new PersonParameter - { - PersonId = person.Id - }; - } - } - - internal class EthnicityResult : IQueryResult - { - public int Id { get; set; } - public string Value { get; set; } - } -} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs b/tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs deleted file mode 100644 index 21ab42c..0000000 --- a/tests/Schemio.Object.Tests/Queries/OrderItemQuery.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Queries -{ - internal class OrderItemQuery : BaseQuery - { - public override void ResolveRootQueryParameter(IDataContext context) - { - // Does not execute as root or level 1 queries. - } - - public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) - { - // Execute as child to order query. - var order = (OrderResult)parentQueryResult; - QueryParameter = new OrderItemParameter - { - OrderId = order.Id - }; - } - } - - internal class OrderItemResult : IQueryResult - { - public int Id { get; set; } - public string Name { get; set; } - public decimal Cost { get; set; } - } - - internal class OrderItemParameter : IQueryParameter - { - public int OrderId { get; set; } - } -} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/PersonQuery.cs b/tests/Schemio.Object.Tests/Queries/PersonQuery.cs deleted file mode 100644 index a91ddbd..0000000 --- a/tests/Schemio.Object.Tests/Queries/PersonQuery.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Queries -{ - internal class PersonQuery : BaseQuery - { - public override void ResolveRootQueryParameter(IDataContext context) - { - // Does not execute as root or level 1 queries. - } - - public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) - { - // Execute as child to customer query. - var customer = (CustomerResult)parentQueryResult; - QueryParameter = new PersonParameter - { - PersonId = customer.PersonId - }; - } - } - - internal class PersonResult : IQueryResult - { - public int Id { get; set; } - public string Name { get; set; } - public int EthnicityId { get; set; } - } - - internal class PersonParameter : IQueryParameter - { - public int PersonId { get; set; } - } -} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs b/tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs deleted file mode 100644 index f8fd57e..0000000 --- a/tests/Schemio.Object.Tests/Queries/PhoneNumberQuery.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Queries -{ - internal class PhoneNumberQuery : BaseQuery - { - public override void ResolveRootQueryParameter(IDataContext context) - { - // Does not execute as root or level 1 queries. - } - - public override void ResolveChildQueryParameter(IDataContext context, IQueryResult parentQueryResult) - { - // Execute as child to customer query. - var customer = (CustomerResult)parentQueryResult; - QueryParameter = new CustomerParameter - { - CustomerId = customer.Id - }; - } - } - - internal class PhoneNumberResult : IQueryResult - { - public int Id { get; set; } - public string Phone { get; set; } - } -} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Transforms/CustomerCommunicationTransform.cs b/tests/Schemio.Object.Tests/Transforms/CustomerCommunicationTransform.cs new file mode 100644 index 0000000..108c75e --- /dev/null +++ b/tests/Schemio.Object.Tests/Transforms/CustomerCommunicationTransform.cs @@ -0,0 +1,31 @@ +using Schemio.Object.Tests.Entities; +using Schemio.Object.Tests.Queries; + +namespace Schemio.Object.Tests.Transforms +{ + public class CustomerCommunicationTransform : BaseTransformer + { + public override Customer Transform(CommunicationResult queryResult, Customer entity) + { + var customer = entity ?? new Customer(); + customer.Communication = new Communication + { + ContactId = queryResult.Id, + Email = queryResult.Email, + Phone = queryResult.Telephone + }; + + if (queryResult.HouseNo != null) + customer.Communication.Address = new Address + { + HouseNo = queryResult.HouseNo, + City = queryResult.City, + Country = queryResult.Country, + PostalCode = queryResult.PostalCode, + Region = queryResult.Region + }; + + return customer; + } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Transforms/CustomerOrderItemsTransform.cs b/tests/Schemio.Object.Tests/Transforms/CustomerOrderItemsTransform.cs new file mode 100644 index 0000000..bc45a66 --- /dev/null +++ b/tests/Schemio.Object.Tests/Transforms/CustomerOrderItemsTransform.cs @@ -0,0 +1,30 @@ +using Schemio.Object.Tests.Entities; +using Schemio.Object.Tests.Queries; + +namespace Schemio.Object.Tests.Transforms +{ + public class CustomerOrderItemsTransform : BaseTransformer + { + public override Customer Transform(OrderItemCollectionResult queryResult, Customer entity) + { + if (queryResult.OrderItems == null || entity?.Orders == null) + return entity; + + foreach (var item in queryResult.OrderItems.Where(x => x.Items != null)) + foreach (var order in entity.Orders) + { + if (order.OrderId == item.OrderId) + { + order.Items = item.Items.Select(x => new OrderItem + { + ItemId = x.ItemId, + Name = x.Name, + Cost = x.Cost + }).ToArray(); + } + } + + return entity; + } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Transforms/CustomerOrdersTransform.cs b/tests/Schemio.Object.Tests/Transforms/CustomerOrdersTransform.cs new file mode 100644 index 0000000..2455ce6 --- /dev/null +++ b/tests/Schemio.Object.Tests/Transforms/CustomerOrdersTransform.cs @@ -0,0 +1,24 @@ +using Schemio.Object.Tests.Entities; +using Schemio.Object.Tests.Queries; + +namespace Schemio.Object.Tests.Transforms +{ + public class CustomerOrdersTransform : BaseTransformer + { + public override Customer Transform(OrderCollectionResult queryResult, Customer entity) + { + if (queryResult.Orders == null) + return entity; + + var customer = entity ?? new Customer(); + customer.Orders = queryResult.Orders.Select(x => new Order + { + Date = x.Date, + OrderId = x.OrderId, + OrderNo = x.OrderNo + }).ToArray(); + + return customer; + } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Transforms/CustomerTransform.cs b/tests/Schemio.Object.Tests/Transforms/CustomerTransform.cs index ad1a09a..514f396 100644 --- a/tests/Schemio.Object.Tests/Transforms/CustomerTransform.cs +++ b/tests/Schemio.Object.Tests/Transforms/CustomerTransform.cs @@ -1,16 +1,18 @@ +using Schemio.Object.Core; using Schemio.Object.Tests.Entities; using Schemio.Object.Tests.Queries; namespace Schemio.Object.Tests.Transforms { - internal class CustomerTransform : BaseTransformer + public class CustomerTransform : BaseTransformer { public override Customer Transform(CustomerResult queryResult, Customer entity) { - entity ??= new Customer(); - entity.Id = queryResult.Id; - entity.CustomerCode = queryResult.CustomerCode; - return entity; + var customer = entity ?? new Customer(); + customer.CustomerId = queryResult.Id; + customer.CustomerName = queryResult.CustomerName; + customer.CustomerCode = queryResult.CustomerCode; + return customer; } } } \ No newline at end of file From a228d4f0d19429339398dd31ea269a7cd9a0708f Mon Sep 17 00:00:00 2001 From: Ninja Date: Wed, 1 Nov 2023 01:47:55 +0000 Subject: [PATCH 06/24] - fix build --- src/Schemio.Object/PathMatchers/JPathMatcher.cs | 8 +++++--- src/Schemio.Object/PathMatchers/XPathMatcher.cs | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Schemio.Object/PathMatchers/JPathMatcher.cs b/src/Schemio.Object/PathMatchers/JPathMatcher.cs index eb0fb6a..7361732 100644 --- a/src/Schemio.Object/PathMatchers/JPathMatcher.cs +++ b/src/Schemio.Object/PathMatchers/JPathMatcher.cs @@ -1,13 +1,15 @@ using Schemio.Object.Core; using Schemio.Object.Core.Helpers; +using System.Linq; +using System.Text.RegularExpressions; namespace Schemio.Object.Pathmatchers { public class JPathMatcher : ISchemaPathMatcher { public bool IsMatch(string inputXPath, ISchemaPaths configuredXPaths) => - // Does the template jsonpath contain any of the mapping jsonpaths? - inputXPath.IsNotNullOrEmpty() - && configuredXPaths.Paths.Any(x => inputXPath.ToLower().Contains(x.ToLower())); + // Does the template xpath contain any of the mapping xpaths? + inputXPath.IsNotNullOrEmpty() + && configuredXPaths.Paths.Any(x => inputXPath.ToLower().Contains(x.ToLower())); } } \ No newline at end of file diff --git a/src/Schemio.Object/PathMatchers/XPathMatcher.cs b/src/Schemio.Object/PathMatchers/XPathMatcher.cs index ec4c44d..34dd9d9 100644 --- a/src/Schemio.Object/PathMatchers/XPathMatcher.cs +++ b/src/Schemio.Object/PathMatchers/XPathMatcher.cs @@ -1,11 +1,13 @@ using Schemio.Object.Core; using Schemio.Object.Core.Helpers; -using System.Linq; +using System.Text.RegularExpressions; namespace Schemio.Object.PathMatchers { public class XPathMatcher : ISchemaPathMatcher { + private static readonly Regex ancestorRegex = new Regex(@"=ancestor::(?'path'.*?)(/@|\[.*\]/@)", RegexOptions.Compiled); + public bool IsMatch(string inputXPath, ISchemaPaths configuredXPaths) => // Does the template xpath contain any of the mapping xpaths? inputXPath.IsNotNullOrEmpty() From 21ca6f55dc781262b7c4ebd9283886f3ef6801df Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 01:30:18 +0000 Subject: [PATCH 07/24] - refactor 1 --- README.md | 111 ++++++++++++- src/Schemio.Object.SQL/ISQLQuery.cs | 2 - src/Schemio.Object.SQL/SQLEngine.cs | 2 - src/Schemio.Object.SQL/SQLQuery.cs | 5 - src/Schemio.Object.SQL/SQLQueryEngine.cs | 4 - src/Schemio.Object/BaseEntity.cs | 2 - src/Schemio.Object/BaseEntitySchema.cs | 5 +- src/Schemio.Object/BaseQuery.cs | 5 +- src/Schemio.Object/BaseTransformer.cs | 6 +- src/Schemio.Object/ChildrenQueries.cs | 5 +- src/Schemio.Object/CreateSchema.cs | 7 +- src/Schemio.Object/DataProvider.cs | 15 +- .../Helpers/ExtentionMethods.cs | 2 +- .../Helpers/Xml/XDocumentExts.cs | 3 +- src/Schemio.Object/Helpers/Xml/XmlHelper.cs | 2 +- .../Helpers/Xml/XmlSanitizer.cs | 2 +- src/Schemio.Object/IDataContext.cs | 2 +- src/Schemio.Object/IDataContextValidator.cs | 2 +- src/Schemio.Object/IDataProvider.cs | 2 +- src/Schemio.Object/IEntity.cs | 2 +- src/Schemio.Object/IEntitySchema.cs | 4 +- src/Schemio.Object/IPolymorphicQueryResult.cs | 2 +- src/Schemio.Object/IQuery.cs | 5 +- src/Schemio.Object/IQueryBuilder.cs | 2 +- src/Schemio.Object/IQueryEngine.cs | 2 +- src/Schemio.Object/IQueryExecutor.cs | 4 +- src/Schemio.Object/IQueryList.cs | 6 +- src/Schemio.Object/IQueryParameter.cs | 2 +- src/Schemio.Object/IQueryResult.cs | 2 +- src/Schemio.Object/ISchemaPathMatcher.cs | 2 +- src/Schemio.Object/ITransformExecutor.cs | 4 +- src/Schemio.Object/ITransformer.cs | 19 +-- src/Schemio.Object/Impl/EventAggregator.cs | 5 +- src/Schemio.Object/Impl/EventSubscriber.cs | 9 +- src/Schemio.Object/Impl/QueryBuilder.cs | 7 +- src/Schemio.Object/Impl/QueryExecutor.cs | 5 +- src/Schemio.Object/Impl/TransformExecutor.cs | 16 +- .../PathMatchers/JPathMatcher.cs | 5 +- .../PathMatchers/XPathMatcher.cs | 3 +- src/Schemio.Object/QueryComparer.cs | 4 +- src/Schemio.Object/QueryList.cs | 5 +- src/Schemio.Object/XML/XMLDataProvider.cs | 6 +- .../DataProvider.Tests/DataProviderTests.cs | 45 ++++++ .../DataProvider.Tests/QueryBuilderTests.cs | 147 ++++++++++++++++++ .../TransformExecutorTests.cs | 92 +++++++++++ .../CustomerContext.cs | 4 +- .../{ => EntitySetup}/Entities/Address.cs | 4 +- .../Entities/Communication.cs | 4 +- .../{ => EntitySetup}/Entities/Customer.cs | 4 +- .../EntitySetup/Entities/EntityDiagram.cd | 50 ++++++ .../{ => EntitySetup}/Entities/Order.cs | 4 +- .../{ => EntitySetup}/Entities/OrderItem.cs | 4 +- .../EntitySchemas/CustomerSchema.cs | 11 +- .../Queries/CommunicationResult.cs | 14 ++ .../Queries/CustomerCommunicationQuery.cs | 16 +- .../Queries/CustomerOrderItemsQuery.cs | 20 +-- .../Queries/CustomerOrdersQuery.cs | 18 +-- .../EntitySetup/Queries/CustomerParameter.cs | 7 + .../Queries/CustomerQuery.cs | 17 +- .../EntitySetup/Queries/CustomerResult.cs | 9 ++ .../Queries/OrderCollectionResult.cs | 15 ++ .../Queries/OrderItemCollectionResult.cs | 13 ++ .../EntitySetup/Queries/OrderItemParameter.cs | 7 + .../CustomerCommunicationTransform.cs | 6 +- .../Transforms/CustomerOrderItemsTransform.cs | 10 +- .../Transforms/CustomerOrdersTransform.cs | 6 +- .../Transforms/CustomerTransform.cs | 7 +- .../Schemio.Object.Tests.csproj | 1 + tests/Schemio.Object.Tests/UnitTest1.cs | 2 +- 69 files changed, 600 insertions(+), 242 deletions(-) create mode 100644 tests/Schemio.Object.Tests/DataProvider.Tests/DataProviderTests.cs create mode 100644 tests/Schemio.Object.Tests/DataProvider.Tests/QueryBuilderTests.cs create mode 100644 tests/Schemio.Object.Tests/DataProvider.Tests/TransformExecutorTests.cs rename tests/Schemio.Object.Tests/{DataProvider => EntitySetup}/CustomerContext.cs (73%) rename tests/Schemio.Object.Tests/{ => EntitySetup}/Entities/Address.cs (81%) rename tests/Schemio.Object.Tests/{ => EntitySetup}/Entities/Communication.cs (76%) rename tests/Schemio.Object.Tests/{ => EntitySetup}/Entities/Customer.cs (81%) create mode 100644 tests/Schemio.Object.Tests/EntitySetup/Entities/EntityDiagram.cd rename tests/Schemio.Object.Tests/{ => EntitySetup}/Entities/Order.cs (75%) rename tests/Schemio.Object.Tests/{ => EntitySetup}/Entities/OrderItem.cs (70%) rename tests/Schemio.Object.Tests/{ => EntitySetup}/EntitySchemas/CustomerSchema.cs (80%) create mode 100644 tests/Schemio.Object.Tests/EntitySetup/Queries/CommunicationResult.cs rename tests/Schemio.Object.Tests/{ => EntitySetup}/Queries/CustomerCommunicationQuery.cs (57%) rename tests/Schemio.Object.Tests/{ => EntitySetup}/Queries/CustomerOrderItemsQuery.cs (59%) rename tests/Schemio.Object.Tests/{ => EntitySetup}/Queries/CustomerOrdersQuery.cs (58%) create mode 100644 tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerParameter.cs rename tests/Schemio.Object.Tests/{ => EntitySetup}/Queries/CustomerQuery.cs (59%) create mode 100644 tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerResult.cs create mode 100644 tests/Schemio.Object.Tests/EntitySetup/Queries/OrderCollectionResult.cs create mode 100644 tests/Schemio.Object.Tests/EntitySetup/Queries/OrderItemCollectionResult.cs create mode 100644 tests/Schemio.Object.Tests/EntitySetup/Queries/OrderItemParameter.cs rename tests/Schemio.Object.Tests/{ => EntitySetup}/Transforms/CustomerCommunicationTransform.cs (85%) rename tests/Schemio.Object.Tests/{ => EntitySetup}/Transforms/CustomerOrderItemsTransform.cs (81%) rename tests/Schemio.Object.Tests/{ => EntitySetup}/Transforms/CustomerOrdersTransform.cs (79%) rename tests/Schemio.Object.Tests/{ => EntitySetup}/Transforms/CustomerTransform.cs (75%) diff --git a/README.md b/README.md index f85412f..2bcbe3c 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,113 @@ [![NuGet version](https://badge.fury.io/nu/Schemio.Object.svg)](https://badge.fury.io/nu/Schemio.Object) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/NinjaRocks/Schemio.Object/blob/master/License.md) [![CI](https://github.com/NinjaRocks/Data2Xml/actions/workflows/CI.yml/badge.svg)](https://github.com/NinjaRocks/Data2Xml/actions/workflows/CI.yml) [![GitHub Release](https://img.shields.io/github/v/release/ninjarocks/Data2Xml?logo=github&sort=semver)](https://github.com/ninjarocks/Data2Xml/releases/latest) [![CodeQL](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml/badge.svg)](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml) [![.Net Stardard](https://img.shields.io/badge/.Net%20Standard-2.1-blue)](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) -- -### .Net Standard 2.1 Library to map data to Entity using Schema Paths (Like XPath or JsonPath). +Schemio - is a .Net 6 utility to hydrate entities with data conditionally by given list of schema paths mapping to object graph. Support JsonPath and Xpath schema mappings. + +## How to use Schemio? +> Step 1 - To mark the entity to hydrate data using schemio, derive the entity from `IEntity` interface. Bear in mind this is the root entity. +``` + public class Customer : IEntity + { + public int CustomerId { get; set; } + public string CustomerCode { get; set; } + public string CustomerName { get; set; } + public Communication Communication { get; set; } + public Order[] Orders { get; set; } + } +``` +Above, Customer is the entity we want to hydrate with data conditionaly passing in schema paths mapping to object graph. + +> Step 2 - Define schema configuration to map query/transformer pairs to schema paths mapping to the object graph. +Derive schema from `IEntitySchema` where T is entity to hydrate. The query/transformer mappings can be nested to 5 levels down. You could map multiple schema paths to a given query/transformer pair. + + +``` +internal class CustomerSchema : IEntitySchema + { + private IEnumerable> mappings; + + private decimal version; + + public IEnumerable> Mappings => mappings; + public decimal Version => version; + + public CustomerSchema() + { + version = 1; + + // Create an object mapping graph of query and transformer pairs using xpaths. + mappings = CreateSchema.For() + .Map(For.Paths("customer/id", "customer/customercode", "customer/customername"), + customer => customer.Dependents + .Map(For.Paths("customer/communication")) + .Map(For.Paths("customer/orders"), + customerOrders => customerOrders.Dependents + .Map(For.Paths("customer/orders/order/items"))) + ).Complete(); + } + } +``` + +#### Query Class +The purpose of a query class is to execute to fetch data when mapped schema path is included in the context paramer of data provider. +- To define a query for a schema path, you need to implement the query by deriving from `BaseQuery : IQuery where TQueryParameter : IQueryParameter where TQueryResult : IQueryResult` +- You may want to run the query in parent or child mode and define the relevant overrides to resovle the query parameter accordingly. +- In `parent` mode the query parameter is resolved using `context` parameter passed to data provider class. +- In `child` mode, the query parameter is resolved using the `query result` of the `parent query` to which the current query is a child. You could have a maximum of `5` levels of children query nesting when defining the Entity schema. + +> See example Customer query as parent below. +``` +public class CustomerQuery : BaseQuery + { + public override void ResolveParameterInParentMode(IDataContext context) + { + // Executes as root or level 1 query. + var customer = (CustomerContext)context; + QueryParameter = new CustomerParameter + { + CustomerId = customer.CustomerId + }; + } + + public override void ResolveParameterInChildMode(IDataContext context, IQueryResult parentQueryResult) + { + // Does not execute as child to any query. + } + } +``` +> see communication query as child to customer query below. +``` + internal class CustomerCommunicationQuery : BaseQuery + { + public override void ResolveParameterInParentMode(IDataContext context) + { + // Does not execute as root or level 1 queries. + } + + public override void ResolveParameterInChildMode(IDataContext context, IQueryResult parentQueryResult) + { + // Execute as child to customer query. + var customer = (CustomerResult)parentQueryResult; + QueryParameter = new CustomerParameter + { + CustomerId = customer.Id + }; + } + } +``` +The parent/child relationship is achieved via entity schema configuration. see CustomerSchema above. +#### Tranformer Class +The purpose of the transformer is to map the data fetched by the linked query class to relevant schema section of the entity to be data hydrated. +- To define a transformer class for the schema path, you need to derive from `BaseTransformer : ITransformer + where T : IEntity + where TD : IQueryResult` +- The output of the linked query serves as input to the transformer to map data to configured section of the entity in context. + +> Step 3 - Use the DataProvider class to get the entity with hydrated data based on configuration and passed in context paratemer with relevant schema paths. +``` +var + +``` + +## Extending Schemio +> coming soon diff --git a/src/Schemio.Object.SQL/ISQLQuery.cs b/src/Schemio.Object.SQL/ISQLQuery.cs index 426079d..4e861f3 100644 --- a/src/Schemio.Object.SQL/ISQLQuery.cs +++ b/src/Schemio.Object.SQL/ISQLQuery.cs @@ -1,5 +1,3 @@ -using Schemio.Object.Core; - namespace Schemio.Object.SQL { public interface ISQLQuery diff --git a/src/Schemio.Object.SQL/SQLEngine.cs b/src/Schemio.Object.SQL/SQLEngine.cs index e5f1abf..4c01370 100644 --- a/src/Schemio.Object.SQL/SQLEngine.cs +++ b/src/Schemio.Object.SQL/SQLEngine.cs @@ -1,5 +1,3 @@ -using Schemio.Object.Core; - namespace Schemio.Object.SQL { public interface SQLEngine diff --git a/src/Schemio.Object.SQL/SQLQuery.cs b/src/Schemio.Object.SQL/SQLQuery.cs index aab89c0..f186665 100644 --- a/src/Schemio.Object.SQL/SQLQuery.cs +++ b/src/Schemio.Object.SQL/SQLQuery.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Schemio.Object.Core; - namespace Schemio.Object.SQL { //internal abstract class SQLQuery : IQuery diff --git a/src/Schemio.Object.SQL/SQLQueryEngine.cs b/src/Schemio.Object.SQL/SQLQueryEngine.cs index 57ade88..58e6567 100644 --- a/src/Schemio.Object.SQL/SQLQueryEngine.cs +++ b/src/Schemio.Object.SQL/SQLQueryEngine.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; using System.Data.Common; using System.Data; -using System.Linq; -using Schemio.Object.Core; using Dapper; namespace Schemio.Object.SQL diff --git a/src/Schemio.Object/BaseEntity.cs b/src/Schemio.Object/BaseEntity.cs index 3764800..202c2d2 100644 --- a/src/Schemio.Object/BaseEntity.cs +++ b/src/Schemio.Object/BaseEntity.cs @@ -1,5 +1,3 @@ -using Schemio.Object.Core; - namespace Schemio.Object { //public abstract class BaseEntity : IEntity diff --git a/src/Schemio.Object/BaseEntitySchema.cs b/src/Schemio.Object/BaseEntitySchema.cs index e5d8bf7..429eda8 100644 --- a/src/Schemio.Object/BaseEntitySchema.cs +++ b/src/Schemio.Object/BaseEntitySchema.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; - -namespace Schemio.Object.Core +namespace Schemio.Object { /// /// Implement to configure schema path mappings for an Entity. diff --git a/src/Schemio.Object/BaseQuery.cs b/src/Schemio.Object/BaseQuery.cs index d3343bf..495663e 100644 --- a/src/Schemio.Object/BaseQuery.cs +++ b/src/Schemio.Object/BaseQuery.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; - -namespace Schemio.Object.Core +namespace Schemio.Object { /// /// Implement this base class to create a data provider query. diff --git a/src/Schemio.Object/BaseTransformer.cs b/src/Schemio.Object/BaseTransformer.cs index 2544a61..ca0b753 100644 --- a/src/Schemio.Object/BaseTransformer.cs +++ b/src/Schemio.Object/BaseTransformer.cs @@ -1,5 +1,3 @@ -using Schemio.Object.Core; - namespace Schemio.Object { public abstract class BaseTransformer : ITransformer @@ -7,13 +5,13 @@ public abstract class BaseTransformer : ITransformer where TD : IQueryResult { public IDataContext Context { get; private set; } + public Type SupportedQueryResult => typeof(TD); public void ResolveContext(IDataContext context) => Context = context; public IEntity Run(IQueryResult queryResult, IEntity entity) { - return queryResult.GetType() == typeof(TD) || queryResult is TD - ? Transform((TD)queryResult, (T)entity) : entity; + return Transform((TD)queryResult, (T)entity); } public abstract T Transform(TD queryResult, T entity); diff --git a/src/Schemio.Object/ChildrenQueries.cs b/src/Schemio.Object/ChildrenQueries.cs index 2427810..d934593 100644 --- a/src/Schemio.Object/ChildrenQueries.cs +++ b/src/Schemio.Object/ChildrenQueries.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; - -namespace Schemio.Object.Core +namespace Schemio.Object { public class ChildrenQueries { diff --git a/src/Schemio.Object/CreateSchema.cs b/src/Schemio.Object/CreateSchema.cs index 105fecd..7ec8f97 100644 --- a/src/Schemio.Object/CreateSchema.cs +++ b/src/Schemio.Object/CreateSchema.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; - -namespace Schemio.Object.Core +namespace Schemio.Object { #region Helpers @@ -66,13 +63,11 @@ public IMapOrComplete Map(ISchemaPaths paths, Func)dependents(mapping)).GetMappings) { dep.DependentOn ??= mapping.Query; Add(dep); } - } Add(mapping); diff --git a/src/Schemio.Object/DataProvider.cs b/src/Schemio.Object/DataProvider.cs index 8148ec6..f4daea4 100644 --- a/src/Schemio.Object/DataProvider.cs +++ b/src/Schemio.Object/DataProvider.cs @@ -1,14 +1,25 @@ using Microsoft.Extensions.Logging; +using Schemio.Object.Impl; -namespace Schemio.Object.Core.Impl +namespace Schemio.Object { - public class DataProvider : IDataProvider where T : IEntity + public class DataProvider : IDataProvider where T : IEntity, new() { private readonly ILogger> logger; private readonly IQueryExecutor queryExecutor; private readonly IQueryBuilder queryBuilder; private readonly ITransformExecutor transformExecutor; + public DataProvider( + ILogger> logger, + IEntitySchema entitySchema, + ISchemaPathMatcher schemaPathMatcher, + IQueryEngine[] queryEngines) + : this(logger, new QueryBuilder(entitySchema, schemaPathMatcher), + new QueryExecutor(queryEngines), new TransformExecutor(entitySchema)) + { + } + public DataProvider( ILogger> logger, IQueryBuilder queryBuilder, diff --git a/src/Schemio.Object/Helpers/ExtentionMethods.cs b/src/Schemio.Object/Helpers/ExtentionMethods.cs index 42a9745..0c099fa 100644 --- a/src/Schemio.Object/Helpers/ExtentionMethods.cs +++ b/src/Schemio.Object/Helpers/ExtentionMethods.cs @@ -1,4 +1,4 @@ -namespace Schemio.Object.Core.Helpers +namespace Schemio.Object.Helpers { public static class ExtentionMethods { diff --git a/src/Schemio.Object/Helpers/Xml/XDocumentExts.cs b/src/Schemio.Object/Helpers/Xml/XDocumentExts.cs index a12258b..b9fd172 100644 --- a/src/Schemio.Object/Helpers/Xml/XDocumentExts.cs +++ b/src/Schemio.Object/Helpers/Xml/XDocumentExts.cs @@ -1,7 +1,6 @@ -using System.Linq; using System.Xml.Linq; -namespace Schemio.Object.Core.Helpers.Xml +namespace Schemio.Object.Helpers.Xml { public static class XDocumentExts { diff --git a/src/Schemio.Object/Helpers/Xml/XmlHelper.cs b/src/Schemio.Object/Helpers/Xml/XmlHelper.cs index 85b3330..c0b65c1 100644 --- a/src/Schemio.Object/Helpers/Xml/XmlHelper.cs +++ b/src/Schemio.Object/Helpers/Xml/XmlHelper.cs @@ -2,7 +2,7 @@ using System.Xml; using System.Xml.Serialization; -namespace Schemio.Object.Core.Helpers.Xml +namespace Schemio.Object.Helpers.Xml { public static class XmlHelper { diff --git a/src/Schemio.Object/Helpers/Xml/XmlSanitizer.cs b/src/Schemio.Object/Helpers/Xml/XmlSanitizer.cs index 0717d48..bd964ee 100644 --- a/src/Schemio.Object/Helpers/Xml/XmlSanitizer.cs +++ b/src/Schemio.Object/Helpers/Xml/XmlSanitizer.cs @@ -2,7 +2,7 @@ using System.Text.RegularExpressions; using System.Xml; -namespace Schemio.Object.Core.Helpers.Xml +namespace Schemio.Object.Helpers.Xml { public static class XmlSanitizer { diff --git a/src/Schemio.Object/IDataContext.cs b/src/Schemio.Object/IDataContext.cs index 5dcd921..2b38183 100644 --- a/src/Schemio.Object/IDataContext.cs +++ b/src/Schemio.Object/IDataContext.cs @@ -1,4 +1,4 @@ -namespace Schemio.Object.Core +namespace Schemio.Object { public interface IDataContext { diff --git a/src/Schemio.Object/IDataContextValidator.cs b/src/Schemio.Object/IDataContextValidator.cs index 9a434cc..ca36725 100644 --- a/src/Schemio.Object/IDataContextValidator.cs +++ b/src/Schemio.Object/IDataContextValidator.cs @@ -1,4 +1,4 @@ -namespace Schemio.Object.Core +namespace Schemio.Object { public interface IDataContextValidator { diff --git a/src/Schemio.Object/IDataProvider.cs b/src/Schemio.Object/IDataProvider.cs index 53bee01..48c21a1 100644 --- a/src/Schemio.Object/IDataProvider.cs +++ b/src/Schemio.Object/IDataProvider.cs @@ -1,4 +1,4 @@ -namespace Schemio.Object.Core +namespace Schemio.Object { public interface IDataProvider where T : IEntity { diff --git a/src/Schemio.Object/IEntity.cs b/src/Schemio.Object/IEntity.cs index f6c12fa..f4dc6fb 100644 --- a/src/Schemio.Object/IEntity.cs +++ b/src/Schemio.Object/IEntity.cs @@ -1,4 +1,4 @@ -namespace Schemio.Object.Core +namespace Schemio.Object { /// /// Implement Entity required to be hydrated (using query/transformer). diff --git a/src/Schemio.Object/IEntitySchema.cs b/src/Schemio.Object/IEntitySchema.cs index 5a2ccba..d37e0f3 100644 --- a/src/Schemio.Object/IEntitySchema.cs +++ b/src/Schemio.Object/IEntitySchema.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Schemio.Object.Core +namespace Schemio.Object { /// /// Implement to configure schema path mappings for an Entity. diff --git a/src/Schemio.Object/IPolymorphicQueryResult.cs b/src/Schemio.Object/IPolymorphicQueryResult.cs index c73eaa7..da18ffa 100644 --- a/src/Schemio.Object/IPolymorphicQueryResult.cs +++ b/src/Schemio.Object/IPolymorphicQueryResult.cs @@ -1,4 +1,4 @@ -namespace Schemio.Object.Core +namespace Schemio.Object { public interface IPolymorphicQueryResult : IQueryResult { diff --git a/src/Schemio.Object/IQuery.cs b/src/Schemio.Object/IQuery.cs index 3d4335b..cbb8a34 100644 --- a/src/Schemio.Object/IQuery.cs +++ b/src/Schemio.Object/IQuery.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; - -namespace Schemio.Object.Core +namespace Schemio.Object { /// /// Implement IQuery to fetch data using API or database. diff --git a/src/Schemio.Object/IQueryBuilder.cs b/src/Schemio.Object/IQueryBuilder.cs index ebaa4e6..af754c0 100644 --- a/src/Schemio.Object/IQueryBuilder.cs +++ b/src/Schemio.Object/IQueryBuilder.cs @@ -1,4 +1,4 @@ -namespace Schemio.Object.Core +namespace Schemio.Object { public interface IQueryBuilder { diff --git a/src/Schemio.Object/IQueryEngine.cs b/src/Schemio.Object/IQueryEngine.cs index 57faf4f..9aa554f 100644 --- a/src/Schemio.Object/IQueryEngine.cs +++ b/src/Schemio.Object/IQueryEngine.cs @@ -1,4 +1,4 @@ -namespace Schemio.Object.Core +namespace Schemio.Object { public interface IQueryEngine { diff --git a/src/Schemio.Object/IQueryExecutor.cs b/src/Schemio.Object/IQueryExecutor.cs index fa636b0..7e3bf93 100644 --- a/src/Schemio.Object/IQueryExecutor.cs +++ b/src/Schemio.Object/IQueryExecutor.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Schemio.Object.Core +namespace Schemio.Object { public interface IQueryExecutor { diff --git a/src/Schemio.Object/IQueryList.cs b/src/Schemio.Object/IQueryList.cs index ea37d18..bdca13f 100644 --- a/src/Schemio.Object/IQueryList.cs +++ b/src/Schemio.Object/IQueryList.cs @@ -1,9 +1,7 @@ -using System.Collections.Generic; - -namespace Schemio.Object.Core +namespace Schemio.Object { public interface IQueryList - { + { int QueryDependencyDepth { get; set; } IEnumerable Queries { get; } diff --git a/src/Schemio.Object/IQueryParameter.cs b/src/Schemio.Object/IQueryParameter.cs index 43d599f..b8bc423 100644 --- a/src/Schemio.Object/IQueryParameter.cs +++ b/src/Schemio.Object/IQueryParameter.cs @@ -1,4 +1,4 @@ -namespace Schemio.Object.Core +namespace Schemio.Object { public interface IQueryParameter { diff --git a/src/Schemio.Object/IQueryResult.cs b/src/Schemio.Object/IQueryResult.cs index 03bc6ec..122c3c2 100644 --- a/src/Schemio.Object/IQueryResult.cs +++ b/src/Schemio.Object/IQueryResult.cs @@ -1,4 +1,4 @@ -namespace Schemio.Object.Core +namespace Schemio.Object { public interface IQueryResult { diff --git a/src/Schemio.Object/ISchemaPathMatcher.cs b/src/Schemio.Object/ISchemaPathMatcher.cs index ae3893d..909d981 100644 --- a/src/Schemio.Object/ISchemaPathMatcher.cs +++ b/src/Schemio.Object/ISchemaPathMatcher.cs @@ -1,4 +1,4 @@ -namespace Schemio.Object.Core +namespace Schemio.Object { public interface ISchemaPathMatcher { diff --git a/src/Schemio.Object/ITransformExecutor.cs b/src/Schemio.Object/ITransformExecutor.cs index 10aab20..e28a627 100644 --- a/src/Schemio.Object/ITransformExecutor.cs +++ b/src/Schemio.Object/ITransformExecutor.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Schemio.Object.Core +namespace Schemio.Object { public interface ITransformExecutor where TEntity : IEntity { diff --git a/src/Schemio.Object/ITransformer.cs b/src/Schemio.Object/ITransformer.cs index 13c8f8f..61266b3 100644 --- a/src/Schemio.Object/ITransformer.cs +++ b/src/Schemio.Object/ITransformer.cs @@ -1,25 +1,14 @@ -namespace Schemio.Object.Core +namespace Schemio.Object { /// - /// Implement transformer to map data to entity using query result. + /// Implement transformer to map data to entity using supported query result. /// - /// - /// - public interface ITransformer : ITransformer - where TQueryResult : IQueryResult - where TEntity : IEntity - { - //IDataContext Context { get; } - - //void ResolveContext(IDataContext context); - - // TEntity Run(TQueryResult queryResult, TEntity entity); - } - public interface ITransformer { IDataContext Context { get; } + Type SupportedQueryResult { get; } + void ResolveContext(IDataContext context); IEntity Run(IQueryResult queryResult, IEntity entity); diff --git a/src/Schemio.Object/Impl/EventAggregator.cs b/src/Schemio.Object/Impl/EventAggregator.cs index 95c4c87..1f8cc86 100644 --- a/src/Schemio.Object/Impl/EventAggregator.cs +++ b/src/Schemio.Object/Impl/EventAggregator.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; - -namespace Schemio.Object.Core.Impl +namespace Schemio.Object.Impl { public class EventAggregator { diff --git a/src/Schemio.Object/Impl/EventSubscriber.cs b/src/Schemio.Object/Impl/EventSubscriber.cs index 5ee650d..758e70d 100644 --- a/src/Schemio.Object/Impl/EventSubscriber.cs +++ b/src/Schemio.Object/Impl/EventSubscriber.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Schemio.Object.Core.Impl +namespace Schemio.Object.Impl { public class EventSubscriber : ISubscriber { @@ -32,9 +29,7 @@ public void OnEventHandler(IDataContext context, ExecutorResultArgs args) continue; foreach (var query in unresolved.Queries) - { query.ResolveParameterInChildMode(context, queryResult); - } } } @@ -54,9 +49,7 @@ public void OnEventHandler(IDataContext context, ExecutorResultArgs args) continue; foreach (var query in unresolved.Queries) - { query.ResolveParameterInChildMode(context, queryResult); - } } } } diff --git a/src/Schemio.Object/Impl/QueryBuilder.cs b/src/Schemio.Object/Impl/QueryBuilder.cs index 5a111a4..a88c8a5 100644 --- a/src/Schemio.Object/Impl/QueryBuilder.cs +++ b/src/Schemio.Object/Impl/QueryBuilder.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Schemio.Object.Core.Impl +namespace Schemio.Object.Impl { public class QueryBuilder : IQueryBuilder where T : IEntity { @@ -40,7 +37,7 @@ private QueryList GetMappedQueries(IReadOnlyCollection> foreach (var map in maps) { var dependentQueries = - mappings.Where(x => x.Order == (index + 1) && x.DependentOn != null && x.DependentOn.GetType() == map.Query.GetType()).ToList(); + mappings.Where(x => x.Order == index + 1 && x.DependentOn != null && x.DependentOn.GetType() == map.Query.GetType()).ToList(); map.Query.Children ??= new List(); diff --git a/src/Schemio.Object/Impl/QueryExecutor.cs b/src/Schemio.Object/Impl/QueryExecutor.cs index a4bec3c..25f9b49 100644 --- a/src/Schemio.Object/Impl/QueryExecutor.cs +++ b/src/Schemio.Object/Impl/QueryExecutor.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Schemio.Object.Core.Impl +namespace Schemio.Object.Impl { public class QueryExecutor : IQueryExecutor { diff --git a/src/Schemio.Object/Impl/TransformExecutor.cs b/src/Schemio.Object/Impl/TransformExecutor.cs index df5e6f3..19c17a2 100644 --- a/src/Schemio.Object/Impl/TransformExecutor.cs +++ b/src/Schemio.Object/Impl/TransformExecutor.cs @@ -1,15 +1,12 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Schemio.Object.Core.Impl +namespace Schemio.Object.Impl { public class TransformExecutor : ITransformExecutor where T : IEntity, new() { - private readonly IEntitySchema entitySchemaMapping; + private readonly IEntitySchema entitySchema; - public TransformExecutor(IEntitySchema entitySchemaMapping) + public TransformExecutor(IEntitySchema entitySchema) { - this.entitySchemaMapping = entitySchemaMapping; + this.entitySchema = entitySchema; } /// @@ -25,7 +22,7 @@ public T Execute(IDataContext context, IList queryResults) if (queryResults == null || !queryResults.Any()) return entity; - var mappings = entitySchemaMapping.Mappings.ToList(); + var mappings = entitySchema.Mappings.ToList(); // resolve context of each transformer so it is available inside for transformation if required. mappings.ForEach(mapping => mapping.Transformer.ResolveContext(context)); @@ -42,7 +39,8 @@ public T Execute(IDataContext context, IList queryResults) .ToList(); foreach (var queryResult in queryResults) - transformers.ForEach(transformer => transformer.Run(queryResult, entity)); + transformers.Where(transformer => transformer.SupportedQueryResult == queryResult.GetType()).ToList() + .ForEach(supportedtransformer => supportedtransformer.Run(queryResult, entity)); } return entity; diff --git a/src/Schemio.Object/PathMatchers/JPathMatcher.cs b/src/Schemio.Object/PathMatchers/JPathMatcher.cs index 7361732..a4c7f9e 100644 --- a/src/Schemio.Object/PathMatchers/JPathMatcher.cs +++ b/src/Schemio.Object/PathMatchers/JPathMatcher.cs @@ -1,7 +1,4 @@ -using Schemio.Object.Core; -using Schemio.Object.Core.Helpers; -using System.Linq; -using System.Text.RegularExpressions; +using Schemio.Object.Helpers; namespace Schemio.Object.Pathmatchers { diff --git a/src/Schemio.Object/PathMatchers/XPathMatcher.cs b/src/Schemio.Object/PathMatchers/XPathMatcher.cs index 34dd9d9..351625f 100644 --- a/src/Schemio.Object/PathMatchers/XPathMatcher.cs +++ b/src/Schemio.Object/PathMatchers/XPathMatcher.cs @@ -1,5 +1,4 @@ -using Schemio.Object.Core; -using Schemio.Object.Core.Helpers; +using Schemio.Object.Helpers; using System.Text.RegularExpressions; namespace Schemio.Object.PathMatchers diff --git a/src/Schemio.Object/QueryComparer.cs b/src/Schemio.Object/QueryComparer.cs index c011602..d9aeb69 100644 --- a/src/Schemio.Object/QueryComparer.cs +++ b/src/Schemio.Object/QueryComparer.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Schemio.Object.Core +namespace Schemio.Object { public class QueryComparer : IEqualityComparer { diff --git a/src/Schemio.Object/QueryList.cs b/src/Schemio.Object/QueryList.cs index 7891334..216dea0 100644 --- a/src/Schemio.Object/QueryList.cs +++ b/src/Schemio.Object/QueryList.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Schemio.Object.Core +namespace Schemio.Object { public class QueryList : IQueryList { diff --git a/src/Schemio.Object/XML/XMLDataProvider.cs b/src/Schemio.Object/XML/XMLDataProvider.cs index 9487554..7080649 100644 --- a/src/Schemio.Object/XML/XMLDataProvider.cs +++ b/src/Schemio.Object/XML/XMLDataProvider.cs @@ -1,10 +1,10 @@ -using Microsoft.Extensions.Logging; -using Schemio.Object.Core.Helpers.Xml; +using Microsoft.Extensions.Logging; +using Schemio.Object.Helpers.Xml; using System.Xml; using System.Xml.Linq; using System.Xml.Serialization; -namespace Schemio.Object.Core.XML +namespace Schemio.Object.XML { internal class XMLDataProvider where T : IEntity { diff --git a/tests/Schemio.Object.Tests/DataProvider.Tests/DataProviderTests.cs b/tests/Schemio.Object.Tests/DataProvider.Tests/DataProviderTests.cs new file mode 100644 index 0000000..2165b92 --- /dev/null +++ b/tests/Schemio.Object.Tests/DataProvider.Tests/DataProviderTests.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Moq; +using Schemio.Object.Tests.EntitySetup; +using Schemio.Object.Tests.EntitySetup.Entities; + +namespace Schemio.Object.Tests.DataProvider +{ + [TestFixture] + internal class DataProviderTests + { + private DataProvider _provider; + private Mock>> _logger; + private Mock> _queryBuilder; + private Mock _queryExecutor; + private Mock> _transformExecutor; + + [SetUp] + public void Setup() + { + _logger = new Mock>>(); + _queryBuilder = new Mock>(); + _queryExecutor = new Mock(); + _transformExecutor = new Mock>(); + + _provider = new DataProvider(_logger.Object, _queryBuilder.Object, _queryExecutor.Object, _transformExecutor.Object); + } + + [Test] + public void TestDataProvider() + { + var context = new CustomerContext { CustomerId = 1 }; + + _provider.GetData(context); + + _queryBuilder.Verify(x => x.Build(context), Times.Once); + _queryExecutor.Verify(x => x.Execute(context, It.IsAny()), Times.Once); + _transformExecutor.Verify(x => x.Execute(context, It.IsAny>()), Times.Once); + } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/DataProvider.Tests/QueryBuilderTests.cs b/tests/Schemio.Object.Tests/DataProvider.Tests/QueryBuilderTests.cs new file mode 100644 index 0000000..1b71198 --- /dev/null +++ b/tests/Schemio.Object.Tests/DataProvider.Tests/QueryBuilderTests.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Moq; +using Schemio.Object.Tests.EntitySetup.Entities; +using Schemio.Object.Tests.EntitySetup; +using Schemio.Object.Impl; +using Schemio.Object.Tests.EntitySetup.EntitySchemas; +using Schemio.Object.PathMatchers; +using Schemio.Object.Tests.EntitySetup.Queries; + +namespace Schemio.Object.Tests.DataProvider +{ + [TestFixture] + internal class QueryBuilderTests + { + private QueryBuilder _queryBuilder; + + private IEntitySchema _entitySchema; + private ISchemaPathMatcher _schemaPathMatcher; + + [SetUp] + public void Setup() + { + _entitySchema = new CustomerSchema(); + + /*----------------------------------------- * + * + * CreateSchema.For() + .Map(For.Paths("customer/id", "customer/customercode", "customer/customername"), + customer => customer.Dependents + .Map(For.Paths("customer/communication")) + .Map(For.Paths("customer/orders"), + customerOrders => customerOrders.Dependents + .Map(For.Paths("customer/orders/order/items"))) + ) + * + * --------------------------------------- */ + + _schemaPathMatcher = new XPathMatcher(); + _queryBuilder = new QueryBuilder(_entitySchema, _schemaPathMatcher); + } + + [Test] + public void TestQueryBuilderForCorrectParentQueryList() + { + var context = new CustomerContext { CustomerId = 1, Paths = new[] { "customer/customercode" } }; + + var result = _queryBuilder.Build(context); + + Assert.IsNotNull(result); + + // returns parent query with filtered out child communication query. + + Assert.That(result.QueryDependencyDepth == 0); + Assert.That(result.Queries.Count, Is.EqualTo(1)); + Assert.That(result.Queries.ElementAt(0).Children.Count, Is.EqualTo(0)); + + var parentQuery = result.Queries.First(); + Assert.That(parentQuery.GetType() == typeof(CustomerQuery)); + } + + [Test] + public void TestQueryBuilderForCorrectParentQueryListWithOneChildren() + { + var context = new CustomerContext { CustomerId = 1, Paths = new[] { "customer/customercode", "customer/communication" } }; + + var result = _queryBuilder.Build(context); + + Assert.IsNotNull(result); + + // returns parent query with filtered out child communication query. + + Assert.That(result.QueryDependencyDepth == 0); + Assert.That(result.Queries.Count, Is.EqualTo(1)); + Assert.That(result.Queries.ElementAt(0).Children.Count, Is.EqualTo(1)); + + var parentQuery = result.Queries.First(); + Assert.That(parentQuery.GetType() == typeof(CustomerQuery)); + + var childQuery = parentQuery.Children.First(); + Assert.That(childQuery.GetType() == typeof(CustomerCommunicationQuery)); + } + + [Test] + public void TestQueryBuilderForCorrectParentQueryListWithTwoChildren() + { + var context = new CustomerContext { CustomerId = 1, Paths = new[] { "customer/customercode", "customer/communication", "customer/orders" } }; + + var result = _queryBuilder.Build(context); + + Assert.IsNotNull(result); + + // returns parent query with filtered out children - communication & orders query. + + Assert.That(result.QueryDependencyDepth == 0); + Assert.That(result.Queries.Count, Is.EqualTo(1)); + Assert.That(result.Queries.ElementAt(0).Children.Count, Is.EqualTo(2)); + + var parentQuery = result.Queries.First(); + Assert.That(parentQuery.GetType() == typeof(CustomerQuery)); + + var communicationChildQuery = parentQuery.Children.FirstOrDefault(x => x.GetType() == typeof(CustomerCommunicationQuery)); + var ordersChildQuery = parentQuery.Children.FirstOrDefault(x => x.GetType() == typeof(CustomerOrdersQuery)); + + Assert.IsNotNull(communicationChildQuery); + Assert.IsNotNull(ordersChildQuery); + + // nested child query for order item not included as order items are excluded from paths + Assert.That(ordersChildQuery.Children.Count, Is.EqualTo(0)); + } + + [Test] + public void TestQueryBuilderForCorrectParentQueryListWithTwoChildrenAndOneChildFurtherNestedChildQuery() + { + var context = new CustomerContext { CustomerId = 1, Paths = new[] { "customer/customercode", "customer/communication", "customer/orders", "customer/orders/order/items" } }; + + var result = _queryBuilder.Build(context); + + Assert.IsNotNull(result); + + // returns parent query with filtered out children - communication & orders query. + + Assert.That(result.QueryDependencyDepth == 0); + Assert.That(result.Queries.Count, Is.EqualTo(1)); + Assert.That(result.Queries.ElementAt(0).Children.Count, Is.EqualTo(2)); + + var parentQuery = result.Queries.First(); + Assert.That(parentQuery.GetType() == typeof(CustomerQuery)); + + var communicationChildQuery = parentQuery.Children.FirstOrDefault(x => x.GetType() == typeof(CustomerCommunicationQuery)); + var ordersChildQuery = parentQuery.Children.FirstOrDefault(x => x.GetType() == typeof(CustomerOrdersQuery)); + + Assert.IsNotNull(communicationChildQuery); + Assert.IsNotNull(ordersChildQuery); + + // nested child query for order item in order query children as order items are included in paths + Assert.That(ordersChildQuery.Children.Count, Is.EqualTo(1)); + + var orderItemsChildQuery = ordersChildQuery.Children.FirstOrDefault(x => x.GetType() == typeof(CustomerOrderItemsQuery)); + Assert.IsNotNull(orderItemsChildQuery); + } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/DataProvider.Tests/TransformExecutorTests.cs b/tests/Schemio.Object.Tests/DataProvider.Tests/TransformExecutorTests.cs new file mode 100644 index 0000000..2f08ac8 --- /dev/null +++ b/tests/Schemio.Object.Tests/DataProvider.Tests/TransformExecutorTests.cs @@ -0,0 +1,92 @@ +using Schemio.Object.Tests.EntitySetup.Entities; +using Schemio.Object.Impl; +using Schemio.Object.Tests.EntitySetup; +using Schemio.Object.Tests.EntitySetup.Queries; + +namespace Schemio.Object.Tests.DataProvider +{ + [TestFixture] + internal class TransformExecutorTests + { + private TransformExecutor _transformExecutor; + private IEntitySchema _entitySchema; + + private static List<(Type result, int InvocationCount)> TransformerInvocations; + + [SetUp] + public void Setup() + { + _entitySchema = new MockCustomerSchema(); + _transformExecutor = new TransformExecutor(_entitySchema); + TransformerInvocations = new List<(Type result, int InvocationCount)>(); + } + + [Test] + public void TestTransformExecutorForCorrectExecutionOfConfiguredTransforms() + { + var queryList = new List + { + new CustomerResult{Id = 123, CustomerCode= "ABC", CustomerName="Ninja Labs"}, + new CommunicationResult{Id = 123, Email = "ninja@labs.com", Telephone = "0212345689"}, + new OrderCollectionResult(), + new OrderItemCollectionResult() + }; + + var entity = _transformExecutor.Execute(new CustomerContext { CustomerId = 1 }, queryList); + + var customerTransforms = TransformerInvocations.Where(x => x.result == typeof(CustomerResult)); + Assert.That(customerTransforms.Count() == 1); + Assert.That(customerTransforms.ElementAt(0).InvocationCount == 1); + + var communicationTransforms = TransformerInvocations.Where(x => x.result == typeof(CommunicationResult)); + Assert.That(communicationTransforms.Count() == 1); + Assert.That(communicationTransforms.ElementAt(0).InvocationCount == 1); + + var orderCollectionTransforms = TransformerInvocations.Where(x => x.result == typeof(OrderCollectionResult)); + Assert.That(orderCollectionTransforms.Count() == 1); + Assert.That(orderCollectionTransforms.ElementAt(0).InvocationCount == 1); + + var orderItemsCollectionTransforms = TransformerInvocations.Where(x => x.result == typeof(OrderItemCollectionResult)); + Assert.That(orderItemsCollectionTransforms.Count() == 1); + Assert.That(orderItemsCollectionTransforms.ElementAt(0).InvocationCount == 1); + + Assert.IsNotNull(entity); + } + + public class MockTransform : BaseTransformer + where TEntity : IEntity + where TQueryResult : IQueryResult + { + public override TEntity Transform(TQueryResult queryResult, TEntity entity) + { + TransformerInvocations.Add((queryResult.GetType(), 1)); + return entity; + } + } + + internal class MockCustomerSchema : IEntitySchema + { + private IEnumerable> mappings; + + private decimal version; + + public IEnumerable> Mappings => mappings; + public decimal Version => version; + + public MockCustomerSchema() + { + version = 1; + + // Create an object mapping graph of query and transformer pairs using xpaths. + mappings = CreateSchema.For() + .Map>(For.Paths("customer/id", "customer/customercode", "customer/customername"), + customer => customer.Dependents + .Map>(For.Paths("customer/communication")) + .Map>(For.Paths("customer/orders"), + customerOrders => customerOrders.Dependents + .Map>(For.Paths("customer/orders/order/items"))) + ).Complete(); + } + } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs b/tests/Schemio.Object.Tests/EntitySetup/CustomerContext.cs similarity index 73% rename from tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs rename to tests/Schemio.Object.Tests/EntitySetup/CustomerContext.cs index 9411b34..886927e 100644 --- a/tests/Schemio.Object.Tests/DataProvider/CustomerContext.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/CustomerContext.cs @@ -1,6 +1,4 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.DataProvider +namespace Schemio.Object.Tests.EntitySetup { internal class CustomerContext : IDataContext { diff --git a/tests/Schemio.Object.Tests/Entities/Address.cs b/tests/Schemio.Object.Tests/EntitySetup/Entities/Address.cs similarity index 81% rename from tests/Schemio.Object.Tests/Entities/Address.cs rename to tests/Schemio.Object.Tests/EntitySetup/Entities/Address.cs index ec724e4..362e645 100644 --- a/tests/Schemio.Object.Tests/Entities/Address.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Entities/Address.cs @@ -1,6 +1,4 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Entities +namespace Schemio.Object.Tests.EntitySetup.Entities { public class Address { diff --git a/tests/Schemio.Object.Tests/Entities/Communication.cs b/tests/Schemio.Object.Tests/EntitySetup/Entities/Communication.cs similarity index 76% rename from tests/Schemio.Object.Tests/Entities/Communication.cs rename to tests/Schemio.Object.Tests/EntitySetup/Entities/Communication.cs index ac3b404..466e1a8 100644 --- a/tests/Schemio.Object.Tests/Entities/Communication.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Entities/Communication.cs @@ -1,6 +1,4 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Entities +namespace Schemio.Object.Tests.EntitySetup.Entities { public class Communication { diff --git a/tests/Schemio.Object.Tests/Entities/Customer.cs b/tests/Schemio.Object.Tests/EntitySetup/Entities/Customer.cs similarity index 81% rename from tests/Schemio.Object.Tests/Entities/Customer.cs rename to tests/Schemio.Object.Tests/EntitySetup/Entities/Customer.cs index 3e88f20..1817594 100644 --- a/tests/Schemio.Object.Tests/Entities/Customer.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Entities/Customer.cs @@ -1,6 +1,4 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Entities +namespace Schemio.Object.Tests.EntitySetup.Entities { public class Customer : IEntity { diff --git a/tests/Schemio.Object.Tests/EntitySetup/Entities/EntityDiagram.cd b/tests/Schemio.Object.Tests/EntitySetup/Entities/EntityDiagram.cd new file mode 100644 index 0000000..3013839 --- /dev/null +++ b/tests/Schemio.Object.Tests/EntitySetup/Entities/EntityDiagram.cd @@ -0,0 +1,50 @@ + + + + + + AAEAACAAAAAAAAAAAAAAAAAAQAAAABAAAAAAAAIAAAA= + EntitySetup\Entities\Customer.cs + + + + + + + + + + + QAAAAAAAgAAAAAAIIAAAAAAAABIAAAAAAAAAAAAAAAA= + EntitySetup\Entities\Address.cs + + + + + + AAAAAAAAACAAAAAAAAAAAAAAAAAAAAECAAAAIAAAAAA= + EntitySetup\Entities\Communication.cs + + + + + + + + + EAAAAAAAAAAACAAAAAAAAAAAAAAAAAABAAAAAAAAAAI= + EntitySetup\Entities\Order.cs + + + + + + + + + AAAAAAAAAAAAAAAAgAAAABQAAAAAAAAAAAAAAAAAAAA= + EntitySetup\Entities\OrderItem.cs + + + + \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Entities/Order.cs b/tests/Schemio.Object.Tests/EntitySetup/Entities/Order.cs similarity index 75% rename from tests/Schemio.Object.Tests/Entities/Order.cs rename to tests/Schemio.Object.Tests/EntitySetup/Entities/Order.cs index f1be999..cdc90d2 100644 --- a/tests/Schemio.Object.Tests/Entities/Order.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Entities/Order.cs @@ -1,6 +1,4 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Entities +namespace Schemio.Object.Tests.EntitySetup.Entities { public class Order { diff --git a/tests/Schemio.Object.Tests/Entities/OrderItem.cs b/tests/Schemio.Object.Tests/EntitySetup/Entities/OrderItem.cs similarity index 70% rename from tests/Schemio.Object.Tests/Entities/OrderItem.cs rename to tests/Schemio.Object.Tests/EntitySetup/Entities/OrderItem.cs index cd52fc2..5fa1771 100644 --- a/tests/Schemio.Object.Tests/Entities/OrderItem.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Entities/OrderItem.cs @@ -1,6 +1,4 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Entities +namespace Schemio.Object.Tests.EntitySetup.Entities { public class OrderItem { diff --git a/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs b/tests/Schemio.Object.Tests/EntitySetup/EntitySchemas/CustomerSchema.cs similarity index 80% rename from tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs rename to tests/Schemio.Object.Tests/EntitySetup/EntitySchemas/CustomerSchema.cs index 909617a..b21e673 100644 --- a/tests/Schemio.Object.Tests/EntitySchemas/CustomerSchema.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/EntitySchemas/CustomerSchema.cs @@ -1,9 +1,8 @@ -using Schemio.Object.Core; -using Schemio.Object.Tests.Entities; -using Schemio.Object.Tests.Queries; -using Schemio.Object.Tests.Transforms; +using Schemio.Object.Tests.EntitySetup.Entities; +using Schemio.Object.Tests.EntitySetup.Queries; +using Schemio.Object.Tests.EntitySetup.Transforms; -namespace Schemio.Object.Tests.EntitySchemas +namespace Schemio.Object.Tests.EntitySetup.EntitySchemas { internal class CustomerSchema : IEntitySchema { @@ -25,7 +24,7 @@ public CustomerSchema() .Map(For.Paths("customer/communication")) .Map(For.Paths("customer/orders"), customerOrders => customerOrders.Dependents - .Map(For.Paths("customer/orders/order/Items"))) + .Map(For.Paths("customer/orders/order/items"))) ).Complete(); } } diff --git a/tests/Schemio.Object.Tests/EntitySetup/Queries/CommunicationResult.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/CommunicationResult.cs new file mode 100644 index 0000000..29d720b --- /dev/null +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/CommunicationResult.cs @@ -0,0 +1,14 @@ +namespace Schemio.Object.Tests.EntitySetup.Queries +{ + public class CommunicationResult : IQueryResult + { + public int Id { get; set; } + public string Telephone { get; set; } + public string Email { get; set; } + public string HouseNo { get; set; } + public string City { get; set; } + public string Region { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/CustomerCommunicationQuery.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerCommunicationQuery.cs similarity index 57% rename from tests/Schemio.Object.Tests/Queries/CustomerCommunicationQuery.cs rename to tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerCommunicationQuery.cs index 73ecaa7..3c19b86 100644 --- a/tests/Schemio.Object.Tests/Queries/CustomerCommunicationQuery.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerCommunicationQuery.cs @@ -1,6 +1,4 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Queries +namespace Schemio.Object.Tests.EntitySetup.Queries { internal class CustomerCommunicationQuery : BaseQuery { @@ -19,16 +17,4 @@ public override void ResolveParameterInChildMode(IDataContext context, IQueryRes }; } } - - public class CommunicationResult : IQueryResult - { - public int Id { get; set; } - public string Telephone { get; set; } - public string Email { get; set; } - public string HouseNo { get; set; } - public string City { get; set; } - public string Region { get; set; } - public string PostalCode { get; set; } - public string Country { get; set; } - } } \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/CustomerOrderItemsQuery.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrderItemsQuery.cs similarity index 59% rename from tests/Schemio.Object.Tests/Queries/CustomerOrderItemsQuery.cs rename to tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrderItemsQuery.cs index 1e46ce6..3d032aa 100644 --- a/tests/Schemio.Object.Tests/Queries/CustomerOrderItemsQuery.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrderItemsQuery.cs @@ -1,6 +1,4 @@ -using Schemio.Object.Core; - -namespace Schemio.Object.Tests.Queries +namespace Schemio.Object.Tests.EntitySetup.Queries { internal class CustomerOrderItemsQuery : BaseQuery { @@ -19,20 +17,4 @@ public override void ResolveParameterInChildMode(IDataContext context, IQueryRes }; } } - - public class OrderItemCollectionResult : IQueryResult - { - public List OrderItems { get; set; } - } - - public class OrderItemValue - { - public int OrderId { get; set; } - public (int ItemId, string Name, decimal Cost)[] Items { get; set; } - } - - internal class OrderItemParameter : IQueryParameter - { - public List OrderIds { get; set; } - } } \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/CustomerOrdersQuery.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrdersQuery.cs similarity index 58% rename from tests/Schemio.Object.Tests/Queries/CustomerOrdersQuery.cs rename to tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrdersQuery.cs index aeaf1d4..78e02b6 100644 --- a/tests/Schemio.Object.Tests/Queries/CustomerOrdersQuery.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrdersQuery.cs @@ -1,7 +1,4 @@ -using Schemio.Object.Core; -using Schemio.Object.Tests.DataProvider; - -namespace Schemio.Object.Tests.Queries +namespace Schemio.Object.Tests.EntitySetup.Queries { internal class CustomerOrdersQuery : BaseQuery { @@ -20,17 +17,4 @@ public override void ResolveParameterInChildMode(IDataContext context, IQueryRes // Does not execute as child to any query. } } - - public class OrderCollectionResult : IQueryResult - { - public int CustomerId { get; set; } - public OrderValue[] Orders { get; set; } - } - - public class OrderValue - { - public int OrderId { get; set; } - public string OrderNo { get; set; } - public DateTime Date { get; set; } - } } \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerParameter.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerParameter.cs new file mode 100644 index 0000000..7e2a7a0 --- /dev/null +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerParameter.cs @@ -0,0 +1,7 @@ +namespace Schemio.Object.Tests.EntitySetup.Queries +{ + public class CustomerParameter : IQueryParameter + { + public int CustomerId { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerQuery.cs similarity index 59% rename from tests/Schemio.Object.Tests/Queries/CustomerQuery.cs rename to tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerQuery.cs index 55400a7..77debdd 100644 --- a/tests/Schemio.Object.Tests/Queries/CustomerQuery.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerQuery.cs @@ -1,7 +1,4 @@ -using Schemio.Object.Core; -using Schemio.Object.Tests.DataProvider; - -namespace Schemio.Object.Tests.Queries +namespace Schemio.Object.Tests.EntitySetup.Queries { public class CustomerQuery : BaseQuery { @@ -20,16 +17,4 @@ public override void ResolveParameterInChildMode(IDataContext context, IQueryRes // Does not execute as child to any query. } } - - public class CustomerResult : IQueryResult - { - public int Id { get; set; } - public string CustomerCode { get; set; } - public string CustomerName { get; set; } - } - - public class CustomerParameter : IQueryParameter - { - public int CustomerId { get; set; } - } } \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerResult.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerResult.cs new file mode 100644 index 0000000..c67dd65 --- /dev/null +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerResult.cs @@ -0,0 +1,9 @@ +namespace Schemio.Object.Tests.EntitySetup.Queries +{ + public class CustomerResult : IQueryResult + { + public int Id { get; set; } + public string CustomerCode { get; set; } + public string CustomerName { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/EntitySetup/Queries/OrderCollectionResult.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/OrderCollectionResult.cs new file mode 100644 index 0000000..7ceb0d6 --- /dev/null +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/OrderCollectionResult.cs @@ -0,0 +1,15 @@ +namespace Schemio.Object.Tests.EntitySetup.Queries +{ + public class OrderCollectionResult : IQueryResult + { + public int CustomerId { get; set; } + public OrderValue[] Orders { get; set; } + } + + public class OrderValue + { + public int OrderId { get; set; } + public string OrderNo { get; set; } + public DateTime Date { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/EntitySetup/Queries/OrderItemCollectionResult.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/OrderItemCollectionResult.cs new file mode 100644 index 0000000..0f4bcc2 --- /dev/null +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/OrderItemCollectionResult.cs @@ -0,0 +1,13 @@ +namespace Schemio.Object.Tests.EntitySetup.Queries +{ + public class OrderItemCollectionResult : IQueryResult + { + public List OrderItems { get; set; } + } + + public class OrderItemValue + { + public int OrderId { get; set; } + public (int ItemId, string Name, decimal Cost)[] Items { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/EntitySetup/Queries/OrderItemParameter.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/OrderItemParameter.cs new file mode 100644 index 0000000..eed9b6e --- /dev/null +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/OrderItemParameter.cs @@ -0,0 +1,7 @@ +namespace Schemio.Object.Tests.EntitySetup.Queries +{ + internal class OrderItemParameter : IQueryParameter + { + public List OrderIds { get; set; } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/Transforms/CustomerCommunicationTransform.cs b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerCommunicationTransform.cs similarity index 85% rename from tests/Schemio.Object.Tests/Transforms/CustomerCommunicationTransform.cs rename to tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerCommunicationTransform.cs index 108c75e..df7b6ca 100644 --- a/tests/Schemio.Object.Tests/Transforms/CustomerCommunicationTransform.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerCommunicationTransform.cs @@ -1,7 +1,7 @@ -using Schemio.Object.Tests.Entities; -using Schemio.Object.Tests.Queries; +using Schemio.Object.Tests.EntitySetup.Entities; +using Schemio.Object.Tests.EntitySetup.Queries; -namespace Schemio.Object.Tests.Transforms +namespace Schemio.Object.Tests.EntitySetup.Transforms { public class CustomerCommunicationTransform : BaseTransformer { diff --git a/tests/Schemio.Object.Tests/Transforms/CustomerOrderItemsTransform.cs b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrderItemsTransform.cs similarity index 81% rename from tests/Schemio.Object.Tests/Transforms/CustomerOrderItemsTransform.cs rename to tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrderItemsTransform.cs index bc45a66..d5c780e 100644 --- a/tests/Schemio.Object.Tests/Transforms/CustomerOrderItemsTransform.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrderItemsTransform.cs @@ -1,7 +1,7 @@ -using Schemio.Object.Tests.Entities; -using Schemio.Object.Tests.Queries; +using Schemio.Object.Tests.EntitySetup.Entities; +using Schemio.Object.Tests.EntitySetup.Queries; -namespace Schemio.Object.Tests.Transforms +namespace Schemio.Object.Tests.EntitySetup.Transforms { public class CustomerOrderItemsTransform : BaseTransformer { @@ -12,17 +12,13 @@ public override Customer Transform(OrderItemCollectionResult queryResult, Custom foreach (var item in queryResult.OrderItems.Where(x => x.Items != null)) foreach (var order in entity.Orders) - { if (order.OrderId == item.OrderId) - { order.Items = item.Items.Select(x => new OrderItem { ItemId = x.ItemId, Name = x.Name, Cost = x.Cost }).ToArray(); - } - } return entity; } diff --git a/tests/Schemio.Object.Tests/Transforms/CustomerOrdersTransform.cs b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrdersTransform.cs similarity index 79% rename from tests/Schemio.Object.Tests/Transforms/CustomerOrdersTransform.cs rename to tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrdersTransform.cs index 2455ce6..4d69301 100644 --- a/tests/Schemio.Object.Tests/Transforms/CustomerOrdersTransform.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrdersTransform.cs @@ -1,7 +1,7 @@ -using Schemio.Object.Tests.Entities; -using Schemio.Object.Tests.Queries; +using Schemio.Object.Tests.EntitySetup.Entities; +using Schemio.Object.Tests.EntitySetup.Queries; -namespace Schemio.Object.Tests.Transforms +namespace Schemio.Object.Tests.EntitySetup.Transforms { public class CustomerOrdersTransform : BaseTransformer { diff --git a/tests/Schemio.Object.Tests/Transforms/CustomerTransform.cs b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerTransform.cs similarity index 75% rename from tests/Schemio.Object.Tests/Transforms/CustomerTransform.cs rename to tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerTransform.cs index 514f396..cdc00a7 100644 --- a/tests/Schemio.Object.Tests/Transforms/CustomerTransform.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerTransform.cs @@ -1,8 +1,7 @@ -using Schemio.Object.Core; -using Schemio.Object.Tests.Entities; -using Schemio.Object.Tests.Queries; +using Schemio.Object.Tests.EntitySetup.Entities; +using Schemio.Object.Tests.EntitySetup.Queries; -namespace Schemio.Object.Tests.Transforms +namespace Schemio.Object.Tests.EntitySetup.Transforms { public class CustomerTransform : BaseTransformer { diff --git a/tests/Schemio.Object.Tests/Schemio.Object.Tests.csproj b/tests/Schemio.Object.Tests/Schemio.Object.Tests.csproj index c9fabde..3aa0550 100644 --- a/tests/Schemio.Object.Tests/Schemio.Object.Tests.csproj +++ b/tests/Schemio.Object.Tests/Schemio.Object.Tests.csproj @@ -10,6 +10,7 @@ + diff --git a/tests/Schemio.Object.Tests/UnitTest1.cs b/tests/Schemio.Object.Tests/UnitTest1.cs index c8f2236..8661426 100644 --- a/tests/Schemio.Object.Tests/UnitTest1.cs +++ b/tests/Schemio.Object.Tests/UnitTest1.cs @@ -1,4 +1,4 @@ -namespace Data2Xml.Tests +namespace Schemio.Object.Tests { public class Tests { From 34d036bded0109be1c3e6052e6e8732c82079bc6 Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 01:38:35 +0000 Subject: [PATCH 08/24] - refactor --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2bcbe3c..a9bc951 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,10 @@ Schemio - is a .Net 6 utility to hydrate entities with data conditionally by given list of schema paths mapping to object graph. Support JsonPath and Xpath schema mappings. ## How to use Schemio? -> Step 1 - To mark the entity to hydrate data using schemio, derive the entity from `IEntity` interface. Bear in mind this is the root entity. +> Step 1 - To mark the class as entity to hydrate data using schemio, derive the class from `IEntity` interface. Bear in mind this is the root entity. + +Below is the Customer entity we want to conditionally hydrate with data, by passing in schema paths mapping to object graph of customer class. + ``` public class Customer : IEntity { @@ -16,9 +19,9 @@ Schemio - is a .Net 6 utility to hydrate entities with data conditionally by giv public Order[] Orders { get; set; } } ``` -Above, Customer is the entity we want to hydrate with data conditionaly passing in schema paths mapping to object graph. -> Step 2 - Define schema configuration to map query/transformer pairs to schema paths mapping to the object graph. +> Step 2 - Define entity schema configuration to map query/transformer pairs to schema paths mapping to the object graph of the entity in context. + Derive schema from `IEntitySchema` where T is entity to hydrate. The query/transformer mappings can be nested to 5 levels down. You could map multiple schema paths to a given query/transformer pair. From 2947eaa9d76777c7e37aa3d02fb5fdbf2836f7a4 Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 01:42:32 +0000 Subject: [PATCH 09/24] - ref1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a9bc951..6a17639 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![NuGet version](https://badge.fury.io/nu/Schemio.Object.svg)](https://badge.fury.io/nu/Schemio.Object) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/NinjaRocks/Schemio.Object/blob/master/License.md) [![CI](https://github.com/NinjaRocks/Data2Xml/actions/workflows/CI.yml/badge.svg)](https://github.com/NinjaRocks/Data2Xml/actions/workflows/CI.yml) [![GitHub Release](https://img.shields.io/github/v/release/ninjarocks/Data2Xml?logo=github&sort=semver)](https://github.com/ninjarocks/Data2Xml/releases/latest) [![CodeQL](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml/badge.svg)](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml) [![.Net Stardard](https://img.shields.io/badge/.Net%20Standard-2.1-blue)](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) -- -Schemio - is a .Net 6 utility to hydrate entities with data conditionally by given list of schema paths mapping to object graph. Support JsonPath and Xpath schema mappings. +Schemio - is a .Net 6 utility to conditionally hydrate entities with data by given list of schema paths mapping to object graph of that entity. Supports JsonPath and XPath schema mappings. ## How to use Schemio? > Step 1 - To mark the class as entity to hydrate data using schemio, derive the class from `IEntity` interface. Bear in mind this is the root entity. From 40e9092272d5275088c64f06e783e0a32a2036e7 Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 19:29:57 +0000 Subject: [PATCH 10/24] - readme --- README.md | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 6a17639..e856733 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,29 @@ [![NuGet version](https://badge.fury.io/nu/Schemio.Object.svg)](https://badge.fury.io/nu/Schemio.Object) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/NinjaRocks/Schemio.Object/blob/master/License.md) [![CI](https://github.com/NinjaRocks/Data2Xml/actions/workflows/CI.yml/badge.svg)](https://github.com/NinjaRocks/Data2Xml/actions/workflows/CI.yml) [![GitHub Release](https://img.shields.io/github/v/release/ninjarocks/Data2Xml?logo=github&sort=semver)](https://github.com/ninjarocks/Data2Xml/releases/latest) [![CodeQL](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml/badge.svg)](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml) [![.Net Stardard](https://img.shields.io/badge/.Net%20Standard-2.1-blue)](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) -- -Schemio - is a .Net 6 utility to conditionally hydrate entities with data by given list of schema paths mapping to object graph of that entity. Supports JsonPath and XPath schema mappings. +## What is Schemio? +`Schemio` is a .Net utility to data hydrate an entity by schema paths mapping to object graph of that entity. +> Supports JsonPath and XPath schemas. + +## When to use Schemio? +Schemio is a perfect utility when you need to fetch a large entity from data source. Ideally, you may not require all of the entity data but only sections of the object graph depending on the usage. +> Example use case is document generation which may require only templated sections of client data to be fetched according to document template in context. ## How to use Schemio? -> Step 1 - To mark the class as entity to hydrate data using schemio, derive the class from `IEntity` interface. Bear in mind this is the root entity. +you could use Schemio out of the box or extend the utility to suit your custom needs. +> To use schemio you need to +> - Setup the entity to be fetched. +> - Construct the DataProvider with required dependencies. + +### Entity Setup +* Define the `entity` to be fetched using `DataProvider` - which is basically a class with nested typed properties. +* Define the `entity schema` with `query` and `transformer` pairs mappings to entity object graph. The relevant query and transformer pairs will execute accordingly when their mapped `schema paths` are included in the `request` parameter of the DataProvider. +* `Query` is an implementation to fetch `data` for the entity object graph from the underlying data storage supported by the chosen `QueryEngine`. QueryEngine is an implementation of `IQueryEngine` to execute queries against implemented data source. +* `Transformer` is an implementation to transform the data fetched by the associated query to mapped section of the object graph. +#### Entity +> Step 1 - To mark the class as Entity to be fetched using schemio, implement the class from `IEntity` interface. Bear in mind this is the root entity. -Below is the Customer entity we want to conditionally hydrate with data, by passing in schema paths mapping to object graph of customer class. +Below is an example Customer entity we want to fetch using schemio. ``` public class Customer : IEntity @@ -19,27 +36,23 @@ Below is the Customer entity we want to conditionally hydrate with data, by pass public Order[] Orders { get; set; } } ``` +#### Entity Schema +> Step 2 - Define entity schema configuration which is basically a hierarchy of query/transformer pairs mapping to the object graph of the entity in context. -> Step 2 - Define entity schema configuration to map query/transformer pairs to schema paths mapping to the object graph of the entity in context. - -Derive schema from `IEntitySchema` where T is entity to hydrate. The query/transformer mappings can be nested to 5 levels down. You could map multiple schema paths to a given query/transformer pair. +To define Entity schema, implement `IEntitySchema` interface where T is entity in context. The `query/transformer` mappings can be `nested` to `5 levels` down. You could map multiple schema paths to a given query/transformer pair. ``` internal class CustomerSchema : IEntitySchema { private IEnumerable> mappings; - - private decimal version; - + public IEnumerable> Mappings => mappings; - public decimal Version => version; - + public CustomerSchema() { - version = 1; + // Create an object mapping graph of query and transformer pairs using xpaths. - // Create an object mapping graph of query and transformer pairs using xpaths. mappings = CreateSchema.For() .Map(For.Paths("customer/id", "customer/customercode", "customer/customername"), customer => customer.Dependents @@ -113,5 +126,5 @@ var ``` -## Extending Schemio +### DataProvider Setup > coming soon From 65435fecc0bd7d7b5e87f04554572a453cab625e Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 20:01:47 +0000 Subject: [PATCH 11/24] - readme --- README.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e856733..e9a2a58 100644 --- a/README.md +++ b/README.md @@ -3,28 +3,28 @@ [![CodeQL](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml/badge.svg)](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml) [![.Net Stardard](https://img.shields.io/badge/.Net%20Standard-2.1-blue)](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) -- ## What is Schemio? -`Schemio` is a .Net utility to data hydrate an entity by schema paths mapping to object graph of that entity. -> Supports JsonPath and XPath schemas. +`Schemio` is a .Net utility to data hydrate an entity by given schema paths of the object graph. +> Supports XPath & JsonPath schema paths. ## When to use Schemio? -Schemio is a perfect utility when you need to fetch a large entity from data source. Ideally, you may not require all of the entity data but only sections of the object graph depending on the usage. -> Example use case is document generation which may require only templated sections of client data to be fetched according to document template in context. +Schemio is a perfect utility when you need to fetch a large entity from data source. Ideally, you may not require all of the entity data but only sections of the object graph by varied fetches. +> Example use case is document generation which may require only templated sections of client data to be fetched for a document template in context. ## How to use Schemio? you could use Schemio out of the box or extend the utility to suit your custom needs. > To use schemio you need to -> - Setup the entity to be fetched. +> - Setup the entity to be fetched using DataProvider. > - Construct the DataProvider with required dependencies. ### Entity Setup * Define the `entity` to be fetched using `DataProvider` - which is basically a class with nested typed properties. -* Define the `entity schema` with `query` and `transformer` pairs mappings to entity object graph. The relevant query and transformer pairs will execute accordingly when their mapped `schema paths` are included in the `request` parameter of the DataProvider. +* Define the `entity schema` with `query` and `transformer` pairs mappings to entity's object graph. The relevant query and transformer pairs will execute in the order of their nesting when their mapped `schema paths` are included in the `request` parameter of the DataProvider. * `Query` is an implementation to fetch `data` for the entity object graph from the underlying data storage supported by the chosen `QueryEngine`. QueryEngine is an implementation of `IQueryEngine` to execute queries against implemented data source. * `Transformer` is an implementation to transform the data fetched by the associated query to mapped section of the object graph. #### Entity -> Step 1 - To mark the class as Entity to be fetched using schemio, implement the class from `IEntity` interface. Bear in mind this is the root entity. +> Step 1 - To mark the class as Entity using schemio, implement the class from `IEntity` interface. Bear in mind this is the root entity to be fetched. -Below is an example Customer entity we want to fetch using schemio. +Below is an example `Customer` entity we want to fetch using schemio. ``` public class Customer : IEntity @@ -36,11 +36,17 @@ Below is an example Customer entity we want to fetch using schemio. public Order[] Orders { get; set; } } ``` +There are three levels of nesting in the object graph for customer class above. +- Level 1 with paths: `Customer/CustomerId`, `Customer/CustomerCode`, `Customer/CustomerName` +- Level 2 with paths: `Customer/Communication` and `Customer/Orders` +- Level 3 with paths: `Customer/Orders/Order/Items` + #### Entity Schema > Step 2 - Define entity schema configuration which is basically a hierarchy of query/transformer pairs mapping to the object graph of the entity in context. To define Entity schema, implement `IEntitySchema` interface where T is entity in context. The `query/transformer` mappings can be `nested` to `5 levels` down. You could map multiple schema paths to a given query/transformer pair. +The above object graph with three levels is configured below with query and transformer pairs nested accordingly, mapping to object graph of customer as defined by the XPath schema. ``` internal class CustomerSchema : IEntitySchema From 0371803dfdb38f237b1f76f78dec2928a5bd4a36 Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 20:40:19 +0000 Subject: [PATCH 12/24] - readme --- README.md | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e9a2a58..f0a799a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Schemio is a perfect utility when you need to fetch a large entity from data sou > Example use case is document generation which may require only templated sections of client data to be fetched for a document template in context. ## How to use Schemio? -you could use Schemio out of the box or extend the utility to suit your custom needs. +You could use Schemio out of the box or extend the utility in order to suit your custom needs. > To use schemio you need to > - Setup the entity to be fetched using DataProvider. > - Construct the DataProvider with required dependencies. @@ -72,19 +72,28 @@ internal class CustomerSchema : IEntitySchema ``` #### Query Class -The purpose of a query class is to execute to fetch data when mapped schema path is included in the context paramer of data provider. -- To define a query for a schema path, you need to implement the query by deriving from `BaseQuery : IQuery where TQueryParameter : IQueryParameter where TQueryResult : IQueryResult` -- You may want to run the query in parent or child mode and define the relevant overrides to resovle the query parameter accordingly. -- In `parent` mode the query parameter is resolved using `context` parameter passed to data provider class. -- In `child` mode, the query parameter is resolved using the `query result` of the `parent query` to which the current query is a child. You could have a maximum of `5` levels of children query nesting when defining the Entity schema. +The purpose of a query class is to execute to fetch data from data source when mapped schema path(s) are included in the request parameter of data provider. +- To define a query you need to implement from `BaseQuery` where `TQueryParameter` is the query parameter and `TQueryResult` is the query result. +- `TQueryParameter` is basically the class that holds the `inputs` required by the query for execution. +- `TQueryResult` is the result that will be obtained from executing the query. +- You can run the query in `Parent` or `Child` (nested) mode. The parent/child relationship is achieved by configuring the query accordingly in entity schema definition. See `CustomerSchema` above. +- The query parameter needs to be resolved before executing the query with QueryEngine. + - In `parent` mode, the query parameter is resolved using the `request/context` parameter passed to data provider class. + - In `child` mode, the query parameter is resolved using the `query result` of the `parent query` as stiched in the entity schema configuration. You could have a maximum of `5` levels of children query nestings. -> See example Customer query as parent below. +> Please Note: The above query implementation is basic and could vary with different implementations of the QueryEngine. +Please see Query engine provider specific implementation of queries below. + + +See example Customer query as parent below. ``` public class CustomerQuery : BaseQuery { public override void ResolveParameterInParentMode(IDataContext context) { - // Executes as root or level 1 query. + // Executes as Parent or Level 1 query. + // The query parameter is resolved using context parameter of data provider class. + var customer = (CustomerContext)context; QueryParameter = new CustomerParameter { @@ -98,18 +107,20 @@ public class CustomerQuery : BaseQuery } } ``` -> see communication query as child to customer query below. +See example communication query implemented to be used as child or nested query to customer query below. ``` internal class CustomerCommunicationQuery : BaseQuery { public override void ResolveParameterInParentMode(IDataContext context) { - // Does not execute as root or level 1 queries. + // Does not execute as Parent or Level 1 query. Hence has no implementation. } public override void ResolveParameterInChildMode(IDataContext context, IQueryResult parentQueryResult) { // Execute as child to customer query. + // The result from parent customer query is used to resolve the query parameter of the nested communication query. + var customer = (CustomerResult)parentQueryResult; QueryParameter = new CustomerParameter { @@ -118,7 +129,7 @@ public class CustomerQuery : BaseQuery } } ``` -The parent/child relationship is achieved via entity schema configuration. see CustomerSchema above. + #### Tranformer Class The purpose of the transformer is to map the data fetched by the linked query class to relevant schema section of the entity to be data hydrated. - To define a transformer class for the schema path, you need to derive from `BaseTransformer : ITransformer From 59110398ad3320ae47f1bd799d32c5b469730119 Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 21:54:35 +0000 Subject: [PATCH 13/24] - read me --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index f0a799a..1734b58 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ You could use Schemio out of the box or extend the utility in order to suit your ### Entity Setup * Define the `entity` to be fetched using `DataProvider` - which is basically a class with nested typed properties. * Define the `entity schema` with `query` and `transformer` pairs mappings to entity's object graph. The relevant query and transformer pairs will execute in the order of their nesting when their mapped `schema paths` are included in the `request` parameter of the DataProvider. -* `Query` is an implementation to fetch `data` for the entity object graph from the underlying data storage supported by the chosen `QueryEngine`. QueryEngine is an implementation of `IQueryEngine` to execute queries against implemented data source. +* `Query` is an implementation to fetch `data` for the entity object graph from the underlying data storage supported by the chosen `QueryEngine`. QueryEngine is an implementation of `IQueryEngine` to execute queries against supported data source. * `Transformer` is an implementation to transform the data fetched by the associated query to mapped section of the object graph. #### Entity > Step 1 - To mark the class as Entity using schemio, implement the class from `IEntity` interface. Bear in mind this is the root entity to be fetched. @@ -44,9 +44,20 @@ There are three levels of nesting in the object graph for customer class above. #### Entity Schema > Step 2 - Define entity schema configuration which is basically a hierarchy of query/transformer pairs mapping to the object graph of the entity in context. -To define Entity schema, implement `IEntitySchema` interface where T is entity in context. The `query/transformer` mappings can be `nested` to `5 levels` down. You could map multiple schema paths to a given query/transformer pair. +To define Entity schema, implement `IEntitySchema` interface where T is entity in context. The `query/transformer` mappings can be `nested` to `5` levels down. -The above object graph with three levels is configured below with query and transformer pairs nested accordingly, mapping to object graph of customer as defined by the XPath schema. +You could map multiple schema paths to a given query/transformer pair. Currently, XPath and JSONPath schema paths are supported. + +If you need to support custom schema language for mapping to object graph, then use the custom paths in entity schema definition however you may need to provide custom implementation of `ISchemaPathMatcher` interface. +``` +public interface ISchemaPathMatcher + { + bool IsMatch(string inputPath, ISchemaPaths configuredPaths); + } +``` + +Example Entity Schema Definition +> The `Customer` object graph with `three` levels of `nesting` is configured in `CustomerSchema` class below to show `query/transformer` pairs nested accordingly to map to object graph using the XPath definitions. ``` internal class CustomerSchema : IEntitySchema @@ -85,7 +96,7 @@ The purpose of a query class is to execute to fetch data from data source when m Please see Query engine provider specific implementation of queries below. -See example Customer query as parent below. +See example `CustomerQuery` implemented to run in parent mode below. ``` public class CustomerQuery : BaseQuery { @@ -103,17 +114,17 @@ public class CustomerQuery : BaseQuery public override void ResolveParameterInChildMode(IDataContext context, IQueryResult parentQueryResult) { - // Does not execute as child to any query. + // Does not execute as child to any query. Hence has no implementation provided. } } ``` -See example communication query implemented to be used as child or nested query to customer query below. +See example `CustomerCommunicationQuery` implemented to run as child or nested query to customer query below. Please see `CustomerSchema` definition above for parent/child configuration setup. ``` internal class CustomerCommunicationQuery : BaseQuery { public override void ResolveParameterInParentMode(IDataContext context) { - // Does not execute as Parent or Level 1 query. Hence has no implementation. + // Does not execute as Parent or Level 1 query. Hence has no implementation provided. } public override void ResolveParameterInChildMode(IDataContext context, IQueryResult parentQueryResult) @@ -131,16 +142,36 @@ See example communication query implemented to be used as child or nested query ``` #### Tranformer Class -The purpose of the transformer is to map the data fetched by the linked query class to relevant schema section of the entity to be data hydrated. -- To define a transformer class for the schema path, you need to derive from `BaseTransformer : ITransformer - where T : IEntity - where TD : IQueryResult` -- The output of the linked query serves as input to the transformer to map data to configured section of the entity in context. +The purpose of the transformer class is to map the data fetched by the linked query class to mapped object graph of the entity. -> Step 3 - Use the DataProvider class to get the entity with hydrated data based on configuration and passed in context paratemer with relevant schema paths. -``` -var +To define a transformer class, you need to implement `BaseTransformer` +- where T is Entity implementing `IEntity`. eg. Customer. +- where TD is Query Result from associated Query implementing `IQueryResult` in EntitySchema definition. This is the query result obtained from the query, the transformer will consume to map to the relevant object graph of the Entity. + +> Please Note: Every `Query` type in the `EntitySchema` definition should have a complementing `Transformer` type. + +Below is the snippet from `CustomerSchema` definition. +> .Map(For.Paths("customer/id", "customer/customercode", "customer/customername")) +The transformer should `map` `data` to only the `schema` mapped `sections` of the `object graph`. + + +In below example, `CustomerTransformer` (transformer) is implemented to transform `Customer` (entity) with `CustomerResult` (query result) obtained from `CustomerQuery` (query) execution. + +The transformer maps data to only `XPath` mapped sections of Customer object grapgh - `customer/id`, `customer/customercode`, `customer/customername` + +``` +public class CustomerTransform : BaseTransformer + { + public override Customer Transform(CustomerResult queryResult, Customer entity) + { + var customer = entity ?? new Customer(); + customer.CustomerId = queryResult.Id; + customer.CustomerName = queryResult.CustomerName; + customer.CustomerCode = queryResult.CustomerCode; + return customer; + } + } ``` ### DataProvider Setup From 6418090fc6ebd07cd69748f6ad6f834a8932fa95 Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 22:00:26 +0000 Subject: [PATCH 14/24] - readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1734b58..6e04991 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ See example `CustomerCommunicationQuery` implemented to run as child or nested q ``` #### Tranformer Class -The purpose of the transformer class is to map the data fetched by the linked query class to mapped object graph of the entity. +The purpose of the transformer class is to transform the data fetched by the linked query class to mapped object graph of the entity. To define a transformer class, you need to implement `BaseTransformer` - where T is Entity implementing `IEntity`. eg. Customer. From 4556a7598f67ace775844231f52cb57b9d793b7c Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 22:04:32 +0000 Subject: [PATCH 15/24] - read me --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6e04991..fa64c17 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ public interface ISchemaPathMatcher ``` Example Entity Schema Definition -> The `Customer` object graph with `three` levels of `nesting` is configured in `CustomerSchema` class below to show `query/transformer` pairs nested accordingly to map to object graph using the XPath definitions. +> The `Customer` entity with `three` levels of `nesting` is configured below in `CustomerSchema` definition to show `query/transformer` pairs nested accordingly mapping to object graph using the XPath definitions. ``` internal class CustomerSchema : IEntitySchema From 15dcb9cdb01a5cea390359be9f9b17302d37c496 Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 22:27:38 +0000 Subject: [PATCH 16/24] - Readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fa64c17..5f41af2 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,12 @@ [![CodeQL](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml/badge.svg)](https://github.com/NinjaRocks/Schemio.Object/actions/workflows/CodeQL.yml) [![.Net Stardard](https://img.shields.io/badge/.Net%20Standard-2.1-blue)](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) -- ## What is Schemio? -`Schemio` is a .Net utility to data hydrate an entity by given schema paths of the object graph. -> Supports XPath & JsonPath schema paths. +`Schemio` is a .Net utility that can be used to fetch entities by specifying sections of object graph for hydrating data. +> Supports XPath & JsonPath for object schema paths. ## When to use Schemio? -Schemio is a perfect utility when you need to fetch a large entity from data source. Ideally, you may not require all of the entity data but only sections of the object graph by varied fetches. -> Example use case is document generation which may require only templated sections of client data to be fetched for a document template in context. +Schemio is a perfect utility when you need to fetch a large entity from data source. Ideally, you may not require all of the entity data but only sections of the object graph for different fetches. +> Example use case is document generation which may require only templated sections of client data to be fetched for different document templates in context. ## How to use Schemio? You could use Schemio out of the box or extend the utility in order to suit your custom needs. From 94a13b354b1d3f0a4ba0fd27289994d15338a059 Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 22:33:48 +0000 Subject: [PATCH 17/24] - Read me --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5f41af2..7ac5e62 100644 --- a/README.md +++ b/README.md @@ -92,10 +92,6 @@ The purpose of a query class is to execute to fetch data from data source when m - In `parent` mode, the query parameter is resolved using the `request/context` parameter passed to data provider class. - In `child` mode, the query parameter is resolved using the `query result` of the `parent query` as stiched in the entity schema configuration. You could have a maximum of `5` levels of children query nestings. -> Please Note: The above query implementation is basic and could vary with different implementations of the QueryEngine. -Please see Query engine provider specific implementation of queries below. - - See example `CustomerQuery` implemented to run in parent mode below. ``` public class CustomerQuery : BaseQuery @@ -140,6 +136,9 @@ See example `CustomerCommunicationQuery` implemented to run as child or nested q } } ``` +Please Note: The above query implementation is basic and could vary with different implementations of the QueryEngine. +> Please see Query engine provider specific implementation of queries below. + #### Tranformer Class The purpose of the transformer class is to transform the data fetched by the linked query class to mapped object graph of the entity. From 99c64b7f7c6baf48c179035cc57bd945f4172292 Mon Sep 17 00:00:00 2001 From: Ninja Date: Thu, 2 Nov 2023 22:39:21 +0000 Subject: [PATCH 18/24] - readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7ac5e62..ff54de3 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ You could use Schemio out of the box or extend the utility in order to suit your * Define the `entity schema` with `query` and `transformer` pairs mappings to entity's object graph. The relevant query and transformer pairs will execute in the order of their nesting when their mapped `schema paths` are included in the `request` parameter of the DataProvider. * `Query` is an implementation to fetch `data` for the entity object graph from the underlying data storage supported by the chosen `QueryEngine`. QueryEngine is an implementation of `IQueryEngine` to execute queries against supported data source. * `Transformer` is an implementation to transform the data fetched by the associated query to mapped section of the object graph. -#### Entity +#### 1. Entity > Step 1 - To mark the class as Entity using schemio, implement the class from `IEntity` interface. Bear in mind this is the root entity to be fetched. Below is an example `Customer` entity we want to fetch using schemio. @@ -41,7 +41,7 @@ There are three levels of nesting in the object graph for customer class above. - Level 2 with paths: `Customer/Communication` and `Customer/Orders` - Level 3 with paths: `Customer/Orders/Order/Items` -#### Entity Schema +#### 2. Entity Schema > Step 2 - Define entity schema configuration which is basically a hierarchy of query/transformer pairs mapping to the object graph of the entity in context. To define Entity schema, implement `IEntitySchema` interface where T is entity in context. The `query/transformer` mappings can be `nested` to `5` levels down. @@ -82,7 +82,7 @@ internal class CustomerSchema : IEntitySchema } ``` -#### Query Class +#### 2.1 Query Class The purpose of a query class is to execute to fetch data from data source when mapped schema path(s) are included in the request parameter of data provider. - To define a query you need to implement from `BaseQuery` where `TQueryParameter` is the query parameter and `TQueryResult` is the query result. - `TQueryParameter` is basically the class that holds the `inputs` required by the query for execution. @@ -140,7 +140,7 @@ Please Note: The above query implementation is basic and could vary with differe > Please see Query engine provider specific implementation of queries below. -#### Tranformer Class +#### 2.2 Tranformer Class The purpose of the transformer class is to transform the data fetched by the linked query class to mapped object graph of the entity. To define a transformer class, you need to implement `BaseTransformer` From 8928050b44a7579751c5479602fa148d790c763e Mon Sep 17 00:00:00 2001 From: Ninja Date: Fri, 3 Nov 2023 23:24:46 +0000 Subject: [PATCH 19/24] - Add SQLQueryEngine --- src/Schemio.Object.SQL/BaseSQLQuery.cs | 9 +++ src/Schemio.Object.SQL/ISQLQuery.cs | 4 +- src/Schemio.Object.SQL/SQLBatchQueryEngine.cs | 65 +++++++++++++++++++ src/Schemio.Object.SQL/SQLEngine.cs | 7 -- src/Schemio.Object.SQL/SQLQuery.cs | 13 ---- src/Schemio.Object.SQL/SQLQueryEngine.cs | 35 ++++++---- src/Schemio.Object/BaseQuery.cs | 2 +- src/Schemio.Object/CollectionResult.cs | 15 +++++ src/Schemio.Object/IQuery.cs | 2 +- src/Schemio.Object/QueryList.cs | 2 +- .../DataProvider.Tests/QueryExecutorTests.cs | 33 ++++++++++ .../Queries/CustomerOrderItemsQuery.cs | 2 +- .../Queries/CustomerOrdersQuery.cs | 2 +- .../Transforms/CustomerOrderItemsTransform.cs | 8 +-- .../Transforms/CustomerOrdersTransform.cs | 8 +-- 15 files changed, 158 insertions(+), 49 deletions(-) create mode 100644 src/Schemio.Object.SQL/BaseSQLQuery.cs create mode 100644 src/Schemio.Object.SQL/SQLBatchQueryEngine.cs delete mode 100644 src/Schemio.Object.SQL/SQLEngine.cs delete mode 100644 src/Schemio.Object.SQL/SQLQuery.cs create mode 100644 src/Schemio.Object/CollectionResult.cs create mode 100644 tests/Schemio.Object.Tests/DataProvider.Tests/QueryExecutorTests.cs diff --git a/src/Schemio.Object.SQL/BaseSQLQuery.cs b/src/Schemio.Object.SQL/BaseSQLQuery.cs new file mode 100644 index 0000000..049447b --- /dev/null +++ b/src/Schemio.Object.SQL/BaseSQLQuery.cs @@ -0,0 +1,9 @@ +namespace Schemio.Object.SQL +{ + internal abstract class BaseSQLQuery : BaseQuery, ISQLQuery + where TQueryParameter : IQueryParameter + where TQueryResult : IQueryResult + { + public abstract string GetSQL(); + } +} \ No newline at end of file diff --git a/src/Schemio.Object.SQL/ISQLQuery.cs b/src/Schemio.Object.SQL/ISQLQuery.cs index 4e861f3..2bf8146 100644 --- a/src/Schemio.Object.SQL/ISQLQuery.cs +++ b/src/Schemio.Object.SQL/ISQLQuery.cs @@ -2,8 +2,8 @@ namespace Schemio.Object.SQL { public interface ISQLQuery { - IQueryResult Run(SQLEngine engine); + Type ResultType { get; } - string GetSQL(); + string GetSQL(); } } \ No newline at end of file diff --git a/src/Schemio.Object.SQL/SQLBatchQueryEngine.cs b/src/Schemio.Object.SQL/SQLBatchQueryEngine.cs new file mode 100644 index 0000000..6d1b4a9 --- /dev/null +++ b/src/Schemio.Object.SQL/SQLBatchQueryEngine.cs @@ -0,0 +1,65 @@ +using System.Data.Common; +using System.Data; +using Dapper; +using System.Text; + +namespace Schemio.Object.SQL +{ + public class SQLBatchQueryEngine : IQueryEngine + { + private readonly int Batch_SIZE = 10; + + public IQueryResult[] Run(IQueryList queryList, IDataContext context) + { + var results = new List(); + + if (queryList?.Queries == null) + return Array.Empty(); + + var queries = queryList.Queries.Cast(); + + if (!queries.Any()) + return Array.Empty(); + + var batches = queries.Chunk(Batch_SIZE); + foreach (var batch in batches) + { + var result = RunQueryBatch(batch); + if (result != null) + results.AddRange(result); + } + + return results.ToArray(); + } + + public IEnumerable RunQueryBatch(ISQLQuery[] queryList) + { + var factory = DbProviderFactories.GetFactory(SqlConfiguration.ConnectionSettings.ProviderName); + + if (factory == null) + throw new InvalidOperationException($"Provider: {SqlConfiguration.ConnectionSettings.ProviderName} is not supported. Please register entry in DbProviderFactories "); + + var output = new List(); + + using (var connection = factory.CreateConnection()) + { + connection.ConnectionString = SqlConfiguration.ConnectionSettings.ConnectionString; + + var sqlBuilder = new StringBuilder(); + + foreach (var query in queryList) + sqlBuilder.Append(query.GetSQL() + ";"); + + var queryResults = connection.QueryMultiple(sqlBuilder.ToString()); + + foreach (var query in queryList) + { + var results = queryResults.Read(query.ResultType)?.Cast(); + if (results != null) + output.AddRange(results); + } + return output; + } + } + } +} \ No newline at end of file diff --git a/src/Schemio.Object.SQL/SQLEngine.cs b/src/Schemio.Object.SQL/SQLEngine.cs deleted file mode 100644 index 4c01370..0000000 --- a/src/Schemio.Object.SQL/SQLEngine.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Schemio.Object.SQL -{ - public interface SQLEngine - { - T Run(ISQLQuery query) where T : IQueryResult; - } -} \ No newline at end of file diff --git a/src/Schemio.Object.SQL/SQLQuery.cs b/src/Schemio.Object.SQL/SQLQuery.cs deleted file mode 100644 index f186665..0000000 --- a/src/Schemio.Object.SQL/SQLQuery.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Schemio.Object.SQL -{ - //internal abstract class SQLQuery : IQuery - // where T : class, IQueryResult, ISQLQuery - //{ - // protected abstract string Query(); - - // public IQueryResult Run(SQLEngine engine) - // { - // return engine.Run((ISQLQuery)this); - // } - //} -} \ No newline at end of file diff --git a/src/Schemio.Object.SQL/SQLQueryEngine.cs b/src/Schemio.Object.SQL/SQLQueryEngine.cs index 58e6567..9ed2b83 100644 --- a/src/Schemio.Object.SQL/SQLQueryEngine.cs +++ b/src/Schemio.Object.SQL/SQLQueryEngine.cs @@ -4,26 +4,32 @@ namespace Schemio.Object.SQL { - public class SQLQueryEngine : IQueryEngine, SQLEngine + public class SQLQueryEngine : IQueryEngine { public IQueryResult[] Run(IQueryList queries, IDataContext context) { + if (queries?.Queries == null) + return Array.Empty(); + + var sqlQueries = queries.Queries.Cast(); + + if (!sqlQueries.Any()) + return Array.Empty(); + var results = new List(); - if (queries?.Queries != null) - foreach (var query in queries.Queries.Cast()) - { - var result = query.Run((SQLEngine)this); - if (result != null) - results.Add(result); - } + + foreach (var query in sqlQueries) + { + var result = RunQuery(query.ResultType, query.GetSQL()); + if (result != null) + results.AddRange(result); + } return results.ToArray(); } - public T Run(ISQLQuery query) where T : IQueryResult + public IEnumerable RunQuery(Type type, string sql) { - var sql = query.GetSQL(); - var factory = DbProviderFactories.GetFactory(SqlConfiguration.ConnectionSettings.ProviderName); if (factory == null) @@ -33,10 +39,11 @@ public T Run(ISQLQuery query) where T : IQueryResult { connection.ConnectionString = SqlConfiguration.ConnectionSettings.ConnectionString; - connection.Open(); - var list = connection.Query(sql); + var list = connection.Query(type, sql); - return list.FirstOrDefault(); + return list != null + ? list.Cast() + : Enumerable.Empty(); } } } diff --git a/src/Schemio.Object/BaseQuery.cs b/src/Schemio.Object/BaseQuery.cs index 495663e..4bd2f74 100644 --- a/src/Schemio.Object/BaseQuery.cs +++ b/src/Schemio.Object/BaseQuery.cs @@ -22,7 +22,7 @@ public abstract class BaseQuery : IQuery /// /// Get the result type for the query /// - public Type GetResultType + public Type ResultType { get { return typeof(TQueryResult); } } diff --git a/src/Schemio.Object/CollectionResult.cs b/src/Schemio.Object/CollectionResult.cs new file mode 100644 index 0000000..d924b6d --- /dev/null +++ b/src/Schemio.Object/CollectionResult.cs @@ -0,0 +1,15 @@ +namespace Schemio.Object +{ + public class CollectionResult : IQueryResult + { + private List list; + + public CollectionResult(List list) + { + this.list = list; + } + + public List Items + { get { return list; } } + } +} \ No newline at end of file diff --git a/src/Schemio.Object/IQuery.cs b/src/Schemio.Object/IQuery.cs index cbb8a34..caeb3bd 100644 --- a/src/Schemio.Object/IQuery.cs +++ b/src/Schemio.Object/IQuery.cs @@ -7,7 +7,7 @@ public interface IQuery { List Children { get; set; } - Type GetResultType { get; } + Type ResultType { get; } void ResolveParameterInParentMode(IDataContext context); diff --git a/src/Schemio.Object/QueryList.cs b/src/Schemio.Object/QueryList.cs index 216dea0..e7e5b5e 100644 --- a/src/Schemio.Object/QueryList.cs +++ b/src/Schemio.Object/QueryList.cs @@ -30,7 +30,7 @@ public IQueryList GetByType() where T : class public List GetChildrenQueries() { var childrenQueries = queryList - .Select(x => new ChildrenQueries { ParentQueryResultType = x.GetResultType, Queries = x.Children }) + .Select(x => new ChildrenQueries { ParentQueryResultType = x.ResultType, Queries = x.Children }) .Where(x => x.Queries.Any()) .ToList(); diff --git a/tests/Schemio.Object.Tests/DataProvider.Tests/QueryExecutorTests.cs b/tests/Schemio.Object.Tests/DataProvider.Tests/QueryExecutorTests.cs new file mode 100644 index 0000000..87a8163 --- /dev/null +++ b/tests/Schemio.Object.Tests/DataProvider.Tests/QueryExecutorTests.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Moq; +using Schemio.Object.Impl; +using Schemio.Object.Tests.EntitySetup; +using Schemio.Object.Tests.EntitySetup.Entities; +using static Schemio.Object.Tests.DataProvider.TransformExecutorTests; + +namespace Schemio.Object.Tests.DataProvider.Tests +{ + [TestFixture] + internal class QueryExecutorTests + { + private QueryExecutor _queryExecutor; + private Mock _queryEngine; + + [SetUp] + public void Setup() + { + _queryEngine = new Mock(); + _queryExecutor = new QueryExecutor(new[] { _queryEngine.Object }); + } + + [Test] + public void TestQueryExecutorForCorrectExecutionOfConfiguredQueries() + { + _queryExecutor.Execute(new CustomerContext(), null); + } + } +} \ No newline at end of file diff --git a/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrderItemsQuery.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrderItemsQuery.cs index 3d032aa..eba45be 100644 --- a/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrderItemsQuery.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrderItemsQuery.cs @@ -1,6 +1,6 @@ namespace Schemio.Object.Tests.EntitySetup.Queries { - internal class CustomerOrderItemsQuery : BaseQuery + internal class CustomerOrderItemsQuery : BaseQuery> { public override void ResolveParameterInParentMode(IDataContext context) { diff --git a/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrdersQuery.cs b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrdersQuery.cs index 78e02b6..e2d6ebf 100644 --- a/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrdersQuery.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Queries/CustomerOrdersQuery.cs @@ -1,6 +1,6 @@ namespace Schemio.Object.Tests.EntitySetup.Queries { - internal class CustomerOrdersQuery : BaseQuery + internal class CustomerOrdersQuery : BaseQuery> { public override void ResolveParameterInParentMode(IDataContext context) { diff --git a/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrderItemsTransform.cs b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrderItemsTransform.cs index d5c780e..cefb715 100644 --- a/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrderItemsTransform.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrderItemsTransform.cs @@ -3,14 +3,14 @@ namespace Schemio.Object.Tests.EntitySetup.Transforms { - public class CustomerOrderItemsTransform : BaseTransformer + public class CustomerOrderItemsTransform : BaseTransformer, Customer> { - public override Customer Transform(OrderItemCollectionResult queryResult, Customer entity) + public override Customer Transform(CollectionResult queryResult, Customer entity) { - if (queryResult.OrderItems == null || entity?.Orders == null) + if (queryResult?.Items == null || entity?.Orders == null) return entity; - foreach (var item in queryResult.OrderItems.Where(x => x.Items != null)) + foreach (var item in queryResult.Items.Where(x => x.Items != null)) foreach (var order in entity.Orders) if (order.OrderId == item.OrderId) order.Items = item.Items.Select(x => new OrderItem diff --git a/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrdersTransform.cs b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrdersTransform.cs index 4d69301..50b0300 100644 --- a/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrdersTransform.cs +++ b/tests/Schemio.Object.Tests/EntitySetup/Transforms/CustomerOrdersTransform.cs @@ -3,15 +3,15 @@ namespace Schemio.Object.Tests.EntitySetup.Transforms { - public class CustomerOrdersTransform : BaseTransformer + public class CustomerOrdersTransform : BaseTransformer, Customer> { - public override Customer Transform(OrderCollectionResult queryResult, Customer entity) + public override Customer Transform(CollectionResult queryResult, Customer entity) { - if (queryResult.Orders == null) + if (queryResult?.Items == null) return entity; var customer = entity ?? new Customer(); - customer.Orders = queryResult.Orders.Select(x => new Order + customer.Orders = queryResult.Items.Select(x => new Order { Date = x.Date, OrderId = x.OrderId, From 2471584627251b01f817c945917dffeee9c25aba Mon Sep 17 00:00:00 2001 From: Ninja Date: Sat, 4 Nov 2023 01:08:15 +0000 Subject: [PATCH 20/24] - SQL Engine Implementation --- Schemio.Object.sln | 9 ++- src/Schemio.Object.SQL/SQLBatchQueryEngine.cs | 65 ------------------- src/Schemio.Object.SQL/SQLQueryEngine.cs | 53 ++++++++++----- src/Schemio.Object.SQL/SqlConfiguration.cs | 15 +++-- .../Schemio.Object.SQL.Tests/GlobalUsings.cs | 1 + .../Schemio.Object.SQL.Tests.csproj | 24 +++++++ tests/Schemio.Object.SQL.Tests/UnitTest1.cs | 16 +++++ 7 files changed, 97 insertions(+), 86 deletions(-) delete mode 100644 src/Schemio.Object.SQL/SQLBatchQueryEngine.cs create mode 100644 tests/Schemio.Object.SQL.Tests/GlobalUsings.cs create mode 100644 tests/Schemio.Object.SQL.Tests/Schemio.Object.SQL.Tests.csproj create mode 100644 tests/Schemio.Object.SQL.Tests/UnitTest1.cs diff --git a/Schemio.Object.sln b/Schemio.Object.sln index 53f04b3..24b2fa0 100644 --- a/Schemio.Object.sln +++ b/Schemio.Object.sln @@ -21,7 +21,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution", "solution", "{AF README.md = README.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schemio.Object.SQL", "src\Schemio.Object.SQL\Schemio.Object.SQL.csproj", "{1A0CB973-23C9-4A17-905E-59510CD18932}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Schemio.Object.SQL", "src\Schemio.Object.SQL\Schemio.Object.SQL.csproj", "{1A0CB973-23C9-4A17-905E-59510CD18932}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schemio.Object.SQL.Tests", "tests\Schemio.Object.SQL.Tests\Schemio.Object.SQL.Tests.csproj", "{CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -41,6 +43,10 @@ Global {1A0CB973-23C9-4A17-905E-59510CD18932}.Debug|Any CPU.Build.0 = Debug|Any CPU {1A0CB973-23C9-4A17-905E-59510CD18932}.Release|Any CPU.ActiveCfg = Release|Any CPU {1A0CB973-23C9-4A17-905E-59510CD18932}.Release|Any CPU.Build.0 = Release|Any CPU + {CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -49,6 +55,7 @@ Global {6F017146-B95A-4081-9CC0-B0245F78D72B} = {F41DA3D8-A0E9-4A05-8A35-78313C0F5804} {FDB00281-8B65-4A17-9F1F-B97865544BEF} = {07BAE427-96CF-4F9B-80A9-48CFB0A89CF3} {1A0CB973-23C9-4A17-905E-59510CD18932} = {F41DA3D8-A0E9-4A05-8A35-78313C0F5804} + {CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA} = {07BAE427-96CF-4F9B-80A9-48CFB0A89CF3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C0FF62D6-1374-4939-A546-432862338528} diff --git a/src/Schemio.Object.SQL/SQLBatchQueryEngine.cs b/src/Schemio.Object.SQL/SQLBatchQueryEngine.cs deleted file mode 100644 index 6d1b4a9..0000000 --- a/src/Schemio.Object.SQL/SQLBatchQueryEngine.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Data.Common; -using System.Data; -using Dapper; -using System.Text; - -namespace Schemio.Object.SQL -{ - public class SQLBatchQueryEngine : IQueryEngine - { - private readonly int Batch_SIZE = 10; - - public IQueryResult[] Run(IQueryList queryList, IDataContext context) - { - var results = new List(); - - if (queryList?.Queries == null) - return Array.Empty(); - - var queries = queryList.Queries.Cast(); - - if (!queries.Any()) - return Array.Empty(); - - var batches = queries.Chunk(Batch_SIZE); - foreach (var batch in batches) - { - var result = RunQueryBatch(batch); - if (result != null) - results.AddRange(result); - } - - return results.ToArray(); - } - - public IEnumerable RunQueryBatch(ISQLQuery[] queryList) - { - var factory = DbProviderFactories.GetFactory(SqlConfiguration.ConnectionSettings.ProviderName); - - if (factory == null) - throw new InvalidOperationException($"Provider: {SqlConfiguration.ConnectionSettings.ProviderName} is not supported. Please register entry in DbProviderFactories "); - - var output = new List(); - - using (var connection = factory.CreateConnection()) - { - connection.ConnectionString = SqlConfiguration.ConnectionSettings.ConnectionString; - - var sqlBuilder = new StringBuilder(); - - foreach (var query in queryList) - sqlBuilder.Append(query.GetSQL() + ";"); - - var queryResults = connection.QueryMultiple(sqlBuilder.ToString()); - - foreach (var query in queryList) - { - var results = queryResults.Read(query.ResultType)?.Cast(); - if (results != null) - output.AddRange(results); - } - return output; - } - } - } -} \ No newline at end of file diff --git a/src/Schemio.Object.SQL/SQLQueryEngine.cs b/src/Schemio.Object.SQL/SQLQueryEngine.cs index 9ed2b83..a0ad2f6 100644 --- a/src/Schemio.Object.SQL/SQLQueryEngine.cs +++ b/src/Schemio.Object.SQL/SQLQueryEngine.cs @@ -1,26 +1,36 @@ using System.Data.Common; using System.Data; using Dapper; +using System.Text; +using System.Linq; namespace Schemio.Object.SQL { public class SQLQueryEngine : IQueryEngine { - public IQueryResult[] Run(IQueryList queries, IDataContext context) + private readonly SqlConfiguration sqlConfiguration; + + public SQLQueryEngine(SqlConfiguration sqlConfiguration) { - if (queries?.Queries == null) - return Array.Empty(); + this.sqlConfiguration = sqlConfiguration; + } - var sqlQueries = queries.Queries.Cast(); + public IQueryResult[] Run(IQueryList queryList, IDataContext context) + { + var results = new List(); - if (!sqlQueries.Any()) + if (queryList?.Queries == null) return Array.Empty(); - var results = new List(); + var queries = queryList.Queries.Cast(); - foreach (var query in sqlQueries) + if (!queries.Any()) + return Array.Empty(); + + var batches = queries.Chunk(sqlConfiguration.QuerySettings.QueryBatchSize); + foreach (var batch in batches) { - var result = RunQuery(query.ResultType, query.GetSQL()); + var result = RunQueryBatch(batch); if (result != null) results.AddRange(result); } @@ -28,22 +38,33 @@ public IQueryResult[] Run(IQueryList queries, IDataContext context) return results.ToArray(); } - public IEnumerable RunQuery(Type type, string sql) + public IEnumerable RunQueryBatch(ISQLQuery[] queryList) { - var factory = DbProviderFactories.GetFactory(SqlConfiguration.ConnectionSettings.ProviderName); + var factory = DbProviderFactories.GetFactory(sqlConfiguration.ConnectionSettings.ProviderName); if (factory == null) - throw new InvalidOperationException($"Provider: {SqlConfiguration.ConnectionSettings.ProviderName} is not supported. Please register entry in DbProviderFactories "); + throw new InvalidOperationException($"Provider: {sqlConfiguration.ConnectionSettings.ProviderName} is not supported. Please register entry in DbProviderFactories "); + + var output = new List(); using (var connection = factory.CreateConnection()) { - connection.ConnectionString = SqlConfiguration.ConnectionSettings.ConnectionString; + connection.ConnectionString = sqlConfiguration.ConnectionSettings.ConnectionString; + + var sqlBuilder = new StringBuilder(); + + foreach (var query in queryList) + sqlBuilder.Append(query.GetSQL() + ";"); - var list = connection.Query(type, sql); + var queryResults = connection.QueryMultiple(sql: sqlBuilder.ToString(), commandTimeout: sqlConfiguration.QuerySettings.TimeoutInSecs); - return list != null - ? list.Cast() - : Enumerable.Empty(); + foreach (var query in queryList) + { + var results = queryResults.Read(query.ResultType)?.Cast(); + if (results != null) + output.AddRange(results); + } + return output; } } } diff --git a/src/Schemio.Object.SQL/SqlConfiguration.cs b/src/Schemio.Object.SQL/SqlConfiguration.cs index 31ed09b..dc3b80b 100644 --- a/src/Schemio.Object.SQL/SqlConfiguration.cs +++ b/src/Schemio.Object.SQL/SqlConfiguration.cs @@ -2,14 +2,21 @@ namespace Schemio.Object.SQL { - internal class SqlConfiguration + public class SqlConfiguration { - public static ConnectionSettings ConnectionSettings { get; internal set; } + public ConnectionSettings ConnectionSettings { get; set; } + public QuerySettings QuerySettings { get; set; } } public class ConnectionSettings { - public DbConnection ProviderName { get; internal set; } - public string ConnectionString { get; internal set; } + public DbConnection ProviderName { get; set; } + public string ConnectionString { get; set; } + } + + public class QuerySettings + { + public int TimeoutInSecs { get; set; } = 30; + public int QueryBatchSize { get; set; } = 10; } } \ No newline at end of file diff --git a/tests/Schemio.Object.SQL.Tests/GlobalUsings.cs b/tests/Schemio.Object.SQL.Tests/GlobalUsings.cs new file mode 100644 index 0000000..cefced4 --- /dev/null +++ b/tests/Schemio.Object.SQL.Tests/GlobalUsings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/tests/Schemio.Object.SQL.Tests/Schemio.Object.SQL.Tests.csproj b/tests/Schemio.Object.SQL.Tests/Schemio.Object.SQL.Tests.csproj new file mode 100644 index 0000000..14adf17 --- /dev/null +++ b/tests/Schemio.Object.SQL.Tests/Schemio.Object.SQL.Tests.csproj @@ -0,0 +1,24 @@ + + + + net6.0 + enable + enable + + false + true + + + + + + + + + + + + + + + diff --git a/tests/Schemio.Object.SQL.Tests/UnitTest1.cs b/tests/Schemio.Object.SQL.Tests/UnitTest1.cs new file mode 100644 index 0000000..34ec5b1 --- /dev/null +++ b/tests/Schemio.Object.SQL.Tests/UnitTest1.cs @@ -0,0 +1,16 @@ +namespace Schemio.Object.SQL.Tests +{ + public class Tests + { + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + Assert.Pass(); + } + } +} \ No newline at end of file From 769f5e731a6c7a6681703ee6a02c2bda0a6b0177 Mon Sep 17 00:00:00 2001 From: Ninja Date: Sat, 4 Nov 2023 01:15:08 +0000 Subject: [PATCH 21/24] - refactor --- src/Schemio.Object.SQL/SqlConfiguration.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Schemio.Object.SQL/SqlConfiguration.cs b/src/Schemio.Object.SQL/SqlConfiguration.cs index dc3b80b..657bbdc 100644 --- a/src/Schemio.Object.SQL/SqlConfiguration.cs +++ b/src/Schemio.Object.SQL/SqlConfiguration.cs @@ -4,6 +4,12 @@ namespace Schemio.Object.SQL { public class SqlConfiguration { + public SqlConfiguration() + { + ConnectionSettings = new ConnectionSettings(); + QuerySettings = new QuerySettings(); + } + public ConnectionSettings ConnectionSettings { get; set; } public QuerySettings QuerySettings { get; set; } } From 9122d22b30f0507c10c1b1565ef8bc9614e90d7a Mon Sep 17 00:00:00 2001 From: Ninja Date: Sat, 4 Nov 2023 18:30:28 +0000 Subject: [PATCH 22/24] - Added EF Query engine --- Schemio.Object.sln | 9 +++- src/Schemio.Object.EF/BaseSQLQuery.cs | 17 ++++++++ src/Schemio.Object.EF/EFQueryEngine.cs | 42 +++++++++++++++++++ src/Schemio.Object.EF/IDbContext.cs | 20 +++++++++ src/Schemio.Object.EF/ISQLQuery.cs | 14 +++++++ .../Schemio.Object.EF.csproj | 17 ++++++++ src/Schemio.Object.SQL/BaseSQLQuery.cs | 4 +- ...SQLQueryEngine.cs => DapperQueryEngine.cs} | 13 +++--- src/Schemio.Object.SQL/ISQLQuery.cs | 2 +- .../Schemio.Object.SQL.Tests.csproj | 1 + tests/Schemio.Object.SQL.Tests/UnitTest1.cs | 4 ++ 11 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 src/Schemio.Object.EF/BaseSQLQuery.cs create mode 100644 src/Schemio.Object.EF/EFQueryEngine.cs create mode 100644 src/Schemio.Object.EF/IDbContext.cs create mode 100644 src/Schemio.Object.EF/ISQLQuery.cs create mode 100644 src/Schemio.Object.EF/Schemio.Object.EF.csproj rename src/Schemio.Object.SQL/{SQLQueryEngine.cs => DapperQueryEngine.cs} (84%) diff --git a/Schemio.Object.sln b/Schemio.Object.sln index 24b2fa0..501bc60 100644 --- a/Schemio.Object.sln +++ b/Schemio.Object.sln @@ -23,7 +23,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution", "solution", "{AF EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Schemio.Object.SQL", "src\Schemio.Object.SQL\Schemio.Object.SQL.csproj", "{1A0CB973-23C9-4A17-905E-59510CD18932}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schemio.Object.SQL.Tests", "tests\Schemio.Object.SQL.Tests\Schemio.Object.SQL.Tests.csproj", "{CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Schemio.Object.SQL.Tests", "tests\Schemio.Object.SQL.Tests\Schemio.Object.SQL.Tests.csproj", "{CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schemio.Object.EF", "src\Schemio.Object.EF\Schemio.Object.EF.csproj", "{6B92CC17-B7DB-446F-BF2F-A93696D48B5D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -47,6 +49,10 @@ Global {CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA}.Debug|Any CPU.Build.0 = Debug|Any CPU {CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA}.Release|Any CPU.ActiveCfg = Release|Any CPU {CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA}.Release|Any CPU.Build.0 = Release|Any CPU + {6B92CC17-B7DB-446F-BF2F-A93696D48B5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B92CC17-B7DB-446F-BF2F-A93696D48B5D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B92CC17-B7DB-446F-BF2F-A93696D48B5D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B92CC17-B7DB-446F-BF2F-A93696D48B5D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -56,6 +62,7 @@ Global {FDB00281-8B65-4A17-9F1F-B97865544BEF} = {07BAE427-96CF-4F9B-80A9-48CFB0A89CF3} {1A0CB973-23C9-4A17-905E-59510CD18932} = {F41DA3D8-A0E9-4A05-8A35-78313C0F5804} {CBFE3D90-7FB2-4CB5-8B74-C8664F0173CA} = {07BAE427-96CF-4F9B-80A9-48CFB0A89CF3} + {6B92CC17-B7DB-446F-BF2F-A93696D48B5D} = {F41DA3D8-A0E9-4A05-8A35-78313C0F5804} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C0FF62D6-1374-4939-A546-432862338528} diff --git a/src/Schemio.Object.EF/BaseSQLQuery.cs b/src/Schemio.Object.EF/BaseSQLQuery.cs new file mode 100644 index 0000000..5ced6f0 --- /dev/null +++ b/src/Schemio.Object.EF/BaseSQLQuery.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore; + +namespace Schemio.Object.EF +{ + public abstract class BaseSQLQuery + : BaseQuery, ISQLQuery + where TQueryParameter : IQueryParameter + where TQueryResult : IQueryResult + { + /// + /// Get query delegate with implementation to return query result. + /// Delegate returns a collection from db. + /// + /// Func> + public abstract Func> GetQuery(); + } +} \ No newline at end of file diff --git a/src/Schemio.Object.EF/EFQueryEngine.cs b/src/Schemio.Object.EF/EFQueryEngine.cs new file mode 100644 index 0000000..566bbe0 --- /dev/null +++ b/src/Schemio.Object.EF/EFQueryEngine.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore; + +namespace Schemio.Object.EF +{ + public class EFQueryEngine : IQueryEngine where T : DbContext + { + private readonly IDbContextFactory _dbContextFactory; + + public EFQueryEngine(IDbContextFactory _dbContextFactory) + => this._dbContextFactory = _dbContextFactory; + + public IQueryResult[] Run(IQueryList queryList, IDataContext context) + { + if (queryList?.Queries == null) + return Array.Empty(); + + var queries = queryList.Queries.Cast(); + + if (!queries.Any()) + return Array.Empty(); + + var output = new List(); + + using (var dbcontext = _dbContextFactory.CreateDbContext()) + { + foreach (var query in queries) + { + var queryDelegate = query.GetQuery(); + if (queryDelegate == null) + continue; + + var results = queryDelegate(dbcontext); + if (results == null) + continue; + + output.AddRange(results); + } + return output.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/src/Schemio.Object.EF/IDbContext.cs b/src/Schemio.Object.EF/IDbContext.cs new file mode 100644 index 0000000..a56c90c --- /dev/null +++ b/src/Schemio.Object.EF/IDbContext.cs @@ -0,0 +1,20 @@ +using System.Diagnostics.CodeAnalysis; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata; + +namespace Schemio.Object.EF +{ + public interface IDbContext + { + //DbSet Set<[DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] TEntity>() + //where TEntity : class; + DbSet Set() where TEntity : class; + } + + internal class SchemioContext : DbContext, IDataContext + { + public string[] Paths { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public decimal CurrentVersion => throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Schemio.Object.EF/ISQLQuery.cs b/src/Schemio.Object.EF/ISQLQuery.cs new file mode 100644 index 0000000..70890fb --- /dev/null +++ b/src/Schemio.Object.EF/ISQLQuery.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; + +namespace Schemio.Object.EF +{ + public interface ISQLQuery + { + /// + /// Get query delegate with implementation to return query result. + /// Delegate returns a collection from db. + /// + /// Func> + Func> GetQuery(); + } +} \ No newline at end of file diff --git a/src/Schemio.Object.EF/Schemio.Object.EF.csproj b/src/Schemio.Object.EF/Schemio.Object.EF.csproj new file mode 100644 index 0000000..7b884ac --- /dev/null +++ b/src/Schemio.Object.EF/Schemio.Object.EF.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/src/Schemio.Object.SQL/BaseSQLQuery.cs b/src/Schemio.Object.SQL/BaseSQLQuery.cs index 049447b..5d486b9 100644 --- a/src/Schemio.Object.SQL/BaseSQLQuery.cs +++ b/src/Schemio.Object.SQL/BaseSQLQuery.cs @@ -1,9 +1,9 @@ namespace Schemio.Object.SQL { - internal abstract class BaseSQLQuery : BaseQuery, ISQLQuery + public abstract class BaseSQLQuery : BaseQuery, ISQLQuery where TQueryParameter : IQueryParameter where TQueryResult : IQueryResult { - public abstract string GetSQL(); + public abstract string GetQuery(); } } \ No newline at end of file diff --git a/src/Schemio.Object.SQL/SQLQueryEngine.cs b/src/Schemio.Object.SQL/DapperQueryEngine.cs similarity index 84% rename from src/Schemio.Object.SQL/SQLQueryEngine.cs rename to src/Schemio.Object.SQL/DapperQueryEngine.cs index a0ad2f6..1610dd9 100644 --- a/src/Schemio.Object.SQL/SQLQueryEngine.cs +++ b/src/Schemio.Object.SQL/DapperQueryEngine.cs @@ -6,19 +6,17 @@ namespace Schemio.Object.SQL { - public class SQLQueryEngine : IQueryEngine + public class DapperQueryEngine : IQueryEngine { private readonly SqlConfiguration sqlConfiguration; - public SQLQueryEngine(SqlConfiguration sqlConfiguration) + public DapperQueryEngine(SqlConfiguration sqlConfiguration) { this.sqlConfiguration = sqlConfiguration; } public IQueryResult[] Run(IQueryList queryList, IDataContext context) { - var results = new List(); - if (queryList?.Queries == null) return Array.Empty(); @@ -27,6 +25,8 @@ public IQueryResult[] Run(IQueryList queryList, IDataContext context) if (!queries.Any()) return Array.Empty(); + var results = new List(); + var batches = queries.Chunk(sqlConfiguration.QuerySettings.QueryBatchSize); foreach (var batch in batches) { @@ -49,12 +49,15 @@ public IEnumerable RunQueryBatch(ISQLQuery[] queryList) using (var connection = factory.CreateConnection()) { + if (connection == null) + throw new Exception($"Failed to create connection with Provider: {sqlConfiguration.ConnectionSettings.ProviderName}. Please check the connection settings."); + connection.ConnectionString = sqlConfiguration.ConnectionSettings.ConnectionString; var sqlBuilder = new StringBuilder(); foreach (var query in queryList) - sqlBuilder.Append(query.GetSQL() + ";"); + sqlBuilder.Append(query.GetQuery() + ";"); var queryResults = connection.QueryMultiple(sql: sqlBuilder.ToString(), commandTimeout: sqlConfiguration.QuerySettings.TimeoutInSecs); diff --git a/src/Schemio.Object.SQL/ISQLQuery.cs b/src/Schemio.Object.SQL/ISQLQuery.cs index 2bf8146..be8798a 100644 --- a/src/Schemio.Object.SQL/ISQLQuery.cs +++ b/src/Schemio.Object.SQL/ISQLQuery.cs @@ -4,6 +4,6 @@ public interface ISQLQuery { Type ResultType { get; } - string GetSQL(); + string GetQuery(); } } \ No newline at end of file diff --git a/tests/Schemio.Object.SQL.Tests/Schemio.Object.SQL.Tests.csproj b/tests/Schemio.Object.SQL.Tests/Schemio.Object.SQL.Tests.csproj index 14adf17..f3d8962 100644 --- a/tests/Schemio.Object.SQL.Tests/Schemio.Object.SQL.Tests.csproj +++ b/tests/Schemio.Object.SQL.Tests/Schemio.Object.SQL.Tests.csproj @@ -10,6 +10,7 @@ + diff --git a/tests/Schemio.Object.SQL.Tests/UnitTest1.cs b/tests/Schemio.Object.SQL.Tests/UnitTest1.cs index 34ec5b1..d3f5fe0 100644 --- a/tests/Schemio.Object.SQL.Tests/UnitTest1.cs +++ b/tests/Schemio.Object.SQL.Tests/UnitTest1.cs @@ -1,3 +1,6 @@ +using System.Data.Common; +using Microsoft.Data.Sqlite; + namespace Schemio.Object.SQL.Tests { public class Tests @@ -5,6 +8,7 @@ public class Tests [SetUp] public void Setup() { + DbProviderFactories.RegisterFactory("System.Data.SQLite", SqliteFactory.Instance); } [Test] From f98cbdb447b6b5cd3af77fa58ae22b013bd22ad2 Mon Sep 17 00:00:00 2001 From: Ninja Sha!4h Date: Sun, 19 Nov 2023 14:54:57 +0000 Subject: [PATCH 23/24] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ff54de3..310b3bb 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,8 @@ internal class CustomerSchema : IEntitySchema } } ``` +image + #### 2.1 Query Class The purpose of a query class is to execute to fetch data from data source when mapped schema path(s) are included in the request parameter of data provider. From 10a0600d898b1d0c5ed4878e06537de22288dcba Mon Sep 17 00:00:00 2001 From: Ninja Sha!4h Date: Sun, 19 Nov 2023 15:06:30 +0000 Subject: [PATCH 24/24] Update README.md --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 310b3bb..d08085a 100644 --- a/README.md +++ b/README.md @@ -36,13 +36,19 @@ Below is an example `Customer` entity we want to fetch using schemio. public Order[] Orders { get; set; } } ``` +Example Customer class with XSD Schema +``` +To Do +``` There are three levels of nesting in the object graph for customer class above. - Level 1 with paths: `Customer/CustomerId`, `Customer/CustomerCode`, `Customer/CustomerName` - Level 2 with paths: `Customer/Communication` and `Customer/Orders` - Level 3 with paths: `Customer/Orders/Order/Items` -#### 2. Entity Schema -> Step 2 - Define entity schema configuration which is basically a hierarchy of query/transformer pairs mapping to the object graph of the entity in context. +#### 2. Entity Schema Definition +> Step 2 - Define entity schema configuration which is basically a hierarchy of query/transformer pairs mapping to the schema paths pointing to the object graph of the entity in context. +In query/transformer setup, the output of the query serves as the input to the transformer to map data to linked object graph of the entity in context. +You could nest query/transformer pairs in a parent/child setup. In which case the output of the parent query would become the input to the child query to resolve query paramter. To define Entity schema, implement `IEntitySchema` interface where T is entity in context. The `query/transformer` mappings can be `nested` to `5` levels down.