metal-orm 1.1.9 → 1.1.10

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 (73) hide show
  1. package/README.md +769 -764
  2. package/dist/index.cjs +2147 -239
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +559 -39
  5. package/dist/index.d.ts +559 -39
  6. package/dist/index.js +2119 -239
  7. package/dist/index.js.map +1 -1
  8. package/package.json +17 -12
  9. package/src/bulk/bulk-context.ts +83 -0
  10. package/src/bulk/bulk-delete-executor.ts +89 -0
  11. package/src/bulk/bulk-executor.base.ts +73 -0
  12. package/src/bulk/bulk-insert-executor.ts +74 -0
  13. package/src/bulk/bulk-types.ts +70 -0
  14. package/src/bulk/bulk-update-executor.ts +192 -0
  15. package/src/bulk/bulk-upsert-executor.ts +95 -0
  16. package/src/bulk/bulk-utils.ts +91 -0
  17. package/src/bulk/index.ts +18 -0
  18. package/src/codegen/typescript.ts +30 -21
  19. package/src/core/ast/expression-builders.ts +107 -10
  20. package/src/core/ast/expression-nodes.ts +52 -22
  21. package/src/core/ast/expression-visitor.ts +23 -13
  22. package/src/core/dialect/abstract.ts +30 -17
  23. package/src/core/dialect/mysql/index.ts +20 -5
  24. package/src/core/execution/db-executor.ts +96 -64
  25. package/src/core/execution/executors/better-sqlite3-executor.ts +94 -0
  26. package/src/core/execution/executors/mssql-executor.ts +66 -34
  27. package/src/core/execution/executors/mysql-executor.ts +98 -66
  28. package/src/core/execution/executors/postgres-executor.ts +33 -11
  29. package/src/core/execution/executors/sqlite-executor.ts +86 -30
  30. package/src/decorators/bootstrap.ts +482 -398
  31. package/src/decorators/column-decorator.ts +87 -96
  32. package/src/decorators/decorator-metadata.ts +100 -24
  33. package/src/decorators/entity.ts +27 -24
  34. package/src/decorators/relations.ts +231 -149
  35. package/src/decorators/transformers/transformer-decorators.ts +26 -29
  36. package/src/decorators/validators/country-validators-decorators.ts +9 -15
  37. package/src/dto/apply-filter.ts +568 -551
  38. package/src/index.ts +16 -9
  39. package/src/orm/entity-hydration.ts +116 -72
  40. package/src/orm/entity-metadata.ts +347 -301
  41. package/src/orm/entity-relations.ts +264 -207
  42. package/src/orm/entity.ts +199 -199
  43. package/src/orm/execute.ts +13 -13
  44. package/src/orm/lazy-batch/morph-many.ts +70 -0
  45. package/src/orm/lazy-batch/morph-one.ts +69 -0
  46. package/src/orm/lazy-batch/morph-to.ts +59 -0
  47. package/src/orm/lazy-batch.ts +4 -1
  48. package/src/orm/orm-session.ts +170 -104
  49. package/src/orm/pooled-executor-factory.ts +99 -58
  50. package/src/orm/query-logger.ts +49 -40
  51. package/src/orm/relation-change-processor.ts +198 -96
  52. package/src/orm/relations/belongs-to.ts +143 -143
  53. package/src/orm/relations/has-many.ts +204 -204
  54. package/src/orm/relations/has-one.ts +174 -174
  55. package/src/orm/relations/many-to-many.ts +288 -288
  56. package/src/orm/relations/morph-many.ts +156 -0
  57. package/src/orm/relations/morph-one.ts +151 -0
  58. package/src/orm/relations/morph-to.ts +162 -0
  59. package/src/orm/save-graph.ts +116 -1
  60. package/src/query-builder/expression-table-mapper.ts +5 -0
  61. package/src/query-builder/hydration-manager.ts +345 -345
  62. package/src/query-builder/hydration-planner.ts +178 -148
  63. package/src/query-builder/relation-conditions.ts +171 -151
  64. package/src/query-builder/relation-cte-builder.ts +5 -1
  65. package/src/query-builder/relation-filter-utils.ts +9 -6
  66. package/src/query-builder/relation-include-strategies.ts +44 -2
  67. package/src/query-builder/relation-join-strategies.ts +8 -1
  68. package/src/query-builder/relation-service.ts +250 -241
  69. package/src/query-builder/select/select-operations.ts +110 -105
  70. package/src/query-builder/update-include.ts +4 -0
  71. package/src/schema/relation.ts +296 -188
  72. package/src/schema/types.ts +138 -123
  73. package/src/tree/tree-decorator.ts +127 -137
