metal-orm 1.0.70 → 1.0.72

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metal-orm",
3
- "version": "1.0.70",
3
+ "version": "1.0.72",
4
4
  "type": "module",
5
5
  "types": "./dist/index.d.ts",
6
6
  "engines": {
@@ -23,6 +23,7 @@
23
23
  "scripts"
24
24
  ],
25
25
  "scripts": {
26
+ "prepublishOnly": "npm run build",
26
27
  "build": "tsup",
27
28
  "check": "tsc --noEmit",
28
29
  "gen:entities": "node scripts/generate-entities.mjs",
package/src/orm/entity.ts CHANGED
@@ -7,13 +7,20 @@ import { RelationIncludeOptions } from '../query-builder/relation-types.js';
7
7
  import { populateHydrationCache } from './entity-hydration.js';
8
8
  import { getRelationWrapper, RelationEntityFactory } from './entity-relations.js';
9
9
 
10
- export { relationLoaderCache } from './entity-relation-cache.js';
11
-
12
- /**
13
- * Creates an entity proxy with lazy loading capabilities.
14
- * @template TTable - The table type
15
- * @template TLazy - The lazy relation keys
16
- * @param ctx - The entity context
10
+ export { relationLoaderCache } from './entity-relation-cache.js';
11
+
12
+ const isRelationWrapperLoaded = (value: unknown): boolean => {
13
+ if (!value || typeof value !== 'object') return false;
14
+ return Boolean((value as { loaded?: boolean }).loaded);
15
+ };
16
+
17
+ type JsonSource<TTable extends TableDef> = EntityInstance<TTable> & Record<string, unknown>;
18
+
19
+ /**
20
+ * Creates an entity proxy with lazy loading capabilities.
21
+ * @template TTable - The table type
22
+ * @template TLazy - The lazy relation keys
23
+ * @param ctx - The entity context
17
24
  * @param table - The table definition
18
25
  * @param row - The database row
19
26
  * @param lazyRelations - Optional lazy relations
@@ -28,26 +35,39 @@ export const createEntityProxy = <
28
35
  row: Record<string, unknown>,
29
36
  lazyRelations: TLazy[] = [] as TLazy[],
30
37
  lazyRelationOptions: Map<string, RelationIncludeOptions> = new Map()
31
- ): EntityInstance<TTable> => {
32
- const target: Record<string, unknown> = { ...row };
33
- const meta: EntityMeta<TTable> = {
34
- ctx,
35
- table,
38
+ ): EntityInstance<TTable> => {
39
+ const target: Record<string, unknown> = { ...row };
40
+ const meta: EntityMeta<TTable> = {
41
+ ctx,
42
+ table,
36
43
  lazyRelations: [...lazyRelations],
37
44
  lazyRelationOptions: new Map(lazyRelationOptions),
38
45
  relationCache: new Map(),
39
- relationHydration: new Map(),
40
- relationWrappers: new Map()
41
- };
42
-
43
- const createRelationEntity: RelationEntityFactory = (relationTable, relationRow) =>
44
- createEntityFromRow(meta.ctx, relationTable, relationRow);
45
-
46
- Object.defineProperty(target, ENTITY_META, {
47
- value: meta,
48
- enumerable: false,
49
- writable: false
50
- });
46
+ relationHydration: new Map(),
47
+ relationWrappers: new Map()
48
+ };
49
+ const createRelationEntity: RelationEntityFactory = (relationTable, relationRow) =>
50
+ createEntityFromRow(meta.ctx, relationTable, relationRow);
51
+
52
+ const buildJson = (self: JsonSource<TTable>): Record<string, unknown> => {
53
+ const json: Record<string, unknown> = {};
54
+ for (const key of Object.keys(target)) {
55
+ json[key] = self[key];
56
+ }
57
+ for (const [relationName, wrapper] of meta.relationWrappers) {
58
+ if (Object.prototype.hasOwnProperty.call(json, relationName)) continue;
59
+ if (isRelationWrapperLoaded(wrapper)) {
60
+ json[relationName] = wrapper;
61
+ }
62
+ }
63
+ return json;
64
+ };
65
+
66
+ Object.defineProperty(target, ENTITY_META, {
67
+ value: meta,
68
+ enumerable: false,
69
+ writable: false
70
+ });
51
71
 
52
72
  const handler: ProxyHandler<object> = {
53
73
  get(targetObj, prop, receiver) {
@@ -55,21 +75,28 @@ export const createEntityProxy = <
55
75
  return meta;
56
76
  }
57
77
 
58
- if (prop === '$load') {
59
- return async (relationName: RelationKey<TTable>) => {
60
- const wrapper = getRelationWrapper(meta, relationName, receiver, createRelationEntity);
61
- if (wrapper && typeof wrapper.load === 'function') {
62
- return wrapper.load();
63
- }
64
- return undefined;
65
- };
66
- }
67
-
68
- if (typeof prop === 'string' && table.relations[prop]) {
69
- return getRelationWrapper(meta, prop as RelationKey<TTable>, receiver, createRelationEntity);
70
- }
71
-
72
- return Reflect.get(targetObj, prop, receiver);
78
+ if (prop === '$load') {
79
+ return async (relationName: RelationKey<TTable>) => {
80
+ const wrapper = getRelationWrapper(meta, relationName, receiver, createRelationEntity);
81
+ if (wrapper && typeof wrapper.load === 'function') {
82
+ return wrapper.load();
83
+ }
84
+ return undefined;
85
+ };
86
+ }
87
+
88
+ if (prop === 'toJSON') {
89
+ if (prop in targetObj) {
90
+ return Reflect.get(targetObj, prop, receiver);
91
+ }
92
+ return () => buildJson(receiver as JsonSource<TTable>);
93
+ }
94
+
95
+ if (typeof prop === 'string' && table.relations[prop]) {
96
+ return getRelationWrapper(meta, prop as RelationKey<TTable>, receiver, createRelationEntity);
97
+ }
98
+
99
+ return Reflect.get(targetObj, prop, receiver);
73
100
  },
74
101
 
75
102
  set(targetObj, prop, value, receiver) {
@@ -77,14 +104,14 @@ export const createEntityProxy = <
77
104
  if (typeof prop === 'string' && table.columns[prop]) {
78
105
  ctx.markDirty(receiver);
79
106
  }
80
- return result;
81
- }
82
- };
83
-
84
- const proxy = new Proxy(target, handler) as EntityInstance<TTable>;
85
- populateHydrationCache(proxy, row, meta);
86
- return proxy;
87
- };
107
+ return result;
108
+ }
109
+ };
110
+
111
+ const proxy = new Proxy(target, handler) as EntityInstance<TTable>;
112
+ populateHydrationCache(proxy, row, meta);
113
+ return proxy;
114
+ };
88
115
 
89
116
  /**
90
117
  * Creates an entity instance from a database row.