sqlmorpheus 0.2.7 → 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 JodliDev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,124 +1,124 @@
1
- # SqlMorpheus
2
-
3
- SQLMorpheus is a standalone SQL migration tool that automatically calculates the differences between a database and a defined state and updates the database structure accordingly. It is not bundled with any ORM or limited to a specific SQL dialect or SQL library, making it very flexible and easy to integrate into any (new or preexisting) project.
4
-
5
- Its stand-out features are:
6
- - Database **changes are calculated at runtime**, allowing SqlMorpheus to be used with different database states without expecting any existing structure or having to recompile your app.
7
- - SQLMorpheus **does not bundle its own SQL library** but allows you to define database access yourself using any library you want. This not only prevents unnecessary overhead, it also makes SQLMorpheus very flexible and easy to migrate between database flavours.
8
- - While SQLMorpheus can work without (almost) any manual input, it optionally **allows for destructive changes to be confirmed** to prevent possible data loss.
9
- - It **keeps a history of changes** (and adds an interface for backups before migrations) and allows viewing all changes made and even roll back to a specific version.
10
-
11
-
12
- ## How to install?
13
- To install SqlMorpheus, run
14
- ```bash
15
- npm install sqlmorpheus
16
- ```
17
-
18
- ## How to use?
19
-
20
- Because SqlMorpheus relies on the framework you choose for database access, it needs a little bit more setup code. But you only need to copy & paste a few simple lines of code:
21
-
22
- ### 1. Access the database
23
- For SqlMorpheus to be able to access your database, you need to provide its `runMigration` call (see bellow) with a `dbAccess` object with three callback functions: `runReadStatement()`, `runWriteStatement()` and `runTransaction()`.
24
- Here is a full example for SQLite using better-sqlite3
25
- For other SQL types you can copy one of the provided examples (see [MySQL](/examples/DatabaseAccess_for_MySQL.md), [Postgres](/examples/DatabaseAccess_for_Postgres.md), [SQLite](/examples/DatabaseAccess_for_SQLite.md))
26
-
27
- ```typescript
28
- import {DatabaseAccess, runMigration} from "sqlmorpheus";
29
- import BetterSqlite3 from "better-sqlite3";
30
-
31
- const db = new BetterSqlite3(":memory:");
32
- const dbAccess: DatabaseAccess = {
33
- runReadStatement: async (query: string) => db.prepare(query).all(),
34
- runWriteStatement: async (query: string) => db.prepare(query).run(),
35
- runTransaction: async (query: string) => {
36
- const transaction = db.transaction(() => db.exec(query));
37
- transaction();
38
- }
39
- }
40
- ```
41
- <details>
42
- <summary>Optional: `createBackup()` in DatabaseAccess.</summary>
43
-
44
- On top of the three mandatory methods, you can also define `createBackup()`. This callback is called whenever the `version` in `DatabaseInstructions` has changed and SqlMorpheus needs to change the database. An example implementation for a backup in SQLite would be:
45
-
46
- ```typescript
47
- const dbAccess: DatabaseAccess = {
48
- ...,
49
- createBackup: async (backupName: string) => {
50
- await db.backup(`backups/${backupName}.sqlite`)
51
- }
52
- }
53
- ```
54
- </details>
55
-
56
-
57
- ### 2. Define the database structure
58
- This part might require the most work from you, but should be familiar to you if you have already used other migration libraries: You need to tell SqlMorpheus what structure it should mold your database into. To make this process as simple as possible, SqlMorpheus provides a convenient `TableObj.create()` builder (see [TableObj example](/examples/database_structure_using_TableObj.md)) or, if you prefer, you can also use decorators (see [decorator example](/examples/database_structure_using_decorators.md)).
59
- Here is an example using `TableObj.create()`:
60
- ```typescript
61
- import {DatabaseAccess, runMigration} from "sqlmorpheus";
62
- const usersTable = TableObj.create("User", {
63
- userId: [0, {primaryKey: true}],
64
- name: "Default name",
65
- email: [null, {dataType: "string"}]
66
- });
67
- const messagesTable = TableObj.create("Message", {
68
- messageId: [0, {primaryKey: true}],
69
- from: 0,
70
- to: 0,
71
- content: ""
72
- })
73
- .foreignKey("from", usersTable, "userId", {onDelete: "CASCADE"})
74
- .foreignKey("to", usersTable, "userId", {onDelete: "CASCADE"});
75
- ```
76
-
77
- ### 3. Create the database instructions and run the migration
78
- Now we combine everything and call `runMigration()`.
79
-
80
- Example:
81
- ```typescript
82
- const instructions: DatabaseInstructions = {
83
- dialect: "Sqlite",
84
- tables: [userTable, messagesTable], // usersTable and messagesTable are defined above
85
- version: 1
86
- };
87
-
88
- await runMigration(dbAccess, instructions); // dbAccess is defined above
89
- ```
90
- <details>
91
- <summary>More information about `DatabaseInstructions`.</summary>
92
-
93
- #### `dialect`
94
- This property tells SqlMorpheus which SQL dialect your database uses.
95
-
96
- #### `tables`
97
- This property contains all tables that should be created in the database.
98
-
99
- #### `version`
100
- SqlMorpheus will only compare the database structure when the database version is different to the version property defined in DatabaseInstructions. The version property is also used to decide which manual migrations defined in `preMigration()` should be executed.
101
-
102
- #### `preMigration()`
103
- This method is run before database migrations (and comparisons) are executed. This is also the place where you allow specific destructive migrations or tell SqlMorpheus that you want to rename a table or column (rather than removing and adding it – which would be the default behaviour).
104
-
105
- #### `postMigration()`
106
- This method is run after the migration was finished. You will very rarely need it.
107
-
108
- > All properties are documented in [DatabaseInstructions](/src/lib/typings/DatabaseInstructions.ts).
109
- </details>
110
-
111
- ## When does SqlMorpheus check for migrations?
112
- SqlMorpheus will only compare the database when the [version property](#version) is different to the version saved in the database itself (or if the database has no version defined at all).
113
-
114
- ## How to rename a table or column?
115
- SqlMorpheus has no way of telling if you want to rename a table / column or want to remove it and add a completely new one. To solve this, it relies on your input to tell it what to do (by default it just removes and adds a table / column).
116
- To tell it to rename a table / column, you call `migration.renameTable(VERSION, "OLD_TABLENAME", "NEW_TABLENAME");` in `preMigration()` ([example](/examples/example_renaming.md))
117
-
118
- ## rollback your database
119
- SqlMorpheus saves its changes into the database (into a table called `__sqlmorpheus_migrations`) which allows you to roll back the database to a previous state with a single command:
120
-
121
- ```typescript
122
- // `dbAccess` and `instructions` are defined above
123
- await rollback(dbAccess, TARGET_VERSION, instructions.dialect);
1
+ # SqlMorpheus
2
+
3
+ SQLMorpheus is a standalone SQL migration tool that automatically calculates the differences between a database and a defined state and updates the database structure accordingly. It is not bundled with any ORM or limited to a specific SQL dialect or SQL library, making it very flexible and easy to integrate into any (new or preexisting) project.
4
+
5
+ Its stand-out features are:
6
+ - Database **changes are calculated at runtime**, allowing SqlMorpheus to be used with different database states without expecting any existing structure or having to recompile your app.
7
+ - SQLMorpheus **does not bundle its own SQL library** but allows you to define database access yourself using any library you want. This not only prevents unnecessary overhead, it also makes SQLMorpheus very flexible and easy to migrate between database flavours.
8
+ - While SQLMorpheus can work without (almost) any manual input, it optionally **allows for destructive changes to be confirmed** to prevent possible data loss.
9
+ - It **keeps a history of changes** (and adds an interface for backups before migrations) and allows viewing all changes made and even roll back to a specific version.
10
+
11
+
12
+ ## How to install?
13
+ To install SqlMorpheus, run
14
+ ```bash
15
+ npm install sqlmorpheus
16
+ ```
17
+
18
+ ## How to use?
19
+
20
+ Because SqlMorpheus relies on the framework you choose for database access, it needs a little bit more setup code. But you only need to copy & paste a few simple lines of code:
21
+
22
+ ### 1. Access the database
23
+ For SqlMorpheus to be able to access your database, you need to provide its `runMigration` call (see bellow) with a `dbAccess` object with three callback functions: `runReadStatement()`, `runWriteStatement()` and `runTransaction()`.
24
+ Here is a full example for SQLite using better-sqlite3
25
+ For other SQL types you can copy one of the provided examples (see [MySQL](/examples/DatabaseAccess_for_MySQL.md), [Postgres](/examples/DatabaseAccess_for_Postgres.md), [SQLite](/examples/DatabaseAccess_for_SQLite.md))
26
+
27
+ ```typescript
28
+ import {DatabaseAccess, runMigration} from "sqlmorpheus";
29
+ import BetterSqlite3 from "better-sqlite3";
30
+
31
+ const db = new BetterSqlite3(":memory:");
32
+ const dbAccess: DatabaseAccess = {
33
+ runReadStatement: async (query: string) => db.prepare(query).all(),
34
+ runWriteStatement: async (query: string) => db.prepare(query).run(),
35
+ runTransaction: async (query: string) => {
36
+ const transaction = db.transaction(() => db.exec(query));
37
+ transaction();
38
+ }
39
+ }
40
+ ```
41
+ <details>
42
+ <summary>Optional: `createBackup()` in DatabaseAccess.</summary>
43
+
44
+ On top of the three mandatory methods, you can also define `createBackup()`. This callback is called whenever the `version` in `DatabaseInstructions` has changed and SqlMorpheus needs to change the database. An example implementation for a backup in SQLite would be:
45
+
46
+ ```typescript
47
+ const dbAccess: DatabaseAccess = {
48
+ ...,
49
+ createBackup: async (backupName: string) => {
50
+ await db.backup(`backups/${backupName}.sqlite`)
51
+ }
52
+ }
53
+ ```
54
+ </details>
55
+
56
+
57
+ ### 2. Define the database structure
58
+ This part might require the most work from you, but should be familiar to you if you have already used other migration libraries: You need to tell SqlMorpheus what structure it should mold your database into. To make this process as simple as possible, SqlMorpheus provides a convenient `TableObj.create()` builder (see [TableObj example](/examples/database_structure_using_TableObj.md)) or, if you prefer, you can also use decorators (see [decorator example](/examples/database_structure_using_decorators.md)).
59
+ Here is an example using `TableObj.create()`:
60
+ ```typescript
61
+ import {DatabaseAccess, runMigration} from "sqlmorpheus";
62
+ const usersTable = TableObj.create("User", {
63
+ userId: [0, {primaryKey: true}],
64
+ name: "Default name",
65
+ email: [null, {dataType: "string"}]
66
+ });
67
+ const messagesTable = TableObj.create("Message", {
68
+ messageId: [0, {primaryKey: true}],
69
+ from: 0,
70
+ to: 0,
71
+ content: ""
72
+ })
73
+ .foreignKey("from", usersTable, "userId", {onDelete: "CASCADE"})
74
+ .foreignKey("to", usersTable, "userId", {onDelete: "CASCADE"});
75
+ ```
76
+
77
+ ### 3. Create the database instructions and run the migration
78
+ Now we combine everything and call `runMigration()`.
79
+
80
+ Example:
81
+ ```typescript
82
+ const instructions: DatabaseInstructions = {
83
+ dialect: "Sqlite",
84
+ tables: [userTable, messagesTable], // usersTable and messagesTable are defined above
85
+ version: 1
86
+ };
87
+
88
+ await runMigration(dbAccess, instructions); // dbAccess is defined above
89
+ ```
90
+ <details>
91
+ <summary>More information about `DatabaseInstructions`.</summary>
92
+
93
+ #### `dialect`
94
+ This property tells SqlMorpheus which SQL dialect your database uses.
95
+
96
+ #### `tables`
97
+ This property contains all tables that should be created in the database.
98
+
99
+ #### `version`
100
+ SqlMorpheus will only compare the database structure when the database version is different to the version property defined in DatabaseInstructions. The version property is also used to decide which manual migrations defined in `preMigration()` should be executed.
101
+
102
+ #### `preMigration()`
103
+ This method is run before database migrations (and comparisons) are executed. This is also the place where you allow specific destructive migrations or tell SqlMorpheus that you want to rename a table or column (rather than removing and adding it – which would be the default behaviour).
104
+
105
+ #### `postMigration()`
106
+ This method is run after the migration was finished. You will very rarely need it.
107
+
108
+ > All properties are documented in [DatabaseInstructions](/src/lib/typings/DatabaseInstructions.ts).
109
+ </details>
110
+
111
+ ## When does SqlMorpheus check for migrations?
112
+ SqlMorpheus will only compare the database when the [version property](#version) is different to the version saved in the database itself (or if the database has no version defined at all).
113
+
114
+ ## How to rename a table or column?
115
+ SqlMorpheus has no way of telling if you want to rename a table / column or want to remove it and add a completely new one. To solve this, it relies on your input to tell it what to do (by default it just removes and adds a table / column).
116
+ To tell it to rename a table / column, you call `migration.renameTable(VERSION, "OLD_TABLENAME", "NEW_TABLENAME");` in `preMigration()` ([example](/examples/example_renaming.md))
117
+
118
+ ## Roll back your database
119
+ SqlMorpheus saves its changes into the database (into a table called `__sqlmorpheus_migrations`) which allows you to roll back the database to a previous state with a single command:
120
+
121
+ ```typescript
122
+ // `dbAccess` and `instructions` are defined above
123
+ await rollback(dbAccess, TARGET_VERSION, instructions.dialect);
124
124
  ```