@pcg/core 1.0.0-alpha.0 → 1.0.0-alpha.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 +21 -1189
- package/dist/index.js +76 -1867
- package/dist/index.js.map +1 -1
- package/package.json +16 -3
- package/.turbo/turbo-build.log +0 -15
- package/CHANGELOG.md +0 -7
- package/src/abstracts/index.ts +0 -3
- package/src/abstracts/nestjs-resource-service.ts +0 -154
- package/src/abstracts/nestjs-service.ts +0 -25
- package/src/configs/app.config.ts +0 -185
- package/src/configs/db.config.ts +0 -122
- package/src/configs/index.ts +0 -4
- package/src/configs/logger.config.ts +0 -62
- package/src/context/action-context.ts +0 -34
- package/src/context/current-user.ts +0 -49
- package/src/context/index.ts +0 -5
- package/src/context/platform-method-context.ts +0 -5
- package/src/context/service-method-context.ts +0 -47
- package/src/db/snake-naming.strategy.ts +0 -277
- package/src/enums/app-env.enum.ts +0 -36
- package/src/enums/app-mode.enum.ts +0 -5
- package/src/enums/app-server.enum.ts +0 -39
- package/src/enums/index.ts +0 -4
- package/src/enums/worker-mode.enum.ts +0 -11
- package/src/errors/access-denied.error.ts +0 -18
- package/src/errors/bad-request.error.ts +0 -9
- package/src/errors/forbidden.error.ts +0 -9
- package/src/errors/index.ts +0 -8
- package/src/errors/input-validation.error.ts +0 -16
- package/src/errors/nest-error.filter.ts +0 -70
- package/src/errors/nest-error.ts +0 -63
- package/src/errors/not-found.error.ts +0 -9
- package/src/errors/unauthorized.error.ts +0 -9
- package/src/exceptions/http-exception-response.ts +0 -34
- package/src/exceptions/http-exceptions.filter.ts +0 -95
- package/src/index.ts +0 -32
- package/src/jwt/extractors.ts +0 -80
- package/src/jwt/types.ts +0 -209
- package/src/logger/classes/logger-factory.ts +0 -54
- package/src/logger/classes/logger.ts +0 -340
- package/src/logger/classes/nest-system-logger.ts +0 -63
- package/src/logger/classes/typeorm-logger.ts +0 -83
- package/src/logger/index.ts +0 -20
- package/src/logger/logger.constants.ts +0 -24
- package/src/logger/logger.interfaces.ts +0 -98
- package/src/logger/logger.module.ts +0 -45
- package/src/logger/logger.providers.ts +0 -140
- package/src/logger/winston.tools.ts +0 -241
- package/src/middlewares/app.middleware.ts +0 -26
- package/src/middlewares/index.ts +0 -1
- package/src/modules/hooks/base-hook.ts +0 -64
- package/src/modules/hooks/decorators/on-hook.decorator.ts +0 -19
- package/src/modules/hooks/hooks.module.ts +0 -10
- package/src/modules/hooks/hooks.service.ts +0 -28
- package/src/modules/hooks/index.ts +0 -11
- package/src/modules/id/id.module.ts +0 -26
- package/src/modules/id/id.service.ts +0 -57
- package/src/modules/id/index.ts +0 -2
- package/src/modules/postgres-pubsub/index.ts +0 -3
- package/src/modules/postgres-pubsub/postgres-pubsub.module.ts +0 -14
- package/src/modules/postgres-pubsub/postgres-pubsub.ts +0 -461
- package/src/pagination/constants.ts +0 -9
- package/src/pagination/cursor/cursor-pagination.exception.ts +0 -16
- package/src/pagination/cursor/cursor-pagination.helpers.ts +0 -145
- package/src/pagination/cursor/cursor-pagination.input.ts +0 -96
- package/src/pagination/cursor/cursor-pagination.types.ts +0 -127
- package/src/pagination/index.ts +0 -9
- package/src/pagination/offset/offset-pagination.exception.ts +0 -15
- package/src/pagination/offset/offset-pagination.helpers.ts +0 -122
- package/src/pagination/offset/offset-pagination.input.ts +0 -30
- package/src/pagination/offset/offset-pagination.types.ts +0 -82
- package/src/pagination/tools.ts +0 -53
- package/src/tools/compose.ts +0 -92
- package/src/tools/convert-to-bigint.ts +0 -27
- package/src/tools/create-list-meta.ts +0 -64
- package/src/tools/define-statuses.ts +0 -15
- package/src/tools/env.ts +0 -139
- package/src/tools/fetch-total-with-query.ts +0 -48
- package/src/tools/generate-entity-id.ts +0 -23
- package/src/tools/get-request-language.ts +0 -13
- package/src/tools/is-object.ts +0 -10
- package/src/tools/postgres/locale-to-pg-collate.ts +0 -21
- package/src/tools/remove-undefined-properties.ts +0 -20
- package/src/tools/request-id.ts +0 -25
- package/src/tools/stringify-opts.ts +0 -20
- package/src/tools/typeorm/add-filter.ts +0 -164
- package/src/tools/typeorm/ensure-inner-join.ts +0 -36
- package/src/tools/typeorm/ensure-left-join.ts +0 -36
- package/src/tools/typeorm/is-alias-already-busy.ts +0 -25
- package/src/tools/wait.ts +0 -26
- package/src/types/express-request.ts +0 -8
- package/src/types/list-mehod-options.ts +0 -32
- package/src/types/list-meta.ts +0 -16
- package/src/types/maybe.ts +0 -2
- package/src/validation/index.ts +0 -1
- package/src/validation/validation-pipe.ts +0 -14
- package/tsconfig.lib.json +0 -9
- package/tsdown.config.ts +0 -15
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { ListMeta } from '#/types/list-meta';
|
|
2
|
-
import type { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
|
|
3
|
-
import { fetchTotalWithQuery } from './fetch-total-with-query.js';
|
|
4
|
-
|
|
5
|
-
export interface CreateListMetaOptions<T extends ObjectLiteral> {
|
|
6
|
-
/**
|
|
7
|
-
* Typeorm query builder
|
|
8
|
-
*/
|
|
9
|
-
query: SelectQueryBuilder<T>;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* If true, total count will be calculated by additional SELECT COUNT.
|
|
13
|
-
*/
|
|
14
|
-
needCountTotal?: boolean;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Limit of items
|
|
18
|
-
*/
|
|
19
|
-
limit?: number;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Offset of items
|
|
23
|
-
*/
|
|
24
|
-
offset?: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Create list meta object
|
|
29
|
-
* @returns list meta object
|
|
30
|
-
* @example
|
|
31
|
-
* class UsersService {
|
|
32
|
-
* async getMany(opts: GetManyUsersOptions): Promise<[User[], ListMeta]> {
|
|
33
|
-
* ...
|
|
34
|
-
* return Promise.all([
|
|
35
|
-
* query.getMany(),
|
|
36
|
-
* createListMeta<User>({
|
|
37
|
-
* query,
|
|
38
|
-
* needCountTotal,
|
|
39
|
-
* limit,
|
|
40
|
-
* offset,
|
|
41
|
-
* }),
|
|
42
|
-
* ]);
|
|
43
|
-
* }
|
|
44
|
-
*/
|
|
45
|
-
export const createListMeta = async <T extends ObjectLiteral>(
|
|
46
|
-
{
|
|
47
|
-
query,
|
|
48
|
-
needCountTotal = false,
|
|
49
|
-
limit,
|
|
50
|
-
offset,
|
|
51
|
-
}: CreateListMetaOptions<T>,
|
|
52
|
-
): Promise<ListMeta> => {
|
|
53
|
-
const meta: ListMeta = {
|
|
54
|
-
limit,
|
|
55
|
-
offset,
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
if (needCountTotal) {
|
|
59
|
-
meta.total = await fetchTotalWithQuery(query);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return meta;
|
|
63
|
-
};
|
|
64
|
-
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Define statuses. Returns array of statuses from filter or default statuses
|
|
3
|
-
* @param statuses - array of statuses from filter. Can be undefined
|
|
4
|
-
* @param defaultStatuses - array of default statuses
|
|
5
|
-
* @returns final array of statuses
|
|
6
|
-
* @example
|
|
7
|
-
* const statuses = defineStatuses(['active', 'pending'], ['active']);
|
|
8
|
-
* // statuses = ['active', 'pending']
|
|
9
|
-
*
|
|
10
|
-
* const statuses = defineStatuses(undefined, ['active']);
|
|
11
|
-
* // statuses = ['active']
|
|
12
|
-
*/
|
|
13
|
-
export const defineStatuses = <T>(statuses: T[] | undefined, defaultStatuses: T[]) => {
|
|
14
|
-
return Array.isArray(statuses) ? statuses : defaultStatuses;
|
|
15
|
-
};
|
package/src/tools/env.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { Type as ClassConstructor } from '@nestjs/common';
|
|
2
|
-
import { plainToInstance } from 'class-transformer';
|
|
3
|
-
import { validateSync } from 'class-validator';
|
|
4
|
-
|
|
5
|
-
import { AppEnv } from '#/enums/app-env.enum';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Validate environment variables using class-validator
|
|
9
|
-
*
|
|
10
|
-
* @param cls - class with environment variables
|
|
11
|
-
* @throws Error if validation fails
|
|
12
|
-
* @returns validated config as typed object
|
|
13
|
-
* @example
|
|
14
|
-
* ```ts
|
|
15
|
-
* export class AppConfigEnvironmentVariables {
|
|
16
|
-
* @Type(() => Number)
|
|
17
|
-
* @IsNumber()
|
|
18
|
-
* PORT = 3000;
|
|
19
|
-
* }
|
|
20
|
-
*
|
|
21
|
-
* const env = validateEnv(AppConfigEnvironmentVariables); // typed object
|
|
22
|
-
* // env.PORT is now a number
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
export const validateEnv = <T>(cls: ClassConstructor<T>): T => {
|
|
26
|
-
const validatedConfig = plainToInstance(
|
|
27
|
-
cls,
|
|
28
|
-
process.env,
|
|
29
|
-
{
|
|
30
|
-
enableImplicitConversion: true,
|
|
31
|
-
},
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
const errors = validateSync(validatedConfig as unknown as object, {
|
|
35
|
-
skipMissingProperties: false,
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
if (errors.length > 0) {
|
|
39
|
-
throw new Error(errors.toString());
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return validatedConfig;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Returns a string with a dash prefix based on the current environment.
|
|
47
|
-
* If the environment is development or local, returns '-dev'.
|
|
48
|
-
* If the environment is stage, returns '-stage'.
|
|
49
|
-
* Otherwise, returns an empty string.
|
|
50
|
-
*
|
|
51
|
-
* @returns a string with a dash prefix based on the current environment
|
|
52
|
-
* @example
|
|
53
|
-
* ```typescript
|
|
54
|
-
* const name = `my-app${withDashEnv()}`;
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
export const withDashEnv = () => {
|
|
58
|
-
if (process.env.APP_ENV === AppEnv.DEVELOPMENT || process.env.APP_ENV === AppEnv.LOCAL || process.env.APP_ENV === AppEnv.TEST) {
|
|
59
|
-
return '-dev';
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (process.env.APP_ENV === AppEnv.STAGE) {
|
|
63
|
-
return '-stage';
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return '';
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Returns a string with a dash prefix based on the current environment.
|
|
71
|
-
* If the environment is development or local, returns '.dev'.
|
|
72
|
-
* If the environment is stage, returns '.stage'.
|
|
73
|
-
* Otherwise, returns an empty string.
|
|
74
|
-
*
|
|
75
|
-
* @returns a string with a dot prefix based on the current environment
|
|
76
|
-
* @example
|
|
77
|
-
* ```typescript
|
|
78
|
-
* const name = `config${withDotEnv()}`;
|
|
79
|
-
* ```
|
|
80
|
-
*/
|
|
81
|
-
export const withDotEnv = () => {
|
|
82
|
-
if (process.env.APP_ENV === AppEnv.DEVELOPMENT || process.env.APP_ENV === AppEnv.LOCAL || process.env.APP_ENV === AppEnv.TEST) {
|
|
83
|
-
return '.dev';
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (process.env.APP_ENV === AppEnv.STAGE) {
|
|
87
|
-
return '.stage';
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return '';
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Returns a string with a colon prefix based on the current environment.
|
|
95
|
-
* If the environment is development or local, returns ':dev'.
|
|
96
|
-
* If the environment is stage, returns ':stage'.
|
|
97
|
-
* Otherwise, returns an empty string.
|
|
98
|
-
*
|
|
99
|
-
* @returns a string with a colon prefix based on the current environment
|
|
100
|
-
* @example
|
|
101
|
-
* ```typescript
|
|
102
|
-
* const name = `my:app${withColonEnv()}`;
|
|
103
|
-
* ```
|
|
104
|
-
*/
|
|
105
|
-
export const withColonEnv = () => {
|
|
106
|
-
if (process.env.APP_ENV === AppEnv.DEVELOPMENT || process.env.APP_ENV === AppEnv.LOCAL || process.env.APP_ENV === AppEnv.TEST) {
|
|
107
|
-
return ':dev';
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (process.env.APP_ENV === AppEnv.STAGE) {
|
|
111
|
-
return ':stage';
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return '';
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Returns a string with an underscore prefix based on the current environment.
|
|
119
|
-
* If the environment is development or local, returns '_dev'.
|
|
120
|
-
* If the environment is stage, returns '_stage'.
|
|
121
|
-
* Otherwise, returns an empty string.
|
|
122
|
-
*
|
|
123
|
-
* @returns a string with an underscore prefix based on the current environment
|
|
124
|
-
* @example
|
|
125
|
-
* ```typescript
|
|
126
|
-
* const name = `my_app${withUnderscoreEnv()}`;
|
|
127
|
-
* ```
|
|
128
|
-
*/
|
|
129
|
-
export const withUnderscoreEnv = () => {
|
|
130
|
-
if (process.env.APP_ENV === AppEnv.DEVELOPMENT || process.env.APP_ENV === AppEnv.LOCAL || process.env.APP_ENV === AppEnv.TEST) {
|
|
131
|
-
return '_dev';
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (process.env.APP_ENV === AppEnv.STAGE) {
|
|
135
|
-
return '_stage';
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return '';
|
|
139
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Returns total count of items with typeorm query
|
|
5
|
-
* @param query - typeorm query builder
|
|
6
|
-
* @returns total count of items
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Returns total count of items with typeorm query
|
|
10
|
-
* @param query - typeorm query builder
|
|
11
|
-
* @returns total count of items
|
|
12
|
-
*/
|
|
13
|
-
export const fetchTotalWithQuery = async <T extends ObjectLiteral>(
|
|
14
|
-
query: SelectQueryBuilder<T>,
|
|
15
|
-
): Promise<number> => {
|
|
16
|
-
const totalQueryBuilder = query.clone();
|
|
17
|
-
|
|
18
|
-
// Clear any pagination settings
|
|
19
|
-
totalQueryBuilder
|
|
20
|
-
.offset(undefined)
|
|
21
|
-
.limit(undefined)
|
|
22
|
-
.skip(undefined)
|
|
23
|
-
.take(undefined)
|
|
24
|
-
.orderBy();
|
|
25
|
-
|
|
26
|
-
const hasDistinctOn = totalQueryBuilder.expressionMap.selectDistinctOn && totalQueryBuilder.expressionMap.selectDistinctOn.length > 0;
|
|
27
|
-
const isGrouped = totalQueryBuilder.expressionMap.groupBys && totalQueryBuilder.expressionMap.groupBys.length > 0;
|
|
28
|
-
|
|
29
|
-
// Check if the original query has DISTINCT ON or GROUP BY
|
|
30
|
-
if (hasDistinctOn || isGrouped) {
|
|
31
|
-
// Wrap the query (either with DISTINCT ON or GROUP BY) in a subquery and count the results
|
|
32
|
-
const subQuery = totalQueryBuilder.getQuery();
|
|
33
|
-
|
|
34
|
-
const result = await query.connection
|
|
35
|
-
.createQueryBuilder()
|
|
36
|
-
.select('COUNT(*)', 'rowsCount')
|
|
37
|
-
.from(`(${subQuery})`, 'subQuery')
|
|
38
|
-
.setParameters(totalQueryBuilder.getParameters())
|
|
39
|
-
.getRawOne<{
|
|
40
|
-
rowsCount: number;
|
|
41
|
-
}>();
|
|
42
|
-
|
|
43
|
-
return result?.rowsCount ?? 0;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// If no DISTINCT ON or GROUP BY, just get the count directly
|
|
47
|
-
return await totalQueryBuilder.getCount();
|
|
48
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { createRandomString } from '@pcg/text-kit';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Generates a unique entity identifier by combining product name, entity prefix, delimiter, and random string.
|
|
5
|
-
*
|
|
6
|
-
* @param product - The product short name to include in the entity ID (e.g., 'fwd' for Forward)
|
|
7
|
-
* @param prefix - The entity type prefix to include in the entity ID (e.g., 'u' for user, 'org' for organization)
|
|
8
|
-
* @param delimiter - The delimiter to separate components (default: ':')
|
|
9
|
-
* @param size - The length of the random string component (default: 11)
|
|
10
|
-
* @returns A formatted entity ID string in the format: `${product}${prefix}${delimiter}${randomString}`
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```typescript
|
|
14
|
-
* generateEntityId('fwd', 'org')
|
|
15
|
-
* // Returns: 'fwdorg:A1b2C3d4E5f'
|
|
16
|
-
*
|
|
17
|
-
* generateEntityId('myapp', 'u', '_', 8)
|
|
18
|
-
* // Returns: 'myappuser_A1b2C3d4'
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export const generateEntityId = (product: string, prefix: string, delimiter = ':', size = 11): string => {
|
|
22
|
-
return `${product}${prefix}${delimiter}${createRandomString(size)}`;
|
|
23
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { parse } from 'accept-language-parser';
|
|
2
|
-
|
|
3
|
-
import { NestExpressRequest } from '#/types/express-request';
|
|
4
|
-
|
|
5
|
-
export const getRequestLanguage = (req: NestExpressRequest, fallbackLanguage: string): string => {
|
|
6
|
-
const headers = req?.headers as ({
|
|
7
|
-
['accept-language']?: string;
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
return parse(headers['accept-language'])
|
|
11
|
-
?.[0]
|
|
12
|
-
?.code ?? fallbackLanguage;
|
|
13
|
-
};
|
package/src/tools/is-object.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Checks if the given value is an object (not an array).
|
|
3
|
-
* @param {unknown} obj - The value to check.
|
|
4
|
-
* @returns {boolean} Returns true if `obj` is an object, false otherwise.
|
|
5
|
-
* @example
|
|
6
|
-
* isObject({ a: 1 }); // Returns true
|
|
7
|
-
* isObject([1, 2, 3]); // Returns false
|
|
8
|
-
*/
|
|
9
|
-
export const isObject = (obj: unknown): obj is Record<string, unknown> =>
|
|
10
|
-
obj !== null && !!obj && typeof obj === 'object' && !Array.isArray(obj);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Converts a locale string to a PostgreSQL collation identifier.
|
|
3
|
-
*
|
|
4
|
-
* @param locale - The locale string to convert (e.g., 'uk', 'en')
|
|
5
|
-
* @returns The PostgreSQL collation identifier (e.g., 'uk_UA', 'en_US')
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* localeToPgCollate('uk') // returns 'uk_UA'
|
|
10
|
-
* localeToPgCollate('en') // returns 'en_US'
|
|
11
|
-
* ```
|
|
12
|
-
*/
|
|
13
|
-
export const localeToPgCollate = (locale: string) => {
|
|
14
|
-
let collate = 'en_US';
|
|
15
|
-
|
|
16
|
-
if (locale === 'uk') {
|
|
17
|
-
collate = 'uk_UA';
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return collate;
|
|
21
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
type DefinedValuesOnly<T> = {
|
|
2
|
-
[K in keyof T]: T[K] extends undefined ? never : K;
|
|
3
|
-
}[keyof T];
|
|
4
|
-
|
|
5
|
-
type UndefinedRemoved<T> = {
|
|
6
|
-
[K in DefinedValuesOnly<T>]: T[K];
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const removeUndefinedProperties = <T extends object>(obj: T): UndefinedRemoved<T> => {
|
|
10
|
-
const result: Partial<UndefinedRemoved<T>> = {
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
for (const key in obj) {
|
|
14
|
-
if (Object.prototype.hasOwnProperty.call(obj, key) && obj[key as keyof T] !== undefined) {
|
|
15
|
-
(result as Record<string, unknown>)[key] = obj[key as keyof T];
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return result as UndefinedRemoved<T>;
|
|
20
|
-
};
|
package/src/tools/request-id.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { createRandomString } from '@pcg/text-kit';
|
|
2
|
-
|
|
3
|
-
import { NestExpressRequest } from '#/types/express-request';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export const generateRequestId = (appShortName: string) => {
|
|
7
|
-
return `${appShortName}req:${createRandomString()}`;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const extractRequestId = (req: NestExpressRequest): string => {
|
|
11
|
-
const headers = req?.headers as ({
|
|
12
|
-
'x-request-id'?: string;
|
|
13
|
-
'x-cloud-trace-context'?: string;
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
if (headers?.['x-request-id']) {
|
|
17
|
-
return headers['x-request-id'];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (headers['x-cloud-trace-context']) {
|
|
21
|
-
return req.appShortname + `req:${headers['x-cloud-trace-context']}`;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return generateRequestId(req.appShortname);
|
|
25
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Converts an object into a human-readable string representation.
|
|
3
|
-
*
|
|
4
|
-
* Takes an object and transforms it into a string where each key-value pair
|
|
5
|
-
* is formatted as "key JSON-value" and all pairs are joined with " and ".
|
|
6
|
-
*
|
|
7
|
-
* @param opts - The object to stringify
|
|
8
|
-
* @returns A string representation of the object with entries joined by " and "
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```ts
|
|
12
|
-
* stringifyOpts({ name: 'John', age: 30 })
|
|
13
|
-
* // Returns: 'name "John" and age 30'
|
|
14
|
-
* ```
|
|
15
|
-
*/
|
|
16
|
-
export const stringifyOpts = (opts: object) => {
|
|
17
|
-
return Object.entries(opts)
|
|
18
|
-
.map(([key, value]) => `${key} ${JSON.stringify(value)}`)
|
|
19
|
-
.join(' and ');
|
|
20
|
-
};
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Brackets, In, IsNull, ObjectLiteral, SelectQueryBuilder, WhereExpressionBuilder,
|
|
3
|
-
} from 'typeorm';
|
|
4
|
-
|
|
5
|
-
import { MaybeNull } from '#/types/maybe';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Adds a filter condition to a TypeORM SelectQueryBuilder based on the provided field and value(s).
|
|
9
|
-
*
|
|
10
|
-
* Handles three types of filtering:
|
|
11
|
-
* - Single value filtering: when a single non-null value is provided
|
|
12
|
-
* - Multiple value filtering: when an array of values is provided
|
|
13
|
-
* - Null value filtering: when null is explicitly provided as the filter value
|
|
14
|
-
*
|
|
15
|
-
* @template T - The entity type that extends ObjectLiteral
|
|
16
|
-
* @template K - The field name key type that must be a string key of T
|
|
17
|
-
*
|
|
18
|
-
* @param query - The TypeORM SelectQueryBuilder instance to add the filter to
|
|
19
|
-
* @param fieldName - The name of the field to filter by, must be a valid key of entity T
|
|
20
|
-
* @param valueOrValues - The filter value(s). Can be:
|
|
21
|
-
* - A single value of type T[K]
|
|
22
|
-
* - An array of values of type T[K]
|
|
23
|
-
* - null to filter for null values
|
|
24
|
-
* - An array containing null values
|
|
25
|
-
* @example
|
|
26
|
-
* ```typescript
|
|
27
|
-
* // Single value filter
|
|
28
|
-
* addFilterByField(queryBuilder, 'status', 'active');
|
|
29
|
-
* // Multiple values filter
|
|
30
|
-
* addFilterByField(queryBuilder, 'id', [1, 2, 3]);
|
|
31
|
-
* // Null value filter
|
|
32
|
-
* addFilterByField(queryBuilder, 'deletedAt', null);
|
|
33
|
-
* ```
|
|
34
|
-
*
|
|
35
|
-
* @returns void - Modifies the query builder in place
|
|
36
|
-
*/
|
|
37
|
-
export const addFilterByField = <
|
|
38
|
-
T extends ObjectLiteral,
|
|
39
|
-
K extends (keyof T & string)
|
|
40
|
-
>(query: SelectQueryBuilder<T>, fieldName: K, valueOrValues: MaybeNull<T[K]> | MaybeNull<T[K]>[]): void => {
|
|
41
|
-
const isFilterValueMultiple = Array.isArray(valueOrValues);
|
|
42
|
-
|
|
43
|
-
if (isFilterValueMultiple) {
|
|
44
|
-
addMultipleFilter(query, fieldName, valueOrValues);
|
|
45
|
-
} else if (valueOrValues === null) {
|
|
46
|
-
addNullableFilter(query, fieldName);
|
|
47
|
-
} else {
|
|
48
|
-
addSingleFilter(query, fieldName, valueOrValues);
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Adds a filter to a TypeORM query that matches multiple values for a given column,
|
|
54
|
-
* including support for null values.
|
|
55
|
-
*
|
|
56
|
-
* @template T - The entity type that extends ObjectLiteral
|
|
57
|
-
* @template K - The key type that must be both a key of T and a string
|
|
58
|
-
* @param query - The TypeORM SelectQueryBuilder instance to add the filter to
|
|
59
|
-
* @param columnName - The name of the column to filter on
|
|
60
|
-
* @param values - An array of values to match, which may include null
|
|
61
|
-
*
|
|
62
|
-
* @remarks
|
|
63
|
-
* This function creates an OR condition that matches any of the provided values.
|
|
64
|
-
* If the values array includes null, a separate null check is added to the filter.
|
|
65
|
-
* Non-null values are handled using TypeORM's `In` operator.
|
|
66
|
-
*
|
|
67
|
-
* @example
|
|
68
|
-
* ```typescript
|
|
69
|
-
* const query = repository.createQueryBuilder('user');
|
|
70
|
-
* addMultipleFilter(query, 'status', ['active', 'pending', null]);
|
|
71
|
-
* // Generates: WHERE (status IS NULL OR status IN ('active', 'pending'))
|
|
72
|
-
* ```
|
|
73
|
-
*/
|
|
74
|
-
const addMultipleFilter = <
|
|
75
|
-
T extends ObjectLiteral,
|
|
76
|
-
K extends (keyof T & string)
|
|
77
|
-
>(query: SelectQueryBuilder<T>, columnName: K, values: MaybeNull<T[K]>[]): void => {
|
|
78
|
-
query.andWhere(new Brackets((subQuery) => {
|
|
79
|
-
if (values.includes(null)) {
|
|
80
|
-
addNullValueToMultipleFilter(subQuery, columnName);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const notNullValues = values.filter((v) => v !== null);
|
|
84
|
-
subQuery.orWhere({
|
|
85
|
-
[columnName]: In(notNullValues),
|
|
86
|
-
});
|
|
87
|
-
}));
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Adds a single filter condition to a TypeORM SelectQueryBuilder.
|
|
92
|
-
*
|
|
93
|
-
* @template T - The entity type that extends ObjectLiteral
|
|
94
|
-
* @template K - The column name type, constrained to string keys of T
|
|
95
|
-
*
|
|
96
|
-
* @param query - The SelectQueryBuilder instance to add the filter to
|
|
97
|
-
* @param columnName - The name of the column to filter on
|
|
98
|
-
* @param value - The value to filter by, must match the type of the column
|
|
99
|
-
*
|
|
100
|
-
* @returns void
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* ```typescript
|
|
104
|
-
* const query = repository.createQueryBuilder('user');
|
|
105
|
-
* addSingleFilter(query, 'email', 'user@example.com');
|
|
106
|
-
* // Results in: WHERE user.email = 'user@example.com'
|
|
107
|
-
* ```
|
|
108
|
-
*/
|
|
109
|
-
const addSingleFilter = <
|
|
110
|
-
T extends ObjectLiteral,
|
|
111
|
-
K extends (keyof T & string)
|
|
112
|
-
>(query: SelectQueryBuilder<T>, columnName: K, value: T[K]): void => {
|
|
113
|
-
query.andWhere({
|
|
114
|
-
[columnName]: value,
|
|
115
|
-
});
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Adds a nullable filter to a TypeORM query builder.
|
|
120
|
-
*
|
|
121
|
-
* This function applies a WHERE clause that filters for NULL values in the specified column.
|
|
122
|
-
* The filter is combined with existing conditions using AND logic.
|
|
123
|
-
*
|
|
124
|
-
* @template T - The entity type that extends ObjectLiteral
|
|
125
|
-
* @param query - The TypeORM SelectQueryBuilder instance to add the filter to
|
|
126
|
-
* @param columnName - The name of the column to check for NULL values
|
|
127
|
-
* @returns void
|
|
128
|
-
*
|
|
129
|
-
* @example
|
|
130
|
-
* ```typescript
|
|
131
|
-
* const query = repository.createQueryBuilder('user');
|
|
132
|
-
* addNullableFilter(query, 'deletedAt');
|
|
133
|
-
* // Results in: WHERE deletedAt IS NULL
|
|
134
|
-
* ```
|
|
135
|
-
*/
|
|
136
|
-
const addNullableFilter = <T extends ObjectLiteral>(query: SelectQueryBuilder<T>, columnName: string): void => {
|
|
137
|
-
query.andWhere({
|
|
138
|
-
[columnName]: IsNull(),
|
|
139
|
-
});
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Adds an OR condition to the query to check if the specified column is NULL.
|
|
144
|
-
*
|
|
145
|
-
* This function is used to extend filtering logic by adding a null value check
|
|
146
|
-
* as an alternative condition in a WHERE clause.
|
|
147
|
-
*
|
|
148
|
-
* @param query - The TypeORM WhereExpressionBuilder instance to which the null condition will be added
|
|
149
|
-
* @param columnName - The name of the database column to check for NULL values
|
|
150
|
-
*
|
|
151
|
-
* @returns void
|
|
152
|
-
*
|
|
153
|
-
* @example
|
|
154
|
-
* ```typescript
|
|
155
|
-
* const queryBuilder = repository.createQueryBuilder('user');
|
|
156
|
-
* addNullValueToMultipleFilter(queryBuilder, 'deletedAt');
|
|
157
|
-
* // Results in: WHERE ... OR deletedAt IS NULL
|
|
158
|
-
* ```
|
|
159
|
-
*/
|
|
160
|
-
const addNullValueToMultipleFilter = (query: WhereExpressionBuilder, columnName: string): void => {
|
|
161
|
-
query.orWhere({
|
|
162
|
-
[columnName]: IsNull(),
|
|
163
|
-
});
|
|
164
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
|
|
2
|
-
import { isAliasAlreadyBusy } from './is-alias-already-busy.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Ensures an inner join is added to the TypeORM query builder only if the alias is not already in use.
|
|
6
|
-
*
|
|
7
|
-
* This function checks if the specified alias is already being used in the query builder.
|
|
8
|
-
* If the alias is available, it adds an inner join with the provided entity, alias, and optional condition.
|
|
9
|
-
* If the alias is already busy, the function returns without making any changes to the query.
|
|
10
|
-
*
|
|
11
|
-
* @template T - The entity type that extends ObjectLiteral
|
|
12
|
-
* @param query - The TypeORM SelectQueryBuilder instance to add the inner join to
|
|
13
|
-
* @param entity - The entity class (Function) or entity name (string) to join
|
|
14
|
-
* @param alias - The alias to use for the joined entity
|
|
15
|
-
* @param condition - Optional join condition as a string
|
|
16
|
-
* @returns void
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```typescript
|
|
20
|
-
* const query = repository.createQueryBuilder('user');
|
|
21
|
-
* ensureInnerJoin(query, Profile, 'profile', 'profile.userId = user.id');
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export const ensureInnerJoin = <T extends ObjectLiteral>(
|
|
25
|
-
query: SelectQueryBuilder<T>,
|
|
26
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
27
|
-
entity: Function | string,
|
|
28
|
-
alias: string,
|
|
29
|
-
condition?: string,
|
|
30
|
-
): void => {
|
|
31
|
-
if (isAliasAlreadyBusy(query, alias)) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
query.innerJoin(entity, alias, condition);
|
|
36
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
|
|
2
|
-
import { isAliasAlreadyBusy } from './is-alias-already-busy.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Ensures a left join is added to a TypeORM query builder if the alias is not already in use.
|
|
6
|
-
*
|
|
7
|
-
* This function checks if the specified alias is already being used in the query.
|
|
8
|
-
* If the alias is available, it performs a left join with the provided entity, alias, and optional condition.
|
|
9
|
-
* If the alias is already busy, the function returns early without modifying the query.
|
|
10
|
-
*
|
|
11
|
-
* @template T - The entity type that extends ObjectLiteral
|
|
12
|
-
* @param query - The TypeORM SelectQueryBuilder instance to add the left join to
|
|
13
|
-
* @param entity - The entity class (Function) or table name (string) to join
|
|
14
|
-
* @param alias - The alias name to use for the joined entity
|
|
15
|
-
* @param condition - Optional join condition as a string (e.g., "alias.id = entity.foreignId")
|
|
16
|
-
* @returns void
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```typescript
|
|
20
|
-
* ensureLeftJoin(queryBuilder, User, 'user', 'user.id = post.userId');
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
export const ensureLeftJoin = <T extends ObjectLiteral>(
|
|
24
|
-
query: SelectQueryBuilder<T>,
|
|
25
|
-
|
|
26
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
27
|
-
entity: Function | string,
|
|
28
|
-
alias: string,
|
|
29
|
-
condition?: string,
|
|
30
|
-
): void => {
|
|
31
|
-
if (isAliasAlreadyBusy(query, alias)) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
query.leftJoin(entity, alias, condition);
|
|
36
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Checks if a given alias is already used in the query builder's join attributes.
|
|
5
|
-
*
|
|
6
|
-
* This utility function inspects the query builder's expression map to determine
|
|
7
|
-
* whether a specific alias name has already been assigned to any join attribute.
|
|
8
|
-
* This is useful to avoid alias conflicts when building complex TypeORM queries.
|
|
9
|
-
*
|
|
10
|
-
* @template T - The entity type that extends ObjectLiteral
|
|
11
|
-
* @param {SelectQueryBuilder<T>} query - The TypeORM SelectQueryBuilder instance to check
|
|
12
|
-
* @param {string} alias - The alias name to search for in the join attributes
|
|
13
|
-
* @returns {boolean} True if the alias is already used in any join attribute, false otherwise
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```typescript
|
|
17
|
-
* const query = repository.createQueryBuilder('user');
|
|
18
|
-
* const isBusy = isAliasAlreadyBusy(query, 'profile');
|
|
19
|
-
* if (!isBusy) {
|
|
20
|
-
* query.leftJoinAndSelect('user.profile', 'profile');
|
|
21
|
-
* }
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export const isAliasAlreadyBusy = <T extends ObjectLiteral>(query: SelectQueryBuilder<T>, alias: string) =>
|
|
25
|
-
query.expressionMap.joinAttributes.some((a) => a.alias.name === alias);
|