turbine-orm 0.13.0 → 0.13.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/dist/cjs/dialect.js +2 -1
- package/dist/cjs/query/builder.js +17 -7
- package/dist/dialect.js +2 -1
- package/dist/query/builder.d.ts +5 -0
- package/dist/query/builder.js +17 -7
- package/package.json +8 -3
package/dist/cjs/dialect.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.postgresDialect = void 0;
|
|
11
|
+
const errors_js_1 = require("./errors.js");
|
|
11
12
|
/** PostgreSQL implementation of the dialect contract. */
|
|
12
13
|
exports.postgresDialect = {
|
|
13
14
|
name: 'postgresql',
|
|
@@ -41,7 +42,7 @@ exports.postgresDialect = {
|
|
|
41
42
|
},
|
|
42
43
|
buildBulkInsertStatement(input) {
|
|
43
44
|
if (!input.columnArrayTypes || input.columnArrayTypes.length !== input.columns.length) {
|
|
44
|
-
throw new
|
|
45
|
+
throw new errors_js_1.ValidationError('PostgreSQL bulk insert requires one array type per column');
|
|
45
46
|
}
|
|
46
47
|
const columnArrays = input.columns.map((_, columnIndex) => input.rowValues.map((row) => row[columnIndex]));
|
|
47
48
|
const unnestArgs = input.columns.map((_, i) => `${this.paramPlaceholder(i + 1)}::${input.columnArrayTypes[i]}`);
|
|
@@ -1538,8 +1538,7 @@ class QueryInterface {
|
|
|
1538
1538
|
}
|
|
1539
1539
|
// Array filter
|
|
1540
1540
|
if (typeof value === 'object' && !Array.isArray(value) && isArrayFilter(value)) {
|
|
1541
|
-
|
|
1542
|
-
parts.push(`${key}:arr(${aKeys.join(',')})`);
|
|
1541
|
+
parts.push(`${key}:arr(${this.fingerprintArrayFilter(value)})`);
|
|
1543
1542
|
continue;
|
|
1544
1543
|
}
|
|
1545
1544
|
// Plain equality
|
|
@@ -1547,6 +1546,15 @@ class QueryInterface {
|
|
|
1547
1546
|
}
|
|
1548
1547
|
return parts.join('&');
|
|
1549
1548
|
}
|
|
1549
|
+
/**
|
|
1550
|
+
* Produce a value-invariant fingerprint for array filters while preserving
|
|
1551
|
+
* parameterless boolean operators that change SQL shape.
|
|
1552
|
+
*/
|
|
1553
|
+
fingerprintArrayFilter(filter) {
|
|
1554
|
+
const keys = Object.keys(filter).sort();
|
|
1555
|
+
const suffix = filter.isEmpty === undefined ? '' : `:empty=${filter.isEmpty ? 'true' : 'false'}`;
|
|
1556
|
+
return `${keys.join(',')}${suffix}`;
|
|
1557
|
+
}
|
|
1550
1558
|
/**
|
|
1551
1559
|
* Fingerprint a relation filter sub-where for some/every/none.
|
|
1552
1560
|
*/
|
|
@@ -1742,8 +1750,10 @@ class QueryInterface {
|
|
|
1742
1750
|
if (!spec)
|
|
1743
1751
|
continue;
|
|
1744
1752
|
const relDef = meta.relations[relName];
|
|
1745
|
-
if (!relDef)
|
|
1753
|
+
if (!relDef) {
|
|
1754
|
+
parts.push(`unknown:${relName}`);
|
|
1746
1755
|
continue;
|
|
1756
|
+
}
|
|
1747
1757
|
if (spec === true) {
|
|
1748
1758
|
parts.push(relName);
|
|
1749
1759
|
continue;
|
|
@@ -2653,12 +2663,12 @@ class QueryInterface {
|
|
|
2653
2663
|
clauses.push(`${column} && ${this.p(params.length)}::${elementType}[]`);
|
|
2654
2664
|
}
|
|
2655
2665
|
if (filter.isEmpty === true) {
|
|
2656
|
-
//
|
|
2657
|
-
clauses.push(`
|
|
2666
|
+
// Treat NULL and empty arrays as empty for Prisma-compatible ergonomics.
|
|
2667
|
+
clauses.push(`COALESCE(cardinality(${column}), 0) = 0`);
|
|
2658
2668
|
}
|
|
2659
2669
|
else if (filter.isEmpty === false) {
|
|
2660
|
-
//
|
|
2661
|
-
clauses.push(`
|
|
2670
|
+
// Require at least one element; excludes both NULL and ARRAY[] values.
|
|
2671
|
+
clauses.push(`cardinality(${column}) > 0`);
|
|
2662
2672
|
}
|
|
2663
2673
|
return clauses;
|
|
2664
2674
|
}
|
package/dist/dialect.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* PostgreSQL-native by default, but query generation now depends on this
|
|
6
6
|
* contract for the SQL primitives that vary across MySQL and SQLite.
|
|
7
7
|
*/
|
|
8
|
+
import { ValidationError } from './errors.js';
|
|
8
9
|
/** PostgreSQL implementation of the dialect contract. */
|
|
9
10
|
export const postgresDialect = {
|
|
10
11
|
name: 'postgresql',
|
|
@@ -38,7 +39,7 @@ export const postgresDialect = {
|
|
|
38
39
|
},
|
|
39
40
|
buildBulkInsertStatement(input) {
|
|
40
41
|
if (!input.columnArrayTypes || input.columnArrayTypes.length !== input.columns.length) {
|
|
41
|
-
throw new
|
|
42
|
+
throw new ValidationError('PostgreSQL bulk insert requires one array type per column');
|
|
42
43
|
}
|
|
43
44
|
const columnArrays = input.columns.map((_, columnIndex) => input.rowValues.map((row) => row[columnIndex]));
|
|
44
45
|
const unnestArgs = input.columns.map((_, i) => `${this.paramPlaceholder(i + 1)}::${input.columnArrayTypes[i]}`);
|
package/dist/query/builder.d.ts
CHANGED
|
@@ -258,6 +258,11 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
258
258
|
* @internal Exposed as package-private for testing via class access.
|
|
259
259
|
*/
|
|
260
260
|
fingerprintWhere(where: Record<string, unknown>): string;
|
|
261
|
+
/**
|
|
262
|
+
* Produce a value-invariant fingerprint for array filters while preserving
|
|
263
|
+
* parameterless boolean operators that change SQL shape.
|
|
264
|
+
*/
|
|
265
|
+
private fingerprintArrayFilter;
|
|
261
266
|
/**
|
|
262
267
|
* Fingerprint a relation filter sub-where for some/every/none.
|
|
263
268
|
*/
|
package/dist/query/builder.js
CHANGED
|
@@ -1535,8 +1535,7 @@ export class QueryInterface {
|
|
|
1535
1535
|
}
|
|
1536
1536
|
// Array filter
|
|
1537
1537
|
if (typeof value === 'object' && !Array.isArray(value) && isArrayFilter(value)) {
|
|
1538
|
-
|
|
1539
|
-
parts.push(`${key}:arr(${aKeys.join(',')})`);
|
|
1538
|
+
parts.push(`${key}:arr(${this.fingerprintArrayFilter(value)})`);
|
|
1540
1539
|
continue;
|
|
1541
1540
|
}
|
|
1542
1541
|
// Plain equality
|
|
@@ -1544,6 +1543,15 @@ export class QueryInterface {
|
|
|
1544
1543
|
}
|
|
1545
1544
|
return parts.join('&');
|
|
1546
1545
|
}
|
|
1546
|
+
/**
|
|
1547
|
+
* Produce a value-invariant fingerprint for array filters while preserving
|
|
1548
|
+
* parameterless boolean operators that change SQL shape.
|
|
1549
|
+
*/
|
|
1550
|
+
fingerprintArrayFilter(filter) {
|
|
1551
|
+
const keys = Object.keys(filter).sort();
|
|
1552
|
+
const suffix = filter.isEmpty === undefined ? '' : `:empty=${filter.isEmpty ? 'true' : 'false'}`;
|
|
1553
|
+
return `${keys.join(',')}${suffix}`;
|
|
1554
|
+
}
|
|
1547
1555
|
/**
|
|
1548
1556
|
* Fingerprint a relation filter sub-where for some/every/none.
|
|
1549
1557
|
*/
|
|
@@ -1739,8 +1747,10 @@ export class QueryInterface {
|
|
|
1739
1747
|
if (!spec)
|
|
1740
1748
|
continue;
|
|
1741
1749
|
const relDef = meta.relations[relName];
|
|
1742
|
-
if (!relDef)
|
|
1750
|
+
if (!relDef) {
|
|
1751
|
+
parts.push(`unknown:${relName}`);
|
|
1743
1752
|
continue;
|
|
1753
|
+
}
|
|
1744
1754
|
if (spec === true) {
|
|
1745
1755
|
parts.push(relName);
|
|
1746
1756
|
continue;
|
|
@@ -2650,12 +2660,12 @@ export class QueryInterface {
|
|
|
2650
2660
|
clauses.push(`${column} && ${this.p(params.length)}::${elementType}[]`);
|
|
2651
2661
|
}
|
|
2652
2662
|
if (filter.isEmpty === true) {
|
|
2653
|
-
//
|
|
2654
|
-
clauses.push(`
|
|
2663
|
+
// Treat NULL and empty arrays as empty for Prisma-compatible ergonomics.
|
|
2664
|
+
clauses.push(`COALESCE(cardinality(${column}), 0) = 0`);
|
|
2655
2665
|
}
|
|
2656
2666
|
else if (filter.isEmpty === false) {
|
|
2657
|
-
//
|
|
2658
|
-
clauses.push(`
|
|
2667
|
+
// Require at least one element; excludes both NULL and ARRAY[] values.
|
|
2668
|
+
clauses.push(`cardinality(${column}) > 0`);
|
|
2659
2669
|
}
|
|
2660
2670
|
return clauses;
|
|
2661
2671
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turbine-orm",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"description": "Postgres-native TypeScript ORM — runs on Neon, Vercel Postgres, Cloudflare, Supabase. Streaming cursors, typed errors, single-query nested relations. 1 dependency, ~110KB",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
],
|
|
42
42
|
"sideEffects": false,
|
|
43
43
|
"scripts": {
|
|
44
|
-
"prebuild": "
|
|
44
|
+
"prebuild": "npm run gen:studio",
|
|
45
45
|
"build": "tsc && tsc --project tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
|
|
46
46
|
"dev": "tsc --watch",
|
|
47
47
|
"typecheck": "tsc --noEmit --project tsconfig.test.json",
|
|
@@ -63,7 +63,12 @@
|
|
|
63
63
|
"db:reset": "psql $DATABASE_URL -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;' && npm run db:seed",
|
|
64
64
|
"site:dev": "cd site && npm run dev",
|
|
65
65
|
"site:build": "cd site && npm run build",
|
|
66
|
-
"site:deploy": "cd site && vercel --prod"
|
|
66
|
+
"site:deploy": "cd site && vercel --prod",
|
|
67
|
+
"gen:studio": "node scripts/build-studio-ui.mjs",
|
|
68
|
+
"pretypecheck": "npm run gen:studio",
|
|
69
|
+
"pretest": "npm run gen:studio",
|
|
70
|
+
"pretest:unit": "npm run gen:studio",
|
|
71
|
+
"pretest:coverage": "npm run gen:studio"
|
|
67
72
|
},
|
|
68
73
|
"engines": {
|
|
69
74
|
"node": ">=18.0.0"
|