@tstdl/base 0.93.3 → 0.93.4

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.
@@ -36,7 +36,7 @@ export declare class AiServiceOptions {
36
36
  };
37
37
  /**
38
38
  * The default model to use for generation requests.
39
- * @default 'gemini-2.5-flash-lite'
39
+ * @default 'small'
40
40
  */
41
41
  defaultModel?: AiModel;
42
42
  }
@@ -133,6 +133,7 @@ export declare class AiService implements Resolvable<AiServiceArgument> {
133
133
  private convertContent;
134
134
  private convertFunctions;
135
135
  private convertGoogleContent;
136
+ private mapModel;
136
137
  }
137
138
  /**
138
139
  * Merges an array of streaming generation results into a single, consolidated result.
package/ai/ai.service.js CHANGED
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var _a;
8
8
  var AiService_1;
9
9
  import { FinishReason, FunctionCallingConfigMode as GoogleFunctionCallingMode, GoogleGenAI } from '@google/genai';
10
+ import { match } from 'ts-pattern';
10
11
  import { CancellationSignal } from '../cancellation/index.js';
11
12
  import { NotSupportedError } from '../errors/not-supported.error.js';
12
13
  import { Singleton } from '../injector/decorators.js';
@@ -39,7 +40,7 @@ export class AiServiceOptions {
39
40
  vertex;
40
41
  /**
41
42
  * The default model to use for generation requests.
42
- * @default 'gemini-2.5-flash-lite'
43
+ * @default 'small'
43
44
  */
44
45
  defaultModel;
45
46
  }
@@ -80,7 +81,7 @@ let AiService = AiService_1 = class AiService {
80
81
  /**
81
82
  * The default AI model to use for requests if not specified otherwise.
82
83
  */
83
- defaultModel = this.#options.defaultModel ?? 'gemini-2.5-flash-lite';
84
+ defaultModel = this.#options.defaultModel ?? 'gemini-flash-lite-latest';
84
85
  /**
85
86
  * Creates a new {@link AiSession} for managing conversational history.
86
87
  */
@@ -202,7 +203,7 @@ let AiService = AiService_1 = class AiService {
202
203
  thinkingBudget: request.generationOptions?.thinkingBudget,
203
204
  },
204
205
  };
205
- const model = request.model ?? this.defaultModel;
206
+ const model = this.mapModel(request.model);
206
207
  const maxModelTokens = await this.getModelOutputTokenLimit(model);
207
208
  const maxTotalOutputTokens = request.generationOptions?.maxOutputTokens ?? maxModelTokens;
208
209
  const inputContent = this.convertContents(request.contents);
@@ -427,6 +428,13 @@ let AiService = AiService_1 = class AiService {
427
428
  .filter(isNotNull),
428
429
  };
429
430
  }
431
+ mapModel(model) {
432
+ return match(model)
433
+ .with('small', () => 'gemini-flash-lite-latest')
434
+ .with('medium', () => 'gemini-flash-latest')
435
+ .with('large', () => 'gemini-2.5-pro')
436
+ .otherwise(() => model ?? this.defaultModel);
437
+ }
430
438
  };
