drizzle-orm 0.25.2 → 0.25.3-4cc2d87
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/aws-data-api/pg/index.cjs +234 -1
- package/aws-data-api/pg/index.cjs.map +1 -1
- package/aws-data-api/pg/index.d.ts +5 -6
- package/aws-data-api/pg/index.mjs +228 -1
- package/aws-data-api/pg/index.mjs.map +1 -1
- package/aws-data-api/pg/migrator.cjs +13 -1
- package/aws-data-api/pg/migrator.cjs.map +1 -1
- package/aws-data-api/pg/migrator.d.ts +5 -6
- package/aws-data-api/pg/migrator.mjs +11 -1
- package/aws-data-api/pg/migrator.mjs.map +1 -1
- package/better-sqlite3/index.cjs +119 -1
- package/better-sqlite3/index.cjs.map +1 -1
- package/better-sqlite3/index.d.ts +14 -12
- package/better-sqlite3/index.mjs +114 -1
- package/better-sqlite3/index.mjs.map +1 -1
- package/better-sqlite3/migrator.cjs +13 -1
- package/better-sqlite3/migrator.cjs.map +1 -1
- package/better-sqlite3/migrator.d.ts +5 -5
- package/better-sqlite3/migrator.mjs +11 -1
- package/better-sqlite3/migrator.mjs.map +1 -1
- package/bun-sqlite/index.cjs +126 -1
- package/bun-sqlite/index.cjs.map +1 -1
- package/bun-sqlite/index.d.ts +14 -12
- package/bun-sqlite/index.mjs +121 -1
- package/bun-sqlite/index.mjs.map +1 -1
- package/bun-sqlite/migrator.cjs +13 -1
- package/bun-sqlite/migrator.cjs.map +1 -1
- package/bun-sqlite/migrator.d.ts +5 -5
- package/bun-sqlite/migrator.mjs +11 -1
- package/bun-sqlite/migrator.mjs.map +1 -1
- package/{column.d-8b137277.d.ts → column.d-c31e7ad3.d.ts} +77 -6
- package/d1/index.cjs +116 -1
- package/d1/index.cjs.map +1 -1
- package/d1/index.d.ts +15 -12
- package/d1/index.mjs +111 -1
- package/d1/index.mjs.map +1 -1
- package/d1/migrator.cjs +13 -1
- package/d1/migrator.cjs.map +1 -1
- package/d1/migrator.d.ts +5 -5
- package/d1/migrator.mjs +11 -1
- package/d1/migrator.mjs.map +1 -1
- package/{db.d-ae495c35.d.ts → db.d-a2311092.d.ts} +121 -44
- package/{db.d-66553b9e.d.ts → db.d-bc9a1d6c.d.ts} +193 -16
- package/driver.d-17ca4c15.d.ts +8 -0
- package/driver.d-300ddb0e.d.ts +64 -0
- package/driver.d-45e56643.d.ts +60 -0
- package/driver.d-64f2125c.d.ts +8 -0
- package/driver.d-7fde2e9d.d.ts +55 -0
- package/driver.d-9d703b84.d.ts +8 -0
- package/driver.d-b2b94bf9.d.ts +46 -0
- package/driver.d-b70ee7ee.d.ts +55 -0
- package/driver.d-dea23ee6.d.ts +8 -0
- package/driver.d-e54af17b.d.ts +52 -0
- package/driver.d-eb490c91.d.ts +9 -0
- package/driver.d-ef6fa2df.d.ts +14 -0
- package/errors-bb636d84.mjs +19 -0
- package/errors-bb636d84.mjs.map +1 -0
- package/errors-d0192d62.cjs +22 -0
- package/errors-d0192d62.cjs.map +1 -0
- package/index.cjs +105 -1
- package/index.cjs.map +1 -1
- package/index.d.ts +16 -432
- package/index.mjs +3 -1
- package/index.mjs.map +1 -1
- package/knex/index.cjs +2 -1
- package/knex/index.cjs.map +1 -1
- package/knex/index.d.ts +1 -1
- package/kysely/index.cjs +2 -1
- package/kysely/index.cjs.map +1 -1
- package/kysely/index.d.ts +1 -1
- package/libsql/index.cjs +155 -1
- package/libsql/index.cjs.map +1 -1
- package/libsql/index.d.ts +14 -12
- package/libsql/index.mjs +150 -1
- package/libsql/index.mjs.map +1 -1
- package/libsql/migrator.cjs +13 -1
- package/libsql/migrator.cjs.map +1 -1
- package/libsql/migrator.d.ts +5 -5
- package/libsql/migrator.mjs +11 -1
- package/libsql/migrator.mjs.map +1 -1
- package/logger-caa1ca6e.cjs +34 -0
- package/logger-caa1ca6e.cjs.map +1 -0
- package/logger-caf75bde.mjs +30 -0
- package/logger-caf75bde.mjs.map +1 -0
- package/migrator.cjs +48 -1
- package/migrator.cjs.map +1 -1
- package/migrator.mjs +46 -1
- package/migrator.mjs.map +1 -1
- package/mysql-core/index.cjs +1004 -1
- package/mysql-core/index.cjs.map +1 -1
- package/mysql-core/index.d.ts +347 -347
- package/mysql-core/index.mjs +869 -1
- package/mysql-core/index.mjs.map +1 -1
- package/mysql2/index.cjs +230 -1
- package/mysql2/index.cjs.map +1 -1
- package/mysql2/index.d.ts +5 -6
- package/mysql2/index.mjs +223 -1
- package/mysql2/index.mjs.map +1 -1
- package/mysql2/migrator.cjs +13 -1
- package/mysql2/migrator.cjs.map +1 -1
- package/mysql2/migrator.d.ts +5 -6
- package/mysql2/migrator.mjs +11 -1
- package/mysql2/migrator.mjs.map +1 -1
- package/neon-serverless/index.cjs +155 -1
- package/neon-serverless/index.cjs.map +1 -1
- package/neon-serverless/index.d.ts +5 -6
- package/neon-serverless/index.mjs +149 -1
- package/neon-serverless/index.mjs.map +1 -1
- package/neon-serverless/migrator.cjs +13 -1
- package/neon-serverless/migrator.cjs.map +1 -1
- package/neon-serverless/migrator.d.ts +5 -6
- package/neon-serverless/migrator.mjs +11 -1
- package/neon-serverless/migrator.mjs.map +1 -1
- package/node-postgres/index.cjs +157 -1
- package/node-postgres/index.cjs.map +1 -1
- package/node-postgres/index.d.ts +5 -6
- package/node-postgres/index.mjs +151 -1
- package/node-postgres/index.mjs.map +1 -1
- package/node-postgres/migrator.cjs +13 -1
- package/node-postgres/migrator.cjs.map +1 -1
- package/node-postgres/migrator.d.ts +5 -6
- package/node-postgres/migrator.mjs +11 -1
- package/node-postgres/migrator.mjs.map +1 -1
- package/package.json +97 -34
- package/pg-core/index.cjs +652 -1
- package/pg-core/index.cjs.map +1 -1
- package/pg-core/index.d.ts +13 -7
- package/pg-core/index.mjs +501 -1
- package/pg-core/index.mjs.map +1 -1
- package/planetscale-serverless/index.cjs +111 -1
- package/planetscale-serverless/index.cjs.map +1 -1
- package/planetscale-serverless/index.d.ts +5 -6
- package/planetscale-serverless/index.mjs +106 -1
- package/planetscale-serverless/index.mjs.map +1 -1
- package/planetscale-serverless/migrator.cjs +13 -1
- package/planetscale-serverless/migrator.cjs.map +1 -1
- package/planetscale-serverless/migrator.d.ts +5 -6
- package/planetscale-serverless/migrator.mjs +11 -1
- package/planetscale-serverless/migrator.mjs.map +1 -1
- package/postgres-js/index.cjs +113 -1
- package/postgres-js/index.cjs.map +1 -1
- package/postgres-js/index.d.ts +5 -6
- package/postgres-js/index.mjs +108 -1
- package/postgres-js/index.mjs.map +1 -1
- package/postgres-js/migrator.cjs +13 -1
- package/postgres-js/migrator.cjs.map +1 -1
- package/postgres-js/migrator.d.ts +5 -6
- package/postgres-js/migrator.mjs +11 -1
- package/postgres-js/migrator.mjs.map +1 -1
- package/query-promise.d-e370e0a9.d.ts +617 -0
- package/relations-47eb5c5f.mjs +2954 -0
- package/relations-47eb5c5f.mjs.map +1 -0
- package/relations-5e2d30dd.cjs +3117 -0
- package/relations-5e2d30dd.cjs.map +1 -0
- package/{select.types.d-c3e86d45.d.ts → select.types.d-34d7f74e.d.ts} +1 -1
- package/{select.types.d-adb82002.d.ts → select.types.d-ae2f8e44.d.ts} +58 -14
- package/session-483ed08d.mjs +1263 -0
- package/session-483ed08d.mjs.map +1 -0
- package/session-6bd76405.cjs +362 -0
- package/session-6bd76405.cjs.map +1 -0
- package/session-a90df8a2.cjs +1252 -0
- package/session-a90df8a2.cjs.map +1 -0
- package/session-b99382a2.mjs +1223 -0
- package/session-b99382a2.mjs.map +1 -0
- package/session-c62f6348.cjs +1298 -0
- package/session-c62f6348.cjs.map +1 -0
- package/session-e8745392.mjs +351 -0
- package/session-e8745392.mjs.map +1 -0
- package/sql-js/index.cjs +175 -1
- package/sql-js/index.cjs.map +1 -1
- package/sql-js/index.d.ts +14 -12
- package/sql-js/index.mjs +170 -1
- package/sql-js/index.mjs.map +1 -1
- package/sql-js/migrator.cjs +13 -1
- package/sql-js/migrator.cjs.map +1 -1
- package/sql-js/migrator.d.ts +5 -5
- package/sql-js/migrator.mjs +11 -1
- package/sql-js/migrator.mjs.map +1 -1
- package/sqlite-core/index.cjs +516 -1
- package/sqlite-core/index.cjs.map +1 -1
- package/sqlite-core/index.d.ts +6 -5
- package/sqlite-core/index.mjs +441 -1
- package/sqlite-core/index.mjs.map +1 -1
- package/sqlite-proxy/index.cjs +118 -1
- package/sqlite-proxy/index.cjs.map +1 -1
- package/sqlite-proxy/index.d.ts +12 -11
- package/sqlite-proxy/index.mjs +113 -1
- package/sqlite-proxy/index.mjs.map +1 -1
- package/sqlite-proxy/migrator.cjs +25 -2
- package/sqlite-proxy/migrator.cjs.map +1 -1
- package/sqlite-proxy/migrator.d.ts +5 -5
- package/sqlite-proxy/migrator.mjs +23 -2
- package/sqlite-proxy/migrator.mjs.map +1 -1
- package/version.cjs +9 -1
- package/version.cjs.map +1 -1
- package/version.d.ts +1 -1
- package/version.mjs +6 -1
- package/version.mjs.map +1 -1
- package/README.md +0 -150
- package/column-builder-592f0191.mjs +0 -2
- package/column-builder-592f0191.mjs.map +0 -1
- package/column-builder-b48639f3.cjs +0 -2
- package/column-builder-b48639f3.cjs.map +0 -1
- package/driver.d-0158cd93.d.ts +0 -11
- package/driver.d-1f73a4a9.d.ts +0 -70
- package/driver.d-2e907d12.d.ts +0 -17
- package/driver.d-3781598a.d.ts +0 -11
- package/driver.d-3a8adf2a.d.ts +0 -61
- package/driver.d-59580d08.d.ts +0 -11
- package/driver.d-5f3fc125.d.ts +0 -12
- package/driver.d-693f7f9f.d.ts +0 -56
- package/driver.d-6c43e393.d.ts +0 -60
- package/driver.d-b00fc6ec.d.ts +0 -57
- package/driver.d-e4bd120b.d.ts +0 -47
- package/driver.d-f4b5b390.d.ts +0 -11
- package/index-59b7992d.cjs +0 -2
- package/index-59b7992d.cjs.map +0 -1
- package/index-b71998f1.mjs +0 -2
- package/index-b71998f1.mjs.map +0 -1
- package/logger-04bad527.cjs +0 -2
- package/logger-04bad527.cjs.map +0 -1
- package/logger-2598bf05.mjs +0 -2
- package/logger-2598bf05.mjs.map +0 -1
- package/logger.d-37185354.d.ts +0 -21
- package/query-builder-2f2e8229.cjs +0 -2
- package/query-builder-2f2e8229.cjs.map +0 -1
- package/query-builder-2fcde2f0.mjs +0 -2
- package/query-builder-2fcde2f0.mjs.map +0 -1
- package/query-promise-2c5b43ab.cjs +0 -2
- package/query-promise-2c5b43ab.cjs.map +0 -1
- package/query-promise-a65edd44.mjs +0 -2
- package/query-promise-a65edd44.mjs.map +0 -1
- package/query-promise.d-a8af8583.d.ts +0 -9
- package/session-8a621f09.mjs +0 -8
- package/session-8a621f09.mjs.map +0 -1
- package/session-b6939bab.cjs +0 -14
- package/session-b6939bab.cjs.map +0 -1
- package/session-b977ce56.mjs +0 -14
- package/session-b977ce56.mjs.map +0 -1
- package/session-c891400d.mjs +0 -8
- package/session-c891400d.mjs.map +0 -1
- package/session-e6db6732.cjs +0 -8
- package/session-e6db6732.cjs.map +0 -1
- package/session-ef1ef979.cjs +0 -8
- package/session-ef1ef979.cjs.map +0 -1
- package/utils-9d882195.cjs +0 -2
- package/utils-9d882195.cjs.map +0 -1
- package/utils-e6870670.mjs +0 -2
- package/utils-e6870670.mjs.map +0 -1
|
@@ -0,0 +1,2954 @@
|
|
|
1
|
+
/*
|
|
2
|
+
`Column` only accepts a full `ColumnConfig` as its generic.
|
|
3
|
+
To infer parts of the config, use `AnyColumn` that accepts a partial config.
|
|
4
|
+
See `GetColumnData` for example usage of inferring.
|
|
5
|
+
*/
|
|
6
|
+
class Column {
|
|
7
|
+
constructor(table, config) {
|
|
8
|
+
this.table = table;
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.name = config.name;
|
|
11
|
+
this.notNull = config.notNull;
|
|
12
|
+
this.default = config.default;
|
|
13
|
+
this.hasDefault = config.hasDefault;
|
|
14
|
+
this.primary = config.primaryKey;
|
|
15
|
+
}
|
|
16
|
+
mapFromDriverValue(value) {
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
mapToDriverValue(value) {
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const ViewBaseConfig = Symbol('ViewBaseConfig');
|
|
25
|
+
class View {
|
|
26
|
+
constructor({ name, schema, selectedFields, query }) {
|
|
27
|
+
this[ViewBaseConfig] = {
|
|
28
|
+
name,
|
|
29
|
+
originalName: name,
|
|
30
|
+
schema,
|
|
31
|
+
selectedFields,
|
|
32
|
+
query: query,
|
|
33
|
+
isExisting: !query,
|
|
34
|
+
isAlias: false,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const SubqueryConfig = Symbol('SubqueryConfig');
|
|
40
|
+
class Subquery {
|
|
41
|
+
constructor(sql, selection, alias, isWith = false) {
|
|
42
|
+
this[SubqueryConfig] = {
|
|
43
|
+
sql,
|
|
44
|
+
selection,
|
|
45
|
+
alias,
|
|
46
|
+
isWith,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
class WithSubquery extends Subquery {
|
|
51
|
+
}
|
|
52
|
+
class SelectionProxyHandler {
|
|
53
|
+
constructor(config) {
|
|
54
|
+
this.config = { ...config };
|
|
55
|
+
}
|
|
56
|
+
get(subquery, prop) {
|
|
57
|
+
if (prop === SubqueryConfig) {
|
|
58
|
+
return {
|
|
59
|
+
...subquery[SubqueryConfig],
|
|
60
|
+
selection: new Proxy(subquery[SubqueryConfig].selection, this),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (prop === ViewBaseConfig) {
|
|
64
|
+
return {
|
|
65
|
+
...subquery[ViewBaseConfig],
|
|
66
|
+
selectedFields: new Proxy(subquery[ViewBaseConfig].selectedFields, this),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (typeof prop === 'symbol') {
|
|
70
|
+
return subquery[prop];
|
|
71
|
+
}
|
|
72
|
+
const columns = subquery instanceof Subquery
|
|
73
|
+
? subquery[SubqueryConfig].selection
|
|
74
|
+
: subquery instanceof View
|
|
75
|
+
? subquery[ViewBaseConfig].selectedFields
|
|
76
|
+
: subquery;
|
|
77
|
+
const value = columns[prop];
|
|
78
|
+
if (value instanceof SQL.Aliased) {
|
|
79
|
+
// Never return the underlying SQL expression for a field previously selected in a subquery
|
|
80
|
+
if (this.config.sqlAliasedBehavior === 'sql' && !value.isSelectionField) {
|
|
81
|
+
return value.sql;
|
|
82
|
+
}
|
|
83
|
+
const newValue = value.clone();
|
|
84
|
+
newValue.isSelectionField = true;
|
|
85
|
+
return newValue;
|
|
86
|
+
}
|
|
87
|
+
if (value instanceof SQL) {
|
|
88
|
+
if (this.config.sqlBehavior === 'sql') {
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
throw new Error(`You tried to reference "${prop}" field from a subquery, which is a raw SQL field, but it doesn't have an alias declared. Please add an alias to the field using ".as('alias')" method.`);
|
|
92
|
+
}
|
|
93
|
+
if (value instanceof Column) {
|
|
94
|
+
if (this.config.alias) {
|
|
95
|
+
return new Proxy(value, new ColumnAliasProxyHandler(new Proxy(value.table, new TableAliasProxyHandler(this.config.alias, this.config.replaceOriginalName ?? false))));
|
|
96
|
+
}
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
if (typeof value !== 'object' || value === null) {
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
return new Proxy(value, new SelectionProxyHandler(this.config));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
var _a$2, _b$1, _c;
|
|
107
|
+
/** @internal */
|
|
108
|
+
const TableName = Symbol('Name');
|
|
109
|
+
/** @internal */
|
|
110
|
+
const Schema = Symbol('Schema');
|
|
111
|
+
/** @internal */
|
|
112
|
+
const Columns = Symbol('Columns');
|
|
113
|
+
/** @internal */
|
|
114
|
+
const OriginalName = Symbol('OriginalName');
|
|
115
|
+
/** @internal */
|
|
116
|
+
const BaseName = Symbol('BaseName');
|
|
117
|
+
/** @internal */
|
|
118
|
+
const IsAlias = Symbol('IsAlias');
|
|
119
|
+
/** @internal */
|
|
120
|
+
const ExtraConfigBuilder = Symbol('ExtraConfigBuilder');
|
|
121
|
+
const IsDrizzleTable = Symbol.for('IsDrizzleTable');
|
|
122
|
+
class Table {
|
|
123
|
+
constructor(name, schema, baseName) {
|
|
124
|
+
/** @internal */
|
|
125
|
+
this[_a$2] = false;
|
|
126
|
+
/** @internal */
|
|
127
|
+
this[_b$1] = undefined;
|
|
128
|
+
this[_c] = true;
|
|
129
|
+
this[TableName] = this[OriginalName] = name;
|
|
130
|
+
this[Schema] = schema;
|
|
131
|
+
this[BaseName] = baseName;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
_a$2 = IsAlias, _b$1 = ExtraConfigBuilder, _c = IsDrizzleTable;
|
|
135
|
+
/** @internal */
|
|
136
|
+
Table.Symbol = {
|
|
137
|
+
Name: TableName,
|
|
138
|
+
Schema: Schema,
|
|
139
|
+
OriginalName: OriginalName,
|
|
140
|
+
Columns: Columns,
|
|
141
|
+
BaseName: BaseName,
|
|
142
|
+
IsAlias: IsAlias,
|
|
143
|
+
ExtraConfigBuilder: ExtraConfigBuilder,
|
|
144
|
+
};
|
|
145
|
+
function isTable(table) {
|
|
146
|
+
return typeof table === 'object' && table !== null && IsDrizzleTable in table;
|
|
147
|
+
}
|
|
148
|
+
function getTableName(table) {
|
|
149
|
+
return table[TableName];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function bindIfParam(value, column) {
|
|
153
|
+
if (isDriverValueEncoder(column) && !isSQLWrapper(value) && !(value instanceof Param) && !(value instanceof Placeholder)
|
|
154
|
+
&& !(value instanceof Column) && !(value instanceof Table) && !(value instanceof View)) {
|
|
155
|
+
return new Param(value, column);
|
|
156
|
+
}
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
function eq(left, right) {
|
|
160
|
+
return sql `${left} = ${bindIfParam(right, left)}`;
|
|
161
|
+
}
|
|
162
|
+
function ne(left, right) {
|
|
163
|
+
return sql `${left} <> ${bindIfParam(right, left)}`;
|
|
164
|
+
}
|
|
165
|
+
function and(...unfilteredConditions) {
|
|
166
|
+
const conditions = unfilteredConditions.filter((c) => c !== undefined);
|
|
167
|
+
if (conditions.length === 0) {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
if (conditions.length === 1) {
|
|
171
|
+
return conditions[0];
|
|
172
|
+
}
|
|
173
|
+
const chunks = [sql.raw('(')];
|
|
174
|
+
for (const [index, condition] of conditions.entries()) {
|
|
175
|
+
if (index === 0) {
|
|
176
|
+
chunks.push(condition);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
chunks.push(sql ` and `, condition);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
chunks.push(sql `)`);
|
|
183
|
+
return sql.fromList(chunks);
|
|
184
|
+
}
|
|
185
|
+
function or(...unfilteredConditions) {
|
|
186
|
+
const conditions = unfilteredConditions.filter((c) => c !== undefined);
|
|
187
|
+
if (conditions.length === 0) {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
if (conditions.length === 1) {
|
|
191
|
+
return conditions[0];
|
|
192
|
+
}
|
|
193
|
+
const chunks = [sql.raw('(')];
|
|
194
|
+
for (const [index, condition] of conditions.entries()) {
|
|
195
|
+
if (index === 0) {
|
|
196
|
+
chunks.push(condition);
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
chunks.push(sql ` or `, condition);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
chunks.push(sql `)`);
|
|
203
|
+
return sql.fromList(chunks);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Negate the meaning of an expression using the `not` keyword.
|
|
207
|
+
*
|
|
208
|
+
* ## Examples
|
|
209
|
+
*
|
|
210
|
+
* ```ts
|
|
211
|
+
* // Select cars _not_ made by GM or Ford.
|
|
212
|
+
* db.select().from(cars)
|
|
213
|
+
* .where(not(inArray(cars.make, ['GM', 'Ford'])))
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
function not(condition) {
|
|
217
|
+
return sql `not ${condition}`;
|
|
218
|
+
}
|
|
219
|
+
function gt(left, right) {
|
|
220
|
+
return sql `${left} > ${bindIfParam(right, left)}`;
|
|
221
|
+
}
|
|
222
|
+
function gte(left, right) {
|
|
223
|
+
return sql `${left} >= ${bindIfParam(right, left)}`;
|
|
224
|
+
}
|
|
225
|
+
function lt(left, right) {
|
|
226
|
+
return sql `${left} < ${bindIfParam(right, left)}`;
|
|
227
|
+
}
|
|
228
|
+
function lte(left, right) {
|
|
229
|
+
return sql `${left} <= ${bindIfParam(right, left)}`;
|
|
230
|
+
}
|
|
231
|
+
function inArray(column, values) {
|
|
232
|
+
if (Array.isArray(values)) {
|
|
233
|
+
if (values.length === 0) {
|
|
234
|
+
throw new Error('inArray requires at least one value');
|
|
235
|
+
}
|
|
236
|
+
return sql `${column} in ${values.map((v) => bindIfParam(v, column))}`;
|
|
237
|
+
}
|
|
238
|
+
return sql `${column} in ${bindIfParam(values, column)}`;
|
|
239
|
+
}
|
|
240
|
+
function notInArray(column, values) {
|
|
241
|
+
if (isSQLWrapper(values)) {
|
|
242
|
+
return sql `${column} not in ${values}`;
|
|
243
|
+
}
|
|
244
|
+
if (Array.isArray(values)) {
|
|
245
|
+
if (values.length === 0) {
|
|
246
|
+
throw new Error('inArray requires at least one value');
|
|
247
|
+
}
|
|
248
|
+
return sql `${column} not in ${values.map((v) => bindIfParam(v, column))}`;
|
|
249
|
+
}
|
|
250
|
+
return sql `${column} not in ${bindIfParam(values, column)}`;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Test whether an expression is NULL. By the SQL standard,
|
|
254
|
+
* NULL is neither equal nor not equal to itself, so
|
|
255
|
+
* it's recommended to use `isNull` and `notIsNull` for
|
|
256
|
+
* comparisons to NULL.
|
|
257
|
+
*
|
|
258
|
+
* ## Examples
|
|
259
|
+
*
|
|
260
|
+
* ```ts
|
|
261
|
+
* // Select cars that have no discontinuedAt date.
|
|
262
|
+
* db.select().from(cars)
|
|
263
|
+
* .where(isNull(cars.discontinuedAt))
|
|
264
|
+
* ```
|
|
265
|
+
*
|
|
266
|
+
* @see isNotNull for the inverse of this test
|
|
267
|
+
*/
|
|
268
|
+
function isNull(column) {
|
|
269
|
+
return sql `${column} is null`;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Test whether an expression is not NULL. By the SQL standard,
|
|
273
|
+
* NULL is neither equal nor not equal to itself, so
|
|
274
|
+
* it's recommended to use `isNull` and `notIsNull` for
|
|
275
|
+
* comparisons to NULL.
|
|
276
|
+
*
|
|
277
|
+
* ## Examples
|
|
278
|
+
*
|
|
279
|
+
* ```ts
|
|
280
|
+
* // Select cars that have been discontinued.
|
|
281
|
+
* db.select().from(cars)
|
|
282
|
+
* .where(isNotNull(cars.discontinuedAt))
|
|
283
|
+
* ```
|
|
284
|
+
*
|
|
285
|
+
* @see isNull for the inverse of this test
|
|
286
|
+
*/
|
|
287
|
+
function isNotNull(column) {
|
|
288
|
+
return sql `${column} is not null`;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Test whether a subquery evaluates to have any rows.
|
|
292
|
+
*
|
|
293
|
+
* ## Examples
|
|
294
|
+
*
|
|
295
|
+
* ```ts
|
|
296
|
+
* // Users whose `homeCity` column has a match in a cities
|
|
297
|
+
* // table.
|
|
298
|
+
* db
|
|
299
|
+
* .select()
|
|
300
|
+
* .from(users)
|
|
301
|
+
* .where(
|
|
302
|
+
* exists(db.select()
|
|
303
|
+
* .from(cities)
|
|
304
|
+
* .where(eq(users.homeCity, cities.id))),
|
|
305
|
+
* );
|
|
306
|
+
* ```
|
|
307
|
+
*
|
|
308
|
+
* @see notExists for the inverse of this test
|
|
309
|
+
*/
|
|
310
|
+
function exists(subquery) {
|
|
311
|
+
return sql `exists (${subquery})`;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Test whether a subquery doesn't include any result
|
|
315
|
+
* rows.
|
|
316
|
+
*
|
|
317
|
+
* ## Examples
|
|
318
|
+
*
|
|
319
|
+
* ```ts
|
|
320
|
+
* // Users whose `homeCity` column doesn't match
|
|
321
|
+
* // a row in the cities table.
|
|
322
|
+
* db
|
|
323
|
+
* .select()
|
|
324
|
+
* .from(users)
|
|
325
|
+
* .where(
|
|
326
|
+
* notExists(db.select()
|
|
327
|
+
* .from(cities)
|
|
328
|
+
* .where(eq(users.homeCity, cities.id))),
|
|
329
|
+
* );
|
|
330
|
+
* ```
|
|
331
|
+
*
|
|
332
|
+
* @see exists for the inverse of this test
|
|
333
|
+
*/
|
|
334
|
+
function notExists(subquery) {
|
|
335
|
+
return sql `exists (${subquery})`;
|
|
336
|
+
}
|
|
337
|
+
function between(column, min, max) {
|
|
338
|
+
return sql `${column} between ${bindIfParam(min, column)} and ${bindIfParam(max, column)}`;
|
|
339
|
+
}
|
|
340
|
+
function notBetween(column, min, max) {
|
|
341
|
+
return sql `${column} not between ${bindIfParam(min, column)} and ${bindIfParam(max, column)}`;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Compare a column to a pattern, which can include `%` and `_`
|
|
345
|
+
* characters to match multiple variations. Including `%`
|
|
346
|
+
* in the pattern matches zero or more characters, and including
|
|
347
|
+
* `_` will match a single character.
|
|
348
|
+
*
|
|
349
|
+
* ## Examples
|
|
350
|
+
*
|
|
351
|
+
* ```ts
|
|
352
|
+
* // Select all cars with 'Turbo' in their names.
|
|
353
|
+
* db.select().from(cars)
|
|
354
|
+
* .where(like(cars.name, '%Turbo%'))
|
|
355
|
+
* ```
|
|
356
|
+
*
|
|
357
|
+
* @see ilike for a case-insensitive version of this condition
|
|
358
|
+
*/
|
|
359
|
+
function like(column, value) {
|
|
360
|
+
return sql `${column} like ${value}`;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* The inverse of like - this tests that a given column
|
|
364
|
+
* does not match a pattern, which can include `%` and `_`
|
|
365
|
+
* characters to match multiple variations. Including `%`
|
|
366
|
+
* in the pattern matches zero or more characters, and including
|
|
367
|
+
* `_` will match a single character.
|
|
368
|
+
*
|
|
369
|
+
* ## Examples
|
|
370
|
+
*
|
|
371
|
+
* ```ts
|
|
372
|
+
* // Select all cars that don't have "ROver" in their name.
|
|
373
|
+
* db.select().from(cars)
|
|
374
|
+
* .where(notLike(cars.name, '%Rover%'))
|
|
375
|
+
* ```
|
|
376
|
+
*
|
|
377
|
+
* @see like for the inverse condition
|
|
378
|
+
* @see notIlike for a case-insensitive version of this condition
|
|
379
|
+
*/
|
|
380
|
+
function notLike(column, value) {
|
|
381
|
+
return sql `${column} not like ${value}`;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Case-insensitively compare a column to a pattern,
|
|
385
|
+
* which can include `%` and `_`
|
|
386
|
+
* characters to match multiple variations. Including `%`
|
|
387
|
+
* in the pattern matches zero or more characters, and including
|
|
388
|
+
* `_` will match a single character.
|
|
389
|
+
*
|
|
390
|
+
* Unlike like, this performs a case-insensitive comparison.
|
|
391
|
+
*
|
|
392
|
+
* ## Examples
|
|
393
|
+
*
|
|
394
|
+
* ```ts
|
|
395
|
+
* // Select all cars with 'Turbo' in their names.
|
|
396
|
+
* db.select().from(cars)
|
|
397
|
+
* .where(ilike(cars.name, '%Turbo%'))
|
|
398
|
+
* ```
|
|
399
|
+
*
|
|
400
|
+
* @see like for a case-sensitive version of this condition
|
|
401
|
+
*/
|
|
402
|
+
function ilike(column, value) {
|
|
403
|
+
return sql `${column} ilike ${value}`;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* The inverse of ilike - this case-insensitively tests that a given column
|
|
407
|
+
* does not match a pattern, which can include `%` and `_`
|
|
408
|
+
* characters to match multiple variations. Including `%`
|
|
409
|
+
* in the pattern matches zero or more characters, and including
|
|
410
|
+
* `_` will match a single character.
|
|
411
|
+
*
|
|
412
|
+
* ## Examples
|
|
413
|
+
*
|
|
414
|
+
* ```ts
|
|
415
|
+
* // Select all cars that don't have "Rover" in their name.
|
|
416
|
+
* db.select().from(cars)
|
|
417
|
+
* .where(notLike(cars.name, '%Rover%'))
|
|
418
|
+
* ```
|
|
419
|
+
*
|
|
420
|
+
* @see ilike for the inverse condition
|
|
421
|
+
* @see notLike for a case-sensitive version of this condition
|
|
422
|
+
*/
|
|
423
|
+
function notIlike(column, value) {
|
|
424
|
+
return sql `${column} not ilike ${value}`;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Used in sorting, this specifies that the given
|
|
429
|
+
* column or expression should be sorted in ascending
|
|
430
|
+
* order. By the SQL standard, ascending order is the
|
|
431
|
+
* default, so it is not usually necessary to specify
|
|
432
|
+
* ascending sort order.
|
|
433
|
+
*
|
|
434
|
+
* ## Examples
|
|
435
|
+
*
|
|
436
|
+
* ```ts
|
|
437
|
+
* // Return cars, starting with the oldest models
|
|
438
|
+
* // and going in ascending order to the newest.
|
|
439
|
+
* db.select().from(cars)
|
|
440
|
+
* .orderBy(asc(cars.year));
|
|
441
|
+
* ```
|
|
442
|
+
*
|
|
443
|
+
* @see desc to sort in descending order
|
|
444
|
+
*/
|
|
445
|
+
function asc(column) {
|
|
446
|
+
return sql `${column} asc`;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Used in sorting, this specifies that the given
|
|
450
|
+
* column or expression should be sorted in descending
|
|
451
|
+
* order.
|
|
452
|
+
*
|
|
453
|
+
* ## Examples
|
|
454
|
+
*
|
|
455
|
+
* ```ts
|
|
456
|
+
* // Select users, with the most recently created
|
|
457
|
+
* // records coming first.
|
|
458
|
+
* db.select().from(users)
|
|
459
|
+
* .orderBy(desc(users.createdAt));
|
|
460
|
+
* ```
|
|
461
|
+
*
|
|
462
|
+
* @see asc to sort in ascending order
|
|
463
|
+
*/
|
|
464
|
+
function desc(column) {
|
|
465
|
+
return sql `${column} desc`;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* This class is used to indicate a primitive param value that is used in `sql` tag.
|
|
470
|
+
* It is only used on type level and is never instantiated at runtime.
|
|
471
|
+
* If you see a value of this type in the code, its runtime value is actually the primitive param value.
|
|
472
|
+
*/
|
|
473
|
+
class FakePrimitiveParam {
|
|
474
|
+
}
|
|
475
|
+
function isSQLWrapper(value) {
|
|
476
|
+
return typeof value === 'object' && value !== null && 'getSQL' in value
|
|
477
|
+
&& typeof value.getSQL === 'function';
|
|
478
|
+
}
|
|
479
|
+
function mergeQueries(queries) {
|
|
480
|
+
const result = { sql: '', params: [] };
|
|
481
|
+
for (const query of queries) {
|
|
482
|
+
result.sql += query.sql;
|
|
483
|
+
result.params.push(...query.params);
|
|
484
|
+
if (result.typings && query.typings?.length) {
|
|
485
|
+
result.typings.push(...query.typings);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return result;
|
|
489
|
+
}
|
|
490
|
+
class StringChunk {
|
|
491
|
+
constructor(value) {
|
|
492
|
+
this.value = Array.isArray(value) ? value : [value];
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
class SQL {
|
|
496
|
+
constructor(queryChunks) {
|
|
497
|
+
this.queryChunks = queryChunks;
|
|
498
|
+
/** @internal */
|
|
499
|
+
this.decoder = noopDecoder;
|
|
500
|
+
this.shouldInlineParams = false;
|
|
501
|
+
}
|
|
502
|
+
append(query) {
|
|
503
|
+
this.queryChunks.push(...query.queryChunks);
|
|
504
|
+
return this;
|
|
505
|
+
}
|
|
506
|
+
toQuery(config) {
|
|
507
|
+
return this.buildQueryFromSourceParams(this.queryChunks, config);
|
|
508
|
+
}
|
|
509
|
+
buildQueryFromSourceParams(chunks, _config) {
|
|
510
|
+
const config = Object.assign({}, _config, {
|
|
511
|
+
inlineParams: _config.inlineParams || this.shouldInlineParams,
|
|
512
|
+
paramStartIndex: _config.paramStartIndex || { value: 0 },
|
|
513
|
+
});
|
|
514
|
+
const { escapeName, escapeParam, prepareTyping, inlineParams, paramStartIndex, } = config;
|
|
515
|
+
return mergeQueries(chunks.map((chunk) => {
|
|
516
|
+
if (chunk instanceof StringChunk) {
|
|
517
|
+
return { sql: chunk.value.join(''), params: [] };
|
|
518
|
+
}
|
|
519
|
+
if (chunk instanceof Name) {
|
|
520
|
+
return { sql: escapeName(chunk.value), params: [] };
|
|
521
|
+
}
|
|
522
|
+
if (chunk === undefined) {
|
|
523
|
+
return { sql: '', params: [] };
|
|
524
|
+
}
|
|
525
|
+
if (Array.isArray(chunk)) {
|
|
526
|
+
const result = [new StringChunk('(')];
|
|
527
|
+
for (const [i, p] of chunk.entries()) {
|
|
528
|
+
result.push(p);
|
|
529
|
+
if (i < chunk.length - 1) {
|
|
530
|
+
result.push(new StringChunk(', '));
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
result.push(new StringChunk(')'));
|
|
534
|
+
return this.buildQueryFromSourceParams(result, config);
|
|
535
|
+
}
|
|
536
|
+
if (chunk instanceof SQL) {
|
|
537
|
+
return this.buildQueryFromSourceParams(chunk.queryChunks, {
|
|
538
|
+
...config,
|
|
539
|
+
inlineParams: inlineParams || chunk.shouldInlineParams,
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
if (chunk instanceof Table) {
|
|
543
|
+
const schemaName = chunk[Table.Symbol.Schema];
|
|
544
|
+
const tableName = chunk[Table.Symbol.Name];
|
|
545
|
+
return {
|
|
546
|
+
sql: schemaName === undefined
|
|
547
|
+
? escapeName(tableName)
|
|
548
|
+
: escapeName(schemaName) + '.' + escapeName(tableName),
|
|
549
|
+
params: [],
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
if (chunk instanceof Column) {
|
|
553
|
+
return { sql: escapeName(chunk.table[Table.Symbol.Name]) + '.' + escapeName(chunk.name), params: [] };
|
|
554
|
+
}
|
|
555
|
+
if (chunk instanceof View) {
|
|
556
|
+
const schemaName = chunk[ViewBaseConfig].schema;
|
|
557
|
+
const viewName = chunk[ViewBaseConfig].name;
|
|
558
|
+
return {
|
|
559
|
+
sql: schemaName === undefined
|
|
560
|
+
? escapeName(viewName)
|
|
561
|
+
: escapeName(schemaName) + '.' + escapeName(viewName),
|
|
562
|
+
params: [],
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
if (chunk instanceof Param) {
|
|
566
|
+
const mappedValue = (chunk.value === null) ? null : chunk.encoder.mapToDriverValue(chunk.value);
|
|
567
|
+
if (mappedValue instanceof SQL) {
|
|
568
|
+
return this.buildQueryFromSourceParams([mappedValue], config);
|
|
569
|
+
}
|
|
570
|
+
if (inlineParams) {
|
|
571
|
+
return { sql: this.mapInlineParam(mappedValue, config), params: [] };
|
|
572
|
+
}
|
|
573
|
+
let typings;
|
|
574
|
+
if (prepareTyping !== undefined) {
|
|
575
|
+
typings = [prepareTyping(chunk.encoder)];
|
|
576
|
+
}
|
|
577
|
+
return { sql: escapeParam(paramStartIndex.value++, mappedValue), params: [mappedValue], typings };
|
|
578
|
+
}
|
|
579
|
+
if (chunk instanceof SQL.Aliased && chunk.fieldAlias !== undefined) {
|
|
580
|
+
return { sql: escapeName(chunk.fieldAlias), params: [] };
|
|
581
|
+
}
|
|
582
|
+
if (chunk instanceof Subquery) {
|
|
583
|
+
if (chunk[SubqueryConfig].isWith) {
|
|
584
|
+
return { sql: escapeName(chunk[SubqueryConfig].alias), params: [] };
|
|
585
|
+
}
|
|
586
|
+
return this.buildQueryFromSourceParams([
|
|
587
|
+
new StringChunk('('),
|
|
588
|
+
chunk[SubqueryConfig].sql,
|
|
589
|
+
new StringChunk(') '),
|
|
590
|
+
new Name(chunk[SubqueryConfig].alias),
|
|
591
|
+
], config);
|
|
592
|
+
}
|
|
593
|
+
if (isSQLWrapper(chunk)) {
|
|
594
|
+
return this.buildQueryFromSourceParams([
|
|
595
|
+
new StringChunk('('),
|
|
596
|
+
chunk.getSQL(),
|
|
597
|
+
new StringChunk(')'),
|
|
598
|
+
], config);
|
|
599
|
+
}
|
|
600
|
+
if (chunk instanceof Relation) {
|
|
601
|
+
return this.buildQueryFromSourceParams([
|
|
602
|
+
chunk.sourceTable,
|
|
603
|
+
new StringChunk('.'),
|
|
604
|
+
sql.identifier(chunk.fieldName),
|
|
605
|
+
], config);
|
|
606
|
+
}
|
|
607
|
+
if (inlineParams) {
|
|
608
|
+
return { sql: this.mapInlineParam(chunk, config), params: [] };
|
|
609
|
+
}
|
|
610
|
+
return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk] };
|
|
611
|
+
}));
|
|
612
|
+
}
|
|
613
|
+
mapInlineParam(chunk, { escapeString }) {
|
|
614
|
+
if (chunk === null) {
|
|
615
|
+
return 'null';
|
|
616
|
+
}
|
|
617
|
+
if (typeof chunk === 'number' || typeof chunk === 'boolean') {
|
|
618
|
+
return chunk.toString();
|
|
619
|
+
}
|
|
620
|
+
if (typeof chunk === 'string') {
|
|
621
|
+
return escapeString(chunk);
|
|
622
|
+
}
|
|
623
|
+
if (typeof chunk === 'object') {
|
|
624
|
+
const mappedValueAsString = chunk.toString();
|
|
625
|
+
if (mappedValueAsString === '[object Object]') {
|
|
626
|
+
return escapeString(JSON.stringify(chunk));
|
|
627
|
+
}
|
|
628
|
+
return escapeString(mappedValueAsString);
|
|
629
|
+
}
|
|
630
|
+
throw new Error('Unexpected param value: ' + chunk);
|
|
631
|
+
}
|
|
632
|
+
getSQL() {
|
|
633
|
+
return this;
|
|
634
|
+
}
|
|
635
|
+
as(alias) {
|
|
636
|
+
// TODO: remove with deprecated overloads
|
|
637
|
+
if (alias === undefined) {
|
|
638
|
+
return this;
|
|
639
|
+
}
|
|
640
|
+
return new SQL.Aliased(this, alias);
|
|
641
|
+
}
|
|
642
|
+
mapWith(decoder) {
|
|
643
|
+
this.decoder = typeof decoder === 'function' ? { mapFromDriverValue: decoder } : decoder;
|
|
644
|
+
return this;
|
|
645
|
+
}
|
|
646
|
+
inlineParams() {
|
|
647
|
+
this.shouldInlineParams = true;
|
|
648
|
+
return this;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Any DB name (table, column, index etc.)
|
|
653
|
+
*/
|
|
654
|
+
class Name {
|
|
655
|
+
constructor(value) {
|
|
656
|
+
this.value = value;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Any DB name (table, column, index etc.)
|
|
661
|
+
* @deprecated Use `sql.identifier` instead.
|
|
662
|
+
*/
|
|
663
|
+
function name(value) {
|
|
664
|
+
return new Name(value);
|
|
665
|
+
}
|
|
666
|
+
function isDriverValueEncoder(value) {
|
|
667
|
+
return typeof value === 'object' && value !== null && 'mapToDriverValue' in value
|
|
668
|
+
&& typeof value.mapToDriverValue === 'function';
|
|
669
|
+
}
|
|
670
|
+
const noopDecoder = {
|
|
671
|
+
mapFromDriverValue: (value) => value,
|
|
672
|
+
};
|
|
673
|
+
const noopEncoder = {
|
|
674
|
+
mapToDriverValue: (value) => value,
|
|
675
|
+
};
|
|
676
|
+
const noopMapper = {
|
|
677
|
+
...noopDecoder,
|
|
678
|
+
...noopEncoder,
|
|
679
|
+
};
|
|
680
|
+
/** Parameter value that is optionally bound to an encoder (for example, a column). */
|
|
681
|
+
class Param {
|
|
682
|
+
/**
|
|
683
|
+
* @param value - Parameter value
|
|
684
|
+
* @param encoder - Encoder to convert the value to a driver parameter
|
|
685
|
+
*/
|
|
686
|
+
constructor(value, encoder = noopEncoder) {
|
|
687
|
+
this.value = value;
|
|
688
|
+
this.encoder = encoder;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
function param(value, encoder) {
|
|
692
|
+
return new Param(value, encoder);
|
|
693
|
+
}
|
|
694
|
+
/*
|
|
695
|
+
The type of `params` is specified as `SQLSourceParam[]`, but that's slightly incorrect -
|
|
696
|
+
in runtime, users won't pass `FakePrimitiveParam` instances as `params` - they will pass primitive values
|
|
697
|
+
which will be wrapped in `Param` using `buildChunksFromParam(...)`. That's why the overload
|
|
698
|
+
specify `params` as `any[]` and not as `SQLSourceParam[]`. This type is used to make our lives easier and
|
|
699
|
+
the type checker happy.
|
|
700
|
+
*/
|
|
701
|
+
function sql(strings, ...params) {
|
|
702
|
+
const queryChunks = [];
|
|
703
|
+
if (params.length > 0 || (strings.length > 0 && strings[0] !== '')) {
|
|
704
|
+
queryChunks.push(new StringChunk(strings[0]));
|
|
705
|
+
}
|
|
706
|
+
for (const [paramIndex, param] of params.entries()) {
|
|
707
|
+
queryChunks.push(param, new StringChunk(strings[paramIndex + 1]));
|
|
708
|
+
}
|
|
709
|
+
return new SQL(queryChunks);
|
|
710
|
+
}
|
|
711
|
+
(function (sql) {
|
|
712
|
+
function empty() {
|
|
713
|
+
return new SQL([]);
|
|
714
|
+
}
|
|
715
|
+
sql.empty = empty;
|
|
716
|
+
function fromList(list) {
|
|
717
|
+
return new SQL(list);
|
|
718
|
+
}
|
|
719
|
+
sql.fromList = fromList;
|
|
720
|
+
/**
|
|
721
|
+
* Convenience function to create an SQL query from a raw string.
|
|
722
|
+
* @param str The raw SQL query string.
|
|
723
|
+
*/
|
|
724
|
+
function raw(str) {
|
|
725
|
+
return new SQL([new StringChunk(str)]);
|
|
726
|
+
}
|
|
727
|
+
sql.raw = raw;
|
|
728
|
+
/**
|
|
729
|
+
* Convenience function to join a list of SQL chunks with a separator.
|
|
730
|
+
*/
|
|
731
|
+
function join(chunks, separator) {
|
|
732
|
+
const result = [];
|
|
733
|
+
for (const [i, chunk] of chunks.entries()) {
|
|
734
|
+
if (i > 0) {
|
|
735
|
+
result.push(separator);
|
|
736
|
+
}
|
|
737
|
+
result.push(chunk);
|
|
738
|
+
}
|
|
739
|
+
return sql.fromList(result);
|
|
740
|
+
}
|
|
741
|
+
sql.join = join;
|
|
742
|
+
/**
|
|
743
|
+
* Any DB identifier (table name, column name, index name etc.)
|
|
744
|
+
*/
|
|
745
|
+
function identifier(value) {
|
|
746
|
+
return name(value);
|
|
747
|
+
}
|
|
748
|
+
sql.identifier = identifier;
|
|
749
|
+
})(sql || (sql = {}));
|
|
750
|
+
(function (SQL) {
|
|
751
|
+
class Aliased {
|
|
752
|
+
constructor(sql, fieldAlias) {
|
|
753
|
+
this.sql = sql;
|
|
754
|
+
this.fieldAlias = fieldAlias;
|
|
755
|
+
/** @internal */
|
|
756
|
+
this.isSelectionField = false;
|
|
757
|
+
}
|
|
758
|
+
getSQL() {
|
|
759
|
+
return this.sql;
|
|
760
|
+
}
|
|
761
|
+
/** @internal */
|
|
762
|
+
clone() {
|
|
763
|
+
return new Aliased(this.sql, this.fieldAlias);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
SQL.Aliased = Aliased;
|
|
767
|
+
})(SQL || (SQL = {}));
|
|
768
|
+
class Placeholder {
|
|
769
|
+
constructor(name) {
|
|
770
|
+
this.name = name;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
function placeholder(name) {
|
|
774
|
+
return new Placeholder(name);
|
|
775
|
+
}
|
|
776
|
+
function fillPlaceholders(params, values) {
|
|
777
|
+
return params.map((p) => {
|
|
778
|
+
if (p instanceof Placeholder) {
|
|
779
|
+
if (!(p.name in values)) {
|
|
780
|
+
throw new Error(`No value for placeholder "${p.name}" was provided`);
|
|
781
|
+
}
|
|
782
|
+
return values[p.name];
|
|
783
|
+
}
|
|
784
|
+
return p;
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
class ColumnAliasProxyHandler {
|
|
789
|
+
constructor(table) {
|
|
790
|
+
this.table = table;
|
|
791
|
+
}
|
|
792
|
+
get(columnObj, prop) {
|
|
793
|
+
if (prop === 'table') {
|
|
794
|
+
return this.table;
|
|
795
|
+
}
|
|
796
|
+
return columnObj[prop];
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
class TableAliasProxyHandler {
|
|
800
|
+
constructor(alias, replaceOriginalName) {
|
|
801
|
+
this.alias = alias;
|
|
802
|
+
this.replaceOriginalName = replaceOriginalName;
|
|
803
|
+
}
|
|
804
|
+
get(target, prop) {
|
|
805
|
+
if (prop === Table.Symbol.IsAlias) {
|
|
806
|
+
return true;
|
|
807
|
+
}
|
|
808
|
+
if (prop === Table.Symbol.Name) {
|
|
809
|
+
return this.alias;
|
|
810
|
+
}
|
|
811
|
+
if (this.replaceOriginalName && prop === Table.Symbol.OriginalName) {
|
|
812
|
+
return this.alias;
|
|
813
|
+
}
|
|
814
|
+
if (prop === ViewBaseConfig) {
|
|
815
|
+
return {
|
|
816
|
+
...target[ViewBaseConfig],
|
|
817
|
+
name: this.alias,
|
|
818
|
+
isAlias: true,
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
if (prop === Table.Symbol.Columns) {
|
|
822
|
+
const columns = target[Table.Symbol.Columns];
|
|
823
|
+
if (!columns) {
|
|
824
|
+
return columns;
|
|
825
|
+
}
|
|
826
|
+
const proxiedColumns = {};
|
|
827
|
+
Object.keys(columns).map((key) => {
|
|
828
|
+
proxiedColumns[key] = new Proxy(columns[key], new ColumnAliasProxyHandler(new Proxy(target, this)));
|
|
829
|
+
});
|
|
830
|
+
return proxiedColumns;
|
|
831
|
+
}
|
|
832
|
+
const value = target[prop];
|
|
833
|
+
if (value instanceof Column) {
|
|
834
|
+
return new Proxy(value, new ColumnAliasProxyHandler(new Proxy(target, this)));
|
|
835
|
+
}
|
|
836
|
+
return value;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
class RelationTableAliasProxyHandler {
|
|
840
|
+
constructor(alias) {
|
|
841
|
+
this.alias = alias;
|
|
842
|
+
}
|
|
843
|
+
get(target, prop) {
|
|
844
|
+
if (prop === 'sourceTable') {
|
|
845
|
+
return aliasedTable(target.sourceTable, this.alias);
|
|
846
|
+
}
|
|
847
|
+
return target[prop];
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
function aliasedTable(table, tableAlias) {
|
|
851
|
+
return new Proxy(table, new TableAliasProxyHandler(tableAlias, false));
|
|
852
|
+
}
|
|
853
|
+
function aliasedRelation(relation, tableAlias) {
|
|
854
|
+
return new Proxy(relation, new RelationTableAliasProxyHandler(tableAlias));
|
|
855
|
+
}
|
|
856
|
+
function aliasedTableColumn(column, tableAlias) {
|
|
857
|
+
return new Proxy(column, new ColumnAliasProxyHandler(new Proxy(column.table, new TableAliasProxyHandler(tableAlias, false))));
|
|
858
|
+
}
|
|
859
|
+
function mapColumnsInAliasedSQLToAlias(query, alias) {
|
|
860
|
+
return new SQL.Aliased(mapColumnsInSQLToAlias(query.sql, alias), query.fieldAlias);
|
|
861
|
+
}
|
|
862
|
+
function mapColumnsInSQLToAlias(query, alias) {
|
|
863
|
+
return sql.fromList(query.queryChunks.map((c) => {
|
|
864
|
+
if (c instanceof Column) {
|
|
865
|
+
return aliasedTableColumn(c, alias);
|
|
866
|
+
}
|
|
867
|
+
if (c instanceof SQL) {
|
|
868
|
+
return mapColumnsInSQLToAlias(c, alias);
|
|
869
|
+
}
|
|
870
|
+
if (c instanceof SQL.Aliased) {
|
|
871
|
+
return mapColumnsInAliasedSQLToAlias(c, alias);
|
|
872
|
+
}
|
|
873
|
+
return c;
|
|
874
|
+
}));
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// To understand how to use `ColumnBuilder` and `AnyColumnBuilder`, see `Column` and `AnyColumn` documentation.
|
|
878
|
+
class ColumnBuilder {
|
|
879
|
+
constructor(name) {
|
|
880
|
+
this.config = {
|
|
881
|
+
name,
|
|
882
|
+
notNull: false,
|
|
883
|
+
default: undefined,
|
|
884
|
+
primaryKey: false,
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
$type() {
|
|
888
|
+
return this;
|
|
889
|
+
}
|
|
890
|
+
notNull() {
|
|
891
|
+
this.config.notNull = true;
|
|
892
|
+
return this;
|
|
893
|
+
}
|
|
894
|
+
default(value) {
|
|
895
|
+
this.config.default = value;
|
|
896
|
+
this.config.hasDefault = true;
|
|
897
|
+
return this;
|
|
898
|
+
}
|
|
899
|
+
primaryKey() {
|
|
900
|
+
this.config.primaryKey = true;
|
|
901
|
+
this.config.notNull = true;
|
|
902
|
+
return this;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
var _a$1;
|
|
907
|
+
class QueryPromise {
|
|
908
|
+
constructor() {
|
|
909
|
+
this[_a$1] = 'QueryPromise';
|
|
910
|
+
}
|
|
911
|
+
catch(onRejected) {
|
|
912
|
+
return this.then(undefined, onRejected);
|
|
913
|
+
}
|
|
914
|
+
finally(onFinally) {
|
|
915
|
+
return this.then((value) => {
|
|
916
|
+
onFinally?.();
|
|
917
|
+
return value;
|
|
918
|
+
}, (reason) => {
|
|
919
|
+
onFinally?.();
|
|
920
|
+
throw reason;
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
then(onFulfilled, onRejected) {
|
|
924
|
+
return this.execute().then(onFulfilled, onRejected);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
_a$1 = Symbol.toStringTag;
|
|
928
|
+
|
|
929
|
+
class CheckBuilder {
|
|
930
|
+
constructor(name, value) {
|
|
931
|
+
this.name = name;
|
|
932
|
+
this.value = value;
|
|
933
|
+
}
|
|
934
|
+
/** @internal */
|
|
935
|
+
build(table) {
|
|
936
|
+
return new Check(table, this);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
class Check {
|
|
940
|
+
constructor(table, builder) {
|
|
941
|
+
this.table = table;
|
|
942
|
+
this.name = builder.name;
|
|
943
|
+
this.value = builder.value;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
function check(name, value) {
|
|
947
|
+
return new CheckBuilder(name, value);
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
var _a, _b;
|
|
951
|
+
/** @internal */
|
|
952
|
+
const InlineForeignKeys = Symbol('InlineForeignKeys');
|
|
953
|
+
class PgTable extends Table {
|
|
954
|
+
constructor() {
|
|
955
|
+
super(...arguments);
|
|
956
|
+
/**@internal */
|
|
957
|
+
this[_a] = [];
|
|
958
|
+
/** @internal */
|
|
959
|
+
this[_b] = undefined;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
_a = InlineForeignKeys, _b = Table.Symbol.ExtraConfigBuilder;
|
|
963
|
+
/** @internal */
|
|
964
|
+
PgTable.Symbol = Object.assign({}, Table.Symbol, {
|
|
965
|
+
InlineForeignKeys: InlineForeignKeys,
|
|
966
|
+
});
|
|
967
|
+
/** @internal */
|
|
968
|
+
function pgTableWithSchema(name, columns, extraConfig, schema, baseName = name) {
|
|
969
|
+
const rawTable = new PgTable(name, schema, baseName);
|
|
970
|
+
const builtColumns = Object.fromEntries(Object.entries(columns).map(([name, colBuilder]) => {
|
|
971
|
+
const column = colBuilder.build(rawTable);
|
|
972
|
+
rawTable[InlineForeignKeys].push(...colBuilder.buildForeignKeys(column, rawTable));
|
|
973
|
+
return [name, column];
|
|
974
|
+
}));
|
|
975
|
+
const table = Object.assign(rawTable, builtColumns);
|
|
976
|
+
table[Table.Symbol.Columns] = builtColumns;
|
|
977
|
+
if (extraConfig) {
|
|
978
|
+
table[PgTable.Symbol.ExtraConfigBuilder] = extraConfig;
|
|
979
|
+
}
|
|
980
|
+
return table;
|
|
981
|
+
}
|
|
982
|
+
const pgTable = (name, columns, extraConfig) => {
|
|
983
|
+
return pgTableWithSchema(name, columns, extraConfig, undefined);
|
|
984
|
+
};
|
|
985
|
+
function pgTableCreator(customizeTableName) {
|
|
986
|
+
return (name, columns, extraConfig) => {
|
|
987
|
+
return pgTableWithSchema(customizeTableName(name), columns, extraConfig, undefined, name);
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
class ForeignKeyBuilder {
|
|
992
|
+
constructor(config, actions) {
|
|
993
|
+
/** @internal */
|
|
994
|
+
this._onUpdate = 'no action';
|
|
995
|
+
/** @internal */
|
|
996
|
+
this._onDelete = 'no action';
|
|
997
|
+
this.reference = () => {
|
|
998
|
+
const { columns, foreignColumns } = config();
|
|
999
|
+
return { columns, foreignTable: foreignColumns[0].table, foreignColumns };
|
|
1000
|
+
};
|
|
1001
|
+
if (actions) {
|
|
1002
|
+
this._onUpdate = actions.onUpdate;
|
|
1003
|
+
this._onDelete = actions.onDelete;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
onUpdate(action) {
|
|
1007
|
+
this._onUpdate = action === undefined ? 'no action' : action;
|
|
1008
|
+
return this;
|
|
1009
|
+
}
|
|
1010
|
+
onDelete(action) {
|
|
1011
|
+
this._onDelete = action === undefined ? 'no action' : action;
|
|
1012
|
+
return this;
|
|
1013
|
+
}
|
|
1014
|
+
/** @internal */
|
|
1015
|
+
build(table) {
|
|
1016
|
+
return new ForeignKey(table, this);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
class ForeignKey {
|
|
1020
|
+
constructor(table, builder) {
|
|
1021
|
+
this.table = table;
|
|
1022
|
+
this.reference = builder.reference;
|
|
1023
|
+
this.onUpdate = builder._onUpdate;
|
|
1024
|
+
this.onDelete = builder._onDelete;
|
|
1025
|
+
}
|
|
1026
|
+
getName() {
|
|
1027
|
+
const { columns, foreignColumns } = this.reference();
|
|
1028
|
+
const columnNames = columns.map((column) => column.name);
|
|
1029
|
+
const foreignColumnNames = foreignColumns.map((column) => column.name);
|
|
1030
|
+
const chunks = [
|
|
1031
|
+
this.table[PgTable.Symbol.Name],
|
|
1032
|
+
...columnNames,
|
|
1033
|
+
foreignColumns[0].table[PgTable.Symbol.Name],
|
|
1034
|
+
...foreignColumnNames,
|
|
1035
|
+
];
|
|
1036
|
+
return `${chunks.join('_')}_fk`;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
function foreignKey(config) {
|
|
1040
|
+
function mappedConfig() {
|
|
1041
|
+
const { columns, foreignColumns } = config;
|
|
1042
|
+
return {
|
|
1043
|
+
columns,
|
|
1044
|
+
foreignColumns,
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
return new ForeignKeyBuilder(mappedConfig);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
class IndexBuilderOn {
|
|
1051
|
+
constructor(unique, name) {
|
|
1052
|
+
this.unique = unique;
|
|
1053
|
+
this.name = name;
|
|
1054
|
+
}
|
|
1055
|
+
on(...columns) {
|
|
1056
|
+
return new IndexBuilder(columns, this.unique, false, this.name);
|
|
1057
|
+
}
|
|
1058
|
+
onOnly(...columns) {
|
|
1059
|
+
return new IndexBuilder(columns, this.unique, true, this.name);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
class IndexBuilder {
|
|
1063
|
+
constructor(columns, unique, only, name) {
|
|
1064
|
+
this.config = {
|
|
1065
|
+
name,
|
|
1066
|
+
columns,
|
|
1067
|
+
unique,
|
|
1068
|
+
only,
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
concurrently() {
|
|
1072
|
+
this.config.concurrently = true;
|
|
1073
|
+
return this;
|
|
1074
|
+
}
|
|
1075
|
+
using(method) {
|
|
1076
|
+
this.config.using = method;
|
|
1077
|
+
return this;
|
|
1078
|
+
}
|
|
1079
|
+
asc() {
|
|
1080
|
+
this.config.order = 'asc';
|
|
1081
|
+
return this;
|
|
1082
|
+
}
|
|
1083
|
+
desc() {
|
|
1084
|
+
this.config.order = 'desc';
|
|
1085
|
+
return this;
|
|
1086
|
+
}
|
|
1087
|
+
nullsFirst() {
|
|
1088
|
+
this.config.nulls = 'first';
|
|
1089
|
+
return this;
|
|
1090
|
+
}
|
|
1091
|
+
nullsLast() {
|
|
1092
|
+
this.config.nulls = 'last';
|
|
1093
|
+
return this;
|
|
1094
|
+
}
|
|
1095
|
+
where(condition) {
|
|
1096
|
+
this.config.where = condition;
|
|
1097
|
+
return this;
|
|
1098
|
+
}
|
|
1099
|
+
/** @internal */
|
|
1100
|
+
build(table) {
|
|
1101
|
+
return new Index(this.config, table);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
class Index {
|
|
1105
|
+
constructor(config, table) {
|
|
1106
|
+
this.config = { ...config, table };
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
function index(name) {
|
|
1110
|
+
return new IndexBuilderOn(false, name);
|
|
1111
|
+
}
|
|
1112
|
+
function uniqueIndex(name) {
|
|
1113
|
+
return new IndexBuilderOn(true, name);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
function primaryKey(...columns) {
|
|
1117
|
+
return new PrimaryKeyBuilder(columns);
|
|
1118
|
+
}
|
|
1119
|
+
class PrimaryKeyBuilder {
|
|
1120
|
+
constructor(columns) {
|
|
1121
|
+
this.columns = columns;
|
|
1122
|
+
}
|
|
1123
|
+
/** @internal */
|
|
1124
|
+
build(table) {
|
|
1125
|
+
return new PrimaryKey(table, this.columns);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
class PrimaryKey {
|
|
1129
|
+
constructor(table, columns) {
|
|
1130
|
+
this.table = table;
|
|
1131
|
+
this.columns = columns;
|
|
1132
|
+
}
|
|
1133
|
+
getName() {
|
|
1134
|
+
return `${this.table[PgTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/** @internal */
|
|
1139
|
+
function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
1140
|
+
// Key -> nested object key, value -> table name if all fields in the nested object are from the same table, false otherwise
|
|
1141
|
+
const nullifyMap = {};
|
|
1142
|
+
const result = columns.reduce((result, { path, field }, columnIndex) => {
|
|
1143
|
+
let decoder;
|
|
1144
|
+
if (field instanceof Column) {
|
|
1145
|
+
decoder = field;
|
|
1146
|
+
}
|
|
1147
|
+
else if (field instanceof SQL) {
|
|
1148
|
+
decoder = field.decoder;
|
|
1149
|
+
}
|
|
1150
|
+
else {
|
|
1151
|
+
decoder = field.sql.decoder;
|
|
1152
|
+
}
|
|
1153
|
+
let node = result;
|
|
1154
|
+
for (const [pathChunkIndex, pathChunk] of path.entries()) {
|
|
1155
|
+
if (pathChunkIndex < path.length - 1) {
|
|
1156
|
+
if (!(pathChunk in node)) {
|
|
1157
|
+
node[pathChunk] = {};
|
|
1158
|
+
}
|
|
1159
|
+
node = node[pathChunk];
|
|
1160
|
+
}
|
|
1161
|
+
else {
|
|
1162
|
+
const rawValue = row[columnIndex];
|
|
1163
|
+
const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
|
|
1164
|
+
if (joinsNotNullableMap && field instanceof Column && path.length === 2) {
|
|
1165
|
+
const objectName = path[0];
|
|
1166
|
+
if (!(objectName in nullifyMap)) {
|
|
1167
|
+
nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
|
|
1168
|
+
}
|
|
1169
|
+
else if (typeof nullifyMap[objectName] === 'string' && nullifyMap[objectName] !== getTableName(field.table)) {
|
|
1170
|
+
nullifyMap[objectName] = false;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
return result;
|
|
1176
|
+
}, {});
|
|
1177
|
+
// Nullify all nested objects from nullifyMap that are nullable
|
|
1178
|
+
if (joinsNotNullableMap && Object.keys(nullifyMap).length > 0) {
|
|
1179
|
+
for (const [objectName, tableName] of Object.entries(nullifyMap)) {
|
|
1180
|
+
if (typeof tableName === 'string' && !joinsNotNullableMap[tableName]) {
|
|
1181
|
+
result[objectName] = null;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
return result;
|
|
1186
|
+
}
|
|
1187
|
+
/** @internal */
|
|
1188
|
+
function orderSelectedFields(fields, pathPrefix) {
|
|
1189
|
+
return Object.entries(fields).reduce((result, [name, field]) => {
|
|
1190
|
+
if (typeof name !== 'string') {
|
|
1191
|
+
return result;
|
|
1192
|
+
}
|
|
1193
|
+
const newPath = pathPrefix ? [...pathPrefix, name] : [name];
|
|
1194
|
+
if (field instanceof Column
|
|
1195
|
+
|| field instanceof SQL
|
|
1196
|
+
|| field instanceof SQL.Aliased) {
|
|
1197
|
+
result.push({ path: newPath, field });
|
|
1198
|
+
}
|
|
1199
|
+
else if (field instanceof Table) {
|
|
1200
|
+
result.push(...orderSelectedFields(field[Table.Symbol.Columns], newPath));
|
|
1201
|
+
}
|
|
1202
|
+
else {
|
|
1203
|
+
result.push(...orderSelectedFields(field, newPath));
|
|
1204
|
+
}
|
|
1205
|
+
return result;
|
|
1206
|
+
}, []);
|
|
1207
|
+
}
|
|
1208
|
+
/** @internal */
|
|
1209
|
+
function mapUpdateSet(table, values) {
|
|
1210
|
+
const entries = Object.entries(values)
|
|
1211
|
+
.filter(([, value]) => value !== undefined)
|
|
1212
|
+
.map(([key, value]) => {
|
|
1213
|
+
// eslint-disable-next-line unicorn/prefer-ternary
|
|
1214
|
+
if (value instanceof SQL) {
|
|
1215
|
+
return [key, value];
|
|
1216
|
+
}
|
|
1217
|
+
else {
|
|
1218
|
+
return [key, new Param(value, table[Table.Symbol.Columns][key])];
|
|
1219
|
+
}
|
|
1220
|
+
});
|
|
1221
|
+
if (entries.length === 0) {
|
|
1222
|
+
throw new Error('No values to set');
|
|
1223
|
+
}
|
|
1224
|
+
return Object.fromEntries(entries);
|
|
1225
|
+
}
|
|
1226
|
+
/** @internal */
|
|
1227
|
+
function applyMixins(baseClass, extendedClasses) {
|
|
1228
|
+
for (const extendedClass of extendedClasses) {
|
|
1229
|
+
for (const name of Object.getOwnPropertyNames(extendedClass.prototype)) {
|
|
1230
|
+
Object.defineProperty(baseClass.prototype, name, Object.getOwnPropertyDescriptor(extendedClass.prototype, name) || Object.create(null));
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
function getTableColumns(table) {
|
|
1235
|
+
return table[Table.Symbol.Columns];
|
|
1236
|
+
}
|
|
1237
|
+
/** @internal */
|
|
1238
|
+
function getTableLikeName(table) {
|
|
1239
|
+
return table instanceof Subquery
|
|
1240
|
+
? table[SubqueryConfig].alias
|
|
1241
|
+
: table instanceof View
|
|
1242
|
+
? table[ViewBaseConfig].name
|
|
1243
|
+
: table instanceof SQL
|
|
1244
|
+
? undefined
|
|
1245
|
+
: table[Table.Symbol.IsAlias]
|
|
1246
|
+
? table[Table.Symbol.Name]
|
|
1247
|
+
: table[Table.Symbol.BaseName];
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
class PgDialect {
|
|
1251
|
+
async migrate(migrations, session) {
|
|
1252
|
+
const migrationTableCreate = sql `
|
|
1253
|
+
CREATE TABLE IF NOT EXISTS "drizzle"."__drizzle_migrations" (
|
|
1254
|
+
id SERIAL PRIMARY KEY,
|
|
1255
|
+
hash text NOT NULL,
|
|
1256
|
+
created_at bigint
|
|
1257
|
+
)
|
|
1258
|
+
`;
|
|
1259
|
+
await session.execute(sql `CREATE SCHEMA IF NOT EXISTS "drizzle"`);
|
|
1260
|
+
await session.execute(migrationTableCreate);
|
|
1261
|
+
const dbMigrations = await session.all(sql `select id, hash, created_at from "drizzle"."__drizzle_migrations" order by created_at desc limit 1`);
|
|
1262
|
+
const lastDbMigration = dbMigrations[0];
|
|
1263
|
+
await session.transaction(async (tx) => {
|
|
1264
|
+
for await (const migration of migrations) {
|
|
1265
|
+
if (!lastDbMigration
|
|
1266
|
+
|| Number(lastDbMigration.created_at) < migration.folderMillis) {
|
|
1267
|
+
for (const stmt of migration.sql) {
|
|
1268
|
+
await tx.execute(sql.raw(stmt));
|
|
1269
|
+
}
|
|
1270
|
+
await tx.execute(sql `insert into "drizzle"."__drizzle_migrations" ("hash", "created_at") values(${migration.hash}, ${migration.folderMillis})`);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
escapeName(name) {
|
|
1276
|
+
return `"${name}"`;
|
|
1277
|
+
}
|
|
1278
|
+
escapeParam(num) {
|
|
1279
|
+
return `$${num + 1}`;
|
|
1280
|
+
}
|
|
1281
|
+
escapeString(str) {
|
|
1282
|
+
return `'${str.replace(/'/g, "''")}'`;
|
|
1283
|
+
}
|
|
1284
|
+
buildDeleteQuery({ table, where, returning }) {
|
|
1285
|
+
const returningSql = returning
|
|
1286
|
+
? sql ` returning ${this.buildSelection(returning, { isSingleTable: true })}`
|
|
1287
|
+
: undefined;
|
|
1288
|
+
const whereSql = where ? sql ` where ${where}` : undefined;
|
|
1289
|
+
return sql `delete from ${table}${whereSql}${returningSql}`;
|
|
1290
|
+
}
|
|
1291
|
+
buildUpdateSet(table, set) {
|
|
1292
|
+
const setEntries = Object.entries(set);
|
|
1293
|
+
const setSize = setEntries.length;
|
|
1294
|
+
return sql.fromList(setEntries
|
|
1295
|
+
.flatMap(([colName, value], i) => {
|
|
1296
|
+
const col = table[Table.Symbol.Columns][colName];
|
|
1297
|
+
const res = sql `${name(col.name)} = ${value}`;
|
|
1298
|
+
if (i < setSize - 1) {
|
|
1299
|
+
return [res, sql.raw(', ')];
|
|
1300
|
+
}
|
|
1301
|
+
return [res];
|
|
1302
|
+
}));
|
|
1303
|
+
}
|
|
1304
|
+
buildUpdateQuery({ table, set, where, returning }) {
|
|
1305
|
+
const setSql = this.buildUpdateSet(table, set);
|
|
1306
|
+
const returningSql = returning
|
|
1307
|
+
? sql ` returning ${this.buildSelection(returning, { isSingleTable: true })}`
|
|
1308
|
+
: undefined;
|
|
1309
|
+
const whereSql = where ? sql ` where ${where}` : undefined;
|
|
1310
|
+
return sql `update ${table} set ${setSql}${whereSql}${returningSql}`;
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* Builds selection SQL with provided fields/expressions
|
|
1314
|
+
*
|
|
1315
|
+
* Examples:
|
|
1316
|
+
*
|
|
1317
|
+
* `select <selection> from`
|
|
1318
|
+
*
|
|
1319
|
+
* `insert ... returning <selection>`
|
|
1320
|
+
*
|
|
1321
|
+
* If `isSingleTable` is true, then columns won't be prefixed with table name
|
|
1322
|
+
*/
|
|
1323
|
+
buildSelection(fields, { isSingleTable = false } = {}) {
|
|
1324
|
+
const columnsLen = fields.length;
|
|
1325
|
+
const chunks = fields
|
|
1326
|
+
.flatMap(({ field }, i) => {
|
|
1327
|
+
const chunk = [];
|
|
1328
|
+
if (field instanceof SQL.Aliased && field.isSelectionField) {
|
|
1329
|
+
chunk.push(name(field.fieldAlias));
|
|
1330
|
+
}
|
|
1331
|
+
else if (field instanceof SQL.Aliased || field instanceof SQL) {
|
|
1332
|
+
const query = field instanceof SQL.Aliased ? field.sql : field;
|
|
1333
|
+
if (isSingleTable) {
|
|
1334
|
+
chunk.push(new SQL(query.queryChunks.map((c) => {
|
|
1335
|
+
if (c instanceof PgColumn) {
|
|
1336
|
+
return name(c.name);
|
|
1337
|
+
}
|
|
1338
|
+
return c;
|
|
1339
|
+
})));
|
|
1340
|
+
}
|
|
1341
|
+
else {
|
|
1342
|
+
chunk.push(query);
|
|
1343
|
+
}
|
|
1344
|
+
if (field instanceof SQL.Aliased) {
|
|
1345
|
+
chunk.push(sql ` as ${name(field.fieldAlias)}`);
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
else if (field instanceof Column) {
|
|
1349
|
+
if (isSingleTable) {
|
|
1350
|
+
chunk.push(name(field.name));
|
|
1351
|
+
}
|
|
1352
|
+
else {
|
|
1353
|
+
chunk.push(field);
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
if (i < columnsLen - 1) {
|
|
1357
|
+
chunk.push(sql `, `);
|
|
1358
|
+
}
|
|
1359
|
+
return chunk;
|
|
1360
|
+
});
|
|
1361
|
+
return sql.fromList(chunks);
|
|
1362
|
+
}
|
|
1363
|
+
buildSelectQuery({ withList, fields, fieldsFlat, where, having, table, joins, orderBy, groupBy, limit, offset, lockingClauses }) {
|
|
1364
|
+
const fieldsList = fieldsFlat ?? orderSelectedFields(fields);
|
|
1365
|
+
for (const f of fieldsList) {
|
|
1366
|
+
if (f.field instanceof Column
|
|
1367
|
+
&& getTableName(f.field.table)
|
|
1368
|
+
!== (table instanceof Subquery
|
|
1369
|
+
? table[SubqueryConfig].alias
|
|
1370
|
+
: table instanceof PgViewBase
|
|
1371
|
+
? table[ViewBaseConfig].name
|
|
1372
|
+
: table instanceof SQL
|
|
1373
|
+
? undefined
|
|
1374
|
+
: getTableName(table))
|
|
1375
|
+
&& !((table) => joins.some(({ alias }) => alias === getTableName(table)))(f.field.table)) {
|
|
1376
|
+
const tableName = getTableName(f.field.table);
|
|
1377
|
+
throw new Error(`Your "${f.path.join('->')}" field references a column "${tableName}"."${f.field.name}", but the table "${tableName}" is not part of the query! Did you forget to join it?`);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
const isSingleTable = joins.length === 0;
|
|
1381
|
+
let withSql;
|
|
1382
|
+
if (withList.length) {
|
|
1383
|
+
const withSqlChunks = [sql `with `];
|
|
1384
|
+
for (const [i, w] of withList.entries()) {
|
|
1385
|
+
withSqlChunks.push(sql `${name(w[SubqueryConfig].alias)} as (${w[SubqueryConfig].sql})`);
|
|
1386
|
+
if (i < withList.length - 1) {
|
|
1387
|
+
withSqlChunks.push(sql `, `);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
withSqlChunks.push(sql ` `);
|
|
1391
|
+
withSql = sql.fromList(withSqlChunks);
|
|
1392
|
+
}
|
|
1393
|
+
const selection = this.buildSelection(fieldsList, { isSingleTable });
|
|
1394
|
+
const tableSql = (() => {
|
|
1395
|
+
if (table instanceof Table && table[Table.Symbol.OriginalName] !== table[Table.Symbol.Name]) {
|
|
1396
|
+
let fullName = sql `${sql.identifier(table[Table.Symbol.OriginalName])}`;
|
|
1397
|
+
if (table[Table.Symbol.Schema]) {
|
|
1398
|
+
fullName = sql `${sql.identifier(table[Table.Symbol.Schema])}.${fullName}`;
|
|
1399
|
+
}
|
|
1400
|
+
return sql `${fullName} ${sql.identifier(table[Table.Symbol.Name])}`;
|
|
1401
|
+
}
|
|
1402
|
+
return table;
|
|
1403
|
+
})();
|
|
1404
|
+
const joinsArray = [];
|
|
1405
|
+
for (const [index, joinMeta] of joins.entries()) {
|
|
1406
|
+
if (index === 0) {
|
|
1407
|
+
joinsArray.push(sql ` `);
|
|
1408
|
+
}
|
|
1409
|
+
const table = joinMeta.table;
|
|
1410
|
+
if (table instanceof PgTable) {
|
|
1411
|
+
const tableName = table[PgTable.Symbol.Name];
|
|
1412
|
+
const tableSchema = table[PgTable.Symbol.Schema];
|
|
1413
|
+
const origTableName = table[PgTable.Symbol.OriginalName];
|
|
1414
|
+
const alias = tableName === origTableName ? undefined : joinMeta.alias;
|
|
1415
|
+
joinsArray.push(sql `${sql.raw(joinMeta.joinType)} join ${tableSchema ? sql `${name(tableSchema)}.` : undefined}${name(origTableName)}${alias && sql ` ${name(alias)}`} on ${joinMeta.on}`);
|
|
1416
|
+
}
|
|
1417
|
+
else {
|
|
1418
|
+
joinsArray.push(sql `${sql.raw(joinMeta.joinType)} join ${table} on ${joinMeta.on}`);
|
|
1419
|
+
}
|
|
1420
|
+
if (index < joins.length - 1) {
|
|
1421
|
+
joinsArray.push(sql ` `);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
const joinsSql = sql.fromList(joinsArray);
|
|
1425
|
+
const whereSql = where ? sql ` where ${where}` : undefined;
|
|
1426
|
+
const havingSql = having ? sql ` having ${having}` : undefined;
|
|
1427
|
+
const orderByList = [];
|
|
1428
|
+
for (const [index, orderByValue] of orderBy.entries()) {
|
|
1429
|
+
orderByList.push(orderByValue);
|
|
1430
|
+
if (index < orderBy.length - 1) {
|
|
1431
|
+
orderByList.push(sql `, `);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
const orderBySql = orderByList.length > 0 ? sql ` order by ${sql.fromList(orderByList)}` : undefined;
|
|
1435
|
+
const groupByList = [];
|
|
1436
|
+
for (const [index, groupByValue] of groupBy.entries()) {
|
|
1437
|
+
groupByList.push(groupByValue);
|
|
1438
|
+
if (index < groupBy.length - 1) {
|
|
1439
|
+
groupByList.push(sql `, `);
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
const groupBySql = groupByList.length > 0 ? sql ` group by ${sql.fromList(groupByList)}` : undefined;
|
|
1443
|
+
const limitSql = limit ? sql ` limit ${limit}` : undefined;
|
|
1444
|
+
const offsetSql = offset ? sql ` offset ${offset}` : undefined;
|
|
1445
|
+
const lockingClausesSql = sql.empty();
|
|
1446
|
+
for (const { strength, config } of lockingClauses) {
|
|
1447
|
+
const clauseSql = sql ` for ${sql.raw(strength)}`;
|
|
1448
|
+
if (config.of) {
|
|
1449
|
+
clauseSql.append(sql ` of ${config.of}`);
|
|
1450
|
+
}
|
|
1451
|
+
if (config.noWait) {
|
|
1452
|
+
clauseSql.append(sql ` no wait`);
|
|
1453
|
+
}
|
|
1454
|
+
else if (config.skipLocked) {
|
|
1455
|
+
clauseSql.append(sql ` skip locked`);
|
|
1456
|
+
}
|
|
1457
|
+
lockingClausesSql.append(clauseSql);
|
|
1458
|
+
}
|
|
1459
|
+
return sql `${withSql}select ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`;
|
|
1460
|
+
}
|
|
1461
|
+
buildInsertQuery({ table, values, onConflict, returning }) {
|
|
1462
|
+
const isSingleValue = values.length === 1;
|
|
1463
|
+
const valuesSqlList = [];
|
|
1464
|
+
const columns = table[Table.Symbol.Columns];
|
|
1465
|
+
const colEntries = isSingleValue
|
|
1466
|
+
? Object.keys(values[0]).map((fieldName) => [fieldName, columns[fieldName]])
|
|
1467
|
+
: Object.entries(columns);
|
|
1468
|
+
const insertOrder = colEntries.map(([, column]) => name(column.name));
|
|
1469
|
+
for (const [valueIndex, value] of values.entries()) {
|
|
1470
|
+
const valueList = [];
|
|
1471
|
+
for (const [fieldName] of colEntries) {
|
|
1472
|
+
const colValue = value[fieldName];
|
|
1473
|
+
if (colValue === undefined || (colValue instanceof Param && colValue.value === undefined)) {
|
|
1474
|
+
valueList.push(sql `default`);
|
|
1475
|
+
}
|
|
1476
|
+
else {
|
|
1477
|
+
valueList.push(colValue);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
valuesSqlList.push(valueList);
|
|
1481
|
+
if (valueIndex < values.length - 1) {
|
|
1482
|
+
valuesSqlList.push(sql `, `);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
const valuesSql = sql.fromList(valuesSqlList);
|
|
1486
|
+
const returningSql = returning
|
|
1487
|
+
? sql ` returning ${this.buildSelection(returning, { isSingleTable: true })}`
|
|
1488
|
+
: undefined;
|
|
1489
|
+
const onConflictSql = onConflict ? sql ` on conflict ${onConflict}` : undefined;
|
|
1490
|
+
return sql `insert into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}${returningSql}`;
|
|
1491
|
+
}
|
|
1492
|
+
buildRefreshMaterializedViewQuery({ view, concurrently, withNoData }) {
|
|
1493
|
+
const concurrentlySql = concurrently ? sql ` concurrently` : undefined;
|
|
1494
|
+
const withNoDataSql = withNoData ? sql ` with no data` : undefined;
|
|
1495
|
+
return sql `refresh materialized view${concurrentlySql} ${view}${withNoDataSql}`;
|
|
1496
|
+
}
|
|
1497
|
+
prepareTyping(encoder) {
|
|
1498
|
+
if (encoder instanceof PgJsonb || encoder instanceof PgJson) {
|
|
1499
|
+
return 'json';
|
|
1500
|
+
}
|
|
1501
|
+
else if (encoder instanceof PgNumeric) {
|
|
1502
|
+
return 'decimal';
|
|
1503
|
+
}
|
|
1504
|
+
else if (encoder instanceof PgTime) {
|
|
1505
|
+
return 'time';
|
|
1506
|
+
}
|
|
1507
|
+
else if (encoder instanceof PgTimestamp) {
|
|
1508
|
+
return 'timestamp';
|
|
1509
|
+
}
|
|
1510
|
+
else if (encoder instanceof PgDate) {
|
|
1511
|
+
return 'date';
|
|
1512
|
+
}
|
|
1513
|
+
else if (encoder instanceof PgUUID) {
|
|
1514
|
+
return 'uuid';
|
|
1515
|
+
}
|
|
1516
|
+
else {
|
|
1517
|
+
return 'none';
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
sqlToQuery(sql) {
|
|
1521
|
+
return sql.toQuery({
|
|
1522
|
+
escapeName: this.escapeName,
|
|
1523
|
+
escapeParam: this.escapeParam,
|
|
1524
|
+
escapeString: this.escapeString,
|
|
1525
|
+
prepareTyping: this.prepareTyping,
|
|
1526
|
+
});
|
|
1527
|
+
}
|
|
1528
|
+
buildRelationalQuery(fullSchema, schema, tableNamesMap, table, tableConfig, config, tableAlias, relationColumns, isRoot = false) {
|
|
1529
|
+
if (config === true) {
|
|
1530
|
+
const selectionEntries = Object.entries(tableConfig.columns);
|
|
1531
|
+
const selection = selectionEntries.map(([key, value]) => ({
|
|
1532
|
+
dbKey: value.name,
|
|
1533
|
+
tsKey: key,
|
|
1534
|
+
field: value,
|
|
1535
|
+
tableTsKey: undefined,
|
|
1536
|
+
isJson: false,
|
|
1537
|
+
selection: [],
|
|
1538
|
+
}));
|
|
1539
|
+
return {
|
|
1540
|
+
tableTsKey: tableConfig.tsName,
|
|
1541
|
+
sql: this.buildSelectQuery({
|
|
1542
|
+
table,
|
|
1543
|
+
fields: {},
|
|
1544
|
+
fieldsFlat: selectionEntries.map(([, c]) => ({
|
|
1545
|
+
path: [c.name],
|
|
1546
|
+
field: c,
|
|
1547
|
+
})),
|
|
1548
|
+
groupBy: [],
|
|
1549
|
+
orderBy: [],
|
|
1550
|
+
joins: [],
|
|
1551
|
+
lockingClauses: [],
|
|
1552
|
+
withList: [],
|
|
1553
|
+
}),
|
|
1554
|
+
selection,
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
const aliasedColumns = Object.fromEntries(Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value, tableAlias)]));
|
|
1558
|
+
const aliasedRelations = Object.fromEntries(Object.entries(tableConfig.relations).map(([key, value]) => [key, aliasedRelation(value, tableAlias)]));
|
|
1559
|
+
const aliasedFields = Object.assign({}, aliasedColumns, aliasedRelations);
|
|
1560
|
+
const fieldsSelection = {};
|
|
1561
|
+
let selectedColumns = [];
|
|
1562
|
+
let selectedExtras = [];
|
|
1563
|
+
let selectedRelations = [];
|
|
1564
|
+
if (config.columns) {
|
|
1565
|
+
let isIncludeMode = false;
|
|
1566
|
+
for (const [field, value] of Object.entries(config.columns)) {
|
|
1567
|
+
if (value === undefined) {
|
|
1568
|
+
continue;
|
|
1569
|
+
}
|
|
1570
|
+
if (field in tableConfig.columns) {
|
|
1571
|
+
if (!isIncludeMode && value === true) {
|
|
1572
|
+
isIncludeMode = true;
|
|
1573
|
+
}
|
|
1574
|
+
selectedColumns.push(field);
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
if (selectedColumns.length > 0) {
|
|
1578
|
+
selectedColumns = isIncludeMode
|
|
1579
|
+
? selectedColumns.filter((c) => config.columns?.[c] === true)
|
|
1580
|
+
: Object.keys(tableConfig.columns).filter((key) => !selectedColumns.includes(key));
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
if (config.with) {
|
|
1584
|
+
selectedRelations = Object.entries(config.with)
|
|
1585
|
+
.filter((entry) => !!entry[1])
|
|
1586
|
+
.map(([key, value]) => ({ key, value }));
|
|
1587
|
+
}
|
|
1588
|
+
if (!config.columns) {
|
|
1589
|
+
selectedColumns = Object.keys(tableConfig.columns);
|
|
1590
|
+
}
|
|
1591
|
+
if (config.extras) {
|
|
1592
|
+
const extrasOrig = typeof config.extras === 'function'
|
|
1593
|
+
? config.extras(aliasedFields, { sql })
|
|
1594
|
+
: config.extras;
|
|
1595
|
+
selectedExtras = Object.entries(extrasOrig).map(([key, value]) => ({
|
|
1596
|
+
key,
|
|
1597
|
+
value: mapColumnsInAliasedSQLToAlias(value, tableAlias),
|
|
1598
|
+
}));
|
|
1599
|
+
}
|
|
1600
|
+
for (const field of selectedColumns) {
|
|
1601
|
+
const column = tableConfig.columns[field];
|
|
1602
|
+
fieldsSelection[field] = column;
|
|
1603
|
+
}
|
|
1604
|
+
for (const { key, value } of selectedExtras) {
|
|
1605
|
+
fieldsSelection[key] = value;
|
|
1606
|
+
}
|
|
1607
|
+
const builtRelations = [];
|
|
1608
|
+
const joins = [];
|
|
1609
|
+
const builtRelationFields = [];
|
|
1610
|
+
for (const { key: selectedRelationKey, value: selectedRelationValue } of selectedRelations) {
|
|
1611
|
+
let relation;
|
|
1612
|
+
for (const [relationKey, relationValue] of Object.entries(tableConfig.relations)) {
|
|
1613
|
+
if (relationValue instanceof Relation && relationKey === selectedRelationKey) {
|
|
1614
|
+
relation = relationValue;
|
|
1615
|
+
break;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
if (!relation) {
|
|
1619
|
+
throw new Error(`Relation ${selectedRelationKey} not found`);
|
|
1620
|
+
}
|
|
1621
|
+
const normalizedRelation = normalizeRelation(schema, tableNamesMap, relation);
|
|
1622
|
+
const relationAlias = `${tableAlias}_${selectedRelationKey}`;
|
|
1623
|
+
const relationConfig = schema[tableNamesMap[relation.referencedTable[Table.Symbol.Name]]];
|
|
1624
|
+
const builtRelation = this.buildRelationalQuery(fullSchema, schema, tableNamesMap, fullSchema[tableNamesMap[relation.referencedTable[Table.Symbol.Name]]], schema[tableNamesMap[relation.referencedTable[Table.Symbol.Name]]], selectedRelationValue, relationAlias, normalizedRelation.references);
|
|
1625
|
+
builtRelations.push({ key: selectedRelationKey, value: builtRelation });
|
|
1626
|
+
joins.push({
|
|
1627
|
+
table: new Subquery(builtRelation.sql, {}, relationAlias),
|
|
1628
|
+
alias: selectedRelationKey,
|
|
1629
|
+
on: and(...normalizedRelation.fields.map((field, i) => eq(aliasedTableColumn(field, tableAlias), aliasedTableColumn(normalizedRelation.references[i], relationAlias)))),
|
|
1630
|
+
joinType: 'left',
|
|
1631
|
+
});
|
|
1632
|
+
const relationAliasedColumns = Object.fromEntries(Object.entries(relationConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value, tableAlias)]));
|
|
1633
|
+
const relationAliasedRelations = Object.fromEntries(Object.entries(relationConfig.relations).map(([key, value]) => [key, aliasedRelation(value, tableAlias)]));
|
|
1634
|
+
const relationAliasedFields = Object.assign({}, relationAliasedColumns, relationAliasedRelations);
|
|
1635
|
+
let orderBy;
|
|
1636
|
+
if (typeof selectedRelationValue === 'object') {
|
|
1637
|
+
let orderByOrig = typeof selectedRelationValue.orderBy === 'function'
|
|
1638
|
+
? selectedRelationValue.orderBy(relationAliasedFields, orderByOperators)
|
|
1639
|
+
: selectedRelationValue.orderBy ?? [];
|
|
1640
|
+
if (!Array.isArray(orderByOrig)) {
|
|
1641
|
+
orderByOrig = [orderByOrig];
|
|
1642
|
+
}
|
|
1643
|
+
orderBy = orderByOrig.map((orderByValue) => {
|
|
1644
|
+
if (orderByValue instanceof Column) {
|
|
1645
|
+
return aliasedTableColumn(orderByValue, relationAlias);
|
|
1646
|
+
}
|
|
1647
|
+
return mapColumnsInSQLToAlias(orderByValue, relationAlias);
|
|
1648
|
+
});
|
|
1649
|
+
}
|
|
1650
|
+
const orderBySql = orderBy?.length ? sql ` order by ${sql.join(orderBy, sql `, `)}` : undefined;
|
|
1651
|
+
const elseField = sql `json_agg(json_build_array(${sql.join(builtRelation.selection.map(({ dbKey: key }) => {
|
|
1652
|
+
const field = sql `${sql.identifier(relationAlias)}.${sql.identifier(key)}`;
|
|
1653
|
+
return field;
|
|
1654
|
+
}), sql `, `)})${orderBySql})`;
|
|
1655
|
+
const field = sql `case when count(${sql.join(normalizedRelation.references.map((c) => aliasedTableColumn(c, relationAlias)), sql.raw(' or '))}) = 0 then '[]' else ${elseField} end`.as(selectedRelationKey);
|
|
1656
|
+
builtRelationFields.push({
|
|
1657
|
+
path: [selectedRelationKey],
|
|
1658
|
+
field,
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1661
|
+
const finalFieldsSelection = Object.entries(fieldsSelection).map(([key, value]) => {
|
|
1662
|
+
return {
|
|
1663
|
+
path: [key],
|
|
1664
|
+
field: value instanceof Column ? aliasedTableColumn(value, tableAlias) : value,
|
|
1665
|
+
};
|
|
1666
|
+
});
|
|
1667
|
+
const initialWhere = and(...selectedRelations.filter(({ key }) => {
|
|
1668
|
+
const relation = config.with?.[key];
|
|
1669
|
+
return typeof relation === 'object' && relation.limit !== undefined;
|
|
1670
|
+
}).map(({ key }) => {
|
|
1671
|
+
const field = sql `${sql.identifier(`${tableAlias}_${key}`)}.${sql.identifier('__drizzle_row_number')}`;
|
|
1672
|
+
const value = config.with?.[key];
|
|
1673
|
+
const cond = or(and(sql `${field} <= ${value.limit}`), sql `(${field} is null)`);
|
|
1674
|
+
return cond;
|
|
1675
|
+
}));
|
|
1676
|
+
const groupBy = (builtRelationFields.length
|
|
1677
|
+
? (tableConfig.primaryKey.length ? tableConfig.primaryKey : Object.values(tableConfig.columns)).map((c) => aliasedTableColumn(c, tableAlias))
|
|
1678
|
+
: []);
|
|
1679
|
+
let orderByOrig = typeof config.orderBy === 'function'
|
|
1680
|
+
? config.orderBy(aliasedFields, orderByOperators)
|
|
1681
|
+
: config.orderBy ?? [];
|
|
1682
|
+
if (!Array.isArray(orderByOrig)) {
|
|
1683
|
+
orderByOrig = [orderByOrig];
|
|
1684
|
+
}
|
|
1685
|
+
const orderBy = orderByOrig.map((orderByValue) => {
|
|
1686
|
+
if (orderByValue instanceof Column) {
|
|
1687
|
+
return aliasedTableColumn(orderByValue, tableAlias);
|
|
1688
|
+
}
|
|
1689
|
+
return mapColumnsInSQLToAlias(orderByValue, tableAlias);
|
|
1690
|
+
});
|
|
1691
|
+
const finalFieldsFlat = isRoot
|
|
1692
|
+
? [
|
|
1693
|
+
...finalFieldsSelection.map(({ path, field }) => ({
|
|
1694
|
+
path,
|
|
1695
|
+
field: field instanceof SQL.Aliased ? sql `${sql.identifier(field.fieldAlias)}` : field,
|
|
1696
|
+
})),
|
|
1697
|
+
...builtRelationFields.map(({ path, field }) => ({
|
|
1698
|
+
path,
|
|
1699
|
+
field: sql `${sql.identifier(field.fieldAlias)}`,
|
|
1700
|
+
})),
|
|
1701
|
+
]
|
|
1702
|
+
: [{
|
|
1703
|
+
path: [],
|
|
1704
|
+
field: sql `${sql.identifier(tableAlias)}.*`,
|
|
1705
|
+
}];
|
|
1706
|
+
const initialFieldsFlat = [
|
|
1707
|
+
{
|
|
1708
|
+
path: [],
|
|
1709
|
+
field: sql `${sql.identifier(tableAlias)}.*`,
|
|
1710
|
+
},
|
|
1711
|
+
...selectedExtras.map(({ key, value }) => ({
|
|
1712
|
+
path: [key],
|
|
1713
|
+
field: value,
|
|
1714
|
+
})),
|
|
1715
|
+
...builtRelationFields,
|
|
1716
|
+
];
|
|
1717
|
+
let limit, offset;
|
|
1718
|
+
if (config.limit !== undefined || config.offset !== undefined) {
|
|
1719
|
+
if (isRoot) {
|
|
1720
|
+
limit = config.limit;
|
|
1721
|
+
offset = config.offset;
|
|
1722
|
+
}
|
|
1723
|
+
else {
|
|
1724
|
+
finalFieldsFlat.push({
|
|
1725
|
+
path: ['__drizzle_row_number'],
|
|
1726
|
+
field: sql `row_number() over(partition by ${relationColumns.map((c) => aliasedTableColumn(c, tableAlias))}${orderBy.length ? sql ` order by ${sql.join(orderBy, sql `, `)}` : undefined})`
|
|
1727
|
+
.as('__drizzle_row_number'),
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
let result = this.buildSelectQuery({
|
|
1732
|
+
table: aliasedTable(table, tableAlias),
|
|
1733
|
+
fields: {},
|
|
1734
|
+
fieldsFlat: initialFieldsFlat,
|
|
1735
|
+
where: initialWhere,
|
|
1736
|
+
groupBy,
|
|
1737
|
+
orderBy: [],
|
|
1738
|
+
joins,
|
|
1739
|
+
lockingClauses: [],
|
|
1740
|
+
withList: [],
|
|
1741
|
+
});
|
|
1742
|
+
let where;
|
|
1743
|
+
if (config.where) {
|
|
1744
|
+
const whereSql = typeof config.where === 'function' ? config.where(aliasedFields, operators) : config.where;
|
|
1745
|
+
where = whereSql && mapColumnsInSQLToAlias(whereSql, tableAlias);
|
|
1746
|
+
}
|
|
1747
|
+
result = this.buildSelectQuery({
|
|
1748
|
+
table: new Subquery(result, {}, tableAlias),
|
|
1749
|
+
fields: {},
|
|
1750
|
+
fieldsFlat: finalFieldsFlat,
|
|
1751
|
+
where,
|
|
1752
|
+
groupBy: [],
|
|
1753
|
+
orderBy: orderBy ?? [],
|
|
1754
|
+
joins: [],
|
|
1755
|
+
lockingClauses: [],
|
|
1756
|
+
withList: [],
|
|
1757
|
+
limit,
|
|
1758
|
+
offset: offset,
|
|
1759
|
+
});
|
|
1760
|
+
return {
|
|
1761
|
+
tableTsKey: tableConfig.tsName,
|
|
1762
|
+
sql: result,
|
|
1763
|
+
selection: [
|
|
1764
|
+
...finalFieldsSelection.map(({ path, field }) => ({
|
|
1765
|
+
dbKey: field instanceof SQL.Aliased ? field.fieldAlias : tableConfig.columns[path[0]].name,
|
|
1766
|
+
tsKey: path[0],
|
|
1767
|
+
field,
|
|
1768
|
+
tableTsKey: undefined,
|
|
1769
|
+
isJson: false,
|
|
1770
|
+
selection: [],
|
|
1771
|
+
})),
|
|
1772
|
+
...builtRelations.map(({ key, value }) => ({
|
|
1773
|
+
dbKey: key,
|
|
1774
|
+
tsKey: key,
|
|
1775
|
+
field: undefined,
|
|
1776
|
+
tableTsKey: value.tableTsKey,
|
|
1777
|
+
isJson: true,
|
|
1778
|
+
selection: value.selection,
|
|
1779
|
+
})),
|
|
1780
|
+
],
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
class TypedQueryBuilder {
|
|
1786
|
+
/** @internal */
|
|
1787
|
+
getSelectedFields() {
|
|
1788
|
+
return this._.selectedFields;
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
class PgSelectBuilder {
|
|
1793
|
+
constructor(fields, session, dialect, withList = []) {
|
|
1794
|
+
this.fields = fields;
|
|
1795
|
+
this.session = session;
|
|
1796
|
+
this.dialect = dialect;
|
|
1797
|
+
this.withList = withList;
|
|
1798
|
+
}
|
|
1799
|
+
/**
|
|
1800
|
+
* Specify the table, subquery, or other target that you’re
|
|
1801
|
+
* building a select query against.
|
|
1802
|
+
*
|
|
1803
|
+
* {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM|Postgres from documentation}
|
|
1804
|
+
*/
|
|
1805
|
+
from(source) {
|
|
1806
|
+
const isPartialSelect = !!this.fields;
|
|
1807
|
+
let fields;
|
|
1808
|
+
if (this.fields) {
|
|
1809
|
+
fields = this.fields;
|
|
1810
|
+
}
|
|
1811
|
+
else if (source instanceof Subquery) {
|
|
1812
|
+
// This is required to use the proxy handler to get the correct field values from the subquery
|
|
1813
|
+
fields = Object.fromEntries(Object.keys(source[SubqueryConfig].selection).map((key) => [key, source[key]]));
|
|
1814
|
+
}
|
|
1815
|
+
else if (source instanceof PgViewBase) {
|
|
1816
|
+
fields = source[ViewBaseConfig].selectedFields;
|
|
1817
|
+
}
|
|
1818
|
+
else if (source instanceof SQL) {
|
|
1819
|
+
fields = {};
|
|
1820
|
+
}
|
|
1821
|
+
else {
|
|
1822
|
+
fields = getTableColumns(source);
|
|
1823
|
+
}
|
|
1824
|
+
return new PgSelect(source, fields, isPartialSelect, this.session, this.dialect, this.withList);
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
class PgSelectQueryBuilder extends TypedQueryBuilder {
|
|
1828
|
+
constructor(table, fields, isPartialSelect, session, dialect, withList) {
|
|
1829
|
+
super();
|
|
1830
|
+
this.isPartialSelect = isPartialSelect;
|
|
1831
|
+
this.session = session;
|
|
1832
|
+
this.dialect = dialect;
|
|
1833
|
+
/**
|
|
1834
|
+
* For each row of the table, include
|
|
1835
|
+
* values from a matching row of the joined
|
|
1836
|
+
* table, if there is a matching row. If not,
|
|
1837
|
+
* all of the columns of the joined table
|
|
1838
|
+
* will be set to null.
|
|
1839
|
+
*/
|
|
1840
|
+
this.leftJoin = this.createJoin('left');
|
|
1841
|
+
/**
|
|
1842
|
+
* Includes all of the rows of the joined table.
|
|
1843
|
+
* If there is no matching row in the main table,
|
|
1844
|
+
* all the columns of the main table will be
|
|
1845
|
+
* set to null.
|
|
1846
|
+
*/
|
|
1847
|
+
this.rightJoin = this.createJoin('right');
|
|
1848
|
+
/**
|
|
1849
|
+
* This is the default type of join.
|
|
1850
|
+
*
|
|
1851
|
+
* For each row of the table, the joined table
|
|
1852
|
+
* needs to have a matching row, or it will
|
|
1853
|
+
* be excluded from results.
|
|
1854
|
+
*/
|
|
1855
|
+
this.innerJoin = this.createJoin('inner');
|
|
1856
|
+
/**
|
|
1857
|
+
* Rows from both the main & joined are included,
|
|
1858
|
+
* regardless of whether or not they have matching
|
|
1859
|
+
* rows in the other table.
|
|
1860
|
+
*/
|
|
1861
|
+
this.fullJoin = this.createJoin('full');
|
|
1862
|
+
this.config = {
|
|
1863
|
+
withList,
|
|
1864
|
+
table,
|
|
1865
|
+
fields: { ...fields },
|
|
1866
|
+
joins: [],
|
|
1867
|
+
orderBy: [],
|
|
1868
|
+
groupBy: [],
|
|
1869
|
+
lockingClauses: [],
|
|
1870
|
+
};
|
|
1871
|
+
this._ = {
|
|
1872
|
+
selectedFields: fields,
|
|
1873
|
+
};
|
|
1874
|
+
this.tableName = getTableLikeName(table);
|
|
1875
|
+
this.joinsNotNullableMap = typeof this.tableName === 'string' ? { [this.tableName]: true } : {};
|
|
1876
|
+
}
|
|
1877
|
+
createJoin(joinType) {
|
|
1878
|
+
return (table, on) => {
|
|
1879
|
+
const baseTableName = this.tableName;
|
|
1880
|
+
const tableName = getTableLikeName(table);
|
|
1881
|
+
if (typeof tableName === 'string' && this.config.joins.some((join) => join.alias === tableName)) {
|
|
1882
|
+
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
1883
|
+
}
|
|
1884
|
+
if (!this.isPartialSelect) {
|
|
1885
|
+
// If this is the first join and this is not a partial select and we're not selecting from raw SQL, "move" the fields from the main table to the nested object
|
|
1886
|
+
if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === 'string') {
|
|
1887
|
+
this.config.fields = {
|
|
1888
|
+
[baseTableName]: this.config.fields,
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
if (typeof tableName === 'string' && !(table instanceof SQL)) {
|
|
1892
|
+
const selection = table instanceof Subquery
|
|
1893
|
+
? table[SubqueryConfig].selection
|
|
1894
|
+
: table instanceof View
|
|
1895
|
+
? table[ViewBaseConfig].selectedFields
|
|
1896
|
+
: table[Table.Symbol.Columns];
|
|
1897
|
+
this.config.fields[tableName] = selection;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
if (typeof on === 'function') {
|
|
1901
|
+
on = on(new Proxy(this.config.fields, new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' })));
|
|
1902
|
+
}
|
|
1903
|
+
this.config.joins.push({ on, table, joinType, alias: tableName });
|
|
1904
|
+
if (typeof tableName === 'string') {
|
|
1905
|
+
switch (joinType) {
|
|
1906
|
+
case 'left': {
|
|
1907
|
+
this.joinsNotNullableMap[tableName] = false;
|
|
1908
|
+
break;
|
|
1909
|
+
}
|
|
1910
|
+
case 'right': {
|
|
1911
|
+
this.joinsNotNullableMap = Object.fromEntries(Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]));
|
|
1912
|
+
this.joinsNotNullableMap[tableName] = true;
|
|
1913
|
+
break;
|
|
1914
|
+
}
|
|
1915
|
+
case 'inner': {
|
|
1916
|
+
this.joinsNotNullableMap[tableName] = true;
|
|
1917
|
+
break;
|
|
1918
|
+
}
|
|
1919
|
+
case 'full': {
|
|
1920
|
+
this.joinsNotNullableMap = Object.fromEntries(Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false]));
|
|
1921
|
+
this.joinsNotNullableMap[tableName] = false;
|
|
1922
|
+
break;
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
return this;
|
|
1927
|
+
};
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1930
|
+
* Specify a condition to narrow the result set. Multiple
|
|
1931
|
+
* conditions can be combined with the `and` and `or`
|
|
1932
|
+
* functions.
|
|
1933
|
+
*
|
|
1934
|
+
* ## Examples
|
|
1935
|
+
*
|
|
1936
|
+
* ```ts
|
|
1937
|
+
* // Find cars made in the year 2000
|
|
1938
|
+
* db.select().from(cars).where(eq(cars.year, 2000));
|
|
1939
|
+
* ```
|
|
1940
|
+
*/
|
|
1941
|
+
where(where) {
|
|
1942
|
+
if (typeof where === 'function') {
|
|
1943
|
+
where = where(new Proxy(this.config.fields, new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' })));
|
|
1944
|
+
}
|
|
1945
|
+
this.config.where = where;
|
|
1946
|
+
return this;
|
|
1947
|
+
}
|
|
1948
|
+
/**
|
|
1949
|
+
* Sets the HAVING clause of this query, which often
|
|
1950
|
+
* used with GROUP BY and filters rows after they've been
|
|
1951
|
+
* grouped together and combined.
|
|
1952
|
+
*
|
|
1953
|
+
* {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-HAVING|Postgres having clause documentation}
|
|
1954
|
+
*/
|
|
1955
|
+
having(having) {
|
|
1956
|
+
if (typeof having === 'function') {
|
|
1957
|
+
having = having(new Proxy(this.config.fields, new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' })));
|
|
1958
|
+
}
|
|
1959
|
+
this.config.having = having;
|
|
1960
|
+
return this;
|
|
1961
|
+
}
|
|
1962
|
+
groupBy(...columns) {
|
|
1963
|
+
if (typeof columns[0] === 'function') {
|
|
1964
|
+
const groupBy = columns[0](new Proxy(this.config.fields, new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' })));
|
|
1965
|
+
this.config.groupBy = Array.isArray(groupBy) ? groupBy : [groupBy];
|
|
1966
|
+
}
|
|
1967
|
+
else {
|
|
1968
|
+
this.config.groupBy = columns;
|
|
1969
|
+
}
|
|
1970
|
+
return this;
|
|
1971
|
+
}
|
|
1972
|
+
orderBy(...columns) {
|
|
1973
|
+
if (typeof columns[0] === 'function') {
|
|
1974
|
+
const orderBy = columns[0](new Proxy(this.config.fields, new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' })));
|
|
1975
|
+
this.config.orderBy = Array.isArray(orderBy) ? orderBy : [orderBy];
|
|
1976
|
+
}
|
|
1977
|
+
else {
|
|
1978
|
+
this.config.orderBy = columns;
|
|
1979
|
+
}
|
|
1980
|
+
return this;
|
|
1981
|
+
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Set the maximum number of rows that will be
|
|
1984
|
+
* returned by this query.
|
|
1985
|
+
*
|
|
1986
|
+
* ## Examples
|
|
1987
|
+
*
|
|
1988
|
+
* ```ts
|
|
1989
|
+
* // Get the first 10 people from this query.
|
|
1990
|
+
* db.select().from(people).limit(10);
|
|
1991
|
+
* ```
|
|
1992
|
+
*
|
|
1993
|
+
* {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-LIMIT|Postgres LIMIT documentation}
|
|
1994
|
+
*/
|
|
1995
|
+
limit(limit) {
|
|
1996
|
+
this.config.limit = limit;
|
|
1997
|
+
return this;
|
|
1998
|
+
}
|
|
1999
|
+
/**
|
|
2000
|
+
* Skip a number of rows when returning results
|
|
2001
|
+
* from this query.
|
|
2002
|
+
*
|
|
2003
|
+
* ## Examples
|
|
2004
|
+
*
|
|
2005
|
+
* ```ts
|
|
2006
|
+
* // Get the 10th-20th people from this query.
|
|
2007
|
+
* db.select().from(people).offset(10).limit(10);
|
|
2008
|
+
* ```
|
|
2009
|
+
*/
|
|
2010
|
+
offset(offset) {
|
|
2011
|
+
this.config.offset = offset;
|
|
2012
|
+
return this;
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* The FOR clause specifies a lock strength for this query
|
|
2016
|
+
* that controls how strictly it acquires exclusive access to
|
|
2017
|
+
* the rows being queried.
|
|
2018
|
+
*
|
|
2019
|
+
* {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-FOR-UPDATE-SHARE|Postgres locking clause documentation}
|
|
2020
|
+
*/
|
|
2021
|
+
for(strength, config = {}) {
|
|
2022
|
+
this.config.lockingClauses.push({ strength, config });
|
|
2023
|
+
return this;
|
|
2024
|
+
}
|
|
2025
|
+
/** @internal */
|
|
2026
|
+
getSQL() {
|
|
2027
|
+
return this.dialect.buildSelectQuery(this.config);
|
|
2028
|
+
}
|
|
2029
|
+
toSQL() {
|
|
2030
|
+
const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL());
|
|
2031
|
+
return rest;
|
|
2032
|
+
}
|
|
2033
|
+
as(alias) {
|
|
2034
|
+
return new Proxy(new Subquery(this.getSQL(), this.config.fields, alias), new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }));
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
class PgSelect extends PgSelectQueryBuilder {
|
|
2038
|
+
constructor() {
|
|
2039
|
+
super(...arguments);
|
|
2040
|
+
this.execute = (placeholderValues) => {
|
|
2041
|
+
return this._prepare().execute(placeholderValues);
|
|
2042
|
+
};
|
|
2043
|
+
}
|
|
2044
|
+
_prepare(name) {
|
|
2045
|
+
if (!this.session) {
|
|
2046
|
+
throw new Error('Cannot execute a query on a query builder. Please use a database instance instead.');
|
|
2047
|
+
}
|
|
2048
|
+
const fieldsList = orderSelectedFields(this.config.fields);
|
|
2049
|
+
const query = this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), fieldsList, name);
|
|
2050
|
+
query.joinsNotNullableMap = this.joinsNotNullableMap;
|
|
2051
|
+
return query;
|
|
2052
|
+
}
|
|
2053
|
+
/**
|
|
2054
|
+
* Create a prepared statement for this query. This allows
|
|
2055
|
+
* the database to remember this query for the given session
|
|
2056
|
+
* and call it by name, rather than specifying the full query.
|
|
2057
|
+
*
|
|
2058
|
+
* {@link https://www.postgresql.org/docs/current/sql-prepare.html|Postgres prepare documentation}
|
|
2059
|
+
*/
|
|
2060
|
+
prepare(name) {
|
|
2061
|
+
return this._prepare(name);
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
applyMixins(PgSelect, [QueryPromise]);
|
|
2065
|
+
|
|
2066
|
+
class QueryBuilder {
|
|
2067
|
+
$with(alias) {
|
|
2068
|
+
const queryBuilder = this;
|
|
2069
|
+
return {
|
|
2070
|
+
as(qb) {
|
|
2071
|
+
if (typeof qb === 'function') {
|
|
2072
|
+
qb = qb(queryBuilder);
|
|
2073
|
+
}
|
|
2074
|
+
return new Proxy(new WithSubquery(qb.getSQL(), qb.getSelectedFields(), alias, true), new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }));
|
|
2075
|
+
},
|
|
2076
|
+
};
|
|
2077
|
+
}
|
|
2078
|
+
with(...queries) {
|
|
2079
|
+
const self = this;
|
|
2080
|
+
function select(fields) {
|
|
2081
|
+
return new PgSelectBuilder(fields ?? undefined, undefined, self.getDialect(), queries);
|
|
2082
|
+
}
|
|
2083
|
+
return { select };
|
|
2084
|
+
}
|
|
2085
|
+
select(fields) {
|
|
2086
|
+
return new PgSelectBuilder(fields ?? undefined, undefined, this.getDialect());
|
|
2087
|
+
}
|
|
2088
|
+
// Lazy load dialect to avoid circular dependency
|
|
2089
|
+
getDialect() {
|
|
2090
|
+
if (!this.dialect) {
|
|
2091
|
+
this.dialect = new PgDialect();
|
|
2092
|
+
}
|
|
2093
|
+
return this.dialect;
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
class DefaultViewBuilderCore {
|
|
2098
|
+
constructor(name, schema) {
|
|
2099
|
+
this.name = name;
|
|
2100
|
+
this.schema = schema;
|
|
2101
|
+
this.config = {};
|
|
2102
|
+
}
|
|
2103
|
+
with(config) {
|
|
2104
|
+
this.config.with = config;
|
|
2105
|
+
return this;
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
class ViewBuilder extends DefaultViewBuilderCore {
|
|
2109
|
+
as(qb) {
|
|
2110
|
+
if (typeof qb === 'function') {
|
|
2111
|
+
qb = qb(new QueryBuilder());
|
|
2112
|
+
}
|
|
2113
|
+
const selectionProxy = new SelectionProxyHandler({
|
|
2114
|
+
alias: this.name,
|
|
2115
|
+
sqlBehavior: 'error',
|
|
2116
|
+
sqlAliasedBehavior: 'alias',
|
|
2117
|
+
replaceOriginalName: true,
|
|
2118
|
+
});
|
|
2119
|
+
const aliasedSelection = new Proxy(qb.getSelectedFields(), selectionProxy);
|
|
2120
|
+
return new Proxy(new PgView({
|
|
2121
|
+
pgConfig: this.config,
|
|
2122
|
+
config: {
|
|
2123
|
+
name: this.name,
|
|
2124
|
+
schema: this.schema,
|
|
2125
|
+
selectedFields: aliasedSelection,
|
|
2126
|
+
query: qb.getSQL().inlineParams(),
|
|
2127
|
+
},
|
|
2128
|
+
}), selectionProxy);
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
class ManualViewBuilder extends DefaultViewBuilderCore {
|
|
2132
|
+
constructor(name, columns, schema) {
|
|
2133
|
+
super(name, schema);
|
|
2134
|
+
this.columns = getTableColumns(pgTable(name, columns));
|
|
2135
|
+
}
|
|
2136
|
+
existing() {
|
|
2137
|
+
return new Proxy(new PgView({
|
|
2138
|
+
pgConfig: undefined,
|
|
2139
|
+
config: {
|
|
2140
|
+
name: this.name,
|
|
2141
|
+
schema: this.schema,
|
|
2142
|
+
selectedFields: this.columns,
|
|
2143
|
+
query: undefined,
|
|
2144
|
+
},
|
|
2145
|
+
}), new SelectionProxyHandler({
|
|
2146
|
+
alias: this.name,
|
|
2147
|
+
sqlBehavior: 'error',
|
|
2148
|
+
sqlAliasedBehavior: 'alias',
|
|
2149
|
+
replaceOriginalName: true,
|
|
2150
|
+
}));
|
|
2151
|
+
}
|
|
2152
|
+
as(query) {
|
|
2153
|
+
return new Proxy(new PgView({
|
|
2154
|
+
pgConfig: this.config,
|
|
2155
|
+
config: {
|
|
2156
|
+
name: this.name,
|
|
2157
|
+
schema: this.schema,
|
|
2158
|
+
selectedFields: this.columns,
|
|
2159
|
+
query: query.inlineParams(),
|
|
2160
|
+
},
|
|
2161
|
+
}), new SelectionProxyHandler({
|
|
2162
|
+
alias: this.name,
|
|
2163
|
+
sqlBehavior: 'error',
|
|
2164
|
+
sqlAliasedBehavior: 'alias',
|
|
2165
|
+
replaceOriginalName: true,
|
|
2166
|
+
}));
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
class MaterializedViewBuilderCore {
|
|
2170
|
+
constructor(name, schema) {
|
|
2171
|
+
this.name = name;
|
|
2172
|
+
this.schema = schema;
|
|
2173
|
+
this.config = {};
|
|
2174
|
+
}
|
|
2175
|
+
using(using) {
|
|
2176
|
+
this.config.using = using;
|
|
2177
|
+
return this;
|
|
2178
|
+
}
|
|
2179
|
+
with(config) {
|
|
2180
|
+
this.config.with = config;
|
|
2181
|
+
return this;
|
|
2182
|
+
}
|
|
2183
|
+
tablespace(tablespace) {
|
|
2184
|
+
this.config.tablespace = tablespace;
|
|
2185
|
+
return this;
|
|
2186
|
+
}
|
|
2187
|
+
withNoData() {
|
|
2188
|
+
this.config.withNoData = true;
|
|
2189
|
+
return this;
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
class MaterializedViewBuilder extends MaterializedViewBuilderCore {
|
|
2193
|
+
as(qb) {
|
|
2194
|
+
if (typeof qb === 'function') {
|
|
2195
|
+
qb = qb(new QueryBuilder());
|
|
2196
|
+
}
|
|
2197
|
+
const selectionProxy = new SelectionProxyHandler({
|
|
2198
|
+
alias: this.name,
|
|
2199
|
+
sqlBehavior: 'error',
|
|
2200
|
+
sqlAliasedBehavior: 'alias',
|
|
2201
|
+
replaceOriginalName: true,
|
|
2202
|
+
});
|
|
2203
|
+
const aliasedSelection = new Proxy(qb.getSelectedFields(), selectionProxy);
|
|
2204
|
+
return new Proxy(new PgMaterializedView({
|
|
2205
|
+
pgConfig: {
|
|
2206
|
+
with: this.config.with,
|
|
2207
|
+
using: this.config.using,
|
|
2208
|
+
tablespace: this.config.tablespace,
|
|
2209
|
+
withNoData: this.config.withNoData,
|
|
2210
|
+
},
|
|
2211
|
+
config: {
|
|
2212
|
+
name: this.name,
|
|
2213
|
+
schema: this.schema,
|
|
2214
|
+
selectedFields: aliasedSelection,
|
|
2215
|
+
query: qb.getSQL().inlineParams(),
|
|
2216
|
+
},
|
|
2217
|
+
}), selectionProxy);
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
class ManualMaterializedViewBuilder extends MaterializedViewBuilderCore {
|
|
2221
|
+
constructor(name, columns, schema) {
|
|
2222
|
+
super(name, schema);
|
|
2223
|
+
this.columns = getTableColumns(pgTable(name, columns));
|
|
2224
|
+
}
|
|
2225
|
+
existing() {
|
|
2226
|
+
return new Proxy(new PgMaterializedView({
|
|
2227
|
+
pgConfig: undefined,
|
|
2228
|
+
config: {
|
|
2229
|
+
name: this.name,
|
|
2230
|
+
schema: this.schema,
|
|
2231
|
+
selectedFields: this.columns,
|
|
2232
|
+
query: undefined,
|
|
2233
|
+
},
|
|
2234
|
+
}), new SelectionProxyHandler({
|
|
2235
|
+
alias: this.name,
|
|
2236
|
+
sqlBehavior: 'error',
|
|
2237
|
+
sqlAliasedBehavior: 'alias',
|
|
2238
|
+
replaceOriginalName: true,
|
|
2239
|
+
}));
|
|
2240
|
+
}
|
|
2241
|
+
as(query) {
|
|
2242
|
+
return new Proxy(new PgMaterializedView({
|
|
2243
|
+
pgConfig: undefined,
|
|
2244
|
+
config: {
|
|
2245
|
+
name: this.name,
|
|
2246
|
+
schema: this.schema,
|
|
2247
|
+
selectedFields: this.columns,
|
|
2248
|
+
query: query.inlineParams(),
|
|
2249
|
+
},
|
|
2250
|
+
}), new SelectionProxyHandler({
|
|
2251
|
+
alias: this.name,
|
|
2252
|
+
sqlBehavior: 'error',
|
|
2253
|
+
sqlAliasedBehavior: 'alias',
|
|
2254
|
+
replaceOriginalName: true,
|
|
2255
|
+
}));
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
class PgViewBase extends View {
|
|
2259
|
+
}
|
|
2260
|
+
const PgViewConfig = Symbol('PgViewConfig');
|
|
2261
|
+
class PgView extends PgViewBase {
|
|
2262
|
+
constructor({ pgConfig, config }) {
|
|
2263
|
+
super(config);
|
|
2264
|
+
if (pgConfig) {
|
|
2265
|
+
this[PgViewConfig] = {
|
|
2266
|
+
with: pgConfig.with,
|
|
2267
|
+
};
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
const PgMaterializedViewConfig = Symbol('PgMaterializedViewConfig');
|
|
2272
|
+
class PgMaterializedView extends PgViewBase {
|
|
2273
|
+
constructor({ pgConfig, config }) {
|
|
2274
|
+
super(config);
|
|
2275
|
+
this[PgMaterializedViewConfig] = {
|
|
2276
|
+
with: pgConfig?.with,
|
|
2277
|
+
using: pgConfig?.using,
|
|
2278
|
+
tablespace: pgConfig?.tablespace,
|
|
2279
|
+
withNoData: pgConfig?.withNoData,
|
|
2280
|
+
};
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
/** @internal */
|
|
2284
|
+
function pgViewWithSchema(name, selection, schema) {
|
|
2285
|
+
if (selection) {
|
|
2286
|
+
return new ManualViewBuilder(name, selection, schema);
|
|
2287
|
+
}
|
|
2288
|
+
return new ViewBuilder(name, schema);
|
|
2289
|
+
}
|
|
2290
|
+
/** @internal */
|
|
2291
|
+
function pgMaterializedViewWithSchema(name, selection, schema) {
|
|
2292
|
+
if (selection) {
|
|
2293
|
+
return new ManualMaterializedViewBuilder(name, selection, schema);
|
|
2294
|
+
}
|
|
2295
|
+
return new MaterializedViewBuilder(name, schema);
|
|
2296
|
+
}
|
|
2297
|
+
function pgView(name, columns) {
|
|
2298
|
+
return pgViewWithSchema(name, columns, undefined);
|
|
2299
|
+
}
|
|
2300
|
+
function pgMaterializedView(name, columns) {
|
|
2301
|
+
return pgMaterializedViewWithSchema(name, columns, undefined);
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
function getTableConfig(table) {
|
|
2305
|
+
const columns = Object.values(table[Table.Symbol.Columns]);
|
|
2306
|
+
const indexes = [];
|
|
2307
|
+
const checks = [];
|
|
2308
|
+
const primaryKeys = [];
|
|
2309
|
+
const foreignKeys = Object.values(table[PgTable.Symbol.InlineForeignKeys]);
|
|
2310
|
+
const name = table[Table.Symbol.Name];
|
|
2311
|
+
const schema = table[Table.Symbol.Schema];
|
|
2312
|
+
const extraConfigBuilder = table[PgTable.Symbol.ExtraConfigBuilder];
|
|
2313
|
+
if (extraConfigBuilder !== undefined) {
|
|
2314
|
+
const extraConfig = extraConfigBuilder(table[Table.Symbol.Columns]);
|
|
2315
|
+
for (const builder of Object.values(extraConfig)) {
|
|
2316
|
+
if (builder instanceof IndexBuilder) {
|
|
2317
|
+
indexes.push(builder.build(table));
|
|
2318
|
+
}
|
|
2319
|
+
else if (builder instanceof CheckBuilder) {
|
|
2320
|
+
checks.push(builder.build(table));
|
|
2321
|
+
}
|
|
2322
|
+
else if (builder instanceof PrimaryKeyBuilder) {
|
|
2323
|
+
primaryKeys.push(builder.build(table));
|
|
2324
|
+
}
|
|
2325
|
+
else if (builder instanceof ForeignKeyBuilder) {
|
|
2326
|
+
foreignKeys.push(builder.build(table));
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
return {
|
|
2331
|
+
columns,
|
|
2332
|
+
indexes,
|
|
2333
|
+
foreignKeys,
|
|
2334
|
+
checks,
|
|
2335
|
+
primaryKeys,
|
|
2336
|
+
name,
|
|
2337
|
+
schema,
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
function getViewConfig(view) {
|
|
2341
|
+
return {
|
|
2342
|
+
...view[ViewBaseConfig],
|
|
2343
|
+
...view[PgViewConfig],
|
|
2344
|
+
};
|
|
2345
|
+
}
|
|
2346
|
+
function getMaterializedViewConfig(view) {
|
|
2347
|
+
return {
|
|
2348
|
+
...view[ViewBaseConfig],
|
|
2349
|
+
...view[PgMaterializedViewConfig],
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
function parsePgArrayValue(arrayString, startFrom, inQuotes) {
|
|
2353
|
+
for (let i = startFrom; i < arrayString.length; i++) {
|
|
2354
|
+
const char = arrayString[i];
|
|
2355
|
+
if (char === '\\') {
|
|
2356
|
+
i++;
|
|
2357
|
+
continue;
|
|
2358
|
+
}
|
|
2359
|
+
if (char === '"') {
|
|
2360
|
+
return [arrayString.slice(startFrom, i).replace(/\\/g, ''), i + 1];
|
|
2361
|
+
}
|
|
2362
|
+
if (inQuotes) {
|
|
2363
|
+
continue;
|
|
2364
|
+
}
|
|
2365
|
+
if (char === ',' || char === '}') {
|
|
2366
|
+
return [arrayString.slice(startFrom, i).replace(/\\/g, ''), i];
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
return [arrayString.slice(startFrom).replace(/\\/g, ''), arrayString.length];
|
|
2370
|
+
}
|
|
2371
|
+
function parsePgNestedArray(arrayString, startFrom = 0) {
|
|
2372
|
+
const result = [];
|
|
2373
|
+
let i = startFrom;
|
|
2374
|
+
let lastCharIsComma = false;
|
|
2375
|
+
while (i < arrayString.length) {
|
|
2376
|
+
const char = arrayString[i];
|
|
2377
|
+
if (char === ',') {
|
|
2378
|
+
if (lastCharIsComma || i === startFrom) {
|
|
2379
|
+
result.push('');
|
|
2380
|
+
}
|
|
2381
|
+
lastCharIsComma = true;
|
|
2382
|
+
i++;
|
|
2383
|
+
continue;
|
|
2384
|
+
}
|
|
2385
|
+
lastCharIsComma = false;
|
|
2386
|
+
if (char === '\\') {
|
|
2387
|
+
i += 2;
|
|
2388
|
+
continue;
|
|
2389
|
+
}
|
|
2390
|
+
if (char === '"') {
|
|
2391
|
+
const [value, startFrom] = parsePgArrayValue(arrayString, i + 1, true);
|
|
2392
|
+
result.push(value);
|
|
2393
|
+
i = startFrom;
|
|
2394
|
+
continue;
|
|
2395
|
+
}
|
|
2396
|
+
if (char === '}') {
|
|
2397
|
+
return [result, i + 1];
|
|
2398
|
+
}
|
|
2399
|
+
if (char === '{') {
|
|
2400
|
+
const [value, startFrom] = parsePgNestedArray(arrayString, i + 1);
|
|
2401
|
+
result.push(value);
|
|
2402
|
+
i = startFrom;
|
|
2403
|
+
continue;
|
|
2404
|
+
}
|
|
2405
|
+
const [value, newStartFrom] = parsePgArrayValue(arrayString, i, false);
|
|
2406
|
+
result.push(value);
|
|
2407
|
+
i = newStartFrom;
|
|
2408
|
+
}
|
|
2409
|
+
return [result, i];
|
|
2410
|
+
}
|
|
2411
|
+
function parsePgArray(arrayString) {
|
|
2412
|
+
const [result] = parsePgNestedArray(arrayString, 1);
|
|
2413
|
+
return result;
|
|
2414
|
+
}
|
|
2415
|
+
function makePgArray(array) {
|
|
2416
|
+
return `{${array.map((item) => {
|
|
2417
|
+
if (Array.isArray(item)) {
|
|
2418
|
+
return makePgArray(item);
|
|
2419
|
+
}
|
|
2420
|
+
if (typeof item === 'string' && item.includes(',')) {
|
|
2421
|
+
return `"${item.replace(/"/g, '\\"')}"`;
|
|
2422
|
+
}
|
|
2423
|
+
return `${item}`;
|
|
2424
|
+
}).join(',')}}`;
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
class PgColumnBuilder extends ColumnBuilder {
|
|
2428
|
+
constructor() {
|
|
2429
|
+
super(...arguments);
|
|
2430
|
+
this.foreignKeyConfigs = [];
|
|
2431
|
+
}
|
|
2432
|
+
array(size) {
|
|
2433
|
+
return new PgArrayBuilder(this.config.name, this, size);
|
|
2434
|
+
}
|
|
2435
|
+
references(ref, actions = {}) {
|
|
2436
|
+
this.foreignKeyConfigs.push({ ref, actions });
|
|
2437
|
+
return this;
|
|
2438
|
+
}
|
|
2439
|
+
/** @internal */
|
|
2440
|
+
buildForeignKeys(column, table) {
|
|
2441
|
+
return this.foreignKeyConfigs.map(({ ref, actions }) => {
|
|
2442
|
+
return ((ref, actions) => {
|
|
2443
|
+
const builder = new ForeignKeyBuilder(() => {
|
|
2444
|
+
const foreignColumn = ref();
|
|
2445
|
+
return { columns: [column], foreignColumns: [foreignColumn] };
|
|
2446
|
+
});
|
|
2447
|
+
if (actions.onUpdate) {
|
|
2448
|
+
builder.onUpdate(actions.onUpdate);
|
|
2449
|
+
}
|
|
2450
|
+
if (actions.onDelete) {
|
|
2451
|
+
builder.onDelete(actions.onDelete);
|
|
2452
|
+
}
|
|
2453
|
+
return builder.build(table);
|
|
2454
|
+
})(ref, actions);
|
|
2455
|
+
});
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
// To understand how to use `PgColumn` and `AnyPgColumn`, see `Column` and `AnyColumn` documentation.
|
|
2459
|
+
class PgColumn extends Column {
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
class PgArrayBuilder extends PgColumnBuilder {
|
|
2463
|
+
constructor(name, baseBuilder, size) {
|
|
2464
|
+
super(name);
|
|
2465
|
+
this.config.baseBuilder = baseBuilder;
|
|
2466
|
+
this.config.size = size;
|
|
2467
|
+
}
|
|
2468
|
+
/** @internal */
|
|
2469
|
+
build(table) {
|
|
2470
|
+
const baseColumn = this.config.baseBuilder.build(table);
|
|
2471
|
+
return new PgArray(table, this.config, baseColumn);
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
class PgArray extends PgColumn {
|
|
2475
|
+
constructor(table, config, baseColumn, range) {
|
|
2476
|
+
super(table, config);
|
|
2477
|
+
this.baseColumn = baseColumn;
|
|
2478
|
+
this.range = range;
|
|
2479
|
+
this.size = config.size;
|
|
2480
|
+
}
|
|
2481
|
+
getSQLType() {
|
|
2482
|
+
return `${this.baseColumn.getSQLType()}[${typeof this.size === 'number' ? this.size : ''}]`;
|
|
2483
|
+
}
|
|
2484
|
+
mapFromDriverValue(value) {
|
|
2485
|
+
if (typeof value === 'string') {
|
|
2486
|
+
// Thank you node-postgres for not parsing enum arrays
|
|
2487
|
+
value = parsePgArray(value);
|
|
2488
|
+
}
|
|
2489
|
+
return value.map((v) => this.baseColumn.mapFromDriverValue(v));
|
|
2490
|
+
}
|
|
2491
|
+
mapToDriverValue(value, isNestedArray = false) {
|
|
2492
|
+
const a = value.map((v) => v === null
|
|
2493
|
+
? null
|
|
2494
|
+
: this.baseColumn instanceof PgArray
|
|
2495
|
+
? this.baseColumn.mapToDriverValue(v, true)
|
|
2496
|
+
: this.baseColumn.mapToDriverValue(v));
|
|
2497
|
+
if (isNestedArray)
|
|
2498
|
+
return a;
|
|
2499
|
+
return makePgArray(a);
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
class PgDateColumnBaseBuilder extends PgColumnBuilder {
|
|
2504
|
+
defaultNow() {
|
|
2505
|
+
return this.default(sql `now()`);
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
class PgDateBuilder extends PgDateColumnBaseBuilder {
|
|
2510
|
+
/** @internal */
|
|
2511
|
+
build(table) {
|
|
2512
|
+
return new PgDate(table, this.config);
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
class PgDate extends PgColumn {
|
|
2516
|
+
getSQLType() {
|
|
2517
|
+
return 'date';
|
|
2518
|
+
}
|
|
2519
|
+
mapFromDriverValue(value) {
|
|
2520
|
+
return new Date(value);
|
|
2521
|
+
}
|
|
2522
|
+
mapToDriverValue(value) {
|
|
2523
|
+
return value.toISOString();
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
class PgDateStringBuilder extends PgDateColumnBaseBuilder {
|
|
2527
|
+
/** @internal */
|
|
2528
|
+
build(table) {
|
|
2529
|
+
return new PgDateString(table, this.config);
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
class PgDateString extends PgColumn {
|
|
2533
|
+
getSQLType() {
|
|
2534
|
+
return 'date';
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
function date(name, config) {
|
|
2538
|
+
if (config?.mode === 'date') {
|
|
2539
|
+
return new PgDateBuilder(name);
|
|
2540
|
+
}
|
|
2541
|
+
return new PgDateStringBuilder(name);
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
class PgJsonBuilder extends PgColumnBuilder {
|
|
2545
|
+
/** @internal */
|
|
2546
|
+
build(table) {
|
|
2547
|
+
return new PgJson(table, this.config);
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
class PgJson extends PgColumn {
|
|
2551
|
+
constructor(table, config) {
|
|
2552
|
+
super(table, config);
|
|
2553
|
+
}
|
|
2554
|
+
getSQLType() {
|
|
2555
|
+
return 'json';
|
|
2556
|
+
}
|
|
2557
|
+
mapToDriverValue(value) {
|
|
2558
|
+
return JSON.stringify(value);
|
|
2559
|
+
}
|
|
2560
|
+
mapFromDriverValue(value) {
|
|
2561
|
+
if (typeof value === 'string') {
|
|
2562
|
+
try {
|
|
2563
|
+
return JSON.parse(value);
|
|
2564
|
+
}
|
|
2565
|
+
catch {
|
|
2566
|
+
return value;
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
return value;
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
function json(name) {
|
|
2573
|
+
return new PgJsonBuilder(name);
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
class PgJsonbBuilder extends PgColumnBuilder {
|
|
2577
|
+
/** @internal */
|
|
2578
|
+
build(table) {
|
|
2579
|
+
return new PgJsonb(table, this.config);
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
class PgJsonb extends PgColumn {
|
|
2583
|
+
constructor(table, config) {
|
|
2584
|
+
super(table, config);
|
|
2585
|
+
}
|
|
2586
|
+
getSQLType() {
|
|
2587
|
+
return 'jsonb';
|
|
2588
|
+
}
|
|
2589
|
+
mapToDriverValue(value) {
|
|
2590
|
+
return JSON.stringify(value);
|
|
2591
|
+
}
|
|
2592
|
+
mapFromDriverValue(value) {
|
|
2593
|
+
if (typeof value === 'string') {
|
|
2594
|
+
try {
|
|
2595
|
+
return JSON.parse(value);
|
|
2596
|
+
}
|
|
2597
|
+
catch {
|
|
2598
|
+
return value;
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
return value;
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
function jsonb(name) {
|
|
2605
|
+
return new PgJsonbBuilder(name);
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
class PgNumericBuilder extends PgColumnBuilder {
|
|
2609
|
+
constructor(name, precision, scale) {
|
|
2610
|
+
super(name);
|
|
2611
|
+
this.config.precision = precision;
|
|
2612
|
+
this.config.scale = scale;
|
|
2613
|
+
}
|
|
2614
|
+
/** @internal */
|
|
2615
|
+
build(table) {
|
|
2616
|
+
return new PgNumeric(table, this.config);
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
class PgNumeric extends PgColumn {
|
|
2620
|
+
constructor(table, config) {
|
|
2621
|
+
super(table, config);
|
|
2622
|
+
this.precision = config.precision;
|
|
2623
|
+
this.scale = config.scale;
|
|
2624
|
+
}
|
|
2625
|
+
getSQLType() {
|
|
2626
|
+
if (this.precision !== undefined && this.scale !== undefined) {
|
|
2627
|
+
return `numeric(${this.precision}, ${this.scale})`;
|
|
2628
|
+
}
|
|
2629
|
+
else if (this.precision === undefined) {
|
|
2630
|
+
return 'numeric';
|
|
2631
|
+
}
|
|
2632
|
+
else {
|
|
2633
|
+
return `numeric(${this.precision})`;
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
function numeric(name, config) {
|
|
2638
|
+
return new PgNumericBuilder(name, config?.precision, config?.scale);
|
|
2639
|
+
}
|
|
2640
|
+
const decimal = numeric;
|
|
2641
|
+
|
|
2642
|
+
class PgTimeBuilder extends PgDateColumnBaseBuilder {
|
|
2643
|
+
constructor(name, withTimezone, precision) {
|
|
2644
|
+
super(name);
|
|
2645
|
+
this.withTimezone = withTimezone;
|
|
2646
|
+
this.precision = precision;
|
|
2647
|
+
this.config.withTimezone = withTimezone;
|
|
2648
|
+
this.config.precision = precision;
|
|
2649
|
+
}
|
|
2650
|
+
/** @internal */
|
|
2651
|
+
build(table) {
|
|
2652
|
+
return new PgTime(table, this.config);
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
class PgTime extends PgColumn {
|
|
2656
|
+
constructor(table, config) {
|
|
2657
|
+
super(table, config);
|
|
2658
|
+
this.withTimezone = config.withTimezone;
|
|
2659
|
+
this.precision = config.precision;
|
|
2660
|
+
}
|
|
2661
|
+
getSQLType() {
|
|
2662
|
+
const precision = this.precision === undefined ? '' : `(${this.precision})`;
|
|
2663
|
+
return `time${precision}${this.withTimezone ? ' with time zone' : ''}`;
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
function time(name, config = {}) {
|
|
2667
|
+
return new PgTimeBuilder(name, config.withTimezone ?? false, config.precision);
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2670
|
+
class PgTimestampBuilder extends PgDateColumnBaseBuilder {
|
|
2671
|
+
constructor(name, withTimezone, precision) {
|
|
2672
|
+
super(name);
|
|
2673
|
+
this.config.withTimezone = withTimezone;
|
|
2674
|
+
this.config.precision = precision;
|
|
2675
|
+
}
|
|
2676
|
+
/** @internal */
|
|
2677
|
+
build(table) {
|
|
2678
|
+
return new PgTimestamp(table, this.config);
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
class PgTimestamp extends PgColumn {
|
|
2682
|
+
constructor(table, config) {
|
|
2683
|
+
super(table, config);
|
|
2684
|
+
this.mapFromDriverValue = (value) => {
|
|
2685
|
+
return new Date(this.withTimezone ? value : value + '+0000');
|
|
2686
|
+
};
|
|
2687
|
+
this.mapToDriverValue = (value) => {
|
|
2688
|
+
return this.withTimezone ? value.toUTCString() : value.toISOString();
|
|
2689
|
+
};
|
|
2690
|
+
this.withTimezone = config.withTimezone;
|
|
2691
|
+
this.precision = config.precision;
|
|
2692
|
+
}
|
|
2693
|
+
getSQLType() {
|
|
2694
|
+
const precision = this.precision === undefined ? '' : ` (${this.precision})`;
|
|
2695
|
+
return `timestamp${precision}${this.withTimezone ? ' with time zone' : ''}`;
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
class PgTimestampStringBuilder extends PgDateColumnBaseBuilder {
|
|
2699
|
+
constructor(name, withTimezone, precision) {
|
|
2700
|
+
super(name);
|
|
2701
|
+
this.config.withTimezone = withTimezone;
|
|
2702
|
+
this.config.precision = precision;
|
|
2703
|
+
}
|
|
2704
|
+
/** @internal */
|
|
2705
|
+
build(table) {
|
|
2706
|
+
return new PgTimestampString(table, this.config);
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
class PgTimestampString extends PgColumn {
|
|
2710
|
+
constructor(table, config) {
|
|
2711
|
+
super(table, config);
|
|
2712
|
+
this.withTimezone = config.withTimezone;
|
|
2713
|
+
this.precision = config.precision;
|
|
2714
|
+
}
|
|
2715
|
+
getSQLType() {
|
|
2716
|
+
const precision = this.precision === undefined ? '' : `(${this.precision})`;
|
|
2717
|
+
return `timestamp${precision}${this.withTimezone ? ' with time zone' : ''}`;
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
function timestamp(name, config = {}) {
|
|
2721
|
+
if (config.mode === 'string') {
|
|
2722
|
+
return new PgTimestampStringBuilder(name, config.withTimezone ?? false, config.precision);
|
|
2723
|
+
}
|
|
2724
|
+
return new PgTimestampBuilder(name, config.withTimezone ?? false, config.precision);
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2727
|
+
class PgUUIDBuilder extends PgColumnBuilder {
|
|
2728
|
+
/**
|
|
2729
|
+
* Adds `default gen_random_uuid()` to the column definition.
|
|
2730
|
+
*/
|
|
2731
|
+
defaultRandom() {
|
|
2732
|
+
return this.default(sql `gen_random_uuid()`);
|
|
2733
|
+
}
|
|
2734
|
+
/** @internal */
|
|
2735
|
+
build(table) {
|
|
2736
|
+
return new PgUUID(table, this.config);
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
class PgUUID extends PgColumn {
|
|
2740
|
+
getSQLType() {
|
|
2741
|
+
return 'uuid';
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
function uuid(name) {
|
|
2745
|
+
return new PgUUIDBuilder(name);
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
class Relation {
|
|
2749
|
+
constructor(sourceTable, referencedTable, relationName) {
|
|
2750
|
+
this.sourceTable = sourceTable;
|
|
2751
|
+
this.referencedTable = referencedTable;
|
|
2752
|
+
this.relationName = relationName;
|
|
2753
|
+
this.referencedTableName = referencedTable[Table.Symbol.Name];
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
class Relations {
|
|
2757
|
+
constructor(table, config) {
|
|
2758
|
+
this.table = table;
|
|
2759
|
+
this.config = config;
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
class One extends Relation {
|
|
2763
|
+
constructor(sourceTable, referencedTable, config, isNullable) {
|
|
2764
|
+
super(sourceTable, referencedTable, config?.relationName);
|
|
2765
|
+
this.config = config;
|
|
2766
|
+
this.isNullable = isNullable;
|
|
2767
|
+
}
|
|
2768
|
+
withFieldName(fieldName) {
|
|
2769
|
+
const relation = new One(this.sourceTable, this.referencedTable, this.config, this.isNullable);
|
|
2770
|
+
relation.fieldName = fieldName;
|
|
2771
|
+
return relation;
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
class Many extends Relation {
|
|
2775
|
+
constructor(sourceTable, referencedTable, config) {
|
|
2776
|
+
super(sourceTable, referencedTable, config?.relationName);
|
|
2777
|
+
this.config = config;
|
|
2778
|
+
}
|
|
2779
|
+
withFieldName(fieldName) {
|
|
2780
|
+
const relation = new Many(this.sourceTable, this.referencedTable, this.config);
|
|
2781
|
+
relation.fieldName = fieldName;
|
|
2782
|
+
return relation;
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
const operators = {
|
|
2786
|
+
sql,
|
|
2787
|
+
eq,
|
|
2788
|
+
and,
|
|
2789
|
+
or,
|
|
2790
|
+
};
|
|
2791
|
+
const orderByOperators = {
|
|
2792
|
+
sql,
|
|
2793
|
+
asc,
|
|
2794
|
+
desc,
|
|
2795
|
+
};
|
|
2796
|
+
function extractTablesRelationalConfig(schema, configHelpers) {
|
|
2797
|
+
if (Object.keys(schema).length === 1 && 'default' in schema && !(schema['default'] instanceof Table)) {
|
|
2798
|
+
schema = schema['default'];
|
|
2799
|
+
}
|
|
2800
|
+
// table DB name -> schema table key
|
|
2801
|
+
const tableNamesMap = {};
|
|
2802
|
+
// Table relations found before their tables - need to buffer them until we know the schema table key
|
|
2803
|
+
const relationsBuffer = {};
|
|
2804
|
+
const tablesConfig = {};
|
|
2805
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
2806
|
+
if (isTable(value)) {
|
|
2807
|
+
const dbName = value[Table.Symbol.Name];
|
|
2808
|
+
const bufferedRelations = relationsBuffer[dbName];
|
|
2809
|
+
tableNamesMap[dbName] = key;
|
|
2810
|
+
tablesConfig[key] = {
|
|
2811
|
+
tsName: key,
|
|
2812
|
+
dbName: value[Table.Symbol.Name],
|
|
2813
|
+
columns: value[Table.Symbol.Columns],
|
|
2814
|
+
relations: bufferedRelations?.relations ?? {},
|
|
2815
|
+
primaryKey: bufferedRelations?.primaryKey ?? [],
|
|
2816
|
+
};
|
|
2817
|
+
// Fill in primary keys
|
|
2818
|
+
for (const column of Object.values(value[Table.Symbol.Columns])) {
|
|
2819
|
+
if (column.primary) {
|
|
2820
|
+
tablesConfig[key].primaryKey.push(column);
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
const extraConfig = value[Table.Symbol.ExtraConfigBuilder]?.(value);
|
|
2824
|
+
if (extraConfig) {
|
|
2825
|
+
for (const configEntry of Object.values(extraConfig)) {
|
|
2826
|
+
if (configEntry instanceof PrimaryKeyBuilder) {
|
|
2827
|
+
tablesConfig[key].primaryKey.push(...configEntry.columns);
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
else if (value instanceof Relations) {
|
|
2833
|
+
const dbName = value.table[Table.Symbol.Name];
|
|
2834
|
+
const tableName = tableNamesMap[dbName];
|
|
2835
|
+
const relations = value.config(configHelpers(value.table));
|
|
2836
|
+
let primaryKey;
|
|
2837
|
+
for (const [relationName, relation] of Object.entries(relations)) {
|
|
2838
|
+
if (tableName) {
|
|
2839
|
+
const tableConfig = tablesConfig[tableName];
|
|
2840
|
+
tableConfig.relations[relationName] = relation;
|
|
2841
|
+
}
|
|
2842
|
+
else {
|
|
2843
|
+
if (!(dbName in relationsBuffer)) {
|
|
2844
|
+
relationsBuffer[dbName] = {
|
|
2845
|
+
relations: {},
|
|
2846
|
+
primaryKey,
|
|
2847
|
+
};
|
|
2848
|
+
}
|
|
2849
|
+
relationsBuffer[dbName].relations[relationName] = relation;
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
return { tables: tablesConfig, tableNamesMap };
|
|
2855
|
+
}
|
|
2856
|
+
function relations(table, relations) {
|
|
2857
|
+
return new Relations(table, (helpers) => Object.fromEntries(Object.entries(relations(helpers))
|
|
2858
|
+
.map(([key, value]) => [key, value.withFieldName(key)])));
|
|
2859
|
+
}
|
|
2860
|
+
function createOne(sourceTable) {
|
|
2861
|
+
return function one(table, config) {
|
|
2862
|
+
return new One(sourceTable, table, config, (config?.fields.reduce((res, f) => res && f.notNull, true) ?? false));
|
|
2863
|
+
};
|
|
2864
|
+
}
|
|
2865
|
+
function createMany(sourceTable) {
|
|
2866
|
+
return function many(referencedTable, config) {
|
|
2867
|
+
return new Many(sourceTable, referencedTable, config);
|
|
2868
|
+
};
|
|
2869
|
+
}
|
|
2870
|
+
function normalizeRelation(schema, tableNamesMap, relation) {
|
|
2871
|
+
if (relation instanceof One && relation.config) {
|
|
2872
|
+
return {
|
|
2873
|
+
fields: relation.config.fields,
|
|
2874
|
+
references: relation.config.references,
|
|
2875
|
+
};
|
|
2876
|
+
}
|
|
2877
|
+
const referencedTableTsName = tableNamesMap[relation.referencedTable[Table.Symbol.Name]];
|
|
2878
|
+
if (!referencedTableTsName) {
|
|
2879
|
+
throw new Error(`Table "${relation.referencedTable[Table.Symbol.Name]}" not found in schema`);
|
|
2880
|
+
}
|
|
2881
|
+
const referencedTableFields = schema[referencedTableTsName];
|
|
2882
|
+
if (!referencedTableFields) {
|
|
2883
|
+
throw new Error(`Table "${referencedTableTsName}" not found in schema`);
|
|
2884
|
+
}
|
|
2885
|
+
const sourceTable = relation.sourceTable;
|
|
2886
|
+
const sourceTableTsName = tableNamesMap[sourceTable[Table.Symbol.Name]];
|
|
2887
|
+
if (!sourceTableTsName) {
|
|
2888
|
+
throw new Error(`Table "${sourceTable[Table.Symbol.Name]}" not found in schema`);
|
|
2889
|
+
}
|
|
2890
|
+
const reverseRelations = [];
|
|
2891
|
+
for (const referencedTableRelation of Object.values(referencedTableFields.relations)) {
|
|
2892
|
+
if ((relation.relationName && referencedTableRelation.relationName === relation.relationName)
|
|
2893
|
+
|| (!relation.relationName && referencedTableRelation.referencedTable === relation.sourceTable)) {
|
|
2894
|
+
reverseRelations.push(referencedTableRelation);
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
if (reverseRelations.length > 1) {
|
|
2898
|
+
throw relation.relationName
|
|
2899
|
+
? new Error(`There are multiple relations with name "${relation.relationName}" in table "${referencedTableTsName}"`)
|
|
2900
|
+
: new Error(`There are multiple relations between "${referencedTableTsName}" and "${relation.sourceTable[Table.Symbol.Name]}". Please specify relation name`);
|
|
2901
|
+
}
|
|
2902
|
+
if (reverseRelations[0] && reverseRelations[0] instanceof One && reverseRelations[0].config) {
|
|
2903
|
+
return {
|
|
2904
|
+
fields: reverseRelations[0].config.references,
|
|
2905
|
+
references: reverseRelations[0].config.fields,
|
|
2906
|
+
};
|
|
2907
|
+
}
|
|
2908
|
+
throw new Error(`There is not enough information to infer relation "${sourceTableTsName}.${relation.fieldName}"`);
|
|
2909
|
+
}
|
|
2910
|
+
function createTableRelationsHelpers(sourceTable) {
|
|
2911
|
+
return {
|
|
2912
|
+
one: createOne(sourceTable),
|
|
2913
|
+
many: createMany(sourceTable),
|
|
2914
|
+
};
|
|
2915
|
+
}
|
|
2916
|
+
function mapRelationalRow(tablesConfig, tableConfig, row, buildQueryResultSelection, jsonParseRelationalFields = false, mapColumnValue = (value) => value) {
|
|
2917
|
+
const result = {};
|
|
2918
|
+
for (const [selectionItemIndex, selectionItem] of buildQueryResultSelection.entries()) {
|
|
2919
|
+
if (selectionItem.isJson) {
|
|
2920
|
+
const relation = tableConfig.relations[selectionItem.tsKey];
|
|
2921
|
+
let subRows = row[selectionItemIndex];
|
|
2922
|
+
if (jsonParseRelationalFields) {
|
|
2923
|
+
subRows = JSON.parse(subRows);
|
|
2924
|
+
}
|
|
2925
|
+
if (relation instanceof One) {
|
|
2926
|
+
result[selectionItem.tsKey] = subRows[0]
|
|
2927
|
+
? mapRelationalRow(tablesConfig, tablesConfig[selectionItem.tableTsKey], subRows[0], selectionItem.selection)
|
|
2928
|
+
: null;
|
|
2929
|
+
}
|
|
2930
|
+
else {
|
|
2931
|
+
result[selectionItem.tsKey] = subRows.map((subRow) => mapRelationalRow(tablesConfig, tablesConfig[selectionItem.tableTsKey], subRow, selectionItem.selection));
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
else {
|
|
2935
|
+
const value = mapColumnValue(row[selectionItemIndex]);
|
|
2936
|
+
const field = selectionItem.field;
|
|
2937
|
+
let decoder;
|
|
2938
|
+
if (field instanceof Column) {
|
|
2939
|
+
decoder = field;
|
|
2940
|
+
}
|
|
2941
|
+
else if (field instanceof SQL) {
|
|
2942
|
+
decoder = field.decoder;
|
|
2943
|
+
}
|
|
2944
|
+
else {
|
|
2945
|
+
decoder = field.sql.decoder;
|
|
2946
|
+
}
|
|
2947
|
+
result[selectionItem.tsKey] = value === null ? null : decoder.mapFromDriverValue(value);
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2950
|
+
return result;
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
export { name as $, notLike as A, ilike as B, ColumnAliasProxyHandler as C, notIlike as D, asc as E, desc as F, Relation as G, Relations as H, operators as I, orderByOperators as J, extractTablesRelationalConfig as K, relations as L, Many as M, createOne as N, One as O, createMany as P, QueryPromise as Q, RelationTableAliasProxyHandler as R, normalizeRelation as S, TableAliasProxyHandler as T, createTableRelationsHelpers as U, mapRelationalRow as V, FakePrimitiveParam as W, isSQLWrapper as X, StringChunk as Y, SQL as Z, Name as _, aliasedTable as a, PgTimestampStringBuilder as a$, isDriverValueEncoder as a0, noopDecoder as a1, noopEncoder as a2, noopMapper as a3, Param as a4, param as a5, sql as a6, Placeholder as a7, placeholder as a8, fillPlaceholders as a9, pgViewWithSchema as aA, pgMaterializedViewWithSchema as aB, CheckBuilder as aC, Check as aD, check as aE, PgArrayBuilder as aF, PgArray as aG, PgDateBuilder as aH, PgDate as aI, PgDateStringBuilder as aJ, PgDateString as aK, date as aL, PgJsonBuilder as aM, PgJson as aN, json as aO, PgJsonbBuilder as aP, PgJsonb as aQ, jsonb as aR, PgNumericBuilder as aS, PgNumeric as aT, numeric as aU, decimal as aV, PgTimeBuilder as aW, PgTime as aX, time as aY, PgTimestampBuilder as aZ, PgTimestamp as a_, SubqueryConfig as aa, Subquery as ab, WithSubquery as ac, SelectionProxyHandler as ad, TableName as ae, Schema as af, Columns as ag, OriginalName as ah, BaseName as ai, IsAlias as aj, ExtraConfigBuilder as ak, Table as al, isTable as am, getTableName as an, mapResultRow as ao, orderSelectedFields as ap, mapUpdateSet as aq, applyMixins as ar, getTableColumns as as, getTableLikeName as at, ViewBaseConfig as au, View as av, PgDialect as aw, PgColumnBuilder as ax, PgColumn as ay, pgTableWithSchema as az, aliasedRelation as b, PgTimestampString as b0, timestamp as b1, PgUUIDBuilder as b2, PgUUID as b3, uuid as b4, ForeignKeyBuilder as b5, ForeignKey as b6, foreignKey as b7, IndexBuilderOn as b8, IndexBuilder as b9, PgViewBase as bA, PgViewConfig as bB, PgView as bC, PgMaterializedViewConfig as bD, PgMaterializedView as bE, pgView as bF, pgMaterializedView as bG, TypedQueryBuilder as bH, Index as ba, index as bb, uniqueIndex as bc, primaryKey as bd, PrimaryKeyBuilder as be, PrimaryKey as bf, QueryBuilder as bg, PgSelectBuilder as bh, PgSelectQueryBuilder as bi, PgSelect as bj, InlineForeignKeys as bk, PgTable as bl, pgTable as bm, pgTableCreator as bn, getTableConfig as bo, getViewConfig as bp, getMaterializedViewConfig as bq, parsePgNestedArray as br, parsePgArray as bs, makePgArray as bt, DefaultViewBuilderCore as bu, ViewBuilder as bv, ManualViewBuilder as bw, MaterializedViewBuilderCore as bx, MaterializedViewBuilder as by, ManualMaterializedViewBuilder as bz, aliasedTableColumn as c, mapColumnsInSQLToAlias as d, Column as e, ColumnBuilder as f, bindIfParam as g, eq as h, and as i, not as j, gt as k, gte as l, mapColumnsInAliasedSQLToAlias as m, ne as n, or as o, lt as p, lte as q, inArray as r, notInArray as s, isNull as t, isNotNull as u, exists as v, notExists as w, between as x, notBetween as y, like as z };
|
|
2954
|
+
//# sourceMappingURL=relations-47eb5c5f.mjs.map
|