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 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('0.0.3')
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.1",
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": "./migrations/cli.js"
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
- For full instructions on running migrations and updating the server, see `MIGRATIONS.md`.
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
-