package/src/index.ts CHANGED
@@ -9,13 +9,13 @@ export * from './schema/types.js';
9
9
  export * from './query-builder/select.js';
10
10
  export * from './query-builder/select-helpers.js';
11
11
  export * from './query-builder/insert.js';
12
- export * from './query-builder/update.js';
13
- export * from './query-builder/delete.js';
14
- export * from './query-builder/procedure-call.js';
15
- export * from './query/index.js';
16
- export * from './core/ast/expression.js';
17
- export * from './core/ast/procedure.js';
18
- export * from './core/ast/window-functions.js';
12
+ export * from './query-builder/update.js';
13
+ export * from './query-builder/delete.js';
14
+ export * from './query-builder/procedure-call.js';
15
+ export * from './query/index.js';
16
+ export * from './core/ast/expression.js';
17
+ export * from './core/ast/procedure.js';
18
+ export * from './core/ast/window-functions.js';
19
19
  export * from './core/hydration/types.js';
20
20
  export * from './core/dialect/mysql/index.js';
21
21
  export * from './core/dialect/mssql/index.js';
@@ -43,8 +43,11 @@ export * from './orm/lazy-batch.js';
43
43
  export * from './orm/relations/has-many.js';
44
44
  export * from './orm/relations/belongs-to.js';
45
45
  export * from './orm/relations/many-to-many.js';
46
- export * from './orm/execute.js';
47
- export * from './orm/execute-procedure.js';
46
+ export * from './orm/relations/morph-one.js';
47
+ export * from './orm/relations/morph-many.js';
48
+ export * from './orm/relations/morph-to.js';
49
+ export * from './orm/execute.js';
50
+ export * from './orm/execute-procedure.js';
48
51
  export type { EntityContext } from './orm/entity-context.js';
49
52
  export type { PrimaryKey as EntityPrimaryKey } from './orm/entity-context.js';
50
53
  export * from './orm/execution-context.js';
@@ -64,6 +67,7 @@ export * from './core/execution/pooling/pool.js';
64
67
  export * from './core/execution/executors/postgres-executor.js';
65
68
  export * from './core/execution/executors/mysql-executor.js';
66
69
  export * from './core/execution/executors/sqlite-executor.js';
70
+ export * from './core/execution/executors/better-sqlite3-executor.js';
67
71
  export * from './core/execution/executors/mssql-executor.js';
68
72
 
69
73
  // NEW: first-class pooling integration
@@ -77,3 +81,6 @@ export * from './tree/index.js';
77
81
 
78
82
  // Cache module
79
83
  export * from './cache/index.js';
