pqb 0.3.0 → 0.3.2
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 +57 -37
- package/dist/index.esm.js +3746 -3663
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +3750 -3662
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/columnSchema/columnType.ts +25 -21
- package/src/columnSchema/columnTypes.ts +2 -12
- package/src/columnSchema/timestamps.test.ts +79 -0
- package/src/columnSchema/timestamps.ts +49 -0
- package/src/columnsOperators.ts +1 -1
- package/src/common.ts +5 -1
- package/src/db.ts +20 -9
- package/src/queryDataUtils.ts +7 -4
- package/src/queryMethods/aggregate.test.ts +3 -3
- package/src/queryMethods/callbacks.test.ts +20 -0
- package/src/queryMethods/callbacks.ts +16 -2
- package/src/queryMethods/clear.test.ts +1 -1
- package/src/queryMethods/clear.ts +2 -2
- package/src/queryMethods/having.test.ts +1 -1
- package/src/queryMethods/queryMethods.test.ts +1 -1
- package/src/queryMethods/queryMethods.ts +3 -2
- package/src/queryMethods/then.ts +24 -16
- package/src/queryMethods/union.test.ts +1 -1
- package/src/queryMethods/update.test.ts +33 -18
- package/src/queryMethods/update.ts +152 -132
- package/src/queryMethods/window.test.ts +1 -1
- package/src/sql/fromAndAs.ts +2 -2
- package/src/sql/select.ts +1 -1
- package/src/sql/toSql.ts +17 -2
- package/src/sql/types.ts +25 -10
- package/src/sql/update.ts +27 -8
- package/src/sql/where.ts +1 -1
- package/src/sql/with.ts +1 -1
- package/src/utils.test.ts +76 -2
- package/src/utils.ts +32 -2
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ import { JSONTypeAny } from './json/typeBase';
|
|
|
3
3
|
import { ColumnsShape } from './columnsSchema';
|
|
4
4
|
import { RawExpression, StringKey } from '../common';
|
|
5
5
|
import { MaybeArray } from '../utils';
|
|
6
|
+
import { Query } from '../query';
|
|
6
7
|
|
|
7
8
|
export type ColumnOutput<T extends ColumnType> = T['type'];
|
|
8
9
|
|
|
@@ -44,6 +45,7 @@ export type ColumnData = {
|
|
|
44
45
|
collate?: string;
|
|
45
46
|
compression?: string;
|
|
46
47
|
foreignKey?: ForeignKey<string, string[]>;
|
|
48
|
+
modifyQuery?: (q: Query) => void;
|
|
47
49
|
};
|
|
48
50
|
|
|
49
51
|
type ForeignKeyMatch = 'FULL' | 'PARTIAL' | 'SIMPLE';
|
|
@@ -109,6 +111,16 @@ export type ForeignKeyModelWithColumns = new () => {
|
|
|
109
111
|
export type ColumnNameOfModel<Model extends ForeignKeyModelWithColumns> =
|
|
110
112
|
StringKey<keyof InstanceType<Model>['columns']['shape']>;
|
|
111
113
|
|
|
114
|
+
const addColumnData = <T extends ColumnType, K extends keyof ColumnData>(
|
|
115
|
+
q: T,
|
|
116
|
+
key: K,
|
|
117
|
+
value: T['data'][K],
|
|
118
|
+
): T => {
|
|
119
|
+
const cloned = Object.create(q);
|
|
120
|
+
cloned.data = { ...q.data, [key]: value };
|
|
121
|
+
return cloned;
|
|
122
|
+
};
|
|
123
|
+
|
|
112
124
|
export abstract class ColumnType<
|
|
113
125
|
Type = unknown,
|
|
114
126
|
Ops extends Operators = Operators,
|
|
@@ -217,51 +229,43 @@ export abstract class ColumnType<
|
|
|
217
229
|
this: T,
|
|
218
230
|
value: T['type'] | RawExpression,
|
|
219
231
|
): T & { hasDefault: true } {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
232
|
+
return addColumnData(this, 'default', value as unknown) as T & {
|
|
233
|
+
hasDefault: true;
|
|
234
|
+
};
|
|
223
235
|
}
|
|
224
236
|
|
|
225
237
|
index<T extends ColumnType>(
|
|
226
238
|
this: T,
|
|
227
239
|
options: Omit<SingleColumnIndexOptions, 'column'> = {},
|
|
228
240
|
): T {
|
|
229
|
-
|
|
230
|
-
cloned.data = { ...cloned.data, index: options };
|
|
231
|
-
return cloned;
|
|
241
|
+
return addColumnData(this, 'index', options);
|
|
232
242
|
}
|
|
233
243
|
|
|
234
244
|
unique<T extends ColumnType>(
|
|
235
245
|
this: T,
|
|
236
246
|
options: Omit<SingleColumnIndexOptions, 'column' | 'unique'> = {},
|
|
237
247
|
): T {
|
|
238
|
-
|
|
239
|
-
cloned.data = { ...cloned.data, index: { ...options, unique: true } };
|
|
240
|
-
return cloned;
|
|
248
|
+
return addColumnData(this, 'index', { ...options, unique: true });
|
|
241
249
|
}
|
|
242
250
|
|
|
243
251
|
comment<T extends ColumnType>(this: T, comment: string): T {
|
|
244
|
-
|
|
245
|
-
cloned.data = { ...cloned.data, comment };
|
|
246
|
-
return cloned;
|
|
252
|
+
return addColumnData(this, 'comment', comment);
|
|
247
253
|
}
|
|
248
254
|
|
|
249
255
|
validationDefault<T extends ColumnType>(this: T, value: T['type']): T {
|
|
250
|
-
|
|
251
|
-
cloned.data = { ...cloned.data, validationDefault: value };
|
|
252
|
-
return cloned;
|
|
256
|
+
return addColumnData(this, 'validationDefault', value as unknown);
|
|
253
257
|
}
|
|
254
258
|
|
|
255
259
|
compression<T extends ColumnType>(this: T, compression: string): T {
|
|
256
|
-
|
|
257
|
-
cloned.data = { ...cloned.data, compression };
|
|
258
|
-
return cloned;
|
|
260
|
+
return addColumnData(this, 'compression', compression);
|
|
259
261
|
}
|
|
260
262
|
|
|
261
263
|
collate<T extends ColumnType>(this: T, collate: string): T {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
264
|
+
return addColumnData(this, 'collate', collate);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
modifyQuery<T extends ColumnType>(this: T, cb: (q: Query) => void): T {
|
|
268
|
+
return addColumnData(this, 'modifyQuery', cb);
|
|
265
269
|
}
|
|
266
270
|
|
|
267
271
|
transform<T extends ColumnType, Transformed>(
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
} from './columnType';
|
|
59
59
|
import { emptyObject, EmptyObject, MaybeArray, toArray } from '../utils';
|
|
60
60
|
import { ColumnsShape } from './columnsSchema';
|
|
61
|
-
import {
|
|
61
|
+
import { timestamps } from './timestamps';
|
|
62
62
|
|
|
63
63
|
export type ColumnTypes = typeof columnTypes;
|
|
64
64
|
|
|
@@ -177,17 +177,7 @@ export const columnTypes = {
|
|
|
177
177
|
jsonText: () => new JSONTextColumn(),
|
|
178
178
|
array: <Item extends ColumnType>(item: Item) => new ArrayColumn(item),
|
|
179
179
|
|
|
180
|
-
timestamps
|
|
181
|
-
timestamp(): T;
|
|
182
|
-
}): {
|
|
183
|
-
createdAt: T & { hasDefault: true };
|
|
184
|
-
updatedAt: T & { hasDefault: true };
|
|
185
|
-
} {
|
|
186
|
-
return {
|
|
187
|
-
createdAt: this.timestamp().default(raw('now()')),
|
|
188
|
-
updatedAt: this.timestamp().default(raw('now()')),
|
|
189
|
-
};
|
|
190
|
-
},
|
|
180
|
+
timestamps,
|
|
191
181
|
|
|
192
182
|
primaryKey(columns: string[], options?: { name?: string }) {
|
|
193
183
|
tableData.primaryKey = { columns, options };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { db, expectSql, now, useTestDatabase } from '../test-utils';
|
|
2
|
+
import { raw } from '../common';
|
|
3
|
+
|
|
4
|
+
describe('timestamps', () => {
|
|
5
|
+
useTestDatabase();
|
|
6
|
+
|
|
7
|
+
const model = db('user', (t) => ({
|
|
8
|
+
name: t.string(),
|
|
9
|
+
...t.timestamps(),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
it('should update updatedAt column when updating', async () => {
|
|
13
|
+
const query = model.update({}, true);
|
|
14
|
+
await query;
|
|
15
|
+
|
|
16
|
+
expectSql(
|
|
17
|
+
query.toSql(),
|
|
18
|
+
`
|
|
19
|
+
UPDATE "user"
|
|
20
|
+
SET "updatedAt" = now()
|
|
21
|
+
`,
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should not update updatedAt column when updating it via object', async () => {
|
|
26
|
+
const query = model.update({ updatedAt: now }, true);
|
|
27
|
+
await query;
|
|
28
|
+
|
|
29
|
+
expectSql(
|
|
30
|
+
query.toSql(),
|
|
31
|
+
`
|
|
32
|
+
UPDATE "user"
|
|
33
|
+
SET "updatedAt" = $1
|
|
34
|
+
`,
|
|
35
|
+
[now],
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should update updatedAt when updating with raw sql', async () => {
|
|
40
|
+
const query = model.updateRaw(raw('name = $1', 'name'), true);
|
|
41
|
+
await query;
|
|
42
|
+
|
|
43
|
+
expectSql(
|
|
44
|
+
query.toSql(),
|
|
45
|
+
`
|
|
46
|
+
UPDATE "user"
|
|
47
|
+
SET name = $1, "updatedAt" = now()
|
|
48
|
+
`,
|
|
49
|
+
['name'],
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should update updatedAt when updating with raw sql which has updatedAt somewhere but not in set', async () => {
|
|
54
|
+
const query = model.updateRaw(raw('"createdAt" = "updatedAt"'), true);
|
|
55
|
+
await query;
|
|
56
|
+
|
|
57
|
+
expectSql(
|
|
58
|
+
query.toSql(),
|
|
59
|
+
`
|
|
60
|
+
UPDATE "user"
|
|
61
|
+
SET "createdAt" = "updatedAt", "updatedAt" = now()
|
|
62
|
+
`,
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should not update updatedAt column when updating with raw sql which contains `updatedAt = `', async () => {
|
|
67
|
+
const query = model.updateRaw(raw('"updatedAt" = $1', now), true);
|
|
68
|
+
await query;
|
|
69
|
+
|
|
70
|
+
expectSql(
|
|
71
|
+
query.toSql(),
|
|
72
|
+
`
|
|
73
|
+
UPDATE "user"
|
|
74
|
+
SET "updatedAt" = $1
|
|
75
|
+
`,
|
|
76
|
+
[now],
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ColumnType } from './columnType';
|
|
2
|
+
import { getRawSql, isRaw, raw } from '../common';
|
|
3
|
+
import { Query } from '../query';
|
|
4
|
+
import { makeRegexToFindInSql, pushOrNewArrayToObject } from '../utils';
|
|
5
|
+
import {
|
|
6
|
+
UpdatedAtDataInjector,
|
|
7
|
+
UpdateQueryData,
|
|
8
|
+
UpdateQueryDataItem,
|
|
9
|
+
} from '../sql';
|
|
10
|
+
|
|
11
|
+
export function timestamps<T extends ColumnType>(this: {
|
|
12
|
+
timestamp(): T;
|
|
13
|
+
}): {
|
|
14
|
+
createdAt: T & { hasDefault: true };
|
|
15
|
+
updatedAt: T & { hasDefault: true };
|
|
16
|
+
} {
|
|
17
|
+
return {
|
|
18
|
+
createdAt: this.timestamp().default(raw('now()')),
|
|
19
|
+
updatedAt: this.timestamp()
|
|
20
|
+
.default(raw('now()'))
|
|
21
|
+
.modifyQuery(addHookForUpdate),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const updatedAtRegex = makeRegexToFindInSql('\\bupdatedAt\\b"?\\s*=');
|
|
26
|
+
const updateUpdatedAtItem = raw('"updatedAt" = now()');
|
|
27
|
+
|
|
28
|
+
const addHookForUpdate = (q: Query) => {
|
|
29
|
+
pushOrNewArrayToObject(
|
|
30
|
+
q.query as UpdateQueryData,
|
|
31
|
+
'updateData',
|
|
32
|
+
updatedAtInjector,
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const updatedAtInjector: UpdatedAtDataInjector = (data) => {
|
|
37
|
+
return checkIfDataHasUpdatedAt(data) ? undefined : updateUpdatedAtItem;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const checkIfDataHasUpdatedAt = (data: UpdateQueryDataItem[]) => {
|
|
41
|
+
return data.some((item) => {
|
|
42
|
+
if (isRaw(item)) {
|
|
43
|
+
updatedAtRegex.lastIndex = 0;
|
|
44
|
+
return updatedAtRegex.test(getRawSql(item));
|
|
45
|
+
} else {
|
|
46
|
+
return typeof item !== 'function' && item.updatedAt;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
};
|
package/src/columnsOperators.ts
CHANGED
package/src/common.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Query, Selectable } from './query';
|
|
2
|
-
import { ColumnOutput, ColumnType } from './columnSchema';
|
|
2
|
+
import { ColumnOutput, ColumnType } from './columnSchema/columnType';
|
|
3
3
|
|
|
4
4
|
export type AliasOrTable<T extends Pick<Query, 'tableAlias' | 'table'>> =
|
|
5
5
|
T['tableAlias'] extends string
|
|
@@ -81,6 +81,10 @@ export const getRaw = (raw: RawExpression, values: unknown[]) => {
|
|
|
81
81
|
return raw.__raw;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
export const getRawSql = (raw: RawExpression) => {
|
|
85
|
+
return raw.__raw;
|
|
86
|
+
};
|
|
87
|
+
|
|
84
88
|
export const EMPTY_OBJECT = {};
|
|
85
89
|
|
|
86
90
|
export const getQueryParsers = (q: Query) => {
|
package/src/db.ts
CHANGED
|
@@ -4,8 +4,16 @@ import {
|
|
|
4
4
|
defaultsKey,
|
|
5
5
|
Query,
|
|
6
6
|
} from './query';
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
QueryMethods,
|
|
9
|
+
handleResult,
|
|
10
|
+
ThenResult,
|
|
11
|
+
WhereQueryBuilder,
|
|
12
|
+
OnQueryBuilder,
|
|
13
|
+
logParamToLogObject,
|
|
14
|
+
QueryLogOptions,
|
|
15
|
+
} from './queryMethods';
|
|
16
|
+
import { QueryData, SelectQueryData, Sql, ToSqlOptions } from './sql';
|
|
9
17
|
import { AdapterOptions, Adapter } from './adapter';
|
|
10
18
|
import {
|
|
11
19
|
ColumnsShape,
|
|
@@ -17,12 +25,8 @@ import {
|
|
|
17
25
|
ColumnTypesBase,
|
|
18
26
|
getColumnTypes,
|
|
19
27
|
} from './columnSchema';
|
|
20
|
-
import { applyMixins } from './utils';
|
|
28
|
+
import { applyMixins, pushOrNewArray } from './utils';
|
|
21
29
|
import { StringKey } from './common';
|
|
22
|
-
import { handleResult, ThenResult } from './queryMethods/then';
|
|
23
|
-
import { WhereQueryBuilder } from './queryMethods/where';
|
|
24
|
-
import { OnQueryBuilder } from './queryMethods/join';
|
|
25
|
-
import { logParamToLogObject, QueryLogOptions } from './queryMethods/log';
|
|
26
30
|
|
|
27
31
|
export type DbTableOptions = {
|
|
28
32
|
schema?: string;
|
|
@@ -128,26 +132,33 @@ export class Db<
|
|
|
128
132
|
|
|
129
133
|
const columnsParsers = {} as ColumnsParsers;
|
|
130
134
|
let hasParsers = false;
|
|
135
|
+
let modifyQuery: ((q: Query) => void)[] | undefined;
|
|
131
136
|
for (const key in shape) {
|
|
132
137
|
const column = shape[key];
|
|
133
138
|
if (column.parseFn) {
|
|
134
139
|
hasParsers = true;
|
|
135
140
|
columnsParsers[key] = column.parseFn;
|
|
136
141
|
}
|
|
142
|
+
|
|
143
|
+
if (column.data.modifyQuery) {
|
|
144
|
+
modifyQuery = pushOrNewArray(modifyQuery, column.data.modifyQuery);
|
|
145
|
+
}
|
|
137
146
|
}
|
|
138
147
|
this.columnsParsers = hasParsers ? columnsParsers : undefined;
|
|
139
148
|
|
|
140
149
|
this.toSql = defaultSelect
|
|
141
|
-
? function <T extends Query>(this: T,
|
|
150
|
+
? function <T extends Query>(this: T, options?: ToSqlOptions): Sql {
|
|
142
151
|
const q = this.clone();
|
|
143
152
|
if (!(q.query as SelectQueryData).select) {
|
|
144
153
|
(q.query as SelectQueryData).select = defaultSelect as string[];
|
|
145
154
|
}
|
|
146
|
-
return toSql.call(q,
|
|
155
|
+
return toSql.call(q, options);
|
|
147
156
|
}
|
|
148
157
|
: toSql;
|
|
149
158
|
|
|
150
159
|
this.relations = {} as Relations;
|
|
160
|
+
|
|
161
|
+
modifyQuery?.forEach((cb) => cb(this));
|
|
151
162
|
}
|
|
152
163
|
}
|
|
153
164
|
|
package/src/queryDataUtils.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Query } from './query';
|
|
2
2
|
import { QueryData } from './sql';
|
|
3
|
+
import { pushOrNewArrayToObject } from './utils';
|
|
3
4
|
|
|
4
5
|
// TODO: remove
|
|
5
6
|
export const removeFromQuery = <T extends Query>(q: T, key: string): T => {
|
|
@@ -26,10 +27,12 @@ export const pushQueryValue = <T extends { query: QueryData }>(
|
|
|
26
27
|
key: string,
|
|
27
28
|
value: unknown,
|
|
28
29
|
): T => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
pushOrNewArrayToObject(
|
|
31
|
+
q.query as unknown as Record<string, unknown[]>,
|
|
32
|
+
key,
|
|
33
|
+
value,
|
|
34
|
+
);
|
|
35
|
+
return q;
|
|
33
36
|
};
|
|
34
37
|
|
|
35
38
|
export const setQueryObjectValue = <T extends { query: QueryData }>(
|
|
@@ -351,7 +351,7 @@ describe('aggregate', () => {
|
|
|
351
351
|
expectQueryNotMutated(q);
|
|
352
352
|
|
|
353
353
|
q[`_${method}` as `_count`]('name');
|
|
354
|
-
expectSql(q.toSql(), expectedSql);
|
|
354
|
+
expectSql(q.toSql({ clearCache: true }), expectedSql);
|
|
355
355
|
});
|
|
356
356
|
|
|
357
357
|
it('should support raw sql parameter', () => {
|
|
@@ -449,7 +449,7 @@ describe('aggregate', () => {
|
|
|
449
449
|
expectQueryNotMutated(q);
|
|
450
450
|
|
|
451
451
|
q[`_${method}` as '_jsonObjectAgg']({ alias: 'name' });
|
|
452
|
-
expectSql(q.toSql(), expectedSql, ['alias']);
|
|
452
|
+
expectSql(q.toSql({ clearCache: true }), expectedSql, ['alias']);
|
|
453
453
|
});
|
|
454
454
|
|
|
455
455
|
it('should support raw sql parameter', () => {
|
|
@@ -545,7 +545,7 @@ describe('aggregate', () => {
|
|
|
545
545
|
expectQueryNotMutated(q);
|
|
546
546
|
|
|
547
547
|
q._stringAgg('name', ' & ');
|
|
548
|
-
expectSql(q.toSql(), expectedSql, [' & ']);
|
|
548
|
+
expectSql(q.toSql({ clearCache: true }), expectedSql, [' & ']);
|
|
549
549
|
});
|
|
550
550
|
|
|
551
551
|
it('should support raw sql parameter', async () => {
|
|
@@ -66,4 +66,24 @@ describe('callbacks', () => {
|
|
|
66
66
|
expect(fn.mock.calls[0]).toEqual([query, result]);
|
|
67
67
|
});
|
|
68
68
|
});
|
|
69
|
+
|
|
70
|
+
describe('beforeDelete', () => {
|
|
71
|
+
it('should run callback before delete', async () => {
|
|
72
|
+
const fn = jest.fn();
|
|
73
|
+
const query = User.beforeDelete(fn).where({ id: 1 }).delete();
|
|
74
|
+
await query;
|
|
75
|
+
|
|
76
|
+
expect(fn.mock.calls[0]).toEqual([query]);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('afterDelete', () => {
|
|
81
|
+
it('should run callback after delete', async () => {
|
|
82
|
+
const fn = jest.fn();
|
|
83
|
+
const query = User.afterDelete(fn).where({ id: 1 }).delete();
|
|
84
|
+
const result = await query;
|
|
85
|
+
|
|
86
|
+
expect(fn.mock.calls[0]).toEqual([query, result]);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
69
89
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Query } from '../query';
|
|
2
2
|
import { pushQueryValue } from '../queryDataUtils';
|
|
3
3
|
|
|
4
|
-
export type BeforeCallback<T extends Query> = (
|
|
4
|
+
export type BeforeCallback<T extends Query = Query> = (
|
|
5
5
|
query: T,
|
|
6
6
|
) => void | Promise<void>;
|
|
7
7
|
|
|
8
|
-
export type AfterCallback<T extends Query> = (
|
|
8
|
+
export type AfterCallback<T extends Query = Query> = (
|
|
9
9
|
query: T,
|
|
10
10
|
data: unknown,
|
|
11
11
|
) => void | Promise<void>;
|
|
@@ -52,4 +52,18 @@ export class QueryCallbacks {
|
|
|
52
52
|
_afterUpdate<T extends Query>(this: T, cb: AfterCallback<T>): T {
|
|
53
53
|
return pushQueryValue(this, 'afterUpdate', cb);
|
|
54
54
|
}
|
|
55
|
+
|
|
56
|
+
beforeDelete<T extends Query>(this: T, cb: BeforeCallback<T>): T {
|
|
57
|
+
return this.clone()._beforeDelete(cb);
|
|
58
|
+
}
|
|
59
|
+
_beforeDelete<T extends Query>(this: T, cb: BeforeCallback<T>): T {
|
|
60
|
+
return pushQueryValue(this, 'beforeDelete', cb);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
afterDelete<T extends Query>(this: T, cb: AfterCallback<T>): T {
|
|
64
|
+
return this.clone()._afterDelete(cb);
|
|
65
|
+
}
|
|
66
|
+
_afterDelete<T extends Query>(this: T, cb: AfterCallback<T>): T {
|
|
67
|
+
return pushQueryValue(this, 'afterDelete', cb);
|
|
68
|
+
}
|
|
55
69
|
}
|
|
@@ -28,8 +28,8 @@ export class Clear {
|
|
|
28
28
|
removeFromQuery(this, 'or');
|
|
29
29
|
} else if (clear === 'counters') {
|
|
30
30
|
if ('type' in this.query && this.query.type === 'update') {
|
|
31
|
-
this.query.
|
|
32
|
-
if (!isRaw(item)) {
|
|
31
|
+
this.query.updateData = this.query.updateData.filter((item) => {
|
|
32
|
+
if (!isRaw(item) && typeof item !== 'function') {
|
|
33
33
|
let removed = false;
|
|
34
34
|
for (const key in item) {
|
|
35
35
|
const value = item[key] as Record<string, unknown>;
|
|
@@ -202,7 +202,7 @@ describe('having', () => {
|
|
|
202
202
|
expectQueryNotMutated(q);
|
|
203
203
|
|
|
204
204
|
q._having(raw('count(*) = 1'), raw('sum(id) = 2'));
|
|
205
|
-
expectSql(q.toSql(), expectedSql);
|
|
205
|
+
expectSql(q.toSql({ clearCache: true }), expectedSql);
|
|
206
206
|
});
|
|
207
207
|
|
|
208
208
|
describe('havingOr', () => {
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
SortDir,
|
|
26
26
|
Sql,
|
|
27
27
|
toSql,
|
|
28
|
+
ToSqlOptions,
|
|
28
29
|
TruncateQueryData,
|
|
29
30
|
} from '../sql';
|
|
30
31
|
import {
|
|
@@ -182,8 +183,8 @@ export class QueryMethods {
|
|
|
182
183
|
return cloned;
|
|
183
184
|
}
|
|
184
185
|
|
|
185
|
-
toSql(this: Query,
|
|
186
|
-
return toSql(this,
|
|
186
|
+
toSql(this: Query, options?: ToSqlOptions): Sql {
|
|
187
|
+
return toSql(this, options);
|
|
187
188
|
}
|
|
188
189
|
|
|
189
190
|
distinct<T extends Query>(this: T, ...columns: Expression<T>[]): T {
|
package/src/queryMethods/then.ts
CHANGED
|
@@ -63,22 +63,23 @@ const then = async (
|
|
|
63
63
|
let sql: Sql | undefined;
|
|
64
64
|
let logData: unknown | undefined;
|
|
65
65
|
try {
|
|
66
|
-
let beforeCallbacks: BeforeCallback
|
|
67
|
-
let afterCallbacks: AfterCallback
|
|
66
|
+
let beforeCallbacks: BeforeCallback[] | undefined;
|
|
67
|
+
let afterCallbacks: AfterCallback[] | undefined;
|
|
68
68
|
if (q.query.type === 'insert') {
|
|
69
69
|
beforeCallbacks = q.query.beforeInsert;
|
|
70
70
|
afterCallbacks = q.query.afterInsert;
|
|
71
71
|
} else if (q.query.type === 'update') {
|
|
72
72
|
beforeCallbacks = q.query.beforeUpdate;
|
|
73
73
|
afterCallbacks = q.query.afterUpdate;
|
|
74
|
+
} else if (q.query.type === 'delete') {
|
|
75
|
+
beforeCallbacks = q.query.beforeDelete;
|
|
76
|
+
afterCallbacks = q.query.afterDelete;
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
if (beforeCallbacks) {
|
|
77
|
-
await Promise.all(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (q.query.beforeQuery) {
|
|
81
|
-
await Promise.all(q.query.beforeQuery.map((cb) => cb(q)));
|
|
79
|
+
if (beforeCallbacks || q.query.beforeQuery) {
|
|
80
|
+
await Promise.all(
|
|
81
|
+
getCallbacks(beforeCallbacks, q.query.beforeQuery).map((cb) => cb(q)),
|
|
82
|
+
);
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
sql = q.toSql();
|
|
@@ -99,14 +100,12 @@ const then = async (
|
|
|
99
100
|
|
|
100
101
|
const result = await q.query.handleResult(q, queryResult);
|
|
101
102
|
|
|
102
|
-
if (afterCallbacks
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
await Promise.all(afterCallbacks.map((query) => query(q, result)));
|
|
109
|
-
}
|
|
103
|
+
if (afterCallbacks || q.query.afterQuery) {
|
|
104
|
+
await Promise.all(
|
|
105
|
+
getCallbacks(q.query.afterQuery, afterCallbacks).map((query) =>
|
|
106
|
+
query(q, result),
|
|
107
|
+
),
|
|
108
|
+
);
|
|
110
109
|
}
|
|
111
110
|
|
|
112
111
|
resolve?.(result);
|
|
@@ -224,3 +223,12 @@ const parseValue = (value: unknown, query: Query) => {
|
|
|
224
223
|
}
|
|
225
224
|
return value;
|
|
226
225
|
};
|
|
226
|
+
|
|
227
|
+
const getCallbacks = <T extends BeforeCallback[] | AfterCallback[]>(
|
|
228
|
+
first?: T,
|
|
229
|
+
second?: T,
|
|
230
|
+
): T => {
|
|
231
|
+
return (
|
|
232
|
+
first && second ? [...first, ...second] : first ? first : second
|
|
233
|
+
) as T;
|
|
234
|
+
};
|