Formbase 0.17.0
Pairs with MorphDB 0.14.x. A projection whose declaration has not changed reads only the documents
appended since its last run, with the result a rebuild would have, and a bound field names its value
column and, optionally, which record its value belongs to. Breaking for code that constructs or reads
EntityRef, for HTTP clients that send or read a bound field's target, and for implementers of
IProjectionStore and IProjectionState, which gain a member each.
Changed
- A bound field's target names its value column as
ValueField, notKeyField. The old name read
as a lookup key, and declarations were written that way —KeyFieldwas always the column the value
comes from.EntityRef(entity, valueField, lookupKey, viaField); on the wire,target.valueField
replacestarget.keyField. Declarations already stored by an earlier release read back unchanged.
RelationHint.KeyField(a relation's link field) is unaffected.
Added
- A bound field can say which record its value belongs to.
EntityRef.LookupKey(the field on the
target that identifies a record) andEntityRef.ViaField(the field of this declaration carrying that
key) — optional, and only as a pair. On the wire,target.lookupKeyandtarget.viaField. - A target naming a field that does not exist is refused. Every declaration writer (in-memory,
SQLite, PostgreSQL) refuses aViaFieldthat is not a field of the same declaration, and a
ValueFieldorLookupKeythat is not a field of the target form type when that form type is
declared (DeclaredTargets); the host answers400/problems/invalid-declaration. An undeclared
target is accepted unchecked. - A projection brings its table forward instead of rebuilding it when only documents were appended.
When the declaration, table and recorded state are unchanged since the last projection, a run reads
only the documents appended since its watermark: rows of records they correct or retire are removed,
their own rows inserted, and the recorded skips updated in place. The table andGET …/projection/skipsare what a rebuild would have produced; the cost of a run follows what was
appended, not the size of the raw stream. A first run, a changed declaration or table, a table left
in doubt by a failed run, and the first run after upgrading still rebuild.ProjectionResult.Mode
(andmodeonPOST …/projection:rebuildorincremental) says which happened; on an
incremental run the run's counts and skip lists cover the documents it read. IProjectionStore.ReplaceRowsAsync(remove rows by record key or document, then insert — idempotent)
andIProjectionState.ApplyProjectedDeltaAsync(compare-and-set on the recorded watermark, withdraw
skips by record or document, append new ones).ProjectionSkip.KeyandProjectionFieldSkip.Key
name the record a skipped document stood for;ProjectionStamp.SkipsKeyedsays whether they do.
SQLite and PostgreSQL state stores add the columns on first use.
Fixed
- Two projections of one form type started at once in one process no longer race: they run one after
the other. A run that finds the recorded projection moved under it marks it unverified, so the next
run rebuilds rather than serving a table both runs wrote to.