metal-orm 1.0.43 → 1.0.45

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 (85) hide show
  1. package/README.md +700 -557
  2. package/dist/index.cjs +896 -476
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +1146 -275
  5. package/dist/index.d.ts +1146 -275
  6. package/dist/index.js +896 -474
  7. package/dist/index.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/core/ast/adapters.ts +8 -2
  10. package/src/core/ast/builders.ts +105 -81
  11. package/src/core/ast/expression-builders.ts +430 -390
  12. package/src/core/ast/expression-visitor.ts +47 -8
  13. package/src/core/ast/helpers.ts +23 -0
  14. package/src/core/ast/join-node.ts +17 -1
  15. package/src/core/ddl/dialects/base-schema-dialect.ts +7 -1
  16. package/src/core/ddl/dialects/index.ts +1 -0
  17. package/src/core/ddl/dialects/mssql-schema-dialect.ts +1 -0
  18. package/src/core/ddl/dialects/mysql-schema-dialect.ts +1 -0
  19. package/src/core/ddl/dialects/postgres-schema-dialect.ts +1 -0
  20. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +1 -0
  21. package/src/core/ddl/introspect/catalogs/index.ts +1 -0
  22. package/src/core/ddl/introspect/catalogs/postgres.ts +2 -0
  23. package/src/core/ddl/introspect/context.ts +6 -0
  24. package/src/core/ddl/introspect/functions/postgres.ts +13 -0
  25. package/src/core/ddl/introspect/mssql.ts +11 -0
  26. package/src/core/ddl/introspect/mysql.ts +2 -0
  27. package/src/core/ddl/introspect/postgres.ts +14 -0
  28. package/src/core/ddl/introspect/registry.ts +14 -0
  29. package/src/core/ddl/introspect/run-select.ts +13 -0
  30. package/src/core/ddl/introspect/sqlite.ts +22 -0
  31. package/src/core/ddl/introspect/utils.ts +18 -0
  32. package/src/core/ddl/naming-strategy.ts +6 -0
  33. package/src/core/ddl/schema-dialect.ts +19 -6
  34. package/src/core/ddl/schema-diff.ts +22 -0
  35. package/src/core/ddl/schema-generator.ts +22 -0
  36. package/src/core/ddl/schema-plan-executor.ts +6 -0
  37. package/src/core/ddl/schema-types.ts +6 -0
  38. package/src/core/dialect/abstract.ts +2 -2
  39. package/src/core/execution/pooling/pool.ts +12 -7
  40. package/src/core/functions/datetime.ts +57 -33
  41. package/src/core/functions/numeric.ts +95 -30
  42. package/src/core/functions/standard-strategy.ts +35 -0
  43. package/src/core/functions/text.ts +83 -22
  44. package/src/core/functions/types.ts +23 -8
  45. package/src/decorators/bootstrap.ts +16 -4
  46. package/src/decorators/column.ts +17 -0
  47. package/src/decorators/decorator-metadata.ts +27 -0
  48. package/src/decorators/entity.ts +8 -0
  49. package/src/decorators/index.ts +3 -0
  50. package/src/decorators/relations.ts +32 -0
  51. package/src/orm/als.ts +34 -9
  52. package/src/orm/entity-context.ts +54 -0
  53. package/src/orm/entity-metadata.ts +122 -9
  54. package/src/orm/execute.ts +15 -0
  55. package/src/orm/lazy-batch.ts +158 -98
  56. package/src/orm/relations/has-many.ts +44 -0
  57. package/src/orm/save-graph.ts +45 -0
  58. package/src/query/index.ts +74 -0
  59. package/src/query/target.ts +46 -0
  60. package/src/query-builder/delete-query-state.ts +30 -0
  61. package/src/query-builder/delete.ts +64 -19
  62. package/src/query-builder/hydration-manager.ts +46 -0
  63. package/src/query-builder/insert-query-state.ts +30 -0
  64. package/src/query-builder/insert.ts +46 -2
  65. package/src/query-builder/query-ast-service.ts +5 -0
  66. package/src/query-builder/query-resolution.ts +78 -0
  67. package/src/query-builder/raw-column-parser.ts +5 -0
  68. package/src/query-builder/relation-alias.ts +7 -0
  69. package/src/query-builder/relation-conditions.ts +61 -48
  70. package/src/query-builder/relation-service.ts +68 -63
  71. package/src/query-builder/relation-utils.ts +3 -0
  72. package/src/query-builder/select/cte-facet.ts +40 -0
  73. package/src/query-builder/select/from-facet.ts +80 -0
  74. package/src/query-builder/select/join-facet.ts +62 -0
  75. package/src/query-builder/select/predicate-facet.ts +103 -0
  76. package/src/query-builder/select/projection-facet.ts +69 -0
  77. package/src/query-builder/select/relation-facet.ts +81 -0
  78. package/src/query-builder/select/setop-facet.ts +36 -0
  79. package/src/query-builder/select-helpers.ts +13 -0
  80. package/src/query-builder/select-query-builder-deps.ts +19 -1
  81. package/src/query-builder/select-query-state.ts +2 -1
  82. package/src/query-builder/select.ts +795 -1163
  83. package/src/query-builder/update-query-state.ts +52 -0
  84. package/src/query-builder/update.ts +69 -19
  85. package/src/schema/table-guards.ts +31 -0