431
439
  AiService = AiService_1 = __decorate([
432
440
  Singleton()
package/ai/types.d.ts CHANGED
@@ -113,8 +113,10 @@ export type FunctionCallingMode = 'auto' | 'force' | 'none';
113
113
  export type FinishReason = 'stop' | 'maxTokens' | 'unknown';
114
114
  /**
115
115
  * The specific AI model to use for a request.
116
+ *
117
+ * Aliases `small`, `medium`, and `large` map to models that change over time.
116
118
  */
117
- export type AiModel = LiteralUnion<'gemini-2.5-pro' | 'gemini-2.5-flash' | 'gemini-2.5-flash-lite', string>;
119
+ export type AiModel = LiteralUnion<'small' | 'medium' | 'large' | 'gemini-flash-latest' | 'gemini-flash-lite-latest' | 'gemini-2.5-pro' | 'gemini-2.5-flash' | 'gemini-2.5-flash-lite', string>;
118
120
  /**
119
121
  * Options to control the generation process.
120
122
  */
@@ -70,7 +70,8 @@ __decorate([
70
70
  ], DocumentValidationExecution.prototype, "completedAt", void 0);
71
71
  DocumentValidationExecution = __decorate([
72
72
  DocumentManagementTable({ name: 'validation_execution' }),
73
- Unique(['tenantId', 'id']),
73
+ Unique(['tenantId', 'id']) // required for foreign key of DocumentValidationExecutionRelatedDocument
74
+ ,
74
75
  Unique(['tenantId', 'workflowId', 'definitionId']),
75
76
  ForeignKey(() => DocumentWorkflow, ['tenantId', 'workflowId'], ['tenantId', 'id'])
76
77
  ], DocumentValidationExecution);
@@ -79,9 +79,9 @@ import { DocumentFileService } from './document-file.service.js';
79
79
  import { DocumentPropertyService } from './document-property.service.js';
80
80
  import { DocumentTagService } from './document-tag.service.js';
81
81
  import { DocumentManagementSingleton } from './singleton.js';
82
- const CLASSIFY_MODEL = 'gemini-2.5-flash-lite';
83
- const EXTRACT_MODEL = 'gemini-2.5-flash';
84
- const ASSIGN_MODEL = 'gemini-2.5-flash-lite';
82
+ const CLASSIFY_MODEL = 'small';
83
+ const EXTRACT_MODEL = 'medium';
84
+ const ASSIGN_MODEL = 'small';
85
85
  let DocumentManagementAiService = DocumentManagementAiService_1 = class DocumentManagementAiService {
86
86
  #documentCollectionService = inject(DocumentCollectionService);
87
87
  #documentTagService = inject(DocumentTagService);
@@ -4,8 +4,7 @@ import type { SchemaTestable } from '../../../schema/schema.js';
4
4
  import { DocumentValidationExecutor, type DocumentValidationExecutorContext, type DocumentValidationExecutorResult } from './validator.js';
5
5
  export declare const AiValidationDifficulty: {
6
6
  readonly Easy: "easy";
7
- readonly MediumLow: "medium-low";
8
- readonly MediumHigh: "medium-high";
7
+ readonly Medium: "medium";
9
8
  readonly Hard: "hard";
10
9
  };
11
10
  export type AiValidationDifficulty = EnumType<typeof AiValidationDifficulty>;
@@ -13,6 +12,7 @@ export declare abstract class AiValidationExecutor<R> extends DocumentValidation
13
12
  protected readonly aiService: AiService;
14
13
  abstract readonly schema: SchemaTestable<R>;
15
14
  abstract readonly difficulty: AiValidationDifficulty;
15
+ abstract readonly thinking: boolean;
16
16
  execute(context: DocumentValidationExecutorContext): Promise<DocumentValidationExecutorResult>;
17
17
  abstract getPrompt(context: DocumentValidationExecutorContext): string | Promise<string>;
18
18
  abstract getResult(output: R): DocumentValidationExecutorResult | Promise<DocumentValidationExecutorResult>;
@@ -12,8 +12,7 @@ import { match } from 'ts-pattern';
12
12
  import { DocumentValidationExecutor } from './validator.js';
13
13
  export const AiValidationDifficulty = defineEnum('AiValidationDifficulty', {
14
14
  Easy: 'easy',
15
- MediumLow: 'medium-low',
16
- MediumHigh: 'medium-high',
15
+ Medium: 'medium',
17
16
  Hard: 'hard',
18
17
  });
19
18
  let AiValidationExecutor = class AiValidationExecutor extends DocumentValidationExecutor {
@@ -21,11 +20,11 @@ let AiValidationExecutor = class AiValidationExecutor extends DocumentValidation
21
20
  async execute(context) {
22
21
  const validationPrompt = await this.getPrompt(context);
23
22
  const model = match(this.difficulty)
24
- .with('easy', () => 'gemini-2.5-flash-lite')
25
- .with('medium-low', () => 'gemini-2.5-flash')
26
- .with('medium-high', () => 'gemini-2.5-flash')
27
- .with('hard', () => 'gemini-2.5-pro')
23
+ .with('easy', () => 'small')
24
+ .with('medium', () => 'medium')
25
+ .with('hard', () => 'large')
28
26
  .exhaustive();
27
+ const thinkingBudget = this.thinking ? -1 : 0;
29
28
  const prompt = `Deine Aufgabe ist es ein Dokument zu validieren.
30
29
 
31
30
  Validierungsaufgabe:
@@ -33,6 +32,7 @@ ${validationPrompt}`;
33
32
  const generation = await this.aiService.generate({
34
33
  model,
35
34
  generationOptions: {
35
+ thinkingBudget,
36
36
  temperature: 0.2,
37
37
  topK: 20,
38
38
  },
@@ -6,7 +6,8 @@ export declare class SingleDocumentValidationExecutor extends AiValidationExecut
6
6
  reason?: string;
7
7
  }> {
8
8
  readonly identifier = "single-document";
9
- readonly difficulty: "medium-low";
9
+ readonly difficulty: "medium";
10
+ readonly thinking = true;
10
11
  schema: import("../../../schema/index.js").ObjectSchema<{
11
12
  hasMultipleDocuments: boolean;
12
13
  reason?: string | undefined;
@@ -3,13 +3,14 @@ import { DocumentValidationResultStatus } from '../../models/document-validation
3
3
  import { AiValidationDifficulty, AiValidationExecutor } from './ai-validation-executor.js';
4
4
  export class SingleDocumentValidationExecutor extends AiValidationExecutor {
5
5
  identifier = 'single-document';
6
- difficulty = AiValidationDifficulty.MediumLow;
6
+ difficulty = AiValidationDifficulty.Medium;
7
+ thinking = true;
7
8
  schema = object({
8
9
  hasMultipleDocuments: boolean(),
9
10
  reason: optional(string()),
10
11
  });
11
12
  getPrompt() {
12
- return 'Überprüfe ob das Dokument aus mehreren Dokumenten zusammengesetzt ist. Falls ja, begründe in wenigen Worten. Antworte auf deutsch.';
13
+ return 'Überprüfe ob das Dokument aus mehreren einzelnen Dokumenten zusammengesetzt ist. Falls ja, begründe in wenigen Worten. Antworte auf deutsch.';
13
14
  }
14
15
  getResult(output) {
15
16
  if (output.hasMultipleDocuments) {
@@ -18,6 +18,7 @@ import { DocumentManagementService } from '../../document-management/server/serv
18
18
  import { configureNodeHttpServer } from '../../http/server/node/module.js';
19
19
  import { Injector, Singleton } from '../../injector/index.js';
20
20
  import { inject, injectManyAsync, runInInjectionContext } from '../../injector/inject.js';
21
+ import { PrettyPrintLogFormatter, provideConsoleLogTransport } from '../../logger/index.js';
21
22
  import { configureLocalMessageBus } from '../../message-bus/index.js';
22
23
  import { WebServerModule } from '../../module/index.js';
23
24
  import { configureS3ObjectStorage } from '../../object-storage/index.js';
@@ -157,4 +158,5 @@ Application.run('DocumentManagementTest', [
157
158
  provideInitializer(bootstrap),
158
159
  provideModule(main, WebServerModule),
159
160
  provideSignalHandler(),
161
+ provideConsoleLogTransport(PrettyPrintLogFormatter),
160
162
  ]);
@@ -0,0 +1 @@
1
+ export * from './schema-converter.js';
@@ -0,0 +1,15 @@
1
+ import { type PgEnum, type PgSchema, type PgTableWithColumns } from 'drizzle-orm/pg-core';
2
+ import type { AbstractConstructor, Enumeration } from '../../../types/index.js';
3
+ import type { EntityType } from '../../entity.js';
4
+ import type { ColumnDefinition, ColumnDefinitionsMap, PgTableFromType } from '../types.js';
5
+ type ConverterContext = {
6
+ type: AbstractConstructor;
7
+ property: string;
8
+ };
9
+ export declare const getDrizzleTableFromType: typeof _getDrizzleTableFromType;
10
+ export declare function getColumnDefinitions(table: PgTableWithColumns<any>): ColumnDefinition[];
11
+ export declare function getColumnDefinitionsMap(table: PgTableWithColumns<any>): ColumnDefinitionsMap;
12
+ export declare function _getDrizzleTableFromType<T extends EntityType, S extends string>(type: T, fallbackSchemaName?: S): PgTableFromType<T, S>;
13
+ export declare function registerEnum(enumeration: Enumeration, name: string): void;
14
+ export declare function getPgEnum(schema: string | PgSchema, enumeration: Enumeration, context?: ConverterContext): PgEnum<[string, ...string[]]>;
15
+ export {};
@@ -0,0 +1,300 @@
1
+ import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing';
2
+ import { boolean, check, doublePrecision, foreignKey, index, integer, jsonb, pgSchema, primaryKey, text, unique, uniqueIndex, uuid } from 'drizzle-orm/pg-core';
3
+ import { MultiKeyMap } from '../../../data-structures/multi-key-map.js';
4
+ import { tryGetEnumName } from '../../../enumeration/enumeration.js';
5
+ import { NotSupportedError } from '../../../errors/not-supported.error.js';
6
+ import { JsonPath } from '../../../json-path/json-path.js';
7
+ import { reflectionRegistry } from '../../../reflection/registry.js';
8
+ import { ArraySchema, BooleanSchema, DefaultSchema, EnumerationSchema, getObjectSchema, NullableSchema, NumberSchema, ObjectSchema, OptionalSchema, StringSchema, Uint8ArraySchema } from '../../../schema/index.js';
9
+ import { compareByValueSelectionToOrder, orderRest } from '../../../utils/comparison.js';
10
+ import { decodeText, encodeUtf8 } from '../../../utils/encoding.js';
11
+ import { enumValues } from '../../../utils/enum.js';
12
+ import { memoize, memoizeSingle } from '../../../utils/function/memoize.js';
13
+ import { compileDereferencer } from '../../../utils/object/dereference.js';
14
+ import { fromEntries, objectEntries } from '../../../utils/object/object.js';
15
+ import { assertDefined, assertDefinedPass, isArray, isDefined, isNotNullOrUndefined, isNull, isString, isUndefined } from '../../../utils/type-guards.js';
16
+ import { bytea, numericDate, timestamp } from '../../data-types/index.js';
17
+ import { JsonSchema } from '../../schemas/json.js';
18
+ import { NumericDateSchema } from '../../schemas/numeric-date.js';
19
+ import { TimestampSchema } from '../../schemas/timestamp.js';
20
+ import { UuidSchema } from '../../schemas/uuid.js';
21
+ import { decryptBytes, encryptBytes } from '../encryption.js';
22
+ import { convertQuery } from '../query-converter.js';
23
+ const getDbSchema = memoizeSingle(pgSchema);
24
+ export const getDrizzleTableFromType = memoize(_getDrizzleTableFromType);
25
+ const columnDefinitionsSymbol = Symbol('columnDefinitions');
26
+ const columnDefinitionsMapSymbol = Symbol('columnDefinitionsMap');
27
+ export function getColumnDefinitions(table) {
28
+ return table[columnDefinitionsSymbol];
29
+ }
30
+ export function getColumnDefinitionsMap(table) {
31
+ return table[columnDefinitionsMapSymbol];
32
+ }
33
+ export function _getDrizzleTableFromType(type, fallbackSchemaName) {
34
+ const metadata = reflectionRegistry.getMetadata(type);
35
+ assertDefined(metadata, `Type ${type.name} does not have reflection metadata.`);
36
+ const tableReflectionDatas = [];
37
+ for (let currentMetadata = metadata; isNotNullOrUndefined(currentMetadata?.parent); currentMetadata = reflectionRegistry.getMetadata(currentMetadata.parent)) {
38
+ const tableReflectionData = currentMetadata.data.tryGet('orm');
39
+ if (isDefined(tableReflectionData)) {
40
+ tableReflectionDatas.push(tableReflectionData);
41
+ }
42
+ }
43
+ const mergedTableReflectionData = tableReflectionDatas.reduceRight((merged, data) => ({ ...merged, ...data }), {});
44
+ const tableReflectionData = tableReflectionDatas[0];
45
+ const schema = assertDefinedPass(mergedTableReflectionData.schema ?? fallbackSchemaName, 'Table schema not provided');
46
+ const tableName = tableReflectionData?.name ?? getDefaultTableName(type);
47
+ const dbSchema = getDbSchema(schema);
48
+ const columnDefinitions = getPostgresColumnEntries(type, dbSchema, tableName);
49
+ const columnDefinitionsMap = new Map(columnDefinitions.map((column) => [column.objectPath.path, column]));
50
+ function getColumn(table, propertyName) {
51
+ return assertDefinedPass(table[propertyName], `Property "${propertyName}" does not exist on ${type.name}`);
52
+ }
53
+ function buildIndex(table, data, columnName) {
54
+ const columns = (data.columns ?? [columnName]).map((columnValue) => {
55
+ assertDefined(columnValue, 'Missing column name for index.');
56
+ const [columnName, columnOrder] = isString(columnValue) ? [columnValue] : columnValue;
57
+ const order = columnOrder ?? data.order ?? 'asc';
58
+ let column = getColumn(table, columnName);
59
+ column = column[order]();
60
+ if (data.options?.nulls == 'first') {
61
+ column = column.nullsFirst();
62
+ }
63
+ else if (data.options?.nulls == 'last') {
64
+ column = column.nullsLast();
65
+ }
66
+ return column;
67
+ });
68
+ const indexFn = (data.options?.unique == true) ? uniqueIndex : index;
69
+ let builder = indexFn(data.options?.name ?? getIndexName(tableName, columns, { naming: data.options?.naming })).using(data.options?.using ?? 'btree', ...columns);
70
+ if (isDefined(data.options?.where)) {
71
+ const query = convertQuery(data.options.where(table), table, columnDefinitionsMap);
72
+ builder = builder.where(query.inlineParams());
73
+ }
74
+ return builder;
75
+ }
76
+ function buildPrimaryKey(table) {
77
+ const columns = primaryKeyColumnDefinitions.map((columnDefinition) => getColumn(table, columnDefinition.name));
78
+ return primaryKey({
79
+ name: mergedTableReflectionData.compundPrimaryKeyName ?? getPrimaryKeyName(tableName, columns, { naming: mergedTableReflectionData.compundPrimaryKeyNaming }),
80
+ columns,
81
+ });
82
+ }
83
+ const primaryKeyColumnDefinitions = columnDefinitions.filter((columnDefinition) => columnDefinition.reflectionData?.primaryKey == true);
84
+ const skipPrimaryKey = primaryKeyColumnDefinitions.length > 1;
85
+ const columnEntries = columnDefinitions.map((entry) => [entry.name, entry.buildType({ skipPrimaryKey })]);
86
+ const drizzleSchema = dbSchema.table(tableName, fromEntries(columnEntries), (table) => [
87
+ ...((primaryKeyColumnDefinitions.length > 1)
88
+ ? [buildPrimaryKey(table)]
89
+ : []),
90
+ ...(columnDefinitions.map((columnDefinition) => {
91
+ const indexData = columnDefinition.reflectionData?.index;
92
+ if (isUndefined(indexData)) {
93
+ return undefined;
94
+ }
95
+ return buildIndex(table, indexData, columnDefinition.name);
96
+ }).filter(isDefined)),
97
+ ...tableReflectionDatas.flatMap((tableReflectionData) => {
98
+ return tableReflectionData.foreignKeys?.map((foreignKeyData) => {
99
+ const foreignTable = getDrizzleTableFromType(foreignKeyData.target(), dbSchema.schemaName);
100
+ return foreignKey({
101
+ name: foreignKeyData.options?.name ?? getForeignKeyName(tableName, foreignKeyData.columns, { naming: foreignKeyData.options?.naming }),
102
+ columns: foreignKeyData.columns.map((column) => getColumn(table, column)),
103
+ foreignColumns: foreignKeyData.foreignColumns.map((column) => getColumn(foreignTable, column)),
104
+ });
105
+ }) ?? [];
106
+ }),
107
+ ...tableReflectionDatas.flatMap((tableReflectionData) => tableReflectionData.unique).filter(isDefined).map((data) => {
108
+ const columns = data.columns?.map((column) => getColumn(table, column));
109
+ let constraint = unique(data.options?.name ?? getUniqueName(tableName, columns, { naming: data.options?.naming })).on(...columns);
110
+ if (data.options?.nulls == 'not distinct') {
111
+ constraint = constraint.nullsNotDistinct();
112
+ }
113
+ return constraint;
114
+ }),
115
+ ...tableReflectionDatas.flatMap((tableReflectionData) => tableReflectionData.index).filter(isDefined).map((data) => buildIndex(table, data)),
116
+ ...tableReflectionDatas.flatMap((tableReflectionData) => tableReflectionData.checks).filter(isDefined).map((data) => check(data.name, data.builder(table))),
117
+ ]);
118
+ drizzleSchema[columnDefinitionsSymbol] = columnDefinitions;
119
+ drizzleSchema[columnDefinitionsMapSymbol] = columnDefinitionsMap;
120
+ return drizzleSchema;
121
+ }
122
+ function getPostgresColumnEntries(type, dbSchema, tableName, path = new JsonPath({ dollar: false }), prefix = '') {
123
+ const metadata = reflectionRegistry.getMetadata(type);
124
+ assertDefined(metadata, `Type ${type.name} does not have reflection metadata (path: ${path.toString()}).`);
125
+ const objectSchema = getObjectSchema(type);
126
+ const entries = objectEntries(objectSchema.properties).toSorted(compareByValueSelectionToOrder(['id', orderRest, 'metadata'], (item) => item[0])).flatMap(([property, schema]) => {
127
+ const columnReflectionData = metadata.properties.get(property)?.data.tryGet('orm');
128
+ const columnName = columnReflectionData?.name ?? toSnakeCase(property);
129
+ if ((schema instanceof ObjectSchema) && !(schema instanceof JsonSchema)) {
130
+ const propertyMetadata = reflectionRegistry.getMetadata(type)?.properties.get(property);
131
+ assertDefined(propertyMetadata, `Property "${property}" of type "${type.name}" does not have reflection metadata (path: ${path.toString()}).`);
132
+ const propertyPrefix = columnReflectionData?.embedded?.prefix;
133
+ const nestedPrefix = [prefix, isNull(propertyPrefix) ? '' : propertyPrefix ?? `${columnName}_`].join('');
134
+ return getPostgresColumnEntries(columnReflectionData?.embedded?.type ?? propertyMetadata.type, dbSchema, tableName, path.add(property), nestedPrefix);
135
+ }
136
+ const objectPath = path.add(property);
137
+ const encrypted = columnReflectionData?.encrypted == true;
138
+ const toDatabase = encrypted
139
+ ? async (value, context) => {
140
+ const bytes = encodeUtf8(value);
141
+ return await encryptBytes(bytes, context.encryptionKey);
142
+ }
143
+ : (value) => value;
144
+ const fromDatabase = encrypted
145
+ ? async (value, context) => {
146
+ const decrypted = await decryptBytes(value, context.encryptionKey);
147
+ return decodeText(decrypted);
148
+ }
149
+ : (value) => value;
150
+ const prefixedColumnName = [prefix, columnName].join('');
151
+ return [{
152
+ name: toCamelCase(prefixedColumnName),
153
+ objectPath,
154
+ reflectionData: columnReflectionData,
155
+ buildType: (options) => getPostgresColumn(tableName, toSnakeCase(prefixedColumnName), dbSchema, schema, columnReflectionData ?? {}, options, { type, property }),
156
+ dereferenceObjectPath: compileDereferencer(objectPath, { optional: true }),
157
+ toDatabase,
158
+ fromDatabase,
159
+ }];
160
+ });
161
+ return entries;
162
+ }
163
+ function getPostgresColumn(tableName, columnName, dbSchema, propertySchema, reflectionData, options, context) {
164
+ let nullable = false;
165
+ let array = false;
166
+ let baseSchema = propertySchema;
167
+ while (true) {
168
+ if ((baseSchema instanceof NullableSchema) || (baseSchema instanceof OptionalSchema)) {
169
+ nullable = true;
170
+ baseSchema = baseSchema.schema;
171
+ }
172
+ else if (baseSchema instanceof ArraySchema) {
173
+ array = true;
174
+ baseSchema = baseSchema.itemSchema;
175
+ }
176
+ else {
177
+ break;
178
+ }
179
+ }
180
+ let column = getPostgresBaseColumn(columnName, dbSchema, baseSchema, reflectionData, context);
181
+ if (array) {
182
+ column = column.array();
183
+ }
184
+ if (!nullable) {
185
+ column = column.notNull();
186
+ }
187
+ if (isDefined(reflectionData.unique)) {
188
+ column = column.unique(reflectionData.unique.options?.name ?? getUniqueName(tableName, [columnName], { naming: reflectionData.unique.options?.naming }), isString(reflectionData.unique.options?.nulls) ? { nulls: reflectionData.unique.options.nulls } : undefined);
189
+ }
190
+ if ((reflectionData.primaryKey == true) && (options.skipPrimaryKey != true)) {
191
+ column = column.primaryKey();
192
+ }
193
+ for (const { target, targetColumn } of reflectionData.references ?? []) {
194
+ column = column.references(() => {
195
+ const targetTable = getDrizzleTableFromType(target(), dbSchema.schemaName);
196
+ return targetTable[(targetColumn ?? 'id')];
197
+ });
198
+ }
199
+ if (isDefined(reflectionData.references)) {
200
+ }
201
+ return column;
202
+ }
203
+ function getPostgresBaseColumn(columnName, dbSchema, schema, reflectionData, context) {
204
+ if (schema instanceof DefaultSchema) {
205
+ const column = getPostgresBaseColumn(columnName, dbSchema, schema.schema, reflectionData, context);
206
+ return column.default(schema.defaultValue);
207
+ }
208
+ if (reflectionData.encrypted) {
209
+ return bytea(columnName);
210
+ }
211
+ if (schema instanceof UuidSchema) {
212
+ let column = uuid(columnName);
213
+ if (schema.defaultRandom) {
214
+ column = column.defaultRandom();
215
+ }
216
+ return column;
217
+ }
218
+ if (schema instanceof TimestampSchema) {
219
+ return timestamp(columnName);
220
+ }
221
+ if (schema instanceof NumericDateSchema) {
222
+ return numericDate(columnName);
223
+ }
224
+ if (schema instanceof NumberSchema) {
225
+ return schema.integer
226
+ ? integer(columnName)
227
+ : doublePrecision(columnName);
228
+ }
229
+ if (schema instanceof StringSchema) {
230
+ return text(columnName);
231
+ }
232
+ if (schema instanceof BooleanSchema) {
233
+ return boolean(columnName);
234
+ }
235
+ if (schema instanceof EnumerationSchema) {
236
+ const pgEnum = getPgEnum(dbSchema, schema.enumeration, context);
237
+ return pgEnum(columnName);
238
+ }
239
+ if (schema instanceof JsonSchema) {
240
+ return jsonb(columnName);
241
+ }
242
+ if (schema instanceof Uint8ArraySchema) {
243
+ return bytea(columnName);
244
+ }
245
+ throw new NotSupportedError(`Schema "${schema.constructor.name}" not supported on type "${context.type.name}" for property "${context.property}"`);
246
+ }
247
+ const enumNames = new Map();
248
+ const enums = new MultiKeyMap();
249
+ export function registerEnum(enumeration, name) {
250
+ enumNames.set(enumeration, toSnakeCase(name));
251
+ }
252
+ export function getPgEnum(schema, enumeration, context) {
253
+ const dbSchema = isString(schema) ? getDbSchema(schema) : schema;
254
+ const enumName = enumNames.get(enumeration) ?? tryGetEnumName(enumeration);
255
+ if (isUndefined(enumName)) {
256
+ const errorMessage = 'Enum is not registered. Please register it using `databaseSchema.getEnum(MyEnum)` before use.';
257
+ if (isDefined(context)) {
258
+ throw new Error(`${errorMessage} (type: ${context.type.name}, property: ${context.property})`);
259
+ }
260
+ throw new Error(errorMessage);
261
+ }
262
+ const values = (isArray(enumeration) ? enumeration : enumValues(enumeration))
263
+ .map((value) => value.toString());
264
+ const dbEnum = dbSchema.enum(toSnakeCase(enumName), values);
265
+ if (enums.has([dbSchema.schemaName, enumeration])) {
266
+ enums.set([dbSchema.schemaName, enumeration], dbEnum);
267
+ }
268
+ return dbEnum;
269
+ }
270
+ function getDefaultTableName(type) {
271
+ return toSnakeCase(isString(type.entityName) ? type.entityName : type.name.replace(/\d+$/u, ''));
272
+ }
273
+ function getPrimaryKeyName(tableName, columns, options) {
274
+ return getIdentifier(tableName, columns, 'pk', options);
275
+ }
276
+ function getIndexName(tableName, columns, options) {
277
+ return getIdentifier(tableName, columns, 'idx', options);
278
+ }
279
+ function getUniqueName(tableName, columns, options) {
280
+ return getIdentifier(tableName, columns, 'unique', options);
281
+ }
282
+ function getForeignKeyName(tableName, columns, options) {
283
+ return getIdentifier(tableName, columns, 'fkey', options);
284
+ }
285
+ function getIdentifier(tableName, columns, suffix, options) {
286
+ const identifier = `${getTablePrefix(tableName, options?.naming)}_${getColumnNames(columns).join('_')}_${suffix}`;
287
+ if (identifier.length > 63) {
288
+ if (options?.naming != 'abbreviated-table') {
289
+ return getIdentifier(tableName, columns, suffix, { naming: 'abbreviated-table' });
290
+ }
291
+ throw new Error(`Identifier "${identifier}" for table "${tableName}" is too long. Maximum length is 63 characters.`);
292
+ }
293
+ return identifier;
294
+ }
295
+ function getTablePrefix(tableName, naming) {
296
+ return (naming == 'abbreviated-table') ? tableName.split('_').map((part) => part[0]).join('') : tableName;
297
+ }
298
+ function getColumnNames(columns) {
299
+ return columns.map((column) => isString(column) ? column : column.name);
300
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tstdl/base",
3
- "version": "0.93.3",
3
+ "version": "0.93.4",
4
4
  "author": "Patrick Hein",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -132,11 +132,11 @@
132
132
  "reflect-metadata": "^0.2",
133
133
  "rxjs": "^7.8",
134
134
  "ts-pattern": "^5.8",
135
- "type-fest": "^5.0"
135
+ "type-fest": "^5.1"
136
136
  },
137
137
  "peerDependencies": {
138
138
  "@google-cloud/storage": "^7.17",
139
- "@google/genai": "^1.22",
139
+ "@google/genai": "^1.24",
140
140
  "@tstdl/angular": "^0.93",
141
141
  "@zxcvbn-ts/core": "^3.0",
142
142
  "@zxcvbn-ts/language-common": "^3.0",
@@ -149,7 +149,7 @@
149
149
  "mjml": "^4.16",
150
150
  "nodemailer": "^7.0",
151
151
  "pg": "^8.16",
152
- "playwright": "^1.55",
152
+ "playwright": "^1.56",
153
153
  "preact": "^10.27",
154
154
  "preact-render-to-string": "^6.6",
155
155
  "sharp": "^0.34",
@@ -178,7 +178,7 @@
178
178
  "typedoc-plugin-markdown": "4.9",
179
179
  "typedoc-plugin-missing-exports": "4.1",
180
180
  "typescript": "5.9",
181
- "typescript-eslint": "8.45"
181
+ "typescript-eslint": "8.46"
182
182
  },
183
183
  "overrides": {
184
184
  "drizzle-kit": {
@@ -1,408 +0,0 @@
1
- import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing';
2
- import { boolean, check, doublePrecision, foreignKey, index, integer, jsonb, pgSchema, primaryKey, text, unique, uniqueIndex, uuid, type ExtraConfigColumn, type PgColumn, type PgColumnBuilder, type PgEnum, type PgSchema, type PgTableWithColumns } from 'drizzle-orm/pg-core';
3
-
4
- import { MultiKeyMap } from '#/data-structures/multi-key-map.js';
5
- import { tryGetEnumName } from '#/enumeration/enumeration.js';
6
- import { NotSupportedError } from '#/errors/not-supported.error.js';
7
- import { JsonPath } from '#/json-path/json-path.js';
8
- import { reflectionRegistry, type TypeMetadata } from '#/reflection/registry.js';
9
- import { ArraySchema, BooleanSchema, DefaultSchema, EnumerationSchema, getObjectSchema, NullableSchema, NumberSchema, ObjectSchema, OptionalSchema, StringSchema, Uint8ArraySchema, type Record, type Schema } from '#/schema/index.js';
10
- import type { AbstractConstructor, Enumeration, EnumerationObject, Type } from '#/types/index.js';
11
- import { compareByValueSelectionToOrder, orderRest } from '#/utils/comparison.js';
12
- import { decodeText, encodeUtf8 } from '#/utils/encoding.js';
13
- import { enumValues } from '#/utils/enum.js';
14
- import { memoize, memoizeSingle } from '#/utils/function/memoize.js';
15
- import { compileDereferencer } from '#/utils/object/dereference.js';
16
- import { fromEntries, objectEntries } from '#/utils/object/object.js';
17
- import { assertDefined, assertDefinedPass, isArray, isDefined, isNotNullOrUndefined, isNull, isString, isUndefined } from '#/utils/type-guards.js';
18
- import { bytea, numericDate, timestamp } from '../../data-types/index.js';
19
- import type { IndexReflectionData, OrmColumnReflectionData, OrmTableReflectionData } from '../../decorators.js';
20
- import type { EntityType } from '../../entity.js';
21
- import { JsonSchema } from '../../schemas/json.js';
22
- import { NumericDateSchema } from '../../schemas/numeric-date.js';
23
- import { TimestampSchema } from '../../schemas/timestamp.js';
24
- import { UuidSchema } from '../../schemas/uuid.js';
25
- import { decryptBytes, encryptBytes } from '../encryption.js';
26
- import { convertQuery } from '../query-converter.js';
27
- import type { BuildTypeOptions, ColumnDefinition, ColumnDefinitionsMap, PgTableFromType, TransformContext } from '../types.js';
28
-
29
- type ConverterContext = { type: AbstractConstructor, property: string };
30
-
31
- const getDbSchema = memoizeSingle(pgSchema);
32
-
33
- export const getDrizzleTableFromType = memoize(_getDrizzleTableFromType);
34
-
35
- const columnDefinitionsSymbol = Symbol('columnDefinitions');
36
- const columnDefinitionsMapSymbol = Symbol('columnDefinitionsMap');
37
-
38
- export function getColumnDefinitions(table: PgTableWithColumns<any>): ColumnDefinition[] {
39
- return (table as PgTableWithColumns<any> & { [columnDefinitionsSymbol]: ColumnDefinition[] })[columnDefinitionsSymbol];
40
- }
41
-
42
- export function getColumnDefinitionsMap(table: PgTableWithColumns<any>): ColumnDefinitionsMap {
43
- return (table as PgTableWithColumns<any> & { [columnDefinitionsMapSymbol]: ColumnDefinitionsMap })[columnDefinitionsMapSymbol];
44
- }
45
-
46
- export function _getDrizzleTableFromType<T extends EntityType, S extends string>(type: T, fallbackSchemaName?: S): PgTableFromType<T, S> {
47
- const metadata = reflectionRegistry.getMetadata(type);
48
- assertDefined(metadata, `Type ${type.name} does not have reflection metadata.`);
49
-
50
- const tableReflectionDatas: OrmTableReflectionData[] = [];
51
-
52
- for (let currentMetadata: TypeMetadata | undefined = metadata; isNotNullOrUndefined(currentMetadata?.parent); currentMetadata = reflectionRegistry.getMetadata(currentMetadata.parent)) {
53
- const tableReflectionData = currentMetadata.data.tryGet<OrmTableReflectionData>('orm');
54
-
55
- if (isDefined(tableReflectionData)) {
56
- tableReflectionDatas.push(tableReflectionData);
57
- }
58
- }
59
-
60
- const mergedTableReflectionData = tableReflectionDatas.reduceRight((merged, data) => ({ ...merged, ...data }), {});
61
-
62
- const tableReflectionData = tableReflectionDatas[0];
63
- const schema = assertDefinedPass(mergedTableReflectionData.schema ?? fallbackSchemaName, 'Table schema not provided');
64
- const tableName = tableReflectionData?.name ?? getDefaultTableName(type);
65
-
66
- const dbSchema = getDbSchema(schema);
67
- const columnDefinitions = getPostgresColumnEntries(type, dbSchema, tableName);
68
- const columnDefinitionsMap = new Map(columnDefinitions.map((column) => [column.objectPath.path, column]));
69
-
70
- function getColumn(table: Record<string, ExtraConfigColumn>, propertyName: string): ExtraConfigColumn {
71
- return assertDefinedPass(table[propertyName], `Property "${propertyName}" does not exist on ${type.name}`);
72
- }
73
-
74
- function buildIndex(table: Record<string, ExtraConfigColumn>, data: IndexReflectionData, columnName?: string) {
75
- const columns = (data.columns ?? [columnName]).map((columnValue) => {
76
- assertDefined(columnValue, 'Missing column name for index.');
77
-
78
- const [columnName, columnOrder] = isString(columnValue) ? [columnValue] as const : columnValue;
79
- const order = columnOrder ?? data.order ?? 'asc';
80
-
81
- let column = getColumn(table, columnName);
82
- column = column[order]() as ExtraConfigColumn;
83
-
84
- if (data.options?.nulls == 'first') {
85
- column = column.nullsFirst() as ExtraConfigColumn;
86
- }
87
- else if (data.options?.nulls == 'last') {
88
- column = column.nullsLast() as ExtraConfigColumn;
89
- }
90
-
91
- return column;
92
- }) as [ExtraConfigColumn, ...ExtraConfigColumn[]];
93
-
94
- const indexFn = (data.options?.unique == true) ? uniqueIndex : index;
95
-
96
- let builder = indexFn(data.options?.name ?? getIndexName(tableName, columns, { naming: data.options?.naming })).using(data.options?.using ?? 'btree', ...columns);
97
-
98
- if (isDefined(data.options?.where)) {
99
- const query = convertQuery(data.options.where(table as PgTableWithColumns<any> as PgTableFromType<EntityType<any>>), table as PgTableWithColumns<any> as PgTableFromType, columnDefinitionsMap);
100
- builder = builder.where(query.inlineParams());
101
- }
102
-
103
- return builder;
104
- }
105
-
106
- function buildPrimaryKey(table: Record<string, ExtraConfigColumn>) {
107
- const columns = primaryKeyColumnDefinitions.map((columnDefinition) => getColumn(table, columnDefinition.name)) as unknown as [PgColumn, ...PgColumn[]];
108
-
109
- return primaryKey({
110
- name: mergedTableReflectionData.compundPrimaryKeyName ?? getPrimaryKeyName(tableName, columns, { naming: mergedTableReflectionData.compundPrimaryKeyNaming }),
111
- columns,
112
- });
113
- }
114
-
115
- const primaryKeyColumnDefinitions = columnDefinitions.filter((columnDefinition) => columnDefinition.reflectionData?.primaryKey == true);
116
-
117
- const skipPrimaryKey = primaryKeyColumnDefinitions.length > 1;
118
- const columnEntries = columnDefinitions.map((entry) => [entry.name, entry.buildType({ skipPrimaryKey })]);
119
-
120
- const drizzleSchema = dbSchema.table(
121
- tableName,
122
- fromEntries(columnEntries) as any,
123
- (table) => [
124
- ...(
125
- (primaryKeyColumnDefinitions.length > 1)
126
- ? [buildPrimaryKey(table)]
127
- : []
128
- ),
129
- ...(
130
- columnDefinitions.map((columnDefinition) => {
131
- const indexData = columnDefinition.reflectionData?.index;
132
-
133
- if (isUndefined(indexData)) {
134
- return undefined;
135
- }
136
-
137
- return buildIndex(table, indexData, columnDefinition.name);
138
- }).filter(isDefined)
139
- ),
140
- ...tableReflectionDatas.flatMap((tableReflectionData) => {
141
- return tableReflectionData.foreignKeys?.map((foreignKeyData) => {
142
- const foreignTable = getDrizzleTableFromType(foreignKeyData.target(), dbSchema.schemaName);
143
-
144
- return foreignKey({
145
- name: foreignKeyData.options?.name ?? getForeignKeyName(tableName, foreignKeyData.columns, { naming: foreignKeyData.options?.naming }),
146
- columns: foreignKeyData.columns.map((column) => getColumn(table, column)) as [ExtraConfigColumn, ...ExtraConfigColumn[]],
147
- foreignColumns: foreignKeyData.foreignColumns.map((column) => getColumn(foreignTable as any as Record<string, ExtraConfigColumn>, column)) as [ExtraConfigColumn, ...ExtraConfigColumn[]],
148
- });
149
- }) ?? [];
150
- }),
151
- ...tableReflectionDatas.flatMap((tableReflectionData) => tableReflectionData.unique).filter(isDefined).map((data) => {
152
- const columns = data.columns?.map((column) => getColumn(table, column)) as [ExtraConfigColumn, ...ExtraConfigColumn[]];
153
-
154
- let constraint = unique(data.options?.name ?? getUniqueName(tableName, columns, { naming: data.options?.naming })).on(...columns);
155
-
156
- if (data.options?.nulls == 'not distinct') {
157
- constraint = constraint.nullsNotDistinct();
158
- }
159
-
160
- return constraint;
161
- }),
162
- ...tableReflectionDatas.flatMap((tableReflectionData) => tableReflectionData.index).filter(isDefined).map((data) => buildIndex(table, data)),
163
- ...tableReflectionDatas.flatMap((tableReflectionData) => tableReflectionData.checks).filter(isDefined).map((data) => check(data.name, data.builder(table as PgTableWithColumns<any> as PgTableFromType<EntityType<any>>))),
164
- ]
165
- );
166
-
167
- (drizzleSchema as Record)[columnDefinitionsSymbol] = columnDefinitions;
168
- (drizzleSchema as Record)[columnDefinitionsMapSymbol] = columnDefinitionsMap;
169
-
170
- return drizzleSchema as any as PgTableFromType<T, S>;
171
- }
172
-
173
- function getPostgresColumnEntries(type: AbstractConstructor, dbSchema: PgSchema, tableName: string, path = new JsonPath({ dollar: false }), prefix: string = ''): ColumnDefinition[] {
174
- const metadata = reflectionRegistry.getMetadata(type);
175
- assertDefined(metadata, `Type ${type.name} does not have reflection metadata (path: ${path.toString()}).`);
176
-
177
- const objectSchema = getObjectSchema<Record<string>>(type);
178
-
179
- const entries = objectEntries(objectSchema.properties).toSorted(compareByValueSelectionToOrder(['id', orderRest, 'metadata'], (item) => item[0])).flatMap(([property, schema]): ColumnDefinition[] => {
180
- const columnReflectionData = metadata.properties.get(property)?.data.tryGet<OrmColumnReflectionData>('orm');
181
- const columnName = columnReflectionData?.name ?? toSnakeCase(property);
182
-
183
- if ((schema instanceof ObjectSchema) && !(schema instanceof JsonSchema)) {
184
- const propertyMetadata = reflectionRegistry.getMetadata(type)?.properties.get(property);
185
- assertDefined(propertyMetadata, `Property "${property}" of type "${type.name}" does not have reflection metadata (path: ${path.toString()}).`);
186
-
187
- const propertyPrefix = columnReflectionData?.embedded?.prefix;
188
- const nestedPrefix = [prefix, isNull(propertyPrefix) ? '' : propertyPrefix ?? `${columnName}_`].join('');
189
-
190
- return getPostgresColumnEntries(columnReflectionData?.embedded?.type ?? propertyMetadata.type, dbSchema, tableName, path.add(property), nestedPrefix);
191
- }
192
-
193
- const objectPath = path.add(property);
194
-
195
- const encrypted = columnReflectionData?.encrypted == true;
196
-
197
- const toDatabase = encrypted
198
- ? async (value: unknown, context: TransformContext) => {
199
- const bytes = encodeUtf8(value as string);
200
- return await encryptBytes(bytes, context.encryptionKey!);
201
- }
202
- : (value: unknown) => value;
203
-
204
- const fromDatabase = encrypted
205
- ? async (value: unknown, context: TransformContext) => {
206
- const decrypted = await decryptBytes(value as Uint8Array, context.encryptionKey!);
207
- return decodeText(decrypted);
208
- }
209
- : (value: unknown) => value;
210
-
211
- const prefixedColumnName = [prefix, columnName].join('');
212
-
213
- return [{
214
- name: toCamelCase(prefixedColumnName),
215
- objectPath,
216
- reflectionData: columnReflectionData,
217
- buildType: (options: BuildTypeOptions) => getPostgresColumn(tableName, toSnakeCase(prefixedColumnName), dbSchema, schema, columnReflectionData ?? {}, options, { type, property }),
218
- dereferenceObjectPath: compileDereferencer(objectPath, { optional: true }),
219
- toDatabase,
220
- fromDatabase,
221
- }];
222
- });
223
-
224
- return entries;
225
- }
226
-
227
- function getPostgresColumn(tableName: string, columnName: string, dbSchema: PgSchema, propertySchema: Schema, reflectionData: OrmColumnReflectionData, options: BuildTypeOptions, context: ConverterContext): PgColumnBuilder<any, any, any, any> {
228
- let nullable = false;
229
- let array = false;
230
-
231
- let baseSchema = propertySchema;
232
- while (true) {
233
- if ((baseSchema instanceof NullableSchema) || (baseSchema instanceof OptionalSchema)) {
234
- nullable = true;
235
- baseSchema = baseSchema.schema;
236
- }
237
- else if (baseSchema instanceof ArraySchema) {
238
- array = true;
239
- baseSchema = baseSchema.itemSchema;
240
- }
241
- else {
242
- break;
243
- }
244
- }
245
-
246
- let column = getPostgresBaseColumn(columnName, dbSchema, baseSchema, reflectionData, context);
247
-
248
- if (array) {
249
- column = column.array();
250
- }
251
-
252
- if (!nullable) {
253
- column = column.notNull();
254
- }
255
-
256
- if (isDefined(reflectionData.unique)) {
257
- column = column.unique(reflectionData.unique.options?.name ?? getUniqueName(tableName, [columnName], { naming: reflectionData.unique.options?.naming }), isString(reflectionData.unique.options?.nulls) ? { nulls: reflectionData.unique.options.nulls } : undefined);
258
- }
259
-
260
- if ((reflectionData.primaryKey == true) && (options.skipPrimaryKey != true)) {
261
- column = column.primaryKey();
262
- }
263
-
264
- for (const { target, targetColumn } of reflectionData.references ?? []) {
265
- column = column.references(() => {
266
- const targetTable = getDrizzleTableFromType(target(), dbSchema.schemaName);
267
- return targetTable[(targetColumn ?? 'id') as keyof PgTableFromType] as PgColumn;
268
- });
269
- }
270
-
271
- if (isDefined(reflectionData.references)) {
272
- }
273
-
274
- return column;
275
- }
276
-
277
- function getPostgresBaseColumn(columnName: string, dbSchema: PgSchema, schema: Schema, reflectionData: OrmColumnReflectionData, context: ConverterContext): PgColumnBuilder<any, any, any, any> {
278
- if (schema instanceof DefaultSchema) {
279
- const column = getPostgresBaseColumn(columnName, dbSchema, schema.schema, reflectionData, context);
280
- return column.default(schema.defaultValue);
281
- }
282
-
283
- if (reflectionData.encrypted) {
284
- return bytea(columnName);
285
- }
286
-
287
- if (schema instanceof UuidSchema) {
288
- let column = uuid(columnName);
289
-
290
- if (schema.defaultRandom) {
291
- column = column.defaultRandom();
292
- }
293
-
294
- return column;
295
- }
296
-
297
- if (schema instanceof TimestampSchema) {
298
- return timestamp(columnName);
299
- }
300
-
301
- if (schema instanceof NumericDateSchema) {
302
- return numericDate(columnName);
303
- }
304
-
305
- if (schema instanceof NumberSchema) {
306
- return schema.integer
307
- ? integer(columnName)
308
- : doublePrecision(columnName);
309
- }
310
-
311
- if (schema instanceof StringSchema) {
312
- return text(columnName);
313
- }
314
-
315
- if (schema instanceof BooleanSchema) {
316
- return boolean(columnName);
317
- }
318
-
319
- if (schema instanceof EnumerationSchema) {
320
- const pgEnum = getPgEnum(dbSchema, schema.enumeration, context);
321
- return pgEnum(columnName);
322
- }
323
-
324
- if (schema instanceof JsonSchema) {
325
- return jsonb(columnName);
326
- }
327
-
328
- if (schema instanceof Uint8ArraySchema) {
329
- return bytea(columnName);
330
- }
331
-
332
- throw new NotSupportedError(`Schema "${schema.constructor.name}" not supported on type "${context.type.name}" for property "${context.property}"`);
333
- }
334
-
335
- const enumNames = new Map<Enumeration, string>();
336
- const enums = new MultiKeyMap<[string, Enumeration], PgEnum<[string, ...string[]]>>();
337
-
338
- export function registerEnum(enumeration: Enumeration, name: string): void {
339
- enumNames.set(enumeration, toSnakeCase(name));
340
- }
341
-
342
- export function getPgEnum(schema: string | PgSchema, enumeration: Enumeration, context?: ConverterContext): PgEnum<[string, ...string[]]> {
343
- const dbSchema = isString(schema) ? getDbSchema(schema) : schema;
344
- const enumName = enumNames.get(enumeration) ?? tryGetEnumName(enumeration as EnumerationObject);
345
-
346
- if (isUndefined(enumName)) {
347
- const errorMessage = 'Enum is not registered. Please register it using `databaseSchema.getEnum(MyEnum)` before use.';
348
-
349
- if (isDefined(context)) {
350
- throw new Error(`${errorMessage} (type: ${context.type.name}, property: ${context.property})`);
351
- }
352
-
353
- throw new Error(errorMessage);
354
- }
355
-
356
- const values = (isArray(enumeration) ? enumeration : enumValues(enumeration))
357
- .map((value) => value.toString()) as [string, ...string[]];
358
-
359
- const dbEnum = dbSchema.enum(toSnakeCase(enumName), values);
360
-
361
- if (enums.has([dbSchema.schemaName, enumeration])) {
362
- enums.set([dbSchema.schemaName, enumeration], dbEnum);
363
- }
364
-
365
- return dbEnum;
366
- }
367
-
368
- function getDefaultTableName(type: Type & Partial<Pick<EntityType, 'entityName'>>): string {
369
- return toSnakeCase(isString(type.entityName) ? type.entityName : type.name.replace(/\d+$/u, ''));
370
- }
371
-
372
- function getPrimaryKeyName(tableName: string, columns: (string | PgColumn)[], options?: { naming?: 'abbreviated-table' }) {
373
- return getIdentifier(tableName, columns, 'pk', options);
374
- }
375
-
376
- function getIndexName(tableName: string, columns: (string | PgColumn)[], options?: { naming?: 'abbreviated-table' }) {
377
- return getIdentifier(tableName, columns, 'idx', options);
378
- }
379
-
380
- function getUniqueName(tableName: string, columns: (string | PgColumn)[], options?: { naming?: 'abbreviated-table' }) {
381
- return getIdentifier(tableName, columns, 'unique', options);
382
- }
383
-
384
- function getForeignKeyName(tableName: string, columns: (string | PgColumn)[], options?: { naming?: 'abbreviated-table' }) {
385
- return getIdentifier(tableName, columns, 'fkey', options);
386
- }
387
-
388
- function getIdentifier(tableName: string, columns: (string | PgColumn)[], suffix: string, options?: { naming?: 'abbreviated-table' }): string {
389
- const identifier = `${getTablePrefix(tableName, options?.naming)}_${getColumnNames(columns).join('_')}_${suffix}`;
390
-
391
- if (identifier.length > 63) {
392
- if (options?.naming != 'abbreviated-table') {
393
- return getIdentifier(tableName, columns, suffix, { naming: 'abbreviated-table' });
394
- }
395
-
396
- throw new Error(`Identifier "${identifier}" for table "${tableName}" is too long. Maximum length is 63 characters.`);
397
- }
398
-
399
- return identifier;
400
- }
401
-
402
- function getTablePrefix(tableName: string, naming?: 'abbreviated-table'): string {
403
- return (naming == 'abbreviated-table') ? tableName.split('_').map((part) => part[0]).join('') : tableName;
404
- }
405
-
406
- function getColumnNames(columns: (string | PgColumn)[]): string[] {
407
- return columns.map((column) => isString(column) ? column : column.name);
408
- }
File without changes