@snolla/data 0.0.0-stage → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/actor.d.ts +28 -0
  2. package/dist/actor.js +63 -0
  3. package/dist/audit.d.ts +36 -0
  4. package/dist/audit.js +198 -0
  5. package/dist/dataProvider.d.ts +41 -0
  6. package/dist/dataProvider.js +148 -0
  7. package/dist/dataSource.d.ts +4 -0
  8. package/dist/dataSource.js +65 -0
  9. package/dist/dbProvider.d.ts +1261 -0
  10. package/dist/dbProvider.js +1898 -0
  11. package/dist/freeze.d.ts +29 -0
  12. package/dist/freeze.js +69 -0
  13. package/dist/guard.d.ts +53 -0
  14. package/dist/guard.js +397 -0
  15. package/dist/insert.d.ts +9 -0
  16. package/dist/insert.js +44 -0
  17. package/dist/migrations/siteid.d.mts +738 -0
  18. package/dist/migrations/siteid.mjs +512 -0
  19. package/dist/publish.d.ts +1 -0
  20. package/dist/publish.js +1 -0
  21. package/dist/schema/dsl.d.ts +64 -0
  22. package/dist/schema/dsl.js +28 -0
  23. package/dist/schema/generate.d.mts +14 -0
  24. package/dist/schema/generate.mjs +282 -0
  25. package/dist/schema/generated/ddl.d.ts +7 -0
  26. package/dist/schema/generated/ddl.js +11 -0
  27. package/dist/schema/generated/kysely-types.d.ts +1988 -0
  28. package/dist/schema/generated/kysely-types.js +5 -0
  29. package/dist/schema/index.d.ts +2 -0
  30. package/dist/schema/index.js +7 -0
  31. package/dist/schema/provision.d.mts +11 -0
  32. package/dist/schema/provision.mjs +111 -0
  33. package/dist/schema/tables.d.ts +2 -0
  34. package/dist/schema/tables.js +3301 -0
  35. package/dist/scripts/canon-audit.d.mts +25 -0
  36. package/dist/scripts/canon-audit.mjs +213 -0
  37. package/dist/scripts/canon-smoke.d.mts +1 -0
  38. package/dist/scripts/canon-smoke.mjs +44 -0
  39. package/dist/scripts/dialect-ddl-stand.d.mts +1 -0
  40. package/dist/scripts/dialect-ddl-stand.mjs +136 -0
  41. package/dist/scripts/owner-spec-check.d.mts +1 -0
  42. package/dist/scripts/owner-spec-check.mjs +166 -0
  43. package/dist/scripts/owners/owner-resolve-spec.json +540 -0
  44. package/dist/scripts/owners-audit.d.mts +60 -0
  45. package/dist/scripts/owners-audit.mjs +443 -0
  46. package/dist/scripts/owners-fixture.d.mts +20 -0
  47. package/dist/scripts/owners-fixture.mjs +192 -0
  48. package/dist/scripts/schema-lengths-audit.d.mts +22 -0
  49. package/dist/scripts/schema-lengths-audit.mjs +146 -0
  50. package/dist/scripts/siteid-migrate.d.mts +7 -0
  51. package/dist/scripts/siteid-migrate.mjs +260 -0
  52. package/dist/scripts/tenant-invariant-audit.d.mts +1 -0
  53. package/dist/scripts/tenant-invariant-audit.mjs +34 -0
  54. package/dist/singleMode.d.ts +5 -0
  55. package/dist/singleMode.js +23 -0
  56. package/dist/sqliteDialect.d.ts +6 -0
  57. package/dist/sqliteDialect.js +92 -0
  58. package/dist/templateDefs.d.ts +38 -0
  59. package/dist/templateDefs.js +163 -0
  60. package/dist/test/fixtures/broken-driver/index.d.ts +3 -0
  61. package/dist/test/fixtures/broken-driver/index.js +5 -0
  62. package/dist/test/support/dialect-stand.d.ts +37 -0
  63. package/dist/test/support/dialect-stand.js +162 -0
  64. package/dist/test/support/render-parity.d.ts +44 -0
  65. package/dist/test/support/render-parity.js +262 -0
  66. package/package.json +50 -5
  67. package/README.md +0 -3
