typeorm-extensions 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +2 -0
- package/.eslintrc +12 -0
- package/README.md +46 -0
- package/package.json +33 -0
- package/src/constants/index.ts +9 -0
- package/src/extensions/get-many-with-totals.extension.ts +62 -0
- package/src/extensions/index.ts +4 -0
- package/src/extensions/ordering.extension.ts +123 -0
- package/src/extensions/pagination.extension.ts +35 -0
- package/src/extensions/typed/index.ts +12 -0
- package/src/extensions/typed/typed-distinct/typed-distinct.extension.ts +38 -0
- package/src/extensions/typed/typed-joins/typed-joins.extension.ts +141 -0
- package/src/extensions/typed/typed-order-by/typed-order-by.extension.ts +73 -0
- package/src/extensions/typed/typed-select/typed-select.extension.ts +124 -0
- package/src/extensions/typed/typed-where/typed-where.extension.ts +268 -0
- package/src/extensions/typed/typeorm-querybuilder.types.ts +75 -0
- package/src/extensions/typed/typeorm.types.ts +30 -0
- package/src/index.ts +3 -0
- package/src/types/interfaces/index.ts +2 -0
- package/src/types/interfaces/ordering.interface.ts +21 -0
- package/src/types/interfaces/pagination.interface.ts +8 -0
- package/src/types/modules/column.types.ts +5 -0
- package/src/types/modules/proxy-types/proxy-callback.types.ts +11 -0
- package/src/types/modules/relations.types.ts +34 -0
- package/src/types/util-types/index.ts +8 -0
- package/src/utils/common.utils.ts +2 -0
- package/src/utils/identifier.utils.ts +60 -0
- package/src/utils/pagination.utils.ts +17 -0
- package/src/utils/proxy-key.utils.ts +133 -0
- package/src/utils/sql.utils.ts +24 -0
- package/tsconfig.json +109 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
|
|
2
|
+
import { KeyHolder, KeyProxyCallback } from '../typeorm-querybuilder.types';
|
|
3
|
+
import { getSqlKey } from '../../../utils/proxy-key.utils';
|
|
4
|
+
|
|
5
|
+
declare module 'typeorm/query-builder/SelectQueryBuilder' {
|
|
6
|
+
interface SelectQueryBuilder<Entity> {
|
|
7
|
+
/**
|
|
8
|
+
* Creates SELECT query.
|
|
9
|
+
* Replaces all previous selections if they exist.
|
|
10
|
+
*/
|
|
11
|
+
selectTyped<Type extends ObjectLiteral = Entity>(
|
|
12
|
+
this: SelectQueryBuilder<Entity>,
|
|
13
|
+
selection: KeyProxyCallback<Type>,
|
|
14
|
+
selectionAliasName?: string
|
|
15
|
+
): SelectQueryBuilder<Entity>;
|
|
16
|
+
/**
|
|
17
|
+
* Creates SELECT query and selects given data.
|
|
18
|
+
* Replaces all previous selections if they exist.
|
|
19
|
+
*/
|
|
20
|
+
selectTyped(
|
|
21
|
+
this: SelectQueryBuilder<Entity>,
|
|
22
|
+
selection: string | KeyHolder,
|
|
23
|
+
selectionAliasName?: string
|
|
24
|
+
): SelectQueryBuilder<Entity>;
|
|
25
|
+
/**
|
|
26
|
+
* Creates SELECT query and selects given data.
|
|
27
|
+
* Replaces all previous selections if they exist.
|
|
28
|
+
*/
|
|
29
|
+
selectTyped<Type extends ObjectLiteral = Entity>(
|
|
30
|
+
this: SelectQueryBuilder<Entity>,
|
|
31
|
+
selection: string[] | KeyHolder[] | Array<KeyProxyCallback<Type>>
|
|
32
|
+
): SelectQueryBuilder<Entity>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Adds new selection to the SELECT query.
|
|
36
|
+
*/
|
|
37
|
+
addSelectTyped<Type extends ObjectLiteral = Entity>(
|
|
38
|
+
this: SelectQueryBuilder<Entity>,
|
|
39
|
+
selection: KeyProxyCallback<Type>,
|
|
40
|
+
selectionAliasName?: string
|
|
41
|
+
): SelectQueryBuilder<Entity>;
|
|
42
|
+
/**
|
|
43
|
+
* Adds new selection to the SELECT query.
|
|
44
|
+
*/
|
|
45
|
+
addSelectTyped(
|
|
46
|
+
this: SelectQueryBuilder<Entity>,
|
|
47
|
+
selection: string | KeyHolder,
|
|
48
|
+
selectionAliasName?: string
|
|
49
|
+
): SelectQueryBuilder<Entity>;
|
|
50
|
+
/**
|
|
51
|
+
* Adds new selection to the SELECT query.
|
|
52
|
+
*/
|
|
53
|
+
addSelectTyped<Type extends ObjectLiteral = Entity>(
|
|
54
|
+
this: SelectQueryBuilder<Entity>,
|
|
55
|
+
selection: string[] | KeyHolder[] | Array<KeyProxyCallback<Type>>
|
|
56
|
+
): SelectQueryBuilder<Entity>;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
SelectQueryBuilder.prototype.selectTyped = function <Entity extends ObjectLiteral, Type extends ObjectLiteral = Entity>(
|
|
61
|
+
this: SelectQueryBuilder<Entity>,
|
|
62
|
+
selection?:
|
|
63
|
+
| string
|
|
64
|
+
| KeyHolder
|
|
65
|
+
| KeyProxyCallback<Type>
|
|
66
|
+
| string[]
|
|
67
|
+
| KeyHolder[]
|
|
68
|
+
| Array<KeyProxyCallback<Type>>,
|
|
69
|
+
selectionAliasName?: string
|
|
70
|
+
): SelectQueryBuilder<Entity> {
|
|
71
|
+
return attachSelectMethod<Entity, Type>(this, 'select', selection, selectionAliasName);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
SelectQueryBuilder.prototype.addSelectTyped = function <
|
|
75
|
+
Entity extends ObjectLiteral,
|
|
76
|
+
Type extends ObjectLiteral = Entity
|
|
77
|
+
>(
|
|
78
|
+
this: SelectQueryBuilder<Entity>,
|
|
79
|
+
selection?:
|
|
80
|
+
| string
|
|
81
|
+
| KeyHolder
|
|
82
|
+
| KeyProxyCallback<Type>
|
|
83
|
+
| string[]
|
|
84
|
+
| KeyHolder[]
|
|
85
|
+
| Array<KeyProxyCallback<Type>>,
|
|
86
|
+
selectionAliasName?: string
|
|
87
|
+
): SelectQueryBuilder<Entity> {
|
|
88
|
+
return attachSelectMethod<Entity, Type>(this, 'addSelect', selection, selectionAliasName);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const attachSelectMethod = <Entity extends ObjectLiteral, Type extends ObjectLiteral = Entity>(
|
|
92
|
+
query: SelectQueryBuilder<Entity>,
|
|
93
|
+
method: 'select' | 'addSelect',
|
|
94
|
+
selection?:
|
|
95
|
+
| string
|
|
96
|
+
| KeyHolder
|
|
97
|
+
| KeyProxyCallback<Type>
|
|
98
|
+
| string[]
|
|
99
|
+
| KeyHolder[]
|
|
100
|
+
| Array<KeyProxyCallback<Type>>,
|
|
101
|
+
selectionAliasName?: string
|
|
102
|
+
): SelectQueryBuilder<Entity> => {
|
|
103
|
+
if (selection instanceof KeyHolder) {
|
|
104
|
+
return query[method](selection.toSql(), selectionAliasName);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (Array.isArray(selection)) {
|
|
108
|
+
const arrayOfKeys = selection.map((value) => getSqlKey<Type>(value, query.alias) as string);
|
|
109
|
+
|
|
110
|
+
return query[method](arrayOfKeys);
|
|
111
|
+
} else if (typeof selection === 'function') {
|
|
112
|
+
const keyArrayOrSingleKey = getSqlKey<Type>(selection, query.alias);
|
|
113
|
+
|
|
114
|
+
if (Array.isArray(keyArrayOrSingleKey)) {
|
|
115
|
+
return query[method](keyArrayOrSingleKey);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return query[method](keyArrayOrSingleKey, selectionAliasName);
|
|
119
|
+
} else if (typeof selection === 'string') {
|
|
120
|
+
return query[method](selection, selectionAliasName);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return query;
|
|
124
|
+
};
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ObjectLiteral,
|
|
3
|
+
SelectQueryBuilder,
|
|
4
|
+
WhereExpressionBuilder,
|
|
5
|
+
UpdateQueryBuilder,
|
|
6
|
+
DeleteQueryBuilder,
|
|
7
|
+
} from 'typeorm';
|
|
8
|
+
import { ColumnValueType } from '../typeorm.types';
|
|
9
|
+
import { getSqlKey } from '../../../utils/proxy-key.utils';
|
|
10
|
+
|
|
11
|
+
export interface TypedWhereOptions {
|
|
12
|
+
useDoubleQuotes?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare module 'typeorm/query-builder/WhereExpressionBuilder' {
|
|
16
|
+
interface WhereExpressionBuilder {
|
|
17
|
+
/**
|
|
18
|
+
* Sets WHERE condition in the query builder.
|
|
19
|
+
* If you had previously WHERE expression defined,
|
|
20
|
+
* calling this function will override previously set WHERE conditions.
|
|
21
|
+
* Additionally you can add parameters used in where expression.
|
|
22
|
+
*/
|
|
23
|
+
whereTyped<Type extends ObjectLiteral>(
|
|
24
|
+
subQuery: (proxy: Type) => ColumnValueType,
|
|
25
|
+
conditions: string,
|
|
26
|
+
parameters?: ObjectLiteral,
|
|
27
|
+
options?: TypedWhereOptions
|
|
28
|
+
): this;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Adds new AND WHERE condition in the query builder.
|
|
32
|
+
* Additionally you can add parameters used in where expression.
|
|
33
|
+
*/
|
|
34
|
+
andWhereTyped<Type extends ObjectLiteral>(
|
|
35
|
+
subQuery: (proxy: Type) => ColumnValueType,
|
|
36
|
+
conditions: string,
|
|
37
|
+
parameters?: ObjectLiteral,
|
|
38
|
+
options?: TypedWhereOptions
|
|
39
|
+
): this;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Adds new OR WHERE condition in the query builder.
|
|
43
|
+
* Additionally you can add parameters used in where expression.
|
|
44
|
+
*/
|
|
45
|
+
orWhereTyped<Type extends ObjectLiteral>(
|
|
46
|
+
subQuery: (proxy: Type) => ColumnValueType,
|
|
47
|
+
conditions: string,
|
|
48
|
+
parameters?: ObjectLiteral,
|
|
49
|
+
options?: TypedWhereOptions
|
|
50
|
+
): this;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
declare module 'typeorm/query-builder/SelectQueryBuilder' {
|
|
55
|
+
interface SelectQueryBuilder<Entity> {
|
|
56
|
+
/**
|
|
57
|
+
* Sets WHERE condition in the query builder.
|
|
58
|
+
* If you had previously WHERE expression defined,
|
|
59
|
+
* calling this function will override previously set WHERE conditions.
|
|
60
|
+
* Additionally you can add parameters used in where expression.
|
|
61
|
+
*/
|
|
62
|
+
whereTyped<Type extends ObjectLiteral = Entity>(
|
|
63
|
+
where: (proxy: Type) => ColumnValueType,
|
|
64
|
+
conditions: string,
|
|
65
|
+
parameters?: ObjectLiteral,
|
|
66
|
+
options?: TypedWhereOptions
|
|
67
|
+
): this;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Adds new AND WHERE condition in the query builder.
|
|
71
|
+
* Additionally you can add parameters used in where expression.
|
|
72
|
+
*/
|
|
73
|
+
andWhereTyped<Type extends ObjectLiteral = Entity>(
|
|
74
|
+
where: (proxy: Type) => ColumnValueType,
|
|
75
|
+
conditions: string,
|
|
76
|
+
parameters?: ObjectLiteral,
|
|
77
|
+
options?: TypedWhereOptions
|
|
78
|
+
): this;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Adds new OR WHERE condition in the query builder.
|
|
82
|
+
* Additionally you can add parameters used in where expression.
|
|
83
|
+
*/
|
|
84
|
+
orWhereTyped<Type extends ObjectLiteral = Entity>(
|
|
85
|
+
where: (proxy: Type) => ColumnValueType,
|
|
86
|
+
conditions: string,
|
|
87
|
+
parameters?: ObjectLiteral,
|
|
88
|
+
options?: TypedWhereOptions
|
|
89
|
+
): this;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
declare module 'typeorm/query-builder/UpdateQueryBuilder' {
|
|
94
|
+
interface UpdateQueryBuilder<Entity> {
|
|
95
|
+
/**
|
|
96
|
+
* Sets WHERE condition in the query builder.
|
|
97
|
+
* If you had previously WHERE expression defined,
|
|
98
|
+
* calling this function will override previously set WHERE conditions.
|
|
99
|
+
* Additionally you can add parameters used in where expression.
|
|
100
|
+
*/
|
|
101
|
+
whereTyped<Type extends ObjectLiteral = Entity>(
|
|
102
|
+
where: (proxy: Type) => ColumnValueType,
|
|
103
|
+
conditions: string,
|
|
104
|
+
parameters?: ObjectLiteral,
|
|
105
|
+
options?: TypedWhereOptions
|
|
106
|
+
): this;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Adds new AND WHERE condition in the query builder.
|
|
110
|
+
* Additionally you can add parameters used in where expression.
|
|
111
|
+
*/
|
|
112
|
+
andWhereTyped<Type extends ObjectLiteral = Entity>(
|
|
113
|
+
where: (proxy: Type) => ColumnValueType,
|
|
114
|
+
conditions: string,
|
|
115
|
+
parameters?: ObjectLiteral,
|
|
116
|
+
options?: TypedWhereOptions
|
|
117
|
+
): this;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Adds new OR WHERE condition in the query builder.
|
|
121
|
+
* Additionally you can add parameters used in where expression.
|
|
122
|
+
*/
|
|
123
|
+
orWhereTyped<Type extends ObjectLiteral = Entity>(
|
|
124
|
+
where: (proxy: Type) => ColumnValueType,
|
|
125
|
+
conditions: string,
|
|
126
|
+
parameters?: ObjectLiteral,
|
|
127
|
+
options?: TypedWhereOptions
|
|
128
|
+
): this;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
declare module 'typeorm/query-builder/DeleteQueryBuilder' {
|
|
133
|
+
interface DeleteQueryBuilder<Entity> {
|
|
134
|
+
/**
|
|
135
|
+
* Sets WHERE condition in the query builder.
|
|
136
|
+
* If you had previously WHERE expression defined,
|
|
137
|
+
* calling this function will override previously set WHERE conditions.
|
|
138
|
+
* Additionally you can add parameters used in where expression.
|
|
139
|
+
*/
|
|
140
|
+
whereTyped<Type extends ObjectLiteral = Entity>(
|
|
141
|
+
where: (proxy: Type) => ColumnValueType,
|
|
142
|
+
conditions: string,
|
|
143
|
+
parameters?: ObjectLiteral,
|
|
144
|
+
options?: TypedWhereOptions
|
|
145
|
+
): this;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Adds new AND WHERE condition in the query builder.
|
|
149
|
+
* Additionally you can add parameters used in where expression.
|
|
150
|
+
*/
|
|
151
|
+
andWhereTyped<Type extends ObjectLiteral = Entity>(
|
|
152
|
+
where: (proxy: Type) => ColumnValueType,
|
|
153
|
+
conditions: string,
|
|
154
|
+
parameters?: ObjectLiteral,
|
|
155
|
+
options?: TypedWhereOptions
|
|
156
|
+
): this;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Adds new OR WHERE condition in the query builder.
|
|
160
|
+
* Additionally you can add parameters used in where expression.
|
|
161
|
+
*/
|
|
162
|
+
orWhereTyped<Type extends ObjectLiteral = Entity>(
|
|
163
|
+
where: (proxy: Type) => ColumnValueType,
|
|
164
|
+
conditions: string,
|
|
165
|
+
parameters?: ObjectLiteral,
|
|
166
|
+
options?: TypedWhereOptions
|
|
167
|
+
): this;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const queryBuilders = [
|
|
172
|
+
SelectQueryBuilder,
|
|
173
|
+
UpdateQueryBuilder,
|
|
174
|
+
DeleteQueryBuilder,
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
const extension = {
|
|
178
|
+
prototype: {
|
|
179
|
+
whereTyped: function <
|
|
180
|
+
Entity extends ObjectLiteral,
|
|
181
|
+
Type extends ObjectLiteral = Entity
|
|
182
|
+
>(
|
|
183
|
+
this: SelectQueryBuilder<Entity>,
|
|
184
|
+
where: (proxy: Type) => ColumnValueType,
|
|
185
|
+
conditions: string,
|
|
186
|
+
parameters?: ObjectLiteral,
|
|
187
|
+
options?: TypedWhereOptions
|
|
188
|
+
): SelectQueryBuilder<Entity> {
|
|
189
|
+
return attachWhere<Type, SelectQueryBuilder<Entity>>(
|
|
190
|
+
this,
|
|
191
|
+
'where',
|
|
192
|
+
where,
|
|
193
|
+
conditions,
|
|
194
|
+
parameters,
|
|
195
|
+
options
|
|
196
|
+
);
|
|
197
|
+
},
|
|
198
|
+
andWhereTyped: function <
|
|
199
|
+
Entity extends ObjectLiteral,
|
|
200
|
+
Type extends ObjectLiteral = Entity
|
|
201
|
+
>(
|
|
202
|
+
this: SelectQueryBuilder<Entity>,
|
|
203
|
+
where: (proxy: Type) => ColumnValueType,
|
|
204
|
+
conditions: string,
|
|
205
|
+
parameters?: ObjectLiteral,
|
|
206
|
+
options?: TypedWhereOptions
|
|
207
|
+
): SelectQueryBuilder<Entity> {
|
|
208
|
+
return attachWhere<Type, SelectQueryBuilder<Entity>>(
|
|
209
|
+
this,
|
|
210
|
+
'andWhere',
|
|
211
|
+
where,
|
|
212
|
+
conditions,
|
|
213
|
+
parameters,
|
|
214
|
+
options
|
|
215
|
+
);
|
|
216
|
+
},
|
|
217
|
+
orWhereTyped: function <
|
|
218
|
+
Entity extends ObjectLiteral,
|
|
219
|
+
Type extends ObjectLiteral = Entity
|
|
220
|
+
>(
|
|
221
|
+
this: SelectQueryBuilder<Entity>,
|
|
222
|
+
where: (proxy: Type) => ColumnValueType,
|
|
223
|
+
conditions: string,
|
|
224
|
+
parameters?: ObjectLiteral,
|
|
225
|
+
options?: TypedWhereOptions
|
|
226
|
+
): SelectQueryBuilder<Entity> {
|
|
227
|
+
return attachWhere<Type, SelectQueryBuilder<Entity>>(
|
|
228
|
+
this,
|
|
229
|
+
'orWhere',
|
|
230
|
+
where,
|
|
231
|
+
conditions,
|
|
232
|
+
parameters,
|
|
233
|
+
options
|
|
234
|
+
);
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
queryBuilders.forEach((builder) => {
|
|
240
|
+
Object.assign(builder, extension);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
type WhereMethod = 'where' | 'andWhere' | 'orWhere';
|
|
244
|
+
|
|
245
|
+
function attachWhere<
|
|
246
|
+
Type extends ObjectLiteral,
|
|
247
|
+
Q extends WhereExpressionBuilder = WhereExpressionBuilder
|
|
248
|
+
>(
|
|
249
|
+
builder: Q,
|
|
250
|
+
method: WhereMethod,
|
|
251
|
+
where: (proxy: Type) => ColumnValueType,
|
|
252
|
+
conditions: string,
|
|
253
|
+
parameters?: ObjectLiteral,
|
|
254
|
+
options?: TypedWhereOptions
|
|
255
|
+
): Q {
|
|
256
|
+
if (typeof where === 'function') {
|
|
257
|
+
const key = getSqlKey<Type>(
|
|
258
|
+
where,
|
|
259
|
+
(builder as unknown as SelectQueryBuilder<Type>).alias,
|
|
260
|
+
options?.useDoubleQuotes
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
// .andWhere(`"table"."column" IN (:...values)`, { values: ['value'] })
|
|
264
|
+
return builder[method](`${key} ${conditions}`, parameters);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return builder;
|
|
268
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { ObjectLiteral } from 'typeorm';
|
|
3
|
+
import { ColumnValueType, EntityOnlyWithRelations, EntityWithoutRelations } from './typeorm.types';
|
|
4
|
+
|
|
5
|
+
export class KeyHolder {
|
|
6
|
+
constructor(public keys: string[] = []) {
|
|
7
|
+
this.keys = [...keys];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
toSql(length: number = 2, addDobleQuotes = true) {
|
|
11
|
+
const string = this.toString(length);
|
|
12
|
+
const sql = addDobleQuotes ? `"${string.replace(/\./g, '"."')}"` : string;
|
|
13
|
+
|
|
14
|
+
return sql;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
toString(length = 2) {
|
|
18
|
+
const keys = this.keys.slice(0, length);
|
|
19
|
+
const string = keys.join('.');
|
|
20
|
+
|
|
21
|
+
return string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
valueOf() {
|
|
25
|
+
return this.toString();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
[Symbol.toPrimitive]() {
|
|
29
|
+
return this.toString();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
add(key: string | symbol) {
|
|
33
|
+
if (
|
|
34
|
+
typeof key !== 'symbol' &&
|
|
35
|
+
!Object.getOwnPropertyNames(this).includes(key) && // check of getOwnPropertyNames(this) is questionable
|
|
36
|
+
!Object.getOwnPropertyNames(KeyHolder.prototype).includes(key)
|
|
37
|
+
) {
|
|
38
|
+
this.keys.push(key);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class TypedProxy {
|
|
46
|
+
public static defaultHandler = {};
|
|
47
|
+
|
|
48
|
+
public static create<T extends ObjectLiteral>(obj: object, handler = TypedProxy.defaultHandler) {
|
|
49
|
+
return new Proxy(obj, handler) as T;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class KeyProxy {
|
|
54
|
+
public static defaultHandler: ProxyHandler<KeyHolder> = {
|
|
55
|
+
get(target, key, receiver) {
|
|
56
|
+
// for each key create new independent layer of KeyProxy
|
|
57
|
+
const newKeyHolder = new KeyHolder(target.keys).add(key);
|
|
58
|
+
const newLayer = TypedProxy.create<ObjectLiteral>(newKeyHolder, KeyProxy.defaultHandler);
|
|
59
|
+
|
|
60
|
+
return Reflect.get(target, key, receiver) ?? newLayer;
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
public static create<T extends ObjectLiteral>() {
|
|
65
|
+
return TypedProxy.create<T>(new KeyHolder(), KeyProxy.defaultHandler);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type KeyProxyCallback<T extends ObjectLiteral> = (proxy: T) => ColumnValueType | Array<ColumnValueType>;
|
|
70
|
+
export type RelationalKeyProxyCallback<T extends ObjectLiteral> = (
|
|
71
|
+
proxy: EntityOnlyWithRelations<T>
|
|
72
|
+
) => ColumnValueType;
|
|
73
|
+
export type NonRelationalKeyProxyCallback<T extends ObjectLiteral> = (
|
|
74
|
+
proxy: EntityWithoutRelations<T>
|
|
75
|
+
) => ColumnValueType;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { BaseEntity, ObjectLiteral } from 'typeorm';
|
|
3
|
+
|
|
4
|
+
export type SimpleColumnType = string | number | boolean | Date | null;
|
|
5
|
+
|
|
6
|
+
export type ColumnValueType = SimpleColumnType | undefined | object | ObjectLiteral | ':value';
|
|
7
|
+
|
|
8
|
+
export type RelationColumnsType<ColumnType, Key> = ColumnType extends SimpleColumnType | ((...args: any[]) => any)
|
|
9
|
+
? never
|
|
10
|
+
: ColumnType extends BaseEntity | BaseEntity[] | ObjectLiteral | ObjectLiteral[]
|
|
11
|
+
? Key
|
|
12
|
+
: never;
|
|
13
|
+
export type NonRelationColumnsType<ColumnType, Key> = ColumnType extends SimpleColumnType ? Key : never;
|
|
14
|
+
|
|
15
|
+
export type RelationPropertyNames<Type> = {
|
|
16
|
+
[Key in keyof Type]: RelationColumnsType<Type[Key], Key>;
|
|
17
|
+
}[keyof Type] &
|
|
18
|
+
string;
|
|
19
|
+
export type NonRelationPropertyNames<Type> = {
|
|
20
|
+
[Key in keyof Type]: NonRelationColumnsType<Type[Key], Key>;
|
|
21
|
+
}[keyof Type] &
|
|
22
|
+
string;
|
|
23
|
+
|
|
24
|
+
export type EntityOnlyWithRelations<Entity extends ObjectLiteral> = {
|
|
25
|
+
[Key in RelationPropertyNames<Entity>]: Entity[Key];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type EntityWithoutRelations<Entity extends ObjectLiteral> = {
|
|
29
|
+
[Key in NonRelationPropertyNames<Entity>]: Entity[Key];
|
|
30
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NonFunctionPropertyNames } from "../util-types";
|
|
2
|
+
|
|
3
|
+
export type OrderDirection = 'asc' | 'desc' | 'ASC' | 'DESC';
|
|
4
|
+
|
|
5
|
+
export type NullsOrder = 'first' | 'last' | 'FIRST' | 'LAST';
|
|
6
|
+
|
|
7
|
+
export type OrderParam<Entity> = {
|
|
8
|
+
field: NonFunctionPropertyNames<Required<Entity>> | string;
|
|
9
|
+
direction?: OrderDirection;
|
|
10
|
+
nulls?: NullsOrder;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type OrderType = {
|
|
14
|
+
selector: string;
|
|
15
|
+
order: 'ASC' | 'DESC';
|
|
16
|
+
nulls?: 'NULLS FIRST' | 'NULLS LAST';
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export interface OrderFilter<Entity> {
|
|
20
|
+
orderBy?: Array<OrderParam<Entity>>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ObjectLiteral } from "typeorm";
|
|
2
|
+
import { ColumnValueType } from "../column.types";
|
|
3
|
+
import { EntityOnlyWithRelations, EntityWithoutRelations } from "../relations.types";
|
|
4
|
+
|
|
5
|
+
export type KeyProxyCallback<T extends ObjectLiteral> = (proxy: T) => ColumnValueType | Array<ColumnValueType>;
|
|
6
|
+
export type RelationalKeyProxyCallback<T extends ObjectLiteral> = (
|
|
7
|
+
proxy: EntityOnlyWithRelations<T>
|
|
8
|
+
) => ColumnValueType;
|
|
9
|
+
export type NonRelationalKeyProxyCallback<T extends ObjectLiteral> = (
|
|
10
|
+
proxy: EntityWithoutRelations<T>
|
|
11
|
+
) => ColumnValueType;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { BaseEntity, ObjectLiteral } from 'typeorm';
|
|
2
|
+
import { SimpleColumnType } from './column.types';
|
|
3
|
+
|
|
4
|
+
export type RelationColumnsType<ColumnType, Key> = ColumnType extends
|
|
5
|
+
| SimpleColumnType
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
| ((...args: any[]) => any)
|
|
8
|
+
? never
|
|
9
|
+
: ColumnType extends
|
|
10
|
+
| BaseEntity
|
|
11
|
+
| BaseEntity[]
|
|
12
|
+
| ObjectLiteral
|
|
13
|
+
| ObjectLiteral[]
|
|
14
|
+
? Key
|
|
15
|
+
: never;
|
|
16
|
+
export type NonRelationColumnsType<ColumnType, Key> =
|
|
17
|
+
ColumnType extends SimpleColumnType ? Key : never;
|
|
18
|
+
|
|
19
|
+
export type RelationPropertyNames<Type> = {
|
|
20
|
+
[Key in keyof Type]: RelationColumnsType<Type[Key], Key>;
|
|
21
|
+
}[keyof Type] &
|
|
22
|
+
string;
|
|
23
|
+
export type NonRelationPropertyNames<Type> = {
|
|
24
|
+
[Key in keyof Type]: NonRelationColumnsType<Type[Key], Key>;
|
|
25
|
+
}[keyof Type] &
|
|
26
|
+
string;
|
|
27
|
+
|
|
28
|
+
export type EntityOnlyWithRelations<Entity extends ObjectLiteral> = {
|
|
29
|
+
[Key in RelationPropertyNames<Entity>]: Entity[Key];
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type EntityWithoutRelations<Entity extends ObjectLiteral> = {
|
|
33
|
+
[Key in NonRelationPropertyNames<Entity>]: Entity[Key];
|
|
34
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
export type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never }[keyof T] &
|
|
3
|
+
string;
|
|
4
|
+
export type NonFunctionPropertyNames<T> = {
|
|
5
|
+
[K in keyof T]: T[K] extends (...args: any[]) => any ? never : K;
|
|
6
|
+
}[keyof T] &
|
|
7
|
+
string;
|
|
8
|
+
export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { stringToSQLIdentifier } from './sql.utils';
|
|
2
|
+
|
|
3
|
+
export class Identifier {
|
|
4
|
+
private readonly useAlias: boolean;
|
|
5
|
+
|
|
6
|
+
constructor(
|
|
7
|
+
public readonly field: string,
|
|
8
|
+
public readonly alias?: string,
|
|
9
|
+
private readonly useDoubleQuotes?: boolean
|
|
10
|
+
) {
|
|
11
|
+
this.useAlias = this.calcUseAlias();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
fieldAsAlias(): string {
|
|
15
|
+
if (this.useAlias) {
|
|
16
|
+
return `${this.fieldSql} AS ${this.aliasSql}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return this.fieldSql;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
fieldIdentifier(): string {
|
|
23
|
+
if (this.useAlias) {
|
|
24
|
+
return `${this.aliasSql}.${this.fieldSql}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return this.fieldSql;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get aliasSql(): string | undefined {
|
|
31
|
+
return Identifier.aliasToSql(this.alias, this.useDoubleQuotes);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get fieldSql(): string {
|
|
35
|
+
return Identifier.fieldToSql(this.field, this.useDoubleQuotes);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* PRIVATE */
|
|
39
|
+
|
|
40
|
+
private calcUseAlias() {
|
|
41
|
+
return !!this.alias && !this.field.includes('.');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* STATIC */
|
|
45
|
+
|
|
46
|
+
static fieldToSql(field: string, useDoubleQuotes?: boolean): string {
|
|
47
|
+
return this.toIdentifier(field, useDoubleQuotes);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static aliasToSql(
|
|
51
|
+
alias: string | undefined,
|
|
52
|
+
useDoubleQuotes?: boolean
|
|
53
|
+
): string | undefined {
|
|
54
|
+
return alias ? this.toIdentifier(alias, useDoubleQuotes) : undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static toIdentifier(value: string, useDoubleQuotes?: boolean): string {
|
|
58
|
+
return useDoubleQuotes ? stringToSQLIdentifier(value) : value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defaultPageSize } from "../constants";
|
|
2
|
+
import { PaginationFilter } from "../types/interfaces/pagination.interface";
|
|
3
|
+
|
|
4
|
+
export const getLimitAndOffset = ({ page, pageSize}: PaginationFilter) => {
|
|
5
|
+
if (!page || page < 1) {
|
|
6
|
+
page = 1;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (!pageSize || pageSize < 1) {
|
|
10
|
+
pageSize = defaultPageSize;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const offset = (page >= 1 ? page - 1 : 0) * pageSize;
|
|
14
|
+
const limit = pageSize;
|
|
15
|
+
|
|
16
|
+
return { limit, offset };
|
|
17
|
+
}
|