Skip to content

Formbase 0.13.0

Choose a tag to compare

@github-actions github-actions released this 28 Sep 13:52
· 41 commits to main since this release

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 FieldFilter names a
    column, an operator and a value: Equal on any column; GreaterThan, GreaterThanOrEqual,
    LessThan and LessThanOrEqual on integer, decimal and timestamp columns; Contains and
    StartsWith, ignoring case, on text columns; IsNull and IsNotNull (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 new InapplicableFilters names 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 (AddSqliteRawStore and AddSqliteProjection over 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.AggregateAsync counts projected records, optionally per group (AggregateSpec:
    GroupBy columns and the same filters). Groups come back ordered by their keys, nulls first, with key
    values as the declared column type, and the answer carries Stale and refuses exactly as a query
    does. Ungrouped, it is one count — zero when nothing matches.

Changed

  • Breaking: QuerySpec.Filters is a list of FieldFilter instead of a column-to-value dictionary;
    FieldFilter.Equal(column, value) is the old entry. IProjectionStore gains AggregateAsync, 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.M3L depends on M3L.Native 0.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's isnull, which needs MorphDB 0.13.1 or 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 first docker compose up MorphDB could start against a server
    that was about to go away.