@@ -0,0 +1,5 @@
1
+ // GENERATED from the canonical schema — do not edit; run schema/generate.mjs
2
+ //
3
+ // Row types for Kysely plus the `Database` interface. Decimals and datetimes
4
+ // are strings (exactness first, plan:49 Q4); optional columns admit null.
5
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './dsl.ts';
2
+ export { canonicalSchema } from './tables.ts';
@@ -0,0 +1,7 @@
1
+ // Public entry point of the canonical schema (task:3812).
2
+ //
3
+ // Consumers: the code generators (task:3820 — Kysely types, per-dialect DDL,
4
+ // Prisma bridge), the access-layer guard (task:3813) and the site transfer tool
5
+ // (task:3825). Import from here, never reach into `tables.ts` directly.
6
+ export * from "./dsl.js";
7
+ export { canonicalSchema } from "./tables.js";
@@ -0,0 +1,11 @@
1
+ export const CANON_TABLES: string[];
2
+ export function canonTablesIn(db: any, dialect: any): Promise<string[]>;
3
+ export function applyCanonDdl({ db, dialect, force }: {
4
+ db: import("kysely").Kysely<any>;
5
+ dialect: "postgres" | "mariadb" | "sqlite" | "mssql";
6
+ force?: boolean;
7
+ }): Promise<{
8
+ dialect: "postgres" | "mariadb" | "sqlite" | "mssql";
9
+ created: string[];
10
+ existing: string[];
11
+ }>;
@@ -0,0 +1,111 @@
1
+ // Canon DDL into an empty cell (task:4001, the tail of the cutover rehearsal
2
+ // [[concepts/cutover-rehearsal-live]]).
3
+ //
4
+ // Provisioning a cell is two commands: this one lays the schema, `site import
5
+ // --provision` adds the control rows a bundle cannot carry. Step one used to be a
6
+ // script somebody ran by hand (`renderDdlSql` + `psql -f`); when they forgot, the
7
+ // import died on `relation "Accounts" does not exist`.
8
+ //
9
+ // The DDL is the *generated* one — the same text the stands and the tests execute —
10
+ // so there is no second generator, and the catalog is asked what it already holds
11
+ // instead of assuming. Three outcomes, no fourth:
12
+ //
13
+ // empty database → every canon table is created;
14
+ // fully provisioned → nothing is executed and the report says so (idempotent);
15
+ // anything else → refused before the first statement, unless `force` says
16
+ // "top up": then only the missing tables are created and the
17
+ // tables that were already there are left exactly as they are.
18
+ //
19
+ // Statements are grouped by the table they belong to (`create table T`, `create
20
+ // index … on T`, `alter table T …`), which is how a top-up skips a table without
21
+ // the generator having to emit per-table pieces.
22
+ import { sql } from 'kysely';
23
+ import { renderDdlSql } from './generate.mjs';
24
+ import { canonicalSchema } from "./index.js";
25
+ export const CANON_TABLES = canonicalSchema.tables.map((table) => table.name);
26
+ /** Each dialect's own catalog — one query, one column, no driver-specific API. */
27
+ const CATALOG = {
28
+ postgres: 'select table_name as name from information_schema.tables where table_schema = current_schema()',
29
+ mariadb: 'select table_name as name from information_schema.tables where table_schema = database()',
30
+ mssql: "select table_name as name from information_schema.tables where table_type = 'BASE TABLE'",
31
+ sqlite: "select name from sqlite_master where type = 'table'",
32
+ };
33
+ /** Every table the database holds, canon or not, compared by lowercase name. */
34
+ const tableNames = async (db, dialect) => {
35
+ const query = CATALOG[dialect];
36
+ if (!query)
37
+ throw new Error(`canon-provision: unsupported dialect "${dialect}" (${Object.keys(CATALOG).join(', ')})`);
38
+ const { rows } = await sql.raw(query).execute(db);
39
+ return rows.map((row) => String(row.name ?? row.NAME ?? row.Name).toLowerCase());
40
+ };
41
+ /** The canon tables this database already holds, in canon order. */
42
+ export const canonTablesIn = async (db, dialect) => {
43
+ const present = new Set(await tableNames(db, dialect));
44
+ return CANON_TABLES.filter((name) => present.has(name.toLowerCase()));
45
+ };
46
+ /** The generated DDL as statements; the header comments are not statements. */
47
+ const statementsOf = (dialect) => renderDdlSql(dialect)
48
+ .split('\n')
49
+ .filter((line) => !line.trim().startsWith('--'))
50
+ .join('\n')
51
+ .split(/;\s*\n/)
52
+ .map((part) => part.trim())
53
+ .filter(Boolean);
54
+ /** The table a statement belongs to — null for anything that names no table. */
55
+ const ownerOf = (statement) => {
56
+ const match = /^create\s+table\s+(?:if\s+not\s+exists\s+)?([^\s(]+)/im.exec(statement) ??
57
+ /^create\s+(?:unique\s+)?index\s+\S+\s+on\s+([^\s(]+)/im.exec(statement) ??
58
+ /^alter\s+table\s+(\S+)/im.exec(statement);
59
+ // quoted identifiers ("T", `T`, [T]) and a schema prefix are not part of the name
60
+ return match ? match[1].replace(/["`[\]]/g, '').replace(/^.*\./, '').toLowerCase() : null;
61
+ };
62
+ /**
63
+ * Applies the canon DDL to an open database. Reports what it created and what was
64
+ * already there; touches nothing outside the canon tables it had to create.
65
+ *
66
+ * @param {object} options
67
+ * @param {import('kysely').Kysely<any>} options.db an open Kysely handle on the target
68
+ * @param {'postgres'|'mariadb'|'sqlite'|'mssql'} options.dialect which generated DDL to run
69
+ * @param {boolean} [options.force] top up a database that already holds tables
70
+ */
71
+ export const applyCanonDdl = async ({ db, dialect, force = false }) => {
72
+ const present = await tableNames(db, dialect);
73
+ const there = new Set(present);
74
+ const existing = CANON_TABLES.filter((name) => there.has(name.toLowerCase()));
75
+ if (existing.length === CANON_TABLES.length)
76
+ return { dialect, created: [], existing };
77
+ if (present.length > 0 && !force) {
78
+ const named = existing.length
79
+ ? ` — ${existing.length} of the canon tables are already among them: ${existing.slice(0, 3).join(', ')}${existing.length > 3 ? ', …' : ''}`
80
+ : '';
81
+ throw new Error(`canon-provision: the target is not empty — it holds ${present.length} table(s)${named}; ` +
82
+ 'the canon DDL goes into an empty database only (--force creates just the missing tables)');
83
+ }
84
+ const statements = statementsOf(dialect).filter((statement) => {
85
+ const owner = ownerOf(statement);
86
+ return !owner || !there.has(owner);
87
+ });
88
+ // SQLite commits every statement on its own (an fsync per commit: measured ~78ms) —
89
+ // one transaction turns the whole canon from ~20s into ~0.1s. Postgres and MariaDB
90
+ // run without one: a pooled handle does not promise the same connection for a raw
91
+ // `begin`, and their round trips are cheap.
92
+ const transactional = dialect === 'sqlite';
93
+ if (transactional)
94
+ await sql.raw('begin').execute(db);
95
+ try {
96
+ for (const statement of statements)
97
+ await sql.raw(statement).execute(db);
98
+ if (transactional)
99
+ await sql.raw('commit').execute(db);
100
+ }
101
+ catch (error) {
102
+ if (transactional)
103
+ await sql.raw('rollback').execute(db).catch(() => { });
104
+ throw error;
105
+ }
106
+ // the catalog is the answer, not the statement count: the run also creates
107
+ // indexes and constraints, and only tables that were missing are "created"
108
+ const after = new Set(await tableNames(db, dialect));
109
+ const created = CANON_TABLES.filter((name) => !there.has(name.toLowerCase()) && after.has(name.toLowerCase()));
110
+ return { dialect, created, existing };
111
+ };
@@ -0,0 +1,2 @@
1
+ import type { CanonSchema } from './dsl.ts';
2
+ export declare const canonicalSchema: CanonSchema;