@@ -1,9 +1,15 @@
1
1
  import { FunctionStrategy, FunctionRenderer, FunctionRenderContext } from './types.js';
2
2
  import { LiteralNode, OperandNode, isOperandNode } from '../ast/expression.js';
3
3
 
4
+ /**
5
+ * Standard implementation of FunctionStrategy for ANSI SQL functions.
6
+ */
4
7
  export class StandardFunctionStrategy implements FunctionStrategy {
5
8
  protected renderers: Map<string, FunctionRenderer> = new Map();
6
9
 
10
+ /**
11
+ * Creates a new StandardFunctionStrategy and registers standard functions.
12
+ */
7
13
  constructor() {
8
14
  this.registerStandard();
9
15
  }
@@ -44,14 +50,27 @@ export class StandardFunctionStrategy implements FunctionStrategy {
44
50
  this.add('GROUP_CONCAT', ctx => this.renderGroupConcat(ctx));
45
51
  }
46
52
 
53
+ /**
54
+ * Registers a renderer for a function name.
55
+ * @param name - The function name.
56
+ * @param renderer - The renderer function.
57
+ */
47
58
  protected add(name: string, renderer: FunctionRenderer) {
48
59
  this.renderers.set(name, renderer);
49
60
  }
50
61
 
62
+ /**
63
+ * @inheritDoc
64
+ */
51
65
  getRenderer(name: string): FunctionRenderer | undefined {
52
66
  return this.renderers.get(name);
53
67
  }
54
68
 
69
+ /**
70
+ * Renders the GROUP_CONCAT function with optional ORDER BY and SEPARATOR.
71
+ * @param ctx - The function render context.
72
+ * @returns The rendered SQL string.
73
+ */
55
74
  private renderGroupConcat(ctx: FunctionRenderContext): string {
56
75
  const arg = ctx.compiledArgs[0];
57
76
  const orderClause = this.buildOrderByExpression(ctx);
@@ -60,6 +79,11 @@ export class StandardFunctionStrategy implements FunctionStrategy {
60
79
  return `GROUP_CONCAT(${arg}${orderSegment}${separatorClause})`;
61
80
  }
62
81
 
82
+ /**
83
+ * Builds the ORDER BY clause for functions like GROUP_CONCAT.
84
+ * @param ctx - The function render context.
85
+ * @returns The ORDER BY SQL clause or empty string.
86
+ */
63
87
  protected buildOrderByExpression(ctx: FunctionRenderContext): string {
64
88
  const orderBy = ctx.node.orderBy;
65
89
  if (!orderBy || orderBy.length === 0) {
@@ -78,6 +102,11 @@ export class StandardFunctionStrategy implements FunctionStrategy {
78
102
  return `ORDER BY ${parts.join(', ')}`;
79
103
  }
80
104
 
105
+ /**
106
+ * Formats the SEPARATOR clause for GROUP_CONCAT.
107
+ * @param ctx - The function render context.
108
+ * @returns The SEPARATOR SQL clause or empty string.
109
+ */
81
110
  protected formatGroupConcatSeparator(ctx: FunctionRenderContext): string {
82
111
  if (!ctx.node.separator) {
83
112
  return '';
@@ -85,10 +114,16 @@ export class StandardFunctionStrategy implements FunctionStrategy {
85
114
  return ` SEPARATOR ${ctx.compileOperand(ctx.node.separator)}`;
86
115
  }
87
116
 
117
+ /**
118
+ * Gets the separator operand for GROUP_CONCAT, defaulting to comma.
119
+ * @param ctx - The function render context.
120
+ * @returns The separator operand.
121
+ */
88
122
  protected getGroupConcatSeparatorOperand(ctx: FunctionRenderContext): OperandNode {
89
123
  return ctx.node.separator ?? StandardFunctionStrategy.DEFAULT_GROUP_CONCAT_SEPARATOR;
90
124
  }
91
125
 
126
+ /** Default separator for GROUP_CONCAT, a comma. */
92
127
  protected static readonly DEFAULT_GROUP_CONCAT_SEPARATOR: LiteralNode = {
93
128
  type: 'Literal',
94
129
  value: ','
@@ -23,22 +23,30 @@ const fn = (key: string, args: OperandInput[]): FunctionNode => ({
23
23
  });
24
24
 
25
25
  /**
26
- * Helper: LOWER(str)
26
+ * Converts a string to lowercase.
27
+ * @param value - The string value.
28
+ * @returns A FunctionNode representing the LOWER SQL function.
27
29
  */
28
30
  export const lower = (value: OperandInput): FunctionNode => fn('LOWER', [value]);
29
31
 
30
32
  /**
31
- * Helper: UPPER(str)
33
+ * Converts a string to uppercase.
34
+ * @param value - The string value.
35
+ * @returns A FunctionNode representing the UPPER SQL function.
32
36
  */
33
37
  export const upper = (value: OperandInput): FunctionNode => fn('UPPER', [value]);
34
38
 
35
39
  /**
36
- * Helper: ASCII(str)
40
+ * Returns the ASCII code of the first character of a string.
41
+ * @param value - The string value.
42
+ * @returns A FunctionNode representing the ASCII SQL function.
37
43
  */
38
44
  export const ascii = (value: OperandInput): FunctionNode => fn('ASCII', [value]);
39
45
 
40
46
  /**
41
- * Helper: CHAR(code[, code...])
47
+ * Returns a string from one or more ASCII codes.
48
+ * @param codes - The ASCII codes.
49
+ * @returns A FunctionNode representing the CHAR SQL function.
42
50
  */
43
51
  export const char = (...codes: OperandInput[]): FunctionNode => {
44
52
  if (codes.length === 0) throw new Error('char() expects at least 1 argument');
@@ -46,33 +54,46 @@ export const char = (...codes: OperandInput[]): FunctionNode => {
46
54
  };
47
55
 
48
56
  /**
49
- * Helper: CHAR_LENGTH(str)
57
+ * Returns the number of characters in a string.
58
+ * @param value - The string value.
59
+ * @returns A FunctionNode representing the CHAR_LENGTH SQL function.
50
60
  */
51
61
  export const charLength = (value: OperandInput): FunctionNode => fn('CHAR_LENGTH', [value]);
52
62
 
53
63
  /**
54
- * Helper: LENGTH(str)
64
+ * Returns the length of a string in bytes or characters.
65
+ * @param value - The string value.
66
+ * @returns A FunctionNode representing the LENGTH SQL function.
55
67
  */
56
68
  export const length = (value: OperandInput): FunctionNode => fn('LENGTH', [value]);
57
69
 
58
70
  /**
59
- * Helper: TRIM([chars FROM] str)
71
+ * Removes leading and trailing whitespace or specified characters from a string.
72
+ * @param value - The string value.
73
+ * @param chars - The characters to trim (optional).
74
+ * @returns A FunctionNode representing the TRIM SQL function.
60
75
  */
61
76
  export const trim = (value: OperandInput, chars?: OperandInput): FunctionNode =>
62
77
  chars === undefined ? fn('TRIM', [value]) : fn('TRIM', [value, chars]);
63
78
 
64
79
  /**
65
- * Helper: LTRIM(str)
80
+ * Removes leading whitespace from a string.
81
+ * @param value - The string value.
82
+ * @returns A FunctionNode representing the LTRIM SQL function.
66
83
  */
67
84
  export const ltrim = (value: OperandInput): FunctionNode => fn('LTRIM', [value]);
68
85
 
69
86
  /**
70
- * Helper: RTRIM(str)
87
+ * Removes trailing whitespace from a string.
88
+ * @param value - The string value.
89
+ * @returns A FunctionNode representing the RTRIM SQL function.
71
90
  */
72
91
  export const rtrim = (value: OperandInput): FunctionNode => fn('RTRIM', [value]);
73
92
 
74
93
  /**
75
- * Helper: CONCAT(arg1, arg2, ...)
94
+ * Concatenates two or more strings.
95
+ * @param args - The strings to concatenate.
96
+ * @returns A FunctionNode representing the CONCAT SQL function.
76
97
  */
77
98
  export const concat = (...args: OperandInput[]): FunctionNode => {
78
99
  if (args.length < 2) throw new Error('concat() expects at least 2 arguments');
@@ -80,7 +101,10 @@ export const concat = (...args: OperandInput[]): FunctionNode => {
80
101
  };
81
102
 
82
103
  /**
83
- * Helper: CONCAT_WS(separator, arg1, arg2, ...)
104
+ * Concatenates strings with a separator.
105
+ * @param separator - The separator string.
106
+ * @param args - The strings to concatenate.
107
+ * @returns A FunctionNode representing the CONCAT_WS SQL function.
84
108
  */
85
109
  export const concatWs = (separator: OperandInput, ...args: OperandInput[]): FunctionNode => {
86
110
  if (args.length < 1) throw new Error('concatWs() expects at least 2 arguments including the separator');
@@ -88,61 +112,98 @@ export const concatWs = (separator: OperandInput, ...args: OperandInput[]): Func
88
112
  };
89
113
 
90
114
  /**
91
- * Helper: SUBSTR(str, start[, length])
115
+ * Extracts a substring from a string.
116
+ * @param value - The string value.
117
+ * @param start - The starting position.
118
+ * @param length - The length of the substring (optional).
119
+ * @returns A FunctionNode representing the SUBSTR SQL function.
92
120
  */
93
121
  export const substr = (value: OperandInput, start: OperandInput, length?: OperandInput): FunctionNode =>
94
122
  length === undefined ? fn('SUBSTR', [value, start]) : fn('SUBSTR', [value, start, length]);
95
123
 
96
124
  /**
97
- * Helper: LEFT(str, length)
125
+ * Returns the leftmost characters of a string.
126
+ * @param value - The string value.
127
+ * @param len - The number of characters to return.
128
+ * @returns A FunctionNode representing the LEFT SQL function.
98
129
  */
99
130
  export const left = (value: OperandInput, len: OperandInput): FunctionNode => fn('LEFT', [value, len]);
100
131
 
101
132
  /**
102
- * Helper: RIGHT(str, length)
133
+ * Returns the rightmost characters of a string.
134
+ * @param value - The string value.
135
+ * @param len - The number of characters to return.
136
+ * @returns A FunctionNode representing the RIGHT SQL function.
103
137
  */
104
138
  export const right = (value: OperandInput, len: OperandInput): FunctionNode => fn('RIGHT', [value, len]);
105
139
 
106
140
  /**
107
- * Helper: POSITION(substring IN string)
141
+ * Returns the position of a substring in a string.
142
+ * @param substring - The substring to search for.
143
+ * @param value - The string to search in.
144
+ * @returns A FunctionNode representing the POSITION SQL function.
108
145
  */
109
146
  export const position = (substring: OperandInput, value: OperandInput): FunctionNode => fn('POSITION', [substring, value]);
110
147
 
111
148
  /**
112
- * Helper: INSTR(string, substring)
149
+ * Returns the position of a substring in a string.
150
+ * @param value - The string to search in.
151
+ * @param substring - The substring to search for.
152
+ * @returns A FunctionNode representing the INSTR SQL function.
113
153
  */
114
154
  export const instr = (value: OperandInput, substring: OperandInput): FunctionNode => fn('INSTR', [value, substring]);
115
155
 
116
156
  /**
117
- * Helper: LOCATE(substring, string[, start])
157
+ * Returns the position of a substring in a string, optionally starting from a position.
158
+ * @param substring - The substring to search for.
159
+ * @param value - The string to search in.
160
+ * @param start - The starting position (optional).
161
+ * @returns A FunctionNode representing the LOCATE SQL function.
118
162
  */
119
163
  export const locate = (substring: OperandInput, value: OperandInput, start?: OperandInput): FunctionNode =>
120
164
  start === undefined ? fn('LOCATE', [substring, value]) : fn('LOCATE', [substring, value, start]);
121
165
 
122
166
  /**
123
- * Helper: REPLACE(string, search, replace)
167
+ * Replaces occurrences of a substring in a string.
168
+ * @param value - The string to search in.
169
+ * @param search - The substring to replace.
170
+ * @param replacement - The replacement string.
171
+ * @returns A FunctionNode representing the REPLACE SQL function.
124
172
  */
125
173
  export const replace = (value: OperandInput, search: OperandInput, replacement: OperandInput): FunctionNode =>
126
174
  fn('REPLACE', [value, search, replacement]);
127
175
 
128
176
  /**
129
- * Helper: REPEAT(string, count)
177
+ * Repeats a string a specified number of times.
178
+ * @param value - The string to repeat.
179
+ * @param count - The number of times to repeat.
180
+ * @returns A FunctionNode representing the REPEAT SQL function.
130
181
  */
131
182
  export const repeat = (value: OperandInput, count: OperandInput): FunctionNode => fn('REPEAT', [value, count]);
132
183
 
133
184
  /**
134
- * Helper: LPAD(string, length, padstr)
185
+ * Left-pads a string to a certain length with another string.
186
+ * @param value - The string to pad.
187
+ * @param len - The length to pad to.
188
+ * @param pad - The padding string.
189
+ * @returns A FunctionNode representing the LPAD SQL function.
135
190
  */
136
191
  export const lpad = (value: OperandInput, len: OperandInput, pad: OperandInput): FunctionNode =>
137
192
  fn('LPAD', [value, len, pad]);
138
193
 
139
194
  /**
140
- * Helper: RPAD(string, length, padstr)
195
+ * Right-pads a string to a certain length with another string.
196
+ * @param value - The string to pad.
197
+ * @param len - The length to pad to.
198
+ * @param pad - The padding string.
199
+ * @returns A FunctionNode representing the RPAD SQL function.
141
200
  */
142
201
  export const rpad = (value: OperandInput, len: OperandInput, pad: OperandInput): FunctionNode =>
143
202
  fn('RPAD', [value, len, pad]);
144
203
 
145
204
  /**
146
- * Helper: SPACE(count)
205
+ * Returns a string consisting of a specified number of spaces.
206
+ * @param count - The number of spaces.
207
+ * @returns A FunctionNode representing the SPACE SQL function.
147
208
  */
148
209
  export const space = (count: OperandInput): FunctionNode => fn('SPACE', [count]);
@@ -1,18 +1,33 @@
1
- import { FunctionNode, OperandNode } from '../ast/expression.js';
2
-
3
- export interface FunctionRenderContext {
4
- node: FunctionNode;
5
- compiledArgs: string[];
6
- /** Helper to compile additional operands (e.g., separators or ORDER BY columns) */
7
- compileOperand: (operand: OperandNode) => string;
8
- }
1
+ import { FunctionNode, OperandNode } from '../ast/expression.js';
9
2
 
3
+ /**
4
+ * Context provided to function renderers.
5
+ */
6
+ export interface FunctionRenderContext {
7
+ /** The function node being rendered. */
8
+ node: FunctionNode;
9
+ /** The compiled arguments for the function. */
10
+ compiledArgs: string[];
11
+ /** Helper to compile additional operands (e.g., separators or ORDER BY columns). */
12
+ compileOperand: (operand: OperandNode) => string;
13
+ }
14
+
15
+ /**
16
+ * A function that renders a SQL function call.
17
+ * @param ctx - The rendering context.
18
+ * @returns The rendered SQL string.
19
+ */
10
20
  export type FunctionRenderer = (ctx: FunctionRenderContext) => string;
11
21
 
22
+ /**
23
+ * Strategy for rendering SQL functions in a specific dialect.
24
+ */
12
25
  export interface FunctionStrategy {
13
26
  /**
14
27
  * Returns a renderer for a specific function name (e.g. "DATE_ADD").
15
28
  * Returns undefined if this dialect doesn't support the function.
29
+ * @param functionName - The name of the function.
30
+ * @returns The renderer function or undefined.
16
31
  */
17
32
  getRenderer(functionName: string): FunctionRenderer | undefined;
18
33
  }
@@ -8,6 +8,7 @@ import {
8
8
  type RelationDef
9
9
  } from '../schema/relation.js';
10
10
  import { TableDef } from '../schema/table.js';
11
+ import { isTableDef } from '../schema/table-guards.js';
11
12
  import {
12
13
  buildTableDef,
13
14
  EntityConstructor,
@@ -20,10 +21,6 @@ import {
20
21
 
21
22
  import { tableRef, type TableRef } from '../schema/table.js';
22
23
 
23
- const isTableDef = (value: unknown): value is TableDef => {
24
- return typeof value === 'object' && value !== null && 'columns' in (value as TableDef);
25
- };
26
-
27
24
  const unwrapTarget = (target: EntityOrTableTargetResolver): EntityOrTableTarget => {
28
25
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
29
26
  if (typeof target === 'function' && (target as Function).prototype === undefined) {
@@ -104,6 +101,10 @@ const buildRelationDefinitions = (
104
101
  return relations;
105
102
  };
106
103
 
104
+ /**
105
+ * Bootstraps all entities by building their table definitions and relations.
106
+ * @returns An array of table definitions for all bootstrapped entities.
107
+ */
107
108
  export const bootstrapEntities = (): TableDef[] => {
108
109
  const metas = getAllEntityMetadata();
109
110
  const tableMap = new Map<EntityConstructor, TableDef>();
@@ -122,6 +123,12 @@ export const bootstrapEntities = (): TableDef[] => {
122
123
  return metas.map(meta => meta.table!) as TableDef[];
123
124
  };
124
125
 
126
+ /**
127
+ * Gets the table definition for a given entity constructor.
128
+ * Bootstraps entities if necessary.
129
+ * @param ctor - The entity constructor.
130
+ * @returns The table definition or undefined if not found.
131
+ */
125
132
  export const getTableDefFromEntity = <TTable extends TableDef = TableDef>(ctor: EntityConstructor): TTable | undefined => {
126
133
  const meta = getEntityMetadata(ctor);
127
134
  if (!meta) return undefined;
@@ -131,6 +138,11 @@ export const getTableDefFromEntity = <TTable extends TableDef = TableDef>(ctor:
131
138
  return meta.table as TTable;
132
139
  };
133
140
 
141
+ /**
142
+ * Creates a select query builder for the given entity.
143
+ * @param ctor - The entity constructor.
144
+ * @returns A select query builder for the entity.
145
+ */
134
146
  export const selectFromEntity = <TTable extends TableDef = TableDef>(
135
147
  ctor: EntityConstructor
136
148
  ): SelectQueryBuilder<unknown, TTable> => {
@@ -12,6 +12,9 @@ import {
12
12
  StandardDecoratorContext
13
13
  } from './decorator-metadata.js';
14
14
 
15
+ /**
16
+ * Options for defining a column in an entity.
17
+ */
15
18
  export interface ColumnOptions {
16
19
  type: ColumnType;
17
20
  args?: ColumnDef['args'];
@@ -20,6 +23,9 @@ export interface ColumnOptions {
20
23
  tsType?: ColumnDef['tsType'];
21
24
  }
22
25
 
26
+ /**
27
+ * Input type for column definitions, either as options object or direct ColumnDef.
28
+ */
23
29
  export type ColumnInput = ColumnOptions | ColumnDef;
24
30
 
25
31
  const normalizeColumnInput = (input: ColumnInput): ColumnDefLike => {
@@ -89,6 +95,11 @@ const registerColumnFromContext = (
89
95
 
90
96
  };
91
97
 
98
+ /**
99
+ * Decorator to define a column on an entity property.
100
+ * @param definition - The column definition or options.
101
+ * @returns A property decorator that registers the column metadata.
102
+ */
92
103
  export function Column(definition: ColumnInput) {
93
104
  const normalized = normalizeColumnInput(definition);
94
105
  const decorator: DualModePropertyDecorator = (targetOrValue, propertyKeyOrContext) => {
@@ -108,6 +119,12 @@ export function Column(definition: ColumnInput) {
108
119
  return decorator;
109
120
  }
110
121
 
122
+ /**
123
+ * Decorator to define a primary key column on an entity property.
124
+ * Sets the primary flag to true and delegates to Column decorator.
125
+ * @param definition - The column definition or options.
126
+ * @returns A property decorator that registers the primary key column metadata.
127
+ */
111
128
  export function PrimaryKey(definition: ColumnInput) {
112
129
  const normalized = normalizeColumnInput(definition);
113
130
  normalized.primary = true;
@@ -1,5 +1,8 @@
1
1
  import { ColumnDefLike, RelationMetadata } from '../orm/entity-metadata.js';
2
2
 
3
+ /**
4
+ * Context object provided by standard decorators in newer TypeScript versions.
5
+ */
3
6
  export interface StandardDecoratorContext {
4
7
  kind: string;
5
8
  name?: string | symbol;
@@ -8,11 +11,17 @@ export interface StandardDecoratorContext {
8
11
  private?: boolean;
9
12
  }
10
13
 
14
+ /**
15
+ * Dual-mode property decorator that supports both legacy and standard decorator syntax.
16
+ */
11
17
  export interface DualModePropertyDecorator {
12
18
  (target: object, propertyKey: string | symbol): void;
13
19
  (value: unknown, context: StandardDecoratorContext): void;
14
20
  }
15
21
 
22
+ /**
23
+ * Dual-mode class decorator that supports both legacy and standard decorator syntax.
24
+ */
16
25
  export interface DualModeClassDecorator {
17
26
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
18
27
  <TFunction extends Function>(value: TFunction): void | TFunction;
@@ -20,6 +29,9 @@ export interface DualModeClassDecorator {
20
29
  <TFunction extends Function>(value: TFunction, context: StandardDecoratorContext): void | TFunction;
21
30
  }
22
31
 
32
+ /**
33
+ * Bag for storing decorator metadata during the decoration phase.
34
+ */
23
35
  export interface DecoratorMetadataBag {
24
36
  columns: Array<{ propertyName: string; column: ColumnDefLike }>;
25
37
  relations: Array<{ propertyName: string; relation: RelationMetadata }>;
@@ -27,10 +39,20 @@ export interface DecoratorMetadataBag {
27
39
 
28
40
  const METADATA_KEY = 'metal-orm:decorators';
29
41
 
42
+ /**
43
+ * Checks if a value is a StandardDecoratorContext.
44
+ * @param value - The value to check.
45
+ * @returns True if the value is a StandardDecoratorContext.
46
+ */
30
47
  export const isStandardDecoratorContext = (value: unknown): value is StandardDecoratorContext => {
31
48
  return typeof value === 'object' && value !== null && 'kind' in (value as object);
32
49
  };
33
50
 
51
+ /**
52
+ * Gets or creates a metadata bag for the given decorator context.
53
+ * @param context - The decorator context.
54
+ * @returns The metadata bag.
55
+ */
34
56
  export const getOrCreateMetadataBag = (context: StandardDecoratorContext): DecoratorMetadataBag => {
35
57
  const metadata = context.metadata || (context.metadata = {} as Record<PropertyKey, unknown>);
36
58
  const existing = metadata[METADATA_KEY] as DecoratorMetadataBag | undefined;
@@ -42,6 +64,11 @@ export const getOrCreateMetadataBag = (context: StandardDecoratorContext): Decor
42
64
  return bag;
43
65
  };
44
66
 
67
+ /**
68
+ * Reads the metadata bag from the given decorator context.
69
+ * @param context - The decorator context.
70
+ * @returns The metadata bag if present.
71
+ */
45
72
  export const readMetadataBag = (context: StandardDecoratorContext): DecoratorMetadataBag | undefined => {
46
73
  return context.metadata?.[METADATA_KEY] as DecoratorMetadataBag | undefined;
47
74
  };
@@ -9,6 +9,9 @@ import {
9
9
  } from '../orm/entity-metadata.js';
10
10
  import { DualModeClassDecorator, isStandardDecoratorContext, readMetadataBag } from './decorator-metadata.js';
11
11
 
12
+ /**
13
+ * Options for defining an entity.
14
+ */
12
15
  export interface EntityOptions {
13
16
  tableName?: string;
14
17
  hooks?: TableHooks;
@@ -34,6 +37,11 @@ const deriveTableNameFromConstructor = (ctor: EntityConstructor<unknown>): strin
34
37
  return normalized.endsWith('s') ? normalized : `${normalized}s`;
35
38
  };
36
39
 
40
+ /**
41
+ * Class decorator to mark a class as an entity and configure its table mapping.
42
+ * @param options - Configuration options for the entity.
43
+ * @returns A class decorator that registers the entity metadata.
44
+ */
37
45
  export function Entity(options: EntityOptions = {}) {
38
46
  const decorator: DualModeClassDecorator = value => {
39
47
  const tableName = options.tableName ?? deriveTableNameFromConstructor(value);
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Decorators for defining entities, columns, and relations in Metal ORM.
3
+ */
1
4
  export * from './entity.js';
2
5
  export * from './column.js';
3
6
  export * from './relations.js';
@@ -18,18 +18,30 @@ interface BaseRelationOptions {
18
18
  localKey?: string;
19
19
  }
20
20
 
21
+ /**
22
+ * Options for HasMany relation.
23
+ */
21
24
  export interface HasManyOptions extends BaseRelationOptions {
22
25
  foreignKey: string;
23
26
  }
24
27
 
28
+ /**
29
+ * Options for HasOne relation.
30
+ */
25
31
  export interface HasOneOptions extends BaseRelationOptions {
26
32
  foreignKey: string;
27
33
  }
28
34
 
35
+ /**
36
+ * Options for BelongsTo relation.
37
+ */
29
38
  export interface BelongsToOptions extends BaseRelationOptions {
30
39
  foreignKey: string;
31
40
  }
32
41
 
42
+ /**
43
+ * Options for BelongsToMany relation.
44
+ */
33
45
  export interface BelongsToManyOptions {
34
46
  target: EntityOrTableTargetResolver;
35
47
  pivotTable: EntityOrTableTargetResolver;
@@ -93,6 +105,11 @@ const createFieldDecorator = (
93
105
  return decorator;
94
106
  };
95
107
 
108
+ /**
109
+ * Decorator to define a HasMany relation on an entity property.
110
+ * @param options - The relation options.
111
+ * @returns A property decorator that registers the relation metadata.
112
+ */
96
113
  export function HasMany(options: HasManyOptions) {
97
114
  return createFieldDecorator(propertyName => ({
98
115
  kind: RelationKinds.HasMany,
@@ -104,6 +121,11 @@ export function HasMany(options: HasManyOptions) {
104
121
  }));
105
122
  }
106
123
 
124
+ /**
125
+ * Decorator to define a HasOne relation on an entity property.
126
+ * @param options - The relation options.
127
+ * @returns A property decorator that registers the relation metadata.
128
+ */
107
129
  export function HasOne(options: HasOneOptions) {
108
130
  return createFieldDecorator(propertyName => ({
109
131
  kind: RelationKinds.HasOne,
@@ -115,6 +137,11 @@ export function HasOne(options: HasOneOptions) {
115
137
  }));
116
138
  }
117
139
 
140
+ /**
141
+ * Decorator to define a BelongsTo relation on an entity property.
142
+ * @param options - The relation options.
143
+ * @returns A property decorator that registers the relation metadata.
144
+ */
118
145
  export function BelongsTo(options: BelongsToOptions) {
119
146
  return createFieldDecorator(propertyName => ({
120
147
  kind: RelationKinds.BelongsTo,
@@ -126,6 +153,11 @@ export function BelongsTo(options: BelongsToOptions) {
126
153
  }));
127
154
  }
128
155
 
156
+ /**
157
+ * Decorator to define a BelongsToMany relation on an entity property.
158
+ * @param options - The relation options.
159
+ * @returns A property decorator that registers the relation metadata.
160
+ */
129
161
  export function BelongsToMany(options: BelongsToManyOptions) {
130
162
  return createFieldDecorator(propertyName => ({
131
163
  kind: RelationKinds.BelongsToMany,
package/src/orm/als.ts CHANGED
@@ -1,18 +1,31 @@
1
1
  // In a real Node environment: import { AsyncLocalStorage } from 'node:async_hooks';
2
2
 
3
3
  /**
4
- * Browser-compatible implementation of AsyncLocalStorage
5
- * Provides a simple in-memory store for browser environments
6
- * @typeParam T - Type of the stored data
4
+ * Browser-compatible implementation of AsyncLocalStorage.
5
+ * Provides a simple in-memory store for browser environments while maintaining
6
+ * Node.js AsyncLocalStorage API compatibility.
7
+ *
8
+ * @template T Type of the data stored in the async context
7
9
  */
8
10
  export class AsyncLocalStorage<T> {
9
11
  private store: T | undefined;
10
12
 
11
13
  /**
12
- * Executes a callback with the specified store value
13
- * @param store - Value to store during callback execution
14
- * @param callback - Function to execute with the store value
15
- * @returns Result of the callback function
14
+ * Executes a callback function within a context containing the specified store value.
15
+ * The store value is only available during the callback's execution and is automatically
16
+ * cleared afterward.
17
+ *
18
+ * @param store - The context value to make available during callback execution
19
+ * @param callback - Function to execute with the store value available
20
+ * @returns Result of the callback function execution
21
+ *
22
+ * @example
23
+ * ```
24
+ * const als = new AsyncLocalStorage<number>();
25
+ * als.run(42, () => {
26
+ * console.log(als.getStore()); // Outputs: 42
27
+ * });
28
+ * ```
16
29
  */
17
30
  run<R>(store: T, callback: () => R): R {
18
31
  this.store = store;
@@ -24,8 +37,20 @@ export class AsyncLocalStorage<T> {
24
37
  }
25
38
 
26
39
  /**
27
- * Gets the currently stored value
28
- * @returns Current store value or undefined if none exists
40
+ * Retrieves the current store value from the async context.
41
+ * Returns undefined if called outside of a `run()` callback execution.
42
+ *
43
+ * @returns Current store value or undefined if no context exists
44
+ *
45
+ * @example
46
+ * ```
47
+ * const als = new AsyncLocalStorage<string>();
48
+ * console.log(als.getStore()); // Outputs: undefined
49
+ *
50
+ * als.run('hello', () => {
51
+ * console.log(als.getStore()); // Outputs: 'hello'
52
+ * });
53
+ * ```
29
54
  */
30
55
  getStore(): T | undefined {
31
56
  return this.store;