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,19 @@
|
|
|
1
|
+
import { SelectQueryData } from './types';
|
|
2
|
+
import { expressionToSql } from './common';
|
|
3
|
+
|
|
4
|
+
export const pushDistinctSql = (
|
|
5
|
+
sql: string[],
|
|
6
|
+
values: unknown[],
|
|
7
|
+
distinct: Exclude<SelectQueryData['distinct'], undefined>,
|
|
8
|
+
quotedAs?: string,
|
|
9
|
+
) => {
|
|
10
|
+
sql.push('DISTINCT');
|
|
11
|
+
|
|
12
|
+
if (distinct.length) {
|
|
13
|
+
const columns: string[] = [];
|
|
14
|
+
distinct?.forEach((item) => {
|
|
15
|
+
columns.push(expressionToSql(item, values, quotedAs));
|
|
16
|
+
});
|
|
17
|
+
sql.push(`ON (${columns.join(', ')})`);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { getRaw, isRaw } from '../common';
|
|
2
|
+
import { quoteSchemaAndTable } from './common';
|
|
3
|
+
import { Query } from '../query';
|
|
4
|
+
import { queryKeysOfNotSimpleQuery, SelectQueryData } from './types';
|
|
5
|
+
|
|
6
|
+
export const pushFromAndAs = (
|
|
7
|
+
sql: string[],
|
|
8
|
+
model: Query,
|
|
9
|
+
query: SelectQueryData,
|
|
10
|
+
values: unknown[],
|
|
11
|
+
quotedAs?: string,
|
|
12
|
+
) => {
|
|
13
|
+
sql.push('FROM');
|
|
14
|
+
if (query.fromOnly) sql.push('ONLY');
|
|
15
|
+
|
|
16
|
+
const from = getFrom(model, query, values);
|
|
17
|
+
sql.push(from);
|
|
18
|
+
|
|
19
|
+
if (query.as && quotedAs && quotedAs !== from) {
|
|
20
|
+
sql.push('AS', quotedAs as string);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const getFrom = (model: Query, query: SelectQueryData, values: unknown[]) => {
|
|
25
|
+
if (query.from) {
|
|
26
|
+
if (typeof query.from === 'object') {
|
|
27
|
+
if (isRaw(query.from)) {
|
|
28
|
+
return getRaw(query.from, values);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!query.from.table) {
|
|
32
|
+
const sql = query.from.toSql(values);
|
|
33
|
+
return `(${sql.text})`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const q = query.from.query;
|
|
37
|
+
const keys = Object.keys(q) as (keyof SelectQueryData)[];
|
|
38
|
+
// if query contains more than just schema return (SELECT ...)
|
|
39
|
+
if (keys.some((key) => queryKeysOfNotSimpleQuery.includes(key))) {
|
|
40
|
+
const sql = query.from.toSql(values);
|
|
41
|
+
return `(${sql.text})`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return quoteSchemaAndTable(q.schema, query.from.table);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return quoteSchemaAndTable(query.schema, query.from);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return quoteSchemaAndTable(query.schema, model.table as string);
|
|
51
|
+
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { AggregateItemOptions, HavingItem, SelectQueryData } from './types';
|
|
2
|
+
import { EMPTY_OBJECT, getRaw, isRaw, RawExpression } from '../common';
|
|
3
|
+
import { Operator } from '../operators';
|
|
4
|
+
import { aggregateToSql } from './aggregate';
|
|
5
|
+
import { Query } from '../query';
|
|
6
|
+
import { addValue, q } from './common';
|
|
7
|
+
|
|
8
|
+
const aggregateOptionNames: (keyof AggregateItemOptions)[] = [
|
|
9
|
+
'distinct',
|
|
10
|
+
'order',
|
|
11
|
+
'filter',
|
|
12
|
+
'filterOr',
|
|
13
|
+
'withinGroup',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
export const pushHavingSql = (
|
|
17
|
+
sql: string[],
|
|
18
|
+
model: Pick<
|
|
19
|
+
Query,
|
|
20
|
+
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
21
|
+
>,
|
|
22
|
+
query: SelectQueryData,
|
|
23
|
+
values: unknown[],
|
|
24
|
+
quotedAs?: string,
|
|
25
|
+
) => {
|
|
26
|
+
const conditions = havingToSql(model, query, values, quotedAs);
|
|
27
|
+
if (conditions.length) sql.push('HAVING', conditions);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const havingToSql = (
|
|
31
|
+
model: Pick<
|
|
32
|
+
Query,
|
|
33
|
+
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
34
|
+
>,
|
|
35
|
+
query: SelectQueryData,
|
|
36
|
+
values: unknown[],
|
|
37
|
+
quotedAs?: string,
|
|
38
|
+
): string => {
|
|
39
|
+
const or =
|
|
40
|
+
query.having && query.havingOr
|
|
41
|
+
? [query.having, ...query.havingOr]
|
|
42
|
+
: query.having
|
|
43
|
+
? [query.having]
|
|
44
|
+
: query.havingOr;
|
|
45
|
+
if (!or?.length) return '';
|
|
46
|
+
|
|
47
|
+
const ors: string[] = [];
|
|
48
|
+
or.forEach((and) => {
|
|
49
|
+
const ands: string[] = [];
|
|
50
|
+
and.forEach((item) => {
|
|
51
|
+
if ('prototype' in item || '__model' in item) {
|
|
52
|
+
const query = item as Query;
|
|
53
|
+
const sql = havingToSql(
|
|
54
|
+
query,
|
|
55
|
+
query.query as SelectQueryData,
|
|
56
|
+
values,
|
|
57
|
+
query.table && q(query.table),
|
|
58
|
+
);
|
|
59
|
+
if (sql.length) ands.push(`(${sql})`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (isRaw(item)) {
|
|
64
|
+
ands.push(getRaw(item, values));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for (const key in item) {
|
|
69
|
+
const columns = item[key as keyof Exclude<HavingItem, RawExpression>];
|
|
70
|
+
if (typeof columns === 'object') {
|
|
71
|
+
for (const column in columns) {
|
|
72
|
+
const valueOrOptions = columns[column as keyof typeof columns];
|
|
73
|
+
if (
|
|
74
|
+
typeof valueOrOptions === 'object' &&
|
|
75
|
+
valueOrOptions !== null &&
|
|
76
|
+
valueOrOptions !== undefined
|
|
77
|
+
) {
|
|
78
|
+
for (const op in valueOrOptions) {
|
|
79
|
+
if (
|
|
80
|
+
!aggregateOptionNames.includes(
|
|
81
|
+
op as keyof AggregateItemOptions,
|
|
82
|
+
)
|
|
83
|
+
) {
|
|
84
|
+
const operator = model.shape[column].operators[
|
|
85
|
+
op
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
87
|
+
] as Operator<any>;
|
|
88
|
+
if (!operator) {
|
|
89
|
+
// TODO: custom error classes
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Unknown operator ${op} provided to condition`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const expression = aggregateToSql(
|
|
96
|
+
model,
|
|
97
|
+
values,
|
|
98
|
+
{
|
|
99
|
+
function: key,
|
|
100
|
+
arg: column,
|
|
101
|
+
options: valueOrOptions as AggregateItemOptions,
|
|
102
|
+
},
|
|
103
|
+
quotedAs,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
ands.push(
|
|
107
|
+
operator(
|
|
108
|
+
expression,
|
|
109
|
+
valueOrOptions[op as keyof typeof valueOrOptions],
|
|
110
|
+
values,
|
|
111
|
+
),
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
ands.push(
|
|
117
|
+
`${aggregateToSql(
|
|
118
|
+
model,
|
|
119
|
+
values,
|
|
120
|
+
{
|
|
121
|
+
function: key,
|
|
122
|
+
arg: column,
|
|
123
|
+
options: EMPTY_OBJECT,
|
|
124
|
+
},
|
|
125
|
+
quotedAs,
|
|
126
|
+
)} = ${addValue(values, valueOrOptions)}`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
ands.push(`${key}(*) = ${columns}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
ors.push(ands.join(' AND '));
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return ors.join(' OR ');
|
|
140
|
+
};
|
package/src/sql/index.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { InsertQueryData, QueryData } from './types';
|
|
2
|
+
import { addValue, q } from './common';
|
|
3
|
+
import { getRaw, isRaw } from '../common';
|
|
4
|
+
import { pushWhereSql } from './where';
|
|
5
|
+
import { Query } from '../query';
|
|
6
|
+
import { selectToSql } from './select';
|
|
7
|
+
|
|
8
|
+
export const pushInsertSql = (
|
|
9
|
+
sql: string[],
|
|
10
|
+
values: unknown[],
|
|
11
|
+
model: Pick<
|
|
12
|
+
Query,
|
|
13
|
+
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
14
|
+
>,
|
|
15
|
+
query: InsertQueryData,
|
|
16
|
+
quotedAs: string,
|
|
17
|
+
) => {
|
|
18
|
+
const quotedColumns = query.columns.map(q);
|
|
19
|
+
|
|
20
|
+
sql.push(
|
|
21
|
+
`INSERT INTO ${quotedAs}(${quotedColumns.join(', ')}) VALUES ${
|
|
22
|
+
isRaw(query.values)
|
|
23
|
+
? getRaw(query.values, values)
|
|
24
|
+
: query.values
|
|
25
|
+
.map(
|
|
26
|
+
(row) =>
|
|
27
|
+
`(${row
|
|
28
|
+
.map((value) =>
|
|
29
|
+
value === undefined ? 'DEFAULT' : addValue(values, value),
|
|
30
|
+
)
|
|
31
|
+
.join(', ')})`,
|
|
32
|
+
)
|
|
33
|
+
.join(', ')
|
|
34
|
+
}`,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (query.onConflict) {
|
|
38
|
+
sql.push('ON CONFLICT');
|
|
39
|
+
|
|
40
|
+
const { expr, type } = query.onConflict;
|
|
41
|
+
if (expr) {
|
|
42
|
+
if (typeof expr === 'string') {
|
|
43
|
+
sql.push(`(${q(expr)})`);
|
|
44
|
+
} else if (Array.isArray(expr)) {
|
|
45
|
+
sql.push(`(${expr.map(q).join(', ')})`);
|
|
46
|
+
} else {
|
|
47
|
+
sql.push(getRaw(expr, values));
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
sql.push(`(${quotedColumns.join(', ')})`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (type === 'ignore') {
|
|
54
|
+
sql.push('DO NOTHING');
|
|
55
|
+
} else if (type === 'merge') {
|
|
56
|
+
let set: string;
|
|
57
|
+
|
|
58
|
+
const { update } = query.onConflict;
|
|
59
|
+
if (update) {
|
|
60
|
+
if (typeof update === 'string') {
|
|
61
|
+
set = `${q(update)} = excluded.${q(update)}`;
|
|
62
|
+
} else if (Array.isArray(update)) {
|
|
63
|
+
set = update
|
|
64
|
+
.map((column) => `${q(column)} = excluded.${q(column)}`)
|
|
65
|
+
.join(', ');
|
|
66
|
+
} else if (isRaw(update)) {
|
|
67
|
+
set = getRaw(update, values);
|
|
68
|
+
} else {
|
|
69
|
+
const arr: string[] = [];
|
|
70
|
+
for (const key in update) {
|
|
71
|
+
arr.push(`${q(key)} = ${addValue(values, update[key])}`);
|
|
72
|
+
}
|
|
73
|
+
set = arr.join(', ');
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
set = quotedColumns
|
|
77
|
+
.map((column) => `${column} = excluded.${column}`)
|
|
78
|
+
.join(', ');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
sql.push('DO UPDATE SET', set);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
pushWhereSql(sql, model, query, values, quotedAs);
|
|
86
|
+
pushReturningSql(sql, model, query, values, quotedAs);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const pushReturningSql = (
|
|
90
|
+
sql: string[],
|
|
91
|
+
model: Pick<
|
|
92
|
+
Query,
|
|
93
|
+
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
94
|
+
>,
|
|
95
|
+
query: QueryData,
|
|
96
|
+
values: unknown[],
|
|
97
|
+
quotedAs: string,
|
|
98
|
+
) => {
|
|
99
|
+
if (query.select) {
|
|
100
|
+
sql.push(`RETURNING ${selectToSql(model, query, values, quotedAs)}`);
|
|
101
|
+
}
|
|
102
|
+
};
|
package/src/sql/join.ts
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { q, quoteFullColumn, quoteSchemaAndTable } from './common';
|
|
2
|
+
import { getRaw, isRaw, RawExpression } from '../common';
|
|
3
|
+
import { JoinItem, QueryData } from './types';
|
|
4
|
+
import { Query, QueryBase } from '../query';
|
|
5
|
+
import { whereToSql } from './where';
|
|
6
|
+
import { Relation } from '../relations';
|
|
7
|
+
|
|
8
|
+
type ItemOf3Or4Length =
|
|
9
|
+
| [
|
|
10
|
+
_: unknown,
|
|
11
|
+
leftColumn: string | RawExpression,
|
|
12
|
+
rightColumn: string | RawExpression,
|
|
13
|
+
]
|
|
14
|
+
| [
|
|
15
|
+
_: unknown,
|
|
16
|
+
leftColumn: string | RawExpression,
|
|
17
|
+
op: string,
|
|
18
|
+
rightColumn?: string | RawExpression,
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
export const processJoinItem = (
|
|
22
|
+
model: Pick<
|
|
23
|
+
Query,
|
|
24
|
+
'whereQueryBuilder' | 'onQueryBuilder' | 'table' | 'shape' | 'relations'
|
|
25
|
+
>,
|
|
26
|
+
query: Pick<QueryData, 'as'>,
|
|
27
|
+
values: unknown[],
|
|
28
|
+
args: JoinItem['args'],
|
|
29
|
+
quotedAs?: string,
|
|
30
|
+
): { target: string; conditions?: string } => {
|
|
31
|
+
const [first] = args;
|
|
32
|
+
if (typeof first === 'string') {
|
|
33
|
+
if (first in model.relations) {
|
|
34
|
+
const { key, joinQuery } = (model.relations as Record<string, Relation>)[
|
|
35
|
+
first
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const table = (
|
|
39
|
+
typeof joinQuery.query.from === 'string'
|
|
40
|
+
? joinQuery.query.from
|
|
41
|
+
: joinQuery.table
|
|
42
|
+
) as string;
|
|
43
|
+
|
|
44
|
+
let target = quoteSchemaAndTable(joinQuery.query.schema, table);
|
|
45
|
+
|
|
46
|
+
const as = joinQuery.query.as || key;
|
|
47
|
+
if (as !== table) {
|
|
48
|
+
target += ` AS ${q(as as string)}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const queryData = {
|
|
52
|
+
and: [],
|
|
53
|
+
or: [],
|
|
54
|
+
} as {
|
|
55
|
+
and: Exclude<QueryData['and'], undefined>;
|
|
56
|
+
or: Exclude<QueryData['or'], undefined>;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
if (joinQuery.query.and) queryData.and.push(...joinQuery.query.and);
|
|
60
|
+
if (joinQuery.query.or) queryData.or.push(...joinQuery.query.or);
|
|
61
|
+
|
|
62
|
+
const arg = (args[1] as ((q: unknown) => QueryBase) | undefined)?.(
|
|
63
|
+
new model.onQueryBuilder({ table: model.table, query }, args[0]),
|
|
64
|
+
).query;
|
|
65
|
+
|
|
66
|
+
if (arg) {
|
|
67
|
+
if (arg.and) queryData.and.push(...arg.and);
|
|
68
|
+
if (arg.or) queryData.or.push(...arg.or);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const joinAs = q(as as string);
|
|
72
|
+
const onConditions = whereToSql(
|
|
73
|
+
joinQuery,
|
|
74
|
+
queryData,
|
|
75
|
+
values,
|
|
76
|
+
quotedAs,
|
|
77
|
+
joinAs,
|
|
78
|
+
);
|
|
79
|
+
const conditions = onConditions ? onConditions : undefined;
|
|
80
|
+
|
|
81
|
+
return { target, conditions };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const target = q(first);
|
|
85
|
+
let conditions: string | undefined;
|
|
86
|
+
|
|
87
|
+
if (args.length === 2) {
|
|
88
|
+
const arg = args[1];
|
|
89
|
+
if (typeof arg === 'function') {
|
|
90
|
+
const joinQuery = arg(
|
|
91
|
+
new model.onQueryBuilder({ table: model.table, query }, args[0]),
|
|
92
|
+
);
|
|
93
|
+
const onConditions = whereToSql(
|
|
94
|
+
model,
|
|
95
|
+
joinQuery.query,
|
|
96
|
+
values,
|
|
97
|
+
quotedAs,
|
|
98
|
+
target,
|
|
99
|
+
);
|
|
100
|
+
if (onConditions) conditions = onConditions;
|
|
101
|
+
} else {
|
|
102
|
+
conditions = getObjectOrRawConditions(arg, values, quotedAs, target);
|
|
103
|
+
}
|
|
104
|
+
} else if (args.length >= 3) {
|
|
105
|
+
conditions = getConditionsFor3Or4LengthItem(
|
|
106
|
+
target,
|
|
107
|
+
values,
|
|
108
|
+
quotedAs,
|
|
109
|
+
args as ItemOf3Or4Length,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return { target, conditions };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const joinTarget = first;
|
|
117
|
+
const joinQuery = joinTarget.query;
|
|
118
|
+
|
|
119
|
+
const quotedFrom =
|
|
120
|
+
typeof joinQuery?.from === 'string' ? q(joinQuery.from) : undefined;
|
|
121
|
+
|
|
122
|
+
let target =
|
|
123
|
+
quotedFrom || quoteSchemaAndTable(joinQuery?.schema, joinTarget.table);
|
|
124
|
+
|
|
125
|
+
let joinAs = quotedFrom || q(joinTarget.table);
|
|
126
|
+
if (joinQuery?.as) {
|
|
127
|
+
const quoted = q(joinQuery.as);
|
|
128
|
+
if (quoted !== joinAs) {
|
|
129
|
+
joinAs = quoted;
|
|
130
|
+
target += ` AS ${quoted}`;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
let conditions: string | undefined;
|
|
135
|
+
|
|
136
|
+
if (args.length === 2) {
|
|
137
|
+
const arg = args[1];
|
|
138
|
+
if (typeof arg === 'function') {
|
|
139
|
+
const joinQuery = arg(
|
|
140
|
+
new model.onQueryBuilder({ table: model.table, query }, args[0]),
|
|
141
|
+
);
|
|
142
|
+
const onConditions = whereToSql(
|
|
143
|
+
model,
|
|
144
|
+
joinQuery.query,
|
|
145
|
+
values,
|
|
146
|
+
quotedAs,
|
|
147
|
+
joinAs,
|
|
148
|
+
);
|
|
149
|
+
if (onConditions) conditions = onConditions;
|
|
150
|
+
} else {
|
|
151
|
+
conditions = getObjectOrRawConditions(arg, values, quotedAs, joinAs);
|
|
152
|
+
}
|
|
153
|
+
} else if (args.length >= 3) {
|
|
154
|
+
conditions = getConditionsFor3Or4LengthItem(
|
|
155
|
+
joinAs,
|
|
156
|
+
values,
|
|
157
|
+
quotedAs,
|
|
158
|
+
args as ItemOf3Or4Length,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (joinQuery) {
|
|
163
|
+
const whereSql = whereToSql(model, joinQuery, values, joinAs, quotedAs);
|
|
164
|
+
if (whereSql) {
|
|
165
|
+
if (conditions) conditions += ` AND ${whereSql}`;
|
|
166
|
+
else conditions = whereSql;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return { target, conditions };
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const getConditionsFor3Or4LengthItem = (
|
|
174
|
+
target: string,
|
|
175
|
+
values: unknown[],
|
|
176
|
+
quotedAs: string | undefined,
|
|
177
|
+
args: ItemOf3Or4Length,
|
|
178
|
+
): string => {
|
|
179
|
+
const [, leftColumn, opOrRightColumn, maybeRightColumn] = args;
|
|
180
|
+
|
|
181
|
+
const op = maybeRightColumn ? opOrRightColumn : '=';
|
|
182
|
+
const rightColumn = maybeRightColumn ? maybeRightColumn : opOrRightColumn;
|
|
183
|
+
|
|
184
|
+
return `${
|
|
185
|
+
typeof leftColumn === 'string'
|
|
186
|
+
? quoteFullColumn(leftColumn, target)
|
|
187
|
+
: getRaw(leftColumn, values)
|
|
188
|
+
} ${op} ${
|
|
189
|
+
typeof rightColumn === 'string'
|
|
190
|
+
? quoteFullColumn(rightColumn, quotedAs)
|
|
191
|
+
: getRaw(rightColumn, values)
|
|
192
|
+
}`;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const getObjectOrRawConditions = (
|
|
196
|
+
data: Record<string, string | RawExpression> | RawExpression,
|
|
197
|
+
values: unknown[],
|
|
198
|
+
quotedAs: string | undefined,
|
|
199
|
+
joinAs: string | undefined,
|
|
200
|
+
): string => {
|
|
201
|
+
if (isRaw(data)) {
|
|
202
|
+
return getRaw(data, values);
|
|
203
|
+
} else {
|
|
204
|
+
const pairs: string[] = [];
|
|
205
|
+
for (const key in data) {
|
|
206
|
+
const value = data[key];
|
|
207
|
+
|
|
208
|
+
pairs.push(
|
|
209
|
+
`${quoteFullColumn(key, joinAs)} = ${
|
|
210
|
+
typeof value === 'string'
|
|
211
|
+
? quoteFullColumn(value, quotedAs)
|
|
212
|
+
: getRaw(value, values)
|
|
213
|
+
}`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return pairs.join(', ');
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
export const pushJoinSql = (
|
|
222
|
+
sql: string[],
|
|
223
|
+
model: Query,
|
|
224
|
+
query: QueryData & {
|
|
225
|
+
join: JoinItem[];
|
|
226
|
+
},
|
|
227
|
+
values: unknown[],
|
|
228
|
+
quotedAs?: string,
|
|
229
|
+
) => {
|
|
230
|
+
query.join.forEach((item) => {
|
|
231
|
+
const { target, conditions } = processJoinItem(
|
|
232
|
+
model,
|
|
233
|
+
query,
|
|
234
|
+
values,
|
|
235
|
+
item.args,
|
|
236
|
+
quotedAs,
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
sql.push(item.type, target);
|
|
240
|
+
if (conditions) sql.push('ON', conditions);
|
|
241
|
+
});
|
|
242
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { OrderItem, SelectQueryData } from './types';
|
|
2
|
+
import { getRaw, isRaw } from '../common';
|
|
3
|
+
import { qc } from './common';
|
|
4
|
+
|
|
5
|
+
export const pushOrderBySql = (
|
|
6
|
+
sql: string[],
|
|
7
|
+
values: unknown[],
|
|
8
|
+
quotedAs: string | undefined,
|
|
9
|
+
order: Exclude<SelectQueryData['order'], undefined>,
|
|
10
|
+
) => {
|
|
11
|
+
sql.push(
|
|
12
|
+
`ORDER BY ${order
|
|
13
|
+
.map((item) => orderByToSql(item, values, quotedAs))
|
|
14
|
+
.join(', ')}`,
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const orderByToSql = (
|
|
19
|
+
order: OrderItem,
|
|
20
|
+
values: unknown[],
|
|
21
|
+
quotedAs?: string,
|
|
22
|
+
) => {
|
|
23
|
+
if (typeof order === 'string') {
|
|
24
|
+
return `${qc(order, quotedAs)} ASC`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isRaw(order)) {
|
|
28
|
+
return getRaw(order, values);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const sql: string[] = [];
|
|
32
|
+
for (const key in order) {
|
|
33
|
+
const value = order[key];
|
|
34
|
+
if (typeof value === 'string') {
|
|
35
|
+
sql.push(`${qc(key, quotedAs)} ${value}`);
|
|
36
|
+
} else if (value) {
|
|
37
|
+
sql.push(`${qc(key, quotedAs)} ${value.dir} NULLS ${value.nulls}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return sql.join(', ');
|
|
41
|
+
};
|