84
+
85
+ // Bulk operations module
86
+ export * from './bulk/index.js';
@@ -1,72 +1,116 @@
1
- import { TableDef } from '../schema/table.js';
2
- import { RelationKinds } from '../schema/relation.js';
3
- import { findPrimaryKey } from '../query-builder/hydration-planner.js';
4
- import { EntityMeta } from './entity-meta.js';
5
-
6
- /**
7
- * Type representing an array of database rows.
8
- */
9
- type Rows = Record<string, unknown>[];
10
-
11
- /**
12
- * Converts a value to a string key.
13
- * @param value - The value to convert
14
- * @returns String representation of the value
15
- */
16
- const toKey = (value: unknown): string => (value === null || value === undefined ? '' : String(value));
17
-
18
- /**
19
- * Populates the hydration cache with relation data from the database row.
20
- * @template TTable - The table type
21
- * @param entity - The entity instance
22
- * @param row - The database row
23
- * @param meta - The entity metadata
24
- */
25
- export const populateHydrationCache = <TTable extends TableDef>(
26
- entity: Record<string, unknown>,
27
- row: Record<string, unknown>,
28
- meta: EntityMeta<TTable>
29
- ): void => {
30
- for (const relationName of Object.keys(meta.table.relations)) {
31
- const relation = meta.table.relations[relationName];
32
- const data = row[relationName];
33
- if (relation.type === RelationKinds.HasOne) {
34
- const localKey = relation.localKey || findPrimaryKey(meta.table);
35
- const rootValue = entity[localKey];
36
- if (rootValue === undefined || rootValue === null) continue;
37
- if (!data || typeof data !== 'object') continue;
38
- const cache = new Map<string, Record<string, unknown>>();
39
- cache.set(toKey(rootValue), data as Record<string, unknown>);
40
- meta.relationHydration.set(relationName, cache);
41
- meta.relationCache.set(relationName, Promise.resolve(cache));
42
- continue;
43
- }
44
-
45
- if (!Array.isArray(data)) continue;
46
-
47
- if (relation.type === RelationKinds.HasMany || relation.type === RelationKinds.BelongsToMany) {
48
- const localKey = relation.localKey || findPrimaryKey(meta.table);
49
- const rootValue = entity[localKey];
50
- if (rootValue === undefined || rootValue === null) continue;
51
- const cache = new Map<string, Rows>();
52
- cache.set(toKey(rootValue), data as Rows);
53
- meta.relationHydration.set(relationName, cache);
54
- meta.relationCache.set(relationName, Promise.resolve(cache));
55
- continue;
56
- }
57
-
58
- if (relation.type === RelationKinds.BelongsTo) {
59
- const targetKey = relation.localKey || findPrimaryKey(relation.target);
60
- const cache = new Map<string, Record<string, unknown>>();
61
- for (const item of data) {
62
- const pkValue = item[targetKey];
63
- if (pkValue === undefined || pkValue === null) continue;
64
- cache.set(toKey(pkValue), item);
65
- }
66
- if (cache.size) {
67
- meta.relationHydration.set(relationName, cache);
68
- meta.relationCache.set(relationName, Promise.resolve(cache));
69
- }
70
- }
71
- }
72
- };
1
+ import { TableDef } from '../schema/table.js';
2
+ import { RelationKinds, MorphToRelation } from '../schema/relation.js';
3
+ import { findPrimaryKey } from '../query-builder/hydration-planner.js';
4
+ import { EntityMeta } from './entity-meta.js';
5
+
6
+ /**
7
+ * Type representing an array of database rows.
8
+ */
9
+ type Rows = Record<string, unknown>[];
10
+
11
+ /**
12
+ * Converts a value to a string key.
13
+ * @param value - The value to convert
14
+ * @returns String representation of the value
15
+ */
16
+ const toKey = (value: unknown): string => (value === null || value === undefined ? '' : String(value));
17
+
18
+ /**
19
+ * Populates the hydration cache with relation data from the database row.
20
+ * @template TTable - The table type
21
+ * @param entity - The entity instance
22
+ * @param row - The database row
23
+ * @param meta - The entity metadata
24
+ */
25
+ export const populateHydrationCache = <TTable extends TableDef>(
26
+ entity: Record<string, unknown>,
27
+ row: Record<string, unknown>,
28
+ meta: EntityMeta<TTable>
29
+ ): void => {
30
+ for (const relationName of Object.keys(meta.table.relations)) {
31
+ const relation = meta.table.relations[relationName];
32
+ const data = row[relationName];
33
+ if (relation.type === RelationKinds.HasOne) {
34
+ const localKey = relation.localKey || findPrimaryKey(meta.table);
35
+ const rootValue = entity[localKey];
36
+ if (rootValue === undefined || rootValue === null) continue;
37
+ if (!data || typeof data !== 'object') continue;
38
+ const cache = new Map<string, Record<string, unknown>>();
39
+ cache.set(toKey(rootValue), data as Record<string, unknown>);
40
+ meta.relationHydration.set(relationName, cache);
41
+ meta.relationCache.set(relationName, Promise.resolve(cache));
42
+ continue;
43
+ }
44
+
45
+ if (!Array.isArray(data)) continue;
46
+
47
+ if (relation.type === RelationKinds.HasMany || relation.type === RelationKinds.BelongsToMany) {
48
+ const localKey = relation.localKey || findPrimaryKey(meta.table);
49
+ const rootValue = entity[localKey];
50
+ if (rootValue === undefined || rootValue === null) continue;
51
+ const cache = new Map<string, Rows>();
52
+ cache.set(toKey(rootValue), data as Rows);
53
+ meta.relationHydration.set(relationName, cache);
54
+ meta.relationCache.set(relationName, Promise.resolve(cache));
55
+ continue;
56
+ }
57
+
58
+ if (relation.type === RelationKinds.BelongsTo) {
59
+ const targetKey = relation.localKey || findPrimaryKey(relation.target);
60
+ const cache = new Map<string, Record<string, unknown>>();
61
+ for (const item of data) {
62
+ const pkValue = item[targetKey];
63
+ if (pkValue === undefined || pkValue === null) continue;
64
+ cache.set(toKey(pkValue), item);
65
+ }
66
+ if (cache.size) {
67
+ meta.relationHydration.set(relationName, cache);
68
+ meta.relationCache.set(relationName, Promise.resolve(cache));
69
+ }
70
+ }
71
+ }
72
+
73
+ // Second pass for morph relations (data may not be arrays)
74
+ for (const relationName of Object.keys(meta.table.relations)) {
75
+ const relation = meta.table.relations[relationName];
76
+ const data = row[relationName];
77
+
78
+ if (relation.type === RelationKinds.MorphOne) {
79
+ const localKey = relation.localKey || findPrimaryKey(meta.table);
80
+ const rootValue = entity[localKey];
81
+ if (rootValue === undefined || rootValue === null) continue;
82
+ if (!data || typeof data !== 'object') continue;
83
+ const cache = new Map<string, Record<string, unknown>>();
84
+ cache.set(toKey(rootValue), data as Record<string, unknown>);
85
+ meta.relationHydration.set(relationName, cache);
86
+ meta.relationCache.set(relationName, Promise.resolve(cache));
87
+ continue;
88
+ }
89
+
90
+ if (relation.type === RelationKinds.MorphMany) {
91
+ if (!Array.isArray(data)) continue;
92
+ const localKey = relation.localKey || findPrimaryKey(meta.table);
93
+ const rootValue = entity[localKey];
94
+ if (rootValue === undefined || rootValue === null) continue;
95
+ const cache = new Map<string, Rows>();
96
+ cache.set(toKey(rootValue), data as Rows);
97
+ meta.relationHydration.set(relationName, cache);
98
+ meta.relationCache.set(relationName, Promise.resolve(cache));
99
+ continue;
100
+ }
101
+
102
+ if (relation.type === RelationKinds.MorphTo) {
103
+ if (!data || typeof data !== 'object') continue;
104
+ const morphTo = relation as MorphToRelation;
105
+ const typeValue = entity[morphTo.typeField];
106
+ const idValue = entity[morphTo.idField];
107
+ if (!typeValue || idValue === undefined || idValue === null) continue;
108
+ const compositeKey = `${toKey(typeValue)}:${toKey(idValue)}`;
109
+ const cache = new Map<string, Record<string, unknown>>();
110
+ cache.set(compositeKey, data as Record<string, unknown>);
111
+ meta.relationHydration.set(relationName, cache);
112
+ meta.relationCache.set(relationName, Promise.resolve(cache));
113
+ continue;
114
+ }
115
+ }
116
+ };