Skip to content

Commit 8933ba9

Browse files
authored
Merge pull request #55 from constructive-io/devin/1775106651-upstream-constructive-db-changes
feat: upstream constructive-db changes to pgpm-modules
2 parents 6cce537 + 476aaa9 commit 8933ba9

20 files changed

Lines changed: 190 additions & 224 deletions

File tree

packages/inflection/deploy/schemas/inflection/tables/inflection_rules/fixtures/1589249334312_fixture.sql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ INSERT INTO inflection.inflection_rules
1313
('plural', '(child)ren$', NULL),
1414
('plural', '([ti])a$', NULL),
1515
('plural', '((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$', NULL),
16-
('plural', '(database|codebase|firebase|knowledgebase)s$', NULL),
16+
('plural', '(.+base)s$', NULL),
17+
('plural', '(database)s$', NULL),
1718
('plural', '(drive)s$', NULL),
1819
('plural', '(hi|ti)ves$', NULL),
1920
('plural', '(curve)s$', NULL),
@@ -105,7 +106,7 @@ INSERT INTO inflection.inflection_rules
105106
('singular', '^(m|wom)en$', E'\\1an'),
106107
('singular', '(pe)ople$', E'\\1rson'),
107108
('singular', '(child)ren$', E'\\1'),
108-
('singular', '(database|codebase|firebase|knowledgebase)s$', E'\\1'),
109+
('singular', '(database)s$', E'\\1'),
109110
('singular', '(drive)s$', E'\\1'),
110111
('singular', '^genera$', E'genus'),
111112
('singular', '^(criteri)a$', E'\\1on'),
@@ -115,6 +116,7 @@ INSERT INTO inflection.inflection_rules
115116
('singular', '(memorand)a$', E'\\1um'),
116117
('singular', '(curricul)a$', E'\\1um'),
117118
('singular', '([ti])a$', E'\\1um'),
119+
('singular', '(.+base)s$', E'\\1'),
118120
('singular', '((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$', E'\\1\\2sis'),
119121
('singular', '(hi|ti)ves$', E'\\1ve'),
120122
('singular', '(curve)s$', E'\\1'),

packages/metaschema-modules/__tests__/__snapshots__/modules.test.ts.snap

