@stonyx/orm 0.2.1-alpha.4 → 0.2.1-alpha.40

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 (171) hide show
  1. package/README.md +64 -6
  2. package/config/environment.js +37 -1
  3. package/dist/aggregates.d.ts +21 -0
  4. package/dist/aggregates.js +93 -0
  5. package/dist/attr.d.ts +2 -0
  6. package/dist/attr.js +22 -0
  7. package/dist/belongs-to.d.ts +11 -0
  8. package/dist/belongs-to.js +59 -0
  9. package/dist/cli.d.ts +22 -0
  10. package/dist/cli.js +148 -0
  11. package/dist/commands.d.ts +7 -0
  12. package/dist/commands.js +146 -0
  13. package/dist/db.d.ts +21 -0
  14. package/dist/db.js +180 -0
  15. package/dist/exports/db.d.ts +7 -0
  16. package/{src → dist}/exports/db.js +2 -4
  17. package/dist/has-many.d.ts +11 -0
  18. package/dist/has-many.js +58 -0
  19. package/dist/hooks.d.ts +47 -0
  20. package/dist/hooks.js +110 -0
  21. package/dist/index.d.ts +14 -0
  22. package/dist/index.js +34 -0
  23. package/dist/main.d.ts +46 -0
  24. package/dist/main.js +181 -0
  25. package/dist/manage-record.d.ts +13 -0
  26. package/dist/manage-record.js +123 -0
  27. package/dist/meta-request.d.ts +6 -0
  28. package/dist/meta-request.js +52 -0
  29. package/dist/migrate.d.ts +2 -0
  30. package/dist/migrate.js +57 -0
  31. package/dist/model-property.d.ts +9 -0
  32. package/dist/model-property.js +29 -0
  33. package/dist/model.d.ts +15 -0
  34. package/dist/model.js +18 -0
  35. package/dist/mysql/connection.d.ts +14 -0
  36. package/dist/mysql/connection.js +24 -0
  37. package/dist/mysql/migration-generator.d.ts +45 -0
  38. package/dist/mysql/migration-generator.js +254 -0
  39. package/dist/mysql/migration-runner.d.ts +12 -0
  40. package/dist/mysql/migration-runner.js +88 -0
  41. package/dist/mysql/mysql-db.d.ts +100 -0
  42. package/dist/mysql/mysql-db.js +425 -0
  43. package/dist/mysql/query-builder.d.ts +10 -0
  44. package/dist/mysql/query-builder.js +44 -0
  45. package/dist/mysql/schema-introspector.d.ts +19 -0
  46. package/dist/mysql/schema-introspector.js +291 -0
  47. package/dist/mysql/type-map.d.ts +21 -0
  48. package/dist/mysql/type-map.js +36 -0
  49. package/dist/orm-request.d.ts +38 -0
  50. package/dist/orm-request.js +474 -0
  51. package/dist/plural-registry.d.ts +4 -0
  52. package/dist/plural-registry.js +9 -0
  53. package/dist/postgres/connection.d.ts +15 -0
  54. package/dist/postgres/connection.js +32 -0
  55. package/dist/postgres/migration-generator.d.ts +45 -0
  56. package/dist/postgres/migration-generator.js +261 -0
  57. package/dist/postgres/migration-runner.d.ts +10 -0
  58. package/dist/postgres/migration-runner.js +87 -0
  59. package/dist/postgres/postgres-db.d.ts +119 -0
  60. package/dist/postgres/postgres-db.js +477 -0
  61. package/dist/postgres/query-builder.d.ts +27 -0
  62. package/dist/postgres/query-builder.js +98 -0
  63. package/dist/postgres/schema-introspector.d.ts +29 -0
  64. package/dist/postgres/schema-introspector.js +314 -0
  65. package/dist/postgres/type-map.d.ts +23 -0
  66. package/dist/postgres/type-map.js +56 -0
  67. package/dist/record.d.ts +75 -0
  68. package/dist/record.js +129 -0
  69. package/dist/relationships.d.ts +10 -0
  70. package/dist/relationships.js +41 -0
  71. package/dist/serializer.d.ts +17 -0
  72. package/dist/serializer.js +136 -0
  73. package/dist/setup-rest-server.d.ts +1 -0
  74. package/dist/setup-rest-server.js +52 -0
  75. package/dist/standalone-db.d.ts +58 -0
  76. package/dist/standalone-db.js +142 -0
  77. package/dist/store.d.ts +62 -0
  78. package/dist/store.js +286 -0
  79. package/dist/timescale/query-builder.d.ts +43 -0
  80. package/dist/timescale/query-builder.js +115 -0
  81. package/dist/timescale/timescale-db.d.ts +45 -0
  82. package/dist/timescale/timescale-db.js +84 -0
  83. package/dist/transforms.d.ts +2 -0
  84. package/dist/transforms.js +17 -0
  85. package/dist/types/orm-types.d.ts +142 -0
  86. package/dist/types/orm-types.js +1 -0
  87. package/dist/utils.d.ts +7 -0
  88. package/dist/utils.js +17 -0
  89. package/dist/view-resolver.d.ts +8 -0
  90. package/dist/view-resolver.js +171 -0
  91. package/dist/view.d.ts +11 -0
  92. package/dist/view.js +18 -0
  93. package/package.json +57 -15
  94. package/src/aggregates.ts +109 -0
  95. package/src/{attr.js → attr.ts} +2 -2
  96. package/src/belongs-to.ts +90 -0
  97. package/src/cli.ts +183 -0
  98. package/src/{commands.js → commands.ts} +179 -170
  99. package/src/{db.js → db.ts} +55 -29
  100. package/src/exports/db.ts +7 -0
  101. package/src/has-many.ts +92 -0
  102. package/src/{hooks.js → hooks.ts} +25 -27
  103. package/src/{index.js → index.ts} +8 -5
  104. package/src/main.ts +229 -0
  105. package/src/manage-record.ts +161 -0
  106. package/src/{meta-request.js → meta-request.ts} +17 -14
  107. package/src/{migrate.js → migrate.ts} +9 -9
  108. package/src/model-property.ts +35 -0
  109. package/src/model.ts +21 -0
  110. package/src/mysql/{connection.js → connection.ts} +43 -28
  111. package/src/mysql/migration-generator.ts +337 -0
  112. package/src/mysql/{migration-runner.js → migration-runner.ts} +121 -110
  113. package/src/mysql/mysql-db.ts +543 -0
  114. package/src/mysql/{query-builder.js → query-builder.ts} +69 -64
  115. package/src/mysql/schema-introspector.ts +358 -0
  116. package/src/mysql/{type-map.js → type-map.ts} +42 -37
  117. package/src/{orm-request.js → orm-request.ts} +196 -103
  118. package/src/plural-registry.ts +12 -0
  119. package/src/postgres/connection.ts +48 -0
  120. package/src/postgres/migration-generator.ts +348 -0
  121. package/src/postgres/migration-runner.ts +115 -0
  122. package/src/postgres/postgres-db.ts +616 -0
  123. package/src/postgres/query-builder.ts +148 -0
  124. package/src/postgres/schema-introspector.ts +386 -0
  125. package/src/postgres/type-map.ts +61 -0
  126. package/src/record.ts +186 -0
  127. package/src/relationships.ts +54 -0
  128. package/src/serializer.ts +161 -0
  129. package/src/{setup-rest-server.js → setup-rest-server.ts} +18 -16
  130. package/src/standalone-db.ts +185 -0
  131. package/src/store.ts +373 -0
  132. package/src/timescale/query-builder.ts +174 -0
  133. package/src/timescale/timescale-db.ts +119 -0
  134. package/src/transforms.ts +20 -0
  135. package/src/types/mysql2.d.ts +30 -0
  136. package/src/types/orm-types.ts +146 -0
  137. package/src/types/pg.d.ts +28 -0
  138. package/src/types/stonyx-cron.d.ts +5 -0
  139. package/src/types/stonyx-events.d.ts +4 -0
  140. package/src/types/stonyx-rest-server.d.ts +11 -0
  141. package/src/types/stonyx-utils.d.ts +33 -0
  142. package/src/types/stonyx.d.ts +21 -0
  143. package/src/utils.ts +22 -0
  144. package/src/view-resolver.ts +211 -0
  145. package/src/view.ts +22 -0
  146. package/.claude/code-style-rules.md +0 -44
  147. package/.claude/hooks.md +0 -250
  148. package/.claude/index.md +0 -279
  149. package/.claude/usage-patterns.md +0 -217
  150. package/.github/workflows/ci.yml +0 -16
  151. package/.github/workflows/publish.yml +0 -51
  152. package/improvements.md +0 -139
  153. package/project-structure.md +0 -343
  154. package/src/belongs-to.js +0 -63
  155. package/src/has-many.js +0 -61
  156. package/src/main.js +0 -159
  157. package/src/manage-record.js +0 -118
  158. package/src/model-property.js +0 -29
  159. package/src/model.js +0 -19
  160. package/src/mysql/migration-generator.js +0 -188
  161. package/src/mysql/mysql-db.js +0 -422
  162. package/src/mysql/schema-introspector.js +0 -159
  163. package/src/record.js +0 -127
  164. package/src/relationships.js +0 -43
  165. package/src/serializer.js +0 -138
  166. package/src/store.js +0 -316
  167. package/src/transforms.js +0 -20
  168. package/src/utils.js +0 -12
  169. package/test-events-setup.js +0 -41
  170. package/test-hooks-manual.js +0 -54
  171. package/test-hooks-with-logging.js +0 -52
