masterrecord 0.3.60 → 0.3.62
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/Migrations/migrations.js +2 -2
- package/SQLLiteEngine.js +4 -1
- package/context.js +7 -2
- package/mySQLEngine.js +2 -2
- package/package.json +1 -1
- package/postgresEngine.js +2 -2
- package/test/new-entity-migration-test.js +162 -0
package/Migrations/migrations.js
CHANGED
|
@@ -58,7 +58,7 @@ class Migrations{
|
|
|
58
58
|
|
|
59
59
|
var table = {
|
|
60
60
|
name: tableName,
|
|
61
|
-
old:
|
|
61
|
+
old: {},
|
|
62
62
|
new :item,
|
|
63
63
|
newColumns : [],
|
|
64
64
|
newTables : [],
|
|
@@ -75,9 +75,9 @@ class Migrations{
|
|
|
75
75
|
var oldItemName = oldItem["__name"];
|
|
76
76
|
if(table.name === oldItemName){
|
|
77
77
|
table.old = oldItem;
|
|
78
|
-
tables.push(table);
|
|
79
78
|
}
|
|
80
79
|
});
|
|
80
|
+
tables.push(table);
|
|
81
81
|
|
|
82
82
|
});
|
|
83
83
|
}
|
package/SQLLiteEngine.js
CHANGED
|
@@ -1224,7 +1224,10 @@ class SQLLiteEngine {
|
|
|
1224
1224
|
return mainString;;
|
|
1225
1225
|
}
|
|
1226
1226
|
|
|
1227
|
-
_execute(query){
|
|
1227
|
+
_execute(query, params){
|
|
1228
|
+
if (params && params.length > 0) {
|
|
1229
|
+
return this._executeWithParams(query, params);
|
|
1230
|
+
}
|
|
1228
1231
|
if (process.env.LOG_SQL === 'true' || process.env.NODE_ENV !== 'production') {
|
|
1229
1232
|
console.debug("[SQL]", query);
|
|
1230
1233
|
}
|
package/context.js
CHANGED
|
@@ -1824,20 +1824,25 @@ class context {
|
|
|
1824
1824
|
|
|
1825
1825
|
|
|
1826
1826
|
/**
|
|
1827
|
-
* Execute a raw SQL query
|
|
1827
|
+
* Execute a raw SQL query, optionally with parameterized values
|
|
1828
1828
|
*
|
|
1829
1829
|
* @param {string} query - SQL query to execute
|
|
1830
|
+
* @param {Array} [params] - Optional array of parameter values for placeholders
|
|
1830
1831
|
*
|
|
1831
1832
|
* @example
|
|
1832
1833
|
* context._execute('CREATE INDEX idx_user_email ON User(email)');
|
|
1834
|
+
* context._execute('UPDATE User SET name = ? WHERE id = ?', ['Alice', 1]);
|
|
1833
1835
|
*/
|
|
1834
|
-
_execute(query) {
|
|
1836
|
+
_execute(query, params) {
|
|
1835
1837
|
if (!this._SQLEngine) {
|
|
1836
1838
|
throw new DatabaseConnectionError(
|
|
1837
1839
|
'Cannot execute query: database engine not initialized. Ensure you have awaited env() before running queries.',
|
|
1838
1840
|
this.isMySQL ? 'MySQL' : this.isPostgres ? 'PostgreSQL' : 'SQLite'
|
|
1839
1841
|
);
|
|
1840
1842
|
}
|
|
1843
|
+
if (params && params.length > 0) {
|
|
1844
|
+
return this._SQLEngine._execute(query, params);
|
|
1845
|
+
}
|
|
1841
1846
|
return this._SQLEngine._execute(query);
|
|
1842
1847
|
}
|
|
1843
1848
|
|
package/mySQLEngine.js
CHANGED
|
@@ -802,8 +802,8 @@ class MySQLEngine {
|
|
|
802
802
|
* Execute raw SQL (DDL statements like CREATE TABLE, ALTER TABLE, etc.)
|
|
803
803
|
* Used by migration schema for non-parameterized DDL queries.
|
|
804
804
|
*/
|
|
805
|
-
_execute(query) {
|
|
806
|
-
return this._runWithParams(query, []);
|
|
805
|
+
_execute(query, params) {
|
|
806
|
+
return this._runWithParams(query, params || []);
|
|
807
807
|
}
|
|
808
808
|
|
|
809
809
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "masterrecord",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.62",
|
|
4
4
|
"description": "An Object-relational mapping for the Master framework. Master Record connects classes to relational database tables to establish a database with almost zero-configuration ",
|
|
5
5
|
"main": "MasterRecord.js",
|
|
6
6
|
"bin": {
|
package/postgresEngine.js
CHANGED
|
@@ -754,8 +754,8 @@ class postgresEngine {
|
|
|
754
754
|
* Execute raw SQL (DDL statements like CREATE TABLE, ALTER TABLE, etc.)
|
|
755
755
|
* Used by migration schema for non-parameterized DDL queries.
|
|
756
756
|
*/
|
|
757
|
-
_execute(query) {
|
|
758
|
-
return this._runWithParams(query, []);
|
|
757
|
+
_execute(query, params) {
|
|
758
|
+
return this._runWithParams(query, params || []);
|
|
759
759
|
}
|
|
760
760
|
|
|
761
761
|
async _runWithParams(query, params = []) {
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: New entity detection in migrations
|
|
3
|
+
*
|
|
4
|
+
* Verifies that when a new entity is added to a context that already has
|
|
5
|
+
* existing entities (non-empty oldSchema), the migration system correctly
|
|
6
|
+
* includes it in the tables array and detects it as a new table.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const Module = require('module');
|
|
11
|
+
const __MASTERRECORD_ROOT__ = path.join(__dirname, '..');
|
|
12
|
+
const __ORIGINAL_REQUIRE__ = Module.prototype.require;
|
|
13
|
+
Module.prototype.require = function(request) {
|
|
14
|
+
if (request === 'masterrecord' || request.startsWith('masterrecord/')) {
|
|
15
|
+
const resolved = request === 'masterrecord'
|
|
16
|
+
? __MASTERRECORD_ROOT__
|
|
17
|
+
: path.join(__MASTERRECORD_ROOT__, request.slice('masterrecord/'.length));
|
|
18
|
+
return __ORIGINAL_REQUIRE__.call(this, resolved);
|
|
19
|
+
}
|
|
20
|
+
return __ORIGINAL_REQUIRE__.call(this, request);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const Migrations = require('../Migrations/migrations');
|
|
24
|
+
|
|
25
|
+
console.log("╔════════════════════════════════════════════════════════════════╗");
|
|
26
|
+
console.log("║ New Entity Migration Detection Test ║");
|
|
27
|
+
console.log("╚════════════════════════════════════════════════════════════════╝\n");
|
|
28
|
+
|
|
29
|
+
let passed = 0;
|
|
30
|
+
let failed = 0;
|
|
31
|
+
|
|
32
|
+
function assert(condition, label) {
|
|
33
|
+
if (condition) {
|
|
34
|
+
console.log(` ✓ ${label}`);
|
|
35
|
+
passed++;
|
|
36
|
+
} else {
|
|
37
|
+
console.log(` ✗ ${label}`);
|
|
38
|
+
failed++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const migration = new Migrations();
|
|
43
|
+
|
|
44
|
+
// Existing entity schema (already in the database)
|
|
45
|
+
const userSchema = {
|
|
46
|
+
__name: 'User',
|
|
47
|
+
id: { name: 'id', type: 'integer', primary: true, auto: true },
|
|
48
|
+
name: { name: 'name', type: 'string' },
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// New entity schema (being added)
|
|
52
|
+
const customTaskTypeSchema = {
|
|
53
|
+
__name: 'CustomTaskType',
|
|
54
|
+
id: { name: 'id', type: 'integer', primary: true, auto: true },
|
|
55
|
+
label: { name: 'label', type: 'string' },
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// -----------------------------------------------------------
|
|
59
|
+
// Test 1: First migration (empty oldSchema) — baseline
|
|
60
|
+
// -----------------------------------------------------------
|
|
61
|
+
console.log("Test 1: First migration (empty oldSchema) includes all entities");
|
|
62
|
+
console.log("──────────────────────────────────────────────────");
|
|
63
|
+
{
|
|
64
|
+
const oldSchema = [];
|
|
65
|
+
const newSchema = [userSchema, customTaskTypeSchema];
|
|
66
|
+
|
|
67
|
+
const result = migration.buildUpObject(oldSchema, newSchema);
|
|
68
|
+
|
|
69
|
+
assert(result.User !== undefined, 'User table is in result');
|
|
70
|
+
assert(result.CustomTaskType !== undefined, 'CustomTaskType table is in result');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// -----------------------------------------------------------
|
|
74
|
+
// Test 2: Subsequent migration — existing entity still works
|
|
75
|
+
// -----------------------------------------------------------
|
|
76
|
+
console.log("\nTest 2: Subsequent migration — existing entity included");
|
|
77
|
+
console.log("──────────────────────────────────────────────────");
|
|
78
|
+
{
|
|
79
|
+
const oldSchema = [userSchema];
|
|
80
|
+
const newSchema = [userSchema];
|
|
81
|
+
|
|
82
|
+
const result = migration.buildUpObject(oldSchema, newSchema);
|
|
83
|
+
|
|
84
|
+
assert(result.User !== undefined, 'User table is in result');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// -----------------------------------------------------------
|
|
88
|
+
// Test 3: Subsequent migration — NEW entity is included (the bug)
|
|
89
|
+
// -----------------------------------------------------------
|
|
90
|
+
console.log("\nTest 3: Subsequent migration — new entity is included");
|
|
91
|
+
console.log("──────────────────────────────────────────────────");
|
|
92
|
+
{
|
|
93
|
+
const oldSchema = [userSchema];
|
|
94
|
+
const newSchema = [userSchema, customTaskTypeSchema];
|
|
95
|
+
|
|
96
|
+
const result = migration.buildUpObject(oldSchema, newSchema);
|
|
97
|
+
|
|
98
|
+
assert(result.User !== undefined, 'User table is in result');
|
|
99
|
+
assert(result.CustomTaskType !== undefined, 'CustomTaskType table is in result (was undefined before fix)');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// -----------------------------------------------------------
|
|
103
|
+
// Test 4: hasChanges detects the new entity
|
|
104
|
+
// -----------------------------------------------------------
|
|
105
|
+
console.log("\nTest 4: hasChanges detects new entity");
|
|
106
|
+
console.log("──────────────────────────────────────────────────");
|
|
107
|
+
{
|
|
108
|
+
const oldSchema = [userSchema];
|
|
109
|
+
const newSchema = [userSchema, customTaskTypeSchema];
|
|
110
|
+
|
|
111
|
+
const changed = migration.hasChanges(oldSchema, newSchema);
|
|
112
|
+
|
|
113
|
+
assert(changed === true, 'hasChanges returns true for new entity');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// -----------------------------------------------------------
|
|
117
|
+
// Test 5: hasChanges returns false when nothing changed
|
|
118
|
+
// -----------------------------------------------------------
|
|
119
|
+
console.log("\nTest 5: hasChanges returns false when nothing changed");
|
|
120
|
+
console.log("──────────────────────────────────────────────────");
|
|
121
|
+
{
|
|
122
|
+
const oldSchema = [userSchema];
|
|
123
|
+
const newSchema = [userSchema];
|
|
124
|
+
|
|
125
|
+
const changed = migration.hasChanges(oldSchema, newSchema);
|
|
126
|
+
|
|
127
|
+
assert(changed === false, 'hasChanges returns false when schemas are identical');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// -----------------------------------------------------------
|
|
131
|
+
// Test 6: Multiple new entities in one migration
|
|
132
|
+
// -----------------------------------------------------------
|
|
133
|
+
console.log("\nTest 6: Multiple new entities in one migration");
|
|
134
|
+
console.log("──────────────────────────────────────────────────");
|
|
135
|
+
{
|
|
136
|
+
const tagSchema = {
|
|
137
|
+
__name: 'Tag',
|
|
138
|
+
id: { name: 'id', type: 'integer', primary: true, auto: true },
|
|
139
|
+
value: { name: 'value', type: 'string' },
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const oldSchema = [userSchema];
|
|
143
|
+
const newSchema = [userSchema, customTaskTypeSchema, tagSchema];
|
|
144
|
+
|
|
145
|
+
const result = migration.buildUpObject(oldSchema, newSchema);
|
|
146
|
+
|
|
147
|
+
assert(result.User !== undefined, 'User table is in result');
|
|
148
|
+
assert(result.CustomTaskType !== undefined, 'CustomTaskType is in result');
|
|
149
|
+
assert(result.Tag !== undefined, 'Tag is in result');
|
|
150
|
+
|
|
151
|
+
const changed = migration.hasChanges(oldSchema, newSchema);
|
|
152
|
+
assert(changed === true, 'hasChanges detects multiple new entities');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Summary
|
|
156
|
+
console.log("\n" + "=".repeat(64));
|
|
157
|
+
console.log(`Test Results: ${passed} passed, ${failed} failed`);
|
|
158
|
+
console.log("=".repeat(64));
|
|
159
|
+
|
|
160
|
+
if (failed > 0) {
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|