From 3ec9dcf2fc91386aaf6d430052a30f3f2bd2b626 Mon Sep 17 00:00:00 2001 From: Brandon Dyck Date: Tue, 6 Aug 2024 11:27:25 -0600 Subject: [PATCH] Added working notes on DB identifiers --- assets/.lua/dbidents.lua.txt | 159 +++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 assets/.lua/dbidents.lua.txt diff --git a/assets/.lua/dbidents.lua.txt b/assets/.lua/dbidents.lua.txt new file mode 100644 index 0000000..0b8b2ac --- /dev/null +++ b/assets/.lua/dbidents.lua.txt @@ -0,0 +1,159 @@ +local re = require "re" + +--[[ + Instead of describing node and field types as tuples, as in Drupal, I'll describe them in the DB schema itself. + If I have a node of type "blogpost" with fields "title" and "body", I'll store it like this: + CREATE TABLE "node:blogpost" (id INTEGER PRIMARY KEY, "title" TEXT NOT NULL, "body" TEXT NOT NULL); + + Complex fields will use a similar system. Here is a field type called "mood", and a node type that uses it called "moody blogpost". + CREATE TABLE "field:mood" (id INTEGER PRIMARY KEY, "description" TEXT NOT NULL, "intensity" INT NOT NULL); + CREATE TABLE "node:moody blogpost" ( + id INTEGER PRIMARY KEY, + "today's mood:mood" INTEGER NOT NULL REFERENCES "field:mood"(id) + ); + + Complex fields can be arbitrarily nested. + + TODO Primitive date/time types + TODO Lists + TODO Variants +]] + +-- type path = [string] + +local function path_to_tablename(path) + -- We join path segments with ':', so escape ':' to [[\:]]' and [[\]] to [[\\]]. + local pattern = [=[[:\]]=] + local escaped_path = {} + for _, segment in ipairs(path) do + local escaped_segment = segment:gsub(pattern, [[\%0]]) + table.insert(escaped_path, escaped_segment) + end + return table.concat(escaped, ':') +end + +local function tablename_to_path(path) + -- Reverse of path_to_tablename. + -- Then write a test of the property that ∀s:string, s == path_to_tablename(tablename_to_path(s)). +end + + + + + +--[[ + + +Node +Field + + +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 (( ) ...)) +variant-field-type := (variant (( ) ...)) +field-type := (field ) +node-type := (node ) +parent-object-type := | +list := (list ) + + + + +(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 ) + id integer primary key + ( ) ... +(list ) + id +(list-item ) + list-id references (list ) primary key + sequence-number primary key + item-id references (composite-value ) +(composite-value ) + id + -- This indirection is so that SQLite will prevent duplicate field type names in table names. + -value-id references (-value ) +(record-value ) + id integer primary key + ( ) ... +(variant-value ) + id integer primary key + ( ) ... + +]] \ No newline at end of file