Changelog — Vali-Flow.Core
All notable changes to this package are documented here.
Format: Keep a Changelog · Versioning: SemVer
[2.0.2] — 2026-04-15
Fixed
ComparisonExpression.Null()andNotNull(): Fixed WHERE 0=1 bug when used with EF CoreGlobalQueryFilter. Now usesExpression.Equal()/Expression.NotEqual()instead of C# operators to ensure consistent expression tree structure for SQL translation.
Added
- EfCoreIsNullIntegrationTests: 6 integration tests verifying
IsNull()andNotNull()work correctly with EF Core GlobalQueryFilter.
[2.0.0] — 2026-04-05
Architecture
- Source generator (
Vali-Flow.Core.Generator): RoslynIIncrementalGeneratorthat reads[ForwardInterface]-marked fields inpartialclasses and emits a sibling.g.csfile with one forwarding method per interface member. Traverses the full interface inheritance hierarchy and generates explicit interface implementations when two interfaces declare conflicting signatures. Eliminates ~468 manually-maintained delegation methods fromValiFlow<T>andValiFlowQuery<T>. ValiFlow<T>andValiFlowQuery<T>reduced from ~893 / ~808 lines to ~110 lines each — now thinpartialfacades; all method bodies live in their respective*Expression/*ExpressionQueryclasses.- 9 query-specific interfaces added (
IBooleanExpressionQuery,IStringExpressionQuery,ICollectionExpressionQuery,INumericExpressionQuery,IDateTimeExpressionQuery,IDateTimeOffsetExpressionQuery,IDateOnlyExpressionQuery,ITimeOnlyExpressionQuery) — complete the interface hierarchy for the EF Core-safe variant. BaseExpression.ValidateNestedDIP fix: extractedprotected virtual CreateNestedBuilder<TProperty>()factory method — decouplesBaseExpressionfrom the concreteValiFlow<T>type.
Infrastructure
Vali-Flow.Core.Analyzers: Roslyn diagnostic analyzer (ValiFlowNonEfMethodAnalyzer) that reportsVFCORE001when a method not supported by EF Core providers is called on aValiFlowQuery<T>instance inside anIQueryable<T>expression context.- Bilingual technical documentation added under
docs/(Spanish + English): architecture overview, builder lifecycle, expression tree internals, EF Core compatibility guide, source generator guide, and full API reference.
Breaking Changes
- Removed deprecated methods:
BeforeDate,AfterDate(useIsBefore/IsAfter),CountEquals(useCount). IStringExpression<TBuilder,T>now inherits from 4 focused sub-interfaces:IStringLengthExpression— MinLength, MaxLength, ExactLength, LengthBetweenIStringContentExpression— StartsWith, EndsWith, Contains, EqualToIgnoreCase, IsOneOfIStringStateExpression— IsNullOrEmpty, IsNullOrWhiteSpace, IsTrimmed, IsLowerCase, IsUpperCase, HasOnlyDigits, HasOnlyLetters, HasLettersAndNumbers, HasSpecialCharactersIStringFormatExpression— IsEmail, IsUrl, IsGuid, IsJson, IsBase64, RegexMatch, MatchesWildcard, IsCreditCard, IsIPv4, IsIPv6, IsHexColor, IsSlug
ValidationResult.ErrorsAbove()renamed toErrorsAtOrAbove()— the method uses>=semantics.ValidationResult.ErrorsAtOrAbove()now returns.AsReadOnly().BaseExpression.CreateNestedBuilder<TProperty>()changed fromabstracttovirtualwith defaultnew ValiFlow<TProperty>().BuildCached()no longer allows post-call mutation — throwsInvalidOperationException(introduced in 1.6.0, now documented as stable contract).
Performance
ConditionEntry<T>compiles predicates lazily viaLazy<Func<T,bool>>— thread-safe without explicit locking.Validate()short-circuits OR groups: returnsOk()as soon as one group passes.ValidateResult.WarningsandCriticalErrorschanged from eagerList<T>toLazy<IReadOnlyList<T>>.StringExpression._regexCachemoved to non-genericStringExpressionCache— the 1,000-entry cap applies globally.BuildWithGlobal()caches the result ofBuild()internally.CollectionExpression._enumerableCountMethodnowstatic readonly.
Migration Guide
| v1.x | v2.0 |
|---|---|
BeforeDate(selector, date) | IsBefore(selector, date) |
AfterDate(selector, date) | IsAfter(selector, date) |
CountEquals(selector, n) | Count(selector, n) |
[1.7.0] — 2026-04-04
Architecture
- ValiFlowQuery<T> God Class eliminated: reduced from 2,329 lines to ~530 lines by extracting all method bodies into 9 domain-specific composition classes.
ValiFlowQuery<T>is now a thin wrapper identical in structure toValiFlow<T>. Public API unchanged. - Deleted
Constant.csandUtil.cs(dead code). - Consolidated
ExpressionDeepClonerintoForceCloneVisitor.
New Features — ValiFlowQuery<T> (EF Core-safe)
String
IsTrimmed,IsLowerCase,IsUpperCase,EqualToIgnoreCaseStartsWithIgnoreCase,EndsWithIgnoreCase,ContainsIgnoreCaseNotContains,NotStartsWith,NotEndsWith
Numeric (int and long)
IsEven,IsOdd,IsMultipleOf(n)— translatable via modulo
DateTime / DateTimeOffset / DateOnly
IsWeekend/IsWeekday/IsDayOfWeekIsToday/IsYesterday/IsTomorrowInLastDays(n)/InNextDays(n)— sliding UTC windows captured at build timeIsFirstDayOfMonth/IsLastDayOfMonth/IsInQuarter(q)
Bug Fixes
ComparisonExpression.EqualTo/NotEqualTo: removed incorrect null guard — fixes nullable value type comparisons.StringExpression: replaced privateReplaceParamVisitorwith canonicalParameterReplacer.
Test Coverage
- xUnit test project added with 961 tests (net9.0). All pass.
[1.6.1] — 2026-03-28
New Features
BaseExpression<TBuilder,T>:Clone()— creates a new, independent builder pre-populated with all conditions from the source. The clone starts unfrozen regardless of source freeze state. Added toIExpression<TBuilder,T>interface.
Test Coverage
- Added 3 new Clone tests. Total: 790 tests.
[1.6.0] — 2026-03-28
New Features
- Freeze pattern: builder is permanently sealed on first call to
BuildCached(),IsValid(),IsNotValid(), orValidate(). Mutation after freeze throwsInvalidOperationException. BaseExpression<TBuilder,T>: new publicFreeze()method for explicit sealing at DI/startup phase.IExpression<TBuilder,T>:Freeze()added to the public interface.
Breaking Change
BuildCached()no longer allows post-call mutation. If you need different conditions, create a new instance.
Bug Fix
- Eliminated silent data-corruption when a shared builder was mutated after use.
Test Coverage
- Added 7 new freeze tests. Total: 787 tests.
[1.5.0] — 2026-03-28
Documentation
- ValiFlowQuery: XML docs added to all previously undocumented numeric, DateTime, DateTimeOffset, DateOnly, and TimeOnly methods.
Test Coverage
- Total: 782 tests (unchanged).
[1.4.9] — 2026-03-28
Bug Fixes
NumericExpressionnullable overloads: added missing selector null guard.NumericExpressionnullableInRange: selector null guard now runs before max < min validation.
New Features
- Full nullable comparison parity for
double?,float?,short?— GreaterThan, LessThan, InRange. ValiFlowQuery: addedFutureDate(DateTimeOffset)andPastDate(DateTimeOffset).
Test Coverage
- Total: 782 tests.
[1.4.8] — 2026-03-28
Bug Fixes
NumericExpressionscalar InRange (all 6 typed overloads): selector null guard now runs before max < min validation.NumericExpression50+ scalar overloads: explicit selector null guard added for consistent API contract.ValiFlowQueryStartsWith, EndsWith, Contains: selector null guard added.
New Features
ValiFlowQuery: addedCountBetween<TValue>— completes API parity withCollectionExpression.CountBetween.
Test Coverage
- Added 4 new tests. Total: 780 tests.
[1.4.7] — 2026-03-28
Bug Fixes
NumericExpression InRange<TValue>(IComparable): added missing selector null guard.DateTimeExpression BetweenDatescross-property: replaced fragile Convert fallback with CloneExpression helper.
New Features
ValiFlowQuery: nullablefloat?overloads — GreaterThan, LessThan, InRange.ValiFlowQuery: nullableshort?overloads — IsNullOrZero, HasValue, GreaterThan, LessThan, InRange.
Test Coverage
- Added 9 new tests. Total: 778 tests.
[1.4.5] — 2026-03-28
Bug Fixes
ValiFlowQuery ValidateNested: added ForceCloneVisitor for null-check node.NumericExpressioncross-propertyIComparable<TValue>: added CloneSelectorBody helper.StringExpression ExpressionDeepCloner.VisitMethodCall: added null guard for static method calls.ValiFlowQuery MaxCount: null collection now returnstrue(wasfalse).
Test Coverage
- Added 20 new tests. Total: 759 tests.
[1.4.4] — 2026-03-28
New Features
NumericExpression/ValiFlow/ValiFlowQuery: addedHasValue(float?)overload.
Bug Fixes
BaseExpression IsNotValid: replaced plain field read post-CompareExchange with atomic return.BaseExpression ValidateNested: replaced no-op ParameterReplacer with ForceCloneVisitor.CollectionExpression All/Any/None/EachItem/AnyItem: null-check now uses its own clone ofselectorBody.StringExpression RegexMatch: cache-full guard now usesVolatile.Read.DateTimeOffsetExpression InLastDays/InNextDays: guard aligned todays <= 0.
Test Coverage
- Added 11 new tests. Total: 741 tests.
[1.4.3] — 2026-03-28
Bug Fixes
BaseExpression BuildCached: replaced plain field read with atomic return — eliminates stale-read risk on ARM64.BaseExpression ValidateNested: cloned selector body to eliminate expression tree node aliasing.NumericExpressioncross-propertyIComparable<TValue>: fixed node aliasing in all 4 overloads.DateTimeOffsetExpression InLastDays/InNextDays: date now evaluated inside lambda (was stale when reused across day boundary).StringExpression RegexMatch:Interlocked.Incrementnow fires only on successfulTryAdd.RegularExpression PhonePattern:+prefix now mandatory (strict E.164 format).ValiFlowQuery IsTrue: added null guard on selector.ValiFlowQuery IsLastDayOfMonth(DateOnly): removed from EF-safe builder (usesDateTime.DaysInMonth, not EF Core translatable).
Test Coverage
- Added 25 new tests. Total: 730 tests.
[1.4.2] — 2026-03-28
New Features
NumericExpression/ValiFlowQuery: addedIsNullOrZero(float?)overload.
Bug Fixes
NumericExpression EqualTo<TValue>: added null guard.ValiFlowQuery IsInMonth/IsInYear (DateTimeOffset): added EF Core UTC-vs-offset divergence warning in XML docs.
[1.4.1] — 2026-03-28
Bug Fixes
StringExpression RegexMatch: cache cap now enforced with atomicInterlockedcounter.ValiFlowQuery DateTime/DateTimeOffset: added null guard on selector in all 22 delegating methods.ValiFlowQuery IsNullOrWhiteSpace/IsNotNullOrWhiteSpace: corrected EF Core remarks (Pomelo < 5.0 unsupported).
[1.4.0] — 2026-03-28
New Features
ValiFlowQuery:GreaterThan(double?),LessThan(double?),InRange(double?)for nullable double columns.ValiFlowQuery:IsLastDayOfMonth(DateOnly).ValiFlowQuery:BeforeDate/AfterDatefor DateTime now normalize todate.Date.
Bug Fixes
StringExpression RegexMatch: cache capped at 1,000 entries.CollectionExpression All/Any/None/EachItem/AnyItem: fixed sharedselector.Bodynode aliasing.CollectionExpression MaxCount: null collection now correctly returnstrue.ValiFlowQuery Contains: rejects empty string.RegularExpression: E.164 phone pattern minimum raised to 7 digits; email pattern rejects leading/trailing dots.DateTimeOffsetExpression InLastDays/InNextDays:UtcNowcaptured once per call.
Test Coverage
- Added 41 new tests. Total: 711 tests.
[1.3.0] — 2025-09-01
New Features
DateTimeOffsetExpression: addedIsYesterdayandIsTomorrow(in-memory only).
Bug Fixes
Combine()/&/|operators: short-circuit when either builder is empty.IComparable<TValue>cross-property overloads: null guard skipped for value types.AddSubGroupempty action: throwsArgumentExceptionwith clear message.ValidateNestedempty configure: throwsArgumentExceptioninstead of silently producing a null-only check.ComparisonExpression EqualTo/NotEqualTo: throwsArgumentNullExceptionwith"Use Null() to check for null values.".Base64Patternregex: enforces groups-of-4 (length multiple of 4).UrlPatternregex: removed unescaped dot.
Test Coverage
- Added
ValiFlowQueryTests: 65 tests covering allValiFlowQuery<T>method groups. Total: 665 tests.
[1.2.0] — 2025-06-01
New Features
ValiFlowQuery<T>: new EF Core-safe builder that only exposes methods translatable to SQL — Boolean, Comparison, String (11 methods), Collection (7), Numeric (typed overloads for int/long/double/decimal/float/short + nullable), DateTime (14), DateTimeOffset (8), DateOnly (9), TimeOnly (7).- Excludes all in-memory-only methods: RegexMatch, IsEmail, IsUrl, IsPhoneNumber, IsGuid, IsJson, IsBase64, IsEven, IsOdd, IsMultipleOf, IsToday, IsYesterday, IsTomorrow, InLastDays, InNextDays, IsLeapYear, IsLastDayOfMonth, All, Any, None, AnyItem, EachItem, HasDuplicates, DistinctCount, IComparable<T> generic overloads.
- Static operators
&,|,!andCombine()for composingValiFlowQuery<T>expressions.
[1.1.0] — 2025-01-01
New Features
ValidateNested<TProperty>: validate nested objects with automatic null check.AnyItem<TValue>/EachItem<TValue>: per-element collection validation.BuildCached(): compile expression once and reuse (thread-safe).BuildWithGlobal(): combine local conditions with ambientValiFlowGlobalfilters.ValiSort<T>: fluent sort builder withBy/ThenBy, applies toIQueryableandIEnumerable.ValiFlowGlobal: static ambient filter registry (thread-safe).When/Unless: conditional condition blocks evaluated at runtime.AddIf: conditionally add conditions based on a bool flag.WithSeverity/Severityenum: mark errors as Info, Warning, Error, or Critical.ValidationResult:Warnings,CriticalErrors,ErrorsAtOrAbove(),HasAnySeverity().PropertyPathonValidationError: identify which property failed.ValidateAll: batch validation returning per-item results.Explain(): human-readable description of the built expression tree.DateTimeOffset,DateOnly,TimeOnlyexpression support.IComparable<T>generic comparison overloads (in-memory).- Cross-property
InRangecomparisons (EF Core compatible). ExpressionExplainerutility.
Bug Fixes
- Fixed
Or()state machine: flat list withisAndflag. - Fixed
BuildCached()thread safety:Volatile.Read+Interlocked.CompareExchange. - Fixed
IsValid/IsNotValidrecompilation on every call. - Fixed
NotEmptynull guard. - Fixed
Contains(string, List<selectors>)OR-logic composition. - Fixed
ValidateExpressionBodyfalse-positive for binary-zero expressions. - Fixed
RegexMatch: Regex compiled once at build time. - Fixed
string.Contains(StringComparison): EF Core compatible viaToLower(). - Fixed cross-property
InRange:Expression.Invokereplaced withParameterReplacer. - Fixed
All/Any/None/EachItem/AnyItem:Expression.Quotefor EF Core compatibility. - Fixed
Validate()thread safety: lock on lazy compile write-back. - Fixed
DateTimeOffset/DateOnlystale date capture inIsToday/IsFuture/IsPast. - Fixed
CountBetween: null guard and min/max validation. - Fixed
InRange: min <= max validation.