@telorun/sql 0.21.3 → 0.22.1

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 (45) hide show
  1. package/dist/index.d.ts +18 -2
  2. package/dist/index.js +9 -2
  3. package/dist/schema/declaration-snapshot.d.ts +21 -0
  4. package/dist/schema/declaration-snapshot.js +46 -0
  5. package/dist/schema/declared-schema.d.ts +64 -0
  6. package/dist/schema/declared-schema.js +16 -0
  7. package/dist/schema/migration-runner.d.ts +30 -0
  8. package/dist/schema/migration-runner.js +38 -0
  9. package/dist/schema/normalize-table.d.ts +57 -0
  10. package/dist/schema/normalize-table.js +125 -0
  11. package/dist/schema/reclaim-policy.d.ts +34 -0
  12. package/dist/schema/reclaim-policy.js +40 -0
  13. package/dist/schema/schema-driver.d.ts +184 -0
  14. package/dist/schema/schema-driver.js +1 -0
  15. package/dist/schema/schema-ledger.d.ts +119 -0
  16. package/dist/schema/schema-ledger.js +231 -0
  17. package/dist/schema/schema-reconciler.d.ts +45 -0
  18. package/dist/schema/schema-reconciler.js +276 -0
  19. package/dist/schema/schema-run.d.ts +50 -0
  20. package/dist/schema/schema-run.js +318 -0
  21. package/dist/schema/table-reference.d.ts +25 -0
  22. package/dist/schema/table-reference.js +61 -0
  23. package/dist/sql-connection-base.d.ts +21 -0
  24. package/dist/sql-connection-base.js +30 -4
  25. package/dist/sql-connection.d.ts +19 -0
  26. package/package.json +5 -3
  27. package/src/index.ts +43 -2
  28. package/src/schema/declaration-snapshot.ts +71 -0
  29. package/src/schema/declared-schema.ts +73 -0
  30. package/src/schema/migration-runner.ts +69 -0
  31. package/src/schema/normalize-table.ts +224 -0
  32. package/src/schema/reclaim-policy.ts +73 -0
  33. package/src/schema/schema-driver.ts +207 -0
  34. package/src/schema/schema-ledger.ts +309 -0
  35. package/src/schema/schema-reconciler.ts +372 -0
  36. package/src/schema/schema-run.ts +441 -0
  37. package/src/schema/table-reference.ts +78 -0
  38. package/src/sql-connection-base.ts +35 -4
  39. package/src/sql-connection.ts +21 -0
  40. package/dist/sql-migration-controller.d.ts +0 -16
  41. package/dist/sql-migration-controller.js +0 -13
  42. package/dist/sql-migrations-controller.d.ts +0 -23
  43. package/dist/sql-migrations-controller.js +0 -98
  44. package/src/sql-migration-controller.ts +0 -20
  45. package/src/sql-migrations-controller.ts +0 -143