@@ -1,43 +0,0 @@
1
- import { relationships } from "@stonyx/orm";
2
-
3
- export default class Relationships {
4
- constructor() {
5
- if (Relationships.instance) return Relationships.instance;
6
- Relationships.instance = this;
7
-
8
- this.data = new Map();
9
- }
10
-
11
- get(key) {
12
- return this.data.get(key);
13
- }
14
-
15
- set(key, value) {
16
- this.data.set(key, value);
17
- }
18
- }
19
-
20
- // TODO: Refactor mapping to remove a level of iteration
21
- export function getRelationships(type, sourceModel, targetModel, relationshipId) {
22
- const allRelationships = relationships.get(type);
23
-
24
- // create relationship map for this type of it doesn't already exist
25
- if (!allRelationships.has(sourceModel)) allRelationships.set(sourceModel, new Map());
26
-
27
- const modelRelationship = allRelationships.get(sourceModel);
28
-
29
- if (!modelRelationship.has(targetModel)) modelRelationship.set(targetModel, new Map());
30
-
31
- const relationship = modelRelationship.get(targetModel);
32
-
33
- // TODO: Determine whether already having id should be handled differently
34
- //if (relationship.has(relationshipId)) return;
35
-
36
- return relationship;
37
- }
38
-
39
- export function getHasManyRelationships(sourceModel, targetModel) {
40
- return relationships.get('hasMany').get(sourceModel)?.get(targetModel);
41
- }
42
-
43
- export const TYPES = ['global', 'hasMany', 'belongsTo', 'pending'];
package/src/serializer.js DELETED
@@ -1,138 +0,0 @@
1
- import config from 'stonyx/config';
2
- import { get, makeArray } from '@stonyx/utils/object';
3
-
4
- const RESERVED_KEYS = ['__name'];
5
-
6
- function searchQuery(query, array, key) {
7
- const result = makeArray(array).find(item => {
8
- for (const [ prop, value ] of Object.entries(query)) {
9
- if (item[prop] !== value) return false;
10
-
11
- return true;
12
- }
13
- });
14
-
15
- if (!result) return null;
16
- if (key) return result[key];
17
-
18
- return result;
19
- }
20
-
21
- function query(rawData, pathPrefix, subPath) {
22
- if (!rawData) return null;
23
-
24
- const [ path, getter, pointer ] = makeArray(subPath);
25
- const fullPath = `${pathPrefix}${path}`;
26
- const value = get(rawData, fullPath);
27
-
28
- if (getter === undefined || getter === null) return value;
29
-
30
- try {
31
- switch(typeof getter) {
32
- case 'object':
33
- return searchQuery(getter, value, pointer);
34
-
35
- case 'function':
36
- return getter(value);
37
-
38
- case 'number':
39
- const element = value[getter];
40
- return pointer ? element[pointer] : element;
41
-
42
- default:
43
- return value[getter];
44
- }
45
- } catch (error) {
46
- if (config.debug) console.error(`Cannot parse value for ${fullPath}.`, { getter, query }, error);
47
- }
48
- }
49
-
50
- export default class Serializer {
51
- map = {};
52
- path = '';
53
-
54
- constructor(model) {
55
- this.model = model;
56
- }
57
-
58
- /**
59
- * This method populates the record's instance with instances of
60
- * the ModelProperty object, while setting parsed values to the record's
61
- * __data property, which represents the serialized version of the data
62
- */
63
- setProperties(rawData, record, options) {
64
- const { path, model } = this;
65
- const keys = Object.keys(model).filter(key => !RESERVED_KEYS.includes(key));
66
- const pathPrefix = path ? `${path}.` : '';
67
- const { __data:parsedData, __relationships:relatedRecords } = record;
68
-
69
- for (const key of keys) {
70
- const subPath = options.serialize ? (this.map[key] || key) : key;
71
- const handler = model[key];
72
- const data = query(rawData, pathPrefix, subPath);
73
-
74
- // Ignore null/undefined values on updates (TODO: What if we want it set to null?)
75
- if ((data === null || data === undefined) && options.update) continue;
76
-
77
- // Relationship handling
78
- if (typeof handler === 'function') {
79
- // Pass relationship key name to handler for pending fulfillment
80
- const handlerOptions = { ...options, _relationshipKey: key };
81
- const childRecord = handler(record, data, handlerOptions);
82
-
83
- record[key] = childRecord
84
- relatedRecords[key] = childRecord;
85
-
86
- continue;
87
- }
88
-
89
- // Direct assignment handling
90
- if (handler?.constructor?.name !== 'ModelProperty') {
91
- parsedData[key] = handler;
92
- record[key] = handler;
93
- continue;
94
- }
95
-
96
- Object.defineProperty(record, key, {
97
- enumerable: true,
98
- configurable: true,
99
- get: () => handler.value,
100
- set(newValue) {
101
- handler.ignoreFirstTransform = !options.transform;
102
- handler.value = newValue;
103
- parsedData[key] = handler.value;
104
- }
105
- });
106
-
107
- record[key] = data;
108
- }
109
-
110
- if (options.update) return;
111
-
112
- // Serialize computed properties
113
- for (const [key, getter] of getComputedProperties(this.model)) {
114
- Object.defineProperty(record, key, {
115
- enumerable: true,
116
- get: () => getter.call(record)
117
- });
118
- }
119
-
120
- record.__serialized = true;
121
- }
122
-
123
- /**
124
- * OVERRIDE: This hook allows for data manipulation prior to serialization logic
125
- */
126
- normalize(data) {
127
- return data;
128
- }
129
- }
130
-
131
- export function getComputedProperties(classInstance) {
132
- const proto = Object.getPrototypeOf(classInstance);
133
- if (!proto || proto === Object.prototype) return [];
134
-
135
- return Object.entries(Object.getOwnPropertyDescriptors(proto))
136
- .filter(([key, descriptor]) => key !== 'constructor' && descriptor.get)
137
- .map(([key, descriptor]) => [key, descriptor.get]);
138
- }
package/src/store.js DELETED
@@ -1,316 +0,0 @@
1
- import { relationships } from '@stonyx/orm';
2
- import { TYPES } from './relationships.js';
3
-
4
- export default class Store {
5
- constructor() {
6
- if (Store.instance) return Store.instance;
7
- Store.instance = this;
8
-
9
- this.data = new Map();
10
- }
11
-
12
- /**
13
- * Synchronous memory-only access.
14
- * Returns the record if it exists in the in-memory store, undefined otherwise.
15
- * Does NOT query the database. For memory:false models, use find() instead.
16
- */
17
- get(key, id) {
18
- if (!id) return this.data.get(key);
19
-
20
- return this.data.get(key)?.get(id);
21
- }
22
-
23
- /**
24
- * Async authoritative read. Always queries MySQL for memory: false models.
25
- * For memory: true models, returns from store (already loaded on boot).
26
- * @param {string} modelName - The model name
27
- * @param {string|number} id - The record ID
28
- * @returns {Promise<Record|undefined>}
29
- */
30
- async find(modelName, id) {
31
- // For memory: true models, the store is authoritative
32
- if (this._isMemoryModel(modelName)) {
33
- return this.get(modelName, id);
34
- }
35
-
36
- // For memory: false models, always query MySQL
37
- if (this._mysqlDb) {
38
- return this._mysqlDb.findRecord(modelName, id);
39
- }
40
-
41
- // Fallback to store (JSON mode or no MySQL)
42
- return this.get(modelName, id);
43
- }
44
-
45
- /**
46
- * Async read for all records of a model. Always queries MySQL for memory: false models.
47
- * For memory: true models, returns from store.
48
- * @param {string} modelName - The model name
49
- * @param {Object} [conditions] - Optional WHERE conditions
50
- * @returns {Promise<Record[]>}
51
- */
52
- async findAll(modelName, conditions) {
53
- // For memory: true models without conditions, return from store
54
- if (this._isMemoryModel(modelName) && !conditions) {
55
- const modelStore = this.get(modelName);
56
- return modelStore ? Array.from(modelStore.values()) : [];
57
- }
58
-
59
- // For memory: false models (or filtered queries), always query MySQL
60
- if (this._mysqlDb) {
61
- return this._mysqlDb.findAll(modelName, conditions);
62
- }
63
-
64
- // Fallback to store (JSON mode) — apply conditions in-memory if provided
65
- const modelStore = this.get(modelName);
66
- if (!modelStore) return [];
67
-
68
- const records = Array.from(modelStore.values());
69
-
70
- if (!conditions || Object.keys(conditions).length === 0) return records;
71
-
72
- return records.filter(record =>
73
- Object.entries(conditions).every(([key, value]) => record.__data[key] === value)
74
- );
75
- }
76
-
77
- /**
78
- * Async query — always hits MySQL, never reads from memory cache.
79
- * Use for complex queries, aggregations, or when you need guaranteed freshness.
80
- * @param {string} modelName - The model name
81
- * @param {Object} conditions - WHERE conditions
82
- * @returns {Promise<Record[]>}
83
- */
84
- async query(modelName, conditions = {}) {
85
- if (this._mysqlDb) {
86
- return this._mysqlDb.findAll(modelName, conditions);
87
- }
88
-
89
- // Fallback: filter in-memory store
90
- const modelStore = this.get(modelName);
91
- if (!modelStore) return [];
92
-
93
- const records = Array.from(modelStore.values());
94
-
95
- if (Object.keys(conditions).length === 0) return records;
96
-
97
- return records.filter(record =>
98
- Object.entries(conditions).every(([key, value]) => record.__data[key] === value)
99
- );
100
- }
101
-
102
- /**
103
- * Set by Orm during init — resolves memory flag for a model name.
104
- * @type {Function|null}
105
- */
106
- _memoryResolver = null;
107
-
108
- /**
109
- * Set by Orm during init — reference to the MysqlDB instance for on-demand queries.
110
- * @type {MysqlDB|null}
111
- */
112
- _mysqlDb = null;
113
-
114
- /**
115
- * Check if a model is configured for in-memory storage.
116
- * @private
117
- */
118
- _isMemoryModel(modelName) {
119
- if (this._memoryResolver) return this._memoryResolver(modelName);
120
- return true; // default to memory if resolver not set yet
121
- }
122
-
123
- set(key, value) {
124
- this.data.set(key, value);
125
- }
126
-
127
- remove(key, id) {
128
- if (id) return this.unloadRecord(key, id);
129
-
130
- this.unloadAllRecords(key);
131
- }
132
-
133
- unloadRecord(model, id, options={}) {
134
- const modelStore = this.data.get(model);
135
-
136
- if (!modelStore) {
137
- console.warn(`[Store] Cannot unload record: model "${model}" not found in store`);
138
- return;
139
- }
140
-
141
- const record = modelStore.get(id);
142
-
143
- if (!record) {
144
- console.warn(`[Store] Cannot unload record: ${model}:${id} not found in store`);
145
- return;
146
- }
147
-
148
- const { toUnload, visited } = options.includeChildren
149
- ? this._buildUnloadQueue(record, options)
150
- : { toUnload: [{ record, modelName: model, recordId: id }], visited: new Set([`${model}:${id}`]) };
151
-
152
- for (const item of toUnload.reverse()) {
153
- const { record: recordToUnload, modelName, recordId } = item;
154
-
155
- this._removeFromHasManyArrays(modelName, recordId, visited);
156
- this._nullifyBelongsToReferences(modelName, recordId, visited);
157
- this._cleanupRelationshipRegistries(modelName, recordId);
158
- recordToUnload.clean();
159
-
160
- this.data.get(modelName).delete(recordId);
161
- }
162
- }
163
-
164
- unloadAllRecords(model, options={}) {
165
- const modelStore = this.data.get(model);
166
-
167
- if (!modelStore) {
168
- console.warn(`[Store] Cannot unload all records: model "${model}" not found in store`);
169
- return;
170
- }
171
-
172
- const recordIds = Array.from(modelStore.keys());
173
-
174
- for (const id of recordIds) {
175
- if (modelStore.has(id)) {
176
- this.unloadRecord(model, id, options);
177
- }
178
- }
179
-
180
- for (const relationshipType of TYPES) relationships.get(relationshipType).delete(model);
181
- }
182
-
183
- _removeFromHasManyArrays(modelName, recordId, visited) {
184
- const hasManyRegistry = relationships.get('hasMany');
185
-
186
- for (const [sourceModel, targetModels] of hasManyRegistry) {
187
- const targetModelMap = targetModels.get(modelName);
188
- if (!targetModelMap) continue;
189
-
190
- for (const [sourceRecordId, hasManyArray] of targetModelMap) {
191
- const sourceKey = `${sourceModel}:${sourceRecordId}`;
192
-
193
- // Don't modify arrays of records being deleted
194
- if (visited.has(sourceKey)) continue;
195
-
196
- const index = hasManyArray.findIndex(r => r && r.id === recordId);
197
- if (index !== -1) hasManyArray.splice(index, 1);
198
- }
199
- }
200
- }
201
-
202
- _nullifyBelongsToReferences(modelName, recordId, visited) {
203
- const belongsToRegistry = relationships.get('belongsTo');
204
-
205
- for (const [sourceModel, targetModels] of belongsToRegistry) {
206
- const targetModelMap = targetModels.get(modelName);
207
- if (!targetModelMap) continue;
208
-
209
- for (const [sourceRecordId, belongsToRecord] of targetModelMap) {
210
- if (belongsToRecord && belongsToRecord.id === recordId) {
211
- const sourceKey = `${sourceModel}:${sourceRecordId}`;
212
-
213
- if (visited.has(sourceKey)) continue;
214
- targetModelMap.set(sourceRecordId, null);
215
-
216
- const sourceRecord = this.get(sourceModel, sourceRecordId);
217
- if (sourceRecord && sourceRecord.__relationships) {
218
- for (const [key, value] of Object.entries(sourceRecord.__relationships)) {
219
- if (value && value.id === recordId) {
220
- sourceRecord.__relationships[key] = null;
221
- }
222
- }
223
- }
224
- }
225
- }
226
- }
227
- }
228
-
229
- _cleanupRelationshipRegistries(modelName, recordId) {
230
- const hasManyMap = relationships.get('hasMany').get(modelName);
231
- if (hasManyMap) {
232
- for (const [, recordMap] of hasManyMap) recordMap.delete(recordId);
233
- }
234
-
235
- const belongsToMap = relationships.get('belongsTo').get(modelName);
236
- if (belongsToMap) {
237
- for (const [, recordMap] of belongsToMap) recordMap.delete(recordId);
238
- }
239
-
240
- const pendingMap = relationships.get('pending').get(modelName);
241
- if (pendingMap) pendingMap.delete(recordId);
242
- }
243
-
244
- /**
245
- * Extracts hasMany and non-bidirectional belongsTo children from a record
246
- * @private
247
- */
248
- _getChildren(record) {
249
- const children = [];
250
-
251
- if (!record.__relationships) return children;
252
-
253
- for (const [key, value] of Object.entries(record.__relationships)) {
254
- // hasMany children - always include
255
- if (Array.isArray(value)) {
256
- for (const childRecord of value) {
257
- if (childRecord) children.push({ childRecord, relationshipKey: key, type: 'hasMany' });
258
- }
259
- } else if (value && !this._isBidirectionalRelationship(
260
- record.__model.__name,
261
- value.__model.__name
262
- )) {
263
- children.push({ childRecord: value, relationshipKey: key, type: 'belongsTo' });
264
- }
265
- }
266
-
267
- return children;
268
- }
269
-
270
- _isBidirectionalRelationship(sourceModel, targetModel) {
271
- const hasManyRegistry = relationships.get('hasMany');
272
- const inverseMap = hasManyRegistry.get(targetModel)?.get(sourceModel);
273
-
274
- return inverseMap && inverseMap.size > 0;
275
- }
276
-
277
- _buildUnloadQueue(record, options) {
278
- const visited = new Set();
279
- const toUnload = [];
280
- const queue = [{
281
- record,
282
- modelName: record.__model.__name,
283
- recordId: record.id,
284
- isRoot: true,
285
- depth: 0
286
- }];
287
-
288
- while (queue.length > 0) {
289
- const item = queue.shift();
290
- const key = `${item.modelName}:${item.recordId}`;
291
-
292
- if (visited.has(key)) continue;
293
- visited.add(key);
294
-
295
- toUnload.push(item);
296
-
297
- // Add children to queue if includeChildren is enabled
298
- if (options.includeChildren) {
299
- const children = this._getChildren(item.record);
300
- for (const { childRecord } of children) {
301
- if (childRecord) {
302
- queue.push({
303
- record: childRecord,
304
- modelName: childRecord.__model.__name,
305
- recordId: childRecord.id,
306
- isRoot: false,
307
- depth: item.depth + 1
308
- });
309
- }
310
- }
311
- }
312
- }
313
-
314
- return { toUnload, visited };
315
- }
316
- }
package/src/transforms.js DELETED
@@ -1,20 +0,0 @@
1
- import { getTimestamp } from "@stonyx/utils/date";
2
-
3
- const transforms = {
4
- boolean: value => typeof value === 'string' ? value.trim().toLowerCase() === 'true' : !!value,
5
- date: value => value ? new Date(value) : null,
6
- float: value => parseFloat(value),
7
- number: value => parseInt(value),
8
- passthrough: value => value,
9
- string: value => String(value),
10
- timestamp: value => getTimestamp(value),
11
- trim: value => value?.trim(),
12
- uppercase: value => value?.toUpperCase(),
13
- };
14
-
15
- // Math Proxies
16
- ['ceil', 'floor', 'round'].forEach(method => {
17
- transforms[method] = value => Math[method](value);
18
- });
19
-
20
- export default transforms;
package/src/utils.js DELETED
@@ -1,12 +0,0 @@
1
- import { pluralize as basePluralize } from '@stonyx/utils/string';
2
-
3
- // Wrapper to handle dasherized model names (e.g., "access-link" → "access-links")
4
- export function pluralize(word) {
5
- if (word.includes('-')) {
6
- const parts = word.split('-');
7
- const pluralizedLast = basePluralize(parts.pop());
8
- return [...parts, pluralizedLast].join('-');
9
- }
10
-
11
- return basePluralize(word);
12
- }
@@ -1,41 +0,0 @@
1
- /**
2
- * Debug script to verify event setup
3
- */
4
-
5
- import Stonyx from 'stonyx';
6
- import config from './config/environment.js';
7
- import Orm from './src/main.js';
8
- import { subscribe } from '@stonyx/events';
9
-
10
- // Override paths for tests
11
- Object.assign(config.paths, {
12
- access: './test/sample/access',
13
- model: './test/sample/models',
14
- serializer: './test/sample/serializers',
15
- transform: './test/sample/transforms'
16
- });
17
-
18
- // Override db settings for tests
19
- Object.assign(config.db, {
20
- file: './test/sample/db.json',
21
- schema: './test/sample/db-schema.js'
22
- });
23
-
24
- new Stonyx(config, import.meta.dirname);
25
-
26
- const orm = new Orm();
27
- await orm.init();
28
-
29
- console.log('ORM initialized');
30
- console.log('Store keys:', Array.from(Orm.store.data.keys()));
31
-
32
- // Try subscribing to an event
33
- try {
34
- const unsubscribe = subscribe('before:create:animal', (context) => {
35
- console.log('Hook called!', context);
36
- });
37
- console.log('✓ Successfully subscribed to before:create:animal');
38
- unsubscribe();
39
- } catch (error) {
40
- console.error('✗ Failed to subscribe:', error.message);
41
- }
@@ -1,54 +0,0 @@
1
- /**
2
- * Manual test script for hooks functionality
3
- * Run with: node test-hooks-manual.js
4
- */
5
-
6
- import { setup, subscribe, emit } from '@stonyx/events';
7
-
8
- console.log('Testing hooks system...\n');
9
-
10
- // Setup events
11
- const eventNames = ['before:create:animal', 'after:create:animal'];
12
- setup(eventNames);
13
-
14
- let beforeCalled = false;
15
- let afterCalled = false;
16
- let contextReceived = null;
17
-
18
- // Subscribe to hooks
19
- const unsubscribe1 = subscribe('before:create:animal', async (context) => {
20
- console.log('✓ before:create:animal hook called');
21
- console.log(' Context:', JSON.stringify(context, null, 2));
22
- beforeCalled = true;
23
- contextReceived = context;
24
- });
25
-
26
- const unsubscribe2 = subscribe('after:create:animal', async (context) => {
27
- console.log('✓ after:create:animal hook called');
28
- console.log(' Context:', JSON.stringify(context, null, 2));
29
- afterCalled = true;
30
- });
31
-
32
- // Simulate hook execution
33
- const testContext = {
34
- model: 'animal',
35
- operation: 'create',
36
- body: { data: { type: 'animals', attributes: { name: 'Test' } } }
37
- };
38
-
39
- console.log('Emitting before:create:animal...');
40
- await emit('before:create:animal', testContext);
41
-
42
- console.log('\nEmitting after:create:animal...');
43
- await emit('after:create:animal', { ...testContext, record: { id: 1, name: 'Test' } });
44
-
45
- console.log('\n--- Test Results ---');
46
- console.log('Before hook called:', beforeCalled ? '✓ PASS' : '✗ FAIL');
47
- console.log('After hook called:', afterCalled ? '✓ PASS' : '✗ FAIL');
48
- console.log('Context passed correctly:', contextReceived?.model === 'animal' ? '✓ PASS' : '✗ FAIL');
49
-
50
- // Cleanup
51
- unsubscribe1();
52
- unsubscribe2();
53
-
54
- console.log('\n✓ Hooks system working correctly!');
@@ -1,52 +0,0 @@
1
- /**
2
- * Test to verify hooks wrapper is being called
3
- */
4
-
5
- import { emit } from '@stonyx/events';
6
-
7
- // Simulate the _withHooks wrapper
8
- function _withHooks(operation, handler, model) {
9
- console.log(`Creating wrapper for ${operation} on ${model}`);
10
-
11
- return async (request, state) => {
12
- console.log(`Wrapper called for ${operation} on ${model}`);
13
-
14
- const context = {
15
- model,
16
- operation,
17
- request,
18
- };
19
-
20
- console.log(`About to emit before:${operation}:${model}`);
21
- await emit(`before:${operation}:${model}`, context);
22
- console.log(`Emitted before hook`);
23
-
24
- const response = await handler(request, state);
25
- console.log(`Handler completed`);
26
-
27
- context.response = response;
28
- await emit(`after:${operation}:${model}`, context);
29
- console.log(`Emitted after hook`);
30
-
31
- return response;
32
- };
33
- }
34
-
35
- // Simulate a handler
36
- const createHandler = ({ body }) => {
37
- console.log('Original handler called');
38
- return { data: { id: 1, ...body } };
39
- };
40
-
41
- // Create wrapped handler
42
- const wrappedHandler = _withHooks('create', createHandler, 'animal');
43
-
44
- // Simulate a request
45
- const mockRequest = {
46
- body: { name: 'Test' }
47
- };
48
-
49
- console.log('\n=== Testing wrapper ===');
50
- const result = await wrappedHandler(mockRequest, {});
51
- console.log('Result:', result);
52
- console.log('\n✓ Wrapper test completed');