@tstdl/base 0.93.1 → 0.93.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.
@@ -1,300 +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 } 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
- }
File without changes