turbine-orm 0.11.0 → 0.12.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/dist/cjs/dialect.js +22 -0
- package/dist/cjs/query/builder.js +30 -23
- package/dist/dialect.d.ts +50 -0
- package/dist/dialect.js +22 -0
- package/dist/index.d.ts +1 -1
- package/dist/query/builder.js +30 -23
- package/dist/query/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/cjs/dialect.js
CHANGED
|
@@ -33,6 +33,28 @@ exports.postgresDialect = {
|
|
|
33
33
|
const suffix = orderBy ? ` ${orderBy}` : '';
|
|
34
34
|
return `COALESCE(json_agg(${jsonObjectExpr}${suffix}), ${this.emptyJsonArrayLiteral})`;
|
|
35
35
|
},
|
|
36
|
+
buildReturningClause(selection = '*') {
|
|
37
|
+
return ` RETURNING ${selection}`;
|
|
38
|
+
},
|
|
39
|
+
buildInsertStatement(input) {
|
|
40
|
+
return `INSERT INTO ${input.table} (${input.columns.join(', ')}) VALUES (${input.valuePlaceholders.join(', ')})${this.buildReturningClause(input.returning)}`;
|
|
41
|
+
},
|
|
42
|
+
buildBulkInsertStatement(input) {
|
|
43
|
+
if (!input.columnArrayTypes || input.columnArrayTypes.length !== input.columns.length) {
|
|
44
|
+
throw new Error('PostgreSQL bulk insert requires one array type per column');
|
|
45
|
+
}
|
|
46
|
+
const columnArrays = input.columns.map((_, columnIndex) => input.rowValues.map((row) => row[columnIndex]));
|
|
47
|
+
const unnestArgs = input.columns.map((_, i) => `${this.paramPlaceholder(i + 1)}::${input.columnArrayTypes[i]}`);
|
|
48
|
+
let sql = `INSERT INTO ${input.table} (${input.columns.join(', ')}) SELECT * FROM UNNEST(${unnestArgs.join(', ')})`;
|
|
49
|
+
if (input.skipDuplicates)
|
|
50
|
+
sql += ' ON CONFLICT DO NOTHING';
|
|
51
|
+
return { sql: `${sql}${this.buildReturningClause(input.returning)}`, params: columnArrays };
|
|
52
|
+
},
|
|
53
|
+
buildUpsertStatement(input) {
|
|
54
|
+
return (`INSERT INTO ${input.table} (${input.insertColumns.join(', ')}) VALUES (${input.valuePlaceholders.join(', ')})` +
|
|
55
|
+
` ON CONFLICT (${input.conflictColumns.join(', ')}) DO UPDATE SET ${input.updateSetClauses.join(', ')}` +
|
|
56
|
+
this.buildReturningClause(input.returning));
|
|
57
|
+
},
|
|
36
58
|
buildInsensitiveLike(column, paramRef) {
|
|
37
59
|
return `${column} ILIKE ${paramRef}`;
|
|
38
60
|
},
|
|
@@ -736,7 +736,12 @@ class QueryInterface {
|
|
|
736
736
|
const columns = entries.map(([k]) => this.toSqlColumn(k));
|
|
737
737
|
const params = entries.map(([, v]) => v);
|
|
738
738
|
const placeholders = entries.map((_, i) => `${this.p(i + 1)}`);
|
|
739
|
-
const sql =
|
|
739
|
+
const sql = this.dialect.buildInsertStatement({
|
|
740
|
+
table: this.q(this.table),
|
|
741
|
+
columns,
|
|
742
|
+
valuePlaceholders: placeholders,
|
|
743
|
+
returning: '*',
|
|
744
|
+
});
|
|
740
745
|
return {
|
|
741
746
|
sql,
|
|
742
747
|
params,
|
|
@@ -776,27 +781,24 @@ class QueryInterface {
|
|
|
776
781
|
}
|
|
777
782
|
const keys = Object.keys(args.data[0]).filter((k) => args.data[0][k] !== undefined);
|
|
778
783
|
const columns = keys.map((k) => this.toColumn(k));
|
|
779
|
-
|
|
780
|
-
const columnArrays = keys.map(() => []);
|
|
781
|
-
for (const row of args.data) {
|
|
784
|
+
const rowValues = args.data.map((row) => {
|
|
782
785
|
const record = row;
|
|
783
|
-
keys.
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
}
|
|
787
|
-
// Use actual Postgres types for array casts
|
|
786
|
+
return keys.map((key) => record[key]);
|
|
787
|
+
});
|
|
788
|
+
// Use actual Postgres types for array casts in the default PostgreSQL dialect.
|
|
788
789
|
const typeCasts = columns.map((col) => this.getColumnArrayType(col));
|
|
789
|
-
const unnestArgs = columnArrays.map((_, i) => `${this.p(i + 1)}::${typeCasts[i]}`);
|
|
790
790
|
const quotedColumns = columns.map((c) => this.q(c));
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
791
|
+
const built = this.dialect.buildBulkInsertStatement({
|
|
792
|
+
table: qt,
|
|
793
|
+
columns: quotedColumns,
|
|
794
|
+
rowValues,
|
|
795
|
+
columnArrayTypes: typeCasts,
|
|
796
|
+
skipDuplicates: args.skipDuplicates,
|
|
797
|
+
returning: '*',
|
|
798
|
+
});
|
|
797
799
|
return {
|
|
798
|
-
sql,
|
|
799
|
-
params:
|
|
800
|
+
sql: built.sql,
|
|
801
|
+
params: built.params,
|
|
800
802
|
transform: (result) => result.rows.map((row) => this.parseRow(row, this.table)),
|
|
801
803
|
tag: `${this.table}.createMany`,
|
|
802
804
|
};
|
|
@@ -825,7 +827,7 @@ class QueryInterface {
|
|
|
825
827
|
const whereClause = this.buildWhereClause(whereObj, freshParams);
|
|
826
828
|
const whereSql = whereClause ? ` WHERE ${whereClause}` : '';
|
|
827
829
|
this.assertMutationHasPredicate('update', whereSql, args.allowFullTableScan);
|
|
828
|
-
return `UPDATE ${this.q(this.table)} SET ${setClauses.join(', ')}${whereSql}
|
|
830
|
+
return `UPDATE ${this.q(this.table)} SET ${setClauses.join(', ')}${whereSql}${this.dialect.buildReturningClause('*')}`;
|
|
829
831
|
});
|
|
830
832
|
// On cache hit, validate predicate
|
|
831
833
|
if (whereFp === '') {
|
|
@@ -874,7 +876,7 @@ class QueryInterface {
|
|
|
874
876
|
const clause = this.buildWhereClause(whereObj, freshParams);
|
|
875
877
|
const whereSql = clause ? ` WHERE ${clause}` : '';
|
|
876
878
|
this.assertMutationHasPredicate('delete', whereSql, args.allowFullTableScan);
|
|
877
|
-
return `DELETE FROM ${this.q(this.table)}${whereSql}
|
|
879
|
+
return `DELETE FROM ${this.q(this.table)}${whereSql}${this.dialect.buildReturningClause('*')}`;
|
|
878
880
|
});
|
|
879
881
|
// On cache hit, still validate the predicate
|
|
880
882
|
if (whereFp === '') {
|
|
@@ -928,9 +930,14 @@ class QueryInterface {
|
|
|
928
930
|
});
|
|
929
931
|
const updateParams = updateEntries.map(([, v]) => v);
|
|
930
932
|
const params = [...createParams, ...updateParams];
|
|
931
|
-
const sql =
|
|
932
|
-
|
|
933
|
-
|
|
933
|
+
const sql = this.dialect.buildUpsertStatement({
|
|
934
|
+
table: this.q(this.table),
|
|
935
|
+
insertColumns: columns,
|
|
936
|
+
valuePlaceholders: placeholders,
|
|
937
|
+
conflictColumns,
|
|
938
|
+
updateSetClauses: setClauses,
|
|
939
|
+
returning: '*',
|
|
940
|
+
});
|
|
934
941
|
return {
|
|
935
942
|
sql,
|
|
936
943
|
params,
|
package/dist/dialect.d.ts
CHANGED
|
@@ -7,6 +7,48 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { SchemaMetadata } from './schema.js';
|
|
9
9
|
export type DialectName = 'postgresql' | 'mysql' | 'sqlite' | (string & {});
|
|
10
|
+
export interface InsertStatementInput {
|
|
11
|
+
/** SQL-ready quoted table name. */
|
|
12
|
+
table: string;
|
|
13
|
+
/** SQL-ready quoted insert columns. */
|
|
14
|
+
columns: string[];
|
|
15
|
+
/** SQL-ready parameter placeholders/expressions for VALUES. */
|
|
16
|
+
valuePlaceholders: string[];
|
|
17
|
+
/** Optional SQL-ready RETURNING selection. */
|
|
18
|
+
returning?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface BulkInsertStatementInput {
|
|
21
|
+
/** SQL-ready quoted table name. */
|
|
22
|
+
table: string;
|
|
23
|
+
/** SQL-ready quoted insert columns. */
|
|
24
|
+
columns: string[];
|
|
25
|
+
/** Row-major values, one inner array per inserted row. */
|
|
26
|
+
rowValues: unknown[][];
|
|
27
|
+
/** Optional SQL-ready array casts for dialects that batch by column arrays (PostgreSQL UNNEST). */
|
|
28
|
+
columnArrayTypes?: string[];
|
|
29
|
+
/** Skip duplicate rows when supported by the dialect. */
|
|
30
|
+
skipDuplicates?: boolean;
|
|
31
|
+
/** Optional SQL-ready RETURNING selection. */
|
|
32
|
+
returning?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface BuiltStatement {
|
|
35
|
+
sql: string;
|
|
36
|
+
params: unknown[];
|
|
37
|
+
}
|
|
38
|
+
export interface UpsertStatementInput {
|
|
39
|
+
/** SQL-ready quoted table name. */
|
|
40
|
+
table: string;
|
|
41
|
+
/** SQL-ready quoted insert columns. */
|
|
42
|
+
insertColumns: string[];
|
|
43
|
+
/** SQL-ready parameter placeholders/expressions for VALUES. */
|
|
44
|
+
valuePlaceholders: string[];
|
|
45
|
+
/** SQL-ready quoted conflict/unique columns. */
|
|
46
|
+
conflictColumns: string[];
|
|
47
|
+
/** SQL-ready update SET clauses. */
|
|
48
|
+
updateSetClauses: string[];
|
|
49
|
+
/** Optional SQL-ready RETURNING selection. */
|
|
50
|
+
returning?: string;
|
|
51
|
+
}
|
|
10
52
|
export interface Dialect {
|
|
11
53
|
/** Dialect identifier. */
|
|
12
54
|
readonly name: DialectName;
|
|
@@ -26,6 +68,14 @@ export interface Dialect {
|
|
|
26
68
|
buildJsonArrayAgg(jsonObjectExpr: string, orderBy?: string): string;
|
|
27
69
|
/** Whether INSERT/UPDATE/DELETE support RETURNING rows. */
|
|
28
70
|
readonly supportsReturning: boolean;
|
|
71
|
+
/** Build a dialect-specific RETURNING clause. Return an empty string when unsupported. */
|
|
72
|
+
buildReturningClause(selection?: string): string;
|
|
73
|
+
/** Build a single-row INSERT statement. Inputs are SQL-ready quoted fragments. */
|
|
74
|
+
buildInsertStatement(input: InsertStatementInput): string;
|
|
75
|
+
/** Build a multi-row bulk INSERT statement and its dialect-shaped params. */
|
|
76
|
+
buildBulkInsertStatement(input: BulkInsertStatementInput): BuiltStatement;
|
|
77
|
+
/** Build an upsert statement. Inputs are SQL-ready quoted fragments. */
|
|
78
|
+
buildUpsertStatement(input: UpsertStatementInput): string;
|
|
29
79
|
/** Whether native ILIKE is supported. */
|
|
30
80
|
readonly supportsILike: boolean;
|
|
31
81
|
/** Build a case-insensitive LIKE equivalent. */
|
package/dist/dialect.js
CHANGED
|
@@ -30,6 +30,28 @@ export const postgresDialect = {
|
|
|
30
30
|
const suffix = orderBy ? ` ${orderBy}` : '';
|
|
31
31
|
return `COALESCE(json_agg(${jsonObjectExpr}${suffix}), ${this.emptyJsonArrayLiteral})`;
|
|
32
32
|
},
|
|
33
|
+
buildReturningClause(selection = '*') {
|
|
34
|
+
return ` RETURNING ${selection}`;
|
|
35
|
+
},
|
|
36
|
+
buildInsertStatement(input) {
|
|
37
|
+
return `INSERT INTO ${input.table} (${input.columns.join(', ')}) VALUES (${input.valuePlaceholders.join(', ')})${this.buildReturningClause(input.returning)}`;
|
|
38
|
+
},
|
|
39
|
+
buildBulkInsertStatement(input) {
|
|
40
|
+
if (!input.columnArrayTypes || input.columnArrayTypes.length !== input.columns.length) {
|
|
41
|
+
throw new Error('PostgreSQL bulk insert requires one array type per column');
|
|
42
|
+
}
|
|
43
|
+
const columnArrays = input.columns.map((_, columnIndex) => input.rowValues.map((row) => row[columnIndex]));
|
|
44
|
+
const unnestArgs = input.columns.map((_, i) => `${this.paramPlaceholder(i + 1)}::${input.columnArrayTypes[i]}`);
|
|
45
|
+
let sql = `INSERT INTO ${input.table} (${input.columns.join(', ')}) SELECT * FROM UNNEST(${unnestArgs.join(', ')})`;
|
|
46
|
+
if (input.skipDuplicates)
|
|
47
|
+
sql += ' ON CONFLICT DO NOTHING';
|
|
48
|
+
return { sql: `${sql}${this.buildReturningClause(input.returning)}`, params: columnArrays };
|
|
49
|
+
},
|
|
50
|
+
buildUpsertStatement(input) {
|
|
51
|
+
return (`INSERT INTO ${input.table} (${input.insertColumns.join(', ')}) VALUES (${input.valuePlaceholders.join(', ')})` +
|
|
52
|
+
` ON CONFLICT (${input.conflictColumns.join(', ')}) DO UPDATE SET ${input.updateSetClauses.join(', ')}` +
|
|
53
|
+
this.buildReturningClause(input.returning));
|
|
54
|
+
},
|
|
33
55
|
buildInsensitiveLike(column, paramRef) {
|
|
34
56
|
return `${column} ILIKE ${paramRef}`;
|
|
35
57
|
},
|
package/dist/index.d.ts
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
export type { DatabaseAdapter, IntrospectionOverrides } from './adapters/index.js';
|
|
36
36
|
export { alloydb, cockroachdb, postgresql, timescale, yugabytedb } from './adapters/index.js';
|
|
37
37
|
export { type Middleware, type MiddlewareNext, type MiddlewareParams, type PgCompatPool, type PgCompatPoolClient, type PgCompatQueryResult, TransactionClient, type TransactionOptions, TurbineClient, type TurbineConfig, } from './client.js';
|
|
38
|
-
export type { Dialect, DialectIntrospector, DialectMigrator, DialectName, IntrospectOptions as DialectIntrospectOptions, } from './dialect.js';
|
|
38
|
+
export type { BuiltStatement, BulkInsertStatementInput, Dialect, DialectIntrospector, DialectMigrator, DialectName, InsertStatementInput, IntrospectOptions as DialectIntrospectOptions, UpsertStatementInput, } from './dialect.js';
|
|
39
39
|
export { postgresDialect } from './dialect.js';
|
|
40
40
|
export { CheckConstraintError, CircularRelationError, ConnectionError, DeadlockError, type ErrorMessageMode, ForeignKeyError, getErrorMessageMode, MigrationError, NotFoundError, NotNullViolationError, PipelineError, type PipelineResultSlot, RelationError, SerializationFailureError, setErrorMessageMode, TimeoutError, TurbineError, TurbineErrorCode, UniqueConstraintError, ValidationError, wrapPgError, } from './errors.js';
|
|
41
41
|
export { type GenerateOptions, generate } from './generate.js';
|
package/dist/query/builder.js
CHANGED
|
@@ -733,7 +733,12 @@ export class QueryInterface {
|
|
|
733
733
|
const columns = entries.map(([k]) => this.toSqlColumn(k));
|
|
734
734
|
const params = entries.map(([, v]) => v);
|
|
735
735
|
const placeholders = entries.map((_, i) => `${this.p(i + 1)}`);
|
|
736
|
-
const sql =
|
|
736
|
+
const sql = this.dialect.buildInsertStatement({
|
|
737
|
+
table: this.q(this.table),
|
|
738
|
+
columns,
|
|
739
|
+
valuePlaceholders: placeholders,
|
|
740
|
+
returning: '*',
|
|
741
|
+
});
|
|
737
742
|
return {
|
|
738
743
|
sql,
|
|
739
744
|
params,
|
|
@@ -773,27 +778,24 @@ export class QueryInterface {
|
|
|
773
778
|
}
|
|
774
779
|
const keys = Object.keys(args.data[0]).filter((k) => args.data[0][k] !== undefined);
|
|
775
780
|
const columns = keys.map((k) => this.toColumn(k));
|
|
776
|
-
|
|
777
|
-
const columnArrays = keys.map(() => []);
|
|
778
|
-
for (const row of args.data) {
|
|
781
|
+
const rowValues = args.data.map((row) => {
|
|
779
782
|
const record = row;
|
|
780
|
-
keys.
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
}
|
|
784
|
-
// Use actual Postgres types for array casts
|
|
783
|
+
return keys.map((key) => record[key]);
|
|
784
|
+
});
|
|
785
|
+
// Use actual Postgres types for array casts in the default PostgreSQL dialect.
|
|
785
786
|
const typeCasts = columns.map((col) => this.getColumnArrayType(col));
|
|
786
|
-
const unnestArgs = columnArrays.map((_, i) => `${this.p(i + 1)}::${typeCasts[i]}`);
|
|
787
787
|
const quotedColumns = columns.map((c) => this.q(c));
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
788
|
+
const built = this.dialect.buildBulkInsertStatement({
|
|
789
|
+
table: qt,
|
|
790
|
+
columns: quotedColumns,
|
|
791
|
+
rowValues,
|
|
792
|
+
columnArrayTypes: typeCasts,
|
|
793
|
+
skipDuplicates: args.skipDuplicates,
|
|
794
|
+
returning: '*',
|
|
795
|
+
});
|
|
794
796
|
return {
|
|
795
|
-
sql,
|
|
796
|
-
params:
|
|
797
|
+
sql: built.sql,
|
|
798
|
+
params: built.params,
|
|
797
799
|
transform: (result) => result.rows.map((row) => this.parseRow(row, this.table)),
|
|
798
800
|
tag: `${this.table}.createMany`,
|
|
799
801
|
};
|
|
@@ -822,7 +824,7 @@ export class QueryInterface {
|
|
|
822
824
|
const whereClause = this.buildWhereClause(whereObj, freshParams);
|
|
823
825
|
const whereSql = whereClause ? ` WHERE ${whereClause}` : '';
|
|
824
826
|
this.assertMutationHasPredicate('update', whereSql, args.allowFullTableScan);
|
|
825
|
-
return `UPDATE ${this.q(this.table)} SET ${setClauses.join(', ')}${whereSql}
|
|
827
|
+
return `UPDATE ${this.q(this.table)} SET ${setClauses.join(', ')}${whereSql}${this.dialect.buildReturningClause('*')}`;
|
|
826
828
|
});
|
|
827
829
|
// On cache hit, validate predicate
|
|
828
830
|
if (whereFp === '') {
|
|
@@ -871,7 +873,7 @@ export class QueryInterface {
|
|
|
871
873
|
const clause = this.buildWhereClause(whereObj, freshParams);
|
|
872
874
|
const whereSql = clause ? ` WHERE ${clause}` : '';
|
|
873
875
|
this.assertMutationHasPredicate('delete', whereSql, args.allowFullTableScan);
|
|
874
|
-
return `DELETE FROM ${this.q(this.table)}${whereSql}
|
|
876
|
+
return `DELETE FROM ${this.q(this.table)}${whereSql}${this.dialect.buildReturningClause('*')}`;
|
|
875
877
|
});
|
|
876
878
|
// On cache hit, still validate the predicate
|
|
877
879
|
if (whereFp === '') {
|
|
@@ -925,9 +927,14 @@ export class QueryInterface {
|
|
|
925
927
|
});
|
|
926
928
|
const updateParams = updateEntries.map(([, v]) => v);
|
|
927
929
|
const params = [...createParams, ...updateParams];
|
|
928
|
-
const sql =
|
|
929
|
-
|
|
930
|
-
|
|
930
|
+
const sql = this.dialect.buildUpsertStatement({
|
|
931
|
+
table: this.q(this.table),
|
|
932
|
+
insertColumns: columns,
|
|
933
|
+
valuePlaceholders: placeholders,
|
|
934
|
+
conflictColumns,
|
|
935
|
+
updateSetClauses: setClauses,
|
|
936
|
+
returning: '*',
|
|
937
|
+
});
|
|
931
938
|
return {
|
|
932
939
|
sql,
|
|
933
940
|
params,
|
package/dist/query/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* former monolithic `import { … } from './query.js'`.
|
|
7
7
|
*/
|
|
8
8
|
export type { AggregateArgs, AggregateResult, ArrayFilter, CountArgs, CreateArgs, CreateManyArgs, DeleteArgs, DeleteManyArgs, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GroupByArgs, JsonFilter, OrderDirection, RelationDescriptor, RelationFilter, TypedWithClause, UpdateArgs, UpdateInput, UpdateManyArgs, UpdateOperatorInput, UpsertArgs, WhereClause, WhereOperator, WhereValue, WithClause, WithOptions, WithResult, } from './types.js';
|
|
9
|
-
export type { Dialect } from '../dialect.js';
|
|
9
|
+
export type { BuiltStatement, BulkInsertStatementInput, Dialect, InsertStatementInput, UpsertStatementInput, } from '../dialect.js';
|
|
10
10
|
export { postgresDialect } from '../dialect.js';
|
|
11
11
|
export type { SqlCacheEntry } from './utils.js';
|
|
12
12
|
export { buildCorrelation, escapeLike, escSingleQuote, fnv1a64Hex, LRUCache, OPERATOR_KEYS, quoteIdent, sqlToPreparedName, } from './utils.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turbine-orm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
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": {
|