Lines changed: 3 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ exports[`db_meta_modules should have all expected module tables 1`] = `
99
"default_ids_module",
1010
"emails_module",
1111
"encrypted_secrets_module",
12-
"field_module",
1312
"hierarchy_module",
1413
"invites_module",
1514
"levels_module",
@@ -22,6 +21,7 @@ exports[`db_meta_modules should have all expected module tables 1`] = `
2221
"rls_module",
2322
"secrets_module",
2423
"sessions_module",
24+
"storage_module",
2525
"table_template_module",
2626
"user_auth_module",
2727
"users_module",
@@ -32,7 +32,7 @@ exports[`db_meta_modules should have all expected module tables 1`] = `
3232
exports[`db_meta_modules should verify all module tables exist in metaschema_modules_public schema 1`] = `
3333
{
3434
"moduleTablesCount": 22,
35-
"totalTables": 27,
35+
"totalTables": 28,
3636
}
3737
`;
3838

@@ -85,67 +85,6 @@ exports[`db_meta_modules should verify emails_module table structure 1`] = `
8585
}
8686
`;
8787

88-
exports[`db_meta_modules should verify field_module table structure 1`] = `
89-
{
90-
"columns": [
91-
{
92-
"column_default": "uuidv7()",
93-
"column_name": "id",
94-
"data_type": "uuid",
95-
"is_nullable": "NO",
96-
},
97-
{
98-
"column_default": null,
99-
"column_name": "database_id",
100-
"data_type": "uuid",
101-
"is_nullable": "NO",
102-
},
103-
{
104-
"column_default": "uuid_nil()",
105-
"column_name": "private_schema_id",
106-
"data_type": "uuid",
107-
"is_nullable": "NO",
108-
},
109-
{
110-
"column_default": "uuid_nil()",
111-
"column_name": "table_id",
112-
"data_type": "uuid",
113-
"is_nullable": "NO",
114-
},
115-
{
116-
"column_default": "uuid_nil()",
117-
"column_name": "field_id",
118-
"data_type": "uuid",
119-
"is_nullable": "NO",
120-
},
121-
{
122-
"column_default": null,
123-
"column_name": "node_type",
124-
"data_type": "text",
125-
"is_nullable": "NO",
126-
},
127-
{
128-
"column_default": "'{}'::jsonb",
129-
"column_name": "data",
130-
"data_type": "jsonb",
131-
"is_nullable": "NO",
132-
},
133-
{
134-
"column_default": null,
135-
"column_name": "triggers",
136-
"data_type": "ARRAY",
137-
"is_nullable": "YES",
138-
},
139-
{
140-
"column_default": null,
141-
"column_name": "functions",
142-
"data_type": "ARRAY",
143-
"is_nullable": "YES",
144-
},
145-
],
146-
}
147-
`;
148-
14988
exports[`db_meta_modules should verify module table structures have database_id foreign keys 1`] = `
15089
{
15190
"constraintCount": 64152,
@@ -154,7 +93,7 @@ exports[`db_meta_modules should verify module table structures have database_id
15493

15594
exports[`db_meta_modules should verify module tables have proper foreign key relationships 1`] = `
15695
{
157-
"constraintCount": 91658,
96+
"constraintCount": 92266,
15897
"foreignTables": [
15998
"database",
16099
"field",

packages/metaschema-modules/__tests__/modules.test.ts

Lines changed: 1 addition & 30 deletions
Large diffs are not rendered by default.

packages/metaschema-modules/deploy/schemas/metaschema_modules_public/tables/blueprint/table.sql

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,6 @@ CREATE TABLE metaschema_modules_public.blueprint (
2727
-- Lineage: where did this come from?
2828
template_id uuid DEFAULT NULL,
2929

30-
-- Execution state
31-
status text NOT NULL DEFAULT 'draft'
32-
CHECK (status IN ('draft', 'constructed', 'failed')),
33-
34-
constructed_at timestamptz,
35-
36-
error_details text,
37-
38-
-- Output: mapping of ref names to created table IDs (populated after construct)
39-
ref_map jsonb NOT NULL DEFAULT '{}',
40-
41-
-- Snapshot of the definition at construct-time (immutable record of what was actually executed)
42-
constructed_definition jsonb,
43-
4430
-- Content-addressable Merkle hashes (backend-computed via trigger)
4531
definition_hash uuid,
4632

@@ -56,7 +42,7 @@ CREATE TABLE metaschema_modules_public.blueprint (
5642
);
5743

5844
COMMENT ON TABLE metaschema_modules_public.blueprint IS
59-
'An owned, executable blueprint scoped to a specific database. Created by copying from a blueprint_template via copy_template_to_blueprint() or built from scratch. The owner can customize the definition before executing it with construct_blueprint(). Each blueprint tracks its execution status (draft/constructed/failed) and stores the ref_map of created table IDs after construction.';
45+
'An owned, editable blueprint scoped to a specific database. Created by copying from a blueprint_template via copy_template_to_blueprint() or built from scratch. The owner can customize the definition at any time. Execute it with construct_blueprint() which creates a separate blueprint_construction record to track the build.';
6046

6147
COMMENT ON COLUMN metaschema_modules_public.blueprint.id IS
6248
'Unique identifier for this blueprint.';
@@ -77,34 +63,19 @@ COMMENT ON COLUMN metaschema_modules_public.blueprint.description IS
7763
'Optional description of the blueprint.';
7864

7965
COMMENT ON COLUMN metaschema_modules_public.blueprint.definition IS
80-
'The blueprint definition as a JSONB document. Same format as blueprint_template.definition: contains tables[] (with nodes[], fields[], grants[], policies[] using $type) and relations[] (using $type). This is a mutable copy that the owner can customize before executing.';
66+
'The blueprint definition as a JSONB document. Contains tables[] (each with table_name, optional schema_name, nodes[] for data behaviors, fields[], grants[], and policies[] using $type), relations[] (using $type with source_table/target_table and optional source_schema/target_schema), indexes[] (using table_name + column), and full_text_searches[] (using table_name + field + sources[]). Everything is name-based — no UUIDs in the definition.';
8167

8268
COMMENT ON COLUMN metaschema_modules_public.blueprint.template_id IS
8369
'If this blueprint was created by copying a template, the ID of the source template. NULL if built from scratch.';
8470

85-
COMMENT ON COLUMN metaschema_modules_public.blueprint.status IS
86-
'Execution state of the blueprint. draft: not yet executed (definition can still be modified). constructed: successfully executed via construct_blueprint(). failed: execution failed (see error_details). Defaults to draft.';
87-
88-
COMMENT ON COLUMN metaschema_modules_public.blueprint.constructed_at IS
89-
'Timestamp when construct_blueprint() successfully completed. NULL until constructed.';
90-
91-
COMMENT ON COLUMN metaschema_modules_public.blueprint.error_details IS
92-
'Error message from the most recent failed construct_blueprint() attempt. NULL unless status is failed.';
93-
94-
COMMENT ON COLUMN metaschema_modules_public.blueprint.ref_map IS
95-
'Mapping of ref names to created table UUIDs, populated by construct_blueprint() after successful execution. Format: {"products": "uuid", "categories": "uuid", ...}. Defaults to empty object.';
96-
97-
COMMENT ON COLUMN metaschema_modules_public.blueprint.constructed_definition IS
98-
'Immutable snapshot of the definition at construct-time. Preserved so the exact definition that was executed is recorded even if the user later modifies the definition for re-execution. NULL until constructed.';
99-
10071
COMMENT ON COLUMN metaschema_modules_public.blueprint.created_at IS
10172
'Timestamp when this blueprint was created.';
10273

10374
COMMENT ON COLUMN metaschema_modules_public.blueprint.definition_hash IS
10475
'UUIDv5 Merkle root hash of the definition. Computed automatically via trigger from the ordered table_hashes. Used for content-addressable deduplication and provenance tracking. Backend-computed — clients should never set this directly.';
10576

10677
COMMENT ON COLUMN metaschema_modules_public.blueprint.table_hashes IS
107-
'JSONB map of table ref names to their individual UUIDv5 content hashes. Each table hash is computed from the canonical jsonb::text of the table entry. Enables structural comparison at the table level across blueprints and templates. Backend-computed via trigger.';
78+
'JSONB map of table names to their individual UUIDv5 content hashes. Each table hash is computed from the canonical jsonb::text of the table entry. Enables structural comparison at the table level across blueprints and templates. Backend-computed via trigger.';
10879

10980
COMMENT ON COLUMN metaschema_modules_public.blueprint.updated_at IS
11081
'Timestamp when this blueprint was last modified.';
@@ -113,7 +84,6 @@ COMMENT ON COLUMN metaschema_modules_public.blueprint.updated_at IS
11384
CREATE INDEX blueprint_owner_id_idx ON metaschema_modules_public.blueprint (owner_id);
11485
CREATE INDEX blueprint_database_id_idx ON metaschema_modules_public.blueprint (database_id);
11586
CREATE INDEX blueprint_template_id_idx ON metaschema_modules_public.blueprint (template_id);
116-
CREATE INDEX blueprint_status_idx ON metaschema_modules_public.blueprint (status);
11787
CREATE INDEX blueprint_definition_hash_idx ON metaschema_modules_public.blueprint (definition_hash);
11888

11989
COMMIT;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
-- Deploy schemas/metaschema_modules_public/tables/blueprint_construction/table to pg
2+
3+
-- requires: schemas/metaschema_modules_public/schema
4+
-- requires: schemas/metaschema_modules_public/tables/blueprint/table
5+
6+
BEGIN;
7+
8+
CREATE TABLE metaschema_modules_public.blueprint_construction (
9+
id uuid PRIMARY KEY DEFAULT uuidv7(),
10+
11+
-- What was constructed
12+
blueprint_id uuid NOT NULL,
13+
14+
database_id uuid NOT NULL,
15+
16+
-- The schema used as the default for tables without an explicit schema_name
17+
schema_id uuid,
18+
19+
-- Execution state
20+
status text NOT NULL DEFAULT 'pending'
21+
CHECK (status IN ('pending', 'constructing', 'constructed', 'failed')),
22+
23+
error_details text,
24+
25+
-- Output: mapping of table names to created table IDs (populated after construct)
26+
table_map jsonb NOT NULL DEFAULT '{}',
27+
28+
-- Snapshot of the definition at construct-time (immutable record of what was actually executed)
29+
constructed_definition jsonb,
30+
31+
constructed_at timestamptz,
32+
33+
created_at timestamptz NOT NULL DEFAULT now(),
34+
35+
updated_at timestamptz NOT NULL DEFAULT now(),
36+
37+
CONSTRAINT blueprint_construction_blueprint_fkey
38+
FOREIGN KEY (blueprint_id) REFERENCES metaschema_modules_public.blueprint(id) ON DELETE CASCADE,
39+
CONSTRAINT blueprint_construction_db_fkey
40+
FOREIGN KEY (database_id) REFERENCES metaschema_public.database(id) ON DELETE CASCADE
41+
);
42+
43+
COMMENT ON TABLE metaschema_modules_public.blueprint_construction IS
44+
'Tracks individual construction attempts of a blueprint. Each time construct_blueprint() is called, a new record is created here. This separates the editable blueprint definition from its build history, allowing blueprints to be re-executed, constructed into multiple databases, and maintain an audit trail of all construction attempts.';
45+
46+
COMMENT ON COLUMN metaschema_modules_public.blueprint_construction.id IS
47+
'Unique identifier for this construction attempt.';
48+
49+
COMMENT ON COLUMN metaschema_modules_public.blueprint_construction.blueprint_id IS
50+
'The blueprint that was constructed.';
51+
52+
COMMENT ON COLUMN metaschema_modules_public.blueprint_construction.database_id IS
53+
'The database the blueprint was constructed into.';
54+
55+
COMMENT ON COLUMN metaschema_modules_public.blueprint_construction.schema_id IS
56+
'The default schema used for tables that did not specify an explicit schema_name. NULL if not yet resolved.';
57+
58+
COMMENT ON COLUMN metaschema_modules_public.blueprint_construction.status IS
59+
'Execution state of this construction attempt. pending: created but not yet started. constructing: currently executing. constructed: successfully completed. failed: execution failed (see error_details).';
60+
61+
COMMENT ON COLUMN metaschema_modules_public.blueprint_construction.error_details IS
62+
'Error message from a failed construction attempt. NULL unless status is failed.';
63+
64+
COMMENT ON COLUMN metaschema_modules_public.blueprint_construction.table_map IS
65+
'Mapping of table names to created table UUIDs, populated after successful construction. Format: {"products": "uuid", "categories": "uuid", ...}. Defaults to empty object.';
66+
67+
COMMENT ON COLUMN metaschema_modules_public.blueprint_construction.constructed_definition IS
68+
'Immutable snapshot of the definition at construct-time. Preserved so the exact definition that was executed is recorded even if the user later modifies the blueprint definition.';
69+
70+
COMMENT ON COLUMN metaschema_modules_public.blueprint_construction.constructed_at IS
71+
'Timestamp when construction successfully completed. NULL until constructed.';
72+
73+
COMMENT ON COLUMN metaschema_modules_public.blueprint_construction.created_at IS
74+
'Timestamp when this construction attempt was created.';
75+
76+
COMMENT ON COLUMN metaschema_modules_public.blueprint_construction.updated_at IS
77+
'Timestamp when this construction attempt was last modified.';
78+
79+
80+
CREATE INDEX blueprint_construction_blueprint_id_idx ON metaschema_modules_public.blueprint_construction (blueprint_id);
81+
CREATE INDEX blueprint_construction_database_id_idx ON metaschema_modules_public.blueprint_construction (database_id);
82+
CREATE INDEX blueprint_construction_status_idx ON metaschema_modules_public.blueprint_construction (status);
83+
84+
COMMIT;

packages/metaschema-modules/deploy/schemas/metaschema_modules_public/tables/field_module/table.sql

Lines changed: 0 additions & 39 deletions
This file was deleted.

packages/metaschema-modules/deploy/schemas/metaschema_modules_public/tables/relation_provision/table.sql

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,10 @@ CREATE TABLE metaschema_modules_public.relation_provision (
6666
expose_in_api boolean NOT NULL DEFAULT true,
6767

6868
-- =========================================================================
69-
-- ManyToMany: field creation (forwarded to secure_table_provision)
69+
-- ManyToMany: field creation (forwarded to provision_table)
7070
-- =========================================================================
7171

72-
node_type text DEFAULT NULL,
73-
74-
node_data jsonb NOT NULL DEFAULT '{}',
72+
nodes jsonb NOT NULL DEFAULT '[]',
7573

7674
-- =========================================================================
7775
-- ManyToMany: grants (forwarded to secure_table_provision)
@@ -139,7 +137,7 @@ COMMENT ON COLUMN metaschema_modules_public.relation_provision.database_id IS
139137
'The database this relation belongs to. Required. Must match the database of both source_table_id and target_table_id.';
140138

141139
COMMENT ON COLUMN metaschema_modules_public.relation_provision.relation_type IS
142-
'The type of relation to create. Uses SuperCase naming matching the node_type_registry:
140+
'The type of relation to create. Uses SuperCase naming:
143141
- RelationBelongsTo: creates a FK field on source_table referencing target_table (e.g., tasks belongs to projects -> tasks.project_id). Field name auto-derived from target table.
144142
- RelationHasMany: creates a FK field on target_table referencing source_table (e.g., projects has many tasks -> tasks.project_id). Field name auto-derived from source table. Inverse of BelongsTo — same FK, different perspective.
145143
- RelationHasOne: creates a FK field + unique constraint on source_table referencing target_table (e.g., user_settings has one user -> user_settings.user_id with UNIQUE). Also supports shared-primary-key patterns (e.g., user_profiles.id = users.id) by setting field_name to the existing PK field.
@@ -246,20 +244,11 @@ COMMENT ON COLUMN metaschema_modules_public.relation_provision.expose_in_api IS
246244
-- ManyToMany: field creation (forwarded to secure_table_provision)
247245
-- =============================================================================
248246

249-
COMMENT ON COLUMN metaschema_modules_public.relation_provision.node_type IS
250-
'For RelationManyToMany: which generator to invoke for field creation on the junction table. Forwarded to secure_table_provision as-is. The trigger does not interpret or validate this value.
251-
Examples: DataId (creates UUID primary key), DataDirectOwner (creates owner_id field), DataEntityMembership (creates entity_id field), DataOwnershipInEntity (creates both owner_id and entity_id), DataTimestamps, DataPeoplestamps, DataPublishable, DataSoftDelete.
252-
NULL means no field creation beyond the FK fields (and composite key if use_composite_key is true).
253-
Ignored for RelationBelongsTo/RelationHasOne.';
254-
255-
COMMENT ON COLUMN metaschema_modules_public.relation_provision.node_data IS
256-
'For RelationManyToMany: configuration passed to the generator function for field creation on the junction table. Forwarded to secure_table_provision as-is. The trigger does not interpret or validate this value.
257-
Only used when node_type is set. Structure varies by node_type. Examples:
258-
- DataId: {"field_name": "id"} (default field name is ''id'')
259-
- DataEntityMembership: {"entity_field_name": "entity_id", "include_id": false, "include_user_fk": true}
260-
- DataDirectOwner: {"owner_field_name": "owner_id"}
261-
Defaults to ''{}'' (empty object).
262-
Ignored for RelationBelongsTo/RelationHasOne.';
247+
COMMENT ON COLUMN metaschema_modules_public.relation_provision.nodes IS
248+
'For RelationManyToMany: array of node objects to apply to the junction table. Each element is a jsonb object with a required "$type" key and an optional "data" key. Forwarded to provision_table as-is. The trigger does not interpret or validate this value.
249+
Examples: [{"$type": "DataId"}, {"$type": "DataTimestamps"}, {"$type": "DataDirectOwner", "data": {"owner_field_name": "author_id"}}].
250+
Defaults to ''[]'' (no node processing beyond the FK fields and composite key if use_composite_key is true).
251+
Ignored for RelationBelongsTo/RelationHasOne/RelationHasMany.';
263252

264253
-- =============================================================================
265254
-- ManyToMany: grants (forwarded to secure_table_provision)

0 commit comments

Comments
 (0)