turbine-orm 0.21.0 → 0.23.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 +19 -2
- package/dist/cjs/client.js +11 -2
- package/dist/cjs/generate.js +4 -0
- package/dist/cjs/introspect.js +6 -0
- package/dist/cjs/powdb.js +865 -0
- package/dist/cjs/powql.js +1262 -0
- package/dist/cli/ui.d.ts +1 -1
- package/dist/client.js +11 -2
- package/dist/generate.js +4 -0
- package/dist/introspect.js +6 -0
- package/dist/powdb.d.ts +341 -0
- package/dist/powdb.js +816 -0
- package/dist/powql.d.ts +205 -0
- package/dist/powql.js +1226 -0
- package/dist/query/builder.d.ts +8 -0
- package/dist/schema.d.ts +10 -0
- package/package.json +16 -1
package/dist/powql.d.ts
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PowqlInterface — Turbine's PowQL query generator (the PowDB analogue of
|
|
3
|
+
* {@link QueryInterface}). It exposes the same public method surface as the SQL
|
|
4
|
+
* `QueryInterface` (`findMany`, `create`, `update`, …) but emits **PowQL** — a
|
|
5
|
+
* pipeline language, not SQL — executed through {@link PowdbPool}.
|
|
6
|
+
*
|
|
7
|
+
* It is a *parallel* implementation rather than a `Dialect` of the SQL builder:
|
|
8
|
+
* PowQL's grammar (`T filter <e> order <k> { .col }`) shares no surface with
|
|
9
|
+
* `SELECT … FROM … WHERE`, so the SQL `Dialect` seam cannot express it. Keeping
|
|
10
|
+
* it separate also means the four SQL engines are untouched.
|
|
11
|
+
*
|
|
12
|
+
* Behavioural deltas from the SQL path, all driven by PowDB's wire reality (see
|
|
13
|
+
* `docs/strategy/powdb-parity-matrix.md`, every row verified against a live
|
|
14
|
+
* server):
|
|
15
|
+
* - `create`/`createMany`/`update`/`delete` use PowDB 0.7.0's trailing
|
|
16
|
+
* `returning` keyword (`RETURNING *`, all columns) to surface affected rows
|
|
17
|
+
* in one round-trip. `upsert` is the lone exception — its statement does not
|
|
18
|
+
* accept `returning`, so it reselects the row by PK (a composite-PK upsert
|
|
19
|
+
* reselects-or-writes inside one flat transaction).
|
|
20
|
+
* - The PK is server-assigned when the column is `isGenerated` (PowDB's `auto`
|
|
21
|
+
* int — read back via `returning`); otherwise a defaulted **string** PK is
|
|
22
|
+
* generated client-side (UUID).
|
|
23
|
+
* - `with` (nested relations) uses **batched N+1 loaders** — D round-trips for
|
|
24
|
+
* depth D, not one query — including manyToMany (junction → targets).
|
|
25
|
+
* - **Relation filters** (`some`/`none`/`every`, all cardinalities incl. m2m)
|
|
26
|
+
* are resolved client-side to a literal `in (…)` list, never an IN-subquery:
|
|
27
|
+
* PowDB's executor caches a subquery's result by plan shape and would return
|
|
28
|
+
* a stale prior result for a later subquery of the same shape.
|
|
29
|
+
* - **Nested writes** (relation ops in `create`/`update` data) run through the
|
|
30
|
+
* shared nested-write engine as one flat top-level transaction (PowDB is
|
|
31
|
+
* single-writer, no savepoints).
|
|
32
|
+
* - pgvector / JSON / array filters and cursor streaming throw
|
|
33
|
+
* {@link UnsupportedFeatureError} (E017) — they have no PowDB equivalent.
|
|
34
|
+
*
|
|
35
|
+
* @module
|
|
36
|
+
*/
|
|
37
|
+
import { type PowdbPool } from './powdb.js';
|
|
38
|
+
import type { MiddlewareFn, QueryInterfaceOptions } from './query/index.js';
|
|
39
|
+
import type { AggregateArgs, AggregateResult, CountArgs, CreateArgs, CreateManyArgs, DeleteArgs, DeleteManyArgs, FindManyArgs, FindUniqueArgs, GroupByArgs, UpdateArgs, UpdateManyArgs, UpsertArgs } from './query/types.js';
|
|
40
|
+
import { type SchemaMetadata } from './schema.js';
|
|
41
|
+
/**
|
|
42
|
+
* The PowQL query interface. Constructed by `turbinePowDB` via the
|
|
43
|
+
* `queryInterfaceFactory` seam and cast to `QueryInterface<object>` so
|
|
44
|
+
* `TurbineClient.table()` can return it transparently.
|
|
45
|
+
*/
|
|
46
|
+
export declare class PowqlInterface<T extends object = Record<string, unknown>> {
|
|
47
|
+
private readonly pool;
|
|
48
|
+
private readonly table;
|
|
49
|
+
private readonly schema;
|
|
50
|
+
private readonly middlewares;
|
|
51
|
+
private readonly options;
|
|
52
|
+
private readonly meta;
|
|
53
|
+
private readonly defaultLimit?;
|
|
54
|
+
private readonly warnOnUnlimited;
|
|
55
|
+
private readonly onQuery?;
|
|
56
|
+
private currentAction;
|
|
57
|
+
private warnedUnlimited;
|
|
58
|
+
constructor(pool: PowdbPool, table: string, schema: SchemaMetadata, middlewares?: MiddlewareFn[], options?: QueryInterfaceOptions);
|
|
59
|
+
/** Resolve a camelCase field name (or raw snake) to its column metadata. */
|
|
60
|
+
private column;
|
|
61
|
+
/** PowQL column reference (`.snake_name`) for a field. */
|
|
62
|
+
private ref;
|
|
63
|
+
/**
|
|
64
|
+
* Push a value into the param array and return its `$N` placeholder. When the
|
|
65
|
+
* value targets a `float` column it is wrapped in {@link PowdbFloatParam} so
|
|
66
|
+
* the *embedded* literal encoder emits a float-form literal even for an
|
|
67
|
+
* integer value (PowQL's `42` is an int literal, `42.0` a float). The
|
|
68
|
+
* networked driver unwraps the marker back to the plain number in
|
|
69
|
+
* {@link toPowdbParam}, so the wire param is unchanged.
|
|
70
|
+
*/
|
|
71
|
+
private param;
|
|
72
|
+
/**
|
|
73
|
+
* Render a value for a write *assignment* (`col := …`). Every value — float
|
|
74
|
+
* columns included — is sent as a positional `$N` param. PowDB ≥ 0.7.0 fixed
|
|
75
|
+
* the int→float UPDATE coercion bug (`score := $n` with an integer param now
|
|
76
|
+
* reads back the integer value, not the raw i64 bits), so the float-literal
|
|
77
|
+
* inlining workaround Turbine carried for ≤ 0.6.2 is gone. Marks the column as
|
|
78
|
+
* float-typed for the *embedded* literal encoder (which materializes params
|
|
79
|
+
* into PowQL text) so an integer-valued float still encodes as a float literal
|
|
80
|
+
* and coercion stays unambiguous. Non-finite floats are still rejected.
|
|
81
|
+
*/
|
|
82
|
+
private writeRef;
|
|
83
|
+
private isFloatCol;
|
|
84
|
+
/** A predicate that is always false — the empty-`in` / contradiction sentinel. */
|
|
85
|
+
private alwaysFalse;
|
|
86
|
+
/**
|
|
87
|
+
* Compile a {@link WhereClause} into a PowQL filter expression, pushing every
|
|
88
|
+
* value as a positional `$N` param. Returns `''` when there are no conditions.
|
|
89
|
+
*/
|
|
90
|
+
private buildWhere;
|
|
91
|
+
/** Build a single `field: value | operator` condition. */
|
|
92
|
+
private buildFieldCondition;
|
|
93
|
+
/** Bind a value, lowercasing for case-insensitive comparisons. */
|
|
94
|
+
private bind;
|
|
95
|
+
/** Bind a LIKE pattern (already escaped), lowercasing for insensitive mode. */
|
|
96
|
+
private bindLike;
|
|
97
|
+
/** `lhs [not] in ($1, $2, …)` — empty list collapses to a constant. */
|
|
98
|
+
private buildInList;
|
|
99
|
+
/**
|
|
100
|
+
* Pre-resolve every relation filter (`some`/`none`/`every`) in a where clause
|
|
101
|
+
* into a plain scalar `in`/`notIn` condition on the **local key**, by running
|
|
102
|
+
* the inner predicate as its own query and materializing the matching keys as
|
|
103
|
+
* a literal list. The compiled where is then relation-free and `buildWhere`
|
|
104
|
+
* emits only `in (<literal list>)`.
|
|
105
|
+
*
|
|
106
|
+
* Why not an IN-subquery (`.k in (Target filter <e> { .fk })`)? PowDB's
|
|
107
|
+
* executor caches a subquery's result by **plan shape, ignoring the literal**,
|
|
108
|
+
* so a second subquery of the same shape with a different value returns the
|
|
109
|
+
* first one's stale rows (reproduced live on the embedded engine; the
|
|
110
|
+
* single-statement literal `in (list)` form is always correct). Resolving
|
|
111
|
+
* client-side trades extra round-trips for correctness, and recurses — nested
|
|
112
|
+
* relation filters in the inner predicate resolve when the target query runs.
|
|
113
|
+
*/
|
|
114
|
+
private resolveRelationFilters;
|
|
115
|
+
/** Resolve one hasMany/hasOne/belongsTo filter to `{ localField: { in|notIn: [...] } }`. */
|
|
116
|
+
private resolveRelationCondition;
|
|
117
|
+
/** Resolve a manyToMany filter through the junction to `{ sourceRefField: { in|notIn: [...] } }`. */
|
|
118
|
+
private resolveManyToManyCondition;
|
|
119
|
+
/** Resolve the set of columns to project, honouring `select` / `omit`. */
|
|
120
|
+
private projectedColumns;
|
|
121
|
+
/** `{ .c1, .c2, … }` projection clause. */
|
|
122
|
+
private projection;
|
|
123
|
+
/** `order .c1 asc, .c2 desc` clause (empty string when no orderBy). */
|
|
124
|
+
private buildOrder;
|
|
125
|
+
/** Run PowQL with optional timeout, emitting a query event either way. */
|
|
126
|
+
private exec;
|
|
127
|
+
private emit;
|
|
128
|
+
/** Run a method body through the middleware chain (mirrors QueryInterface). */
|
|
129
|
+
private withMiddleware;
|
|
130
|
+
/** Map raw rows to typed entities. */
|
|
131
|
+
private shape;
|
|
132
|
+
findMany(args?: FindManyArgs<T>): Promise<T[]>;
|
|
133
|
+
/** Build + run the flat findMany select; returns raw rows. */
|
|
134
|
+
private runFind;
|
|
135
|
+
findUnique(args: FindUniqueArgs<T>): Promise<T | null>;
|
|
136
|
+
findFirst(args?: FindManyArgs<T>): Promise<T | null>;
|
|
137
|
+
findUniqueOrThrow(args: FindUniqueArgs<T>): Promise<T>;
|
|
138
|
+
findFirstOrThrow(args?: FindManyArgs<T>): Promise<T>;
|
|
139
|
+
/** Load each requested relation for `parents` and attach it onto each row. */
|
|
140
|
+
private loadRelations;
|
|
141
|
+
/**
|
|
142
|
+
* manyToMany nested read — a three-hop batched loader (no `json_agg`/join
|
|
143
|
+
* pushdown): (1) read the junction rows for all parents in `sourceKey in (…)`
|
|
144
|
+
* chunks, (2) read the target rows for the collected `targetKey`s, (3) stitch
|
|
145
|
+
* each parent → its junction rows → its targets in memory. Mirrors the
|
|
146
|
+
* single-key N+1 loaders; the junction's source/target columns must be single
|
|
147
|
+
* (composite junction keys would need PowQL tuple-`in`, which it lacks).
|
|
148
|
+
*/
|
|
149
|
+
private loadManyToMany;
|
|
150
|
+
/** Split `data` into scalar assignments; reject relation (nested-write) keys. */
|
|
151
|
+
private scalarData;
|
|
152
|
+
/**
|
|
153
|
+
* Fill in a client-generated UUID for a defaulted **string** PK that wasn't
|
|
154
|
+
* supplied. A server-generated PK ({@link ColumnMetadata.isGenerated}, e.g. an
|
|
155
|
+
* `int` column with PowDB's `auto` modifier) is left untouched — PowDB assigns
|
|
156
|
+
* it and the trailing `returning` reads it back — as is any non-string PK.
|
|
157
|
+
*/
|
|
158
|
+
private applyPkDefault;
|
|
159
|
+
create(args: CreateArgs<T>): Promise<T>;
|
|
160
|
+
createMany(args: CreateManyArgs<T>): Promise<T[]>;
|
|
161
|
+
update(args: UpdateArgs<T>): Promise<T>;
|
|
162
|
+
updateMany(args: UpdateManyArgs<T>): Promise<{
|
|
163
|
+
count: number;
|
|
164
|
+
}>;
|
|
165
|
+
/** Compile `data` into PowQL update assignments, including atomic operators. */
|
|
166
|
+
private buildUpdateAssignments;
|
|
167
|
+
private isTxScoped;
|
|
168
|
+
private nestedCreate;
|
|
169
|
+
private nestedUpdate;
|
|
170
|
+
/** Open a flat PowDB transaction on a pinned connection and run `fn` inside it. */
|
|
171
|
+
private runInImplicitTx;
|
|
172
|
+
/** Already inside a transaction: build a context whose table accessors reuse the pinned pool. */
|
|
173
|
+
private buildNestedCtx;
|
|
174
|
+
delete(args: DeleteArgs<T>): Promise<T>;
|
|
175
|
+
deleteMany(args: DeleteManyArgs<T>): Promise<{
|
|
176
|
+
count: number;
|
|
177
|
+
}>;
|
|
178
|
+
upsert(args: UpsertArgs<T>): Promise<T>;
|
|
179
|
+
/**
|
|
180
|
+
* Composite-key upsert: PowQL's `upsert … on .col` only takes one conflict
|
|
181
|
+
* column, so reselect by the full composite PK and update-or-create inside one
|
|
182
|
+
* flat transaction (PowDB single-writer makes the read-then-write safe from
|
|
183
|
+
* concurrent writers; the transaction makes it atomic with the write).
|
|
184
|
+
*/
|
|
185
|
+
private upsertComposite;
|
|
186
|
+
count(args?: CountArgs<T>): Promise<number>;
|
|
187
|
+
aggregate(args: AggregateArgs<T>): Promise<AggregateResult<T>>;
|
|
188
|
+
groupBy(args: GroupByArgs<T>): Promise<Record<string, unknown>[]>;
|
|
189
|
+
/** `having <expr>` over group aggregates (count/sum/avg/min/max). */
|
|
190
|
+
private buildHaving;
|
|
191
|
+
findManyStream(): AsyncGenerator<T>;
|
|
192
|
+
/** Reselect a single row by its single-column primary key value. */
|
|
193
|
+
private reselectByPk;
|
|
194
|
+
/**
|
|
195
|
+
* Empty-where guard — blocks accidental whole-table writes. Mirrors the SQL
|
|
196
|
+
* path's `assertMutationHasPredicate` (query/builder.ts): it gates on the
|
|
197
|
+
* *compiled* PowQL filter fragment, NOT the shape of the `where` object. A
|
|
198
|
+
* `where` whose conditions all evaporate during compilation — `{}`,
|
|
199
|
+
* `{ id: undefined }`, `{ OR: [] }`, `{ AND: [] }`, `{ NOT: {} }`,
|
|
200
|
+
* `{ OR: [{ f: undefined }] }` — compiles to the empty string and is refused,
|
|
201
|
+
* because emitting a filter-less write would hit every row.
|
|
202
|
+
*/
|
|
203
|
+
private assertCompiledWhere;
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=powql.d.ts.map
|