metal-orm 1.1.10 → 1.1.16

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 (192) hide show
  1. package/README.md +758 -769
  2. package/dist/index.cjs +106 -43
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +5 -5
  5. package/dist/index.d.ts +5 -5
  6. package/dist/index.js +106 -43
  7. package/dist/index.js.map +1 -1
  8. package/package.json +100 -96
  9. package/scripts/generate-entities/render.mjs +21 -12
  10. package/scripts/generate-entities/schema.mjs +209 -195
  11. package/scripts/generate-entities/tree-detection.mjs +159 -153
  12. package/scripts/inflection/pt-br.mjs +468 -468
  13. package/scripts/run-eslint.mjs +33 -34
  14. package/scripts/show-sql-seed.sql +102 -0
  15. package/scripts/show-sql.mjs +321 -325
  16. package/src/bulk/bulk-delete-executor.ts +3 -5
  17. package/src/bulk/bulk-insert-executor.ts +7 -7
  18. package/src/bulk/bulk-update-executor.ts +2 -2
  19. package/src/bulk/bulk-upsert-executor.ts +5 -7
  20. package/src/codegen/naming-strategy.ts +54 -54
  21. package/src/codegen/typescript.ts +482 -482
  22. package/src/core/ast/adapters.ts +1 -1
  23. package/src/core/ast/builders.ts +123 -123
  24. package/src/core/ast/expression-builders.ts +745 -745
  25. package/src/core/ast/expression-nodes.ts +304 -304
  26. package/src/core/ast/expression-visitor.ts +212 -212
  27. package/src/core/ast/expression.ts +20 -20
  28. package/src/core/ast/helpers.ts +14 -14
  29. package/src/core/ast/join.ts +18 -18
  30. package/src/core/ast/query.ts +200 -200
  31. package/src/core/ddl/dialects/base-schema-dialect.ts +1 -1
  32. package/src/core/ddl/dialects/mssql-schema-dialect.ts +1 -1
  33. package/src/core/ddl/dialects/mysql-schema-dialect.ts +1 -1
  34. package/src/core/ddl/dialects/postgres-schema-dialect.ts +1 -1
  35. package/src/core/ddl/dialects/render-reference.test.ts +70 -70
  36. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +1 -1
  37. package/src/core/ddl/introspect/catalogs/index.ts +5 -5
  38. package/src/core/ddl/introspect/catalogs/postgres.ts +146 -146
  39. package/src/core/ddl/introspect/context.ts +15 -15
  40. package/src/core/ddl/introspect/functions/postgres.ts +35 -35
  41. package/src/core/ddl/introspect/mysql.ts +113 -36
  42. package/src/core/ddl/introspect/registry.ts +40 -40
  43. package/src/core/ddl/introspect/run-select.ts +35 -35
  44. package/src/core/ddl/introspect/utils.ts +56 -56
  45. package/src/core/ddl/naming-strategy.ts +16 -16
  46. package/src/core/ddl/schema-dialect.ts +56 -56
  47. package/src/core/ddl/schema-diff.ts +234 -234
  48. package/src/core/ddl/schema-generator.ts +1 -1
  49. package/src/core/ddl/schema-introspect.ts +25 -25
  50. package/src/core/ddl/sql-writing.ts +171 -171
  51. package/src/core/dialect/abstract.ts +541 -541
  52. package/src/core/dialect/base/cte-compiler.ts +33 -33
  53. package/src/core/dialect/base/function-table-formatter.ts +103 -103
  54. package/src/core/dialect/base/groupby-compiler.ts +21 -21
  55. package/src/core/dialect/base/join-compiler.ts +25 -25
  56. package/src/core/dialect/base/orderby-compiler.ts +35 -35
  57. package/src/core/dialect/base/pagination-strategy.ts +32 -32
  58. package/src/core/dialect/base/returning-strategy.ts +57 -57
  59. package/src/core/dialect/base/sql-dialect.ts +294 -294
  60. package/src/core/dialect/dialect-factory.ts +91 -91
  61. package/src/core/dialect/mssql/functions.ts +120 -120
  62. package/src/core/dialect/mssql/index.ts +317 -317
  63. package/src/core/dialect/mysql/functions.ts +103 -103
  64. package/src/core/dialect/mysql/index.ts +105 -105
  65. package/src/core/dialect/postgres/functions.ts +108 -108
  66. package/src/core/dialect/postgres/index.ts +91 -91
  67. package/src/core/dialect/sqlite/functions.ts +129 -129
  68. package/src/core/dialect/sqlite/index.ts +67 -67
  69. package/src/core/driver/database-driver.ts +19 -19
  70. package/src/core/driver/mssql-driver.ts +23 -23
  71. package/src/core/driver/mysql-driver.ts +23 -23
  72. package/src/core/driver/postgres-driver.ts +23 -23
  73. package/src/core/driver/sqlite-driver.ts +23 -23
  74. package/src/core/execution/db-executor.ts +92 -92
  75. package/src/core/execution/executors/better-sqlite3-executor.ts +94 -94
  76. package/src/core/execution/executors/mssql-executor.ts +184 -184
  77. package/src/core/execution/executors/mysql-executor.ts +88 -88
  78. package/src/core/execution/executors/postgres-executor.ts +26 -26
  79. package/src/core/execution/executors/sqlite-executor.ts +42 -42
  80. package/src/core/execution/pooling/pool-types.ts +30 -30
  81. package/src/core/execution/pooling/pool.ts +275 -275
  82. package/src/core/functions/array.ts +35 -35
  83. package/src/core/functions/control-flow.ts +79 -79
  84. package/src/core/functions/datetime.ts +237 -237
  85. package/src/core/functions/json.ts +70 -70
  86. package/src/core/functions/numeric.ts +297 -297
  87. package/src/core/functions/text.ts +334 -334
  88. package/src/core/functions/types.ts +33 -33
  89. package/src/core/hydration/types.ts +51 -51
  90. package/src/core/sql/sql-operator-config.ts +39 -39
  91. package/src/core/sql/sql.ts +152 -152
  92. package/src/decorators/column-decorator.ts +87 -87
  93. package/src/decorators/decorator-metadata.ts +143 -143
  94. package/src/decorators/entity.ts +93 -93
  95. package/src/decorators/index.ts +39 -39
  96. package/src/decorators/relations.ts +231 -231
  97. package/src/decorators/transformers/built-in/string-transformers.ts +231 -231
  98. package/src/decorators/transformers/transformer-decorators.ts +134 -134
  99. package/src/decorators/transformers/transformer-executor.ts +171 -171
  100. package/src/decorators/transformers/transformer-metadata.ts +73 -73
  101. package/src/decorators/validators/built-in/br-cep-validator.ts +55 -55
  102. package/src/decorators/validators/built-in/br-cnpj-validator.ts +105 -105
  103. package/src/decorators/validators/built-in/br-cpf-validator.ts +103 -103
  104. package/src/decorators/validators/country-validator-registry.ts +64 -64
  105. package/src/decorators/validators/country-validators-decorators.ts +203 -203
  106. package/src/decorators/validators/country-validators.ts +105 -105
  107. package/src/decorators/validators/validator-metadata.ts +59 -59
  108. package/src/dto/dto-types.ts +226 -226
  109. package/src/dto/filter-types.ts +141 -141
  110. package/src/dto/index.ts +95 -95
  111. package/src/dto/openapi/generators/base.ts +29 -29
  112. package/src/dto/openapi/generators/column.ts +37 -37
  113. package/src/dto/openapi/generators/dto.ts +91 -91
  114. package/src/dto/openapi/generators/filter.ts +75 -75
  115. package/src/dto/openapi/generators/nested-dto.ts +618 -618
  116. package/src/dto/openapi/generators/pagination.ts +111 -111
  117. package/src/dto/openapi/generators/relation-filter.ts +228 -228
  118. package/src/dto/openapi/index.ts +12 -12
  119. package/src/dto/openapi/types.ts +101 -101
  120. package/src/dto/openapi/utilities.ts +95 -95
  121. package/src/dto/pagination-utils.ts +150 -150
  122. package/src/dto/transform.ts +197 -197
  123. package/src/index.ts +86 -86
  124. package/src/orm/als.ts +58 -58
  125. package/src/orm/domain-event-bus.ts +119 -119
  126. package/src/orm/entity-context.ts +86 -86
  127. package/src/orm/entity-materializer.ts +159 -159
  128. package/src/orm/entity-meta.ts +97 -97
  129. package/src/orm/entity-registry.ts +39 -39
  130. package/src/orm/entity-relation-cache.ts +39 -39
  131. package/src/orm/execute.ts +194 -194
  132. package/src/orm/execution-context.ts +18 -18
  133. package/src/orm/hydration-context.ts +26 -26
  134. package/src/orm/hydration.ts +112 -112
  135. package/src/orm/identity-map.ts +61 -61
  136. package/src/orm/interceptor-pipeline.ts +16 -16
  137. package/src/orm/lazy-batch/belongs-to-many.ts +119 -119
  138. package/src/orm/lazy-batch/belongs-to.ts +108 -108
  139. package/src/orm/lazy-batch/has-many.ts +69 -69
  140. package/src/orm/lazy-batch/has-one.ts +68 -68
  141. package/src/orm/lazy-batch/shared.ts +125 -125
  142. package/src/orm/orm-session.ts +620 -620
  143. package/src/orm/orm.ts +34 -34
  144. package/src/orm/pooled-executor-factory.ts +121 -121
  145. package/src/orm/query-logger.ts +40 -40
  146. package/src/orm/relation-change-processor.ts +420 -420
  147. package/src/orm/relations/belongs-to.ts +143 -143
  148. package/src/orm/relations/has-many.ts +204 -204
  149. package/src/orm/relations/has-one.ts +174 -174
  150. package/src/orm/relations/many-to-many.ts +288 -288
  151. package/src/orm/relations/morph-many.ts +156 -156
  152. package/src/orm/relations/morph-one.ts +151 -151
  153. package/src/orm/relations/morph-to.ts +162 -162
  154. package/src/orm/runtime-types.ts +92 -92
  155. package/src/orm/save-graph.ts +561 -561
  156. package/src/orm/transaction-runner.ts +24 -24
  157. package/src/orm/unit-of-work.ts +426 -426
  158. package/src/query/index.ts +69 -69
  159. package/src/query/target.ts +46 -46
  160. package/src/query-builder/column-selector.ts +81 -81
  161. package/src/query-builder/delete.ts +141 -141
  162. package/src/query-builder/insert-query-state.ts +149 -149
  163. package/src/query-builder/insert.ts +117 -117
  164. package/src/query-builder/query-ast-service.ts +287 -287
  165. package/src/query-builder/query-resolution.ts +78 -78
  166. package/src/query-builder/raw-column-parser.ts +38 -38
  167. package/src/query-builder/relation-filter-utils.ts +153 -153
  168. package/src/query-builder/relation-join-planner.ts +10 -10
  169. package/src/query-builder/relation-manager.ts +87 -87
  170. package/src/query-builder/relation-projection-helper.ts +102 -102
  171. package/src/query-builder/relation-types.ts +9 -9
  172. package/src/query-builder/relation-utils.ts +15 -15
  173. package/src/query-builder/select/cte-facet.ts +40 -40
  174. package/src/query-builder/select/from-facet.ts +80 -80
  175. package/src/query-builder/select/join-facet.ts +62 -62
  176. package/src/query-builder/select/predicate-facet.ts +104 -104
  177. package/src/query-builder/select/projection-facet.ts +70 -70
  178. package/src/query-builder/select/relation-facet.ts +81 -81
  179. package/src/query-builder/select/setop-facet.ts +36 -36
  180. package/src/query-builder/select-helpers.ts +1 -1
  181. package/src/query-builder/select-query-builder-deps.ts +130 -130
  182. package/src/query-builder/select-query-state.ts +207 -207
  183. package/src/query-builder/update.ts +151 -151
  184. package/src/schema/column-types.ts +322 -322
  185. package/src/schema/table-guards.ts +37 -37
  186. package/src/schema/table.ts +281 -281
  187. package/src/tree/index.ts +13 -13
  188. package/src/tree/nested-set-strategy.ts +545 -545
  189. package/src/tree/tree-decorator.ts +397 -397
  190. package/src/tree/tree-manager.ts +754 -754
  191. package/src/tree/tree-query.ts +427 -427
  192. package/src/tree/tree-types.ts +299 -299
