turbine-orm 0.32.2 → 0.34.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 +2 -2
- package/dist/cjs/dialect.js +1 -0
- package/dist/cjs/index-advisor.js +0 -0
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/mssql.js +3 -0
- package/dist/cjs/mysql.js +3 -0
- package/dist/cjs/optional-peer-import.cjs +28 -0
- package/dist/cjs/powdb-introspect.js +222 -0
- package/dist/cjs/powdb.js +446 -55
- package/dist/cjs/powql.js +566 -111
- package/dist/cjs/query/builder.js +136 -53
- package/dist/cjs/query/filters.js +4 -4
- package/dist/cjs/schema-builder.js +16 -0
- package/dist/cjs/schema-metadata.js +81 -10
- package/dist/cjs/sqlite.js +2 -0
- package/dist/dialect.d.ts +7 -0
- package/dist/dialect.js +1 -0
- package/dist/index-advisor.d.ts +15 -1
- package/dist/index-advisor.js +0 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mssql.js +3 -0
- package/dist/mysql.js +3 -0
- package/dist/optional-peer-import.cjs +28 -0
- package/dist/optional-peer-import.d.cts +19 -0
- package/dist/powdb-introspect.d.ts +84 -0
- package/dist/powdb-introspect.js +219 -0
- package/dist/powdb.d.ts +249 -13
- package/dist/powdb.js +438 -54
- package/dist/powql.d.ts +113 -6
- package/dist/powql.js +568 -113
- package/dist/query/builder.d.ts +11 -0
- package/dist/query/builder.js +136 -53
- package/dist/query/filters.d.ts +3 -3
- package/dist/query/filters.js +4 -4
- package/dist/query/types.d.ts +50 -6
- package/dist/schema-builder.d.ts +46 -1
- package/dist/schema-builder.js +15 -0
- package/dist/schema-metadata.d.ts +13 -7
- package/dist/schema-metadata.js +82 -11
- package/dist/schema.d.ts +25 -0
- package/dist/sqlite.js +2 -0
- package/package.json +3 -3
package/dist/schema-metadata.js
CHANGED
|
@@ -24,10 +24,12 @@
|
|
|
24
24
|
* the same conservative auto-`manyToMany` treatment as introspection.
|
|
25
25
|
* - Explicit `manyToMany` declarations on the SchemaDef are merged via
|
|
26
26
|
* {@link applyManyToManyRelations} (additive, never clobbering).
|
|
27
|
-
* - `indexes`
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
27
|
+
* - `indexes` carries any declared `TableDef.indexes` (plain column and/or
|
|
28
|
+
* PowDB doc-field expression indexes); a table with none declared gets
|
|
29
|
+
* `[]`, which keeps `schemaHasIndexInfo()` false so the index advisor and
|
|
30
|
+
* the dev-mode missing-index warning stay silent instead of producing
|
|
31
|
+
* blanket false positives. Doc-field (docPath) indexes are ignored by the
|
|
32
|
+
* advisor, so a doc-only index set never flips `schemaHasIndexInfo()`.
|
|
31
33
|
*
|
|
32
34
|
* @example
|
|
33
35
|
* ```ts
|
|
@@ -42,9 +44,10 @@
|
|
|
42
44
|
* // → usable anywhere SchemaMetadata is expected (e.g. turbinePowDB, TurbineClient)
|
|
43
45
|
* ```
|
|
44
46
|
*/
|
|
47
|
+
import { ValidationError } from './errors.js';
|
|
45
48
|
import { addAutoManyToManyRelations, buildRelationsFromForeignKeys, isUnknownTsType, } from './introspect.js';
|
|
46
49
|
import { camelToSnake, isDateType, pgArrayType, pgTypeToTs, } from './schema.js';
|
|
47
|
-
import { applyManyToManyRelations } from './schema-builder.js';
|
|
50
|
+
import { applyManyToManyRelations, isDocFieldIndexDef, } from './schema-builder.js';
|
|
48
51
|
// ---------------------------------------------------------------------------
|
|
49
52
|
// DDL type → Postgres udt_name (what introspection reads from the catalog)
|
|
50
53
|
// ---------------------------------------------------------------------------
|
|
@@ -94,6 +97,67 @@ function resolveColumnName(raw, target) {
|
|
|
94
97
|
return camelToSnake(raw);
|
|
95
98
|
}
|
|
96
99
|
// ---------------------------------------------------------------------------
|
|
100
|
+
// Index declarations → IndexMetadata
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
/**
|
|
103
|
+
* Render a doc-field JSON path into an illustrative PowQL fragment for the
|
|
104
|
+
* `IndexMetadata.definition` field (debuggability only; the authoritative,
|
|
105
|
+
* lexer-exact emission lives in `powqlSchemaDDL`). String segments are shown
|
|
106
|
+
* double-quoted, integer array indexes bare.
|
|
107
|
+
*/
|
|
108
|
+
function docPathFragment(column, path) {
|
|
109
|
+
const segs = path.map((s) => (typeof s === 'number' ? `->${s}` : `->"${s}"`)).join('');
|
|
110
|
+
return `(.${column}${segs})`;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Convert a table's {@link SchemaIndexDef} list into {@link IndexMetadata}.
|
|
114
|
+
* A doc-field index carries `docPath` and `columns: [<json column>]`; a plain
|
|
115
|
+
* column index carries its snake_case column list and no `docPath`. Names are
|
|
116
|
+
* auto-derived (`<table>_<cols>_idx`) when not supplied.
|
|
117
|
+
*/
|
|
118
|
+
function mapIndexes(tableDef, declared) {
|
|
119
|
+
if (!declared || declared.length === 0)
|
|
120
|
+
return [];
|
|
121
|
+
const out = [];
|
|
122
|
+
for (const idx of declared) {
|
|
123
|
+
if (isDocFieldIndexDef(idx)) {
|
|
124
|
+
const column = camelToSnake(idx.docField);
|
|
125
|
+
const segPart = idx.path.map((s) => (typeof s === 'number' ? String(s) : s)).join('_');
|
|
126
|
+
const name = idx.name ?? `${tableDef.name}_${column}_${segPart}_idx`;
|
|
127
|
+
// Validate numeric (array-index) segments up front: PowDB rejects a
|
|
128
|
+
// negative / fractional / NaN JSON-path index at migration time with an
|
|
129
|
+
// opaque parse error, so fail here with a typed ValidationError naming the
|
|
130
|
+
// index instead of emitting malformed PowQL later.
|
|
131
|
+
for (const seg of idx.path) {
|
|
132
|
+
if (typeof seg === 'number' && (!Number.isInteger(seg) || seg < 0)) {
|
|
133
|
+
throw new ValidationError(`[turbine] Doc-field index "${name}" on "${tableDef.name}": array-index path segment ${seg} must be a ` +
|
|
134
|
+
'non-negative integer (a JSON array index). Use a string for an object key.');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
out.push({
|
|
138
|
+
name,
|
|
139
|
+
columns: [column],
|
|
140
|
+
unique: idx.unique ?? false,
|
|
141
|
+
definition: `${idx.unique ? 'unique ' : 'index '}${docPathFragment(column, idx.path)}`,
|
|
142
|
+
docPath: [...idx.path],
|
|
143
|
+
declared: true,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
const columns = idx.columns.map(camelToSnake);
|
|
148
|
+
const name = idx.name ?? `${tableDef.name}_${columns.join('_')}_idx`;
|
|
149
|
+
out.push({
|
|
150
|
+
name,
|
|
151
|
+
columns,
|
|
152
|
+
unique: idx.unique ?? false,
|
|
153
|
+
definition: `${idx.unique ? 'unique ' : 'index '}(${columns.join(', ')})`,
|
|
154
|
+
declared: true,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
97
161
|
// The converter
|
|
98
162
|
// ---------------------------------------------------------------------------
|
|
99
163
|
/**
|
|
@@ -119,10 +183,14 @@ function resolveColumnName(raw, target) {
|
|
|
119
183
|
* - Explicit `manyToMany` declarations → merged additively.
|
|
120
184
|
* - Schema-level `enums`.
|
|
121
185
|
*
|
|
186
|
+
* What maps (continued):
|
|
187
|
+
* - `indexes` → declared `TableDef.indexes` become `IndexMetadata` (plain
|
|
188
|
+
* column indexes and PowDB doc-field expression indexes, the latter
|
|
189
|
+
* carrying `docPath`). A table with no declared indexes gets `[]`, keeping
|
|
190
|
+
* `schemaHasIndexInfo()` false so index-advisor consumers produce no false
|
|
191
|
+
* positives on index-less code-first metadata.
|
|
192
|
+
*
|
|
122
193
|
* What SchemaDef cannot express (and how it degrades):
|
|
123
|
-
* - Indexes → every table gets `indexes: []`, which keeps
|
|
124
|
-
* `schemaHasIndexInfo()` false so index-advisor consumers produce no
|
|
125
|
-
* false positives on code-first metadata.
|
|
126
194
|
* - Views → never marked (`isView` is introspection-only).
|
|
127
195
|
* - Composite foreign keys → `references:` is single-column by design.
|
|
128
196
|
*/
|
|
@@ -299,9 +367,12 @@ export function schemaDefToMetadata(def) {
|
|
|
299
367
|
primaryKey: pk,
|
|
300
368
|
uniqueColumns,
|
|
301
369
|
relations: relationsByTable.get(tableDef.name) ?? {},
|
|
302
|
-
//
|
|
303
|
-
//
|
|
304
|
-
indexes
|
|
370
|
+
// Declared `indexes` (plain column + doc-field expression) carry through;
|
|
371
|
+
// an undeclared table gets `[]`, which keeps schemaHasIndexInfo() false so
|
|
372
|
+
// the index advisor stays silent. Doc-field (docPath) indexes are ignored
|
|
373
|
+
// by the advisor entirely (see index-advisor.ts), so a doc-only index set
|
|
374
|
+
// never flips schemaHasIndexInfo() and never produces FK false positives.
|
|
375
|
+
indexes: mapIndexes(tableDef, tableDef.indexes),
|
|
305
376
|
};
|
|
306
377
|
}
|
|
307
378
|
const enums = {};
|
package/dist/schema.d.ts
CHANGED
|
@@ -170,6 +170,31 @@ export interface IndexMetadata {
|
|
|
170
170
|
columns: string[];
|
|
171
171
|
unique: boolean;
|
|
172
172
|
definition: string;
|
|
173
|
+
/**
|
|
174
|
+
* Set only for a PowDB doc-field expression index: the JSON path (string keys
|
|
175
|
+
* and integer array indexes) into the single json document column named by
|
|
176
|
+
* `columns[0]`. When present, `columns` is `[<json column>]` and the index
|
|
177
|
+
* targets `columns[0]-><segments>` rather than the raw column.
|
|
178
|
+
*
|
|
179
|
+
* Consumed by the PowDB DDL generator (`powqlSchemaDDL` emits
|
|
180
|
+
* `alter T add index (.col->"seg")`). The missing-FK index advisor ignores
|
|
181
|
+
* doc-field indexes entirely (a JSON expression index never covers an
|
|
182
|
+
* equality probe on the raw column). Doc-field indexes are invisible to
|
|
183
|
+
* `describe`-based introspection, so they do NOT round-trip through
|
|
184
|
+
* introspection.
|
|
185
|
+
*/
|
|
186
|
+
docPath?: (string | number)[];
|
|
187
|
+
/**
|
|
188
|
+
* Set for indexes DECLARED in a code-first `defineSchema` (`TableDef.indexes`)
|
|
189
|
+
* rather than read from a live database by introspection. The SQL DDL
|
|
190
|
+
* generators (`schema-sql.ts` / `schemaDiff`) do NOT emit these yet, so a
|
|
191
|
+
* declared index does not reflect a real database index on the SQL engines.
|
|
192
|
+
* The missing-FK index advisor therefore treats declared indexes as
|
|
193
|
+
* "index-info unknown" (same as an index-less schema): counting them would
|
|
194
|
+
* both arm blanket FK false positives and suppress warnings for indexes that
|
|
195
|
+
* were never created. Introspected metadata never sets this.
|
|
196
|
+
*/
|
|
197
|
+
declared?: boolean;
|
|
173
198
|
}
|
|
174
199
|
/** Map a Postgres type to its TypeScript equivalent */
|
|
175
200
|
export declare function pgTypeToTs(pgType: string, nullable: boolean): string;
|
package/dist/sqlite.js
CHANGED
|
@@ -370,6 +370,8 @@ export const sqliteDialect = {
|
|
|
370
370
|
supportsListenNotify: false,
|
|
371
371
|
supportsRLS: false,
|
|
372
372
|
supportsAdvisoryLock: false,
|
|
373
|
+
// No FROM-clause LATERAL: the opt-in lateral pick plan is Postgres-only.
|
|
374
|
+
supportsLateralJoin: false,
|
|
373
375
|
// json_group_array / json_object have no inline ORDER BY argument, so every
|
|
374
376
|
// ordered to-many relation is forced through the inner-subquery rewrite.
|
|
375
377
|
aggSupportsInlineOrderBy: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turbine-orm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "Postgres-native TypeScript ORM — runs on Neon, Vercel Postgres, Cloudflare, Supabase. Streaming cursors, typed errors, single-query nested relations. One dependency, no WASM engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -103,11 +103,11 @@
|
|
|
103
103
|
"@size-limit/esbuild": "^12.1.0",
|
|
104
104
|
"@size-limit/file": "^12.1.0",
|
|
105
105
|
"@types/node": "^26.1.0",
|
|
106
|
+
"@zvndev/powdb-client": "^0.13.0",
|
|
107
|
+
"@zvndev/powdb-embedded": "^0.13.0",
|
|
106
108
|
"c8": "^11.0.0",
|
|
107
109
|
"husky": "^9.1.7",
|
|
108
110
|
"lint-staged": "^17.0.8",
|
|
109
|
-
"@zvndev/powdb-client": "^0.8.0",
|
|
110
|
-
"@zvndev/powdb-embedded": "^0.8.0",
|
|
111
111
|
"mssql": "^12.7.0",
|
|
112
112
|
"mysql2": "^3.22.5",
|
|
113
113
|
"size-limit": "^12.1.0",
|