@tstdl/base 0.93.1 → 0.93.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/api/server/api-request-token.provider.d.ts +5 -3
  2. package/api/server/api-request-token.provider.js +12 -4
  3. package/api/server/gateway.d.ts +1 -9
  4. package/api/server/gateway.js +67 -36
  5. package/api/types.d.ts +5 -1
  6. package/application/application.d.ts +2 -0
  7. package/application/application.js +3 -1
  8. package/application/providers.d.ts +1 -1
  9. package/application/providers.js +1 -1
  10. package/audit/audit.model.d.ts +106 -6
  11. package/audit/audit.model.js +156 -13
  12. package/audit/auditor.d.ts +115 -30
  13. package/audit/auditor.js +160 -19
  14. package/audit/drizzle/0000_bored_stick.sql +26 -0
  15. package/audit/drizzle/meta/0000_snapshot.json +195 -0
  16. package/audit/drizzle/meta/_journal.json +13 -0
  17. package/audit/drizzle.config.d.ts +2 -0
  18. package/audit/drizzle.config.js +11 -0
  19. package/audit/index.d.ts +3 -1
  20. package/audit/index.js +3 -1
  21. package/audit/module.d.ts +22 -0
  22. package/audit/module.js +33 -0
  23. package/audit/schemas.d.ts +6 -0
  24. package/audit/schemas.js +8 -0
  25. package/audit/types.d.ts +2 -1
  26. package/audit/types.js +2 -1
  27. package/authentication/models/authentication-credentials.model.js +1 -2
  28. package/authentication/models/authentication-session.model.d.ts +2 -2
  29. package/authentication/models/authentication-session.model.js +3 -5
  30. package/authentication/models/index.d.ts +0 -1
  31. package/authentication/models/index.js +0 -1
  32. package/authentication/server/authentication-api-request-token.provider.d.ts +2 -2
  33. package/authentication/server/authentication-api-request-token.provider.js +8 -5
  34. package/authentication/server/authentication.api-controller.d.ts +8 -8
  35. package/authentication/server/authentication.api-controller.js +16 -16
  36. package/authentication/server/authentication.audit.d.ts +34 -0
  37. package/authentication/server/authentication.audit.js +1 -0
  38. package/authentication/server/authentication.service.d.ts +19 -10
  39. package/authentication/server/authentication.service.js +158 -43
  40. package/authentication/server/drizzle.config.js +1 -1
  41. package/authentication/server/index.d.ts +1 -0
  42. package/authentication/server/index.js +1 -0
  43. package/authentication/server/module.d.ts +1 -1
  44. package/authentication/{models → server}/schemas.d.ts +2 -3
  45. package/authentication/{models → server}/schemas.js +2 -3
  46. package/constants.d.ts +1 -0
  47. package/constants.js +1 -0
  48. package/document-management/api/document-management.api.d.ts +74 -74
  49. package/document-management/models/document-assignment-scope.model.d.ts +1 -2
  50. package/document-management/models/document-assignment-scope.model.js +4 -6
  51. package/document-management/models/document-assignment-task.model.d.ts +1 -2
  52. package/document-management/models/document-assignment-task.model.js +3 -5
  53. package/document-management/models/document-category.model.d.ts +1 -2
  54. package/document-management/models/document-category.model.js +3 -4
  55. package/document-management/models/document-collection-assignment.model.d.ts +1 -2
  56. package/document-management/models/document-collection-assignment.model.js +5 -7
  57. package/document-management/models/document-collection.model.d.ts +1 -2
  58. package/document-management/models/document-collection.model.js +3 -4
  59. package/document-management/models/document-management-table.d.ts +1 -1
  60. package/document-management/models/document-management-table.js +1 -1
  61. package/document-management/models/document-property-value.model.d.ts +1 -2
  62. package/document-management/models/document-property-value.model.js +5 -8
  63. package/document-management/models/document-property.model.d.ts +1 -2
  64. package/document-management/models/document-property.model.js +2 -3
  65. package/document-management/models/document-request-collection-assignment.model.d.ts +1 -2
  66. package/document-management/models/document-request-collection-assignment.model.js +4 -6
  67. package/document-management/models/document-request-template.d.ts +1 -2
  68. package/document-management/models/document-request-template.js +4 -6
  69. package/document-management/models/document-request.model.d.ts +1 -1
  70. package/document-management/models/document-request.model.js +4 -5
  71. package/document-management/models/document-requests-template.d.ts +1 -1
  72. package/document-management/models/document-requests-template.js +2 -3
  73. package/document-management/models/document-tag-assignment.model.d.ts +1 -2
  74. package/document-management/models/document-tag-assignment.model.js +4 -6
  75. package/document-management/models/document-tag.model.d.ts +1 -1
  76. package/document-management/models/document-tag.model.js +2 -3
  77. package/document-management/models/document-type-property.model.d.ts +1 -2
  78. package/document-management/models/document-type-property.model.js +4 -6
  79. package/document-management/models/document-type-validation.model.d.ts +1 -2
  80. package/document-management/models/document-type-validation.model.js +4 -6
  81. package/document-management/models/document-type.model.d.ts +1 -2
  82. package/document-management/models/document-type.model.js +3 -5
  83. package/document-management/models/document-validation-definition.model.d.ts +1 -2
  84. package/document-management/models/document-validation-definition.model.js +3 -4
  85. package/document-management/models/document-validation-execution-related-document.model.d.ts +1 -2
  86. package/document-management/models/document-validation-execution-related-document.model.js +4 -6
  87. package/document-management/models/document-validation-execution.model.d.ts +1 -2
  88. package/document-management/models/document-validation-execution.model.js +6 -8
  89. package/document-management/models/document-workflow.model.d.ts +1 -2
  90. package/document-management/models/document-workflow.model.js +5 -7
  91. package/document-management/models/document.model.d.ts +1 -2
  92. package/document-management/models/document.model.js +5 -7
  93. package/document-management/server/api/document-management.api.js +1 -1
  94. package/document-management/server/module.d.ts +1 -1
  95. package/document-management/server/module.js +1 -1
  96. package/document-management/server/schemas.d.ts +1 -1
  97. package/document-management/server/schemas.js +1 -1
  98. package/document-management/server/services/document-category-type.service.d.ts +2 -2
  99. package/document-management/server/services/document-category-type.service.js +1 -2
  100. package/document-management/server/services/document-collection.service.d.ts +1 -1
  101. package/document-management/server/services/document-collection.service.js +1 -2
  102. package/document-management/server/services/document-management.service.js +6 -6
  103. package/document-management/server/services/document-property.service.d.ts +1 -1
  104. package/document-management/server/services/document-property.service.js +1 -2
  105. package/document-management/server/services/document-validation.service.js +2 -2
  106. package/document-management/server/services/document-workflow.service.d.ts +2 -2
  107. package/document-management/server/services/document-workflow.service.js +1 -2
  108. package/document-management/server/services/document.service.d.ts +1 -1
  109. package/document-management/server/services/document.service.js +1 -2
  110. package/document-management/server/services/singleton.js +1 -1
  111. package/document-management/service-models/document.service-model.d.ts +62 -62
  112. package/document-management/service-models/document.service-model.js +1 -1
  113. package/document-management/service-models/enriched/enriched-document-management-data.view.js +1 -1
  114. package/document-management/service-models/enriched/enriched-document.view.d.ts +1 -1
  115. package/examples/api/authentication.js +2 -2
  116. package/examples/api/basic-overview.js +2 -2
  117. package/examples/api/custom-authentication.js +2 -2
  118. package/examples/api/streaming.js +2 -2
  119. package/examples/browser/basic.js +2 -2
  120. package/examples/document-management/main.js +2 -2
  121. package/examples/http/client.js +2 -2
  122. package/examples/mail/basic.js +2 -2
  123. package/examples/pdf/basic.js +2 -2
  124. package/examples/template/basic.js +2 -2
  125. package/http/server/http-server-request.d.ts +3 -3
  126. package/key-value-store/postgres/key-value-store.service.js +1 -2
  127. package/key-value-store/postgres/models/key-value.model.d.ts +1 -2
  128. package/key-value-store/postgres/models/key-value.model.js +2 -4
  129. package/key-value-store/postgres/models/schemas.d.ts +1 -1
  130. package/key-value-store/postgres/models/schemas.js +1 -1
  131. package/lock/postgres/lock.js +1 -1
  132. package/lock/postgres/models/lock.model.d.ts +1 -2
  133. package/lock/postgres/models/lock.model.js +3 -5
  134. package/lock/postgres/models/schemas.d.ts +1 -1
  135. package/lock/postgres/models/schemas.js +1 -1
  136. package/lock/postgres/provider.js +1 -2
  137. package/mail/models/mail-log.model.d.ts +1 -1
  138. package/mail/models/mail-log.model.js +4 -5
  139. package/mail/models/schemas.d.ts +1 -1
  140. package/mail/models/schemas.js +1 -1
  141. package/openid-connect/oidc-state.model.d.ts +1 -1
  142. package/openid-connect/oidc-state.model.js +2 -3
  143. package/openid-connect/oidc.service.js +1 -1
  144. package/orm/data-types/bytea.js +1 -1
  145. package/orm/data-types/numeric-date.js +1 -1
  146. package/orm/decorators.d.ts +65 -72
  147. package/orm/decorators.js +42 -40
  148. package/orm/entity.d.ts +7 -1
  149. package/orm/entity.js +25 -11
  150. package/orm/index.d.ts +2 -1
  151. package/orm/index.js +2 -1
  152. package/orm/schemas/json.d.ts +1 -1
  153. package/orm/schemas/json.js +1 -1
  154. package/orm/schemas/numeric-date.d.ts +1 -1
  155. package/orm/schemas/numeric-date.js +1 -1
  156. package/orm/schemas/timestamp.d.ts +1 -1
  157. package/orm/schemas/timestamp.js +1 -1
  158. package/orm/schemas/uuid.d.ts +2 -2
  159. package/orm/schemas/uuid.js +1 -1
  160. package/orm/server/drizzle/schema-converter.ts +408 -0
  161. package/orm/server/repository.d.ts +1 -1
  162. package/orm/server/repository.js +12 -9
  163. package/orm/sqls.d.ts +1 -1
  164. package/orm/sqls.js +1 -1
  165. package/orm/types.d.ts +2 -6
  166. package/orm/types.js +1 -4
  167. package/package.json +15 -24
  168. package/queue/postgres/job.model.d.ts +3 -3
  169. package/queue/postgres/job.model.js +5 -6
  170. package/queue/postgres/queue.js +2 -2
  171. package/queue/postgres/schemas.d.ts +1 -1
  172. package/queue/postgres/schemas.js +1 -1
  173. package/supports.d.ts +1 -0
  174. package/supports.js +2 -1
  175. package/types/types.d.ts +12 -1
  176. package/utils/object/object.d.ts +3 -1
  177. package/utils/object/object.js +7 -1
  178. package/orm/server/drizzle/index.js +0 -1
  179. package/orm/server/drizzle/schema-converter.d.ts +0 -15
  180. package/orm/server/drizzle/schema-converter.js +0 -300
  181. /package/orm/server/drizzle/{index.d.ts → index.ts} +0 -0
