| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
JsonToLinq - lightweight C# library that converts JSON-based query definitions into LINQ expressions. Ideal for building dynamic filters, predicates, and queries.
Use JSON to build LINQ expressions!
Friendliness
JSON is a simple and widely known format, easy to read not only for developers.
Broad applicability
JSON-based filters can be used in tests, specifications, test plans, and other technical documentation, lowering the entry barrier for readers.
Universality
To retrieve data from a .NET application using EF, it is enough to request it in JSON format. This makes the approach accessible to any client that knows the field names and their types.
Client-server independence
To build filters, the client only needs to know the names and types of data fields, which are usually already present in DTOs.
Flexibility
Custom operators can be added out of the box, and the core functionality can serve as a foundation for other projects - for example, building an alternative to HotChocolate with standard JSON and different design choices.
Simplicity
Install the NuGet package and pass JSON filters into Where() and other filtering methods. This enables not a minimal subset, but the full functionality.
No need to:
Everything required for filtering is already contained in the DTOs.
using Neomaster.JsonToLinq;
var users = source.Where(
"""
{
"Logic": "&&",
"Rules": [
{ "Field": "balance", "Operator": "=", "Value": 0 },
{ "Field": "status", "Operator": "in", "Value": [ 1, 3 ] },
{ "Field": "country", "Operator": "as lower contains", "Value": "islands" },
{
"Logic": "||",
"Rules": [
{ "Field": "lastVisitAt", "Operator": "=", "Value": null },
{ "Field": "lastVisitAt", "Operator": "<=", "Value": "2026-01-01T00:00:00Z" }
]
}
]
}
""");Equivalent LINQ query:
var users = source.Where(u =>
(u.Balance == 0
&& new[] { 1, 3 }.Contains(u.Status)
&& u.Country.ToLower().Contains("islands"))
&&
(u.LastVisitAt == null
|| u.LastVisitAt <= JsonSerializer.Deserialize<DateTime?>("\"2026-01-01T00:00:00Z\"")));| Operator | Description |
|---|---|
| & | Bitwise AND |
| | | Bitwise OR |
| && / and | Logical AND |
| || / or | Logical OR |
| = / eq | Equal |
| != / neq | Not equal |
| > / gt | Greater than |
| >= / gte | Greater than or equal |
| < / lt | Less than |
| <= / lte | Less than or equal |
| in | In collection |
| as lower in | Element lower-cased in collection |
| as upper in | Element upper-cased in collection |
| contains | Contains substring |
| as lower contains | Element lower-cased contains substring |
| as upper contains | Element upper-cased contains substring |
| starts with | Starts with |
| as lower starts with | Element lower-cased starts with |
| as upper starts with | Element upper-cased starts with |
| ends with | Ends with |
| as lower ends with | Element lower-cased ends with |
| as upper ends with | Element upper-cased ends with |
The word not is an alias for !.
It improves readability but is not suitable for all operators:
All built-in operators are designed to be translatable by LINQ providers (e.g. Entity Framework Core) and do not rely on client-side evaluation.
JsonLinq.Configure(options =>
{
options.OperatorMapper = new ExpressionOperatorMapper()
.Add("=", Expression.Equal)
.WithAliases("eq", "EQ")
.AddNot("!=", "=")
.WithAliases("neq", "NEQ")
.AddAlias("==", "=")
.WithNot("<>");
});JsonLinq.Configure(options =>
{
options.OperatorMapper = ExpressionOperatorMapper.OnDefault()
.Add(...
});Negated operators can be defined without explicitly providing a key. In this case, the key is automatically generated using the NegatedKeyProvider. This provider can be set via SetNegatedKeyProvider().
new ExpressionOperatorMapper()
// Default provider
.Add("a", ...).WithNot() // "!a"
.Add("b c", ...).WithNot() // "! b c"
// Custom provider
.SetNegatedKeyProvider(key => (key.Contains(' ') ? "~ " : "~") + key)
.Add("x", ...).WithNot() // "~x"
.Add("y z", ...).WithNot() // "~ y z"The library is built on netstandard2.1 and does not depend on EF or any other ORM. To perform case-insensitive string comparisons, use the built-in operators with as lower or as upper. They differ only in the preferred case for filter values.
JsonLinq.Configure(options =>
{
options.OperatorMapper = ExpressionOperatorMapper.OnDefault()
.Add("like", (element, pattern) =>
Expression.Call(
typeof(DbFunctionsExtensions).GetMethod(
nameof(DbFunctionsExtensions.Like),
[typeof(DbFunctions), typeof(string), typeof(string)]),
Expression.Constant(EF.Functions),
element,
pattern))
.Add("ilike", (element, pattern) =>
Expression.Call(
typeof(NpgsqlDbFunctionsExtensions).GetMethod(
nameof(NpgsqlDbFunctionsExtensions.ILike),
[typeof(DbFunctions), typeof(string), typeof(string)]),
Expression.Constant(EF.Functions),
element,
pattern));
});You can define your own settings via JsonLinq.Configure(). To reset the configuration, call JsonLinq.ResetConfiguration(). This is necessary for testing.
JsonLinq.Configure(options =>
{
// Property names in JSON filters
options.LogicOperatorPropertyName = "🔗";
options.RulesPropertyName = "⚖️";
options.OperatorPropertyName = "⚡";
options.FieldPropertyName = "🍁";
options.ValuePropertyName = "🍬";
// Operator definitions and aliases
options.OperatorMapper = ExpressionOperatorMapper.OnDefault()
.AddAlias("does not contain", "!contains");
// Handling logic for expressions with null
options.BindBuilder = ExpressionBindBuilders.NullAsFalse;
// How C# property names appear in JSON
options.ConvertPropertyNameForJson = JsonNamingPolicy.SnakeCaseUpper.ConvertName;
});The JSON filter structure settings are relevant.
For example, adding syntactic sugar:
"Logic": "&&", "Rules": [...] → "&&": [...]
Or specifying the property order to support TONL filters.
This may be implemented in future versions.
Unit tests cover:
Full unit test coverage will be relevant after the library has been used in real projects.
This repository includes the JsonToLinq.Demo project with working examples. You are welcome to submit a PR with your own examples, bug reports, or new features. To describe a filter, use the following notation:
expr = logic[expr(, expr)*]
This project provides examples of working with EF Core and a PostgreSQL database.
🧪 A real database is used instead of in-memory storage, ensuring clean and realistic experiments.
➕ You can add your own examples with other databases or ORMs via a PR.
▶️ Before running the demos, select the first menu item, Prepare Data, to apply migrations and populate the tables with test data.
No IDE syntax highlighting for JSON filter arguments in LINQ methods
The library targets netstandard2.1, which does not support StringSyntaxAttribute. Care is needed when writing filters manually. In practice, this is not critical, as filters typically come from client applications.
No IntelliSense for JSON filters
Without suggestions, it is harder to ensure filter correctness.
Aggregate fields are not supported
For now, it is recommended to use flat DTOs and database views.
{
"Rules": [
{ "Field": "✅ user_id", "Operator": "=", "Value": 123 },
{ "Field": "❌ user.id", "Operator": "=", "Value": 123 }
]
}These features may be implemented in future versions.
Filtering is just the first stage in the development of JSON-LINQ infrastructure. Possible future directions include:
| Back | FazBrowse Home | New Git URL |