mirror: update implementation notes for EAV tables (#1345)
Summary: The notes used to focus on the legacy implementation with a minor note about the EAV implementation; this change flips that relationship. Test Plan: None. wchargin-branch: mirror-eav-impl-notes
This commit is contained in:
parent
809fd23def
commit
0380088af2
|
@ -111,11 +111,9 @@ export class Mirror {
|
||||||
* ---
|
* ---
|
||||||
*
|
*
|
||||||
* Objects have three kinds of fields: connections, links, and
|
* Objects have three kinds of fields: connections, links, and
|
||||||
* primitives (plus an ID, which we ignore for now). The database has
|
* primitives. The database likewise has a `connections` table,
|
||||||
* a single `connections` table for all objects, and also a single
|
* `links` table, and `primitives` table, each storing corresponding
|
||||||
* `links` table for all objects. For primitives, each GraphQL data
|
* data for all GraphQL object types.
|
||||||
* type has its own table, and each object of that type has a row in
|
|
||||||
* the corresponding table.
|
|
||||||
*
|
*
|
||||||
* In more detail:
|
* In more detail:
|
||||||
*
|
*
|
||||||
|
@ -131,23 +129,24 @@ export class Mirror {
|
||||||
* where `fieldname` is the name of a link field on the object
|
* where `fieldname` is the name of a link field on the object
|
||||||
* with the given ID. This simply points to the referenced object.
|
* with the given ID. This simply points to the referenced object.
|
||||||
*
|
*
|
||||||
* - For each type `T`, the `primitives_T` table has one row for
|
* - The `primitives` table has a row for each `(id, fieldname)`
|
||||||
* each object of type `T`, storing the primitive data of the
|
* pair, where `fieldname` is the name of a (non-ID) primitive
|
||||||
* object.
|
* field on the object with the given ID. The `value` column holds
|
||||||
|
* the JSON-stringified primitive value: so, for instance, the
|
||||||
|
* JSON value `null` is represented as the SQL string 'null',
|
||||||
|
* _not_ SQL NULL, while the JSON string "null" is represented as
|
||||||
|
* the SQL string '"null"'. This is primarily to accommodate
|
||||||
|
* storing booleans: SQLite has no boolean storage class, and we
|
||||||
|
* cannot simply encode `true` and `false` as `1` and `0` because
|
||||||
|
* we need to be able to distinguish between these respective
|
||||||
|
* values when we read them back out. There are other ways to do
|
||||||
|
* this more efficiently in both space and time (see discussion on
|
||||||
|
* #883 for some options).
|
||||||
*
|
*
|
||||||
* All values are stored as stringified JSON values: so, for
|
* NOTE: A previous version of the schema used a separate
|
||||||
* instance, the JSON value `null` is represented as the SQL
|
* primitives table for each GraphQL object type. These
|
||||||
* string 'null', _not_ SQL NULL, while the JSON string "null" is
|
* `primitives_*` tables are still written, but are no longer read
|
||||||
* represented as the SQL string '"null"'. This is primarily to
|
* by default. They will be removed entirely in a future change.
|
||||||
* accommodate storing booleans: SQLite encodes `true` and `false`
|
|
||||||
* as `1` and `0`, but we need to be able to distinguish between
|
|
||||||
* these respective values. There are other ways to do this more
|
|
||||||
* efficiently in both space and time (see discussion on #883 for
|
|
||||||
* some options).
|
|
||||||
*
|
|
||||||
* NOTE: A migration is underway to switch from type-specific
|
|
||||||
* primitive tables to a single entity-attribute-value table
|
|
||||||
* storing primitives for all types. See issue #1313 for details.
|
|
||||||
*
|
*
|
||||||
* We refer to node and primitive data together as "own data", because
|
* We refer to node and primitive data together as "own data", because
|
||||||
* this is the data that can be queried uniformly for all elements of
|
* this is the data that can be queried uniformly for all elements of
|
||||||
|
@ -155,19 +154,20 @@ export class Mirror {
|
||||||
* object-specific end cursor.
|
* object-specific end cursor.
|
||||||
*
|
*
|
||||||
* Nested fields merit additional explanation. The nested field itself
|
* Nested fields merit additional explanation. The nested field itself
|
||||||
* exists on the primitives table with SQL value either NULL, 0, or 1
|
* exists on the `primitives` table with SQL value NULL, 0, or 1 (as
|
||||||
* (as SQL integers, not strings). As with all other primitives,
|
* SQL integers, not strings). As with all other primitives, `NULL`
|
||||||
* `NULL` indicates that the value has never been fetched. If the
|
* indicates that the value has never been fetched. If the value has
|
||||||
* value has been fetched, it is 0 if the nested field itself was
|
* been fetched, it is 0 if the nested field itself was `null` on the
|
||||||
* `null` on the GraphQL result, or 1 if it was present. This field
|
* GraphQL result, or 1 if it was present. This field lets us
|
||||||
* lets us distinguish "author: null" from "author: {user: null}".
|
* distinguish "author: null" from "author: {user: null}".
|
||||||
*
|
*
|
||||||
* The "eggs" of a nested field are treated as normal primitive or
|
* The "eggs" of a nested field are treated as normal primitive or
|
||||||
* link values, whose fieldname is the nested fieldname and egg
|
* link values, whose fieldname is the nested fieldname and egg
|
||||||
* fieldname joined by a period. So, if object type `Foo` has nested
|
* fieldname joined by a period. So, if object type `Foo` has nested
|
||||||
* field `bar: Schema.nested({baz: Schema.primitive()})`, then the
|
* field `bar: Schema.nested({baz: Schema.primitive()})`, then the
|
||||||
* `primitives_Foo` table will include a column "bar.baz". Likewise, a
|
* `primitives` table will include a row with fieldname 'bar.baz'.
|
||||||
* row in the `links` table might have fieldname 'quux.zod'.
|
* Likewise, a row in the `links` table might have fieldname
|
||||||
|
* 'quux.zod'.
|
||||||
*
|
*
|
||||||
* All aforementioned tables are keyed by object ID. Each object also
|
* All aforementioned tables are keyed by object ID. Each object also
|
||||||
* appears once in the `objects` table, which relates its ID,
|
* appears once in the `objects` table, which relates its ID,
|
||||||
|
@ -176,12 +176,11 @@ export class Mirror {
|
||||||
* of each other and of own-data.
|
* of each other and of own-data.
|
||||||
*
|
*
|
||||||
* Note that any object in the database should have entries in the
|
* Note that any object in the database should have entries in the
|
||||||
* `connections` and `links` table for all relevant fields, as well as
|
* `connections`, `links`, and `primitives` tables for all relevant
|
||||||
* an entry in the relevant primitives table, even if the node has
|
* fields, even if the node has never been updated. This is for
|
||||||
* never been updated. This is for convenience of implementation: it
|
* convenience of implementation: it means that the first fetch for a
|
||||||
* means that the first fetch for a node is the same as subsequent
|
* node is the same as subsequent fetches (a simple SQL `UPDATE`
|
||||||
* fetches (a SQL `UPDATE` instead of first requiring an existence
|
* instead of first requiring an existence check).
|
||||||
* check).
|
|
||||||
*
|
*
|
||||||
* Finally, a table `meta` is used to store metadata about the mirror
|
* Finally, a table `meta` is used to store metadata about the mirror
|
||||||
* itself. This is used to make sure that the mirror is not loaded
|
* itself. This is used to make sure that the mirror is not loaded
|
||||||
|
|
Loading…
Reference in New Issue