DataFilters is a .NET library (C#) that converts strings into generic IFilter / IOrder objects using a syntax inspired by Lucene and elastic queries. It targets .NET SDK 10.0 (see global.json).
| Path | Role |
|---|---|
src/DataFilters/ |
Core library — parsing, IFilter, Filter, MultiFilter, Order |
src/Datafilters.Expressions/ |
Converts IFilter → Expression<Func<T,bool>> |
src/DataFilters.Queries/ |
Converts IFilter → IWhereClause (SQL) |
test/DataFilters.UnitTests/ |
Core unit tests |
test/DataFilters.Expressions.UnitTests/ |
Expression unit tests |
test/DataFilters.Queries.UnitTests/ |
Query unit tests |
test/DataFilters.PerformanceTests/ |
Benchmarks |
test/DataFilters.TestObjects/ |
Shared test models |
build/ |
Nuke build project |
./build.sh restore # restore packages & tools
./build.sh tests # run unit tests
./build.sh # full buildBuild system: Nuke. Entrypoint: build/Build.cs.
These rules are mandatory — see CONTRIBUTING.md for full details.
- No
varexcept with anonymous types. Always use explicit types. - Single exit point per method — assign to a result variable and return once at the end.
- Usings: place
Systemdirectives first; remove unused usings. - Indentation: follow the existing style (spaces, consistent alignment).
- Tests: use xunit + FluentAssertions + FsCheck. Test projects reference
tests.props. - Semantic Versioning: the project follows SemVer 2.0. Version zero — public API is not yet stable.
// ✅ DO — explicit type
Filter filter = new Filter("Nickname", FilterOperator.EqualTo, "Batman");
IList<IFilter> filters = new List<IFilter>();
string name = "Bruce";
// ❌ DON'T — var is forbidden
var filter = new Filter("Nickname", FilterOperator.EqualTo, "Batman");
var filters = new List<IFilter>();
var name = "Bruce";// ✅ DO — one return at the end
public string GetLabel(FilterOperator op)
{
string result;
if (op == FilterOperator.EqualTo)
{
result = "eq";
}
else
{
result = "other";
}
return result;
}
// ❌ DON'T — multiple returns
public string GetLabel(FilterOperator op)
{
if (op == FilterOperator.EqualTo)
{
return "eq";
}
return "other";
}// ✅ DO — System first, then others alphabetically
using System;
using System.Collections.Generic;
using System.Linq;
using DataFilters;
using FluentAssertions;
// ❌ DON'T — System not first, or unused usings left in
using DataFilters;
using System;
using System.IO; // unused// ✅ DO — xunit + FluentAssertions, [UnitTest] category, TheoryData for cases
[UnitTest]
public class MyTests
{
public static TheoryData<string, FilterOperator> Cases => new()
{
{ "eq", FilterOperator.EqualTo },
{ "contains", FilterOperator.Contains },
};
[Theory]
[MemberData(nameof(Cases))]
public void Should_parse_operator(string input, FilterOperator expected)
{
// Act
FilterOperator result = Parse(input);
// Assert
result.Should().Be(expected);
}
}
// ❌ DON'T — NUnit, Assert.Equal, missing category
[Test]
public void TestParse()
{
var result = Parse("eq");
Assert.AreEqual(FilterOperator.EqualTo, result);
}- Every new feature or bug fix must have corresponding unit tests.
- Mutation testing (Stryker) is configured — aim for high mutation score.
- Test data generators live in
Generators.csfiles alongside tests.
- Default branch:
develop. - Production branch:
main. - Create topic branches off
develop.
- Do not add unnecessary abstractions, helpers, or wrappers.
- Do not introduce dependencies without justification.
- Do not modify build infrastructure unless explicitly asked.
- Do not use
var(except anonymous types). - Do not write methods with multiple return statements.
// ❌ DON'T — unnecessary wrapper/helper
public static class FilterHelper
{
public static Filter Eq(string field, object value)
=> new(field, FilterOperator.EqualTo, value);
}
// ✅ DO — use the types directly
Filter filter = new Filter("Age", FilterOperator.EqualTo, 30);// ❌ DON'T — over-engineer with defensive checks on internal code
public void Process(Filter filter)
{
if (filter == null) throw new ArgumentNullException(nameof(filter));
if (string.IsNullOrEmpty(filter.Field)) throw new ArgumentException("Field required");
// ...
}
// ✅ DO — trust internal callers, validate only at system boundaries
public void Process(Filter filter)
{
// filter is guaranteed non-null by the calling pipeline
string field = filter.Field;
// ...
}