3.7 KiB
3.7 KiB
The website schema needs to be discoverable. The sqlite_schema
table (or the table_list
pragma) and the table_info
pragma are essential.
The following facts need to be discoverable:
- The name of each node type.
- The fields in each node type.
- The type of each field in a node.
- The subfields in each field type.
- The type of each subfield in a field.
- Whether a field or subfield is repeated, optional, or single.
- Whether a field has an application-primitive, but non-sqlite-primitive, type, such as datetime.
- Discriminated union fields.
Field types need to be acyclic. Do they really?
Field values need to be deleted when the node that contains them is deleted.
If field types are namespaced to a node type, then SQLite schema object naming will get harder. Maybe just let them be shared.
(node blogpost)
(composite-field car)
(node "car review")
(field cars)
(field car)
node:blogpost
field:
(: road-review node)
(: car composite-field)
-- Entity names must be qualified by their type/kind, or there can't be e.g. a node type and field type that share a name.
-- I think qualification is best, because then SQLite will prevent duplicates by the requirement that table names be unique.
(list (: car composite-field))
create table "car:composite-field" (
id integer primary key,
"Make" text not null,
"Model" text not null,
"Year" text not null,
"Test distance" int not null,
"Test date:date" text not null,
);
create table "road review.cars:(list-field (road review:node))" (
"Road review:node" int primary key references "road review:node",
"Car:composite-field" int primary key references "car:composite-field",
);
create table "Road review:node" (
id integer primary key,
"Title" text not null,
"Cars:(list car)"
);
(field car)
(node review)
(list (field car) (node review)) -- If we parameterize each list relation by both the listed field and the containing node or field, then we've basically monomorphized it.
-- However, that won't cut it if a node or field contains multiple lists of the same type. We also need to parameterize list relations by the field name in the containing node or field.
primitive-field-type := int | text | date |
record-field-type := (record <field-type-name> ((<field-name> <field-type>) ...))
variant-field-type := (variant <field-type-name> ((<field-name> <field-type>) ...))
field-type := (field <field-type-name>)
node-type := (node <node-type-name>)
parent-object-type := <field-type> | <node-type>
list := (list <element-type> <parent-object-type> <field-name>)
(record car)
(id integer)
(make text)
(model text)
(year text)
(test-distance integer)
(test-date date)
(list car)
(node road-review)
(car car)
(node road-review)
(id integer)
(title text)
(cars (list car))
(node <node-type-name>)
id integer primary key
(<composite-type-name> <field-name>) <db-type> ...
(list <composite-type-name>)
id
(list-item <composite-type-name>)
list-id references (list <composite-type-name>) primary key
sequence-number primary key
item-id references (composite-value <composite-type-name>)
(composite-value <composite-type-name>)
id
-- This indirection is so that SQLite will prevent duplicate field type names in table names.
<record|variant>-value-id references (<record|variant>-value <composite-type-name>)
(record-value <composite-type-name>)
id integer primary key
(<composite-type-name> <field-name>) integer references (composite-value <composite-type-name>) ...
(primitive <primitive-type-name> <field-name>) <primitive-type-impl-name> ...
(variant-value <composite-type-name>)
id integer primary key
(<composite-type-name> <field-name>) integer references (composite-value <composite-type-name>) ...
(primitive <primitive-type-name> <field-name>) <primitive-type-impl-name> ...