turbine-orm 0.4.0 → 0.7.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.
Files changed (57) hide show
  1. package/README.md +243 -26
  2. package/dist/cjs/cli/config.js +151 -0
  3. package/dist/cjs/cli/index.js +1176 -0
  4. package/dist/cjs/cli/migrate.js +446 -0
  5. package/dist/cjs/cli/ui.js +233 -0
  6. package/dist/cjs/client.js +512 -0
  7. package/dist/cjs/errors.js +293 -0
  8. package/dist/cjs/generate.js +321 -0
  9. package/dist/cjs/index.js +94 -0
  10. package/dist/cjs/introspect.js +287 -0
  11. package/dist/cjs/package.json +1 -0
  12. package/dist/cjs/pipeline.js +78 -0
  13. package/dist/cjs/query.js +1891 -0
  14. package/dist/cjs/schema-builder.js +238 -0
  15. package/dist/cjs/schema-sql.js +509 -0
  16. package/dist/cjs/schema.js +140 -0
  17. package/dist/cjs/serverless.js +110 -0
  18. package/dist/cli/config.js +6 -16
  19. package/dist/cli/index.js +256 -49
  20. package/dist/cli/migrate.d.ts +35 -6
  21. package/dist/cli/migrate.js +124 -76
  22. package/dist/cli/ui.js +5 -9
  23. package/dist/client.d.ts +87 -3
  24. package/dist/client.js +122 -46
  25. package/dist/errors.d.ts +138 -0
  26. package/dist/errors.js +278 -0
  27. package/dist/generate.js +37 -11
  28. package/dist/index.d.ts +10 -8
  29. package/dist/index.js +15 -11
  30. package/dist/introspect.js +3 -5
  31. package/dist/pipeline.js +8 -1
  32. package/dist/query.d.ts +310 -45
  33. package/dist/query.js +565 -237
  34. package/dist/schema-builder.js +91 -23
  35. package/dist/schema-sql.d.ts +6 -2
  36. package/dist/schema-sql.js +180 -26
  37. package/dist/schema.js +4 -1
  38. package/dist/serverless.d.ts +91 -139
  39. package/dist/serverless.js +86 -173
  40. package/package.json +44 -21
  41. package/dist/cli/config.d.ts.map +0 -1
  42. package/dist/cli/index.d.ts.map +0 -1
  43. package/dist/cli/migrate.d.ts.map +0 -1
  44. package/dist/cli/ui.d.ts.map +0 -1
  45. package/dist/client.d.ts.map +0 -1
  46. package/dist/generate.d.ts.map +0 -1
  47. package/dist/index.d.ts.map +0 -1
  48. package/dist/introspect.d.ts.map +0 -1
  49. package/dist/pipeline.d.ts.map +0 -1
  50. package/dist/query.d.ts.map +0 -1
  51. package/dist/schema-builder.d.ts.map +0 -1
  52. package/dist/schema-sql.d.ts.map +0 -1
  53. package/dist/schema.d.ts.map +0 -1
  54. package/dist/serverless.d.ts.map +0 -1
  55. package/dist/types.d.ts +0 -93
  56. package/dist/types.d.ts.map +0 -1
  57. package/dist/types.js +0 -126
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ /**
3
+ * turbine-orm
4
+ *
5
+ * Turbine TypeScript SDK — type-safe Postgres queries with nested relations
6
+ * and pipeline batching. Feels like Prisma, runs at raw-SQL speed.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * // 1. Generate types from your database:
11
+ * // npx turbine generate
12
+ *
13
+ * // 2. Import the generated client:
14
+ * import { turbine } from './generated/turbine';
15
+ *
16
+ * const db = turbine({ connectionString: process.env.DATABASE_URL });
17
+ *
18
+ * // Type-safe queries with auto-complete
19
+ * const user = await db.users.findUnique({ where: { id: 1 } });
20
+ *
21
+ * // Nested relations in a single query (json_agg, no N+1)
22
+ * const userWithPosts = await db.users.findUnique({
23
+ * where: { id: 1 },
24
+ * with: { posts: { with: { comments: true } } },
25
+ * });
26
+ *
27
+ * // Pipeline: multiple queries in one round-trip
28
+ * const [user, count] = await db.pipeline(
29
+ * db.users.buildFindUnique({ where: { id: 1 } }),
30
+ * db.posts.buildCount({ where: { orgId: 1 } }),
31
+ * );
32
+ *
33
+ * await db.disconnect();
34
+ * ```
35
+ */
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.turbineHttp = exports.schemaToSQLString = exports.schemaToSQL = exports.schemaPush = exports.schemaDiff = exports.table = exports.defineSchema = exports.column = exports.ColumnBuilder = exports.snakeToPascal = exports.snakeToCamel = exports.singularize = exports.pgTypeToTs = exports.pgArrayType = exports.isDateType = exports.camelToSnake = exports.QueryInterface = exports.executePipeline = exports.introspect = exports.generate = exports.wrapPgError = exports.ValidationError = exports.UniqueConstraintError = exports.TurbineErrorCode = exports.TurbineError = exports.TimeoutError = exports.RelationError = exports.NotNullViolationError = exports.NotFoundError = exports.MigrationError = exports.ForeignKeyError = exports.ConnectionError = exports.CircularRelationError = exports.CheckConstraintError = exports.TurbineClient = exports.TransactionClient = void 0;
38
+ // Client
39
+ var client_js_1 = require("./client.js");
40
+ Object.defineProperty(exports, "TransactionClient", { enumerable: true, get: function () { return client_js_1.TransactionClient; } });
41
+ Object.defineProperty(exports, "TurbineClient", { enumerable: true, get: function () { return client_js_1.TurbineClient; } });
42
+ // Error types
43
+ var errors_js_1 = require("./errors.js");
44
+ Object.defineProperty(exports, "CheckConstraintError", { enumerable: true, get: function () { return errors_js_1.CheckConstraintError; } });
45
+ Object.defineProperty(exports, "CircularRelationError", { enumerable: true, get: function () { return errors_js_1.CircularRelationError; } });
46
+ Object.defineProperty(exports, "ConnectionError", { enumerable: true, get: function () { return errors_js_1.ConnectionError; } });
47
+ Object.defineProperty(exports, "ForeignKeyError", { enumerable: true, get: function () { return errors_js_1.ForeignKeyError; } });
48
+ Object.defineProperty(exports, "MigrationError", { enumerable: true, get: function () { return errors_js_1.MigrationError; } });
49
+ Object.defineProperty(exports, "NotFoundError", { enumerable: true, get: function () { return errors_js_1.NotFoundError; } });
50
+ Object.defineProperty(exports, "NotNullViolationError", { enumerable: true, get: function () { return errors_js_1.NotNullViolationError; } });
51
+ Object.defineProperty(exports, "RelationError", { enumerable: true, get: function () { return errors_js_1.RelationError; } });
52
+ Object.defineProperty(exports, "TimeoutError", { enumerable: true, get: function () { return errors_js_1.TimeoutError; } });
53
+ Object.defineProperty(exports, "TurbineError", { enumerable: true, get: function () { return errors_js_1.TurbineError; } });
54
+ Object.defineProperty(exports, "TurbineErrorCode", { enumerable: true, get: function () { return errors_js_1.TurbineErrorCode; } });
55
+ Object.defineProperty(exports, "UniqueConstraintError", { enumerable: true, get: function () { return errors_js_1.UniqueConstraintError; } });
56
+ Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return errors_js_1.ValidationError; } });
57
+ Object.defineProperty(exports, "wrapPgError", { enumerable: true, get: function () { return errors_js_1.wrapPgError; } });
58
+ // Code generation
59
+ var generate_js_1 = require("./generate.js");
60
+ Object.defineProperty(exports, "generate", { enumerable: true, get: function () { return generate_js_1.generate; } });
61
+ // Introspection
62
+ var introspect_js_1 = require("./introspect.js");
63
+ Object.defineProperty(exports, "introspect", { enumerable: true, get: function () { return introspect_js_1.introspect; } });
64
+ // Pipeline
65
+ var pipeline_js_1 = require("./pipeline.js");
66
+ Object.defineProperty(exports, "executePipeline", { enumerable: true, get: function () { return pipeline_js_1.executePipeline; } });
67
+ // Query builder
68
+ var query_js_1 = require("./query.js");
69
+ Object.defineProperty(exports, "QueryInterface", { enumerable: true, get: function () { return query_js_1.QueryInterface; } });
70
+ // Schema utilities
71
+ var schema_js_1 = require("./schema.js");
72
+ Object.defineProperty(exports, "camelToSnake", { enumerable: true, get: function () { return schema_js_1.camelToSnake; } });
73
+ Object.defineProperty(exports, "isDateType", { enumerable: true, get: function () { return schema_js_1.isDateType; } });
74
+ Object.defineProperty(exports, "pgArrayType", { enumerable: true, get: function () { return schema_js_1.pgArrayType; } });
75
+ Object.defineProperty(exports, "pgTypeToTs", { enumerable: true, get: function () { return schema_js_1.pgTypeToTs; } });
76
+ Object.defineProperty(exports, "singularize", { enumerable: true, get: function () { return schema_js_1.singularize; } });
77
+ Object.defineProperty(exports, "snakeToCamel", { enumerable: true, get: function () { return schema_js_1.snakeToCamel; } });
78
+ Object.defineProperty(exports, "snakeToPascal", { enumerable: true, get: function () { return schema_js_1.snakeToPascal; } });
79
+ // Schema builder — define schemas in TypeScript
80
+ var schema_builder_js_1 = require("./schema-builder.js");
81
+ Object.defineProperty(exports, "ColumnBuilder", { enumerable: true, get: function () { return schema_builder_js_1.ColumnBuilder; } });
82
+ Object.defineProperty(exports, "column", { enumerable: true, get: function () { return schema_builder_js_1.column; } });
83
+ Object.defineProperty(exports, "defineSchema", { enumerable: true, get: function () { return schema_builder_js_1.defineSchema; } });
84
+ // Legacy compat (deprecated — use object format with defineSchema)
85
+ Object.defineProperty(exports, "table", { enumerable: true, get: function () { return schema_builder_js_1.table; } });
86
+ // Schema SQL — generate DDL, diff, and push
87
+ var schema_sql_js_1 = require("./schema-sql.js");
88
+ Object.defineProperty(exports, "schemaDiff", { enumerable: true, get: function () { return schema_sql_js_1.schemaDiff; } });
89
+ Object.defineProperty(exports, "schemaPush", { enumerable: true, get: function () { return schema_sql_js_1.schemaPush; } });
90
+ Object.defineProperty(exports, "schemaToSQL", { enumerable: true, get: function () { return schema_sql_js_1.schemaToSQL; } });
91
+ Object.defineProperty(exports, "schemaToSQLString", { enumerable: true, get: function () { return schema_sql_js_1.schemaToSQLString; } });
92
+ // Serverless / edge factory
93
+ var serverless_js_1 = require("./serverless.js");
94
+ Object.defineProperty(exports, "turbineHttp", { enumerable: true, get: function () { return serverless_js_1.turbineHttp; } });
@@ -0,0 +1,287 @@
1
+ "use strict";
2
+ /**
3
+ * turbine-orm — Schema introspection
4
+ *
5
+ * Connects to a live Postgres database, reads information_schema + pg_catalog,
6
+ * and produces a SchemaMetadata object describing every table, column, relation,
7
+ * and index in the target schema.
8
+ *
9
+ * This is the foundation of `npx turbine generate`.
10
+ */
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.introspect = introspect;
16
+ const pg_1 = __importDefault(require("pg"));
17
+ const schema_js_1 = require("./schema.js");
18
+ // ---------------------------------------------------------------------------
19
+ // SQL queries (all parameterized, no interpolation)
20
+ // ---------------------------------------------------------------------------
21
+ const SQL_TABLES = `
22
+ SELECT table_name
23
+ FROM information_schema.tables
24
+ WHERE table_schema = $1
25
+ AND table_type = 'BASE TABLE'
26
+ ORDER BY table_name
27
+ `;
28
+ const SQL_COLUMNS = `
29
+ SELECT
30
+ table_name,
31
+ column_name,
32
+ udt_name,
33
+ data_type,
34
+ is_nullable,
35
+ column_default,
36
+ ordinal_position,
37
+ character_maximum_length
38
+ FROM information_schema.columns
39
+ WHERE table_schema = $1
40
+ ORDER BY table_name, ordinal_position
41
+ `;
42
+ const SQL_PRIMARY_KEYS = `
43
+ SELECT
44
+ tc.table_name,
45
+ kcu.column_name,
46
+ kcu.ordinal_position
47
+ FROM information_schema.table_constraints tc
48
+ JOIN information_schema.key_column_usage kcu
49
+ ON tc.constraint_name = kcu.constraint_name
50
+ AND tc.table_schema = kcu.table_schema
51
+ WHERE tc.constraint_type = 'PRIMARY KEY'
52
+ AND tc.table_schema = $1
53
+ ORDER BY tc.table_name, kcu.ordinal_position
54
+ `;
55
+ const SQL_FOREIGN_KEYS = `
56
+ SELECT
57
+ tc.table_name AS source_table,
58
+ kcu.column_name AS source_column,
59
+ ccu.table_name AS target_table,
60
+ ccu.column_name AS target_column,
61
+ tc.constraint_name
62
+ FROM information_schema.table_constraints tc
63
+ JOIN information_schema.key_column_usage kcu
64
+ ON tc.constraint_name = kcu.constraint_name
65
+ AND tc.table_schema = kcu.table_schema
66
+ JOIN information_schema.constraint_column_usage ccu
67
+ ON tc.constraint_name = ccu.constraint_name
68
+ AND tc.table_schema = ccu.table_schema
69
+ WHERE tc.constraint_type = 'FOREIGN KEY'
70
+ AND tc.table_schema = $1
71
+ `;
72
+ const SQL_UNIQUE_CONSTRAINTS = `
73
+ SELECT
74
+ tc.table_name,
75
+ kcu.column_name
76
+ FROM information_schema.table_constraints tc
77
+ JOIN information_schema.key_column_usage kcu
78
+ ON tc.constraint_name = kcu.constraint_name
79
+ AND tc.table_schema = kcu.table_schema
80
+ WHERE tc.constraint_type = 'UNIQUE'
81
+ AND tc.table_schema = $1
82
+ `;
83
+ const SQL_INDEXES = `
84
+ SELECT tablename, indexname, indexdef
85
+ FROM pg_indexes
86
+ WHERE schemaname = $1
87
+ `;
88
+ const SQL_ENUMS = `
89
+ SELECT t.typname, e.enumlabel
90
+ FROM pg_type t
91
+ JOIN pg_enum e ON t.oid = e.enumtypid
92
+ JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
93
+ WHERE n.nspname = $1
94
+ ORDER BY t.typname, e.enumsortorder
95
+ `;
96
+ // ---------------------------------------------------------------------------
97
+ // Main introspection function
98
+ // ---------------------------------------------------------------------------
99
+ async function introspect(options) {
100
+ const schema = options.schema ?? 'public';
101
+ const pool = new pg_1.default.Pool({
102
+ connectionString: options.connectionString,
103
+ max: 1,
104
+ connectionTimeoutMillis: 10_000,
105
+ });
106
+ try {
107
+ // Run all information_schema queries in parallel
108
+ const [tablesResult, columnsResult, pkResult, fkResult, uniqueResult, indexResult, enumResult] = await Promise.all([
109
+ pool.query(SQL_TABLES, [schema]),
110
+ pool.query(SQL_COLUMNS, [schema]),
111
+ pool.query(SQL_PRIMARY_KEYS, [schema]),
112
+ pool.query(SQL_FOREIGN_KEYS, [schema]),
113
+ pool.query(SQL_UNIQUE_CONSTRAINTS, [schema]),
114
+ pool.query(SQL_INDEXES, [schema]),
115
+ pool.query(SQL_ENUMS, [schema]),
116
+ ]);
117
+ // Filter tables by include/exclude
118
+ let tableNames = tablesResult.rows.map((r) => r.table_name);
119
+ if (options.include?.length) {
120
+ const includeSet = new Set(options.include);
121
+ tableNames = tableNames.filter((t) => includeSet.has(t));
122
+ }
123
+ if (options.exclude?.length) {
124
+ const excludeSet = new Set(options.exclude);
125
+ tableNames = tableNames.filter((t) => !excludeSet.has(t));
126
+ }
127
+ const tableSet = new Set(tableNames);
128
+ // ----- Group columns by table -----
129
+ const columnsByTable = new Map();
130
+ for (const row of columnsResult.rows) {
131
+ const tableName = row.table_name;
132
+ if (!tableSet.has(tableName))
133
+ continue;
134
+ const isNullable = row.is_nullable === 'YES';
135
+ const isArray = row.data_type === 'ARRAY';
136
+ const baseType = isArray ? row.udt_name.slice(1) : row.udt_name;
137
+ const col = {
138
+ name: row.column_name,
139
+ field: (0, schema_js_1.snakeToCamel)(row.column_name),
140
+ pgType: row.udt_name,
141
+ tsType: (0, schema_js_1.pgTypeToTs)(isArray ? row.udt_name : baseType, isNullable),
142
+ nullable: isNullable,
143
+ hasDefault: row.column_default !== null,
144
+ isArray,
145
+ pgArrayType: (0, schema_js_1.pgArrayType)(baseType),
146
+ maxLength: row.character_maximum_length ?? undefined,
147
+ };
148
+ if (!columnsByTable.has(tableName))
149
+ columnsByTable.set(tableName, []);
150
+ columnsByTable.get(tableName).push(col);
151
+ }
152
+ // ----- Group primary keys by table -----
153
+ const pkByTable = new Map();
154
+ for (const row of pkResult.rows) {
155
+ if (!tableSet.has(row.table_name))
156
+ continue;
157
+ if (!pkByTable.has(row.table_name))
158
+ pkByTable.set(row.table_name, []);
159
+ pkByTable.get(row.table_name).push(row.column_name);
160
+ }
161
+ // ----- Group unique constraints by table -----
162
+ const uniqueByTable = new Map();
163
+ for (const row of uniqueResult.rows) {
164
+ if (!tableSet.has(row.table_name))
165
+ continue;
166
+ if (!uniqueByTable.has(row.table_name))
167
+ uniqueByTable.set(row.table_name, []);
168
+ // Each unique constraint may be multi-column; for simplicity, treat as single-col here
169
+ uniqueByTable.get(row.table_name).push([row.column_name]);
170
+ }
171
+ // ----- Group indexes by table -----
172
+ const indexesByTable = new Map();
173
+ for (const row of indexResult.rows) {
174
+ if (!tableSet.has(row.tablename))
175
+ continue;
176
+ if (!indexesByTable.has(row.tablename))
177
+ indexesByTable.set(row.tablename, []);
178
+ const isUnique = row.indexdef.includes('UNIQUE');
179
+ // Extract column names from indexdef (e.g. "CREATE INDEX idx ON tbl USING btree (col1, col2)")
180
+ const colMatch = row.indexdef.match(/\((.+)\)/);
181
+ const columns = colMatch ? colMatch[1].split(',').map((c) => c.trim().replace(/ (ASC|DESC)/i, '')) : [];
182
+ indexesByTable.get(row.tablename).push({
183
+ name: row.indexname,
184
+ columns,
185
+ unique: isUnique,
186
+ definition: row.indexdef,
187
+ });
188
+ }
189
+ // ----- Collect enums -----
190
+ const enums = {};
191
+ for (const row of enumResult.rows) {
192
+ if (!enums[row.typname])
193
+ enums[row.typname] = [];
194
+ enums[row.typname].push(row.enumlabel);
195
+ }
196
+ const foreignKeys = [];
197
+ for (const row of fkResult.rows) {
198
+ if (!tableSet.has(row.source_table) || !tableSet.has(row.target_table))
199
+ continue;
200
+ foreignKeys.push({
201
+ sourceTable: row.source_table,
202
+ sourceColumn: row.source_column,
203
+ targetTable: row.target_table,
204
+ targetColumn: row.target_column,
205
+ });
206
+ }
207
+ // ----- Build relations from foreign keys -----
208
+ // Count FKs per (source, target) pair for disambiguation
209
+ const fkCounts = new Map();
210
+ for (const fk of foreignKeys) {
211
+ const key = `${fk.sourceTable}→${fk.targetTable}`;
212
+ fkCounts.set(key, (fkCounts.get(key) ?? 0) + 1);
213
+ }
214
+ const relationsByTable = new Map();
215
+ for (const fk of foreignKeys) {
216
+ const pairKey = `${fk.sourceTable}→${fk.targetTable}`;
217
+ const needsDisambiguation = (fkCounts.get(pairKey) ?? 0) > 1;
218
+ // --- belongsTo on the source (child) table ---
219
+ // e.g. posts.user_id → users.id creates posts.user (belongsTo)
220
+ const belongsToName = needsDisambiguation
221
+ ? (0, schema_js_1.snakeToCamel)(fk.sourceColumn.replace(/_id$/, ''))
222
+ : (0, schema_js_1.singularize)((0, schema_js_1.snakeToCamel)(fk.targetTable));
223
+ if (!relationsByTable.has(fk.sourceTable))
224
+ relationsByTable.set(fk.sourceTable, {});
225
+ relationsByTable.get(fk.sourceTable)[belongsToName] = {
226
+ type: 'belongsTo',
227
+ name: belongsToName,
228
+ from: fk.sourceTable,
229
+ to: fk.targetTable,
230
+ foreignKey: fk.sourceColumn,
231
+ referenceKey: fk.targetColumn,
232
+ };
233
+ // --- hasMany on the target (parent) table ---
234
+ // e.g. posts.user_id → users.id creates users.posts (hasMany)
235
+ const hasManyName = needsDisambiguation
236
+ ? (0, schema_js_1.snakeToCamel)(`${fk.sourceTable}_by_${fk.sourceColumn.replace(/_id$/, '')}`)
237
+ : (0, schema_js_1.snakeToCamel)(fk.sourceTable);
238
+ if (!relationsByTable.has(fk.targetTable))
239
+ relationsByTable.set(fk.targetTable, {});
240
+ relationsByTable.get(fk.targetTable)[hasManyName] = {
241
+ type: 'hasMany',
242
+ name: hasManyName,
243
+ from: fk.targetTable,
244
+ to: fk.sourceTable,
245
+ foreignKey: fk.sourceColumn,
246
+ referenceKey: fk.targetColumn,
247
+ };
248
+ }
249
+ // ----- Assemble TableMetadata for each table -----
250
+ const tables = {};
251
+ for (const tableName of tableNames) {
252
+ const columns = columnsByTable.get(tableName) ?? [];
253
+ const columnMap = {};
254
+ const reverseColumnMap = {};
255
+ const dateColumns = new Set();
256
+ const pgTypes = {};
257
+ const allColumns = [];
258
+ for (const col of columns) {
259
+ columnMap[col.field] = col.name;
260
+ reverseColumnMap[col.name] = col.field;
261
+ allColumns.push(col.name);
262
+ pgTypes[col.name] = col.pgType;
263
+ const baseType = col.isArray ? col.pgType.slice(1) : col.pgType;
264
+ if ((0, schema_js_1.isDateType)(baseType)) {
265
+ dateColumns.add(col.name);
266
+ }
267
+ }
268
+ tables[tableName] = {
269
+ name: tableName,
270
+ columns,
271
+ columnMap,
272
+ reverseColumnMap,
273
+ dateColumns,
274
+ pgTypes,
275
+ allColumns,
276
+ primaryKey: pkByTable.get(tableName) ?? [],
277
+ uniqueColumns: uniqueByTable.get(tableName) ?? [],
278
+ relations: relationsByTable.get(tableName) ?? {},
279
+ indexes: indexesByTable.get(tableName) ?? [],
280
+ };
281
+ }
282
+ return { tables, enums };
283
+ }
284
+ finally {
285
+ await pool.end();
286
+ }
287
+ }
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * turbine-orm — Pipeline execution
4
+ *
5
+ * Pipelines batch multiple independent queries into a single database round-trip.
6
+ * Instead of N sequential awaits (N round-trips), you get 1 round-trip for all N queries.
7
+ *
8
+ * How it works:
9
+ * 1. Each query method (findUnique, count, etc.) can produce a DeferredQuery descriptor
10
+ * containing the SQL, params, and a transform function.
11
+ * 2. pipeline() collects these descriptors, executes them in a single Postgres
12
+ * pipeline/transaction, and maps each result through its transform.
13
+ *
14
+ * In the production Turbine engine, this would go through the Rust proxy which uses
15
+ * actual Postgres pipeline protocol (libpq PQpipelineEnter). For the TS SDK prototype,
16
+ * we simulate it by running queries concurrently on a single connection or via
17
+ * a multi-statement batch.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.executePipeline = executePipeline;
21
+ const errors_js_1 = require("./errors.js");
22
+ // ---------------------------------------------------------------------------
23
+ // Pipeline executor
24
+ // ---------------------------------------------------------------------------
25
+ /**
26
+ * Execute multiple deferred queries in a single batch.
27
+ *
28
+ * Uses a single connection from the pool and runs all queries within
29
+ * a transaction to guarantee consistency and minimize round-trips.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const [user, count, posts] = await executePipeline(pool, [
34
+ * db.users.buildFindUnique({ where: { id: 1 } }),
35
+ * db.posts.buildCount({ where: { orgId: 1 } }),
36
+ * db.posts.buildFindMany({ where: { userId: 1 }, limit: 10 }),
37
+ * ]);
38
+ * ```
39
+ */
40
+ async function executePipeline(pool, queries) {
41
+ if (queries.length === 0) {
42
+ return [];
43
+ }
44
+ // Acquire a single connection for the entire batch
45
+ const client = await pool.connect();
46
+ try {
47
+ // Wrap in a transaction for consistency
48
+ await client.query('BEGIN');
49
+ // Execute all queries on the same connection — in sequence on a single
50
+ // connection this avoids pool checkout overhead, and the Postgres server
51
+ // processes them as a tight batch.
52
+ //
53
+ // Execute queries sequentially on the same connection to avoid the
54
+ // "already executing a query" deprecation in pg@8. This is still faster
55
+ // than separate pool checkouts because we skip N-1 acquire/release cycles.
56
+ // Future: use actual Postgres pipeline protocol for true pipelining.
57
+ const results = [];
58
+ for (const q of queries) {
59
+ let raw;
60
+ try {
61
+ raw = await client.query(q.sql, q.params);
62
+ }
63
+ catch (err) {
64
+ throw (0, errors_js_1.wrapPgError)(err);
65
+ }
66
+ results.push(q.transform(raw));
67
+ }
68
+ await client.query('COMMIT');
69
+ return results;
70
+ }
71
+ catch (err) {
72
+ await client.query('ROLLBACK');
73
+ throw err;
74
+ }
75
+ finally {
76
+ client.release();
77
+ }
78
+ }