@stonyx/orm 0.2.1-beta.41 → 0.2.1-beta.43
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 +1 -1
- package/src/belongs-to.js +4 -1
- package/src/has-many.js +4 -1
- package/src/main.js +1 -1
- package/src/model.js +4 -4
- package/src/mysql/schema-introspector.js +33 -29
- package/src/store.js +1 -1
package/package.json
CHANGED
package/src/belongs-to.js
CHANGED
|
@@ -11,7 +11,7 @@ export default function belongsTo(modelName) {
|
|
|
11
11
|
const pendingHasManyQueue = relationships.get('pending');
|
|
12
12
|
const pendingBelongsToQueue = relationships.get('pendingBelongsTo');
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
const fn = (sourceRecord, rawData, options) => {
|
|
15
15
|
if (!rawData) return null;
|
|
16
16
|
|
|
17
17
|
const { __name: sourceModelName } = sourceRecord.__model;
|
|
@@ -60,4 +60,7 @@ export default function belongsTo(modelName) {
|
|
|
60
60
|
|
|
61
61
|
return output;
|
|
62
62
|
}
|
|
63
|
+
|
|
64
|
+
Object.defineProperty(fn, '__relatedModelName', { value: modelName });
|
|
65
|
+
return fn;
|
|
63
66
|
}
|
package/src/has-many.js
CHANGED
|
@@ -16,7 +16,7 @@ export default function hasMany(modelName) {
|
|
|
16
16
|
const globalRelationships = relationships.get('global');
|
|
17
17
|
const pendingRelationships = relationships.get('pending');
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
const fn = (sourceRecord, rawData, options) => {
|
|
20
20
|
const { __name: sourceModelName } = sourceRecord.__model;
|
|
21
21
|
const relationshipId = sourceRecord.id;
|
|
22
22
|
const relationship = getRelationships('hasMany', sourceModelName, modelName, relationshipId);
|
|
@@ -58,4 +58,7 @@ export default function hasMany(modelName) {
|
|
|
58
58
|
|
|
59
59
|
return output;
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
Object.defineProperty(fn, '__relatedModelName', { value: modelName });
|
|
63
|
+
return fn;
|
|
61
64
|
}
|
package/src/main.js
CHANGED
|
@@ -128,7 +128,7 @@ export default class Orm {
|
|
|
128
128
|
// Wire up memory resolver so store.find() can check model memory flags
|
|
129
129
|
Orm.store._memoryResolver = (modelName) => {
|
|
130
130
|
const { modelClass } = this.getRecordClasses(modelName);
|
|
131
|
-
return modelClass?.memory
|
|
131
|
+
return modelClass?.memory === true;
|
|
132
132
|
};
|
|
133
133
|
|
|
134
134
|
// Wire up MySQL reference for on-demand queries from store.find()/findAll()
|
package/src/model.js
CHANGED
|
@@ -4,12 +4,12 @@ export default class Model {
|
|
|
4
4
|
/**
|
|
5
5
|
* Controls whether records of this model are loaded into memory on startup.
|
|
6
6
|
*
|
|
7
|
-
* - true → loaded on boot, kept in store
|
|
8
|
-
* - false → never cached; find() always queries MySQL
|
|
7
|
+
* - true → loaded on boot, kept in store
|
|
8
|
+
* - false → never cached; find() always queries MySQL (default)
|
|
9
9
|
*
|
|
10
|
-
* Override in subclass: static memory =
|
|
10
|
+
* Override in subclass: static memory = true;
|
|
11
11
|
*/
|
|
12
|
-
static memory =
|
|
12
|
+
static memory = false;
|
|
13
13
|
static pluralName = undefined;
|
|
14
14
|
|
|
15
15
|
id = attr('number');
|
|
@@ -8,13 +8,18 @@ import { AggregateProperty } from '../aggregates.js';
|
|
|
8
8
|
function getRelationshipInfo(property) {
|
|
9
9
|
if (typeof property !== 'function') return null;
|
|
10
10
|
const fnStr = property.toString();
|
|
11
|
+
const modelName = property.__relatedModelName || null;
|
|
11
12
|
|
|
12
|
-
if (fnStr.includes(`getRelationships('belongsTo',`)) return 'belongsTo';
|
|
13
|
-
if (fnStr.includes(`getRelationships('hasMany',`)) return 'hasMany';
|
|
13
|
+
if (fnStr.includes(`getRelationships('belongsTo',`)) return { type: 'belongsTo', modelName };
|
|
14
|
+
if (fnStr.includes(`getRelationships('hasMany',`)) return { type: 'hasMany', modelName };
|
|
14
15
|
|
|
15
16
|
return null;
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
function sanitizeTableName(name) {
|
|
20
|
+
return name.replace(/[-/]/g, '_');
|
|
21
|
+
}
|
|
22
|
+
|
|
18
23
|
export function introspectModels() {
|
|
19
24
|
const { models } = Orm.instance;
|
|
20
25
|
const schemas = {};
|
|
@@ -35,12 +40,12 @@ export function introspectModels() {
|
|
|
35
40
|
for (const [key, property] of Object.entries(model)) {
|
|
36
41
|
if (key.startsWith('__')) continue;
|
|
37
42
|
|
|
38
|
-
const
|
|
43
|
+
const relInfo = getRelationshipInfo(property);
|
|
39
44
|
|
|
40
|
-
if (
|
|
41
|
-
relationships.belongsTo[key] =
|
|
42
|
-
} else if (
|
|
43
|
-
relationships.hasMany[key] =
|
|
45
|
+
if (relInfo?.type === 'belongsTo') {
|
|
46
|
+
relationships.belongsTo[key] = relInfo.modelName;
|
|
47
|
+
} else if (relInfo?.type === 'hasMany') {
|
|
48
|
+
relationships.hasMany[key] = relInfo.modelName;
|
|
44
49
|
} else if (property?.constructor?.name === 'ModelProperty') {
|
|
45
50
|
if (key === 'id') {
|
|
46
51
|
idType = property.type;
|
|
@@ -51,22 +56,21 @@ export function introspectModels() {
|
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
// Build foreign keys from belongsTo relationships
|
|
54
|
-
for (const relName of Object.
|
|
55
|
-
const modelName = camelCaseToKebabCase(relName);
|
|
59
|
+
for (const [relName, targetModelName] of Object.entries(relationships.belongsTo)) {
|
|
56
60
|
const fkColumn = `${relName}_id`;
|
|
57
61
|
foreignKeys[fkColumn] = {
|
|
58
|
-
references: getPluralName(
|
|
62
|
+
references: sanitizeTableName(getPluralName(targetModelName)),
|
|
59
63
|
column: 'id',
|
|
60
64
|
};
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
schemas[name] = {
|
|
64
|
-
table: getPluralName(name),
|
|
68
|
+
table: sanitizeTableName(getPluralName(name)),
|
|
65
69
|
idType,
|
|
66
70
|
columns,
|
|
67
71
|
foreignKeys,
|
|
68
72
|
relationships,
|
|
69
|
-
memory: modelClass.memory
|
|
73
|
+
memory: modelClass.memory === true,
|
|
70
74
|
};
|
|
71
75
|
}
|
|
72
76
|
|
|
@@ -74,7 +78,8 @@ export function introspectModels() {
|
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
export function buildTableDDL(name, schema, allSchemas = {}) {
|
|
77
|
-
const {
|
|
81
|
+
const { idType, columns, foreignKeys } = schema;
|
|
82
|
+
const table = sanitizeTableName(schema.table);
|
|
78
83
|
const lines = [];
|
|
79
84
|
|
|
80
85
|
// Primary key
|
|
@@ -101,7 +106,8 @@ export function buildTableDDL(name, schema, allSchemas = {}) {
|
|
|
101
106
|
|
|
102
107
|
// Foreign key constraints
|
|
103
108
|
for (const [fkCol, fkDef] of Object.entries(foreignKeys)) {
|
|
104
|
-
|
|
109
|
+
const refTable = sanitizeTableName(fkDef.references);
|
|
110
|
+
lines.push(` FOREIGN KEY (\`${fkCol}\`) REFERENCES \`${refTable}\`(\`${fkDef.column}\`) ON DELETE SET NULL`);
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
return `CREATE TABLE IF NOT EXISTS \`${table}\` (\n${lines.join(',\n')}\n)`;
|
|
@@ -131,8 +137,8 @@ export function getTopologicalOrder(schemas) {
|
|
|
131
137
|
if (!schema) return;
|
|
132
138
|
|
|
133
139
|
// Visit dependencies (belongsTo targets) first
|
|
134
|
-
for (const
|
|
135
|
-
visit(
|
|
140
|
+
for (const targetModelName of Object.values(schema.relationships.belongsTo)) {
|
|
141
|
+
visit(targetModelName);
|
|
136
142
|
}
|
|
137
143
|
|
|
138
144
|
order.push(name);
|
|
@@ -172,18 +178,17 @@ export function introspectViews() {
|
|
|
172
178
|
continue;
|
|
173
179
|
}
|
|
174
180
|
|
|
175
|
-
const
|
|
181
|
+
const relInfo = getRelationshipInfo(property);
|
|
176
182
|
|
|
177
|
-
if (
|
|
178
|
-
relationships.belongsTo[key] =
|
|
179
|
-
const modelName = camelCaseToKebabCase(key);
|
|
183
|
+
if (relInfo?.type === 'belongsTo') {
|
|
184
|
+
relationships.belongsTo[key] = relInfo.modelName;
|
|
180
185
|
const fkColumn = `${key}_id`;
|
|
181
186
|
foreignKeys[fkColumn] = {
|
|
182
|
-
references: getPluralName(modelName),
|
|
187
|
+
references: sanitizeTableName(getPluralName(relInfo.modelName)),
|
|
183
188
|
column: 'id',
|
|
184
189
|
};
|
|
185
|
-
} else if (
|
|
186
|
-
relationships.hasMany[key] =
|
|
190
|
+
} else if (relInfo?.type === 'hasMany') {
|
|
191
|
+
relationships.hasMany[key] = relInfo.modelName;
|
|
187
192
|
} else if (property?.constructor?.name === 'ModelProperty') {
|
|
188
193
|
const transforms = Orm.instance.transforms;
|
|
189
194
|
columns[key] = getMysqlType(property.type, transforms[property.type]);
|
|
@@ -191,7 +196,7 @@ export function introspectViews() {
|
|
|
191
196
|
}
|
|
192
197
|
|
|
193
198
|
schemas[name] = {
|
|
194
|
-
viewName: getPluralName(name),
|
|
199
|
+
viewName: sanitizeTableName(getPluralName(name)),
|
|
195
200
|
source,
|
|
196
201
|
groupBy: viewClass.groupBy || undefined,
|
|
197
202
|
columns,
|
|
@@ -213,9 +218,9 @@ export function buildViewDDL(name, viewSchema, modelSchemas = {}) {
|
|
|
213
218
|
|
|
214
219
|
const sourceModelName = viewSchema.source;
|
|
215
220
|
const sourceSchema = modelSchemas[sourceModelName];
|
|
216
|
-
const sourceTable = sourceSchema
|
|
221
|
+
const sourceTable = sanitizeTableName(sourceSchema
|
|
217
222
|
? sourceSchema.table
|
|
218
|
-
: getPluralName(sourceModelName);
|
|
223
|
+
: getPluralName(sourceModelName));
|
|
219
224
|
|
|
220
225
|
const selectColumns = [];
|
|
221
226
|
const joins = [];
|
|
@@ -241,8 +246,7 @@ export function buildViewDDL(name, viewSchema, modelSchemas = {}) {
|
|
|
241
246
|
} else {
|
|
242
247
|
// Relationship aggregate
|
|
243
248
|
const relName = aggProp.relationship;
|
|
244
|
-
const
|
|
245
|
-
const relTable = getPluralName(relModelName);
|
|
249
|
+
const relTable = sanitizeTableName(getPluralName(relName));
|
|
246
250
|
|
|
247
251
|
if (aggProp.aggregateType === 'count') {
|
|
248
252
|
selectColumns.push(`${aggProp.mysqlFunction}(\`${relTable}\`.\`id\`) AS \`${key}\``);
|
|
@@ -281,7 +285,7 @@ export function buildViewDDL(name, viewSchema, modelSchemas = {}) {
|
|
|
281
285
|
groupBy = `\nGROUP BY \`${sourceTable}\`.\`id\``;
|
|
282
286
|
}
|
|
283
287
|
|
|
284
|
-
const viewName = viewSchema.viewName;
|
|
288
|
+
const viewName = sanitizeTableName(viewSchema.viewName);
|
|
285
289
|
const sql = `CREATE OR REPLACE VIEW \`${viewName}\` AS\nSELECT\n ${selectColumns.join(',\n ')}\nFROM \`${sourceTable}\`${joinClauses ? '\n ' + joinClauses : ''}${groupBy}`;
|
|
286
290
|
|
|
287
291
|
return sql;
|
package/src/store.js
CHANGED
|
@@ -136,7 +136,7 @@ export default class Store {
|
|
|
136
136
|
*/
|
|
137
137
|
_isMemoryModel(modelName) {
|
|
138
138
|
if (this._memoryResolver) return this._memoryResolver(modelName);
|
|
139
|
-
return
|
|
139
|
+
return false; // default to non-memory if resolver not set yet
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
set(key, value) {
|