-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactored use of JsonElement and JsonNode into different implementat…
…ion or via type accessors.
- Loading branch information
1 parent
621d785
commit a846f7d
Showing
43 changed files
with
1,007 additions
and
715 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using Hyperbee.Json.Evaluators.Parser; | ||
|
||
namespace Hyperbee.Json.Evaluators; | ||
|
||
public interface IJsonTypeDescriptor | ||
{ | ||
public Dictionary<string, FunctionCreator> Functions { get; } | ||
|
||
public IJsonValueAccessor<TElement> GetAccessor<TElement>(); | ||
public IJsonPathFilterEvaluator<TElement> GetFilterEvaluator<TElement>(); | ||
public FilterFunction GetFilterFunction( ParseExpressionContext context ); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
namespace Hyperbee.Json.Evaluators; | ||
|
||
public interface IJsonValueAccessor<TElement> | ||
{ | ||
IEnumerable<(TElement, string)> EnumerateChildValues( TElement value ); | ||
TElement GetElementAt( TElement value, int index ); | ||
bool IsObjectOrArray( TElement current ); | ||
bool IsArray( TElement current, out int length ); | ||
bool IsObject( TElement current ); | ||
bool TryGetChildValue( in TElement current, ReadOnlySpan<char> childKey, out TElement childValue ); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 3 additions & 3 deletions
6
...rser/Functions/JsonPathElementFunction.cs → ...s/Parser/Element/FilterElementFunction.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,14 @@ | ||
using System.Linq.Expressions; | ||
|
||
namespace Hyperbee.Json.Evaluators.Parser.Functions; | ||
namespace Hyperbee.Json.Evaluators.Parser.Element; | ||
|
||
public class JsonPathElementFunction<TType>( ParseExpressionContext<TType> context ) : ParserFunction<TType> | ||
public class FilterElementFunction( ParseExpressionContext context ) : FilterFunction | ||
{ | ||
protected override Expression Evaluate( ReadOnlySpan<char> data, ReadOnlySpan<char> item, ref int start, ref int from ) | ||
{ | ||
var queryExp = Expression.Constant( item.ToString() ); | ||
|
||
// Create a call expression for the extension method | ||
return Expression.Call( JsonPathHelper<TType>.GetFirstElementValueMethod, context.Current, context.Root, queryExp ); | ||
return Expression.Call( FilterElementHelper.SelectFirstElementValueMethod, context.Current, context.Root, queryExp ); | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
src/Hyperbee.Json/Evaluators/Parser/Element/FilterElementHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
using System.Reflection; | ||
using System.Text.Json; | ||
|
||
namespace Hyperbee.Json.Evaluators.Parser.Element; | ||
|
||
public static class FilterElementHelper | ||
{ | ||
public static readonly MethodInfo SelectFirstElementValueMethod; | ||
public static readonly MethodInfo SelectFirstMethod; | ||
|
||
public static readonly MethodInfo SelectElementsMethod; | ||
|
||
static FilterElementHelper() | ||
{ | ||
var thisType = typeof( FilterElementHelper ); | ||
|
||
SelectFirstElementValueMethod = thisType.GetMethod( nameof( SelectFirstElementValue ), [typeof( JsonElement ), typeof( JsonElement ), typeof( string )] ); | ||
SelectFirstMethod = thisType.GetMethod( nameof( SelectFirst ), [typeof( JsonElement ), typeof( JsonElement ), typeof( string )] ); | ||
SelectElementsMethod = thisType.GetMethod( nameof( SelectElements ), [typeof( JsonElement ), typeof( JsonElement ), typeof( string )] ); | ||
} | ||
|
||
private static bool IsNotEmpty( JsonElement element ) | ||
{ | ||
return element.ValueKind switch | ||
{ | ||
JsonValueKind.Array => element.EnumerateArray().Any(), | ||
JsonValueKind.Object => element.EnumerateObject().Any(), | ||
_ => false | ||
}; | ||
} | ||
|
||
public static object SelectFirstElementValue( JsonElement current, JsonElement root, string query ) | ||
{ | ||
var element = SelectFirst( current, root, query ); | ||
|
||
return element.ValueKind switch | ||
{ | ||
JsonValueKind.Number => element.GetSingle(), | ||
JsonValueKind.String => element.GetString(), | ||
JsonValueKind.Object => IsNotEmpty( element ), | ||
JsonValueKind.Array => IsNotEmpty( element ), | ||
JsonValueKind.True => true, | ||
JsonValueKind.False => false, | ||
JsonValueKind.Null => false, | ||
JsonValueKind.Undefined => false, | ||
_ => false | ||
}; | ||
} | ||
|
||
public static JsonElement SelectFirst( JsonElement current, JsonElement root, string query ) | ||
{ | ||
return SelectElements( current, root, query ) | ||
.FirstOrDefault(); | ||
} | ||
|
||
public static IEnumerable<JsonElement> SelectElements( JsonElement current, JsonElement root, string query ) | ||
{ | ||
return JsonPath<JsonElement> | ||
.Select( current, root, query ); | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
src/Hyperbee.Json/Evaluators/Parser/Element/JsonElementTypeDescriptor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
namespace Hyperbee.Json.Evaluators.Parser.Element; | ||
|
||
public class JsonElementTypeDescriptor : IJsonTypeDescriptor | ||
{ | ||
public Dictionary<string, FunctionCreator> Functions { get; init; } | ||
|
||
public IJsonValueAccessor<TElement> GetAccessor<TElement>() => | ||
new JsonElementValueAccessor() as IJsonValueAccessor<TElement>; | ||
|
||
public IJsonPathFilterEvaluator<TElement> GetFilterEvaluator<TElement>() => | ||
new JsonPathFilterEvaluator<TElement>( this ); | ||
|
||
public FilterFunction GetFilterFunction( ParseExpressionContext context ) => | ||
new FilterElementFunction( context ); | ||
|
||
public JsonElementTypeDescriptor() | ||
{ | ||
Functions = new Dictionary<string, FunctionCreator>( | ||
[ | ||
new KeyValuePair<string, FunctionCreator>( CountElementFunction.Name, ( name, arguments, context ) => new CountElementFunction( name, arguments, context ) ), | ||
new KeyValuePair<string, FunctionCreator>( LengthElementFunction.Name, ( name, arguments, context ) => new LengthElementFunction( name, arguments, context ) ), | ||
new KeyValuePair<string, FunctionCreator>( MatchElementFunction.Name, ( name, arguments, context ) => new MatchElementFunction( name, arguments, context ) ), | ||
new KeyValuePair<string, FunctionCreator>( SearchElementFunction.Name, ( name, arguments, context ) => new SearchElementFunction( name, arguments, context ) ), | ||
new KeyValuePair<string, FunctionCreator>( ValueElementFunction.Name, ( name, arguments, context ) => new ValueElementFunction( name, arguments, context ) ), | ||
] ); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
src/Hyperbee.Json/Evaluators/Parser/Element/LengthElementFunction.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
using System.Text.Json; | ||
|
||
namespace Hyperbee.Json.Evaluators.Parser.Element; | ||
|
||
public class LengthElementFunction( string methodName, IList<string> arguments, ParseExpressionContext context ) : FilterExpressionFunction( methodName, arguments, context ) | ||
{ | ||
public const string Name = "length"; | ||
|
||
private static readonly MethodInfo LengthMethod; | ||
|
||
static LengthElementFunction() | ||
{ | ||
LengthMethod = typeof( LengthElementFunction ).GetMethod( nameof( Length ), [typeof( JsonElement )] ); | ||
} | ||
|
||
public override Expression GetExpression( string methodName, IList<string> arguments, ParseExpressionContext context ) | ||
{ | ||
if ( arguments.Count != 1 ) | ||
{ | ||
return Expression.Throw( Expression.Constant( new ArgumentException( $"{Name} function has invalid parameter count." ) ) ); | ||
} | ||
|
||
var queryExp = Expression.Constant( arguments[0] ); | ||
|
||
return Expression.Call( | ||
LengthMethod, | ||
Expression.Call( FilterElementHelper.SelectFirstMethod, | ||
context.Current, | ||
context.Root, | ||
queryExp ) ); | ||
} | ||
|
||
public static float Length( JsonElement element ) | ||
{ | ||
return element.ValueKind switch | ||
{ | ||
JsonValueKind.String => element.GetString()?.Length ?? 0, | ||
JsonValueKind.Array => element.GetArrayLength(), | ||
JsonValueKind.Object => element.EnumerateObject().Count(), | ||
_ => 0 | ||
}; | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
src/Hyperbee.Json/Evaluators/Parser/Element/MatchElementFunction.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
using System.Text.Json; | ||
using System.Text.RegularExpressions; | ||
|
||
namespace Hyperbee.Json.Evaluators.Parser.Element; | ||
|
||
public class MatchElementFunction( string methodName, IList<string> arguments, ParseExpressionContext context ) : FilterExpressionFunction( methodName, arguments, context ) | ||
{ | ||
public const string Name = "match"; | ||
|
||
private static readonly MethodInfo MatchMethod; | ||
|
||
static MatchElementFunction() | ||
{ | ||
MatchMethod = typeof( MatchElementFunction ).GetMethod( nameof( Match ), [typeof( JsonElement ), typeof( string )] ); | ||
} | ||
|
||
public override Expression GetExpression( string methodName, IList<string> arguments, ParseExpressionContext context ) | ||
{ | ||
if ( arguments.Count != 2 ) | ||
{ | ||
return Expression.Throw( Expression.Constant( new ArgumentException( $"{Name} function has invalid parameter count." ) ) ); | ||
} | ||
|
||
var queryExp = Expression.Constant( arguments[0] ); | ||
var regex = Expression.Constant( arguments[1] ); | ||
|
||
return Expression.Call( | ||
MatchMethod, | ||
Expression.Call( FilterElementHelper.SelectFirstMethod, | ||
context.Current, | ||
context.Root, | ||
queryExp ) | ||
, regex ); | ||
} | ||
|
||
public static bool Match( JsonElement element, string regex ) | ||
{ | ||
var regexPattern = new Regex( regex.Trim( '\"', '\'' ) ); | ||
var value = $"^{element.GetString()}$"; | ||
|
||
return regexPattern.IsMatch( value ); | ||
} | ||
} |
Oops, something went wrong.