Formbase 0.13.0
Pairs with MorphDB 0.13.x, 0.13.1 or later. Record queries grow from equality to ranges, text
matching and empty-column tests, and the engine counts records per group. Formbase.Sqlite is new: the
whole engine's storage in one SQLite file, for a process with no database server. One breaking change
for code: QuerySpec.Filters is a list of FieldFilter (FieldFilter.Equal(column, value) is the old
entry), and an IProjectionStore adapter implements AggregateAsync. On the MorphDB store, a filter for
records whose column is empty used to miss them.
Added
- Record queries filter with ranges and text matching, not only equality. A
FieldFilternames a
column, an operator and a value:Equalon any column;GreaterThan,GreaterThanOrEqual,
LessThanandLessThanOrEqualon integer, decimal and timestamp columns;Containsand
StartsWith, ignoring case, on text columns;IsNullandIsNotNull(FieldFilter.IsNull(column)),
which take no value, on any column — "the records whose judgement is still blank". Filters all apply, and values are coerced to the
column's declared type as equality values already were, so a date range can be written as text. An
operator the column's type does not answer, a range or text match against null, or a value given to
IsNull/IsNotNull, is refused with
InvalidQueryException(its newInapplicableFiltersnames them) rather than answered with no rows.
Text ranges are left out on purpose: backends order text differently, and the same query must return
the same rows whichever store answers it. Formbase.Sqlite: the raw store, projection store, projection state and field hints in one SQLite
file (AddSqliteRawStoreandAddSqliteProjectionover one connection string — two different files
are refused), for a process with no database server. Raw watermarks are never reused, so a restarted
process finds its documents and its projections current. It passes the same contract tests as
the in-memory and MorphDB stores: decimals compare numerically (kept as exact text under a numeric
collation), instants compare as instants whatever their offset, and text matching ignores case beyond
ASCII. Declared relations are not materialized.FormbaseEngine.AggregateAsynccounts projected records, optionally per group (AggregateSpec:
GroupBycolumns and the same filters). Groups come back ordered by their keys, nulls first, with key
values as the declared column type, and the answer carriesStaleand refuses exactly as a query
does. Ungrouped, it is one count — zero when nothing matches.
Changed
- Breaking:
QuerySpec.Filtersis a list ofFieldFilterinstead of a column-to-value dictionary;
FieldFilter.Equal(column, value)is the old entry.IProjectionStoregainsAggregateAsync, which
an adapter implements by counting rows per group; the in-memory and MorphDB stores do, and both pass
the same contract tests. The HTTP record endpoint still takes equality filters only. Formbase.M3Ldepends onM3L.Native0.17.0 (was 0.15.0), which targets .NET 10 like Formbase. The
parsed declarations it reads are unchanged.
Fixed
- On the MorphDB store, an equality filter with a null value — "the records whose column is empty" —
was sent as a comparison with an empty string and missed the empty records. It is now sent as
MorphDB'sisnull, which needs MorphDB0.13.1or later; the in-memory store always answered it. - The compose bundle's PostgreSQL health check asks over TCP. Asked over the Unix socket, it reported
the database healthy while the image was still running its init scripts on a socket-only server
that restarts afterwards, so on a firstdocker compose upMorphDB could start against a server
that was about to go away.