turbine-orm 0.9.1 → 0.9.2
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 +8 -3
- package/dist/cjs/cli/migrate.js +2 -2
- package/dist/cjs/cli/studio.js +7 -7
- package/dist/cjs/client.js +3 -3
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/query/builder.js +2641 -0
- package/dist/cjs/query/index.js +20 -0
- package/dist/cjs/query/types.js +7 -0
- package/dist/cjs/query/utils.js +122 -0
- package/dist/cjs/schema-sql.js +26 -26
- package/dist/cli/migrate.js +1 -1
- package/dist/cli/studio.js +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/pipeline-submittable.d.ts +1 -1
- package/dist/pipeline.d.ts +1 -1
- package/dist/query/builder.d.ts +498 -0
- package/dist/query/builder.js +2638 -0
- package/dist/query/index.d.ts +13 -0
- package/dist/query/index.js +10 -0
- package/dist/query/types.d.ts +365 -0
- package/dist/query/types.js +7 -0
- package/dist/query/utils.d.ts +60 -0
- package/dist/query/utils.js +114 -0
- package/dist/schema-sql.js +1 -1
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# turbine-orm
|
|
2
2
|
|
|
3
|
-
Postgres-
|
|
3
|
+
Postgres ORM built for the edge. One runtime dependency. Built-in read-only Studio. Code-first and DB-first schema workflows in the same CLI. Runs on **Neon, Vercel Postgres, Cloudflare Hyperdrive, Supabase**, and any pg-compatible driver.
|
|
4
4
|
|
|
5
5
|
```
|
|
6
6
|
npm install turbine-orm
|
|
@@ -8,9 +8,14 @@ npm install turbine-orm
|
|
|
8
8
|
|
|
9
9
|
## Why Turbine?
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The elevator pitch: **a Prisma-like DX without Prisma's engine, a Drizzle-class runtime footprint, and the only built-in read-only Studio in the TS ORM ecosystem.** Four things bundled together that no other ORM bundles:
|
|
12
12
|
|
|
13
|
-
**One
|
|
13
|
+
1. **One runtime dependency (`pg`).** No engine binary, no WASM adapter, no code-generation DSL. ~110 KB on npm. 5 KB on the edge entry.
|
|
14
|
+
2. **First-class edge support.** `turbineHttp(pool, schema)` — one import swap — and the full API runs on Neon, Vercel Postgres, Cloudflare Hyperdrive, Supabase. No extra adapter package, no WASM bundle.
|
|
15
|
+
3. **Built-in read-only Studio.** `npx turbine studio` spins up a loopback-bound, token-authed web UI with `BEGIN READ ONLY` + statement-stacking guard. DBA-approvable. No separate install.
|
|
16
|
+
4. **Code-first and DB-first in the same CLI.** `defineSchema()` in TypeScript *or* `npx turbine pull` against a live database — same generated client, same migrations runner. Prisma forces the DSL; Drizzle is code-only.
|
|
17
|
+
|
|
18
|
+
Plus the architectural bits you'd expect: pipeline batching (N queries in one round-trip via the pg extended-query protocol), `json_agg`-based nested relation loading (same technique Drizzle and Prisma 7 use — no N+1), deep `with` type inference, streaming cursors, typed error hierarchy with `isRetryable` discriminants, middleware.
|
|
14
19
|
|
|
15
20
|
## Benchmarks
|
|
16
21
|
|
package/dist/cjs/cli/migrate.js
CHANGED
|
@@ -33,12 +33,12 @@ const node_fs_1 = require("node:fs");
|
|
|
33
33
|
const node_path_1 = require("node:path");
|
|
34
34
|
const pg_1 = __importDefault(require("pg"));
|
|
35
35
|
const errors_js_1 = require("../errors.js");
|
|
36
|
-
const
|
|
36
|
+
const index_js_1 = require("../query/index.js");
|
|
37
37
|
// ---------------------------------------------------------------------------
|
|
38
38
|
// Tracking table management
|
|
39
39
|
// ---------------------------------------------------------------------------
|
|
40
40
|
const TRACKING_TABLE = '_turbine_migrations';
|
|
41
|
-
const QUOTED_TRACKING_TABLE = (0,
|
|
41
|
+
const QUOTED_TRACKING_TABLE = (0, index_js_1.quoteIdent)(TRACKING_TABLE);
|
|
42
42
|
const CREATE_TRACKING_TABLE = `
|
|
43
43
|
CREATE TABLE IF NOT EXISTS ${QUOTED_TRACKING_TABLE} (
|
|
44
44
|
id SERIAL PRIMARY KEY,
|
package/dist/cjs/cli/studio.js
CHANGED
|
@@ -38,7 +38,7 @@ const node_os_1 = require("node:os");
|
|
|
38
38
|
const node_path_1 = require("node:path");
|
|
39
39
|
const pg_1 = __importDefault(require("pg"));
|
|
40
40
|
const introspect_js_1 = require("../introspect.js");
|
|
41
|
-
const
|
|
41
|
+
const index_js_1 = require("../query/index.js");
|
|
42
42
|
const studio_ui_generated_js_1 = require("./studio-ui.generated.js");
|
|
43
43
|
// ---------------------------------------------------------------------------
|
|
44
44
|
// Main entry point
|
|
@@ -259,10 +259,10 @@ async function apiTableRows(res, ctx, rawTableName, params) {
|
|
|
259
259
|
if (orderByRaw) {
|
|
260
260
|
const col = resolveColumnName(table, orderByRaw);
|
|
261
261
|
if (col)
|
|
262
|
-
orderByClause = `ORDER BY ${(0,
|
|
262
|
+
orderByClause = `ORDER BY ${(0, index_js_1.quoteIdent)(col)} ${dir}`;
|
|
263
263
|
}
|
|
264
264
|
if (!orderByClause && table.primaryKey.length > 0 && table.primaryKey[0]) {
|
|
265
|
-
orderByClause = `ORDER BY ${(0,
|
|
265
|
+
orderByClause = `ORDER BY ${(0, index_js_1.quoteIdent)(table.primaryKey[0])} ${dir}`;
|
|
266
266
|
}
|
|
267
267
|
// Full-text-ish search: ILIKE across text/varchar columns. The value is
|
|
268
268
|
// parameterized so injection is impossible. Each query gets its own
|
|
@@ -276,7 +276,7 @@ async function apiTableRows(res, ctx, rawTableName, params) {
|
|
|
276
276
|
let mainWhere = '';
|
|
277
277
|
if (hasSearch && pattern !== null) {
|
|
278
278
|
mainValues.push(pattern);
|
|
279
|
-
const conds = textColumns.map((c) => `${(0,
|
|
279
|
+
const conds = textColumns.map((c) => `${(0, index_js_1.quoteIdent)(c)} ILIKE $3`);
|
|
280
280
|
mainWhere = `WHERE (${conds.join(' OR ')})`;
|
|
281
281
|
}
|
|
282
282
|
// Count query: $1 = pattern (if search)
|
|
@@ -284,10 +284,10 @@ async function apiTableRows(res, ctx, rawTableName, params) {
|
|
|
284
284
|
let countWhere = '';
|
|
285
285
|
if (hasSearch && pattern !== null) {
|
|
286
286
|
countValues.push(pattern);
|
|
287
|
-
const conds = textColumns.map((c) => `${(0,
|
|
287
|
+
const conds = textColumns.map((c) => `${(0, index_js_1.quoteIdent)(c)} ILIKE $1`);
|
|
288
288
|
countWhere = `WHERE (${conds.join(' OR ')})`;
|
|
289
289
|
}
|
|
290
|
-
const qualifiedTable = `${(0,
|
|
290
|
+
const qualifiedTable = `${(0, index_js_1.quoteIdent)(ctx.options.schema)}.${(0, index_js_1.quoteIdent)(table.name)}`;
|
|
291
291
|
const sql = `SELECT * FROM ${qualifiedTable} ${mainWhere} ${orderByClause} LIMIT $1 OFFSET $2`;
|
|
292
292
|
const countSql = `SELECT COUNT(*)::text AS count FROM ${qualifiedTable} ${countWhere}`;
|
|
293
293
|
const client = await ctx.pool.connect();
|
|
@@ -397,7 +397,7 @@ async function apiBuilder(req, res, ctx) {
|
|
|
397
397
|
}
|
|
398
398
|
let deferred;
|
|
399
399
|
try {
|
|
400
|
-
const qi = new
|
|
400
|
+
const qi = new index_js_1.QueryInterface(ctx.pool, tableName, ctx.metadata, [], {
|
|
401
401
|
warnOnUnlimited: false,
|
|
402
402
|
sqlCache: false,
|
|
403
403
|
preparedStatements: false,
|
package/dist/cjs/client.js
CHANGED
|
@@ -30,7 +30,7 @@ exports.TurbineClient = exports.TransactionClient = void 0;
|
|
|
30
30
|
const pg_1 = __importDefault(require("pg"));
|
|
31
31
|
const errors_js_1 = require("./errors.js");
|
|
32
32
|
const pipeline_js_1 = require("./pipeline.js");
|
|
33
|
-
const
|
|
33
|
+
const index_js_1 = require("./query/index.js");
|
|
34
34
|
/** Maps isolation level names to SQL */
|
|
35
35
|
const ISOLATION_LEVELS = {
|
|
36
36
|
ReadUncommitted: 'READ UNCOMMITTED',
|
|
@@ -79,7 +79,7 @@ class TransactionClient {
|
|
|
79
79
|
// Create a QueryInterface that uses the transaction client as its "pool"
|
|
80
80
|
// We use a proxy pool that routes queries through the transaction client
|
|
81
81
|
const txPool = this.createTxPool();
|
|
82
|
-
qi = new
|
|
82
|
+
qi = new index_js_1.QueryInterface(txPool, name, this.schema, this.middlewares, this.queryOptions);
|
|
83
83
|
this.tableCache.set(name, qi);
|
|
84
84
|
}
|
|
85
85
|
return qi;
|
|
@@ -306,7 +306,7 @@ class TurbineClient {
|
|
|
306
306
|
table(name) {
|
|
307
307
|
let qi = this.tableCache.get(name);
|
|
308
308
|
if (!qi) {
|
|
309
|
-
qi = new
|
|
309
|
+
qi = new index_js_1.QueryInterface(this.pool, name, this.schema, this.middlewares, this.queryOptions);
|
|
310
310
|
this.tableCache.set(name, qi);
|
|
311
311
|
}
|
|
312
312
|
return qi;
|
package/dist/cjs/index.js
CHANGED
|
@@ -71,8 +71,8 @@ var pipeline_js_1 = require("./pipeline.js");
|
|
|
71
71
|
Object.defineProperty(exports, "executePipeline", { enumerable: true, get: function () { return pipeline_js_1.executePipeline; } });
|
|
72
72
|
Object.defineProperty(exports, "pipelineSupported", { enumerable: true, get: function () { return pipeline_js_1.pipelineSupported; } });
|
|
73
73
|
// Query builder
|
|
74
|
-
var
|
|
75
|
-
Object.defineProperty(exports, "QueryInterface", { enumerable: true, get: function () { return
|
|
74
|
+
var index_js_1 = require("./query/index.js");
|
|
75
|
+
Object.defineProperty(exports, "QueryInterface", { enumerable: true, get: function () { return index_js_1.QueryInterface; } });
|
|
76
76
|
// Schema utilities
|
|
77
77
|
var schema_js_1 = require("./schema.js");
|
|
78
78
|
Object.defineProperty(exports, "camelToSnake", { enumerable: true, get: function () { return schema_js_1.camelToSnake; } });
|