turbine-orm 0.50.0 → 0.51.0
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.
- package/README.md +66 -66
- package/dist/adapters/cockroachdb.d.ts +5 -5
- package/dist/adapters/cockroachdb.js +10 -10
- package/dist/adapters/index.d.ts +5 -5
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/yugabytedb.d.ts +7 -7
- package/dist/adapters/yugabytedb.js +10 -10
- package/dist/cjs/adapters/cockroachdb.d.ts +5 -5
- package/dist/cjs/adapters/cockroachdb.js +10 -10
- package/dist/cjs/adapters/index.d.ts +5 -5
- package/dist/cjs/adapters/index.js +7 -7
- package/dist/cjs/adapters/yugabytedb.d.ts +7 -7
- package/dist/cjs/adapters/yugabytedb.js +10 -10
- package/dist/cjs/cli/config.d.ts +13 -2
- package/dist/cjs/cli/config.js +3 -2
- package/dist/cjs/cli/destructive.d.ts +1 -1
- package/dist/cjs/cli/destructive.js +1 -1
- package/dist/cjs/cli/index.d.ts +10 -10
- package/dist/cjs/cli/index.js +49 -45
- package/dist/cjs/cli/loader.d.ts +7 -7
- package/dist/cjs/cli/loader.js +9 -9
- package/dist/cjs/cli/mcp.js +4 -4
- package/dist/cjs/cli/migrate.d.ts +5 -5
- package/dist/cjs/cli/migrate.js +11 -11
- package/dist/cjs/cli/studio-ui.generated.js +1 -1
- package/dist/cjs/cli/ui.d.ts +2 -2
- package/dist/cjs/cli/ui.js +2 -2
- package/dist/cjs/client.d.ts +49 -38
- package/dist/cjs/client.js +57 -56
- package/dist/cjs/dialect.d.ts +62 -18
- package/dist/cjs/dialect.js +40 -2
- package/dist/cjs/errors.d.ts +5 -5
- package/dist/cjs/errors.js +11 -11
- package/dist/cjs/generate.d.ts +6 -6
- package/dist/cjs/generate.js +31 -29
- package/dist/cjs/index-advisor.d.ts +5 -5
- package/dist/cjs/index-advisor.js +0 -0
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +7 -7
- package/dist/cjs/introspect.d.ts +35 -9
- package/dist/cjs/introspect.js +83 -32
- package/dist/cjs/mssql.d.ts +11 -11
- package/dist/cjs/mssql.js +64 -29
- package/dist/cjs/mysql.d.ts +8 -8
- package/dist/cjs/mysql.js +61 -23
- package/dist/cjs/nested-write.d.ts +21 -2
- package/dist/cjs/nested-write.js +51 -14
- package/dist/cjs/optional-peer-import.cjs +7 -7
- package/dist/cjs/optional-peer-import.d.cts +7 -7
- package/dist/cjs/pipeline-submittable.d.ts +2 -2
- package/dist/cjs/pipeline-submittable.js +6 -6
- package/dist/cjs/pipeline.d.ts +1 -1
- package/dist/cjs/pipeline.js +4 -4
- package/dist/cjs/powdb-introspect.d.ts +1 -1
- package/dist/cjs/powdb-introspect.js +1 -1
- package/dist/cjs/powdb.d.ts +28 -28
- package/dist/cjs/powdb.js +66 -66
- package/dist/cjs/powql.d.ts +27 -27
- package/dist/cjs/powql.js +73 -52
- package/dist/cjs/query/aggregates.d.ts +1 -1
- package/dist/cjs/query/aggregates.js +5 -5
- package/dist/cjs/query/batched-loader.d.ts +11 -11
- package/dist/cjs/query/batched-loader.js +24 -24
- package/dist/cjs/query/builder.d.ts +39 -21
- package/dist/cjs/query/builder.js +99 -57
- package/dist/cjs/query/compound-unique.d.ts +1 -1
- package/dist/cjs/query/compound-unique.js +0 -0
- package/dist/cjs/query/deferred.d.ts +12 -6
- package/dist/cjs/query/deferred.js +1 -1
- package/dist/cjs/query/filters.d.ts +31 -11
- package/dist/cjs/query/filters.js +67 -14
- package/dist/cjs/query/index.d.ts +1 -1
- package/dist/cjs/query/index.js +1 -1
- package/dist/cjs/query/relations.d.ts +9 -9
- package/dist/cjs/query/relations.js +164 -57
- package/dist/cjs/query/types.d.ts +86 -35
- package/dist/cjs/query/types.js +1 -1
- package/dist/cjs/query/utils.d.ts +27 -10
- package/dist/cjs/query/utils.js +86 -14
- package/dist/cjs/query/where.d.ts +47 -28
- package/dist/cjs/query/where.js +130 -31
- package/dist/cjs/query/writes.d.ts +24 -5
- package/dist/cjs/query/writes.js +102 -13
- package/dist/cjs/realtime.d.ts +7 -7
- package/dist/cjs/realtime.js +9 -9
- package/dist/cjs/schema-builder.d.ts +18 -7
- package/dist/cjs/schema-builder.js +17 -10
- package/dist/cjs/schema-metadata.d.ts +3 -3
- package/dist/cjs/schema-metadata.js +9 -9
- package/dist/cjs/schema-sql.d.ts +9 -9
- package/dist/cjs/schema-sql.js +20 -20
- package/dist/cjs/schema.d.ts +19 -9
- package/dist/cjs/schema.js +6 -6
- package/dist/cjs/serverless.d.ts +15 -15
- package/dist/cjs/serverless.js +16 -16
- package/dist/cjs/sqlite.d.ts +8 -8
- package/dist/cjs/sqlite.js +53 -22
- package/dist/cjs/typed-sql.d.ts +4 -4
- package/dist/cjs/typed-sql.js +5 -5
- package/dist/cli/config.d.ts +13 -2
- package/dist/cli/config.js +3 -2
- package/dist/cli/destructive.d.ts +1 -1
- package/dist/cli/destructive.js +1 -1
- package/dist/cli/index.d.ts +10 -10
- package/dist/cli/index.js +49 -45
- package/dist/cli/loader.d.ts +7 -7
- package/dist/cli/loader.js +9 -9
- package/dist/cli/mcp.js +4 -4
- package/dist/cli/migrate.d.ts +5 -5
- package/dist/cli/migrate.js +11 -11
- package/dist/cli/studio-ui.generated.js +1 -1
- package/dist/cli/ui.d.ts +2 -2
- package/dist/cli/ui.js +2 -2
- package/dist/client.d.ts +49 -38
- package/dist/client.js +57 -56
- package/dist/dialect.d.ts +62 -18
- package/dist/dialect.js +40 -2
- package/dist/errors.d.ts +5 -5
- package/dist/errors.js +11 -11
- package/dist/generate.d.ts +6 -6
- package/dist/generate.js +31 -29
- package/dist/index-advisor.d.ts +5 -5
- package/dist/index-advisor.js +0 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +7 -7
- package/dist/introspect.d.ts +35 -9
- package/dist/introspect.js +82 -32
- package/dist/mssql.d.ts +11 -11
- package/dist/mssql.js +64 -29
- package/dist/mysql.d.ts +8 -8
- package/dist/mysql.js +61 -23
- package/dist/nested-write.d.ts +21 -2
- package/dist/nested-write.js +51 -14
- package/dist/optional-peer-import.cjs +7 -7
- package/dist/optional-peer-import.d.cts +7 -7
- package/dist/pipeline-submittable.d.ts +2 -2
- package/dist/pipeline-submittable.js +6 -6
- package/dist/pipeline.d.ts +1 -1
- package/dist/pipeline.js +4 -4
- package/dist/powdb-introspect.d.ts +1 -1
- package/dist/powdb-introspect.js +1 -1
- package/dist/powdb.d.ts +28 -28
- package/dist/powdb.js +66 -66
- package/dist/powql.d.ts +27 -27
- package/dist/powql.js +73 -52
- package/dist/query/aggregates.d.ts +1 -1
- package/dist/query/aggregates.js +5 -5
- package/dist/query/batched-loader.d.ts +11 -11
- package/dist/query/batched-loader.js +24 -24
- package/dist/query/builder.d.ts +39 -21
- package/dist/query/builder.js +100 -58
- package/dist/query/compound-unique.d.ts +1 -1
- package/dist/query/compound-unique.js +0 -0
- package/dist/query/deferred.d.ts +12 -6
- package/dist/query/deferred.js +1 -1
- package/dist/query/filters.d.ts +31 -11
- package/dist/query/filters.js +66 -13
- package/dist/query/index.d.ts +1 -1
- package/dist/query/index.js +1 -1
- package/dist/query/relations.d.ts +9 -9
- package/dist/query/relations.js +165 -58
- package/dist/query/types.d.ts +86 -35
- package/dist/query/types.js +1 -1
- package/dist/query/utils.d.ts +27 -10
- package/dist/query/utils.js +84 -14
- package/dist/query/where.d.ts +47 -28
- package/dist/query/where.js +129 -32
- package/dist/query/writes.d.ts +24 -5
- package/dist/query/writes.js +101 -13
- package/dist/realtime.d.ts +7 -7
- package/dist/realtime.js +9 -9
- package/dist/schema-builder.d.ts +18 -7
- package/dist/schema-builder.js +17 -10
- package/dist/schema-metadata.d.ts +3 -3
- package/dist/schema-metadata.js +9 -9
- package/dist/schema-sql.d.ts +9 -9
- package/dist/schema-sql.js +20 -20
- package/dist/schema.d.ts +19 -9
- package/dist/schema.js +6 -6
- package/dist/serverless.d.ts +15 -15
- package/dist/serverless.js +16 -16
- package/dist/sqlite.d.ts +8 -8
- package/dist/sqlite.js +53 -22
- package/dist/typed-sql.d.ts +4 -4
- package/dist/typed-sql.js +5 -5
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* turbine-orm
|
|
2
|
+
* turbine-orm, YugabyteDB adapter
|
|
3
3
|
*
|
|
4
4
|
* YugabyteDB is a distributed SQL database that speaks the PostgreSQL wire
|
|
5
5
|
* protocol. It supports most PostgreSQL features including json_agg,
|
|
@@ -7,28 +7,28 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Key differences from PostgreSQL that this adapter addresses:
|
|
9
9
|
*
|
|
10
|
-
* 1. **Advisory locks are per-node
|
|
10
|
+
* 1. **Advisory locks are per-node**, `pg_try_advisory_lock()` is supported
|
|
11
11
|
* but only scoped to the tserver node handling the connection. In a
|
|
12
12
|
* multi-node cluster, two concurrent `turbine migrate` runs routed to
|
|
13
13
|
* different nodes would both acquire the "same" advisory lock. This adapter
|
|
14
14
|
* provides a table-based distributed lock using `SELECT FOR UPDATE NOWAIT`
|
|
15
15
|
* which is cluster-wide via YugabyteDB's distributed transactions.
|
|
16
16
|
*
|
|
17
|
-
* 2. **Sequences may have gaps
|
|
17
|
+
* 2. **Sequences may have gaps**, YugabyteDB uses distributed sequences.
|
|
18
18
|
* SERIAL/BIGSERIAL columns work correctly but may produce non-contiguous
|
|
19
19
|
* IDs under concurrent inserts. This is purely cosmetic and does not affect
|
|
20
20
|
* Turbine's behavior.
|
|
21
21
|
*
|
|
22
|
-
* 3. **pg_catalog
|
|
22
|
+
* 3. **pg_catalog**, Mostly complete. `pg_indexes`, `pg_type`, `pg_enum`,
|
|
23
23
|
* `information_schema.columns` all work. Row estimate via `pg_class.reltuples`
|
|
24
24
|
* may be stale or zero on recently created tables (YugabyteDB's stats
|
|
25
25
|
* collection is asynchronous). This adapter provides an override that
|
|
26
26
|
* falls back to `yb_table_properties` when available.
|
|
27
27
|
*
|
|
28
28
|
* Features that work identically to PostgreSQL (no adapter override needed):
|
|
29
|
-
* - `json_agg` / `json_build_object
|
|
30
|
-
* - Correlated subqueries
|
|
31
|
-
* - `COALESCE`, `LIMIT`, `OFFSET`, `ORDER BY
|
|
29
|
+
* - `json_agg` / `json_build_object`, fully supported
|
|
30
|
+
* - Correlated subqueries, fully supported
|
|
31
|
+
* - `COALESCE`, `LIMIT`, `OFFSET`, `ORDER BY`, fully supported
|
|
32
32
|
* - `information_schema` for table/column/constraint introspection
|
|
33
33
|
* - Extended query protocol (parameterized queries, pipeline batching)
|
|
34
34
|
* - Transactions with `SAVEPOINT` (nested transactions)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* turbine-orm
|
|
2
|
+
* turbine-orm, YugabyteDB adapter
|
|
3
3
|
*
|
|
4
4
|
* YugabyteDB is a distributed SQL database that speaks the PostgreSQL wire
|
|
5
5
|
* protocol. It supports most PostgreSQL features including json_agg,
|
|
@@ -7,28 +7,28 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Key differences from PostgreSQL that this adapter addresses:
|
|
9
9
|
*
|
|
10
|
-
* 1. **Advisory locks are per-node
|
|
10
|
+
* 1. **Advisory locks are per-node**, `pg_try_advisory_lock()` is supported
|
|
11
11
|
* but only scoped to the tserver node handling the connection. In a
|
|
12
12
|
* multi-node cluster, two concurrent `turbine migrate` runs routed to
|
|
13
13
|
* different nodes would both acquire the "same" advisory lock. This adapter
|
|
14
14
|
* provides a table-based distributed lock using `SELECT FOR UPDATE NOWAIT`
|
|
15
15
|
* which is cluster-wide via YugabyteDB's distributed transactions.
|
|
16
16
|
*
|
|
17
|
-
* 2. **Sequences may have gaps
|
|
17
|
+
* 2. **Sequences may have gaps**, YugabyteDB uses distributed sequences.
|
|
18
18
|
* SERIAL/BIGSERIAL columns work correctly but may produce non-contiguous
|
|
19
19
|
* IDs under concurrent inserts. This is purely cosmetic and does not affect
|
|
20
20
|
* Turbine's behavior.
|
|
21
21
|
*
|
|
22
|
-
* 3. **pg_catalog
|
|
22
|
+
* 3. **pg_catalog**, Mostly complete. `pg_indexes`, `pg_type`, `pg_enum`,
|
|
23
23
|
* `information_schema.columns` all work. Row estimate via `pg_class.reltuples`
|
|
24
24
|
* may be stale or zero on recently created tables (YugabyteDB's stats
|
|
25
25
|
* collection is asynchronous). This adapter provides an override that
|
|
26
26
|
* falls back to `yb_table_properties` when available.
|
|
27
27
|
*
|
|
28
28
|
* Features that work identically to PostgreSQL (no adapter override needed):
|
|
29
|
-
* - `json_agg` / `json_build_object
|
|
30
|
-
* - Correlated subqueries
|
|
31
|
-
* - `COALESCE`, `LIMIT`, `OFFSET`, `ORDER BY
|
|
29
|
+
* - `json_agg` / `json_build_object`, fully supported
|
|
30
|
+
* - Correlated subqueries, fully supported
|
|
31
|
+
* - `COALESCE`, `LIMIT`, `OFFSET`, `ORDER BY`, fully supported
|
|
32
32
|
* - `information_schema` for table/column/constraint introspection
|
|
33
33
|
* - Extended query protocol (parameterized queries, pipeline batching)
|
|
34
34
|
* - Transactions with `SAVEPOINT` (nested transactions)
|
|
@@ -105,7 +105,7 @@ export const yugabytedb = {
|
|
|
105
105
|
await client.query(`SELECT lock_id FROM "${LOCK_TABLE}" WHERE lock_id = $1 FOR UPDATE NOWAIT`, [lockId]);
|
|
106
106
|
// Update acquisition metadata for observability
|
|
107
107
|
await client.query(`UPDATE "${LOCK_TABLE}" SET acquired_at = now(), acquired_by = current_user WHERE lock_id = $1`, [lockId]);
|
|
108
|
-
// Leave the transaction open
|
|
108
|
+
// Leave the transaction open, lock is held until releaseLock()
|
|
109
109
|
return true;
|
|
110
110
|
}
|
|
111
111
|
catch (err) {
|
|
@@ -120,7 +120,7 @@ export const yugabytedb = {
|
|
|
120
120
|
}
|
|
121
121
|
return false;
|
|
122
122
|
}
|
|
123
|
-
// Any other error
|
|
123
|
+
// Any other error, rollback and re-throw
|
|
124
124
|
try {
|
|
125
125
|
await client.query('ROLLBACK');
|
|
126
126
|
}
|
|
@@ -136,7 +136,7 @@ export const yugabytedb = {
|
|
|
136
136
|
await client.query('COMMIT');
|
|
137
137
|
}
|
|
138
138
|
catch {
|
|
139
|
-
// If commit fails, try rollback
|
|
139
|
+
// If commit fails, try rollback, either way the lock is released
|
|
140
140
|
try {
|
|
141
141
|
await client.query('ROLLBACK');
|
|
142
142
|
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* turbine-orm
|
|
2
|
+
* turbine-orm, CockroachDB adapter
|
|
3
3
|
*
|
|
4
4
|
* CockroachDB speaks the PostgreSQL wire protocol but has key differences:
|
|
5
5
|
*
|
|
6
|
-
* 1. **No advisory locks
|
|
6
|
+
* 1. **No advisory locks**, `pg_try_advisory_lock()` is not supported.
|
|
7
7
|
* This adapter uses a `_turbine_lock` table with `SELECT FOR UPDATE NOWAIT`
|
|
8
8
|
* as a concurrency mechanism for migrations.
|
|
9
9
|
*
|
|
10
|
-
* 2. **No `SET LOCAL statement_timeout
|
|
10
|
+
* 2. **No `SET LOCAL statement_timeout`**, CockroachDB uses
|
|
11
11
|
* `SET transaction_timeout` (v23.1+) for per-transaction time limits.
|
|
12
12
|
*
|
|
13
|
-
* 3. **`pg_indexes` view
|
|
13
|
+
* 3. **`pg_indexes` view**, CockroachDB supports `pg_indexes` since v22.1
|
|
14
14
|
* but the `indexdef` column may not match Postgres exactly. We use
|
|
15
15
|
* `SHOW INDEXES` as a more reliable alternative.
|
|
16
16
|
*
|
|
17
|
-
* 4. **`pg_class.reltuples
|
|
17
|
+
* 4. **`pg_class.reltuples`**, Not reliable in CockroachDB. We use
|
|
18
18
|
* `crdb_internal.table_row_statistics` for row estimates.
|
|
19
19
|
*
|
|
20
20
|
* Known limitations with Turbine on CockroachDB:
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* turbine-orm
|
|
3
|
+
* turbine-orm, CockroachDB adapter
|
|
4
4
|
*
|
|
5
5
|
* CockroachDB speaks the PostgreSQL wire protocol but has key differences:
|
|
6
6
|
*
|
|
7
|
-
* 1. **No advisory locks
|
|
7
|
+
* 1. **No advisory locks**, `pg_try_advisory_lock()` is not supported.
|
|
8
8
|
* This adapter uses a `_turbine_lock` table with `SELECT FOR UPDATE NOWAIT`
|
|
9
9
|
* as a concurrency mechanism for migrations.
|
|
10
10
|
*
|
|
11
|
-
* 2. **No `SET LOCAL statement_timeout
|
|
11
|
+
* 2. **No `SET LOCAL statement_timeout`**, CockroachDB uses
|
|
12
12
|
* `SET transaction_timeout` (v23.1+) for per-transaction time limits.
|
|
13
13
|
*
|
|
14
|
-
* 3. **`pg_indexes` view
|
|
14
|
+
* 3. **`pg_indexes` view**, CockroachDB supports `pg_indexes` since v22.1
|
|
15
15
|
* but the `indexdef` column may not match Postgres exactly. We use
|
|
16
16
|
* `SHOW INDEXES` as a more reliable alternative.
|
|
17
17
|
*
|
|
18
|
-
* 4. **`pg_class.reltuples
|
|
18
|
+
* 4. **`pg_class.reltuples`**, Not reliable in CockroachDB. We use
|
|
19
19
|
* `crdb_internal.table_row_statistics` for row estimates.
|
|
20
20
|
*
|
|
21
21
|
* Known limitations with Turbine on CockroachDB:
|
|
@@ -72,7 +72,7 @@ const SQL_INDEXES_CRDB = `
|
|
|
72
72
|
`;
|
|
73
73
|
/**
|
|
74
74
|
* Row estimates using crdb_internal. Falls back gracefully if the view
|
|
75
|
-
* doesn't exist (permissions issue)
|
|
75
|
+
* doesn't exist (permissions issue), returns 0 rows in that case.
|
|
76
76
|
*/
|
|
77
77
|
const SQL_ROW_ESTIMATES_CRDB = `
|
|
78
78
|
SELECT
|
|
@@ -85,7 +85,7 @@ const SQL_ROW_ESTIMATES_CRDB = `
|
|
|
85
85
|
AND t.database_name = current_database()
|
|
86
86
|
`;
|
|
87
87
|
/**
|
|
88
|
-
* Enum introspection
|
|
88
|
+
* Enum introspection, CockroachDB supports pg_type/pg_enum since v20.2.
|
|
89
89
|
* The standard query works, but we include it explicitly so the override
|
|
90
90
|
* mechanism is complete.
|
|
91
91
|
*/
|
|
@@ -110,13 +110,13 @@ exports.cockroachdb = {
|
|
|
110
110
|
await client.query(CREATE_LOCK_TABLE_SQL);
|
|
111
111
|
// Insert the lock row if it doesn't exist (idempotent)
|
|
112
112
|
await client.query(`INSERT INTO "${LOCK_TABLE}" (lock_id) VALUES ($1) ON CONFLICT (lock_id) DO NOTHING`, [lockId]);
|
|
113
|
-
// Try to acquire the row lock with NOWAIT
|
|
113
|
+
// Try to acquire the row lock with NOWAIT, fails immediately if held
|
|
114
114
|
try {
|
|
115
115
|
await client.query('BEGIN');
|
|
116
116
|
await client.query(`SELECT lock_id FROM "${LOCK_TABLE}" WHERE lock_id = $1 FOR UPDATE NOWAIT`, [lockId]);
|
|
117
117
|
// Update the acquired metadata
|
|
118
118
|
await client.query(`UPDATE "${LOCK_TABLE}" SET acquired_at = now(), acquired_by = current_user WHERE lock_id = $1`, [lockId]);
|
|
119
|
-
// Note: we leave the transaction OPEN
|
|
119
|
+
// Note: we leave the transaction OPEN, the lock is held until
|
|
120
120
|
// releaseLock() commits or rolls back.
|
|
121
121
|
return true;
|
|
122
122
|
}
|
|
@@ -132,7 +132,7 @@ exports.cockroachdb = {
|
|
|
132
132
|
}
|
|
133
133
|
return false;
|
|
134
134
|
}
|
|
135
|
-
// Any other error
|
|
135
|
+
// Any other error, rollback and re-throw
|
|
136
136
|
try {
|
|
137
137
|
await client.query('ROLLBACK');
|
|
138
138
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* turbine-orm
|
|
2
|
+
* turbine-orm, Database adapter interface
|
|
3
3
|
*
|
|
4
4
|
* Adapters allow Turbine to work with PostgreSQL-compatible databases that
|
|
5
5
|
* have subtle differences (e.g. CockroachDB, YugabyteDB). The default
|
|
6
|
-
* behavior remains standard PostgreSQL
|
|
6
|
+
* behavior remains standard PostgreSQL, adapters only override specific
|
|
7
7
|
* operations where compatibility gaps exist.
|
|
8
8
|
*
|
|
9
9
|
* @example
|
|
@@ -57,9 +57,9 @@ export interface DatabaseAdapter {
|
|
|
57
57
|
* Generate the SQL to set a statement timeout within a transaction.
|
|
58
58
|
* PostgreSQL uses `SELECT set_config('statement_timeout', $1, true)`.
|
|
59
59
|
* CockroachDB uses `SELECT set_config('transaction_timeout', $1, true)` (v23.1+).
|
|
60
|
-
* (`SET LOCAL ... = $1` is a syntax error
|
|
60
|
+
* (`SET LOCAL ... = $1` is a syntax error, SET takes no bind params.)
|
|
61
61
|
*
|
|
62
|
-
* @param seconds
|
|
62
|
+
* @param seconds, timeout in seconds
|
|
63
63
|
* @returns an object with the parameterized SQL and its bound values
|
|
64
64
|
*/
|
|
65
65
|
statementTimeout?(seconds: number): {
|
|
@@ -79,7 +79,7 @@ export interface DatabaseAdapter {
|
|
|
79
79
|
export declare const postgresql: DatabaseAdapter;
|
|
80
80
|
/**
|
|
81
81
|
* Google AlloyDB adapter. AlloyDB is PostgreSQL with Google's columnar storage
|
|
82
|
-
* engine. It is wire-protocol and catalog-compatible
|
|
82
|
+
* engine. It is wire-protocol and catalog-compatible, no adapter overrides
|
|
83
83
|
* are needed. All Turbine features (json_agg, advisory locks, introspection,
|
|
84
84
|
* migrations) work identically to standard PostgreSQL.
|
|
85
85
|
*
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* turbine-orm
|
|
3
|
+
* turbine-orm, Database adapter interface
|
|
4
4
|
*
|
|
5
5
|
* Adapters allow Turbine to work with PostgreSQL-compatible databases that
|
|
6
6
|
* have subtle differences (e.g. CockroachDB, YugabyteDB). The default
|
|
7
|
-
* behavior remains standard PostgreSQL
|
|
7
|
+
* behavior remains standard PostgreSQL, adapters only override specific
|
|
8
8
|
* operations where compatibility gaps exist.
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
exports.yugabytedb = exports.cockroachdb = exports.timescale = exports.alloydb = exports.postgresql = void 0;
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
|
-
// Default PostgreSQL adapter (no-op
|
|
21
|
+
// Default PostgreSQL adapter (no-op, standard behavior)
|
|
22
22
|
// ---------------------------------------------------------------------------
|
|
23
23
|
/**
|
|
24
24
|
* The default PostgreSQL adapter. Uses pg_try_advisory_lock, standard
|
|
@@ -34,18 +34,18 @@ exports.postgresql = {
|
|
|
34
34
|
await client.query(`SELECT pg_advisory_unlock($1)`, [lockId]);
|
|
35
35
|
},
|
|
36
36
|
statementTimeout(seconds) {
|
|
37
|
-
// `SET LOCAL ... = $1` is a Postgres syntax error
|
|
37
|
+
// `SET LOCAL ... = $1` is a Postgres syntax error, SET does not accept
|
|
38
38
|
// bind parameters. `set_config(name, value, is_local=true)` is the
|
|
39
39
|
// parameterizable, transaction-local equivalent.
|
|
40
40
|
return { sql: `SELECT set_config('statement_timeout', $1, true)`, params: [`${seconds}s`] };
|
|
41
41
|
},
|
|
42
42
|
};
|
|
43
43
|
// ---------------------------------------------------------------------------
|
|
44
|
-
// AlloyDB
|
|
44
|
+
// AlloyDB, fully PostgreSQL-compatible, no adapter logic needed
|
|
45
45
|
// ---------------------------------------------------------------------------
|
|
46
46
|
/**
|
|
47
47
|
* Google AlloyDB adapter. AlloyDB is PostgreSQL with Google's columnar storage
|
|
48
|
-
* engine. It is wire-protocol and catalog-compatible
|
|
48
|
+
* engine. It is wire-protocol and catalog-compatible, no adapter overrides
|
|
49
49
|
* are needed. All Turbine features (json_agg, advisory locks, introspection,
|
|
50
50
|
* migrations) work identically to standard PostgreSQL.
|
|
51
51
|
*
|
|
@@ -61,7 +61,7 @@ exports.alloydb = {
|
|
|
61
61
|
name: 'alloydb',
|
|
62
62
|
};
|
|
63
63
|
// ---------------------------------------------------------------------------
|
|
64
|
-
// TimescaleDB
|
|
64
|
+
// TimescaleDB, PostgreSQL extension, fully compatible
|
|
65
65
|
// ---------------------------------------------------------------------------
|
|
66
66
|
/**
|
|
67
67
|
* TimescaleDB adapter. Timescale is a PostgreSQL extension that adds
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* turbine-orm
|
|
2
|
+
* turbine-orm, YugabyteDB adapter
|
|
3
3
|
*
|
|
4
4
|
* YugabyteDB is a distributed SQL database that speaks the PostgreSQL wire
|
|
5
5
|
* protocol. It supports most PostgreSQL features including json_agg,
|
|
@@ -7,28 +7,28 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Key differences from PostgreSQL that this adapter addresses:
|
|
9
9
|
*
|
|
10
|
-
* 1. **Advisory locks are per-node
|
|
10
|
+
* 1. **Advisory locks are per-node**, `pg_try_advisory_lock()` is supported
|
|
11
11
|
* but only scoped to the tserver node handling the connection. In a
|
|
12
12
|
* multi-node cluster, two concurrent `turbine migrate` runs routed to
|
|
13
13
|
* different nodes would both acquire the "same" advisory lock. This adapter
|
|
14
14
|
* provides a table-based distributed lock using `SELECT FOR UPDATE NOWAIT`
|
|
15
15
|
* which is cluster-wide via YugabyteDB's distributed transactions.
|
|
16
16
|
*
|
|
17
|
-
* 2. **Sequences may have gaps
|
|
17
|
+
* 2. **Sequences may have gaps**, YugabyteDB uses distributed sequences.
|
|
18
18
|
* SERIAL/BIGSERIAL columns work correctly but may produce non-contiguous
|
|
19
19
|
* IDs under concurrent inserts. This is purely cosmetic and does not affect
|
|
20
20
|
* Turbine's behavior.
|
|
21
21
|
*
|
|
22
|
-
* 3. **pg_catalog
|
|
22
|
+
* 3. **pg_catalog**, Mostly complete. `pg_indexes`, `pg_type`, `pg_enum`,
|
|
23
23
|
* `information_schema.columns` all work. Row estimate via `pg_class.reltuples`
|
|
24
24
|
* may be stale or zero on recently created tables (YugabyteDB's stats
|
|
25
25
|
* collection is asynchronous). This adapter provides an override that
|
|
26
26
|
* falls back to `yb_table_properties` when available.
|
|
27
27
|
*
|
|
28
28
|
* Features that work identically to PostgreSQL (no adapter override needed):
|
|
29
|
-
* - `json_agg` / `json_build_object
|
|
30
|
-
* - Correlated subqueries
|
|
31
|
-
* - `COALESCE`, `LIMIT`, `OFFSET`, `ORDER BY
|
|
29
|
+
* - `json_agg` / `json_build_object`, fully supported
|
|
30
|
+
* - Correlated subqueries, fully supported
|
|
31
|
+
* - `COALESCE`, `LIMIT`, `OFFSET`, `ORDER BY`, fully supported
|
|
32
32
|
* - `information_schema` for table/column/constraint introspection
|
|
33
33
|
* - Extended query protocol (parameterized queries, pipeline batching)
|
|
34
34
|
* - Transactions with `SAVEPOINT` (nested transactions)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* turbine-orm
|
|
3
|
+
* turbine-orm, YugabyteDB adapter
|
|
4
4
|
*
|
|
5
5
|
* YugabyteDB is a distributed SQL database that speaks the PostgreSQL wire
|
|
6
6
|
* protocol. It supports most PostgreSQL features including json_agg,
|
|
@@ -8,28 +8,28 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Key differences from PostgreSQL that this adapter addresses:
|
|
10
10
|
*
|
|
11
|
-
* 1. **Advisory locks are per-node
|
|
11
|
+
* 1. **Advisory locks are per-node**, `pg_try_advisory_lock()` is supported
|
|
12
12
|
* but only scoped to the tserver node handling the connection. In a
|
|
13
13
|
* multi-node cluster, two concurrent `turbine migrate` runs routed to
|
|
14
14
|
* different nodes would both acquire the "same" advisory lock. This adapter
|
|
15
15
|
* provides a table-based distributed lock using `SELECT FOR UPDATE NOWAIT`
|
|
16
16
|
* which is cluster-wide via YugabyteDB's distributed transactions.
|
|
17
17
|
*
|
|
18
|
-
* 2. **Sequences may have gaps
|
|
18
|
+
* 2. **Sequences may have gaps**, YugabyteDB uses distributed sequences.
|
|
19
19
|
* SERIAL/BIGSERIAL columns work correctly but may produce non-contiguous
|
|
20
20
|
* IDs under concurrent inserts. This is purely cosmetic and does not affect
|
|
21
21
|
* Turbine's behavior.
|
|
22
22
|
*
|
|
23
|
-
* 3. **pg_catalog
|
|
23
|
+
* 3. **pg_catalog**, Mostly complete. `pg_indexes`, `pg_type`, `pg_enum`,
|
|
24
24
|
* `information_schema.columns` all work. Row estimate via `pg_class.reltuples`
|
|
25
25
|
* may be stale or zero on recently created tables (YugabyteDB's stats
|
|
26
26
|
* collection is asynchronous). This adapter provides an override that
|
|
27
27
|
* falls back to `yb_table_properties` when available.
|
|
28
28
|
*
|
|
29
29
|
* Features that work identically to PostgreSQL (no adapter override needed):
|
|
30
|
-
* - `json_agg` / `json_build_object
|
|
31
|
-
* - Correlated subqueries
|
|
32
|
-
* - `COALESCE`, `LIMIT`, `OFFSET`, `ORDER BY
|
|
30
|
+
* - `json_agg` / `json_build_object`, fully supported
|
|
31
|
+
* - Correlated subqueries, fully supported
|
|
32
|
+
* - `COALESCE`, `LIMIT`, `OFFSET`, `ORDER BY`, fully supported
|
|
33
33
|
* - `information_schema` for table/column/constraint introspection
|
|
34
34
|
* - Extended query protocol (parameterized queries, pipeline batching)
|
|
35
35
|
* - Transactions with `SAVEPOINT` (nested transactions)
|
|
@@ -108,7 +108,7 @@ exports.yugabytedb = {
|
|
|
108
108
|
await client.query(`SELECT lock_id FROM "${LOCK_TABLE}" WHERE lock_id = $1 FOR UPDATE NOWAIT`, [lockId]);
|
|
109
109
|
// Update acquisition metadata for observability
|
|
110
110
|
await client.query(`UPDATE "${LOCK_TABLE}" SET acquired_at = now(), acquired_by = current_user WHERE lock_id = $1`, [lockId]);
|
|
111
|
-
// Leave the transaction open
|
|
111
|
+
// Leave the transaction open, lock is held until releaseLock()
|
|
112
112
|
return true;
|
|
113
113
|
}
|
|
114
114
|
catch (err) {
|
|
@@ -123,7 +123,7 @@ exports.yugabytedb = {
|
|
|
123
123
|
}
|
|
124
124
|
return false;
|
|
125
125
|
}
|
|
126
|
-
// Any other error
|
|
126
|
+
// Any other error, rollback and re-throw
|
|
127
127
|
try {
|
|
128
128
|
await client.query('ROLLBACK');
|
|
129
129
|
}
|
|
@@ -139,7 +139,7 @@ exports.yugabytedb = {
|
|
|
139
139
|
await client.query('COMMIT');
|
|
140
140
|
}
|
|
141
141
|
catch {
|
|
142
|
-
// If commit fails, try rollback
|
|
142
|
+
// If commit fails, try rollback, either way the lock is released
|
|
143
143
|
try {
|
|
144
144
|
await client.query('ROLLBACK');
|
|
145
145
|
}
|
package/dist/cjs/cli/config.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* turbine-orm CLI
|
|
2
|
+
* turbine-orm CLI, Configuration file support
|
|
3
3
|
*
|
|
4
4
|
* Loads turbine.config.ts (or .js/.mjs) via dynamic import.
|
|
5
5
|
* Falls back to CLI args and environment variables.
|
|
@@ -15,6 +15,15 @@ export interface TurbineCliConfig {
|
|
|
15
15
|
include?: string[];
|
|
16
16
|
/** Tables to exclude */
|
|
17
17
|
exclude?: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Rename derived relations, as `{ table: { derivedName: desiredName } }`.
|
|
20
|
+
*
|
|
21
|
+
* Relation names are composed by introspection (a database does not name its
|
|
22
|
+
* relationships), so two foreign keys to the same table produce names nobody
|
|
23
|
+
* would predict, and a port from another ORM that named them differently has
|
|
24
|
+
* to hand-edit every call site. A typo here is an error, not a silent no-op.
|
|
25
|
+
*/
|
|
26
|
+
relationNames?: Record<string, Record<string, string>>;
|
|
18
27
|
/**
|
|
19
28
|
* Extension for the generated `index.ts` sibling imports (F3):
|
|
20
29
|
* `'js'` (`./types.js`), `'none'` (`./types`), or `'auto'` (default:
|
|
@@ -69,7 +78,7 @@ export type TurbineConfig = TurbineCliConfig;
|
|
|
69
78
|
* path rather than a Postgres schema name? `schema` is the Postgres namespace
|
|
70
79
|
* to introspect (default `public`); the schema-builder file goes in `schemaFile`.
|
|
71
80
|
* A value containing a path separator or a JS/TS extension is almost certainly a
|
|
72
|
-
* mis-set `schemaFile
|
|
81
|
+
* mis-set `schemaFile`, introspecting `WHERE table_schema = './turbine/schema.ts'`
|
|
73
82
|
* silently matches zero tables. Used by `turbine generate` to fail loudly.
|
|
74
83
|
*/
|
|
75
84
|
export declare function looksLikeSchemaFilePath(schema: string): boolean;
|
|
@@ -156,6 +165,8 @@ export interface ResolvedConfig {
|
|
|
156
165
|
keepColumnNames: boolean;
|
|
157
166
|
/** Resolved opt-out of the unique-FK → hasOne introspection flip (F2). */
|
|
158
167
|
legacyToManyUniques: boolean;
|
|
168
|
+
/** Resolved derived-relation rename map, or undefined when none is declared. */
|
|
169
|
+
relationNames?: Record<string, Record<string, string>>;
|
|
159
170
|
}
|
|
160
171
|
export interface CliOverrides {
|
|
161
172
|
url?: string;
|
package/dist/cjs/cli/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* turbine-orm CLI
|
|
3
|
+
* turbine-orm CLI, Configuration file support
|
|
4
4
|
*
|
|
5
5
|
* Loads turbine.config.ts (or .js/.mjs) via dynamic import.
|
|
6
6
|
* Falls back to CLI args and environment variables.
|
|
@@ -57,7 +57,7 @@ const node_url_1 = require("node:url");
|
|
|
57
57
|
* path rather than a Postgres schema name? `schema` is the Postgres namespace
|
|
58
58
|
* to introspect (default `public`); the schema-builder file goes in `schemaFile`.
|
|
59
59
|
* A value containing a path separator or a JS/TS extension is almost certainly a
|
|
60
|
-
* mis-set `schemaFile
|
|
60
|
+
* mis-set `schemaFile`, introspecting `WHERE table_schema = './turbine/schema.ts'`
|
|
61
61
|
* silently matches zero tables. Used by `turbine generate` to fail loudly.
|
|
62
62
|
*/
|
|
63
63
|
function looksLikeSchemaFilePath(schema) {
|
|
@@ -203,6 +203,7 @@ function resolveConfig(fileConfig, overrides) {
|
|
|
203
203
|
out: overrides.out ?? fileConfig.out ?? './generated/turbine',
|
|
204
204
|
schema: overrides.schema ?? fileConfig.schema ?? 'public',
|
|
205
205
|
include: overrides.include ?? fileConfig.include ?? [],
|
|
206
|
+
relationNames: fileConfig.relationNames,
|
|
206
207
|
exclude: overrides.exclude ?? fileConfig.exclude ?? [],
|
|
207
208
|
migrationsDir: fileConfig.migrationsDir ?? './turbine/migrations',
|
|
208
209
|
// `seedFile` is canonical (what the docs and `turbine init` use); `seed` is a
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
export type DestructiveKind = 'drop-table' | 'drop-schema' | 'drop-database' | 'drop-owned' | 'drop-matview' | 'drop-column' | 'truncate' | 'delete' | 'update-without-where' | 'alter-column-type' | 'merge-delete';
|
|
25
25
|
export interface DestructiveStatement {
|
|
26
|
-
/** The offending SQL statement (trimmed, possibly long
|
|
26
|
+
/** The offending SQL statement (trimmed, possibly long, display truncated) */
|
|
27
27
|
statement: string;
|
|
28
28
|
kind: DestructiveKind;
|
|
29
29
|
/** Best-effort extracted object name (table, schema, or table.column) */
|
|
@@ -133,7 +133,7 @@ function isEscapeStringPrefix(sql, quoteAt) {
|
|
|
133
133
|
/** Unquote a "quoted" identifier for display. */
|
|
134
134
|
const ident = (raw) => (raw ?? '?').replace(/^"|"$/g, '');
|
|
135
135
|
const IDENT = String.raw `("[^"]+"|[a-zA-Z_][\w$]*)(\.("[^"]+"|[a-zA-Z_][\w$]*))?`;
|
|
136
|
-
/** Ordered rules
|
|
136
|
+
/** Ordered rules, first match per statement wins. */
|
|
137
137
|
const RULES = [
|
|
138
138
|
{
|
|
139
139
|
kind: 'drop-table',
|
package/dist/cjs/cli/index.d.ts
CHANGED
|
@@ -3,21 +3,21 @@
|
|
|
3
3
|
* turbine-orm CLI
|
|
4
4
|
*
|
|
5
5
|
* Commands:
|
|
6
|
-
* turbine init
|
|
7
|
-
* turbine generate | pull
|
|
6
|
+
* turbine init , Initialize a Turbine project
|
|
7
|
+
* turbine generate | pull , Introspect database and generate TypeScript types
|
|
8
8
|
* turbine migrate-from-prisma - Parse a schema.prisma and emit a Prisma->Turbine name map + report
|
|
9
9
|
* turbine push - Apply schema-builder definitions to database (destructive ops gated)
|
|
10
10
|
* turbine migrate create <name> - Create a new SQL migration file (--auto | --from-diff | --recipe <name>)
|
|
11
|
-
* turbine migrate up
|
|
12
|
-
* turbine migrate deploy
|
|
13
|
-
* turbine migrate down
|
|
14
|
-
* turbine migrate status
|
|
15
|
-
* turbine seed
|
|
16
|
-
* turbine status
|
|
11
|
+
* turbine migrate up , Apply pending migrations
|
|
12
|
+
* turbine migrate deploy , Apply pending migrations without prompts
|
|
13
|
+
* turbine migrate down , Rollback last migration
|
|
14
|
+
* turbine migrate status , Show migration status
|
|
15
|
+
* turbine seed , Run seed file
|
|
16
|
+
* turbine status , Show schema summary
|
|
17
17
|
* turbine doctor - Cost-aware missing-FK-index triage (--fix, --json, --no-concurrently, --unused, --audit)
|
|
18
18
|
* turbine studio : Launch local read-only web UI (--demo for a seeded sample DB)
|
|
19
|
-
* turbine mcp
|
|
20
|
-
* turbine observe
|
|
19
|
+
* turbine mcp , Start read-only MCP server over JSON-RPC stdio
|
|
20
|
+
* turbine observe , Launch metrics dashboard (requires TURBINE_OBSERVE_URL)
|
|
21
21
|
*
|
|
22
22
|
* Usage:
|
|
23
23
|
* DATABASE_URL=postgres://... npx turbine generate
|