Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ x => !x.Archive && x.Id > minimumId)`. This returns a materialized list, quotes
identifiers, parameterizes values and uses the active migration transaction.
See [DTO queries](docs/dto-queries.md) for column mapping, supported predicates
and SQL null semantics.
Alternatively, pass an immutable typed filter such as
`Filter<ScreenDto>.Equal(x => x.Archive, false).And(Filter<ScreenDto>.GreaterThan(x => x.Id, minimumId))`.

Supported rebuilds retain mapped data, named/composite keys, declared column collations, supported indexes and triggers, and the AUTOINCREMENT high-water mark. Generated columns, `STRICT`, `WITHOUT ROWID` and indexes with explicit collations are rejected for reconstruction; hidden rowid values are not preserved. Foreign keys retain separate update/delete actions; unsupported `MATCH FULL`/`PARTIAL` requests fail explicitly. See the [SQLite preservation matrix](docs/migration-framework-comparison.md#what-survives-reconstructionand-what-is-not-guaranteed).

Expand Down
6 changes: 6 additions & 0 deletions docs/_src/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ def page(group, slug, title, summary, *sections, source="src/Migrator/Framework/
var minimumId = 10;
var screens = Database.Select<ScreenDto>(
"Common_Screens", x => !x.Archive && x.Id > minimumId);
var filter = Filter<ScreenDto>.Equal(x => x.Archive, false)
.And(Filter<ScreenDto>.GreaterThan(x => x.Id, minimumId));
var filteredScreens = Database.Select("Common_Screens", filter);
}
public override void Down() { }
}
Expand All @@ -227,6 +230,9 @@ def page(group, slug, title, summary, *sections, source="src/Migrator/Framework/
var minimumId = 10;
var screens = Context.Select<ScreenDto>(
"Common_Screens", x => !x.Archive && x.Id > minimumId);
var filter = Filter<ScreenDto>.Equal(x => x.Archive, false)
.And(Filter<ScreenDto>.GreaterThan(x => x.Id, minimumId));
var filteredScreens = Context.Select("Common_Screens", filter);
}
public override void BuildDown(MigrationBuilder migration) { }
}
Expand Down
2 changes: 1 addition & 1 deletion docs/assets/search-index.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions docs/dto-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,47 @@ unspecified; sorting after materialization is explicit client-side work.

In a `FluentMigration`, call `Context.Select<T>` for immediate reads. Reads during
`BuildUp` cannot see schema operations merely queued in that same builder.

## Explicit typed filters

Use `Filter<T>` when you prefer explicit operations to predicate translation:

```csharp
var filter = Filter<ScreenDto>.Equal(x => x.Archive, false)
.And(Filter<ScreenDto>.GreaterThan(x => x.Id, minimumId));

var screens = Database.Select("Common_Screens", filter);
// Explicit generic syntax is also supported:
var sameScreens = Database.Select<ScreenDto>("Common_Screens", filter);
```

The builder supports `Equal`, `NotEqual`, `LessThan`, `LessThanOrEqual`,
`GreaterThan`, `GreaterThanOrEqual`, `IsNull` and `IsNotNull`. Combine filters using
`And`, `Or` and `Not()`; each returns a new immutable filter, preserving grouping.
Reusing a filter does not reuse commands or parameter collections. Values are
captured when the filter is built, so later changes to local variables do not
change it.

Selectors must name a direct mapped property in its declared type. The generic
`TValue` connects selector and comparison value types; widened/boxed selectors,
casts, calculations, method calls and nested properties are rejected. Ordering
has the same type restrictions as the lambda API. `IsNull` and `IsNotNull` require
a nullable value or reference property; equality with a null reference/nullable
value also renders a SQL null check.

```csharp
public sealed class OptionalDto
{
public int? Optional { get; set; }
}

// Include NULL rows explicitly when comparing against a non-null value:
var optionalFilter = Filter<OptionalDto>.IsNull(x => x.Optional)
.Or(Filter<OptionalDto>.NotEqual(x => x.Optional, 7));
```

Both APIs share the DTO mapping, quoting, native parameter binding, SQL null
semantics, transaction and resource-lifetime behavior described above. A null
filter throws instead of selecting all rows; omit the predicate/filter argument
to select all rows. For explicit null arguments, use `predicate: null` to select
the lambda overload or `filter: null` to select the filter overload.
Loading
Loading