@@ -1,299 +1,299 @@
1
- /**
2
- * Tree Behavior Types
3
- *
4
- * Core type definitions for the Nested Set (MPTT) tree implementation.
5
- * These types support hierarchical data structures in relational databases.
6
- */
7
-
8
- import type { TableDef } from '../schema/table.js';
9
- import type { ColumnDef } from '../schema/column-types.js';
10
-
11
- /**
12
- * Configuration options for tree behavior.
13
- */
14
- export interface TreeConfig {
15
- /** Column name for parent reference (default: 'parentId') */
16
- parentKey: string;
17
- /** Column name for left boundary (default: 'lft') */
18
- leftKey: string;
19
- /** Column name for right boundary (default: 'rght') */
20
- rightKey: string;
21
- /** Optional column name for cached depth level */
22
- depthKey?: string;
23
- /** Columns used for scoping multiple trees in one table (e.g., ['tenantId']) */
24
- scope?: string[];
25
- /** Whether to load and delete children individually to trigger hooks (default: false) */
26
- cascadeCallbacks?: boolean;
27
- /** Custom ordering for tree recovery (default: primary key ASC) */
28
- recoverOrder?: Record<string, 'ASC' | 'DESC'>;
29
- }
30
-
31
- /**
32
- * Default tree configuration values.
33
- */
34
- export const DEFAULT_TREE_CONFIG: Readonly<Required<Omit<TreeConfig, 'depthKey' | 'scope' | 'recoverOrder'>>> = {
35
- parentKey: 'parentId',
36
- leftKey: 'lft',
37
- rightKey: 'rght',
38
- cascadeCallbacks: false,
39
- };
40
-
41
- /**
42
- * Represents a node in the tree with its nested set boundaries.
43
- * @typeParam T - The entity type
44
- */
45
- export interface TreeNode<T> {
46
- /** The underlying entity */
47
- entity: T;
48
- /** Left boundary value */
49
- lft: number;
50
- /** Right boundary value */
51
- rght: number;
52
- /** Depth level (0 = root), if available */
53
- depth?: number;
54
- /** Whether this node has no children */
55
- isLeaf: boolean;
56
- /** Whether this node has no parent */
57
- isRoot: boolean;
58
- /** Number of descendants (calculated from lft/rght) */
59
- childCount: number;
60
- }
61
-
62
- /**
63
- * Options for finding children/descendants.
64
- */
65
- export interface FindChildrenOptions {
66
- /** Only return immediate children (default: false = all descendants) */
67
- direct?: boolean;
68
- /** Nest results into a tree structure with .children property */
69
- threaded?: boolean;
70
- /** Maximum depth to fetch (undefined = unlimited) */
71
- depth?: number;
72
- }
73
-
74
- /**
75
- * Options for generating a tree list (for dropdowns/selects).
76
- */
77
- export interface TreeListOptions {
78
- /** Dot-separated path to the field used as key (default: primary key) */
79
- keyPath?: string;
80
- /** Dot-separated path to the field used as value (default: primary key) */
81
- valuePath?: string;
82
- /** Prefix string repeated per depth level (default: '__') */
83
- spacer?: string;
84
- }
85
-
86
- /**
87
- * Options for finding the path from a node to root.
88
- */
89
- export interface FindPathOptions {
90
- /** Include the node itself in the path (default: true) */
91
- includeSelf?: boolean;
92
- /** Order of results: 'asc' = root first, 'desc' = node first (default: 'asc') */
93
- order?: 'asc' | 'desc';
94
- }
95
-
96
- /**
97
- * Options for moving a node within the tree.
98
- */
99
- export interface MoveOptions {
100
- /** Position relative to target: 'before', 'after', 'firstChild', 'lastChild' */
101
- position?: 'before' | 'after' | 'firstChild' | 'lastChild';
102
- }
103
-
104
- /**
105
- * Result of a tree recovery operation.
106
- */
107
- export interface RecoverResult {
108
- /** Number of nodes processed */
109
- processed: number;
110
- /** Whether the recovery was successful */
111
- success: boolean;
112
- /** Any errors encountered */
113
- errors?: string[];
114
- }
115
-
116
- /**
117
- * Scope values for multi-tree tables.
118
- */
119
- export type TreeScope = Record<string, unknown>;
120
-
121
- /**
122
- * Internal representation of nested set boundaries for calculations.
123
- */
124
- export interface NestedSetBounds {
125
- lft: number;
126
- rght: number;
127
- }
128
-
129
- /**
130
- * Data required to insert a new node into the tree.
131
- */
132
- export interface TreeInsertData {
133
- /** Parent node ID (null for root) */
134
- parentId: unknown;
135
- /** Calculated left boundary */
136
- lft: number;
137
- /** Calculated right boundary */
138
- rght: number;
139
- /** Calculated depth (if depthKey is configured) */
140
- depth?: number;
141
- }
142
-
143
- /**
144
- * Data required to move a node within the tree.
145
- */
146
- export interface TreeMoveData {
147
- /** New parent node ID */
148
- newParentId: unknown;
149
- /** New left boundary */
150
- newLft: number;
151
- /** New right boundary */
152
- newRght: number;
153
- /** New depth (if depthKey is configured) */
154
- newDepth?: number;
155
- /** Delta to apply to lft/rght of affected nodes */
156
- delta: number;
157
- }
158
-
159
- /**
160
- * Represents a node with its children in a threaded tree structure.
161
- * @typeParam T - The entity type
162
- */
163
- export interface ThreadedNode<T> {
164
- /** The node data */
165
- node: T;
166
- /** Child nodes */
167
- children: ThreadedNode<T>[];
168
- }
169
-
170
- /**
171
- * A tree list entry for dropdown/select rendering.
172
- */
173
- export interface TreeListEntry<K = unknown, V = string> {
174
- /** The key (usually primary key) */
175
- key: K;
176
- /** The display value with depth prefix */
177
- value: V;
178
- /** The depth level */
179
- depth: number;
180
- }
181
-
182
- /**
183
- * Validates that a table has the required tree columns.
184
- * @param table - The table definition to validate
185
- * @param config - The tree configuration
186
- * @returns Validation result with any missing columns
187
- */
188
- export interface TreeValidationResult {
189
- valid: boolean;
190
- missingColumns: string[];
191
- warnings: string[];
192
- }
193
-
194
- /**
195
- * Extracts tree column definitions from a table.
196
- */
197
- export interface TreeColumns {
198
- parentColumn: ColumnDef;
199
- leftColumn: ColumnDef;
200
- rightColumn: ColumnDef;
201
- depthColumn?: ColumnDef;
202
- scopeColumns: ColumnDef[];
203
- }
204
-
205
- /**
206
- * Type guard to check if a value is a valid TreeConfig.
207
- */
208
- export function isTreeConfig(value: unknown): value is TreeConfig {
209
- if (typeof value !== 'object' || value === null) return false;
210
- const obj = value as Record<string, unknown>;
211
- return (
212
- typeof obj.parentKey === 'string' &&
213
- typeof obj.leftKey === 'string' &&
214
- typeof obj.rightKey === 'string'
215
- );
216
- }
217
-
218
- /**
219
- * Merges partial config with defaults.
220
- */
221
- export function resolveTreeConfig(partial: Partial<TreeConfig>): TreeConfig {
222
- return {
223
- parentKey: partial.parentKey ?? DEFAULT_TREE_CONFIG.parentKey,
224
- leftKey: partial.leftKey ?? DEFAULT_TREE_CONFIG.leftKey,
225
- rightKey: partial.rightKey ?? DEFAULT_TREE_CONFIG.rightKey,
226
- depthKey: partial.depthKey,
227
- scope: partial.scope,
228
- cascadeCallbacks: partial.cascadeCallbacks ?? DEFAULT_TREE_CONFIG.cascadeCallbacks,
229
- recoverOrder: partial.recoverOrder,
230
- };
231
- }
232
-
233
- /**
234
- * Validates that a table definition contains the required tree columns.
235
- */
236
- export function validateTreeTable(table: TableDef, config: TreeConfig): TreeValidationResult {
237
- const missingColumns: string[] = [];
238
- const warnings: string[] = [];
239
-
240
- const requiredColumns = [config.parentKey, config.leftKey, config.rightKey];
241
- for (const col of requiredColumns) {
242
- if (!(col in table.columns)) {
243
- missingColumns.push(col);
244
- }
245
- }
246
-
247
- if (config.depthKey && !(config.depthKey in table.columns)) {
248
- warnings.push(`Optional depth column '${config.depthKey}' not found in table '${table.name}'`);
249
- }
250
-
251
- if (config.scope) {
252
- for (const scopeCol of config.scope) {
253
- if (!(scopeCol in table.columns)) {
254
- missingColumns.push(scopeCol);
255
- }
256
- }
257
- }
258
-
259
- const leftCol = table.columns[config.leftKey];
260
- const rightCol = table.columns[config.rightKey];
261
- if (leftCol && leftCol.type !== 'int' && leftCol.type !== 'integer') {
262
- warnings.push(`Left column '${config.leftKey}' should be an integer type`);
263
- }
264
- if (rightCol && rightCol.type !== 'int' && rightCol.type !== 'integer') {
265
- warnings.push(`Right column '${config.rightKey}' should be an integer type`);
266
- }
267
-
268
- return {
269
- valid: missingColumns.length === 0,
270
- missingColumns,
271
- warnings,
272
- };
273
- }
274
-
275
- /**
276
- * Extracts tree-related columns from a table definition.
277
- */
278
- export function getTreeColumns(table: TableDef, config: TreeConfig): TreeColumns {
279
- const parentColumn = table.columns[config.parentKey];
280
- const leftColumn = table.columns[config.leftKey];
281
- const rightColumn = table.columns[config.rightKey];
282
- const depthColumn = config.depthKey ? table.columns[config.depthKey] : undefined;
283
- const scopeColumns = (config.scope ?? []).map(s => table.columns[s]).filter(Boolean);
284
-
285
- if (!parentColumn || !leftColumn || !rightColumn) {
286
- throw new Error(
287
- `Table '${table.name}' is missing required tree columns. ` +
288
- `Required: ${config.parentKey}, ${config.leftKey}, ${config.rightKey}`
289
- );
290
- }
291
-
292
- return {
293
- parentColumn,
294
- leftColumn,
295
- rightColumn,
296
- depthColumn,
297
- scopeColumns,
298
- };
299
- }
1
+ /**
2
+ * Tree Behavior Types
3
+ *
4
+ * Core type definitions for the Nested Set (MPTT) tree implementation.
5
+ * These types support hierarchical data structures in relational databases.
6
+ */
7
+
8
+ import type { TableDef } from '../schema/table.js';
9
+ import type { ColumnDef } from '../schema/column-types.js';
10
+
11
+ /**
12
+ * Configuration options for tree behavior.
13
+ */
14
+ export interface TreeConfig {
15
+ /** Column name for parent reference (default: 'parentId') */
16
+ parentKey: string;
17
+ /** Column name for left boundary (default: 'lft') */
18
+ leftKey: string;
19
+ /** Column name for right boundary (default: 'rght') */
20
+ rightKey: string;
21
+ /** Optional column name for cached depth level */
22
+ depthKey?: string;
23
+ /** Columns used for scoping multiple trees in one table (e.g., ['tenantId']) */
24
+ scope?: string[];
25
+ /** Whether to load and delete children individually to trigger hooks (default: false) */
26
+ cascadeCallbacks?: boolean;
27
+ /** Custom ordering for tree recovery (default: primary key ASC) */
28
+ recoverOrder?: Record<string, 'ASC' | 'DESC'>;
29
+ }
30
+
31
+ /**
32
+ * Default tree configuration values.
33
+ */
34
+ export const DEFAULT_TREE_CONFIG: Readonly<Required<Omit<TreeConfig, 'depthKey' | 'scope' | 'recoverOrder'>>> = {
35
+ parentKey: 'parentId',
36
+ leftKey: 'lft',
37
+ rightKey: 'rght',
38
+ cascadeCallbacks: false,
39
+ };
40
+
41
+ /**
42
+ * Represents a node in the tree with its nested set boundaries.
43
+ * @typeParam T - The entity type
44
+ */
45
+ export interface TreeNode<T> {
46
+ /** The underlying entity */
47
+ entity: T;
48
+ /** Left boundary value */
49
+ lft: number;
50
+ /** Right boundary value */
51
+ rght: number;
52
+ /** Depth level (0 = root), if available */
53
+ depth?: number;
54
+ /** Whether this node has no children */
55
+ isLeaf: boolean;
56
+ /** Whether this node has no parent */
57
+ isRoot: boolean;
58
+ /** Number of descendants (calculated from lft/rght) */
59
+ childCount: number;
60
+ }
61
+
62
+ /**
63
+ * Options for finding children/descendants.
64
+ */
65
+ export interface FindChildrenOptions {
66
+ /** Only return immediate children (default: false = all descendants) */
67
+ direct?: boolean;
68
+ /** Nest results into a tree structure with .children property */
69
+ threaded?: boolean;
70
+ /** Maximum depth to fetch (undefined = unlimited) */
71
+ depth?: number;
72
+ }
73
+
74
+ /**
75
+ * Options for generating a tree list (for dropdowns/selects).
76
+ */
77
+ export interface TreeListOptions {
78
+ /** Dot-separated path to the field used as key (default: primary key) */
79
+ keyPath?: string;
80
+ /** Dot-separated path to the field used as value (default: primary key) */
81
+ valuePath?: string;
82
+ /** Prefix string repeated per depth level (default: '__') */
83
+ spacer?: string;
84
+ }
85
+
86
+ /**
87
+ * Options for finding the path from a node to root.
88
+ */
89
+ export interface FindPathOptions {
90
+ /** Include the node itself in the path (default: true) */
91
+ includeSelf?: boolean;
92
+ /** Order of results: 'asc' = root first, 'desc' = node first (default: 'asc') */
93
+ order?: 'asc' | 'desc';
94
+ }
95
+
96
+ /**
97
+ * Options for moving a node within the tree.
98
+ */
99
+ export interface MoveOptions {
100
+ /** Position relative to target: 'before', 'after', 'firstChild', 'lastChild' */
101
+ position?: 'before' | 'after' | 'firstChild' | 'lastChild';
102
+ }
103
+
104
+ /**
105
+ * Result of a tree recovery operation.
106
+ */
107
+ export interface RecoverResult {
108
+ /** Number of nodes processed */
109
+ processed: number;
110
+ /** Whether the recovery was successful */
111
+ success: boolean;
112
+ /** Any errors encountered */
113
+ errors?: string[];
114
+ }
115
+
116
+ /**
117
+ * Scope values for multi-tree tables.
118
+ */
119
+ export type TreeScope = Record<string, unknown>;
120
+
121
+ /**
122
+ * Internal representation of nested set boundaries for calculations.
123
+ */
124
+ export interface NestedSetBounds {
125
+ lft: number;
126
+ rght: number;
127
+ }
128
+
129
+ /**
130
+ * Data required to insert a new node into the tree.
131
+ */
132
+ export interface TreeInsertData {
133
+ /** Parent node ID (null for root) */
134
+ parentId: unknown;
135
+ /** Calculated left boundary */
136
+ lft: number;
137
+ /** Calculated right boundary */
138
+ rght: number;
139
+ /** Calculated depth (if depthKey is configured) */
140
+ depth?: number;
141
+ }
142
+
143
+ /**
144
+ * Data required to move a node within the tree.
145
+ */
146
+ export interface TreeMoveData {
147
+ /** New parent node ID */
148
+ newParentId: unknown;
149
+ /** New left boundary */
150
+ newLft: number;
151
+ /** New right boundary */
152
+ newRght: number;
153
+ /** New depth (if depthKey is configured) */
154
+ newDepth?: number;
155
+ /** Delta to apply to lft/rght of affected nodes */
156
+ delta: number;
157
+ }
158
+
159
+ /**
160
+ * Represents a node with its children in a threaded tree structure.
161
+ * @typeParam T - The entity type
162
+ */
163
+ export interface ThreadedNode<T> {
164
+ /** The node data */
165
+ node: T;
166
+ /** Child nodes */
167
+ children: ThreadedNode<T>[];
168
+ }
169
+
170
+ /**
171
+ * A tree list entry for dropdown/select rendering.
172
+ */
173
+ export interface TreeListEntry<K = unknown, V = string> {
174
+ /** The key (usually primary key) */
175
+ key: K;
176
+ /** The display value with depth prefix */
177
+ value: V;
178
+ /** The depth level */
179
+ depth: number;
180
+ }
181
+
182
+ /**
183
+ * Validates that a table has the required tree columns.
184
+ * @param table - The table definition to validate
185
+ * @param config - The tree configuration
186
+ * @returns Validation result with any missing columns
187
+ */
188
+ export interface TreeValidationResult {
189
+ valid: boolean;
190
+ missingColumns: string[];
191
+ warnings: string[];
192
+ }
193
+
194
+ /**
195
+ * Extracts tree column definitions from a table.
196
+ */
197
+ export interface TreeColumns {
198
+ parentColumn: ColumnDef;
199
+ leftColumn: ColumnDef;
200
+ rightColumn: ColumnDef;
201
+ depthColumn?: ColumnDef;
202
+ scopeColumns: ColumnDef[];
203
+ }
204
+
205
+ /**
206
+ * Type guard to check if a value is a valid TreeConfig.
207
+ */
208
+ export function isTreeConfig(value: unknown): value is TreeConfig {
209
+ if (typeof value !== 'object' || value === null) return false;
210
+ const obj = value as Record<string, unknown>;
211
+ return (
212
+ typeof obj.parentKey === 'string' &&
213
+ typeof obj.leftKey === 'string' &&
214
+ typeof obj.rightKey === 'string'
215
+ );
216
+ }
217
+
218
+ /**
219
+ * Merges partial config with defaults.
220
+ */
221
+ export function resolveTreeConfig(partial: Partial<TreeConfig>): TreeConfig {
222
+ return {
223
+ parentKey: partial.parentKey ?? DEFAULT_TREE_CONFIG.parentKey,
224
+ leftKey: partial.leftKey ?? DEFAULT_TREE_CONFIG.leftKey,
225
+ rightKey: partial.rightKey ?? DEFAULT_TREE_CONFIG.rightKey,
226
+ depthKey: partial.depthKey,
227
+ scope: partial.scope,
228
+ cascadeCallbacks: partial.cascadeCallbacks ?? DEFAULT_TREE_CONFIG.cascadeCallbacks,
229
+ recoverOrder: partial.recoverOrder,
230
+ };
231
+ }
232
+
233
+ /**
234
+ * Validates that a table definition contains the required tree columns.
235
+ */
236
+ export function validateTreeTable(table: TableDef, config: TreeConfig): TreeValidationResult {
237
+ const missingColumns: string[] = [];
238
+ const warnings: string[] = [];
239
+
240
+ const requiredColumns = [config.parentKey, config.leftKey, config.rightKey];
241
+ for (const col of requiredColumns) {
242
+ if (!(col in table.columns)) {
243
+ missingColumns.push(col);
244
+ }
245
+ }
246
+
247
+ if (config.depthKey && !(config.depthKey in table.columns)) {
248
+ warnings.push(`Optional depth column '${config.depthKey}' not found in table '${table.name}'`);
249
+ }
250
+
251
+ if (config.scope) {
252
+ for (const scopeCol of config.scope) {
253
+ if (!(scopeCol in table.columns)) {
254
+ missingColumns.push(scopeCol);
255
+ }
256
+ }
257
+ }
258
+
259
+ const leftCol = table.columns[config.leftKey];
260
+ const rightCol = table.columns[config.rightKey];
261
+ if (leftCol && leftCol.type !== 'int' && leftCol.type !== 'integer') {
262
+ warnings.push(`Left column '${config.leftKey}' should be an integer type`);
263
+ }
264
+ if (rightCol && rightCol.type !== 'int' && rightCol.type !== 'integer') {
265
+ warnings.push(`Right column '${config.rightKey}' should be an integer type`);
266
+ }
267
+
268
+ return {
269
+ valid: missingColumns.length === 0,
270
+ missingColumns,
271
+ warnings,
272
+ };
273
+ }
274
+
275
+ /**
276
+ * Extracts tree-related columns from a table definition.
277
+ */
278
+ export function getTreeColumns(table: TableDef, config: TreeConfig): TreeColumns {
279
+ const parentColumn = table.columns[config.parentKey];
280
+ const leftColumn = table.columns[config.leftKey];
281
+ const rightColumn = table.columns[config.rightKey];
282
+ const depthColumn = config.depthKey ? table.columns[config.depthKey] : undefined;
283
+ const scopeColumns = (config.scope ?? []).map(s => table.columns[s]).filter(Boolean);
284
+
285
+ if (!parentColumn || !leftColumn || !rightColumn) {
286
+ throw new Error(
287
+ `Table '${table.name}' is missing required tree columns. ` +
288
+ `Required: ${config.parentKey}, ${config.leftKey}, ${config.rightKey}`
289
+ );
290
+ }
291
+
292
+ return {
293
+ parentColumn,
294
+ leftColumn,
295
+ rightColumn,
296
+ depthColumn,
297
+ scopeColumns,
298
+ };
299
+ }