Migrations 0013_docs.sql + 0014_docs_triggers.sql land the docs table (JSONB body + GIN-on-jsonb_path_ops index, PK keyed on (app_id, collection, id) for cross-app isolation) and widen the triggers.kind and outbox.source_kind CHECK constraints to include 'docs', plus the docs_trigger_details detail table mirroring kv_trigger_details. picloud-shared grows the DocsService trait + DocRow/DocsListPage/ DocsError + NoopDocsService, the TriggerEvent::Docs variant with the prev_data change-data-capture surface, the DocsEventOp enum, the docs field on the Services bundle, and the SDK_VERSION bump 1.2 -> 1.3. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
40 lines
1.9 KiB
SQL
40 lines
1.9 KiB
SQL
-- v1.1.2: Documents — schemaless JSONB store with basic query semantics.
|
|
--
|
|
-- Identity tuple `(app_id, collection, id)`. `id` is a server-generated
|
|
-- UUID; scripts never supply it on create. `app_id` is first in the
|
|
-- primary key so the implicit index is always per-app — cross-app reads
|
|
-- are impossible even under a buggy query.
|
|
--
|
|
-- `data` is JSONB so scripts can store nested structures without a
|
|
-- separate serialization step. The GIN-on-`jsonb_path_ops` index
|
|
-- accelerates the v1.1.2 query DSL's equality and containment operators
|
|
-- (`docs::find` with `$eq` / `$in`); range/comparison operators rely on
|
|
-- the per-collection seq scan within the small `app_id` partition.
|
|
--
|
|
-- `created_at` / `updated_at` are server-managed: created on insert,
|
|
-- bumped on every successful update. The returned doc envelope surfaces
|
|
-- both fields to scripts for read-only access (no script-side override).
|
|
|
|
CREATE TABLE docs (
|
|
app_id UUID NOT NULL REFERENCES apps(id) ON DELETE CASCADE,
|
|
collection TEXT NOT NULL,
|
|
id UUID NOT NULL,
|
|
data JSONB NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
PRIMARY KEY (app_id, collection, id)
|
|
);
|
|
|
|
-- The dispatcher/find hot path: "all docs in app X / collection Y."
|
|
-- The PK already covers (app_id, collection) as a prefix but spelling
|
|
-- out the explicit index makes intent clear for the planner. Mirrors
|
|
-- 0007_kv.sql's idx_kv_entries_app_collection.
|
|
CREATE INDEX idx_docs_app_collection ON docs (app_id, collection);
|
|
|
|
-- GIN on JSONB with the `jsonb_path_ops` opclass: smaller index than
|
|
-- the default `jsonb_ops`, supports `@>` (containment) which is what
|
|
-- equality filters compile to under the GIN-friendly path. Range
|
|
-- operators ($gt/$gte/$lt/$lte/$ne) fall back to per-collection scans;
|
|
-- those are still bounded by the (app_id, collection) selectivity.
|
|
CREATE INDEX idx_docs_data_gin ON docs USING GIN (data jsonb_path_ops);
|