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.
Files changed (31) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +12 -0
  3. package/README.md +46 -0
  4. package/package.json +33 -0
  5. package/src/constants/index.ts +9 -0
  6. package/src/extensions/get-many-with-totals.extension.ts +62 -0
  7. package/src/extensions/index.ts +4 -0
  8. package/src/extensions/ordering.extension.ts +123 -0
  9. package/src/extensions/pagination.extension.ts +35 -0
  10. package/src/extensions/typed/index.ts +12 -0
  11. package/src/extensions/typed/typed-distinct/typed-distinct.extension.ts +38 -0
  12. package/src/extensions/typed/typed-joins/typed-joins.extension.ts +141 -0
  13. package/src/extensions/typed/typed-order-by/typed-order-by.extension.ts +73 -0
  14. package/src/extensions/typed/typed-select/typed-select.extension.ts +124 -0
  15. package/src/extensions/typed/typed-where/typed-where.extension.ts +268 -0
  16. package/src/extensions/typed/typeorm-querybuilder.types.ts +75 -0
  17. package/src/extensions/typed/typeorm.types.ts +30 -0
  18. package/src/index.ts +3 -0
  19. package/src/types/interfaces/index.ts +2 -0
  20. package/src/types/interfaces/ordering.interface.ts +21 -0
  21. package/src/types/interfaces/pagination.interface.ts +8 -0
  22. package/src/types/modules/column.types.ts +5 -0
  23. package/src/types/modules/proxy-types/proxy-callback.types.ts +11 -0
  24. package/src/types/modules/relations.types.ts +34 -0
  25. package/src/types/util-types/index.ts +8 -0
  26. package/src/utils/common.utils.ts +2 -0
  27. package/src/utils/identifier.utils.ts +60 -0
  28. package/src/utils/pagination.utils.ts +17 -0
  29. package/src/utils/proxy-key.utils.ts +133 -0
  30. package/src/utils/sql.utils.ts +24 -0
  31. 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,3 @@
1
+ export * from './extensions';
2
+
3
+ export * from './types/interfaces';
@@ -0,0 +1,2 @@
1
+ export * from './ordering.interface';
2
+ export * from './pagination.interface';
@@ -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,8 @@
1
+ export type PageSize = number;
2
+
3
+ export type PageNumber = number; // 1-based index
4
+
5
+ export interface PaginationFilter {
6
+ page?: PageNumber;
7
+ pageSize?: PageSize;
8
+ }
@@ -0,0 +1,5 @@
1
+ import { ObjectLiteral } from "typeorm";
2
+
3
+ export type SimpleColumnType = string | number | boolean | Date | null;
4
+
5
+ export type ColumnValueType = SimpleColumnType | undefined | object | ObjectLiteral;
@@ -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,2 @@
1
+ export const isNil = (val: unknown): boolean =>
2
+ typeof val === 'undefined' || val === null;
@@ -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
+ }