metal-orm 1.1.9 → 1.1.11

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 (77) hide show
  1. package/README.md +769 -764
  2. package/dist/index.cjs +2255 -284
  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 +2227 -284
  7. package/dist/index.js.map +1 -1
  8. package/package.json +17 -12
  9. package/scripts/generate-entities/render.mjs +21 -12
  10. package/scripts/generate-entities/schema.mjs +87 -73
  11. package/scripts/generate-entities/tree-detection.mjs +67 -61
  12. package/src/bulk/bulk-context.ts +83 -0
  13. package/src/bulk/bulk-delete-executor.ts +87 -0
  14. package/src/bulk/bulk-executor.base.ts +73 -0
  15. package/src/bulk/bulk-insert-executor.ts +74 -0
  16. package/src/bulk/bulk-types.ts +70 -0
  17. package/src/bulk/bulk-update-executor.ts +192 -0
  18. package/src/bulk/bulk-upsert-executor.ts +93 -0
  19. package/src/bulk/bulk-utils.ts +91 -0
  20. package/src/bulk/index.ts +18 -0
  21. package/src/codegen/typescript.ts +30 -21
  22. package/src/core/ast/expression-builders.ts +107 -10
  23. package/src/core/ast/expression-nodes.ts +52 -22
  24. package/src/core/ast/expression-visitor.ts +23 -13
  25. package/src/core/ddl/introspect/mysql.ts +113 -36
  26. package/src/core/dialect/abstract.ts +30 -17
  27. package/src/core/dialect/mysql/index.ts +20 -5
  28. package/src/core/execution/db-executor.ts +96 -64
  29. package/src/core/execution/executors/better-sqlite3-executor.ts +94 -0
  30. package/src/core/execution/executors/mssql-executor.ts +66 -34
  31. package/src/core/execution/executors/mysql-executor.ts +98 -66
  32. package/src/core/execution/executors/postgres-executor.ts +33 -11
  33. package/src/core/execution/executors/sqlite-executor.ts +86 -30
  34. package/src/decorators/bootstrap.ts +482 -398
  35. package/src/decorators/column-decorator.ts +87 -96
  36. package/src/decorators/decorator-metadata.ts +100 -24
  37. package/src/decorators/entity.ts +27 -24
  38. package/src/decorators/relations.ts +231 -149
  39. package/src/decorators/transformers/transformer-decorators.ts +26 -29
  40. package/src/decorators/validators/country-validators-decorators.ts +9 -15
  41. package/src/dto/apply-filter.ts +568 -551
  42. package/src/index.ts +16 -9
  43. package/src/orm/entity-hydration.ts +116 -72
  44. package/src/orm/entity-metadata.ts +347 -301
  45. package/src/orm/entity-relations.ts +264 -207
  46. package/src/orm/entity.ts +199 -199
  47. package/src/orm/execute.ts +13 -13
  48. package/src/orm/lazy-batch/morph-many.ts +70 -0
  49. package/src/orm/lazy-batch/morph-one.ts +69 -0
  50. package/src/orm/lazy-batch/morph-to.ts +59 -0
  51. package/src/orm/lazy-batch.ts +4 -1
  52. package/src/orm/orm-session.ts +170 -104
  53. package/src/orm/pooled-executor-factory.ts +99 -58
  54. package/src/orm/query-logger.ts +49 -40
  55. package/src/orm/relation-change-processor.ts +198 -96
  56. package/src/orm/relations/belongs-to.ts +143 -143
  57. package/src/orm/relations/has-many.ts +204 -204
  58. package/src/orm/relations/has-one.ts +174 -174
  59. package/src/orm/relations/many-to-many.ts +288 -288
  60. package/src/orm/relations/morph-many.ts +156 -0
  61. package/src/orm/relations/morph-one.ts +151 -0
  62. package/src/orm/relations/morph-to.ts +162 -0
  63. package/src/orm/save-graph.ts +116 -1
  64. package/src/query-builder/expression-table-mapper.ts +5 -0
  65. package/src/query-builder/hydration-manager.ts +345 -345
  66. package/src/query-builder/hydration-planner.ts +178 -148
  67. package/src/query-builder/relation-conditions.ts +171 -151
  68. package/src/query-builder/relation-cte-builder.ts +5 -1
  69. package/src/query-builder/relation-filter-utils.ts +9 -6
  70. package/src/query-builder/relation-include-strategies.ts +44 -2
  71. package/src/query-builder/relation-join-strategies.ts +8 -1
  72. package/src/query-builder/relation-service.ts +250 -241
  73. package/src/query-builder/select/select-operations.ts +110 -105
  74. package/src/query-builder/update-include.ts +4 -0
  75. package/src/schema/relation.ts +296 -188
  76. package/src/schema/types.ts +138 -123
  77. 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
+ };