mango-orm 1.0.2 β 1.1.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/README.md +86 -5
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +38 -0
- package/dist/src/mango.d.ts +25 -0
- package/dist/src/mango.js +212 -1
- package/dist/src/migration-cli.d.ts +2 -0
- package/dist/src/migration-cli.js +40 -0
- package/package.json +14 -5
package/README.md
CHANGED
|
@@ -900,7 +900,88 @@ Schema type builder for column definitions.
|
|
|
900
900
|
|
|
901
901
|
---
|
|
902
902
|
|
|
903
|
-
##
|
|
903
|
+
## οΏ½ Database Migrations
|
|
904
|
+
|
|
905
|
+
Mango includes a powerful migration system to version and manage database schema changes with color-coded console feedback.
|
|
906
|
+
|
|
907
|
+
### Creating Migration Files
|
|
908
|
+
|
|
909
|
+
Generate a new migration file:
|
|
910
|
+
|
|
911
|
+
```bash
|
|
912
|
+
npm run migration:generate create_users_table
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
This creates a timestamped migration file like `migrations/1734912000000_create_users_table.ts`:
|
|
916
|
+
|
|
917
|
+
```typescript
|
|
918
|
+
import { IMangoMigrationType, Mango } from "mango-orm";
|
|
919
|
+
|
|
920
|
+
export const create_users_table: IMangoMigrationType = {
|
|
921
|
+
name: "create_users_table",
|
|
922
|
+
timestamp: 1734912000000,
|
|
923
|
+
|
|
924
|
+
up: async (mango: Mango) => {
|
|
925
|
+
await mango.createTable("users", {
|
|
926
|
+
id: mango.types().int().primaryKey().autoIncrement(),
|
|
927
|
+
username: mango.types().varchar(255).notNull().unique(),
|
|
928
|
+
email: mango.types().varchar(255).notNull(),
|
|
929
|
+
created_at: mango.types().timeStamp().default("CURRENT_TIMESTAMP")
|
|
930
|
+
});
|
|
931
|
+
console.log("β Users table created");
|
|
932
|
+
},
|
|
933
|
+
|
|
934
|
+
down: async (mango: Mango) => {
|
|
935
|
+
await mango.dropTable("users");
|
|
936
|
+
console.log("β Users table dropped");
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
### Running Migrations
|
|
942
|
+
|
|
943
|
+
Create a migration runner script:
|
|
944
|
+
|
|
945
|
+
```typescript
|
|
946
|
+
import { Mango, MangoMigration } from "mango-orm";
|
|
947
|
+
import { create_users_table } from "./migrations/1734912000000_create_users_table.js";
|
|
948
|
+
|
|
949
|
+
const mango = new Mango();
|
|
950
|
+
await mango.connect({ /* config */ });
|
|
951
|
+
|
|
952
|
+
const migration = new MangoMigration(mango);
|
|
953
|
+
migration.add(create_users_table);
|
|
954
|
+
|
|
955
|
+
// Check migration status
|
|
956
|
+
await migration.status();
|
|
957
|
+
|
|
958
|
+
// Run next pending migration
|
|
959
|
+
await migration.migrateUp();
|
|
960
|
+
|
|
961
|
+
// Run all pending migrations
|
|
962
|
+
await migration.migrateUpToLatest();
|
|
963
|
+
|
|
964
|
+
// Rollback last migration
|
|
965
|
+
await migration.migrateDown();
|
|
966
|
+
|
|
967
|
+
// Rollback all migrations
|
|
968
|
+
await migration.migrateDownToOldest();
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
### Migration Console Output
|
|
972
|
+
|
|
973
|
+
```
|
|
974
|
+
=== Migration Status ===
|
|
975
|
+
|
|
976
|
+
β Executed: create_users_table
|
|
977
|
+
β¦Ώ Pending: add_posts_table
|
|
978
|
+
|
|
979
|
+
Total: 2 | Executed: 1 | Pending: 1
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
---
|
|
983
|
+
|
|
984
|
+
## οΏ½π Security
|
|
904
985
|
|
|
905
986
|
Mango ORM is built with security in mind:
|
|
906
987
|
|
|
@@ -982,9 +1063,9 @@ await mango.connect({
|
|
|
982
1063
|
|
|
983
1064
|
While Mango is functional, some features are still in development:
|
|
984
1065
|
|
|
1066
|
+
- β
**Migration System**: Database schema migrations with version tracking
|
|
985
1067
|
- β³ **No Transaction Support**: BEGIN/COMMIT/ROLLBACK not fully implemented
|
|
986
1068
|
- β³ **Limited JOIN Support**: Basic joins work but complex joins need testing
|
|
987
|
-
- β³ **No Migration System**: Schema versioning and migrations coming soon
|
|
988
1069
|
- β³ **No Relations**: ORM-style relations (hasMany, belongsTo) not yet available
|
|
989
1070
|
- β³ **No Query Caching**: Results are not cached (may add in future)
|
|
990
1071
|
- β³ **No Connection Retry**: Failed connections don't auto-retry
|
|
@@ -994,17 +1075,17 @@ While Mango is functional, some features are still in development:
|
|
|
994
1075
|
|
|
995
1076
|
## πΊοΈ Roadmap
|
|
996
1077
|
|
|
997
|
-
### Short Term (
|
|
1078
|
+
### Short Term (v1.1.0)
|
|
998
1079
|
- [x] WHERE clause support
|
|
999
1080
|
- [x] UPDATE operations
|
|
1000
1081
|
- [x] DELETE operations
|
|
1001
1082
|
- [x] Comprehensive documentation
|
|
1083
|
+
- [x] Migration system with CLI
|
|
1002
1084
|
- [ ] Transaction support (BEGIN, COMMIT, ROLLBACK)
|
|
1003
1085
|
- [ ] Better error messages with stack traces
|
|
1004
1086
|
- [ ] Connection pool configuration options
|
|
1005
1087
|
|
|
1006
|
-
### Medium Term (
|
|
1007
|
-
- [ ] Migration system
|
|
1088
|
+
### Medium Term (v1.2.0)
|
|
1008
1089
|
- [ ] Seed data functionality
|
|
1009
1090
|
- [ ] Query result caching
|
|
1010
1091
|
- [ ] Batch operation optimization
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { generateMangoMigrationFile } from "./migration-cli.js";
|
|
4
|
+
const command = process.argv[2];
|
|
5
|
+
const migrationName = process.argv[3];
|
|
6
|
+
const outputDir = process.argv[4] || './migrations';
|
|
7
|
+
console.log(chalk.bold.cyan('\nπ₯ Mango Migration CLI\n'));
|
|
8
|
+
switch (command) {
|
|
9
|
+
case "generate":
|
|
10
|
+
case "g":
|
|
11
|
+
if (!migrationName) {
|
|
12
|
+
console.log(chalk.red("β") + " Migration name is required\n");
|
|
13
|
+
showHelp();
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
generateMangoMigrationFile(migrationName, outputDir);
|
|
17
|
+
break;
|
|
18
|
+
case "help":
|
|
19
|
+
case "--help":
|
|
20
|
+
case "-h":
|
|
21
|
+
showHelp();
|
|
22
|
+
break;
|
|
23
|
+
default:
|
|
24
|
+
console.log(chalk.red("β") + ` Unknown command: ${command}\n`);
|
|
25
|
+
showHelp();
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
function showHelp() {
|
|
29
|
+
console.log(chalk.bold("Usage:"));
|
|
30
|
+
console.log(" npm run migration:generate <name> [outputDir]\n");
|
|
31
|
+
console.log(chalk.bold("Commands:"));
|
|
32
|
+
console.log(chalk.cyan(" generate, g") + " Generate a new migration file");
|
|
33
|
+
console.log(chalk.cyan(" help, -h") + " Show this help message\n");
|
|
34
|
+
console.log(chalk.bold("Examples:"));
|
|
35
|
+
console.log(" npm run migration:generate create_users_table");
|
|
36
|
+
console.log(" npm run migration:generate add_email_column");
|
|
37
|
+
console.log(" npm run migration:generate create_posts_table ./db/migrations\n");
|
|
38
|
+
}
|
package/dist/src/mango.d.ts
CHANGED
|
@@ -274,4 +274,29 @@ declare class Mango {
|
|
|
274
274
|
haveTable(name: string): boolean;
|
|
275
275
|
customQuery<Type>(query: string, supplies: any[]): Promise<Type>;
|
|
276
276
|
}
|
|
277
|
+
interface IMangoMigrationType {
|
|
278
|
+
name: string;
|
|
279
|
+
timestamp: number;
|
|
280
|
+
up: (mango: Mango) => Promise<void>;
|
|
281
|
+
down: (mango: Mango) => Promise<void>;
|
|
282
|
+
}
|
|
283
|
+
declare class MangoMigration {
|
|
284
|
+
private mango;
|
|
285
|
+
private mango_migration_table_name;
|
|
286
|
+
private migrations;
|
|
287
|
+
initialize(): Promise<void>;
|
|
288
|
+
constructor(mango: Mango);
|
|
289
|
+
addOneMigrationToDB(migration: IMangoMigrationType): Promise<void>;
|
|
290
|
+
addManyMigrationToDB(migration: IMangoMigrationType[]): Promise<void>;
|
|
291
|
+
deleteOneMigrationFromDB(migration: IMangoMigrationType): Promise<void>;
|
|
292
|
+
deleteManyMigrationFromDB(migrations: IMangoMigrationType[]): Promise<void>;
|
|
293
|
+
add(migration: IMangoMigrationType): MangoMigration;
|
|
294
|
+
getExecutedMigrations(): Promise<string[]>;
|
|
295
|
+
migrateUp(): Promise<void>;
|
|
296
|
+
migrateUpToLatest(): Promise<void>;
|
|
297
|
+
migrateDown(): Promise<void>;
|
|
298
|
+
migrateDownToOldest(): Promise<void>;
|
|
299
|
+
status(): Promise<void>;
|
|
300
|
+
}
|
|
277
301
|
export { Mango, MangoType, MangoTable };
|
|
302
|
+
export { MangoMigration, IMangoMigrationType };
|
package/dist/src/mango.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Requires sql for connection
|
|
3
3
|
*/
|
|
4
4
|
import * as sql from "mysql";
|
|
5
|
+
import chalk from "chalk";
|
|
5
6
|
/**
|
|
6
7
|
* MangoType - Schema builder for defining table column types
|
|
7
8
|
* Provides chainable methods to build SQL column definitions
|
|
@@ -676,7 +677,7 @@ class Mango {
|
|
|
676
677
|
return [...this.tables];
|
|
677
678
|
}
|
|
678
679
|
async createTable(name, fields) {
|
|
679
|
-
this.query.query = "CREATE TABLE " + name + "( \n";
|
|
680
|
+
this.query.query = "CREATE TABLE " + name.toLowerCase() + "( \n";
|
|
680
681
|
const fieldEnteries = Object.entries(fields);
|
|
681
682
|
let table = new MangoTable(this.db, name.toLowerCase(), [
|
|
682
683
|
...fieldEnteries.map(([key, value], index) => {
|
|
@@ -690,6 +691,7 @@ class Mango {
|
|
|
690
691
|
}
|
|
691
692
|
});
|
|
692
693
|
this.query.query += "\n)";
|
|
694
|
+
// console.log(this.query.query);
|
|
693
695
|
await this.query.execute();
|
|
694
696
|
this.query.query = "";
|
|
695
697
|
this.tables.push(table);
|
|
@@ -719,4 +721,213 @@ class Mango {
|
|
|
719
721
|
return this.query.customQuery(query, supplies);
|
|
720
722
|
}
|
|
721
723
|
}
|
|
724
|
+
class MangoMigration {
|
|
725
|
+
async initialize() {
|
|
726
|
+
try {
|
|
727
|
+
if (!this.mango.haveTable(this.mango_migration_table_name)) {
|
|
728
|
+
await this.mango.createTable(this.mango_migration_table_name, {
|
|
729
|
+
id: this.mango.types().int().primaryKey().notNull().autoIncrement(),
|
|
730
|
+
name: this.mango.types().text().notNull().unique(),
|
|
731
|
+
timestamp: this.mango.types().bigInt().notNull(),
|
|
732
|
+
executed_at: this.mango.types().bigInt().notNull(),
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
catch (error) {
|
|
737
|
+
console.log("Error encountered while initializing mangoMigration");
|
|
738
|
+
throw error;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
constructor(mango) {
|
|
742
|
+
this.mango_migration_table_name = "mango_migrations";
|
|
743
|
+
this.migrations = [];
|
|
744
|
+
this.mango = mango;
|
|
745
|
+
this.initialize();
|
|
746
|
+
}
|
|
747
|
+
async addOneMigrationToDB(migration) {
|
|
748
|
+
try {
|
|
749
|
+
await this.mango.selectTable(this.mango_migration_table_name).insertOne({
|
|
750
|
+
name: migration.name,
|
|
751
|
+
timestamp: migration.timestamp,
|
|
752
|
+
executed_at: Date.now()
|
|
753
|
+
}).execute();
|
|
754
|
+
console.log(chalk.dim(` β Recorded in database`));
|
|
755
|
+
}
|
|
756
|
+
catch (error) {
|
|
757
|
+
console.error(chalk.red(`β Error:`) + ` Failed to record migration in DB:`, error.message);
|
|
758
|
+
throw error;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
async addManyMigrationToDB(migration) {
|
|
762
|
+
try {
|
|
763
|
+
await this.mango.selectTable(this.mango_migration_table_name).insertMany(["name", "timestamp", "executed_at"], migration.map((m) => ([
|
|
764
|
+
m.name,
|
|
765
|
+
m.timestamp,
|
|
766
|
+
Date.now()
|
|
767
|
+
]))).execute();
|
|
768
|
+
console.log(chalk.dim(` β Recorded ${migration.length} migrations in database`));
|
|
769
|
+
}
|
|
770
|
+
catch (error) {
|
|
771
|
+
console.error(chalk.red(`β Error:`) + ` Failed to record migrations in DB:`, error.message);
|
|
772
|
+
throw error;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
async deleteOneMigrationFromDB(migration) {
|
|
776
|
+
try {
|
|
777
|
+
await this.mango.selectTable(this.mango_migration_table_name).delete().where("name", "=", migration.name).execute();
|
|
778
|
+
console.log(chalk.dim(` β Removed from database`));
|
|
779
|
+
}
|
|
780
|
+
catch (error) {
|
|
781
|
+
console.error(chalk.red(`β Error:`) + ` Failed to delete migration from DB:`, error);
|
|
782
|
+
throw error;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
async deleteManyMigrationFromDB(migrations) {
|
|
786
|
+
const names = [...migrations].map((m) => m.name);
|
|
787
|
+
try {
|
|
788
|
+
await this.mango.selectTable(this.mango_migration_table_name).delete().whereIn("name", names).execute();
|
|
789
|
+
console.log(chalk.dim(` β Removed ${migrations.length} migrations from database`));
|
|
790
|
+
}
|
|
791
|
+
catch (error) {
|
|
792
|
+
console.error(chalk.red(`β Error:`) + ` Failed to delete migrations from DB:`, error.message);
|
|
793
|
+
throw error;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
add(migration) {
|
|
797
|
+
this.migrations.push(migration);
|
|
798
|
+
return this;
|
|
799
|
+
}
|
|
800
|
+
async getExecutedMigrations() {
|
|
801
|
+
const migration = await this.mango.selectTable(this.mango_migration_table_name).selectAll().orderBy("timestamp").sort(1).execute();
|
|
802
|
+
return migration.map((m) => m.name);
|
|
803
|
+
}
|
|
804
|
+
async migrateUp() {
|
|
805
|
+
await this.initialize();
|
|
806
|
+
const executed = await this.getExecutedMigrations();
|
|
807
|
+
const sorted = [...this.migrations].sort((a, b) => a.timestamp - b.timestamp);
|
|
808
|
+
const pending = sorted.find(m => !executed.includes(m.name));
|
|
809
|
+
if (!pending) {
|
|
810
|
+
console.log(chalk.yellow("β ") + " No pending migrations to execute");
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
console.log(chalk.cyan("β") + ` Running migration: ${chalk.bold(pending.name)}`);
|
|
814
|
+
try {
|
|
815
|
+
await pending.up(this.mango);
|
|
816
|
+
console.log(chalk.green("β") + ` Migration completed: ${chalk.bold(pending.name)}`);
|
|
817
|
+
await this.addOneMigrationToDB(pending);
|
|
818
|
+
}
|
|
819
|
+
catch (error) {
|
|
820
|
+
console.error(chalk.red("β") + ` Migration failed: ${chalk.bold(pending.name)}`);
|
|
821
|
+
console.error(chalk.dim(` Error: ${error.message}`));
|
|
822
|
+
throw error;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
async migrateUpToLatest() {
|
|
826
|
+
await this.initialize();
|
|
827
|
+
const executed = await this.getExecutedMigrations();
|
|
828
|
+
const sorted = [...this.migrations].sort((a, b) => a.timestamp - b.timestamp);
|
|
829
|
+
const pending = sorted.filter(m => !executed.includes(m.name));
|
|
830
|
+
if (pending.length === 0) {
|
|
831
|
+
console.log(chalk.yellow("β ") + " No pending migrations to execute");
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
console.log(chalk.cyan("β") + ` Running ${pending.length} pending migration(s)...\n`);
|
|
835
|
+
for (const migration of pending) {
|
|
836
|
+
console.log(chalk.cyan(" β") + ` ${chalk.bold(migration.name)}`);
|
|
837
|
+
try {
|
|
838
|
+
await migration.up(this.mango);
|
|
839
|
+
await this.addOneMigrationToDB(migration);
|
|
840
|
+
console.log(chalk.green(" β") + ` Completed\n`);
|
|
841
|
+
}
|
|
842
|
+
catch (error) {
|
|
843
|
+
console.error(chalk.red(" β") + ` Failed`);
|
|
844
|
+
console.error(chalk.dim(` Error: ${error.message}`));
|
|
845
|
+
throw error;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
console.log(chalk.green("β") + ` All migrations completed successfully`);
|
|
849
|
+
}
|
|
850
|
+
async migrateDown() {
|
|
851
|
+
await this.initialize();
|
|
852
|
+
const executed = await this.getExecutedMigrations();
|
|
853
|
+
const sorted = [...this.migrations].sort((a, b) => a.timestamp - b.timestamp);
|
|
854
|
+
if (executed.length === 0) {
|
|
855
|
+
console.log(chalk.yellow("β ") + " No migrations to rollback");
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
const oldMigrationName = executed[executed.length - 1];
|
|
859
|
+
const migration = sorted.find(m => m.name === oldMigrationName);
|
|
860
|
+
if (!migration) {
|
|
861
|
+
throw new Error(`Migration not found: ${oldMigrationName}`);
|
|
862
|
+
}
|
|
863
|
+
console.log(chalk.magenta("β") + ` Rolling back: ${chalk.bold(migration.name)}`);
|
|
864
|
+
try {
|
|
865
|
+
await migration.down(this.mango);
|
|
866
|
+
await this.deleteOneMigrationFromDB(migration);
|
|
867
|
+
console.log(chalk.green("β") + ` Rollback completed`);
|
|
868
|
+
}
|
|
869
|
+
catch (error) {
|
|
870
|
+
console.error(chalk.red("β") + ` Rollback failed: ${chalk.bold(migration.name)}`);
|
|
871
|
+
console.error(chalk.dim(` Error: ${error.message}`));
|
|
872
|
+
throw error;
|
|
873
|
+
}
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
async migrateDownToOldest() {
|
|
877
|
+
await this.initialize();
|
|
878
|
+
const executed = await this.getExecutedMigrations();
|
|
879
|
+
const sorted = [...this.migrations].sort((a, b) => a.timestamp - b.timestamp);
|
|
880
|
+
if (executed.length === 0) {
|
|
881
|
+
console.log(chalk.yellow("β ") + " No migrations to rollback");
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
console.log(chalk.magenta("β") + ` Rolling back ${executed.length} migration(s)...\n`);
|
|
885
|
+
for (const migrationName of executed.reverse()) {
|
|
886
|
+
const migration = sorted.find(migration => migration.name === migrationName);
|
|
887
|
+
if (!migration) {
|
|
888
|
+
throw new Error(`Migration not found: ${migrationName}`);
|
|
889
|
+
}
|
|
890
|
+
console.log(chalk.magenta(" β") + ` ${chalk.bold(migration.name)}`);
|
|
891
|
+
try {
|
|
892
|
+
await migration.down(this.mango);
|
|
893
|
+
await this.deleteOneMigrationFromDB(migration);
|
|
894
|
+
console.log(chalk.green(" β") + ` Completed\n`);
|
|
895
|
+
}
|
|
896
|
+
catch (error) {
|
|
897
|
+
console.error(chalk.red(" β") + ` Failed`);
|
|
898
|
+
console.error(chalk.dim(` Error: ${error.message}`));
|
|
899
|
+
throw error;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
console.log(chalk.green("β") + ` All migrations rolled back successfully`);
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
async status() {
|
|
906
|
+
await this.initialize();
|
|
907
|
+
const executedMigrations = await this.getExecutedMigrations();
|
|
908
|
+
const sortedMigrations = [...this.migrations].sort((a, b) => a.timestamp - b.timestamp);
|
|
909
|
+
console.log(chalk.bold.cyan("\n=== Migration Status ==="));
|
|
910
|
+
console.log();
|
|
911
|
+
if (sortedMigrations.length === 0) {
|
|
912
|
+
console.log(chalk.dim(" No migrations registered"));
|
|
913
|
+
}
|
|
914
|
+
else {
|
|
915
|
+
for (const migration of sortedMigrations) {
|
|
916
|
+
if (executedMigrations.includes(migration.name)) {
|
|
917
|
+
console.log(chalk.green(" β Executed:") + ` ${chalk.cyan(migration.name)}`);
|
|
918
|
+
}
|
|
919
|
+
else {
|
|
920
|
+
console.log(chalk.yellow(" β§ Pending: ") + ` ${chalk.cyan(migration.name)}`);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
console.log();
|
|
925
|
+
console.log(chalk.bold("Total:") + ` ${this.migrations.length} | ` +
|
|
926
|
+
chalk.green("Executed:") + ` ${executedMigrations.length} | ` +
|
|
927
|
+
chalk.yellow("Pending:") + ` ${this.migrations.length - executedMigrations.length}`);
|
|
928
|
+
console.log();
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
;
|
|
722
932
|
export { Mango, MangoType, MangoTable };
|
|
933
|
+
export { MangoMigration };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
const generateMangoMigrationFile = (migrationFilename, outputDir = './migrations') => {
|
|
5
|
+
const timestamp = Date.now();
|
|
6
|
+
const filepath = path.join(outputDir, `${timestamp}_${migrationFilename}.ts`);
|
|
7
|
+
const template = `import { IMangoMigrationType, Mango } from "../src/mango.js";
|
|
8
|
+
|
|
9
|
+
export const ${migrationFilename}: IMangoMigrationType = {
|
|
10
|
+
name: "${migrationFilename}",
|
|
11
|
+
timestamp: ${timestamp},
|
|
12
|
+
|
|
13
|
+
up: async (mango: Mango) => {
|
|
14
|
+
// TODO: Write your migration code here
|
|
15
|
+
// Example:
|
|
16
|
+
// await mango.createTable("users", {
|
|
17
|
+
// id: mango.types().int().primaryKey().autoIncrement(),
|
|
18
|
+
// username: mango.types().varchar(255).notNull().unique(),
|
|
19
|
+
// password: mango.types().varchar(255).notNull()
|
|
20
|
+
// });
|
|
21
|
+
|
|
22
|
+
console.log("β Migration ${migrationFilename} completed");
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
down: async (mango: Mango) => {
|
|
26
|
+
// TODO: Write your rollback code here
|
|
27
|
+
// Example:
|
|
28
|
+
// await mango.dropTable("users");
|
|
29
|
+
|
|
30
|
+
console.log("β Rollback ${migrationFilename} completed");
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
`;
|
|
34
|
+
if (!fs.existsSync(outputDir)) {
|
|
35
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
fs.writeFileSync(filepath, template);
|
|
38
|
+
console.log(chalk.green("β") + ` Created migration: ${chalk.cyan(filepath)}`);
|
|
39
|
+
};
|
|
40
|
+
export { generateMangoMigrationFile };
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mango-orm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "A lightweight, type-safe MySQL ORM for Node.js and TypeScript",
|
|
5
|
+
"description": "A lightweight, type-safe MySQL ORM for Node.js and TypeScript with database migrations",
|
|
6
6
|
"main": "dist/src/mango.js",
|
|
7
7
|
"types": "dist/src/mango.d.ts",
|
|
8
8
|
"scripts": {
|
|
@@ -10,11 +10,14 @@
|
|
|
10
10
|
"dev": "tsc --watch",
|
|
11
11
|
"test": "tsc && node dist/test/test.js",
|
|
12
12
|
"test:ops": "tsc && node dist/test/test-operations.js",
|
|
13
|
-
"prepublishOnly": "pnpm build"
|
|
13
|
+
"prepublishOnly": "pnpm build",
|
|
14
|
+
"migration:generate": "tsc && node dist/src/cli.js generate",
|
|
15
|
+
"migration:help": "tsc && node dist/src/cli.js help"
|
|
14
16
|
},
|
|
15
17
|
"files": [
|
|
16
18
|
"dist/src",
|
|
17
|
-
"README.md"
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
18
21
|
],
|
|
19
22
|
"keywords": [
|
|
20
23
|
"mysql",
|
|
@@ -23,7 +26,12 @@
|
|
|
23
26
|
"database",
|
|
24
27
|
"sql",
|
|
25
28
|
"type-safe",
|
|
26
|
-
"query-builder"
|
|
29
|
+
"query-builder",
|
|
30
|
+
"migrations",
|
|
31
|
+
"schema-management",
|
|
32
|
+
"mysql-orm",
|
|
33
|
+
"nodejs",
|
|
34
|
+
"fluent-api"
|
|
27
35
|
],
|
|
28
36
|
"author": "Siddharth Karn siddharth2062.karn@gmail.com (https://github.com/devSiddharthKarn)",
|
|
29
37
|
"license": "ISC",
|
|
@@ -38,6 +46,7 @@
|
|
|
38
46
|
"packageManager": "pnpm@10.25.0",
|
|
39
47
|
"dependencies": {
|
|
40
48
|
"@types/mysql": "^2.15.27",
|
|
49
|
+
"chalk": "^5.6.2",
|
|
41
50
|
"mysql": "^2.18.1"
|
|
42
51
|
},
|
|
43
52
|
"devDependencies": {
|