masterrecord 0.2.20 → 0.2.22
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/cli.js +26 -4
- package/Migrations/migrations.js +16 -0
- package/context.js +11 -7
- package/package.json +1 -1
package/Migrations/cli.js
CHANGED
|
@@ -191,24 +191,40 @@ program.option('-V', 'output the version');
|
|
|
191
191
|
return;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
// Resolve relative paths from the snapshot directory (portable snapshots)
|
|
195
|
+
const snapDir = path.dirname(file);
|
|
196
|
+
const contextAbs = path.resolve(snapDir, contextSnapshot.contextLocation || '');
|
|
197
|
+
const migBase = path.resolve(snapDir, contextSnapshot.migrationFolder || '.');
|
|
198
|
+
|
|
194
199
|
let ContextCtor;
|
|
195
200
|
try{
|
|
196
|
-
ContextCtor = require(
|
|
201
|
+
ContextCtor = require(contextAbs);
|
|
197
202
|
}catch(_){
|
|
198
|
-
console.log(`Error - Cannot load Context file at '${
|
|
203
|
+
console.log(`Error - Cannot load Context file at '${contextAbs}'.`);
|
|
199
204
|
return;
|
|
200
205
|
}
|
|
201
206
|
let contextInstance;
|
|
202
207
|
try{
|
|
203
208
|
contextInstance = new ContextCtor();
|
|
204
209
|
}catch(_){
|
|
205
|
-
console.log(`Error - Failed to construct Context from '${
|
|
210
|
+
console.log(`Error - Failed to construct Context from '${contextAbs}'.`);
|
|
206
211
|
return;
|
|
207
212
|
}
|
|
208
213
|
var cleanEntities = migration.cleanEntities(contextInstance.__entities);
|
|
214
|
+
|
|
215
|
+
// Skip if no changes between snapshot schema and current entities
|
|
216
|
+
const has = migration.hasChanges(contextSnapshot.schema || [], cleanEntities || []);
|
|
217
|
+
if(!has){
|
|
218
|
+
console.log(`No changes detected for ${path.basename(contextAbs)}. Skipping.`);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
209
222
|
var newEntity = migration.template(name, contextSnapshot.schema, cleanEntities);
|
|
223
|
+
if(!fs.existsSync(migBase)){
|
|
224
|
+
try{ fs.mkdirSync(migBase, { recursive: true }); }catch(_){ /* ignore */ }
|
|
225
|
+
}
|
|
210
226
|
var migrationDate = Date.now();
|
|
211
|
-
var outputFile = `${
|
|
227
|
+
var outputFile = `${migBase}/${migrationDate}_${name}_migration.js`
|
|
212
228
|
fs.writeFile(outputFile, newEntity, 'utf8', function (err) {
|
|
213
229
|
if (err) return console.log("--- Error running cammand, re-run command add-migration ---- ", err);
|
|
214
230
|
});
|
|
@@ -595,6 +611,12 @@ program.option('-V', 'output the version');
|
|
|
595
611
|
}
|
|
596
612
|
var migration = new Migration();
|
|
597
613
|
var cleanEntities = migration.cleanEntities(contextInstance.__entities);
|
|
614
|
+
// If no changes, skip with message
|
|
615
|
+
const has = migration.hasChanges(cs.schema || [], cleanEntities || []);
|
|
616
|
+
if(!has){
|
|
617
|
+
console.log(`No changes detected for ${path.basename(contextAbs)}. Skipping.`);
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
598
620
|
var newEntity = migration.template(name, cs.schema, cleanEntities);
|
|
599
621
|
if(!fs.existsSync(migBase)){
|
|
600
622
|
try{ fs.mkdirSync(migBase, { recursive: true }); }catch(_){ /* ignore */ }
|
package/Migrations/migrations.js
CHANGED
|
@@ -277,6 +277,22 @@ class Migrations{
|
|
|
277
277
|
return tableObj;
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
+
// Returns true if there are any changes between old and new schema
|
|
281
|
+
hasChanges(oldSchema, newSchema){
|
|
282
|
+
const tables = this.#buildMigrationObject(oldSchema, newSchema);
|
|
283
|
+
for(const t of tables){
|
|
284
|
+
if(!t) continue;
|
|
285
|
+
if((t.newTables && t.newTables.length) ||
|
|
286
|
+
(t.newColumns && t.newColumns.length) ||
|
|
287
|
+
(t.deletedColumns && t.deletedColumns.length) ||
|
|
288
|
+
(t.updatedColumns && t.updatedColumns.length) ||
|
|
289
|
+
(t.old === null) || (t.new === null)){
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
|
|
280
296
|
template(name, oldSchema, newSchema){
|
|
281
297
|
var MT = new MigrationTemplate(name);
|
|
282
298
|
var tables = this.#buildMigrationObject(oldSchema, newSchema);
|
package/context.js
CHANGED
|
@@ -98,17 +98,19 @@ class context {
|
|
|
98
98
|
let currentRoot = root;
|
|
99
99
|
const maxHops = 12;
|
|
100
100
|
for(let i = 0; i < maxHops; i++){
|
|
101
|
-
const rootFolder = path.isAbsolute(rootFolderLocation) ? rootFolderLocation :
|
|
101
|
+
const rootFolder = path.isAbsolute(rootFolderLocation) ? rootFolderLocation : path.join(currentRoot, rootFolderLocation);
|
|
102
102
|
// Support both env.development.json and development.json naming
|
|
103
103
|
const searchA = `${rootFolder}/**/*env.${envType}.json`;
|
|
104
104
|
const searchB = `${rootFolder}/**/*${envType}.json`;
|
|
105
|
-
let files = globSearch.sync(searchA, currentRoot);
|
|
105
|
+
let files = globSearch.sync(searchA, { cwd: currentRoot, dot: true, nocase: true, windowsPathsNoEscape: true });
|
|
106
106
|
if(!files || files.length === 0){
|
|
107
|
-
files = globSearch.sync(searchB, currentRoot);
|
|
107
|
+
files = globSearch.sync(searchB, { cwd: currentRoot, dot: true, nocase: true, windowsPathsNoEscape: true });
|
|
108
108
|
}
|
|
109
|
-
const
|
|
110
|
-
if(
|
|
111
|
-
|
|
109
|
+
const rel = files && files[0];
|
|
110
|
+
if(rel){
|
|
111
|
+
// Ensure absolute path for require()
|
|
112
|
+
const abs = path.isAbsolute(rel) ? rel : path.resolve(currentRoot, rel);
|
|
113
|
+
return { file: abs, rootFolder: currentRoot };
|
|
112
114
|
}
|
|
113
115
|
const parent = tools.removeBackwardSlashSection(currentRoot, 1, "/");
|
|
114
116
|
if(parent === currentRoot || parent === ""){
|
|
@@ -151,7 +153,9 @@ class context {
|
|
|
151
153
|
throw new Error(`Environment config not found for '${envType}' under '${rootFolderLocation}'.`);
|
|
152
154
|
}
|
|
153
155
|
|
|
154
|
-
|
|
156
|
+
// Always require absolute file path to avoid module root ambiguity on global installs/Windows
|
|
157
|
+
const settingsPath = path.isAbsolute(file.file) ? file.file : path.resolve(file.rootFolder, file.file);
|
|
158
|
+
const settings = require(settingsPath);
|
|
155
159
|
const options = settings[contextName];
|
|
156
160
|
if(options === undefined){
|
|
157
161
|
console.log("settings missing context name settings");
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"app-root-path": "^3.1.0",
|
|
10
10
|
"better-sqlite3": "^12.4.1"
|
|
11
11
|
},
|
|
12
|
-
"version": "0.2.
|
|
12
|
+
"version": "0.2.22",
|
|
13
13
|
"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 ",
|
|
14
14
|
"homepage": "https://github.com/Tailor/MasterRecord#readme",
|
|
15
15
|
"repository": {
|