Skip to content

Commit 88cd3e8

Browse files
committed
- Add Transform Hooks
1 parent ea5501e commit 88cd3e8

38 files changed

+4911
-101
lines changed

src/Schemio.Core/BaseTransformer.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace Schemio.Core
44

55
{
6-
public abstract class BaseTransformer<TQueryResult, TEntity> : ITransformer, ITransformerContext, ITransformerQueryResult
6+
public abstract class BaseTransformer<TQueryResult, TEntity> : ITransformer, ITransformerContext, ITransformerQueryResult, ITransformerHooks
77
where TEntity : IEntity
88
where TQueryResult : IQueryResult
99
{
@@ -39,5 +39,25 @@ public void Transform(IQueryResult queryResult, IEntity entity)
3939
/// <param name="queryResult">Query Result</param>
4040
/// <param name="entity">Entity</param>
4141
public abstract void Transform(TQueryResult queryResult, TEntity entity);
42+
43+
/// <summary>
44+
/// Pre-transform method that can be used to perform any pre-transformation logic if needed.
45+
/// </summary>
46+
/// <param name="context"></param>
47+
public virtual void PreTransform(PreTransformContext context)
48+
{
49+
// This method can be used to perform any pre-transformation logic if needed.
50+
// For example, you could log the query result data or modify it before transformation.
51+
}
52+
53+
/// <summary>
54+
/// Post-transform method that can be used to perform any post-transformation logic if needed.
55+
/// </summary>
56+
/// <param name="context"></param>
57+
public virtual void PostTransform(PostTransformContext context)
58+
{
59+
// This method can be used to perform any post-transformation logic if needed.
60+
// For example, you could log the transformed entity or perform additional processing.
61+
}
4262
}
4363
}

src/Schemio.Core/Helpers/EnumerableExtentions.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using System.Text;
45

