Skip to content
Open
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 docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The quick lookup surface: one line and a minimal snippet per construct. For rule
| [`entities`](/spec/entities) | tables + CRUD UI + a generated data layer & API |
| [field / relation attributes](/spec/entities#fields) | uniqueness, layout, read-only, dropdown filtering, cascades |
| [`entities.unique`](/spec/entities#unique-a-business-key-over-more-than-one-field) | a business key spanning more than one field or to-one relation |
| [`renamedFrom`](/spec/entities#renamedfrom-dropped-evolving-a-table-that-already-holds-data) | a field's former name: the stored column is renamed in place, so the values move with the new name |
| [`entities.dropped`](/spec/entities#renamedfrom-dropped-evolving-a-table-that-already-holds-data) | former field / to-one relation names whose columns are removed, data included - a field merely deleted from the file keeps its column |
| [`visibleTo`](/spec/entities#role-scoped-field-visibility-visibleto) | an allow-list of roles that may read one field, enforced on the wire |
| [`pattern`](/spec/entities#fields) | an input-format regular expression enforced in the UI and server-side |
| [`defaultValue`](/spec/entities#defaultvalue-field-defaults) | a field default: column default, satisfies `required`, and seeds a new row in the UI |
Expand Down
43 changes: 43 additions & 0 deletions docs/spec/entities.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ fields:
| `calculatedActionOnCreate` / `calculatedActionOnUpdate` | a server-side action call-out (see [Calculated fields](#calculated-fields)) |
| `number` | turn a string field into a platform-numbered document field (see [Document numbering](#document-numbering)) |
| `sensitive` | strip this field from scoped (personal / partner) surfaces (see [Scoped surfaces](/spec/surfaces)) |
| `renamedFrom` | the field's former name: applying the file renames the stored column, so the values keep up with the rename (see [renamedFrom / dropped](#renamedfrom-dropped-evolving-a-table-that-already-holds-data)) |

### Logical types

Expand All @@ -75,6 +76,7 @@ Generators map each logical type to a physical column type. `text` is a large-ob
| `imports:` | injects import lines into the generated data-access layer (pairs with calculated actions) |
| `aggregate: true` | on a document master's numeric field, keeps it equal to the sum of the items' same-named field |
| `kind: setting` | marks the entity as nomenclature / configuration (see [Setting entities](#setting-entities)) |
| `dropped:` | former field / to-one relation names whose columns applying the file removes, data included (see [renamedFrom / dropped](#renamedfrom-dropped-evolving-a-table-that-already-holds-data)) |

### Control order

Expand Down Expand Up @@ -184,6 +186,47 @@ A name repeated within one key, and a key declared twice on one entity, MUST be
An implementation is NOT required to add the constraint to a table that already exists.
:::

## renamedFrom / dropped — evolving a table that already holds data

An entity's table outlives the version of the file that created it. Once the application holds
data, renaming a field and retiring one look alike from the file alone - a name disappears and,
for a rename, another appears - so the file says which it is:

```yaml
entities:
- name: Invoice
dropped: [legacyCode]
fields:
- { name: id, type: integer, primaryKey: true, generated: true }
- { name: issueDate, type: date, renamedFrom: invoiceDate }
```

`renamedFrom:` on a field names the field it was called before. Applying the file renames the
stored column, so the existing values move with the new name instead of staying behind in the old
column while the new field starts empty. It acts only while the old column exists and the new one
does not, so it is harmless to leave in the file after the rename has run.

`dropped:` on an entity lists former field and to-one relation names whose columns applying the
file removes, data included. It is the explicit contract step of an expand/contract change: a field
is first removed from the file - its column and values are kept - and dropped once nothing reads it
any more.

A field simply deleted from the file is **not** dropped: its column and its values are kept.

::: info Normative
Applying a file MUST NOT remove the stored column, or the values, of a field or to-one relation
that the file no longer declares, unless its name is listed under the entity's `dropped:`; a name
listed there MUST have its column removed, values included. For a field declaring `renamedFrom:`,
while the column of the former name exists and the field's own does not, applying the file MUST
make the former column's values readable under the field's name; once either condition no longer
holds, `renamedFrom:` MUST have no effect.

Each of the following MUST be reported as an authoring error: a `dropped:` name or a
`renamedFrom:` source that the entity still declares as a field or a relation, compared by the
column the name maps to; a field `renamedFrom` its own name; a `renamedFrom:` source also listed
under `dropped:`; two fields `renamedFrom` the same name; and an empty name in either key.
:::

## defaultValue — field defaults

`defaultValue` states what a field holds when nobody supplies a value:
Expand Down