package/orm/index.js CHANGED
@@ -3,10 +3,11 @@
3
3
  *
4
4
  * @module ORM
5
5
  */
6
- export * from './data-types/index.js';
6
+ export * from './decorators.js';
7
7
  export * from './entity.js';
8
8
  export * from './query.js';
9
9
  export * from './repository.types.js';
10
+ export * from './schemas/index.js';
10
11
  export * from './sqls.js';
11
12
  export * from './types.js';
12
13
  export * from './utils.js';
@@ -12,4 +12,4 @@ export declare class JsonSchema<T> extends Schema<T> {
12
12
  _test(value: any, path: JsonPath, options: SchemaTestOptions): SchemaTestResult<T>;
13
13
  }
14
14
  export declare function json<T>(options?: JsonSchemaOptions<T>): JsonSchema<T>;
15
- export declare function Json(options?: JsonSchemaOptions<any> & TypedOmit<SchemaDecoratorOptions, 'schema'>): Decorator<'class' | 'property' | 'accessor'>;
15
+ export declare function JsonProperty(options?: JsonSchemaOptions<any> & TypedOmit<SchemaDecoratorOptions, 'schema'>): Decorator<'class' | 'property' | 'accessor'>;
@@ -15,7 +15,7 @@ export class JsonSchema extends Schema {
15
15
  export function json(options) {
16
16
  return new JsonSchema(options);
17
17
  }
18
- export function Json(options) {
18
+ export function JsonProperty(options) {
19
19
  const { schema, ...optionsRest } = options ?? {};
20
20
  return createDecorator({ class: true, property: true, accessor: true }, (data, metadata, args) => {
21
21
  if (data.type == 'class') {
@@ -5,4 +5,4 @@ export declare class NumericDateSchema extends NumberSchema {
5
5
  constructor(options?: NumericDateSchemaOptions);
6
6
  }
7
7
  export declare function numericDate(options?: NumericDateSchemaOptions): NumericDateSchema;
8
- export declare function NumericDate(options?: NumericDateSchemaOptions & SchemaDecoratorOptions): SchemaPropertyDecorator;
8
+ export declare function NumericDateProperty(options?: NumericDateSchemaOptions & SchemaDecoratorOptions): SchemaPropertyDecorator;
@@ -8,6 +8,6 @@ export class NumericDateSchema extends NumberSchema {
8
8
  export function numericDate(options) {
9
9
  return new NumericDateSchema(options);
10
10
  }
11
- export function NumericDate(options) {
11
+ export function NumericDateProperty(options) {
12
12
  return Property(numericDate(options), options);
13
13
  }
@@ -7,4 +7,4 @@ export declare class TimestampSchema extends NumberSchema {
7
7
  _test(value: any, path: JsonPath, options: SchemaTestOptions): SchemaTestResult<number>;
8
8
  }
9
9
  export declare function timestamp(options?: TimestampSchemaOptions): TimestampSchema;
10
- export declare function Timestamp(options?: TimestampSchemaOptions & SchemaDecoratorOptions): SchemaPropertyDecorator;
10
+ export declare function TimestampProperty(options?: TimestampSchemaOptions & SchemaDecoratorOptions): SchemaPropertyDecorator;
@@ -15,6 +15,6 @@ export class TimestampSchema extends NumberSchema {
15
15
  export function timestamp(options) {
16
16
  return new TimestampSchema(options);
17
17
  }
18
- export function Timestamp(options) {
18
+ export function TimestampProperty(options) {
19
19
  return Property(timestamp(options), options);
20
20
  }
@@ -1,4 +1,4 @@
1
- import { StringSchema, type SchemaPropertyDecorator, type SchemaDecoratorOptions } from '../../schema/index.js';
1
+ import { StringSchema, type SchemaDecoratorOptions, type SchemaPropertyDecorator } from '../../schema/index.js';
2
2
  export type UuidSchemaOptions = {
3
3
  defaultRandom?: boolean;
4
4
  };
@@ -8,4 +8,4 @@ export declare class UuidSchema extends StringSchema {
8
8
  constructor(options?: UuidSchemaOptions);
9
9
  }
10
10
  export declare function uuid(options?: UuidSchemaOptions): UuidSchema;
11
- export declare function Uuid(options?: UuidSchemaOptions & SchemaDecoratorOptions): SchemaPropertyDecorator;
11
+ export declare function UuidProperty(options?: UuidSchemaOptions & SchemaDecoratorOptions): SchemaPropertyDecorator;
@@ -11,6 +11,6 @@ export class UuidSchema extends StringSchema {
11
11
  export function uuid(options) {
12
12
  return new UuidSchema(options);
13
13
  }
14
- export function Uuid(options) {
14
+ export function UuidProperty(options) {
15
15
  return Property(uuid(options), options);
16
16
  }
@@ -0,0 +1,408 @@
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
+ }
@@ -279,7 +279,7 @@ export declare class EntityRepository<T extends Entity | EntityWithoutMetadata =
279
279
  */
280
280
  deleteMany(ids: string[], metadataUpdate?: EntityMetadataUpdate): Promise<T[]>;
281
281
  /**
282
- * Deletes multiple entities matching a query (soft delete if metadata is available).
282
+ * Deletes multiple entities matching a query (soft delete if metadata is available). Already deleted entities are ignored.
283
283
  * @param query The query to filter entities.
284
284
  * @param metadataUpdate Optional metadata update to apply during soft delete.
285
285
  * @returns A promise that resolves to an array of the deleted entities.
@@ -62,13 +62,14 @@ let EntityRepository = class EntityRepository extends Transactional {
62
62
  }
63
63
  }
64
64
  async expirationLoop() {
65
- const softExpirationColumns = this.#columnDefinitions.filter((column) => column.reflectionData?.expirationField?.mode == 'soft');
66
- const hardExpirationColumns = this.#columnDefinitions.filter((column) => column.reflectionData?.expirationField?.mode == 'hard');
65
+ const expirationColumns = this.#columnDefinitions.filter((column) => isDefined(column.reflectionData?.expirationField));
66
+ const softExpirationColumns = expirationColumns.filter((column) => column.reflectionData.expirationField.mode == 'soft');
67
+ const hardExpirationColumns = expirationColumns.filter((column) => column.reflectionData.expirationField.mode == 'hard');
67
68
  if ((softExpirationColumns.length + hardExpirationColumns.length) == 0) {
68
69
  return;
69
70
  }
70
- const softDeletionQuery = or(...softExpirationColumns.map((column) => lte(this.getColumn(column), TRANSACTION_TIMESTAMP)));
71
- const hardDeletionQuery = or(...hardExpirationColumns.map((column) => lte(this.getColumn(column), TRANSACTION_TIMESTAMP)));
71
+ const softDeletionQuery = or(...softExpirationColumns.map((column) => lte(sql `${this.getColumn(column)} + INTERVAL '${sql.raw(String(column.reflectionData.expirationField.after))} ms'`, TRANSACTION_TIMESTAMP)));
72
+ const hardDeletionQuery = or(...hardExpirationColumns.map((column) => lte(sql `${this.getColumn(column)} + INTERVAL '${sql.raw(String(column.reflectionData.expirationField.after))} ms'`, TRANSACTION_TIMESTAMP)));
72
73
  assertDefined(this.#cancellationSignal);
73
74
  while (this.#cancellationSignal.isUnset) {
74
75
  if (isDefined(softDeletionQuery)) {
@@ -550,7 +551,7 @@ let EntityRepository = class EntityRepository extends Transactional {
550
551
  if (!this.hasMetadata) {
551
552
  return await this.tryHardDelete(id);
552
553
  }
553
- const sqlQuery = this.convertQuery(eq(this.#table.id, id));
554
+ const sqlQuery = and(isNull(this.#tableWithMetadata.deleteTimestamp), this.convertQuery(eq(this.#table.id, id)));
554
555
  const [row] = await this.session
555
556
  .update(this.#tableWithMetadata)
556
557
  .set({
@@ -591,13 +592,14 @@ let EntityRepository = class EntityRepository extends Transactional {
591
592
  return await this.tryHardDeleteByQuery(query);
592
593
  }
593
594
  const idQuery = this.getIdLimitQuery(query).for('update');
595
+ const sqlQuery = and(isNull(this.#tableWithMetadata.deleteTimestamp), inArray(this.#table.id, idQuery));
594
596
  const [row] = await this.session
595
597
  .update(this.#tableWithMetadata)
596
598
  .set({
597
599
  deleteTimestamp: TRANSACTION_TIMESTAMP,
598
600
  attributes: this.getAttributesUpdate(metadataUpdate?.attributes),
599
601
  })
600
- .where(inArray(this.#table.id, idQuery))
602
+ .where(sqlQuery)
601
603
  .returning();
602
604
  if (isUndefined(row)) {
603
605
  return undefined;
@@ -617,7 +619,7 @@ let EntityRepository = class EntityRepository extends Transactional {
617
619
  return await this.deleteManyByQuery(inArray(this.#table.id, ids), metadataUpdate);
618
620
  }
619
621
  /**
620
- * Deletes multiple entities matching a query (soft delete if metadata is available).
622
+ * Deletes multiple entities matching a query (soft delete if metadata is available). Already deleted entities are ignored.
621
623
  * @param query The query to filter entities.
622
624
  * @param metadataUpdate Optional metadata update to apply during soft delete.
623
625
  * @returns A promise that resolves to an array of the deleted entities.
@@ -626,7 +628,7 @@ let EntityRepository = class EntityRepository extends Transactional {
626
628
  if (!this.hasMetadata) {
627
629
  return await this.hardDeleteManyByQuery(query);
628
630
  }
629
- const sqlQuery = this.convertQuery(query);
631
+ const sqlQuery = and(isNull(this.#tableWithMetadata.deleteTimestamp), this.convertQuery(query));
630
632
  const rows = await this.session
631
633
  .update(this.#tableWithMetadata)
632
634
  .set({
@@ -690,9 +692,10 @@ let EntityRepository = class EntityRepository extends Transactional {
690
692
  */
691
693
  async tryHardDeleteByQuery(query) {
692
694
  const idQuery = this.getIdLimitQuery(query).for('update');
695
+ const sqlQuery = inArray(this.#table.id, idQuery);
693
696
  const [row] = await this.session
694
697
  .delete(this.#table)
695
- .where(inArray(this.#table.id, idQuery))
698
+ .where(sqlQuery)
696
699
  .returning();
697
700
  if (isUndefined(row)) {
698
701
  return undefined;
package/orm/sqls.d.ts CHANGED
@@ -4,7 +4,7 @@ import type { Uuid } from './types.js';
4
4
  /** Drizzle SQL helper for getting the current transaction's timestamp. Returns a Date object. */
5
5
  export declare const TRANSACTION_TIMESTAMP: SQL<Date>;
6
6
  /** Drizzle SQL helper for generating a random UUID (v4). Returns a Uuid string. */
7
- export declare const RANDOM_UUID: SQL<Uuid>;
7
+ export declare const RANDOM_UUID_V4: SQL<Uuid>;
8
8
  /** Represents valid units for PostgreSQL interval values. */
9
9
  export type IntervalUnit = 'millennium' | 'millenniums' | 'millennia' | 'century' | 'centuries' | 'decade' | 'decades' | 'year' | 'years' | 'day' | 'days' | 'hour' | 'hours' | 'minute' | 'minutes' | 'second' | 'seconds' | 'millisecond' | 'milliseconds' | 'microsecond' | 'microseconds';
10
10
  export declare function autoAlias<T>(column: AnyColumn<{
package/orm/sqls.js CHANGED
@@ -9,7 +9,7 @@ import { sql, Table } from 'drizzle-orm';
9
9
  /** Drizzle SQL helper for getting the current transaction's timestamp. Returns a Date object. */
10
10
  export const TRANSACTION_TIMESTAMP = sql `transaction_timestamp()`;
11
11
  /** Drizzle SQL helper for generating a random UUID (v4). Returns a Uuid string. */
12
- export const RANDOM_UUID = sql `gen_random_uuid()`;
12
+ export const RANDOM_UUID_V4 = sql `gen_random_uuid()`;
13
13
  export function autoAlias(column) {
14
14
  return sql `${column}`.as(`${column.table[Table['Symbol']['Name']]}_${column.name}`);
15
15
  }
package/orm/types.d.ts CHANGED
@@ -6,12 +6,8 @@
6
6
  */
7
7
  import type { $Type, HasDefault as DrizzleHasDefault, IsPrimaryKey as DrizzleIsPrimaryKey } from 'drizzle-orm';
8
8
  import type { boolean, doublePrecision, integer, jsonb, PgColumnBuilder, PgColumnBuilderBase, PgEnumColumnBuilderInitial, text, uuid } from 'drizzle-orm/pg-core';
9
- import { Array, Integer } from '../schema/index.js';
10
- import type { AbstractConstructor, EnumerationObject, EnumerationValue, ObjectLiteral, UnionToTuple } from '../types/index.js';
11
- import type { GetTagMetadata, HasTag, Tagged, UnwrapTagged } from '../types/index.js';
9
+ import type { AbstractConstructor, EnumerationObject, EnumerationValue, GetTagMetadata, HasTag, ObjectLiteral, Tagged, UnionToTuple, UnwrapTagged } from '../types/index.js';
12
10
  import type { bytea, numericDate, timestamp } from './data-types/index.js';
13
- import { Check, Column, Embedded, Encrypted, Index, PrimaryKey, References, Table, Unique } from './decorators.js';
14
- import { Json, NumericDate, Timestamp, Uuid } from './schemas/index.js';
15
11
  /** Tag identifier for column type information. */
16
12
  export type ColumnTypeTag = 'column';
17
13
  /** Tag identifier for embedded type configuration. */
@@ -90,4 +86,4 @@ export type Bytea = Tagged<Uint8Array, ColumnTypeTag, ReturnType<typeof bytea>>;
90
86
  * @template T - The original (unencrypted) type of the data.
91
87
  */
92
88
  export type Encrypted<T> = Tagged<T, ColumnTypeTag, ReturnType<typeof bytea>>;
93
- export { Array, Check, Column, Embedded, Encrypted, Index, Integer, Json, NumericDate, PrimaryKey, References, Table, Timestamp, Unique, Uuid };
89
+ export {};
package/orm/types.js CHANGED
@@ -1,4 +1 @@
1
- import { Array, Integer } from '../schema/index.js';
2
- import { Check, Column, Embedded, Encrypted, Index, PrimaryKey, References, Table, Unique } from './decorators.js';
3
- import { Json, NumericDate, Timestamp, Uuid } from './schemas/index.js';
4
- export { Array, Check, Column, Embedded, Encrypted, Index, Integer, Json, NumericDate, PrimaryKey, References, Table, Timestamp, Unique, Uuid };
1
+ export {};