masterrecord 0.0.29 → 0.0.31
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/Entity/{EntityModel.js → entityModel.js} +0 -0
- package/Entity/{EntityModelBuilder.js → entityModelBuilder.js} +0 -0
- package/Entity/{EntityTrackerModel.js → entityTrackerModel.js} +0 -0
- package/Masterrecord.js +7 -238
- package/Migrations/cli.js +21 -15
- package/Migrations/migrationSQLiteQuery.js +92 -0
- package/Migrations/migrationTemplate.js +15 -15
- package/Migrations/migrations.js +52 -18
- package/Migrations/schema.js +33 -7
- package/Migrations/test.js +34 -0
- package/QueryLanguage/queryMethods.js +1 -1
- package/context.js +248 -0
- package/{DeleteManager.js → deleteManager.js} +0 -0
- package/{InsertManager.js → insertManager.js} +0 -0
- package/package.json +1 -1
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/Masterrecord.js
CHANGED
|
@@ -2,252 +2,21 @@
|
|
|
2
2
|
// https://github.com/kriasoft/node-sqlite
|
|
3
3
|
// https://www.learnentityframeworkcore.com/dbset/deleting-data
|
|
4
4
|
// version 1.0.19
|
|
5
|
+
var context = require("./context");
|
|
6
|
+
var schema = require("./Migrations/schema");
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
var query = require('masterrecord/QueryLanguage/queryMethods');
|
|
8
|
-
var tools = require('./Tools');
|
|
9
|
-
var SQLLiteEngine = require('masterrecord/SQLLiteEngine');
|
|
10
|
-
var MYSQLEngine = require('masterrecord/MYSQLEngine');
|
|
11
|
-
var insertManager = require('./InsertManager');
|
|
12
|
-
var deleteManager = require('./DeleteManager');
|
|
13
|
-
var globSearch = require("glob");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class Context {
|
|
17
|
-
_isModelValid = {
|
|
18
|
-
isValid: true,
|
|
19
|
-
errors: []
|
|
20
|
-
};
|
|
21
|
-
__entities = [];
|
|
22
|
-
__builderEntities = [];
|
|
23
|
-
__trackedEntities = [];
|
|
24
|
-
__relationshipModels = [];
|
|
25
|
-
__enviornment = "";
|
|
26
|
-
__name = "";
|
|
8
|
+
class masterrecord{
|
|
27
9
|
|
|
28
10
|
constructor(){
|
|
29
|
-
this.
|
|
30
|
-
this.
|
|
31
|
-
this._SQLEngine = "";
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/*
|
|
35
|
-
SQLite expected model
|
|
36
|
-
{
|
|
37
|
-
"type": "better-sqlite3",
|
|
38
|
-
"connection" : "/db/",
|
|
39
|
-
"password": "",
|
|
40
|
-
"username": ""
|
|
41
|
-
}
|
|
42
|
-
*/
|
|
43
|
-
__SQLiteInit(env, sqlName){
|
|
44
|
-
try{
|
|
45
|
-
console.log("===========+++++++++++++++")
|
|
46
|
-
const sqlite3 = require(sqlName);
|
|
47
|
-
let DBAddress = env.completeConnection;
|
|
48
|
-
var db = new sqlite3(DBAddress, env);
|
|
49
|
-
db.__name = sqlName;
|
|
50
|
-
this._SQLEngine = new SQLLiteEngine();
|
|
51
|
-
return db;
|
|
52
|
-
}
|
|
53
|
-
catch (e) {
|
|
54
|
-
console.log("error SQL", e);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/*
|
|
59
|
-
mysql expected model
|
|
60
|
-
{
|
|
61
|
-
"type": "mysql",
|
|
62
|
-
host : 'localhost',
|
|
63
|
-
user : 'me',
|
|
64
|
-
password : 'secret',
|
|
65
|
-
database : 'my_db'
|
|
66
|
-
}
|
|
67
|
-
*/
|
|
68
|
-
__mysqlInit(env, sqlName){
|
|
69
|
-
try{
|
|
70
|
-
const mysql = require(sqlName);
|
|
71
|
-
const connection = mysql.createConnection(env);
|
|
72
|
-
connection.connect();
|
|
73
|
-
db.__name = sqlName;
|
|
74
|
-
this._SQLEngine = new MYSQLEngine();
|
|
75
|
-
return connection;
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
catch (e) {
|
|
79
|
-
console.log("error SQL", e);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
__clearErrorHandler(){
|
|
86
|
-
this._isModelValid = {
|
|
87
|
-
isValid: true,
|
|
88
|
-
errors: []
|
|
89
|
-
};
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
__findSettings(root, rootFolderLocation, envType){
|
|
93
|
-
|
|
94
|
-
var rootFolder = `${root}/${rootFolderLocation}`;
|
|
95
|
-
var search = `${rootFolder}/**/*env.${envType}.json`;
|
|
96
|
-
var files = globSearch.sync(search, rootFolder);
|
|
97
|
-
var file = files[0];
|
|
98
|
-
if(file === undefined){
|
|
99
|
-
root = tools.removeBackwardSlashSection(root, 1, "/");
|
|
100
|
-
rootFolder = `${root}/${rootFolderLocation}`;
|
|
101
|
-
var search = `${rootFolder}/**/*env.${envType}.json`;
|
|
102
|
-
var files = globSearch.sync(search,rootFolder);
|
|
103
|
-
file = files[0];
|
|
104
|
-
if(file === undefined){
|
|
105
|
-
root = tools.removeBackwardSlashSection(root, 1, "/");
|
|
106
|
-
rootFolder = `${root}/${rootFolderLocation}`;
|
|
107
|
-
var search = `${rootFolder}/**/*env.${envType}.json`;
|
|
108
|
-
var files = globSearch.sync(search,rootFolder);
|
|
109
|
-
file = files[0];
|
|
110
|
-
if(file === undefined){
|
|
111
|
-
console.log(`could not find file - ${rootFolder}/env.${envType}.json`);
|
|
112
|
-
throw error(`could not find file - ${rootFolder}/env.${envType}.json`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
file: file,
|
|
121
|
-
rootFolder : root
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
useSqlite(rootFolderLocation){
|
|
126
|
-
var root = process.cwd();
|
|
127
|
-
var envType = this.__enviornment;
|
|
128
|
-
var contextName = this.__name;
|
|
129
|
-
var file = this.__findSettings(root, rootFolderLocation, envType);
|
|
130
|
-
var settings = require(file.file);
|
|
131
|
-
var options = settings[contextName];
|
|
132
|
-
if(options === undefined){
|
|
133
|
-
console.log("settings missing context name settings");
|
|
134
|
-
throw error("settings missing context name settings");
|
|
135
|
-
}
|
|
136
|
-
this.validateSQLiteOptions(options);
|
|
137
|
-
options.completeConnection = `${file.rootFolder}${options.connection}`;
|
|
138
|
-
this.db = this.__SQLiteInit(options, "better-sqlite3");
|
|
139
|
-
this._SQLEngine.setDB(this.db, "better-sqlite3");
|
|
140
|
-
return this;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
validateSQLiteOptions(options){
|
|
144
|
-
if(options.hasOwnProperty('connect') === undefined){
|
|
145
|
-
console.log("connnect string settings is missing")
|
|
146
|
-
throw error("connection string settings is missing");
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
useMySql(options, rootFolderLocation){
|
|
152
|
-
if(options !== undefined){
|
|
153
|
-
this.db = this.__mysqlInit(options, "mysql");
|
|
154
|
-
this._SQLEngine.setDB(this.db, "mysql");
|
|
155
|
-
return this;
|
|
156
|
-
}
|
|
157
|
-
else{
|
|
158
|
-
console.log("database options not defined - Master Record");
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
dbset(model, name){
|
|
164
|
-
var validModel = modelBuilder.create(model);
|
|
165
|
-
validModel.__name = name === undefined ? model.name : name;
|
|
166
|
-
this.__entities.push(validModel); // model object
|
|
167
|
-
var buildMod = tools.createNewInstance(validModel, query, this);
|
|
168
|
-
this.__builderEntities.push(buildMod); // query builder entites
|
|
169
|
-
this[validModel.__name] = buildMod;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
modelState(){
|
|
173
|
-
return this._isModelValid;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
saveChanges(){
|
|
177
|
-
try{
|
|
178
|
-
var tracked = this.__trackedEntities;
|
|
179
|
-
// start transaction
|
|
180
|
-
this._SQLEngine.startTransaction();
|
|
181
|
-
for (var model in tracked) {
|
|
182
|
-
var currentModel = tracked[model];
|
|
183
|
-
switch(currentModel.__state) {
|
|
184
|
-
case "insert":
|
|
185
|
-
var insert = new insertManager(this._SQLEngine, this._isModelValid, this.__entities);
|
|
186
|
-
insert.init(currentModel);
|
|
187
|
-
|
|
188
|
-
break;
|
|
189
|
-
case "modified":
|
|
190
|
-
if(currentModel.__dirtyFields.length > 0){
|
|
191
|
-
var cleanCurrentModel = tools.removePrimarykeyandVirtual(currentModel, currentModel._entity);
|
|
192
|
-
// build columns equal to value string
|
|
193
|
-
var argu = this._SQLEngine._buildSQLEqualTo(cleanCurrentModel);
|
|
194
|
-
var primaryKey = tools.getPrimaryKeyObject(cleanCurrentModel.__entity);
|
|
195
|
-
var sqlUpdate = {tableName: cleanCurrentModel.__entity.__name, arg: argu, primaryKey : primaryKey, primaryKeyValue : cleanCurrentModel[primaryKey] };
|
|
196
|
-
this._SQLEngine.update(sqlUpdate);
|
|
197
|
-
}
|
|
198
|
-
else{
|
|
199
|
-
console.log("Tracked entity modified with no values being changed");
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// code block
|
|
203
|
-
break;
|
|
204
|
-
case "delete":
|
|
205
|
-
var deleteObject = new deleteManager(this._SQLEngine, this.__entities);
|
|
206
|
-
deleteObject.init(currentModel);
|
|
207
|
-
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
this.__clearErrorHandler();
|
|
212
|
-
this._SQLEngine.endTransaction();
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
catch(error){
|
|
216
|
-
this.__clearErrorHandler();
|
|
217
|
-
this._SQLEngine.errorTransaction();
|
|
218
|
-
console.log("error", error);
|
|
219
|
-
this.__clearTracked();
|
|
220
|
-
throw error;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
this.__clearTracked();
|
|
224
|
-
return true;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// TODO: WHY WE HAVE DOUBLE TRACKED OBJECTS - LOOP THROUGH ALL TRACKED OBJECTS
|
|
228
|
-
__track(model){
|
|
229
|
-
this.__trackedEntities.push(model);
|
|
230
|
-
return model;
|
|
11
|
+
this.context = context;
|
|
12
|
+
this.schema = schema;
|
|
231
13
|
}
|
|
14
|
+
}
|
|
232
15
|
|
|
233
|
-
__findTracked(id){
|
|
234
|
-
if(id){
|
|
235
|
-
for (var model in this.__trackedEntities) {
|
|
236
|
-
if(this.__trackedEntities[model].__ID === id){
|
|
237
|
-
return this.__trackedEntities[model];
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return null;
|
|
242
|
-
}
|
|
243
16
|
|
|
244
|
-
|
|
245
|
-
this.__trackedEntities = [];
|
|
246
|
-
}
|
|
247
|
-
}
|
|
17
|
+
module.exports = masterrecord;
|
|
248
18
|
|
|
249
19
|
|
|
250
|
-
module.exports = Context;
|
|
251
20
|
|
|
252
21
|
/*
|
|
253
22
|
|
package/Migrations/cli.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
// version 0.0.4
|
|
4
|
+
// https://docs.microsoft.com/en-us/ef/ef6/modeling/code-first/migrations/
|
|
5
|
+
// how to add environment variables on cli call example - master=development masterrecord add-migration auth authContext
|
|
6
|
+
|
|
3
7
|
const program = require('commander');
|
|
4
8
|
let fs = require('fs');
|
|
5
9
|
let path = require('path');
|
|
@@ -12,7 +16,7 @@ const [,, ...args] = process.argv
|
|
|
12
16
|
|
|
13
17
|
program
|
|
14
18
|
.version('0.0.2')
|
|
15
|
-
.option('-v, --version', '0.0.
|
|
19
|
+
.option('-v, --version', '0.0.31')
|
|
16
20
|
.description('A ORM framework that facilitates the creation and use of business objects whose data requires persistent storage to a database');
|
|
17
21
|
|
|
18
22
|
// Instructions : to run command you must go to main project folder is located and run the command using the context file name.
|
|
@@ -31,9 +35,7 @@ program
|
|
|
31
35
|
var snap = {
|
|
32
36
|
file : contextInstance.fileLocation,
|
|
33
37
|
executedLocation : executedLocation,
|
|
34
|
-
context : new contextInstance.context(
|
|
35
|
-
root: executedLocation
|
|
36
|
-
}),
|
|
38
|
+
context : new contextInstance.context(),
|
|
37
39
|
contextFileName: contextFileName.toLowerCase()
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -73,14 +75,13 @@ program
|
|
|
73
75
|
});
|
|
74
76
|
|
|
75
77
|
program
|
|
76
|
-
.command('update-database <contextFileName>
|
|
78
|
+
.command('update-database <contextFileName>')
|
|
77
79
|
.alias('ud')
|
|
78
80
|
.description('Apply pending migrations to database')
|
|
79
|
-
.action(function(contextFileName
|
|
80
|
-
console.log("NODE_ENV", process.NODE_ENV)
|
|
81
|
+
.action(function(contextFileName){
|
|
81
82
|
var executedLocation = process.cwd();
|
|
82
83
|
contextFileName = contextFileName.toLowerCase();
|
|
83
|
-
|
|
84
|
+
var migration = new Migration();
|
|
84
85
|
try{
|
|
85
86
|
// find context file from main folder location
|
|
86
87
|
var search = `${executedLocation}/**/*${contextFileName}_contextSnapShot.json`;
|
|
@@ -88,24 +89,29 @@ program
|
|
|
88
89
|
var file = files[0];
|
|
89
90
|
var contextSnapshot = require(file);
|
|
90
91
|
|
|
91
|
-
var searchMigration =
|
|
92
|
+
var searchMigration = `${contextSnapshot.migrationFolder}/**/*_migration.js`;
|
|
92
93
|
var migrationFiles = globSearch.sync(searchMigration, contextSnapshot.migrationFolder);
|
|
93
94
|
if( migrationFiles){
|
|
94
95
|
// find newest migration file
|
|
95
96
|
var mFiles = migrationFiles.sort(function(x, y){
|
|
96
97
|
return new Date(x.timestamp) < new Date(y.timestamp) ? 1 : -1
|
|
97
98
|
});
|
|
98
|
-
|
|
99
|
-
var
|
|
99
|
+
|
|
100
|
+
var mFile = mFiles[0];
|
|
101
|
+
console.log("ontextSnapshot -------------",mFile);
|
|
102
|
+
var migrationFile = require(mFile);
|
|
100
103
|
var context = require(contextSnapshot.contextLocation);
|
|
101
104
|
var contextInstance = new context();
|
|
102
|
-
|
|
103
|
-
newMigrationInstance
|
|
105
|
+
|
|
106
|
+
var newMigrationInstance = new migrationFile(context);
|
|
107
|
+
|
|
108
|
+
var tableList = migration.callMigrationUp(contextSnapshot.schema, contextInstance.__entities);
|
|
109
|
+
//newMigrationInstance.up(tableList);
|
|
104
110
|
}
|
|
105
111
|
}catch (e){
|
|
106
112
|
console.log("Cannot read or find file ", e);
|
|
107
113
|
}
|
|
108
|
-
console.log("
|
|
114
|
+
console.log("databasedsdsd updated");
|
|
109
115
|
});
|
|
110
116
|
|
|
111
117
|
// we will find the migration folder inside the nearest app folder if no migration folder is location is added
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
class migrationSQLiteQuery {
|
|
4
|
+
|
|
5
|
+
addColum(table){
|
|
6
|
+
var buildDefinations = this.buildDefinations(table);
|
|
7
|
+
return `ALTER TABLE ${table.name}
|
|
8
|
+
ADD ${table.column} ${buildDefinations}`;
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
column definations
|
|
12
|
+
NULL
|
|
13
|
+
TEXT. The value is a text string, stored using the database encoding (UTF-8, UTF-16BE or UTF-16LE).
|
|
14
|
+
BLOB. The value is a blob of data, stored exactly as it was input
|
|
15
|
+
INTEGER,
|
|
16
|
+
real
|
|
17
|
+
*/
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
buildDefinations(definations){
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
createTable(){
|
|
25
|
+
`CREATE TABLE devices (
|
|
26
|
+
name TEXT NOT NULL,
|
|
27
|
+
model TEXT NOT NULL,
|
|
28
|
+
Serial INTEGER NOT NULL UNIQUE
|
|
29
|
+
);`
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
INTEGER PRIMARY KEY AUTOINCREMENT
|
|
33
|
+
all these are equal to interger
|
|
34
|
+
INT
|
|
35
|
+
INTEGER
|
|
36
|
+
TINYINT
|
|
37
|
+
SMALLINT
|
|
38
|
+
MEDIUMINT
|
|
39
|
+
BIGINT
|
|
40
|
+
UNSIGNED BIG INT
|
|
41
|
+
INT2
|
|
42
|
+
INT8
|
|
43
|
+
*/
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
dropTable(name){
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
dropIndex(){
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
//"dbo.People", "Location"
|
|
55
|
+
alterColumn(){
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
renameColumn(){
|
|
60
|
+
`ALTER TABLE existing_table
|
|
61
|
+
RENAME TO new_table;`
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
/*
|
|
69
|
+
ADDING NEW COLUMN SQLITE
|
|
70
|
+
There are some restrictions on the new column:
|
|
71
|
+
The new column cannot have a UNIQUE or PRIMARY KEY constraint.
|
|
72
|
+
If the new column has a NOT NULL constraint, you must specify a default value for the column other than a NULL value.
|
|
73
|
+
The new column cannot have a default of CURRENT_TIMESTAMP, CURRENT_DATE, and CURRENT_TIME, or an expression.
|
|
74
|
+
If the new column is a foreign key and the foreign key constraint check is enabled, the new column must accept a default value NULL.
|
|
75
|
+
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
/*
|
|
79
|
+
|
|
80
|
+
DROPING A COLUMN SQLITE
|
|
81
|
+
Possible reasons why the DROP COLUMN command can fail include:
|
|
82
|
+
|
|
83
|
+
The column is a PRIMARY KEY or part of one.
|
|
84
|
+
The column has a UNIQUE constraint.
|
|
85
|
+
The column is indexed.
|
|
86
|
+
The column is named in the WHERE clause of a partial index.
|
|
87
|
+
The column is named in a table or column CHECK constraint not associated with the column being dropped.
|
|
88
|
+
The column is used in a foreign key constraint.
|
|
89
|
+
The column is used in the expression of a generated column.
|
|
90
|
+
The column appears in a trigger or view.
|
|
91
|
+
|
|
92
|
+
*/
|
|
@@ -28,48 +28,48 @@ module.exports = ${this.name};
|
|
|
28
28
|
`
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
alterColumn(){
|
|
31
|
+
alterColumn(type, name){
|
|
32
32
|
if(type === "up"){
|
|
33
|
-
this.up += os.EOL + ` this.alterColumn(table
|
|
33
|
+
this.up += os.EOL + ` this.alterColumn(table.${name});`
|
|
34
34
|
}
|
|
35
35
|
else{
|
|
36
|
-
this.down += os.EOL + ` this.alterColumn(table
|
|
36
|
+
this.down += os.EOL + ` this.alterColumn(table.${name});`
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
createTable(){
|
|
39
|
+
createTable(type, name){
|
|
40
40
|
if(type === "up"){
|
|
41
|
-
this.up += os.EOL + ` this.createTable(table
|
|
41
|
+
this.up += os.EOL + ` this.createTable(table.${name});`
|
|
42
42
|
}
|
|
43
43
|
else{
|
|
44
|
-
this.down += os.EOL + ` this.createTable(table
|
|
44
|
+
this.down += os.EOL + ` this.createTable(table.${name});`
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
addColumn(type){
|
|
48
|
+
addColumn(type, name){
|
|
49
49
|
if(type === "up"){
|
|
50
|
-
this.up += os.EOL + ` this.addColumn(table
|
|
50
|
+
this.up += os.EOL + ` this.addColumn(table.${name});`
|
|
51
51
|
}
|
|
52
52
|
else{
|
|
53
|
-
this.down += os.EOL + ` this.addColumn(table
|
|
53
|
+
this.down += os.EOL + ` this.addColumn(table.${name});`
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
dropTable(type){
|
|
58
|
+
dropTable(type, name){
|
|
59
59
|
if(type === "up"){
|
|
60
|
-
this.down += os.EOL + ` this.droptable(table
|
|
60
|
+
this.down += os.EOL + ` this.droptable(table.${name});`
|
|
61
61
|
}
|
|
62
62
|
else{
|
|
63
|
-
this.down += os.EOL + ` this.droptable(table
|
|
63
|
+
this.down += os.EOL + ` this.droptable(table.${name});`
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
dropColumn(type){
|
|
67
|
+
dropColumn(type, name){
|
|
68
68
|
if(type === "up"){
|
|
69
|
-
this.up += os.EOL + ` this.dropColumn(table
|
|
69
|
+
this.up += os.EOL + ` this.dropColumn(table.${name});`
|
|
70
70
|
}
|
|
71
71
|
else{
|
|
72
|
-
this.down += os.EOL + ` this.dropColumn(table
|
|
72
|
+
this.down += os.EOL + ` this.dropColumn(table.${name});`
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
package/Migrations/migrations.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// version 0.0.
|
|
1
|
+
// version 0.0.4
|
|
2
2
|
// learn more about seeding info - https://www.pauric.blog/Database-Updates-and-Migrations-with-Entity-Framework/
|
|
3
3
|
|
|
4
4
|
var fs = require('fs');
|
|
@@ -29,9 +29,6 @@ class Migrations{
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
var content = {
|
|
32
|
-
seed : function(seed){
|
|
33
|
-
this.seed(this);
|
|
34
|
-
},
|
|
35
32
|
contextLocation: snap.file,
|
|
36
33
|
migrationFolder: `${snap.executedLocation}/db/migrations`,
|
|
37
34
|
snapShotLocation: `${snap.executedLocation}/db/migrations/${snap.contextFileName}_contextSnapShot.json`,
|
|
@@ -129,39 +126,76 @@ class Migrations{
|
|
|
129
126
|
return tables;
|
|
130
127
|
}
|
|
131
128
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
var MT = new MigrationTemplate(name);
|
|
129
|
+
// build table to build new migration snapshot
|
|
130
|
+
buildMigrationObject(oldSchema, newSchema){
|
|
136
131
|
var tables = this.organizeSchemaByTables(oldSchema, newSchema);
|
|
137
132
|
tables = this.findNewColumnsInTables(tables);
|
|
138
133
|
tables = this.findDeletedColumnsInTables(tables);
|
|
139
134
|
tables = this.findUpdatedColumns(tables);
|
|
135
|
+
return tables;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
//
|
|
139
|
+
callMigrationUp(oldSchema, newSchema){
|
|
140
|
+
var tableArray =[];
|
|
141
|
+
var tables = this.buildMigrationObject(oldSchema, newSchema);
|
|
142
|
+
tables.forEach(function (item, index) {
|
|
143
|
+
|
|
144
|
+
// add new columns for table
|
|
145
|
+
item.newColumns.forEach(function (column, index) {
|
|
146
|
+
tableArray.push(tables[column]);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
item.deletedColumns.forEach(function (column, index) {
|
|
150
|
+
tableArray.push(tables[column]);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
item.updatedColumns.forEach(function (column, index) {
|
|
154
|
+
tableArray.push(tables[column]);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if(item.old === null){
|
|
158
|
+
tableArray.push(tables[column]);
|
|
159
|
+
|
|
160
|
+
}
|
|
161
|
+
if(item.new === null){
|
|
162
|
+
tableArray.push(tables[column]);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
return tableArray;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
buildMigrationTemplate(name, oldSchema, newSchema){
|
|
171
|
+
|
|
172
|
+
var MT = new MigrationTemplate(name);
|
|
173
|
+
var tables = this.buildMigrationObject(oldSchema, newSchema);
|
|
140
174
|
tables.forEach(function (item, index) {
|
|
141
175
|
// add new columns for table
|
|
142
176
|
item.newColumns.forEach(function (column, index) {
|
|
143
|
-
MT.addColumn();
|
|
144
|
-
MT.dropColumn("down");
|
|
177
|
+
MT.addColumn("up", column);
|
|
178
|
+
MT.dropColumn("down", column);
|
|
145
179
|
});
|
|
146
180
|
|
|
147
181
|
item.deletedColumns.forEach(function (column, index) {
|
|
148
|
-
MT.dropColumn("up");
|
|
149
|
-
MT.addColumn("down");
|
|
182
|
+
MT.dropColumn("up", column);
|
|
183
|
+
MT.addColumn("down",column);
|
|
150
184
|
});
|
|
151
185
|
|
|
152
186
|
item.updatedColumns.forEach(function (column, index) {
|
|
153
|
-
MT.alterColumn();
|
|
154
|
-
MT.alterColumn("down")
|
|
187
|
+
MT.alterColumn("up", column);
|
|
188
|
+
MT.alterColumn("down", column)
|
|
155
189
|
});
|
|
156
190
|
|
|
157
191
|
if(item.old === null){
|
|
158
|
-
MT.createTable();
|
|
159
|
-
MT.dropTable("down");
|
|
192
|
+
MT.createTable("up", column);
|
|
193
|
+
MT.dropTable("down", column);
|
|
160
194
|
|
|
161
195
|
}
|
|
162
196
|
if(item.new === null){
|
|
163
|
-
MT.dropTable("up");
|
|
164
|
-
MT.createTable("down");
|
|
197
|
+
MT.dropTable("up", column);
|
|
198
|
+
MT.createTable("down", column);
|
|
165
199
|
}
|
|
166
200
|
|
|
167
201
|
});
|
package/Migrations/schema.js
CHANGED
|
@@ -1,15 +1,41 @@
|
|
|
1
1
|
// version 1
|
|
2
2
|
var fs = require('fs');
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
var table = {
|
|
5
|
+
email : {
|
|
6
|
+
name: "auth",
|
|
7
|
+
column : "email",
|
|
8
|
+
rules: {
|
|
9
|
+
"type": "integer",
|
|
10
|
+
"primary": true,
|
|
11
|
+
"nullable": false,
|
|
12
|
+
"unique": true,
|
|
13
|
+
"auto": true,
|
|
14
|
+
"cascadeOnDelete": true,
|
|
15
|
+
"lazyLoading": true,
|
|
16
|
+
"isNavigational": false
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class schema{
|
|
24
|
+
// TODO : check what database we are using
|
|
25
|
+
// based on the database you can make the call to update the database.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
constructor(context){
|
|
29
|
+
this.context = context;
|
|
8
30
|
}
|
|
9
31
|
|
|
10
32
|
// create obj to convert into create sql
|
|
11
|
-
addColumn(
|
|
12
|
-
|
|
33
|
+
addColumn(table){
|
|
34
|
+
if(this.context.isSQite){
|
|
35
|
+
var sqliteQuery = require("./migrationSQLiteQuery");
|
|
36
|
+
var query = sqliteQuery.addColumn(table);
|
|
37
|
+
this.context.db.prepare(query).all();
|
|
38
|
+
}
|
|
13
39
|
// add column to database
|
|
14
40
|
}
|
|
15
41
|
|
|
@@ -61,4 +87,4 @@ class Schema{
|
|
|
61
87
|
|
|
62
88
|
*/
|
|
63
89
|
|
|
64
|
-
module.exports =
|
|
90
|
+
module.exports = schema;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
class temp {
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
hatml =
|
|
5
|
+
buildMOdal(className, header, body){
|
|
6
|
+
|
|
7
|
+
`
|
|
8
|
+
Copy
|
|
9
|
+
<div class="modal" tabindex="-1" role="dialog" ${className}>
|
|
10
|
+
<div class="modal-dialog" role="document">
|
|
11
|
+
<div class="modal-content">
|
|
12
|
+
<div class="modal-header">
|
|
13
|
+
${ buildheader(header)}
|
|
14
|
+
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
15
|
+
<span aria-hidden="true">×</span>
|
|
16
|
+
</button>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="modal-body">
|
|
19
|
+
${body}
|
|
20
|
+
</div>
|
|
21
|
+
<div class="modal-footer">
|
|
22
|
+
<button type="button" class="btn btn-primary">Save changes</button>
|
|
23
|
+
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>`
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
buildheader(title){
|
|
32
|
+
return ` <h5 class="modal-title">${title}</h5>`
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// ALL THIS SHOULD DO IS BUILD A SQL QUERY
|
|
2
2
|
// version 1.0.222
|
|
3
3
|
// TODO: change name of queryManager to select manager;
|
|
4
|
-
var entityTrackerModel = require('masterrecord/Entity/
|
|
4
|
+
var entityTrackerModel = require('masterrecord/Entity/entityTrackerModel');
|
|
5
5
|
var tools = require('masterrecord/Tools');
|
|
6
6
|
var queryScript = require('masterrecord/QueryLanguage/queryScript');
|
|
7
7
|
|
package/context.js
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
|
|
2
|
+
var modelBuilder = require('./Entity/EntityModelBuilder');
|
|
3
|
+
var query = require('masterrecord/QueryLanguage/queryMethods');
|
|
4
|
+
var tools = require('./Tools');
|
|
5
|
+
var SQLLiteEngine = require('masterrecord/SQLLiteEngine');
|
|
6
|
+
var MYSQLEngine = require('masterrecord/MYSQLEngine');
|
|
7
|
+
var insertManager = require('./InsertManager');
|
|
8
|
+
var deleteManager = require('./DeleteManager');
|
|
9
|
+
var globSearch = require("glob");
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Context {
|
|
13
|
+
_isModelValid = {
|
|
14
|
+
isValid: true,
|
|
15
|
+
errors: []
|
|
16
|
+
};
|
|
17
|
+
__entities = [];
|
|
18
|
+
__builderEntities = [];
|
|
19
|
+
__trackedEntities = [];
|
|
20
|
+
__relationshipModels = [];
|
|
21
|
+
__enviornment = "";
|
|
22
|
+
__name = "";
|
|
23
|
+
isSQite = false;
|
|
24
|
+
isMySQL = false;
|
|
25
|
+
|
|
26
|
+
constructor(){
|
|
27
|
+
this. __enviornment = process.env.master;
|
|
28
|
+
this.__name = this.constructor.name;
|
|
29
|
+
this._SQLEngine = "";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
SQLite expected model
|
|
34
|
+
{
|
|
35
|
+
"type": "better-sqlite3",
|
|
36
|
+
"connection" : "/db/",
|
|
37
|
+
"password": "",
|
|
38
|
+
"username": ""
|
|
39
|
+
}
|
|
40
|
+
*/
|
|
41
|
+
__SQLiteInit(env, sqlName){
|
|
42
|
+
try{
|
|
43
|
+
const sqlite3 = require(sqlName);
|
|
44
|
+
let DBAddress = env.completeConnection;
|
|
45
|
+
var db = new sqlite3(DBAddress, env);
|
|
46
|
+
db.__name = sqlName;
|
|
47
|
+
this._SQLEngine = new SQLLiteEngine();
|
|
48
|
+
return db;
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
console.log("error SQL", e);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/*
|
|
56
|
+
mysql expected model
|
|
57
|
+
{
|
|
58
|
+
"type": "mysql",
|
|
59
|
+
host : 'localhost',
|
|
60
|
+
user : 'me',
|
|
61
|
+
password : 'secret',
|
|
62
|
+
database : 'my_db'
|
|
63
|
+
}
|
|
64
|
+
*/
|
|
65
|
+
__mysqlInit(env, sqlName){
|
|
66
|
+
try{
|
|
67
|
+
const mysql = require(sqlName);
|
|
68
|
+
const connection = mysql.createConnection(env);
|
|
69
|
+
connection.connect();
|
|
70
|
+
db.__name = sqlName;
|
|
71
|
+
this._SQLEngine = new MYSQLEngine();
|
|
72
|
+
return connection;
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
console.log("error SQL", e);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
__clearErrorHandler(){
|
|
83
|
+
this._isModelValid = {
|
|
84
|
+
isValid: true,
|
|
85
|
+
errors: []
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
__findSettings(root, rootFolderLocation, envType){
|
|
90
|
+
|
|
91
|
+
var rootFolder = `${root}/${rootFolderLocation}`;
|
|
92
|
+
var search = `${rootFolder}/**/*env.${envType}.json`;
|
|
93
|
+
var files = globSearch.sync(search, rootFolder);
|
|
94
|
+
var file = files[0];
|
|
95
|
+
if(file === undefined){
|
|
96
|
+
root = tools.removeBackwardSlashSection(root, 1, "/");
|
|
97
|
+
rootFolder = `${root}/${rootFolderLocation}`;
|
|
98
|
+
var search = `${rootFolder}/**/*env.${envType}.json`;
|
|
99
|
+
var files = globSearch.sync(search,rootFolder);
|
|
100
|
+
file = files[0];
|
|
101
|
+
if(file === undefined){
|
|
102
|
+
root = tools.removeBackwardSlashSection(root, 1, "/");
|
|
103
|
+
rootFolder = `${root}/${rootFolderLocation}`;
|
|
104
|
+
var search = `${rootFolder}/**/*env.${envType}.json`;
|
|
105
|
+
var files = globSearch.sync(search,rootFolder);
|
|
106
|
+
file = files[0];
|
|
107
|
+
if(file === undefined){
|
|
108
|
+
console.log(`could not find file - ${rootFolder}/env.${envType}.json`);
|
|
109
|
+
throw error(`could not find file - ${rootFolder}/env.${envType}.json`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
file: file,
|
|
118
|
+
rootFolder : root
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
useSqlite(rootFolderLocation){
|
|
123
|
+
this.isSQite = true;
|
|
124
|
+
var root = process.cwd();
|
|
125
|
+
var envType = this.__enviornment;
|
|
126
|
+
var contextName = this.__name;
|
|
127
|
+
var file = this.__findSettings(root, rootFolderLocation, envType);
|
|
128
|
+
var settings = require(file.file);
|
|
129
|
+
var options = settings[contextName];
|
|
130
|
+
if(options === undefined){
|
|
131
|
+
console.log("settings missing context name settings");
|
|
132
|
+
throw error("settings missing context name settings");
|
|
133
|
+
}
|
|
134
|
+
this.validateSQLiteOptions(options);
|
|
135
|
+
options.completeConnection = `${file.rootFolder}${options.connection}`;
|
|
136
|
+
this.db = this.__SQLiteInit(options, "better-sqlite3");
|
|
137
|
+
this._SQLEngine.setDB(this.db, "better-sqlite3");
|
|
138
|
+
return this;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
validateSQLiteOptions(options){
|
|
142
|
+
if(options.hasOwnProperty('connect') === undefined){
|
|
143
|
+
console.log("connnect string settings is missing")
|
|
144
|
+
throw error("connection string settings is missing");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
useMySql(options, rootFolderLocation){
|
|
150
|
+
if(options !== undefined){
|
|
151
|
+
this.db = this.__mysqlInit(options, "mysql");
|
|
152
|
+
this._SQLEngine.setDB(this.db, "mysql");
|
|
153
|
+
return this;
|
|
154
|
+
}
|
|
155
|
+
else{
|
|
156
|
+
console.log("database options not defined - Master Record");
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
dbset(model, name){
|
|
162
|
+
var validModel = modelBuilder.create(model);
|
|
163
|
+
validModel.__name = name === undefined ? model.name : name;
|
|
164
|
+
this.__entities.push(validModel); // model object
|
|
165
|
+
var buildMod = tools.createNewInstance(validModel, query, this);
|
|
166
|
+
this.__builderEntities.push(buildMod); // query builder entites
|
|
167
|
+
this[validModel.__name] = buildMod;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
modelState(){
|
|
171
|
+
return this._isModelValid;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
saveChanges(){
|
|
175
|
+
try{
|
|
176
|
+
var tracked = this.__trackedEntities;
|
|
177
|
+
// start transaction
|
|
178
|
+
this._SQLEngine.startTransaction();
|
|
179
|
+
for (var model in tracked) {
|
|
180
|
+
var currentModel = tracked[model];
|
|
181
|
+
switch(currentModel.__state) {
|
|
182
|
+
case "insert":
|
|
183
|
+
var insert = new insertManager(this._SQLEngine, this._isModelValid, this.__entities);
|
|
184
|
+
insert.init(currentModel);
|
|
185
|
+
|
|
186
|
+
break;
|
|
187
|
+
case "modified":
|
|
188
|
+
if(currentModel.__dirtyFields.length > 0){
|
|
189
|
+
var cleanCurrentModel = tools.removePrimarykeyandVirtual(currentModel, currentModel._entity);
|
|
190
|
+
// build columns equal to value string
|
|
191
|
+
var argu = this._SQLEngine._buildSQLEqualTo(cleanCurrentModel);
|
|
192
|
+
var primaryKey = tools.getPrimaryKeyObject(cleanCurrentModel.__entity);
|
|
193
|
+
var sqlUpdate = {tableName: cleanCurrentModel.__entity.__name, arg: argu, primaryKey : primaryKey, primaryKeyValue : cleanCurrentModel[primaryKey] };
|
|
194
|
+
this._SQLEngine.update(sqlUpdate);
|
|
195
|
+
}
|
|
196
|
+
else{
|
|
197
|
+
console.log("Tracked entity modified with no values being changed");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// code block
|
|
201
|
+
break;
|
|
202
|
+
case "delete":
|
|
203
|
+
var deleteObject = new deleteManager(this._SQLEngine, this.__entities);
|
|
204
|
+
deleteObject.init(currentModel);
|
|
205
|
+
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
this.__clearErrorHandler();
|
|
210
|
+
this._SQLEngine.endTransaction();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
catch(error){
|
|
214
|
+
this.__clearErrorHandler();
|
|
215
|
+
this._SQLEngine.errorTransaction();
|
|
216
|
+
console.log("error", error);
|
|
217
|
+
this.__clearTracked();
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.__clearTracked();
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// TODO: WHY WE HAVE DOUBLE TRACKED OBJECTS - LOOP THROUGH ALL TRACKED OBJECTS
|
|
226
|
+
__track(model){
|
|
227
|
+
this.__trackedEntities.push(model);
|
|
228
|
+
return model;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
__findTracked(id){
|
|
232
|
+
if(id){
|
|
233
|
+
for (var model in this.__trackedEntities) {
|
|
234
|
+
if(this.__trackedEntities[model].__ID === id){
|
|
235
|
+
return this.__trackedEntities[model];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
__clearTracked(){
|
|
243
|
+
this.__trackedEntities = [];
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
module.exports = Context;
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"glob" : "^8.0.3",
|
|
7
7
|
"deep-object-diff" : "^1.1.7"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.0.
|
|
9
|
+
"version": "0.0.31",
|
|
10
10
|
"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 ",
|
|
11
11
|
"homepage": "https://github.com/Tailor/MasterRecord#readme",
|
|
12
12
|
"repository": {
|