masterrecord 0.2.1 → 0.2.3
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 +12 -2
- package/package.json +2 -2
- package/readme.md +181 -2
- package/MIGRATIONS.md +0 -178
package/Migrations/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ let fs = require('fs');
|
|
|
9
9
|
let path = require('path');
|
|
10
10
|
var Migration = require('./migrations');
|
|
11
11
|
var globSearch = require("glob");
|
|
12
|
+
const pkg = require(path.join(__dirname, '..', 'package.json'));
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
const [,, ...args] = process.argv
|
|
@@ -16,9 +17,12 @@ const [,, ...args] = process.argv
|
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
program
|
|
19
|
-
.version(
|
|
20
|
+
.version(pkg.version, '-v, --version')
|
|
20
21
|
.description('A ORM framework that facilitates the creation and use of business objects whose data requires persistent storage to a database');
|
|
21
22
|
|
|
23
|
+
// Support legacy '-V' as an alias to print version
|
|
24
|
+
program.option('-V', 'output the version');
|
|
25
|
+
|
|
22
26
|
// Instructions : to run command you must go to main project folder is located and run the command using the context file name.
|
|
23
27
|
program
|
|
24
28
|
.command('enable-migrations <contextFileName>')
|
|
@@ -275,4 +279,10 @@ program
|
|
|
275
279
|
|
|
276
280
|
|
|
277
281
|
|
|
278
|
-
program.parse(process.argv);
|
|
282
|
+
program.parse(process.argv);
|
|
283
|
+
|
|
284
|
+
// Handle manual '-V' alias
|
|
285
|
+
const opts = program.opts();
|
|
286
|
+
if (opts && opts.V) {
|
|
287
|
+
console.log(pkg.version);
|
|
288
|
+
}
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"sync-mysql2" : "^1.0.6",
|
|
9
9
|
"app-root-path": "^3.1.0"
|
|
10
10
|
},
|
|
11
|
-
"version": "0.2.
|
|
11
|
+
"version": "0.2.3",
|
|
12
12
|
"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 ",
|
|
13
13
|
"homepage": "https://github.com/Tailor/MasterRecord#readme",
|
|
14
14
|
"repository": {
|
|
@@ -22,6 +22,6 @@
|
|
|
22
22
|
"author": "Alexander Rich",
|
|
23
23
|
"license": "ISC",
|
|
24
24
|
"bin": {
|
|
25
|
-
"masterrecord": "./
|
|
25
|
+
"masterrecord": "./Migrations/cli.js"
|
|
26
26
|
}
|
|
27
27
|
}
|
package/readme.md
CHANGED
|
@@ -1,3 +1,182 @@
|
|
|
1
|
-
local install of CLI package run code in terminal - "npm install -g ./" master
|
|
2
1
|
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
# MasterRecord
|
|
4
|
+
|
|
5
|
+
MasterRecord is a lightweight, code-first ORM and migration tool for Node.js with a fluent query API. It lets you define entities in JavaScript, generate migrations, and query with expressive syntax.
|
|
6
|
+
|
|
7
|
+
- Supported databases: MySQL, SQLite
|
|
8
|
+
- Synchronous API by default (no await needed)
|
|
9
|
+
- Built-in CLI for migrations and seeding
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# npm
|
|
15
|
+
npm install masterrecord
|
|
16
|
+
|
|
17
|
+
# pnpm
|
|
18
|
+
pnpm add masterrecord
|
|
19
|
+
|
|
20
|
+
# yarn
|
|
21
|
+
yarn add masterrecord
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
1) Create an environment config file (see Environment below), then enable migrations:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx masterrecord enable-migrations AppContext
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
2) Make or change your entities, then create a migration file:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx masterrecord add-migration Init AppContext
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
3) Apply the migration to your database:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
master=development npx masterrecord update-database AppContext
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Enable migrations (one-time per Context)
|
|
45
|
+
|
|
46
|
+
- Run from the project root where your Context file lives. Use the Context file name (without extension) as the argument.
|
|
47
|
+
```bash
|
|
48
|
+
master=development masterrecord enable-migrations AppContext
|
|
49
|
+
```
|
|
50
|
+
This creates `db/migrations/<context>_contextSnapShot.json` and the `db/migrations` directory.
|
|
51
|
+
|
|
52
|
+
### Create a migration
|
|
53
|
+
|
|
54
|
+
- After you change your entity models, generate a migration file:
|
|
55
|
+
```bash
|
|
56
|
+
master=development masterrecord add-migration <MigrationName> AppContext
|
|
57
|
+
```
|
|
58
|
+
This writes a new file to `db/migrations/<timestamp>_<MigrationName>_migration.js`.
|
|
59
|
+
|
|
60
|
+
### Apply migrations to the database
|
|
61
|
+
|
|
62
|
+
- Apply only the latest pending migration:
|
|
63
|
+
```bash
|
|
64
|
+
master=development masterrecord update-database AppContext
|
|
65
|
+
```
|
|
66
|
+
- Apply all migrations from the beginning (useful for a clean DB):
|
|
67
|
+
```bash
|
|
68
|
+
master=development masterrecord update-database-restart AppContext
|
|
69
|
+
```
|
|
70
|
+
- List migration files (debug/inspection):
|
|
71
|
+
```bash
|
|
72
|
+
master=development masterrecord get-migrations AppContext
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Notes:
|
|
76
|
+
- The CLI searches for `<context>_contextSnapShot.json` under `db/migrations` relative to your current working directory.
|
|
77
|
+
- For MySQL, ensure your credentials allow DDL. For SQLite, the data directory is created if missing.
|
|
78
|
+
|
|
79
|
+
### Updating the running server
|
|
80
|
+
|
|
81
|
+
General flow to roll out schema changes:
|
|
82
|
+
- Stop the server or put it into maintenance mode (optional but recommended for non-backward-compatible changes).
|
|
83
|
+
- Pull the latest code (containing updated models and generated migration files).
|
|
84
|
+
- Run migrations against the target environment:
|
|
85
|
+
```bash
|
|
86
|
+
master=production masterrecord update-database AppContext
|
|
87
|
+
```
|
|
88
|
+
- Restart your server/process manager (e.g., `pm2 restart <app>`, `docker compose up -d`, or your platform’s restart command).
|
|
89
|
+
|
|
90
|
+
Backward-compatible rollout tip:
|
|
91
|
+
- If possible, deploy additive changes first (new tables/columns), release app code that begins using them, then later clean up/removal migrations.
|
|
92
|
+
|
|
93
|
+
### Troubleshooting
|
|
94
|
+
|
|
95
|
+
- Cannot find Context file: ensure you run commands from the app root and pass the correct Context file name used when defining your class (case-insensitive in the snapshot, but supply the same name you used).
|
|
96
|
+
- Cannot connect to DB: confirm `master=<env>` is set and `env.<env>.json` exists with correct credentials and paths.
|
|
97
|
+
- MySQL type mismatches: the migration engine maps MasterRecord types to SQL types; verify your entity field `type` values are correct.
|
|
98
|
+
|
|
99
|
+
### Recent improvements (2025-09)
|
|
100
|
+
|
|
101
|
+
- Query language and SQL engines:
|
|
102
|
+
- Correct parsing of multi-char operators (>=, <=, ===, !==) and spaced logical operators.
|
|
103
|
+
- Support for grouped OR conditions rendered as parenthesized OR in WHERE across SQLite/MySQL.
|
|
104
|
+
- Resilient fallback for partially parsed expressions.
|
|
105
|
+
- Relationships:
|
|
106
|
+
- `hasManyThrough` supported in insert and delete cascades.
|
|
107
|
+
- Environment file discovery:
|
|
108
|
+
- Context now walks up directories to find `config/environments/env.<env>.json`; fixed error throwing.
|
|
109
|
+
- Migrations (DDL generation):
|
|
110
|
+
- Default values emitted for SQLite/MySQL (including boolean coercion).
|
|
111
|
+
- `CREATE TABLE IF NOT EXISTS` to avoid failures when rerunning.
|
|
112
|
+
- Table introspection added; existing tables are synced: missing columns are added, MySQL applies `ALTER ... MODIFY` for NULL/DEFAULT changes, SQLite rebuilds table when necessary.
|
|
113
|
+
- Migration API additions in `schema.js`:
|
|
114
|
+
- `renameColumn(table)` implemented for SQLite/MySQL.
|
|
115
|
+
- `seed(tableName, rows)` implemented for bulk/single inserts with safe quoting.
|
|
116
|
+
|
|
117
|
+
### Using renameColumn and seed in migrations
|
|
118
|
+
|
|
119
|
+
Basic migration skeleton (generated by CLI):
|
|
120
|
+
```js
|
|
121
|
+
var masterrecord = require('masterrecord');
|
|
122
|
+
|
|
123
|
+
class AddSettings extends masterrecord.schema {
|
|
124
|
+
constructor(context){ super(context); }
|
|
125
|
+
|
|
126
|
+
up(table){
|
|
127
|
+
this.init(table);
|
|
128
|
+
// Add a new table
|
|
129
|
+
this.createTable(table.MailSettings);
|
|
130
|
+
|
|
131
|
+
// Rename a column on an existing table
|
|
132
|
+
this.renameColumn({ tableName: 'MailSettings', name: 'from_email', newName: 'reply_to' });
|
|
133
|
+
|
|
134
|
+
// Seed initial data (single row)
|
|
135
|
+
this.seed('MailSettings', {
|
|
136
|
+
from_name: 'System',
|
|
137
|
+
reply_to: 'no-reply@example.com',
|
|
138
|
+
return_path_matches_from: 0,
|
|
139
|
+
weekly_summary_enabled: 0,
|
|
140
|
+
created_at: Date.now(),
|
|
141
|
+
updated_at: Date.now()
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Seed multiple rows
|
|
145
|
+
this.seed('MailSettings', [
|
|
146
|
+
{ from_name: 'Support', reply_to: 'support@example.com', created_at: Date.now(), updated_at: Date.now() },
|
|
147
|
+
{ from_name: 'Marketing', reply_to: 'marketing@example.com', created_at: Date.now(), updated_at: Date.now() }
|
|
148
|
+
]);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
down(table){
|
|
152
|
+
this.init(table);
|
|
153
|
+
// Revert the rename
|
|
154
|
+
this.renameColumn({ tableName: 'MailSettings', name: 'reply_to', newName: 'from_email' });
|
|
155
|
+
|
|
156
|
+
// Optionally clean up seeded rows
|
|
157
|
+
// this.context._execute("DELETE FROM MailSettings WHERE reply_to IN ('no-reply@example.com','support@example.com','marketing@example.com')");
|
|
158
|
+
|
|
159
|
+
// Drop table if that was part of up
|
|
160
|
+
// this.dropTable(table.MailSettings);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
module.exports = AddSettings;
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Notes:
|
|
167
|
+
- `renameColumn` expects an object: `{ tableName, name, newName }` and works in both SQLite and MySQL.
|
|
168
|
+
- `seed(tableName, rows)` accepts:
|
|
169
|
+
- a single object: `{ col: value, ... }`
|
|
170
|
+
- or an array of objects: `[{...}, {...}]`
|
|
171
|
+
Values are auto-quoted; booleans become 1/0.
|
|
172
|
+
- When a table already exists, `update-database` will sync schema:
|
|
173
|
+
- Add missing columns.
|
|
174
|
+
- MySQL: adjust default/nullability via `ALTER ... MODIFY`.
|
|
175
|
+
- SQLite: rebuilds the table when nullability/default/type changes require it.
|
|
176
|
+
|
|
177
|
+
### Tips
|
|
178
|
+
- Prefer additive changes (add columns) before destructive changes (drops/renames) to minimize downtime.
|
|
179
|
+
- For large SQLite tables, a rebuild copies data; consider maintenance windows.
|
|
180
|
+
- Use `master=development masterrecord get-migrations AppContext` to inspect migration order.
|
|
181
|
+
|
|
182
|
+
|
package/MIGRATIONS.md
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
### Migrations and Server Update Guide
|
|
2
|
-
|
|
3
|
-
This project ships a CLI, exposed as `masterrecord`, to manage database migrations. Below are the steps to enable migrations, create migrations, apply them, and update your running server.
|
|
4
|
-
|
|
5
|
-
### 1) Install the CLI (local repo checkout)
|
|
6
|
-
|
|
7
|
-
- From the project root, install the CLI globally:
|
|
8
|
-
```bash
|
|
9
|
-
npm install -g ./
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
After install, the `masterrecord` command becomes available in your shell.
|
|
13
|
-
|
|
14
|
-
### 2) Prepare your Context and Environment
|
|
15
|
-
|
|
16
|
-
- Ensure your app has a Context class that extends `context` and configures a DB connection (SQLite or MySQL) using either `useSqlite()` or `useMySql()`.
|
|
17
|
-
- Set the environment via the `master` env var when running commands, e.g. `master=development` or `master=production`.
|
|
18
|
-
- Provide environment JSON at `env.<ENV>.json` reachable from your app root, keyed by your Context class name. Example for SQLite:
|
|
19
|
-
```json
|
|
20
|
-
{
|
|
21
|
-
"AppContext": {
|
|
22
|
-
"type": "better-sqlite3",
|
|
23
|
-
"connection": "/db/app.sqlite"
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
Example for MySQL:
|
|
28
|
-
```json
|
|
29
|
-
{
|
|
30
|
-
"AppContext": {
|
|
31
|
-
"type": "mysql",
|
|
32
|
-
"host": "localhost",
|
|
33
|
-
"user": "root",
|
|
34
|
-
"password": "secret",
|
|
35
|
-
"database": "app_db"
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### 3) Enable migrations (one-time per Context)
|
|
41
|
-
|
|
42
|
-
- Run from the project root where your Context file lives. Use the Context file name (without extension) as the argument.
|
|
43
|
-
```bash
|
|
44
|
-
master=development masterrecord enable-migrations AppContext
|
|
45
|
-
```
|
|
46
|
-
This creates `db/migrations/<context>_contextSnapShot.json` and the `db/migrations` directory.
|
|
47
|
-
|
|
48
|
-
### 4) Create a migration
|
|
49
|
-
|
|
50
|
-
- After you change your entity models, generate a migration file:
|
|
51
|
-
```bash
|
|
52
|
-
master=development masterrecord add-migration <MigrationName> AppContext
|
|
53
|
-
```
|
|
54
|
-
This writes a new file to `db/migrations/<timestamp>_<MigrationName>_migration.js`.
|
|
55
|
-
|
|
56
|
-
### 5) Apply migrations to the database
|
|
57
|
-
|
|
58
|
-
- Apply only the latest pending migration:
|
|
59
|
-
```bash
|
|
60
|
-
master=development masterrecord update-database AppContext
|
|
61
|
-
```
|
|
62
|
-
- Apply all migrations from the beginning (useful for a clean DB):
|
|
63
|
-
```bash
|
|
64
|
-
master=development masterrecord update-database-restart AppContext
|
|
65
|
-
```
|
|
66
|
-
- List migration files (debug/inspection):
|
|
67
|
-
```bash
|
|
68
|
-
master=development masterrecord get-migrations AppContext
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Notes:
|
|
72
|
-
- The CLI searches for `<context>_contextSnapShot.json` under `db/migrations` relative to your current working directory.
|
|
73
|
-
- For MySQL, ensure your credentials allow DDL. For SQLite, the data directory is created if missing.
|
|
74
|
-
|
|
75
|
-
### 6) Updating the running server
|
|
76
|
-
|
|
77
|
-
General flow to roll out schema changes:
|
|
78
|
-
- Stop the server or put it into maintenance mode (optional but recommended for non-backward-compatible changes).
|
|
79
|
-
- Pull the latest code (containing updated models and generated migration files).
|
|
80
|
-
- Run migrations against the target environment:
|
|
81
|
-
```bash
|
|
82
|
-
master=production masterrecord update-database AppContext
|
|
83
|
-
```
|
|
84
|
-
- Restart your server/process manager (e.g., `pm2 restart <app>`, `docker compose up -d`, or your platform’s restart command).
|
|
85
|
-
|
|
86
|
-
Backward-compatible rollout tip:
|
|
87
|
-
- If possible, deploy additive changes first (new tables/columns), release app code that begins using them, then later clean up/removal migrations.
|
|
88
|
-
|
|
89
|
-
### Troubleshooting
|
|
90
|
-
|
|
91
|
-
- Cannot find Context file: ensure you run commands from the app root and pass the correct Context file name used when defining your class (case-insensitive in the snapshot, but supply the same name you used).
|
|
92
|
-
- Cannot connect to DB: confirm `master=<env>` is set and `env.<env>.json` exists with correct credentials and paths.
|
|
93
|
-
- MySQL type mismatches: the migration engine maps MasterRecord types to SQL types; verify your entity field `type` values are correct.
|
|
94
|
-
|
|
95
|
-
### Recent improvements (2025-09)
|
|
96
|
-
|
|
97
|
-
- Query language and SQL engines:
|
|
98
|
-
- Correct parsing of multi-char operators (>=, <=, ===, !==) and spaced logical operators.
|
|
99
|
-
- Support for grouped OR conditions rendered as parenthesized OR in WHERE across SQLite/MySQL.
|
|
100
|
-
- Resilient fallback for partially parsed expressions.
|
|
101
|
-
- Relationships:
|
|
102
|
-
- `hasManyThrough` supported in insert and delete cascades.
|
|
103
|
-
- Environment file discovery:
|
|
104
|
-
- Context now walks up directories to find `config/environments/env.<env>.json`; fixed error throwing.
|
|
105
|
-
- Migrations (DDL generation):
|
|
106
|
-
- Default values emitted for SQLite/MySQL (including boolean coercion).
|
|
107
|
-
- `CREATE TABLE IF NOT EXISTS` to avoid failures when rerunning.
|
|
108
|
-
- Table introspection added; existing tables are synced: missing columns are added, MySQL applies `ALTER ... MODIFY` for NULL/DEFAULT changes, SQLite rebuilds table when necessary.
|
|
109
|
-
- Migration API additions in `schema.js`:
|
|
110
|
-
- `renameColumn(table)` implemented for SQLite/MySQL.
|
|
111
|
-
- `seed(tableName, rows)` implemented for bulk/single inserts with safe quoting.
|
|
112
|
-
|
|
113
|
-
### Using renameColumn and seed in migrations
|
|
114
|
-
|
|
115
|
-
Basic migration skeleton (generated by CLI):
|
|
116
|
-
```js
|
|
117
|
-
var masterrecord = require('masterrecord');
|
|
118
|
-
|
|
119
|
-
class AddSettings extends masterrecord.schema {
|
|
120
|
-
constructor(context){ super(context); }
|
|
121
|
-
|
|
122
|
-
up(table){
|
|
123
|
-
this.init(table);
|
|
124
|
-
// Add a new table
|
|
125
|
-
this.createTable(table.MailSettings);
|
|
126
|
-
|
|
127
|
-
// Rename a column on an existing table
|
|
128
|
-
this.renameColumn({ tableName: 'MailSettings', name: 'from_email', newName: 'reply_to' });
|
|
129
|
-
|
|
130
|
-
// Seed initial data (single row)
|
|
131
|
-
this.seed('MailSettings', {
|
|
132
|
-
from_name: 'System',
|
|
133
|
-
reply_to: 'no-reply@example.com',
|
|
134
|
-
return_path_matches_from: 0,
|
|
135
|
-
weekly_summary_enabled: 0,
|
|
136
|
-
created_at: Date.now(),
|
|
137
|
-
updated_at: Date.now()
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// Seed multiple rows
|
|
141
|
-
this.seed('MailSettings', [
|
|
142
|
-
{ from_name: 'Support', reply_to: 'support@example.com', created_at: Date.now(), updated_at: Date.now() },
|
|
143
|
-
{ from_name: 'Marketing', reply_to: 'marketing@example.com', created_at: Date.now(), updated_at: Date.now() }
|
|
144
|
-
]);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
down(table){
|
|
148
|
-
this.init(table);
|
|
149
|
-
// Revert the rename
|
|
150
|
-
this.renameColumn({ tableName: 'MailSettings', name: 'reply_to', newName: 'from_email' });
|
|
151
|
-
|
|
152
|
-
// Optionally clean up seeded rows
|
|
153
|
-
// this.context._execute("DELETE FROM MailSettings WHERE reply_to IN ('no-reply@example.com','support@example.com','marketing@example.com')");
|
|
154
|
-
|
|
155
|
-
// Drop table if that was part of up
|
|
156
|
-
// this.dropTable(table.MailSettings);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
module.exports = AddSettings;
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
Notes:
|
|
163
|
-
- `renameColumn` expects an object: `{ tableName, name, newName }` and works in both SQLite and MySQL.
|
|
164
|
-
- `seed(tableName, rows)` accepts:
|
|
165
|
-
- a single object: `{ col: value, ... }`
|
|
166
|
-
- or an array of objects: `[{...}, {...}]`
|
|
167
|
-
Values are auto-quoted; booleans become 1/0.
|
|
168
|
-
- When a table already exists, `update-database` will sync schema:
|
|
169
|
-
- Add missing columns.
|
|
170
|
-
- MySQL: adjust default/nullability via `ALTER ... MODIFY`.
|
|
171
|
-
- SQLite: rebuilds the table when nullability/default/type changes require it.
|
|
172
|
-
|
|
173
|
-
### Tips
|
|
174
|
-
- Prefer additive changes (add columns) before destructive changes (drops/renames) to minimize downtime.
|
|
175
|
-
- For large SQLite tables, a rebuild copies data; consider maintenance windows.
|
|
176
|
-
- Use `master=development masterrecord get-migrations AppContext` to inspect migration order.
|
|
177
|
-
|
|
178
|
-
|