@@ -1,98 +0,0 @@
1
- import { CompiledQuery, Migrator, } from "kysely";
2
- import { resolveSqlConnection } from "./sql-connection-ref.js";
3
- function entryStatements(entry) {
4
- return entry.statements ?? (entry.statement != null ? [entry.statement] : []);
5
- }
6
- class TeloMigrationProvider {
7
- migrations;
8
- constructor(migrations) {
9
- this.migrations = migrations;
10
- }
11
- async getMigrations() {
12
- return Object.fromEntries(Object.entries(this.migrations).map(([name, statements]) => [
13
- name,
14
- {
15
- // Each statement runs as its own prepared statement on the migration
16
- // transaction's connection, so a migration may hold multiple
17
- // statements while the whole batch stays a single transaction.
18
- async up(db) {
19
- for (const statement of statements) {
20
- await db.executeQuery(CompiledQuery.raw(statement));
21
- }
22
- },
23
- },
24
- ]));
25
- }
26
- }
27
- class SqlMigrationsResource {
28
- manifest;
29
- ctx;
30
- constructor(manifest, ctx) {
31
- this.manifest = manifest;
32
- this.ctx = ctx;
33
- }
34
- async run() {
35
- const conn = resolveSqlConnection(this.manifest.connection, this.ctx, () => `Sql.Migrations "${this.manifest.metadata.name}": 'connection'`) ?? failMissingConnection();
36
- const migrations = {};
37
- // Legacy: standalone `Sql.Migration` resources in the same module scope.
38
- for (const [, { resource }] of this.ctx.moduleContext.resourceInstances) {
39
- if (resource.kind === "Sql.Migration") {
40
- const version = (resource.version ?? resource.metadata.name);
41
- migrations[version] = [resource.sql];
42
- }
43
- }
44
- // Preferred: the keyed `migrations` map on this resource.
45
- for (const [name, entry] of Object.entries(this.manifest.migrations ?? {})) {
46
- const statements = entryStatements(entry);
47
- if (statements.length === 0) {
48
- throw new Error(`Sql.Migrations: migration '${name}' has no statement(s) — ` +
49
- `set 'statement' or a non-empty 'statements'`);
50
- }
51
- migrations[name] = statements;
52
- }
53
- if (!conn.kysely) {
54
- throw new Error(`Sql.Migrations '${this.manifest.metadata.name}': the referenced connection is not ` +
55
- `built on kysely, which this kind's migration runner requires. Use a backend that ` +
56
- `extends SqlConnectionBase, or run the statements through Sql.Command.`);
57
- }
58
- const migrator = new Migrator({
59
- db: conn.kysely,
60
- provider: new TeloMigrationProvider(migrations),
61
- migrationTableName: "migrations",
62
- migrationLockTableName: "migration_locks",
63
- });
64
- const { error, results } = await migrator.migrateToLatest();
65
- // A schema change is the least reversible thing an app does at boot, and the
66
- // per-migration outcome was being discarded — so a run that applied four
67
- // migrations and a run that found none to apply looked identical afterwards.
68
- // `info`, because which migrations a deployment applied is the fact you go
69
- // looking for when a schema is not what you expected.
70
- // `sql.migration.name`, not `db.migration.name`: OTel owns `db.*` and defines
71
- // no migration attribute, and §6.2 forbids inventing keys inside a namespace
72
- // someone else governs.
73
- for (const applied of results ?? []) {
74
- if (applied.status === "Success") {
75
- this.ctx.log.info("Migration applied", { "sql.migration.name": applied.migrationName });
76
- }
77
- else if (applied.status === "Error") {
78
- // The cause rides on the record: this is the error-severity line an
79
- // operator finds first, and the migration name alone cannot say what
80
- // went wrong. `error` keeps the type, stack and cause chain (§4.2).
81
- this.ctx.log.error("Migration failed", { "sql.migration.name": applied.migrationName }, { error });
82
- }
83
- }
84
- if (error) {
85
- throw error;
86
- }
87
- if (!results?.length) {
88
- this.ctx.log.debug("No pending migrations");
89
- }
90
- }
91
- }
92
- function failMissingConnection() {
93
- throw new Error("Sql.Migrations: missing connection");
94
- }
95
- export function register() { }
96
- export async function create(resource, ctx) {
97
- return new SqlMigrationsResource(resource, ctx);
98
- }
@@ -1,20 +0,0 @@
1
- import type { ResourceInstance } from "@telorun/sdk";
2
-
3
- interface SqlMigrationManifest {
4
- metadata: { name: string; module: string };
5
- sql: string;
6
- }
7
-
8
- class SqlMigrationResource implements ResourceInstance {
9
- constructor(readonly manifest: SqlMigrationManifest) {}
10
-
11
- snapshot(): Record<string, unknown> {
12
- return {};
13
- }
14
- }
15
-
16
- export function register(): void {}
17
-
18
- export async function create(resource: SqlMigrationManifest): Promise<SqlMigrationResource> {
19
- return new SqlMigrationResource(resource);
20
- }
@@ -1,143 +0,0 @@
1
- import type { ResourceContext, ResourceInstance } from "@telorun/sdk";
2
- import {
3
- CompiledQuery,
4
- Migrator,
5
- type Kysely,
6
- type Migration,
7
- type MigrationProvider,
8
- } from "kysely";
9
- import type { SqlConnection } from "./sql-connection.js";
10
- import { resolveSqlConnection } from "./sql-connection-ref.js";
11
-
12
- // A migration entry is one statement or an ordered list of statements; both
13
- // forms normalize to a non-empty array of single statements.
14
- interface MigrationEntry {
15
- statement?: string;
16
- statements?: string[];
17
- }
18
-
19
- interface SqlMigrationsManifest {
20
- metadata: { name: string; module: string };
21
- connection: SqlConnection;
22
- migrations?: Record<string, MigrationEntry>;
23
- }
24
-
25
- function entryStatements(entry: MigrationEntry): string[] {
26
- return entry.statements ?? (entry.statement != null ? [entry.statement] : []);
27
- }
28
-
29
- class TeloMigrationProvider implements MigrationProvider {
30
- constructor(private readonly migrations: Record<string, string[]>) {}
31
-
32
- async getMigrations(): Promise<Record<string, Migration>> {
33
- return Object.fromEntries(
34
- Object.entries(this.migrations).map(([name, statements]) => [
35
- name,
36
- {
37
- // Each statement runs as its own prepared statement on the migration
38
- // transaction's connection, so a migration may hold multiple
39
- // statements while the whole batch stays a single transaction.
40
- async up(db: Kysely<any>): Promise<void> {
41
- for (const statement of statements) {
42
- await db.executeQuery(CompiledQuery.raw(statement));
43
- }
44
- },
45
- },
46
- ]),
47
- );
48
- }
49
- }
50
-
51
- class SqlMigrationsResource implements ResourceInstance {
52
- constructor(
53
- private readonly manifest: SqlMigrationsManifest,
54
- private readonly ctx: ResourceContext,
55
- ) {}
56
-
57
- async run(): Promise<void> {
58
- const conn =
59
- resolveSqlConnection(
60
- this.manifest.connection,
61
- this.ctx,
62
- () => `Sql.Migrations "${this.manifest.metadata.name}": 'connection'`,
63
- ) ?? failMissingConnection();
64
-
65
- const migrations: Record<string, string[]> = {};
66
- // Legacy: standalone `Sql.Migration` resources in the same module scope.
67
- for (const [, { resource }] of this.ctx.moduleContext.resourceInstances) {
68
- if (resource.kind === "Sql.Migration") {
69
- const version = (resource.version ?? resource.metadata.name) as string;
70
- migrations[version] = [resource.sql as string];
71
- }
72
- }
73
- // Preferred: the keyed `migrations` map on this resource.
74
- for (const [name, entry] of Object.entries(this.manifest.migrations ?? {})) {
75
- const statements = entryStatements(entry);
76
- if (statements.length === 0) {
77
- throw new Error(
78
- `Sql.Migrations: migration '${name}' has no statement(s) — ` +
79
- `set 'statement' or a non-empty 'statements'`,
80
- );
81
- }
82
- migrations[name] = statements;
83
- }
84
-
85
- if (!conn.kysely) {
86
- throw new Error(
87
- `Sql.Migrations '${this.manifest.metadata.name}': the referenced connection is not ` +
88
- `built on kysely, which this kind's migration runner requires. Use a backend that ` +
89
- `extends SqlConnectionBase, or run the statements through Sql.Command.`,
90
- );
91
- }
92
-
93
- const migrator = new Migrator({
94
- db: conn.kysely,
95
- provider: new TeloMigrationProvider(migrations),
96
- migrationTableName: "migrations",
97
- migrationLockTableName: "migration_locks",
98
- });
99
-
100
- const { error, results } = await migrator.migrateToLatest();
101
- // A schema change is the least reversible thing an app does at boot, and the
102
- // per-migration outcome was being discarded — so a run that applied four
103
- // migrations and a run that found none to apply looked identical afterwards.
104
- // `info`, because which migrations a deployment applied is the fact you go
105
- // looking for when a schema is not what you expected.
106
- // `sql.migration.name`, not `db.migration.name`: OTel owns `db.*` and defines
107
- // no migration attribute, and §6.2 forbids inventing keys inside a namespace
108
- // someone else governs.
109
- for (const applied of results ?? []) {
110
- if (applied.status === "Success") {
111
- this.ctx.log.info("Migration applied", { "sql.migration.name": applied.migrationName });
112
- } else if (applied.status === "Error") {
113
- // The cause rides on the record: this is the error-severity line an
114
- // operator finds first, and the migration name alone cannot say what
115
- // went wrong. `error` keeps the type, stack and cause chain (§4.2).
116
- this.ctx.log.error(
117
- "Migration failed",
118
- { "sql.migration.name": applied.migrationName },
119
- { error },
120
- );
121
- }
122
- }
123
- if (error) {
124
- throw error;
125
- }
126
- if (!results?.length) {
127
- this.ctx.log.debug("No pending migrations");
128
- }
129
- }
130
- }
131
-
132
- function failMissingConnection(): never {
133
- throw new Error("Sql.Migrations: missing connection");
134
- }
135
-
136
- export function register(): void {}
137
-
138
- export async function create(
139
- resource: SqlMigrationsManifest,
140
- ctx: ResourceContext,
141
- ): Promise<SqlMigrationsResource> {
142
- return new SqlMigrationsResource(resource, ctx);
143
- }