pqb 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3630 -0
- package/dist/index.esm.js +4587 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +4691 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
- package/rollup.config.js +35 -0
- package/src/adapter.test.ts +10 -0
- package/src/adapter.ts +171 -0
- package/src/columnSchema/array.ts +21 -0
- package/src/columnSchema/boolean.ts +10 -0
- package/src/columnSchema/columnType.test.ts +129 -0
- package/src/columnSchema/columnType.ts +77 -0
- package/src/columnSchema/columnTypes.ts +145 -0
- package/src/columnSchema/columnsSchema.test.ts +32 -0
- package/src/columnSchema/columnsSchema.ts +100 -0
- package/src/columnSchema/commonMethods.ts +130 -0
- package/src/columnSchema/dateTime.ts +104 -0
- package/src/columnSchema/enum.ts +13 -0
- package/src/columnSchema/index.ts +11 -0
- package/src/columnSchema/json/array.ts +55 -0
- package/src/columnSchema/json/discriminatedUnion.ts +91 -0
- package/src/columnSchema/json/enum.ts +29 -0
- package/src/columnSchema/json/instanceOf.ts +16 -0
- package/src/columnSchema/json/intersection.ts +23 -0
- package/src/columnSchema/json/lazy.ts +22 -0
- package/src/columnSchema/json/literal.ts +12 -0
- package/src/columnSchema/json/map.ts +29 -0
- package/src/columnSchema/json/nativeEnum.ts +30 -0
- package/src/columnSchema/json/nullable.ts +33 -0
- package/src/columnSchema/json/nullish.ts +30 -0
- package/src/columnSchema/json/object.ts +206 -0
- package/src/columnSchema/json/optional.ts +28 -0
- package/src/columnSchema/json/record.ts +40 -0
- package/src/columnSchema/json/scalarTypes.ts +117 -0
- package/src/columnSchema/json/set.ts +34 -0
- package/src/columnSchema/json/tuple.ts +40 -0
- package/src/columnSchema/json/typeBase.ts +202 -0
- package/src/columnSchema/json/union.ts +16 -0
- package/src/columnSchema/json.ts +64 -0
- package/src/columnSchema/number.ts +122 -0
- package/src/columnSchema/string.ts +222 -0
- package/src/columnSchema/utils.ts +27 -0
- package/src/common.ts +86 -0
- package/src/db.test.ts +67 -0
- package/src/db.ts +212 -0
- package/src/errors.ts +7 -0
- package/src/index.ts +18 -0
- package/src/operators.test.ts +608 -0
- package/src/operators.ts +177 -0
- package/src/query.ts +292 -0
- package/src/queryDataUtils.ts +50 -0
- package/src/queryMethods/aggregate.test.ts +583 -0
- package/src/queryMethods/aggregate.ts +878 -0
- package/src/queryMethods/callbacks.test.ts +69 -0
- package/src/queryMethods/callbacks.ts +55 -0
- package/src/queryMethods/clear.test.ts +64 -0
- package/src/queryMethods/clear.ts +58 -0
- package/src/queryMethods/columnInfo.test.ts +45 -0
- package/src/queryMethods/columnInfo.ts +67 -0
- package/src/queryMethods/delete.test.ts +135 -0
- package/src/queryMethods/delete.ts +50 -0
- package/src/queryMethods/for.test.ts +57 -0
- package/src/queryMethods/for.ts +99 -0
- package/src/queryMethods/from.test.ts +66 -0
- package/src/queryMethods/from.ts +58 -0
- package/src/queryMethods/get.test.ts +66 -0
- package/src/queryMethods/get.ts +88 -0
- package/src/queryMethods/having.test.ts +247 -0
- package/src/queryMethods/having.ts +99 -0
- package/src/queryMethods/insert.test.ts +555 -0
- package/src/queryMethods/insert.ts +453 -0
- package/src/queryMethods/join.test.ts +150 -0
- package/src/queryMethods/join.ts +508 -0
- package/src/queryMethods/json.test.ts +398 -0
- package/src/queryMethods/json.ts +259 -0
- package/src/queryMethods/log.test.ts +172 -0
- package/src/queryMethods/log.ts +123 -0
- package/src/queryMethods/queryMethods.test.ts +629 -0
- package/src/queryMethods/queryMethods.ts +428 -0
- package/src/queryMethods/select.test.ts +479 -0
- package/src/queryMethods/select.ts +249 -0
- package/src/queryMethods/then.ts +236 -0
- package/src/queryMethods/transaction.test.ts +66 -0
- package/src/queryMethods/transaction.ts +66 -0
- package/src/queryMethods/union.test.ts +59 -0
- package/src/queryMethods/union.ts +89 -0
- package/src/queryMethods/update.test.ts +417 -0
- package/src/queryMethods/update.ts +350 -0
- package/src/queryMethods/upsert.test.ts +56 -0
- package/src/queryMethods/upsert.ts +43 -0
- package/src/queryMethods/where.test.ts +1594 -0
- package/src/queryMethods/where.ts +450 -0
- package/src/queryMethods/window.test.ts +66 -0
- package/src/queryMethods/window.ts +108 -0
- package/src/queryMethods/with.test.ts +191 -0
- package/src/queryMethods/with.ts +92 -0
- package/src/quote.ts +36 -0
- package/src/relations.ts +194 -0
- package/src/sql/aggregate.ts +80 -0
- package/src/sql/columnInfo.ts +22 -0
- package/src/sql/common.ts +42 -0
- package/src/sql/delete.ts +41 -0
- package/src/sql/distinct.ts +19 -0
- package/src/sql/fromAndAs.ts +51 -0
- package/src/sql/having.ts +140 -0
- package/src/sql/index.ts +2 -0
- package/src/sql/insert.ts +102 -0
- package/src/sql/join.ts +242 -0
- package/src/sql/orderBy.ts +41 -0
- package/src/sql/select.ts +153 -0
- package/src/sql/toSql.ts +153 -0
- package/src/sql/truncate.ts +13 -0
- package/src/sql/types.ts +355 -0
- package/src/sql/update.ts +62 -0
- package/src/sql/where.ts +314 -0
- package/src/sql/window.ts +38 -0
- package/src/sql/with.ts +32 -0
- package/src/test-utils.ts +172 -0
- package/src/utils.ts +140 -0
- package/tsconfig.build.json +6 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultsKey,
|
|
3
|
+
Query,
|
|
4
|
+
SetQueryReturnsAll,
|
|
5
|
+
SetQueryReturnsOne,
|
|
6
|
+
SetQueryReturnsRowCount,
|
|
7
|
+
} from '../query';
|
|
8
|
+
import { pushQueryArray } from '../queryDataUtils';
|
|
9
|
+
import { isRaw, RawExpression } from '../common';
|
|
10
|
+
import {
|
|
11
|
+
BelongsToNestedInsert,
|
|
12
|
+
BelongsToRelation,
|
|
13
|
+
HasOneNestedInsert,
|
|
14
|
+
HasOneRelation,
|
|
15
|
+
NestedInsertItem,
|
|
16
|
+
NestedInsertOneItem,
|
|
17
|
+
Relation,
|
|
18
|
+
} from '../relations';
|
|
19
|
+
import { SetOptional } from '../utils';
|
|
20
|
+
import { InsertQueryData, OnConflictItem, OnConflictMergeUpdate } from '../sql';
|
|
21
|
+
import { WhereArg } from './where';
|
|
22
|
+
import { parseResult, queryMethodByReturnType } from './then';
|
|
23
|
+
|
|
24
|
+
export type OptionalKeys<T extends Query> = {
|
|
25
|
+
[K in keyof T['shape']]: T['shape'][K]['isPrimaryKey'] extends true
|
|
26
|
+
? K
|
|
27
|
+
: T['shape'][K]['isNullable'] extends true
|
|
28
|
+
? K
|
|
29
|
+
: never;
|
|
30
|
+
}[keyof T['shape']];
|
|
31
|
+
|
|
32
|
+
export type InsertData<
|
|
33
|
+
T extends Query,
|
|
34
|
+
DefaultKeys extends string = T[defaultsKey] extends string
|
|
35
|
+
? T[defaultsKey]
|
|
36
|
+
: never,
|
|
37
|
+
Data = SetOptional<SetOptional<T['inputType'], OptionalKeys<T>>, DefaultKeys>,
|
|
38
|
+
> = [keyof T['relations']] extends [never]
|
|
39
|
+
? Data
|
|
40
|
+
: Omit<
|
|
41
|
+
Data,
|
|
42
|
+
{
|
|
43
|
+
[K in keyof T['relations']]: T['relations'][K] extends BelongsToRelation
|
|
44
|
+
? T['relations'][K]['options']['foreignKey']
|
|
45
|
+
: never;
|
|
46
|
+
}[keyof T['relations']]
|
|
47
|
+
> &
|
|
48
|
+
{
|
|
49
|
+
[Key in keyof T['relations']]: T['relations'][Key] extends BelongsToRelation
|
|
50
|
+
?
|
|
51
|
+
| SetOptional<
|
|
52
|
+
{
|
|
53
|
+
[K in T['relations'][Key]['options']['foreignKey']]: T['relations'][Key]['options']['foreignKey'] extends keyof T['inputType']
|
|
54
|
+
? T['inputType'][T['relations'][Key]['options']['foreignKey']]
|
|
55
|
+
: never;
|
|
56
|
+
},
|
|
57
|
+
DefaultKeys
|
|
58
|
+
>
|
|
59
|
+
| {
|
|
60
|
+
[K in Key]: {
|
|
61
|
+
create?: InsertData<
|
|
62
|
+
T['relations'][Key]['nestedCreateQuery']
|
|
63
|
+
>;
|
|
64
|
+
connect?: WhereArg<T['relations'][Key]['model']>;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
: T['relations'][Key] extends HasOneRelation
|
|
68
|
+
? 'through' extends T['relations'][Key]['options']
|
|
69
|
+
? // eslint-disable-next-line @typescript-eslint/ban-types
|
|
70
|
+
{}
|
|
71
|
+
: {
|
|
72
|
+
[K in Key]?: {
|
|
73
|
+
create?: InsertData<T['relations'][Key]['nestedCreateQuery']>;
|
|
74
|
+
connect?: WhereArg<T['relations'][Key]['model']>;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
: T['relations'][Key] extends Relation
|
|
78
|
+
? 'through' extends T['relations'][Key]['options']
|
|
79
|
+
? // eslint-disable-next-line @typescript-eslint/ban-types
|
|
80
|
+
{}
|
|
81
|
+
: {
|
|
82
|
+
[K in Key]?: {
|
|
83
|
+
create?: InsertData<
|
|
84
|
+
T['relations'][Key]['nestedCreateQuery']
|
|
85
|
+
>[];
|
|
86
|
+
connect?: WhereArg<T['relations'][Key]['model']>[];
|
|
87
|
+
connectOrCreate?: {
|
|
88
|
+
where: WhereArg<T['relations'][Key]['model']>;
|
|
89
|
+
create: InsertData<
|
|
90
|
+
T['relations'][Key]['nestedCreateQuery']
|
|
91
|
+
>;
|
|
92
|
+
}[];
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
: // eslint-disable-next-line @typescript-eslint/ban-types
|
|
96
|
+
{};
|
|
97
|
+
}[keyof T['relations']];
|
|
98
|
+
|
|
99
|
+
type InsertOneResult<T extends Query> = T['hasSelect'] extends false
|
|
100
|
+
? SetQueryReturnsRowCount<T>
|
|
101
|
+
: T['returnType'] extends 'all'
|
|
102
|
+
? SetQueryReturnsOne<T>
|
|
103
|
+
: T['returnType'] extends 'one'
|
|
104
|
+
? SetQueryReturnsOne<T>
|
|
105
|
+
: T;
|
|
106
|
+
|
|
107
|
+
type InsertManyResult<T extends Query> = T['hasSelect'] extends false
|
|
108
|
+
? SetQueryReturnsRowCount<T>
|
|
109
|
+
: T['returnType'] extends 'one' | 'oneOrThrow'
|
|
110
|
+
? SetQueryReturnsAll<T>
|
|
111
|
+
: T;
|
|
112
|
+
|
|
113
|
+
type OnConflictArg<T extends Query> =
|
|
114
|
+
| keyof T['shape']
|
|
115
|
+
| (keyof T['shape'])[]
|
|
116
|
+
| RawExpression;
|
|
117
|
+
|
|
118
|
+
type PrependRelations = Record<
|
|
119
|
+
string,
|
|
120
|
+
[rowIndex: number, columnIndex: number, data: Record<string, unknown>][]
|
|
121
|
+
>;
|
|
122
|
+
|
|
123
|
+
type AppendRelations = Record<
|
|
124
|
+
string,
|
|
125
|
+
[rowIndex: number, data: NestedInsertItem][]
|
|
126
|
+
>;
|
|
127
|
+
|
|
128
|
+
const processInsertItem = (
|
|
129
|
+
item: Record<string, unknown>,
|
|
130
|
+
rowIndex: number,
|
|
131
|
+
relations: Record<string, Relation>,
|
|
132
|
+
prependRelations: PrependRelations,
|
|
133
|
+
appendRelations: AppendRelations,
|
|
134
|
+
requiredReturning: Record<string, boolean>,
|
|
135
|
+
columns: string[],
|
|
136
|
+
columnsMap: Record<string, number>,
|
|
137
|
+
) => {
|
|
138
|
+
Object.keys(item).forEach((key) => {
|
|
139
|
+
if (relations[key]) {
|
|
140
|
+
if (relations[key].type === 'belongsTo') {
|
|
141
|
+
const foreignKey = (relations[key] as BelongsToRelation).options
|
|
142
|
+
.foreignKey;
|
|
143
|
+
|
|
144
|
+
let columnIndex = columnsMap[foreignKey];
|
|
145
|
+
if (columnIndex === undefined) {
|
|
146
|
+
columnsMap[foreignKey] = columnIndex = columns.length;
|
|
147
|
+
columns.push(foreignKey);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!prependRelations[key]) prependRelations[key] = [];
|
|
151
|
+
|
|
152
|
+
prependRelations[key].push([
|
|
153
|
+
rowIndex,
|
|
154
|
+
columnIndex,
|
|
155
|
+
item[key] as Record<string, unknown>,
|
|
156
|
+
]);
|
|
157
|
+
} else {
|
|
158
|
+
requiredReturning[relations[key].primaryKey] = true;
|
|
159
|
+
|
|
160
|
+
if (!appendRelations[key]) appendRelations[key] = [];
|
|
161
|
+
|
|
162
|
+
appendRelations[key].push([rowIndex, item[key] as NestedInsertItem]);
|
|
163
|
+
}
|
|
164
|
+
} else if (columnsMap[key] === undefined) {
|
|
165
|
+
columnsMap[key] = columns.length;
|
|
166
|
+
columns.push(key);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export class Insert {
|
|
172
|
+
insert<T extends Query>(this: T, data: InsertData<T>): InsertOneResult<T>;
|
|
173
|
+
insert<T extends Query>(
|
|
174
|
+
this: T,
|
|
175
|
+
data: InsertData<T>[] | { columns: string[]; values: RawExpression },
|
|
176
|
+
): InsertManyResult<T>;
|
|
177
|
+
insert(this: Query, data: InsertData<Query> & InsertData<Query>[]) {
|
|
178
|
+
return this.clone()._insert(data) as unknown as InsertOneResult<Query> &
|
|
179
|
+
InsertManyResult<Query>;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
_insert<T extends Query>(this: T, data: InsertData<T>): InsertOneResult<T>;
|
|
183
|
+
_insert<T extends Query>(
|
|
184
|
+
this: T,
|
|
185
|
+
data: InsertData<T>[] | { columns: string[]; values: RawExpression },
|
|
186
|
+
): InsertManyResult<T>;
|
|
187
|
+
_insert(
|
|
188
|
+
data:
|
|
189
|
+
| Record<string, unknown>
|
|
190
|
+
| Record<string, unknown>[]
|
|
191
|
+
| { columns: string[]; values: RawExpression },
|
|
192
|
+
) {
|
|
193
|
+
const q = this as unknown as Query & { query: InsertQueryData };
|
|
194
|
+
const returning = q.query.select;
|
|
195
|
+
|
|
196
|
+
delete q.query.and;
|
|
197
|
+
delete q.query.or;
|
|
198
|
+
|
|
199
|
+
let columns: string[];
|
|
200
|
+
const prependRelations: PrependRelations = {};
|
|
201
|
+
const appendRelations: AppendRelations = {};
|
|
202
|
+
const requiredReturning: Record<string, boolean> = {};
|
|
203
|
+
const relations = (this as unknown as Query).relations as unknown as Record<
|
|
204
|
+
string,
|
|
205
|
+
Relation
|
|
206
|
+
>;
|
|
207
|
+
let values: unknown[][] | RawExpression;
|
|
208
|
+
|
|
209
|
+
let returnType = q.query.returnType;
|
|
210
|
+
if (returning) {
|
|
211
|
+
if (Array.isArray(data)) {
|
|
212
|
+
if (returnType === 'one' || returnType === 'oneOrThrow') {
|
|
213
|
+
returnType = 'all';
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
if (returnType === 'all') {
|
|
217
|
+
returnType = 'one';
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
returnType = 'rowCount';
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (
|
|
225
|
+
'values' in data &&
|
|
226
|
+
typeof data.values === 'object' &&
|
|
227
|
+
data.values &&
|
|
228
|
+
isRaw(data.values)
|
|
229
|
+
) {
|
|
230
|
+
columns = (data as { columns: string[] }).columns;
|
|
231
|
+
values = data.values;
|
|
232
|
+
} else {
|
|
233
|
+
columns = [];
|
|
234
|
+
const columnsMap: Record<string, number> = {};
|
|
235
|
+
const defaults = q.query.defaults;
|
|
236
|
+
|
|
237
|
+
if (Array.isArray(data)) {
|
|
238
|
+
if (defaults) {
|
|
239
|
+
data = data.map((item) => ({ ...defaults, ...item }));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
data.forEach((item, i) => {
|
|
243
|
+
processInsertItem(
|
|
244
|
+
item,
|
|
245
|
+
i,
|
|
246
|
+
relations,
|
|
247
|
+
prependRelations,
|
|
248
|
+
appendRelations,
|
|
249
|
+
requiredReturning,
|
|
250
|
+
columns,
|
|
251
|
+
columnsMap,
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
values = Array(data.length);
|
|
256
|
+
|
|
257
|
+
data.forEach((item, i) => {
|
|
258
|
+
(values as unknown[][])[i] = columns.map((key) => item[key]);
|
|
259
|
+
});
|
|
260
|
+
} else {
|
|
261
|
+
if (defaults) {
|
|
262
|
+
data = { ...defaults, ...data };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
processInsertItem(
|
|
266
|
+
data,
|
|
267
|
+
0,
|
|
268
|
+
relations,
|
|
269
|
+
prependRelations,
|
|
270
|
+
appendRelations,
|
|
271
|
+
requiredReturning,
|
|
272
|
+
columns,
|
|
273
|
+
columnsMap,
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
values = [columns.map((key) => (data as Record<string, unknown>)[key])];
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const prependRelationsKeys = Object.keys(prependRelations);
|
|
281
|
+
if (prependRelationsKeys.length) {
|
|
282
|
+
pushQueryArray(
|
|
283
|
+
q,
|
|
284
|
+
'beforeQuery',
|
|
285
|
+
prependRelationsKeys.map((relationName) => {
|
|
286
|
+
return async (q: Query) => {
|
|
287
|
+
const relationData = prependRelations[relationName];
|
|
288
|
+
const relation = relations[relationName];
|
|
289
|
+
|
|
290
|
+
const inserted = await (
|
|
291
|
+
relation.nestedInsert as BelongsToNestedInsert
|
|
292
|
+
)(
|
|
293
|
+
q,
|
|
294
|
+
relationData.map(([, , data]) => data as NestedInsertOneItem),
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
const primaryKey = (relation as BelongsToRelation).options
|
|
298
|
+
.primaryKey;
|
|
299
|
+
relationData.forEach(([rowIndex, columnIndex], index) => {
|
|
300
|
+
(values as unknown[][])[rowIndex][columnIndex] =
|
|
301
|
+
inserted[index][primaryKey];
|
|
302
|
+
});
|
|
303
|
+
};
|
|
304
|
+
}),
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const appendRelationsKeys = Object.keys(appendRelations);
|
|
309
|
+
if (appendRelationsKeys.length) {
|
|
310
|
+
if (!returning?.includes('*')) {
|
|
311
|
+
const requiredColumns = Object.keys(requiredReturning);
|
|
312
|
+
|
|
313
|
+
if (!returning) {
|
|
314
|
+
q.query.select = requiredColumns;
|
|
315
|
+
} else {
|
|
316
|
+
q.query.select = [
|
|
317
|
+
...new Set([...(returning as string[]), ...requiredColumns]),
|
|
318
|
+
];
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
let resultOfTypeAll: Record<string, unknown>[] | undefined;
|
|
323
|
+
if (returnType !== 'all') {
|
|
324
|
+
const { handleResult } = q.query;
|
|
325
|
+
q.query.handleResult = async (q, queryResult) => {
|
|
326
|
+
resultOfTypeAll = (await handleResult(q, queryResult)) as Record<
|
|
327
|
+
string,
|
|
328
|
+
unknown
|
|
329
|
+
>[];
|
|
330
|
+
|
|
331
|
+
if (queryMethodByReturnType[returnType] === 'arrays') {
|
|
332
|
+
queryResult.rows.forEach(
|
|
333
|
+
(row, i) =>
|
|
334
|
+
((queryResult.rows as unknown as unknown[][])[i] =
|
|
335
|
+
Object.values(row)),
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return parseResult(q, returnType, queryResult);
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
pushQueryArray(
|
|
344
|
+
q,
|
|
345
|
+
'afterQuery',
|
|
346
|
+
appendRelationsKeys.map((relationName) => {
|
|
347
|
+
return (q: Query, result: Record<string, unknown>[]) => {
|
|
348
|
+
const all = resultOfTypeAll || result;
|
|
349
|
+
return (
|
|
350
|
+
relations[relationName].nestedInsert as HasOneNestedInsert
|
|
351
|
+
)?.(
|
|
352
|
+
q,
|
|
353
|
+
appendRelations[relationName].map(([rowIndex, data]) => [
|
|
354
|
+
all[rowIndex],
|
|
355
|
+
data as NestedInsertOneItem,
|
|
356
|
+
]),
|
|
357
|
+
);
|
|
358
|
+
};
|
|
359
|
+
}),
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
q.query.type = 'insert';
|
|
364
|
+
q.query.columns = columns;
|
|
365
|
+
q.query.values = values;
|
|
366
|
+
if (prependRelationsKeys.length || appendRelationsKeys.length) {
|
|
367
|
+
q.query.wrapInTransaction = true;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
q.query.returnType = appendRelationsKeys.length ? 'all' : returnType;
|
|
371
|
+
|
|
372
|
+
return q as unknown as InsertOneResult<Query> & InsertManyResult<Query>;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
create<T extends Query>(this: T, data: InsertData<T>): SetQueryReturnsOne<T>;
|
|
376
|
+
create<T extends Query>(
|
|
377
|
+
this: T,
|
|
378
|
+
data: InsertData<T>[] | { columns: string[]; values: RawExpression },
|
|
379
|
+
): SetQueryReturnsAll<T>;
|
|
380
|
+
create(this: Query, data: InsertData<Query> & InsertData<Query>[]) {
|
|
381
|
+
return this.clone()._create(data) as unknown as SetQueryReturnsOne<Query> &
|
|
382
|
+
SetQueryReturnsAll<Query>;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
_create<T extends Query>(this: T, data: InsertData<T>): SetQueryReturnsOne<T>;
|
|
386
|
+
_create<T extends Query>(
|
|
387
|
+
this: T,
|
|
388
|
+
data: InsertData<T>[] | { columns: string[]; values: RawExpression },
|
|
389
|
+
): SetQueryReturnsAll<T>;
|
|
390
|
+
_create(this: Query, data: InsertData<Query> & InsertData<Query>[]) {
|
|
391
|
+
if (!this.query.select) {
|
|
392
|
+
this.query.select = ['*'];
|
|
393
|
+
}
|
|
394
|
+
return this.insert(data) as unknown as never;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
defaults<T extends Query, Data extends Partial<InsertData<T>>>(
|
|
398
|
+
this: T,
|
|
399
|
+
data: Data,
|
|
400
|
+
): T & { [defaultsKey]: keyof Data } {
|
|
401
|
+
return (this.clone() as T)._defaults(data);
|
|
402
|
+
}
|
|
403
|
+
_defaults<T extends Query, Data extends Partial<InsertData<T>>>(
|
|
404
|
+
this: T,
|
|
405
|
+
data: Data,
|
|
406
|
+
): T & { [defaultsKey]: keyof Data } {
|
|
407
|
+
this.query.defaults = data;
|
|
408
|
+
return this as T & { [defaultsKey]: keyof Data };
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
onConflict<T extends Query, Arg extends OnConflictArg<T>>(
|
|
412
|
+
this: T,
|
|
413
|
+
arg?: Arg,
|
|
414
|
+
): OnConflictQueryBuilder<T, Arg> {
|
|
415
|
+
return this.clone()._onConflict(arg);
|
|
416
|
+
}
|
|
417
|
+
_onConflict<
|
|
418
|
+
T extends Query,
|
|
419
|
+
Arg extends OnConflictArg<T> | undefined = undefined,
|
|
420
|
+
>(this: T, arg?: Arg): OnConflictQueryBuilder<T, Arg> {
|
|
421
|
+
return new OnConflictQueryBuilder(this, arg as Arg);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export class OnConflictQueryBuilder<
|
|
426
|
+
T extends Query,
|
|
427
|
+
Arg extends OnConflictArg<T> | undefined,
|
|
428
|
+
> {
|
|
429
|
+
constructor(private query: T, private onConflict: Arg) {}
|
|
430
|
+
|
|
431
|
+
ignore(): T {
|
|
432
|
+
(this.query.query as InsertQueryData).onConflict = {
|
|
433
|
+
type: 'ignore',
|
|
434
|
+
expr: this.onConflict as OnConflictItem,
|
|
435
|
+
};
|
|
436
|
+
return this.query;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
merge(
|
|
440
|
+
update?:
|
|
441
|
+
| keyof T['shape']
|
|
442
|
+
| (keyof T['shape'])[]
|
|
443
|
+
| Partial<T['inputType']>
|
|
444
|
+
| RawExpression,
|
|
445
|
+
): T {
|
|
446
|
+
(this.query.query as InsertQueryData).onConflict = {
|
|
447
|
+
type: 'merge',
|
|
448
|
+
expr: this.onConflict as OnConflictItem,
|
|
449
|
+
update: update as OnConflictMergeUpdate,
|
|
450
|
+
};
|
|
451
|
+
return this.query;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { expectQueryNotMutated, expectSql, Message, User } from '../test-utils';
|
|
2
|
+
import { OnQueryBuilder } from './join';
|
|
3
|
+
import { testJoin, testWhere } from './where.test';
|
|
4
|
+
import { Sql } from '../sql';
|
|
5
|
+
import { Query } from '../query';
|
|
6
|
+
|
|
7
|
+
describe.each`
|
|
8
|
+
method | sql
|
|
9
|
+
${'join'} | ${'JOIN'}
|
|
10
|
+
${'innerJoin'} | ${'INNER JOIN'}
|
|
11
|
+
${'leftJoin'} | ${'LEFT JOIN'}
|
|
12
|
+
${'leftOuterJoin'} | ${'LEFT OUTER JOIN'}
|
|
13
|
+
${'rightJoin'} | ${'RIGHT JOIN'}
|
|
14
|
+
${'rightOuterJoin'} | ${'RIGHT OUTER JOIN'}
|
|
15
|
+
${'fullOuterJoin'} | ${'FULL OUTER JOIN'}
|
|
16
|
+
`('$method', ({ method, sql }) => {
|
|
17
|
+
testJoin(
|
|
18
|
+
method,
|
|
19
|
+
(target: string, conditions: string) => `
|
|
20
|
+
SELECT "user".* FROM "user"
|
|
21
|
+
${sql} ${target} ON ${conditions}
|
|
22
|
+
`,
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('join callback with query builder', () => {
|
|
27
|
+
it('should have .on and .onOr properly working', () => {
|
|
28
|
+
const q = User.all();
|
|
29
|
+
|
|
30
|
+
const expectedSql = `
|
|
31
|
+
SELECT "user".* FROM "user"
|
|
32
|
+
JOIN "message"
|
|
33
|
+
ON "message"."authorId" = "user"."id"
|
|
34
|
+
OR "message"."text" = "user"."name"
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
expectSql(
|
|
38
|
+
q
|
|
39
|
+
.join(Message, (q) =>
|
|
40
|
+
q.on('message.authorId', 'user.id').orOn('message.text', 'user.name'),
|
|
41
|
+
)
|
|
42
|
+
.toSql(),
|
|
43
|
+
expectedSql,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
expectSql(
|
|
47
|
+
q
|
|
48
|
+
.join(Message, (q) =>
|
|
49
|
+
q
|
|
50
|
+
.on('message.authorId', '=', 'user.id')
|
|
51
|
+
.orOn('message.text', '=', 'user.name'),
|
|
52
|
+
)
|
|
53
|
+
.toSql(),
|
|
54
|
+
expectedSql,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
expectQueryNotMutated(q);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should have .onJsonPathEquals method', () => {
|
|
61
|
+
const q = User.all();
|
|
62
|
+
|
|
63
|
+
expectSql(
|
|
64
|
+
q
|
|
65
|
+
.join(User.as('otherUser'), (q) =>
|
|
66
|
+
q.onJsonPathEquals('user.data', '$.name', 'otherUser.data', '$.name'),
|
|
67
|
+
)
|
|
68
|
+
.toSql(),
|
|
69
|
+
`
|
|
70
|
+
SELECT "user".* FROM "user"
|
|
71
|
+
JOIN "user" AS "otherUser"
|
|
72
|
+
ON jsonb_path_query_first("user"."data", $1) = jsonb_path_query_first("otherUser"."data", $2)
|
|
73
|
+
`,
|
|
74
|
+
['$.name', '$.name'],
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('where methods', () => {
|
|
79
|
+
describe('and', () => {
|
|
80
|
+
let query: OnQueryBuilder;
|
|
81
|
+
let where: OnQueryBuilder['where'];
|
|
82
|
+
let _where: OnQueryBuilder['_where'];
|
|
83
|
+
User.join(Message, (q) => {
|
|
84
|
+
query = q;
|
|
85
|
+
where = q.where;
|
|
86
|
+
_where = q._where;
|
|
87
|
+
return q;
|
|
88
|
+
}).toSql();
|
|
89
|
+
beforeEach(() => {
|
|
90
|
+
query.where = jest.fn();
|
|
91
|
+
query._where = jest.fn();
|
|
92
|
+
});
|
|
93
|
+
afterAll(() => {
|
|
94
|
+
query.where = where;
|
|
95
|
+
query._where = _where;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('is alias for where', () => {
|
|
99
|
+
query.and({});
|
|
100
|
+
expect(query.where).toBeCalled();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('has modifier', () => {
|
|
104
|
+
query._and({});
|
|
105
|
+
expect(query._where).toBeCalled();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('andNot', () => {
|
|
110
|
+
let query: OnQueryBuilder;
|
|
111
|
+
let whereNot: OnQueryBuilder['whereNot'];
|
|
112
|
+
let _whereNot: OnQueryBuilder['_whereNot'];
|
|
113
|
+
User.join(Message, (q) => {
|
|
114
|
+
query = q;
|
|
115
|
+
whereNot = q.whereNot;
|
|
116
|
+
_whereNot = q._whereNot;
|
|
117
|
+
return q;
|
|
118
|
+
}).toSql();
|
|
119
|
+
beforeEach(() => {
|
|
120
|
+
query.whereNot = jest.fn();
|
|
121
|
+
query._whereNot = jest.fn();
|
|
122
|
+
});
|
|
123
|
+
afterAll(() => {
|
|
124
|
+
query.whereNot = whereNot;
|
|
125
|
+
query._whereNot = _whereNot;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('is alias for where', () => {
|
|
129
|
+
query.andNot({});
|
|
130
|
+
expect(query.whereNot).toBeCalled();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('has modifier', () => {
|
|
134
|
+
query._andNot({});
|
|
135
|
+
expect(query._whereNot).toBeCalled();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const buildSql = (cb: (q: OnQueryBuilder) => OnQueryBuilder): Sql => {
|
|
140
|
+
return User.join(Message, cb).toSql();
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const startSql = `SELECT "user".* FROM "user" JOIN "message" ON`;
|
|
144
|
+
|
|
145
|
+
testWhere(
|
|
146
|
+
buildSql as unknown as (cb: (q: Query) => Query) => Sql,
|
|
147
|
+
startSql,
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
});
|