56
namespace Schemio.Core.Helpers
@@ -8,12 +9,24 @@ public static class EnumerableExtentions
89
{
910
public static void Each<T>(this IEnumerable<T> enumerable, Action<T> action)
1011
{
12+
if (enumerable == null)
13+
throw new ArgumentNullException(nameof(enumerable), "Enumerable cannot be null");
14+
15+
if (action == null)
16+
throw new ArgumentNullException(nameof(action), "Action cannot be null");
17+
1118
foreach (var item in enumerable)
1219
action(item);
1320
}
1421

1522
public static string ToCSV<T>(this IEnumerable<T> instance, char separator)
1623
{
24+
if (instance == null)
25+
return null;
26+
27+
if (!instance.Any())
28+
return string.Empty;
29+
1730
StringBuilder csv;
1831
if (instance != null)
1932
{
@@ -26,6 +39,9 @@ public static string ToCSV<T>(this IEnumerable<T> instance, char separator)
2639

2740
public static string ToCSV<T>(this IEnumerable<T> instance)
2841
{
42+
if (instance == null)
43+
return null;
44+
2945
return instance.ToCSV(',');
3046
}
3147
}

src/Schemio.Core/Helpers/Xml/XmlHelper.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Text;
23
using System.Xml;
34
using System.Xml.Serialization;
@@ -8,6 +9,12 @@ public static class XmlHelper
89
{
910
public static string SerializeToXml<T>(T value, XmlSerializerNamespaces namespaces, XmlWriterSettings settings)
1011
{
12+
if (value == null)
13+
throw new ArgumentNullException(nameof(value), "Value cannot be null");
14+
15+
if (settings == null)
16+
throw new ArgumentNullException(nameof(settings), "Settings cannot be null");
17+
1118
var xmlStr = new StringBuilder();
1219
var x = new XmlSerializer(typeof(T));
1320

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
3+
namespace Schemio.Core
4+
{
5+
/// <summary>
6+
/// Interface for Schemio options builder.
7+
/// </summary>
8+
public interface ISchemioOptions
9+
{
10+
/// <summary>
11+
/// Register a query engine.
12+
/// </summary>
13+
/// <param name="queryEngines"></param>
14+
/// <returns></returns>
15+
ISchemioOptions WithEngine(Func<IServiceProvider, IQueryEngine> queryEngines);
16+
17+
/// <summary>
18+
/// Register a query engine of type <typeparamref name="TEngine"/>.
19+
/// </summary>
20+
/// <typeparam name="TEngine"></typeparam>
21+
/// <returns></returns>
22+
ISchemioOptions WithEngine<TEngine>() where TEngine : IQueryEngine;
23+
24+
/// <summary>
25+
/// Register an array of query engines.
26+
/// </summary>
27+
/// <param name="queryEngines"></param>
28+
/// <returns></returns>
29+
ISchemioOptions WithEngines(Func<IServiceProvider, IQueryEngine[]> queryEngines);
30+
31+
/// <summary>
32+
/// Register an instance of ISchemaPathMatcher. Default is XPathMatcher.
33+
/// </summary>
34+
/// <param name="pathMatcher"></param>
35+
/// <returns></returns>
36+
ISchemioOptions WithPathMatcher(Func<IServiceProvider, ISchemaPathMatcher> pathMatcher);
37+
38+
/// <summary>
39+
/// Register an instance of EntityConfiguration<typeparamref name="TEntity"/>.
40+
/// </summary>
41+
/// <typeparam name="TEntity"></typeparam>
42+
/// <param name="entityConfiguration"></param>
43+
/// <returns></returns>
44+
ISchemioOptions WithEntityConfiguration<TEntity>(Func<IServiceProvider, IEntityConfiguration<TEntity>> entityConfiguration)
45+
where TEntity : class, IEntity, new();
46+
47+
/// <summary>
48+
/// Set Schemio to silent mode. In this mode, no exceptions will be thrown if there are no entity configurations or query engines registered.
49+
/// </summary>
50+
/// <returns></returns>
51+
ISchemioOptions InSilentMode();
52+
}
53+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace Schemio.Core
2+
{
3+
/// <summary>
4+
/// Transformer hooks interface to allow pre and post transformation actions.
5+
/// </summary>
6+
public interface ITransformerHooks
7+
{
8+
/// <summary>
9+
/// Pre-transform hook to perform actions before the transformation.
10+
/// </summary>
11+
/// <param name="context"></param>
12+
void PreTransform(PreTransformContext context);
13+
14+
/// <summary>
15+
/// Post-transform hook to perform actions after the transformation.
16+
/// </summary>
17+
/// <param name="context"></param>
18+
void PostTransform(PostTransformContext context);
19+
}
20+
}

src/Schemio.Core/Impl/EntityBuilder.cs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,50 @@ public T Build(IDataContext context, IList<IQueryResult> queryResults)
4444

4545
foreach (var queryResult in queryResults)
4646
transformers.Where(transformer => IsMatch(((ITransformerQueryResult)transformer).SupportedQueryResult, queryResult.GetType())).ToList()
47-
.ForEach(supportedtransformer => supportedtransformer?.Transform(queryResult, entity));
47+
.ForEach(transformer => TransformWithHooks(new TransformContext(context, queryResult, transformer, entity)));
4848
}
4949

5050
return entity;
5151
}
5252

53-
private bool IsMatch(Type transformer, Type queryResult)
53+
/// <summary>
54+
/// Checks if the transformer query result type matches the query result type.
55+
/// </summary>
56+
/// <param name="transformerQueryResult"></param>
57+
/// <param name="queryResult"></param>
58+
/// <returns></returns>
59+
private bool IsMatch(Type transformerQueryResult, Type queryResult)
60+
{
61+
return transformerQueryResult == queryResult;
62+
}
63+
64+
/// <summary>
65+
/// Transform method that includes hooks for pre and post transformation.
66+
/// </summary>
67+
/// <param name="context"></param>
68+
private void TransformWithHooks(TransformContext context)
5469
{
55-
return transformer == queryResult;
70+
// Create a pre-transform context to pass the data before transformation.
71+
var preTransformContext = new PreTransformContext(context);
72+
// Call the pre-transform method with the context.
73+
if (context.Transformer is ITransformerHooks transformerPreHook)
74+
transformerPreHook.PreTransform(preTransformContext);
75+
76+
// If the pre-transform context is cancelled, skip the transformation.
77+
if (!preTransformContext.IsCancelled)
78+
context.Transformer.Transform(context.QueryResult, context.Entity);
79+
80+
// Post-transform hook can be used to perform any post-transformation logic if needed.
81+
if (context.Transformer is ITransformerHooks transformerPostHook)
82+
{
83+
// Create a post-transform context to pass the data after transformation.
84+
var postTransformContext = new PostTransformContext(context);
85+
// Call the post-transform method with the context.
86+
transformerPostHook.PostTransform(postTransformContext);
87+
// If the post-transform context is repeat, transform again.
88+
if (postTransformContext.IsRepeat)
89+
context.Transformer.Transform(context.QueryResult, context.Entity);
90+
}
5691
}
5792
}
5893
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace Schemio.Core
2+
{
3+
public class PostTransformContext : TransformContext
4+
{
5+
/// <summary>
6+
/// Indicates whether the transformation needs to be repeated.
7+
/// </summary>
8+
internal bool IsRepeat { get; private set; }
9+
10+
/// <summary>
11+
/// Repeat the transformation process.
12+
/// </summary>
13+
public void Repeat() => IsRepeat = true;
14+
15+
/// <summary>
16+
/// Creates a new instance of PostTransformContext with the provided parameters.
17+
/// </summary>
18+
/// <summary>
19+
/// Creates a new instance of PreTransformContext with the provided parameters.
20+
/// </summary>
21+
/// <param name="context">TransformContext</param>
22+
public PostTransformContext(TransformContext context) :
23+
base(context.DataContext, context.QueryResult, context.Transformer, context.Entity)
24+
{
25+
}
26+
}
27+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace Schemio.Core
2+
{
3+
public class PreTransformContext : TransformContext
4+
{
5+
/// <summary>
6+
/// Indicates whether the transformation has been cancelled.
7+
/// </summary>
8+
internal bool IsCancelled { get; private set; }
9+
10+
/// <summary>
11+
/// Cancels the transformation process.
12+
/// </summary>
13+
public void Cancel() => IsCancelled = true;
14+
15+
/// <summary>
16+
/// Creates a new instance of PreTransformContext with the provided parameters.
17+
/// </summary>
18+
/// <param name="context">TransformContext</param>
19+
public PreTransformContext(TransformContext context) :
20+
base(context.DataContext, context.QueryResult, context.Transformer, context.Entity)
21+
{
22+
}
23+
}
24+
}

src/Schemio.Core/QueryComparer.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,24 @@ public class QueryComparer : IEqualityComparer<IQuery>
66
{
77
#region IQuery
88

9-
public bool Equals(IQuery x, IQuery y) => x.GetType() == y.GetType();
9+
public bool Equals(IQuery x, IQuery y)
10+
{
11+
if (x == null && y == null)
12+
return true;
1013

11-
public int GetHashCode(IQuery obj) => obj.GetType().GetHashCode();
14+
if (x == null || y == null)
15+
return false;
16+
17+
return x.GetType() == y.GetType();
18+
}
19+
20+
public int GetHashCode(IQuery obj)
21+
{
22+
if (obj == null)
23+
throw new System.ArgumentNullException(nameof(obj), "Query object cannot be null");
24+
25+
return obj.GetType().GetHashCode();
26+
}
1227

1328
#endregion IQuery
1429
}

0 commit comments

Comments
 (0)