mango-orm 1.1.2 → 1.1.4
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/dist/{src/cli.js → cli.js} +5 -4
- package/dist/mango.d.ts +114 -0
- package/dist/{src/mango.js → mango.js} +4 -215
- package/dist/{src/migration-cli.js → migration-cli.js} +1 -1
- package/package.json +8 -10
- package/dist/src/mango.d.ts +0 -302
- /package/dist/{src/cli.d.ts → cli.d.ts} +0 -0
- /package/dist/{src/migration-cli.d.ts → migration-cli.d.ts} +0 -0
|
@@ -27,12 +27,13 @@ switch (command) {
|
|
|
27
27
|
}
|
|
28
28
|
function showHelp() {
|
|
29
29
|
console.log(chalk.bold("Usage:"));
|
|
30
|
-
console.log("
|
|
30
|
+
console.log(" mango generate <name> [outputDir]");
|
|
31
|
+
console.log(" npx mango generate <name> [outputDir]\n");
|
|
31
32
|
console.log(chalk.bold("Commands:"));
|
|
32
33
|
console.log(chalk.cyan(" generate, g") + " Generate a new migration file");
|
|
33
34
|
console.log(chalk.cyan(" help, -h") + " Show this help message\n");
|
|
34
35
|
console.log(chalk.bold("Examples:"));
|
|
35
|
-
console.log("
|
|
36
|
-
console.log("
|
|
37
|
-
console.log("
|
|
36
|
+
console.log(" mango generate create_users_table");
|
|
37
|
+
console.log(" mango generate add_email_column");
|
|
38
|
+
console.log(" mango generate create_posts_table ./db/migrations\n");
|
|
38
39
|
}
|
package/dist/mango.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as sql from "mysql";
|
|
2
|
+
declare class MangoType {
|
|
3
|
+
private query;
|
|
4
|
+
constructor();
|
|
5
|
+
int(): this;
|
|
6
|
+
bigInt(): this;
|
|
7
|
+
float(): this;
|
|
8
|
+
char(length: number): this;
|
|
9
|
+
text(): this;
|
|
10
|
+
date(): this;
|
|
11
|
+
dateTime(): this;
|
|
12
|
+
timeStamp(): this;
|
|
13
|
+
boolean(): this;
|
|
14
|
+
tinyInt(length: number): this;
|
|
15
|
+
autoIncrement(): this;
|
|
16
|
+
primaryKey(): this;
|
|
17
|
+
varchar(length: number): this;
|
|
18
|
+
notNull(): this;
|
|
19
|
+
unique(): this;
|
|
20
|
+
getQuery(): string;
|
|
21
|
+
}
|
|
22
|
+
declare class MangoQuery {
|
|
23
|
+
private db;
|
|
24
|
+
query: string;
|
|
25
|
+
supplies: any;
|
|
26
|
+
config(db: sql.Pool): void;
|
|
27
|
+
execute<T>(): Promise<T>;
|
|
28
|
+
customQuery<T>(query: string, supplies: any[]): Promise<T>;
|
|
29
|
+
}
|
|
30
|
+
declare class MangoTable<T> {
|
|
31
|
+
private db;
|
|
32
|
+
private tableName;
|
|
33
|
+
private tableFields;
|
|
34
|
+
private query;
|
|
35
|
+
constructor(db: sql.Pool, name: string, fields?: string[]);
|
|
36
|
+
addColumns(fields: Record<string, MangoType>): this;
|
|
37
|
+
removeColumns(fields: string[]): this;
|
|
38
|
+
selectAll(): this;
|
|
39
|
+
selectColumns(columns: string[]): this;
|
|
40
|
+
selectDistinctColumns(columns: string[]): this;
|
|
41
|
+
orderBy(columnName: string): this;
|
|
42
|
+
sort(sort?: number): this;
|
|
43
|
+
limit(length: number): this;
|
|
44
|
+
offset(length: number): this;
|
|
45
|
+
insertOne(data: Record<string, any>): this;
|
|
46
|
+
insertMany(fields: string[], data?: any[][]): this;
|
|
47
|
+
getFields(): string[];
|
|
48
|
+
getName(): string;
|
|
49
|
+
truncate(): this;
|
|
50
|
+
where(field: string, operator: string, value: any): this;
|
|
51
|
+
and(field: string, operator: string, value: any): this;
|
|
52
|
+
or(field: string, operator: string, value: any): this;
|
|
53
|
+
update(data: Record<string, any>): this;
|
|
54
|
+
join(type: 'INNER' | 'LEFT' | 'RIGHT' | 'FULL', table: string, condition: {
|
|
55
|
+
left: string;
|
|
56
|
+
operator: string;
|
|
57
|
+
right: string;
|
|
58
|
+
}): this;
|
|
59
|
+
delete(): this;
|
|
60
|
+
whereIn(field: string, values: any[]): this;
|
|
61
|
+
whereNotIn(field: string, values: any[]): this;
|
|
62
|
+
getQuery(): MangoQuery;
|
|
63
|
+
execute(): Promise<T[]>;
|
|
64
|
+
customQuery<Type>(query: string, supplies: any[]): Promise<Type[]>;
|
|
65
|
+
}
|
|
66
|
+
declare class Mango {
|
|
67
|
+
private db;
|
|
68
|
+
private tables;
|
|
69
|
+
private query;
|
|
70
|
+
connect({ host, user, password, database, connectionLimit, waitForConnection, queueLimit, connectTimeout, charset, }: {
|
|
71
|
+
host: any;
|
|
72
|
+
user: any;
|
|
73
|
+
password: any;
|
|
74
|
+
database: any;
|
|
75
|
+
connectionLimit?: number;
|
|
76
|
+
waitForConnection?: boolean;
|
|
77
|
+
queueLimit?: number;
|
|
78
|
+
connectTimeout?: number;
|
|
79
|
+
charset?: string;
|
|
80
|
+
}): Promise<this>;
|
|
81
|
+
disconnect(): Promise<void>;
|
|
82
|
+
types(): MangoType;
|
|
83
|
+
selectTable<T = any>(name: string): MangoTable<T>;
|
|
84
|
+
getTables(): MangoTable<any>[];
|
|
85
|
+
createTable<T>(name: string, fields: Record<string, MangoType>): Promise<MangoTable<T>>;
|
|
86
|
+
dropTable(name: string): Promise<void>;
|
|
87
|
+
haveTable(name: string): boolean;
|
|
88
|
+
customQuery<Type>(query: string, supplies: any[]): Promise<Type>;
|
|
89
|
+
}
|
|
90
|
+
interface IMangoMigrationType {
|
|
91
|
+
name: string;
|
|
92
|
+
timestamp: number;
|
|
93
|
+
up: (mango: Mango) => Promise<void>;
|
|
94
|
+
down: (mango: Mango) => Promise<void>;
|
|
95
|
+
}
|
|
96
|
+
declare class MangoMigration {
|
|
97
|
+
private mango;
|
|
98
|
+
private mango_migration_table_name;
|
|
99
|
+
private migrations;
|
|
100
|
+
private initialize;
|
|
101
|
+
constructor(mango: Mango);
|
|
102
|
+
private addOneMigrationToDB;
|
|
103
|
+
private addManyMigrationToDB;
|
|
104
|
+
private deleteOneMigrationFromDB;
|
|
105
|
+
private deleteManyMigrationFromDB;
|
|
106
|
+
add(migration: IMangoMigrationType): MangoMigration;
|
|
107
|
+
private getExecutedMigrations;
|
|
108
|
+
migrateUp(): Promise<void>;
|
|
109
|
+
migrateUpToLatest(): Promise<void>;
|
|
110
|
+
migrateDown(): Promise<void>;
|
|
111
|
+
migrateDownToOldest(): Promise<void>;
|
|
112
|
+
status(): Promise<void>;
|
|
113
|
+
}
|
|
114
|
+
export { Mango, MangoType, MangoTable, MangoMigration, IMangoMigrationType };
|
|
@@ -1,135 +1,84 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Requires sql for connection
|
|
3
|
-
*/
|
|
4
1
|
import * as sql from "mysql";
|
|
5
2
|
import chalk from "chalk";
|
|
6
|
-
/**
|
|
7
|
-
* MangoType - Schema builder for defining table column types
|
|
8
|
-
* Provides chainable methods to build SQL column definitions
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* const type = new MangoType();
|
|
12
|
-
* type.varchar(255).notNull().unique();
|
|
13
|
-
*/
|
|
14
3
|
class MangoType {
|
|
15
4
|
constructor() {
|
|
16
5
|
this.query = "";
|
|
17
6
|
}
|
|
18
|
-
/** Define an INT column */
|
|
19
7
|
int() {
|
|
20
8
|
this.query += " INT ";
|
|
21
9
|
return this;
|
|
22
10
|
}
|
|
23
|
-
/** Define a BIGINT column */
|
|
24
11
|
bigInt() {
|
|
25
12
|
this.query += " BIGINT ";
|
|
26
13
|
return this;
|
|
27
14
|
}
|
|
28
|
-
/** Define a FLOAT column */
|
|
29
15
|
float() {
|
|
30
16
|
this.query += " FLOAT ";
|
|
31
17
|
return this;
|
|
32
18
|
}
|
|
33
|
-
/**
|
|
34
|
-
* Define a CHAR column with fixed length
|
|
35
|
-
* @param length - The fixed character length
|
|
36
|
-
*/
|
|
37
19
|
char(length) {
|
|
38
20
|
this.query += ` CHAR(${length}) `;
|
|
39
21
|
return this;
|
|
40
22
|
}
|
|
41
|
-
/** Define a TEXT column for large text data */
|
|
42
23
|
text() {
|
|
43
24
|
this.query += " TEXT ";
|
|
44
25
|
return this;
|
|
45
26
|
}
|
|
46
|
-
/** Define a DATE column (YYYY-MM-DD) */
|
|
47
27
|
date() {
|
|
48
28
|
this.query += " DATE ";
|
|
49
29
|
return this;
|
|
50
30
|
}
|
|
51
|
-
/** Define a DATETIME column (YYYY-MM-DD HH:MM:SS) */
|
|
52
31
|
dateTime() {
|
|
53
32
|
this.query += " DATETIME ";
|
|
54
33
|
return this;
|
|
55
34
|
}
|
|
56
|
-
/** Define a TIMESTAMP column (auto-updated on changes) */
|
|
57
35
|
timeStamp() {
|
|
58
36
|
this.query += " TIMESTAMP ";
|
|
59
37
|
return this;
|
|
60
38
|
}
|
|
61
|
-
/** Define a BOOLEAN column (stored as TINYINT(1)) */
|
|
62
39
|
boolean() {
|
|
63
40
|
this.query += " BOOLEAN ";
|
|
64
41
|
return this;
|
|
65
42
|
}
|
|
66
|
-
/**
|
|
67
|
-
* Define a TINYINT column
|
|
68
|
-
* @param length - Display width (e.g., TINYINT(1))
|
|
69
|
-
*/
|
|
70
43
|
tinyInt(length) {
|
|
71
44
|
this.query += ` TINYINT(${length})`;
|
|
72
45
|
return this;
|
|
73
46
|
}
|
|
74
|
-
/** Make column auto-incrementing (use with INT/BIGINT) */
|
|
75
47
|
autoIncrement() {
|
|
76
48
|
this.query += " AUTO_INCREMENT ";
|
|
77
49
|
return this;
|
|
78
50
|
}
|
|
79
|
-
/** Mark column as primary key */
|
|
80
51
|
primaryKey() {
|
|
81
52
|
this.query += " PRIMARY KEY ";
|
|
82
53
|
return this;
|
|
83
54
|
}
|
|
84
|
-
/**
|
|
85
|
-
* Define a VARCHAR column with variable length
|
|
86
|
-
* @param length - Maximum character length (e.g., 255)
|
|
87
|
-
*/
|
|
88
55
|
varchar(length) {
|
|
89
56
|
this.query += ` VARCHAR(${length}) `;
|
|
90
57
|
return this;
|
|
91
58
|
}
|
|
92
|
-
/** Make column NOT NULL (required field) */
|
|
93
59
|
notNull() {
|
|
94
60
|
this.query += ` NOT NULL `;
|
|
95
61
|
return this;
|
|
96
62
|
}
|
|
97
|
-
/** Add UNIQUE constraint (no duplicate values) */
|
|
98
63
|
unique() {
|
|
99
64
|
this.query += " UNIQUE ";
|
|
100
65
|
return this;
|
|
101
66
|
}
|
|
102
|
-
/** Get the built SQL column definition */
|
|
103
67
|
getQuery() {
|
|
104
68
|
return this.query;
|
|
105
69
|
}
|
|
106
70
|
}
|
|
107
|
-
/**
|
|
108
|
-
* MangoQuery - Internal query executor
|
|
109
|
-
* Handles SQL query execution and prepared statements
|
|
110
|
-
* Automatically resets state after execution to prevent query contamination
|
|
111
|
-
*/
|
|
112
71
|
class MangoQuery {
|
|
113
72
|
constructor() {
|
|
114
73
|
this.query = "";
|
|
115
|
-
this.supplies = [];
|
|
74
|
+
this.supplies = [];
|
|
116
75
|
}
|
|
117
|
-
/**
|
|
118
|
-
* Configure the database connection pool
|
|
119
|
-
* @param db - MySQL connection pool instance
|
|
120
|
-
*/
|
|
121
76
|
config(db) {
|
|
122
77
|
this.db = db;
|
|
123
78
|
}
|
|
124
|
-
/**
|
|
125
|
-
* Execute the built query with prepared statements
|
|
126
|
-
* Automatically resets query and supplies after execution
|
|
127
|
-
* @returns Promise resolving to query results
|
|
128
|
-
*/
|
|
129
79
|
execute() {
|
|
130
80
|
return new Promise((resolve, reject) => {
|
|
131
81
|
this.db.query(this.query, this.supplies, (err, result) => {
|
|
132
|
-
// Reset state BEFORE resolving to prevent contamination
|
|
133
82
|
this.query = "";
|
|
134
83
|
this.supplies = [];
|
|
135
84
|
if (err)
|
|
@@ -139,13 +88,6 @@ class MangoQuery {
|
|
|
139
88
|
});
|
|
140
89
|
});
|
|
141
90
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Execute a custom SQL query with parameters
|
|
144
|
-
* Use for complex queries not covered by the query builder
|
|
145
|
-
* @param query - Raw SQL query string
|
|
146
|
-
* @param supplies - Array of parameter values
|
|
147
|
-
* @returns Promise resolving to query results
|
|
148
|
-
*/
|
|
149
91
|
customQuery(query, supplies) {
|
|
150
92
|
return new Promise((resolve, reject) => {
|
|
151
93
|
this.db.query(query, supplies, (err, result) => {
|
|
@@ -157,53 +99,21 @@ class MangoQuery {
|
|
|
157
99
|
});
|
|
158
100
|
}
|
|
159
101
|
}
|
|
160
|
-
/**
|
|
161
|
-
* MangoTable<T> - Main query builder class for table operations
|
|
162
|
-
* Provides chainable methods for building SQL queries
|
|
163
|
-
* Generic type T represents the shape of table rows
|
|
164
|
-
*
|
|
165
|
-
* @example
|
|
166
|
-
* const users = new MangoTable(db, 'users', ['id', 'name', 'email']);
|
|
167
|
-
* const result = await users.selectAll().where('id', '=', 1).execute();
|
|
168
|
-
*/
|
|
169
102
|
class MangoTable {
|
|
170
|
-
/**
|
|
171
|
-
* Create a new table instance
|
|
172
|
-
* @param db - MySQL connection pool
|
|
173
|
-
* @param name - Table name (no spaces allowed)
|
|
174
|
-
* @param fields - Array of column names in the table
|
|
175
|
-
*/
|
|
176
103
|
constructor(db, name, fields = []) {
|
|
177
104
|
this.query = new MangoQuery();
|
|
178
|
-
// Validate that fields are provided
|
|
179
105
|
if (fields.length == 0 || (fields.length == 1 && fields[0] === "")) {
|
|
180
106
|
throw new Error("no fields provided for table " + name);
|
|
181
107
|
}
|
|
182
108
|
this.db = db;
|
|
183
|
-
// Validate table name doesn't contain spaces
|
|
184
109
|
if (Array.from(name.split(" ")).length > 1) {
|
|
185
110
|
throw new Error("No spaces in table name allowed:");
|
|
186
111
|
}
|
|
187
112
|
this.tableName = name.toLowerCase();
|
|
188
|
-
this.tableFields = [...fields];
|
|
189
|
-
// Initialize query executor
|
|
190
|
-
// this.query = new MangoQuery();
|
|
113
|
+
this.tableFields = [...fields];
|
|
191
114
|
this.query.config(db);
|
|
192
115
|
}
|
|
193
|
-
/**
|
|
194
|
-
* Add new columns to an existing table
|
|
195
|
-
* Updates internal field list for validation
|
|
196
|
-
* @param fields - Object mapping column names to MangoType definitions
|
|
197
|
-
* @returns this for method chaining
|
|
198
|
-
*
|
|
199
|
-
* @example
|
|
200
|
-
* table.addColumns({
|
|
201
|
-
* age: mango.types().int().notNull(),
|
|
202
|
-
* status: mango.types().varchar(50)
|
|
203
|
-
* }).execute();
|
|
204
|
-
*/
|
|
205
116
|
addColumns(fields) {
|
|
206
|
-
// Early return if no fields provided
|
|
207
117
|
if (Object.entries(fields).length === 0)
|
|
208
118
|
return this;
|
|
209
119
|
this.query.query += "ALTER TABLE " + this.tableName + "\n";
|
|
@@ -211,7 +121,6 @@ class MangoTable {
|
|
|
211
121
|
this.query.query += entries
|
|
212
122
|
.map(([key, value]) => {
|
|
213
123
|
let QUERY = " ADD COLUMN ";
|
|
214
|
-
// Validate column name doesn't contain spaces
|
|
215
124
|
if (Array.from(key.split(" ")).length > 1) {
|
|
216
125
|
throw new Error("Field/Column name cannot have spaces: " +
|
|
217
126
|
key +
|
|
@@ -224,28 +133,16 @@ class MangoTable {
|
|
|
224
133
|
})
|
|
225
134
|
.join(",\n");
|
|
226
135
|
this.query.query += ";\n";
|
|
227
|
-
// Update internal field list for future validations
|
|
228
136
|
entries.forEach(([key]) => this.tableFields.push(key));
|
|
229
137
|
return this;
|
|
230
138
|
}
|
|
231
|
-
/**
|
|
232
|
-
* Remove columns from the table
|
|
233
|
-
* Validates columns exist before removal
|
|
234
|
-
* @param fields - Array of column names to remove
|
|
235
|
-
* @returns this for method chaining
|
|
236
|
-
*
|
|
237
|
-
* @example
|
|
238
|
-
* table.removeColumns(['old_field', 'deprecated_col']).execute();
|
|
239
|
-
*/
|
|
240
139
|
removeColumns(fields) {
|
|
241
|
-
// Early return if no fields provided
|
|
242
140
|
if (fields.length === 0)
|
|
243
141
|
return this;
|
|
244
142
|
this.query.query += "ALTER TABLE " + this.tableName + "\n";
|
|
245
143
|
this.query.query += fields
|
|
246
144
|
.map((field) => {
|
|
247
145
|
let QUERY = " DROP COLUMN ";
|
|
248
|
-
// Validate field exists in table
|
|
249
146
|
if (!this.tableFields.includes(field)) {
|
|
250
147
|
throw new Error("field/column : " +
|
|
251
148
|
field +
|
|
@@ -257,38 +154,18 @@ class MangoTable {
|
|
|
257
154
|
})
|
|
258
155
|
.join(",\n");
|
|
259
156
|
this.query.query += ";\n";
|
|
260
|
-
// Remove fields from internal tracking
|
|
261
157
|
this.tableFields = this.tableFields.filter((value) => !fields.includes(value));
|
|
262
158
|
return this;
|
|
263
159
|
}
|
|
264
|
-
/**
|
|
265
|
-
* Select all columns from the table
|
|
266
|
-
* @returns this for method chaining
|
|
267
|
-
*
|
|
268
|
-
* @example
|
|
269
|
-
* await table.selectAll().where('active', '=', true).execute();
|
|
270
|
-
*/
|
|
271
160
|
selectAll() {
|
|
272
161
|
this.query.query = `SELECT * from ${this.tableName}`;
|
|
273
162
|
return this;
|
|
274
163
|
}
|
|
275
|
-
/**
|
|
276
|
-
* Select specific columns from the table
|
|
277
|
-
* Validates all columns exist before building query
|
|
278
|
-
* @param columns - Array of column names to select
|
|
279
|
-
* @returns this for method chaining
|
|
280
|
-
*
|
|
281
|
-
* @example
|
|
282
|
-
* await table.selectColumns(['id', 'name', 'email']).execute();
|
|
283
|
-
*/
|
|
284
164
|
selectColumns(columns) {
|
|
285
|
-
// Early return if no columns specified
|
|
286
165
|
if (columns.length === 0)
|
|
287
166
|
return this;
|
|
288
167
|
this.query.query = `SELECT `;
|
|
289
|
-
// Build column list with proper comma separation
|
|
290
168
|
for (let i = 0; i < columns.length; i++) {
|
|
291
|
-
// Validate each column exists in table
|
|
292
169
|
if (!this.tableFields.includes(columns[i])) {
|
|
293
170
|
throw new Error("Table field: " +
|
|
294
171
|
columns[i] +
|
|
@@ -296,7 +173,6 @@ class MangoTable {
|
|
|
296
173
|
this.tableName);
|
|
297
174
|
}
|
|
298
175
|
this.query.query += " " + columns[i];
|
|
299
|
-
// Add comma between columns, but not after the last one
|
|
300
176
|
if (i < columns.length - 1) {
|
|
301
177
|
this.query.query += " , ";
|
|
302
178
|
}
|
|
@@ -399,26 +275,10 @@ class MangoTable {
|
|
|
399
275
|
this.query.query = " TRUNCATE TABLE " + this.tableName;
|
|
400
276
|
return this;
|
|
401
277
|
}
|
|
402
|
-
/**
|
|
403
|
-
* Add WHERE clause to filter query results
|
|
404
|
-
* Use with comparison operators to filter rows
|
|
405
|
-
* Supports falsy values (0, false, empty string)
|
|
406
|
-
* @param field - Column name to filter on
|
|
407
|
-
* @param operator - SQL comparison operator (=, !=, <, >, LIKE, etc.)
|
|
408
|
-
* @param value - Value to compare against (any type)
|
|
409
|
-
* @returns this for method chaining
|
|
410
|
-
*
|
|
411
|
-
* @example
|
|
412
|
-
* table.selectAll().where('age', '>=', 18).execute();
|
|
413
|
-
* table.selectAll().where('active', '=', false).execute(); // Works with false!
|
|
414
|
-
* table.selectAll().where('count', '=', 0).execute(); // Works with 0!
|
|
415
|
-
*/
|
|
416
278
|
where(field, operator, value) {
|
|
417
|
-
// Validate field exists in table
|
|
418
279
|
if (!this.tableFields.includes(field)) {
|
|
419
280
|
throw new Error(`Field/Column: ${field} does not exist in table: ${this.tableName}`);
|
|
420
281
|
}
|
|
421
|
-
// Validate operator is allowed
|
|
422
282
|
const validOperators = [
|
|
423
283
|
"=",
|
|
424
284
|
"!=",
|
|
@@ -437,25 +297,10 @@ class MangoTable {
|
|
|
437
297
|
if (!validOperators.includes(operator.toUpperCase())) {
|
|
438
298
|
throw new Error(`Invalid operator: ${operator}`);
|
|
439
299
|
}
|
|
440
|
-
// Build WHERE clause with placeholder
|
|
441
300
|
this.query.query += ` WHERE ${field} ${operator} ? `;
|
|
442
301
|
this.query.supplies.push(value);
|
|
443
302
|
return this;
|
|
444
303
|
}
|
|
445
|
-
/**
|
|
446
|
-
* Add AND condition to existing WHERE clause
|
|
447
|
-
* Chain multiple conditions together
|
|
448
|
-
* @param field - Column name
|
|
449
|
-
* @param operator - SQL comparison operator
|
|
450
|
-
* @param value - Value to compare (any type including 0, false)
|
|
451
|
-
* @returns this for method chaining
|
|
452
|
-
*
|
|
453
|
-
* @example
|
|
454
|
-
* table.selectAll()
|
|
455
|
-
* .where('age', '>=', 18)
|
|
456
|
-
* .and('active', '=', true)
|
|
457
|
-
* .execute();
|
|
458
|
-
*/
|
|
459
304
|
and(field, operator, value) {
|
|
460
305
|
if (!this.tableFields.includes(field)) {
|
|
461
306
|
throw new Error(`Field/Column: ${field} does not exist in table: ${this.tableName}`);
|
|
@@ -482,20 +327,6 @@ class MangoTable {
|
|
|
482
327
|
this.query.supplies.push(value);
|
|
483
328
|
return this;
|
|
484
329
|
}
|
|
485
|
-
/**
|
|
486
|
-
* Add OR condition to existing WHERE clause
|
|
487
|
-
* Combine alternative conditions
|
|
488
|
-
* @param field - Column name
|
|
489
|
-
* @param operator - SQL comparison operator
|
|
490
|
-
* @param value - Value to compare (any type including 0, false)
|
|
491
|
-
* @returns this for method chaining
|
|
492
|
-
*
|
|
493
|
-
* @example
|
|
494
|
-
* table.selectAll()
|
|
495
|
-
* .where('role', '=', 'admin')
|
|
496
|
-
* .or('role', '=', 'moderator')
|
|
497
|
-
* .execute();
|
|
498
|
-
*/
|
|
499
330
|
or(field, operator, value) {
|
|
500
331
|
if (!this.tableFields.includes(field)) {
|
|
501
332
|
throw new Error(`Field/Column: ${field} does not exist in table: ${this.tableName}`);
|
|
@@ -584,26 +415,9 @@ class MangoTable {
|
|
|
584
415
|
return this.query.customQuery(query, supplies);
|
|
585
416
|
}
|
|
586
417
|
}
|
|
587
|
-
/**
|
|
588
|
-
* Mango - Main ORM class for MySQL database operations
|
|
589
|
-
* Manages connection pool and provides table instances
|
|
590
|
-
* Auto-discovers existing tables on connection
|
|
591
|
-
*
|
|
592
|
-
* @example
|
|
593
|
-
* const mango = new Mango();
|
|
594
|
-
* await mango.connect({
|
|
595
|
-
* host: 'localhost',
|
|
596
|
-
* user: 'root',
|
|
597
|
-
* password: 'pass',
|
|
598
|
-
* database: 'mydb'
|
|
599
|
-
* });
|
|
600
|
-
*
|
|
601
|
-
* const users = mango.selectTable('users');
|
|
602
|
-
* const results = await users.selectAll().execute();
|
|
603
|
-
*/
|
|
604
418
|
class Mango {
|
|
605
419
|
constructor() {
|
|
606
|
-
this.tables = [];
|
|
420
|
+
this.tables = [];
|
|
607
421
|
this.query = new MangoQuery();
|
|
608
422
|
}
|
|
609
423
|
async connect({ host, user, password, database, connectionLimit = 10, waitForConnection = true, queueLimit = 0, connectTimeout = 10000, charset = "utf8mb4", }) {
|
|
@@ -640,27 +454,9 @@ class Mango {
|
|
|
640
454
|
});
|
|
641
455
|
});
|
|
642
456
|
}
|
|
643
|
-
/**
|
|
644
|
-
* Get a new MangoType instance for schema building
|
|
645
|
-
* Use when creating or modifying table columns
|
|
646
|
-
* @returns New MangoType instance for chaining
|
|
647
|
-
*
|
|
648
|
-
* @example
|
|
649
|
-
* const idField = mango.types().int().autoIncrement().primaryKey();
|
|
650
|
-
*/
|
|
651
457
|
types() {
|
|
652
458
|
return new MangoType();
|
|
653
459
|
}
|
|
654
|
-
/**
|
|
655
|
-
* Get a table instance by name
|
|
656
|
-
* Returns strongly-typed table if generic provided
|
|
657
|
-
* @param name - Name of the table
|
|
658
|
-
* @returns MangoTable instance for building queries
|
|
659
|
-
*
|
|
660
|
-
* @example
|
|
661
|
-
* interface User { id: number; name: string; email: string }
|
|
662
|
-
* const users = mango.selectTable<User>('users');
|
|
663
|
-
*/
|
|
664
460
|
selectTable(name) {
|
|
665
461
|
for (const table of this.tables) {
|
|
666
462
|
if (table.getName() == name.toLowerCase()) {
|
|
@@ -669,10 +465,6 @@ class Mango {
|
|
|
669
465
|
}
|
|
670
466
|
throw new Error("Table not found: " + name);
|
|
671
467
|
}
|
|
672
|
-
/**
|
|
673
|
-
* Get all discovered table instances
|
|
674
|
-
* @returns Array of all MangoTable instances
|
|
675
|
-
*/
|
|
676
468
|
getTables() {
|
|
677
469
|
return [...this.tables];
|
|
678
470
|
}
|
|
@@ -691,14 +483,12 @@ class Mango {
|
|
|
691
483
|
}
|
|
692
484
|
});
|
|
693
485
|
this.query.query += "\n)";
|
|
694
|
-
// console.log(this.query.query);
|
|
695
486
|
await this.query.execute();
|
|
696
487
|
this.query.query = "";
|
|
697
488
|
this.tables.push(table);
|
|
698
489
|
return table;
|
|
699
490
|
}
|
|
700
491
|
async dropTable(name) {
|
|
701
|
-
// Find and remove from tables array first
|
|
702
492
|
for (let i = 0; i < this.tables.length; i++) {
|
|
703
493
|
if (this.tables[i].getName() === name.toLowerCase()) {
|
|
704
494
|
this.query.query = "DROP TABLE " + name.toLowerCase();
|
|
@@ -929,5 +719,4 @@ class MangoMigration {
|
|
|
929
719
|
}
|
|
930
720
|
}
|
|
931
721
|
;
|
|
932
|
-
export { Mango, MangoType, MangoTable };
|
|
933
|
-
export { MangoMigration };
|
|
722
|
+
export { Mango, MangoType, MangoTable, MangoMigration };
|
|
@@ -4,7 +4,7 @@ import path from "path";
|
|
|
4
4
|
const generateMangoMigrationFile = (migrationFilename, outputDir = './migrations') => {
|
|
5
5
|
const timestamp = Date.now();
|
|
6
6
|
const filepath = path.join(outputDir, `${timestamp}_${migrationFilename}.ts`);
|
|
7
|
-
const template = `import { IMangoMigrationType, Mango } from "
|
|
7
|
+
const template = `import { IMangoMigrationType, Mango } from "mango-orm;
|
|
8
8
|
|
|
9
9
|
export const ${migrationFilename}: IMangoMigrationType = {
|
|
10
10
|
name: "${migrationFilename}",
|
package/package.json
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mango-orm",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A lightweight, type-safe MySQL ORM for Node.js and TypeScript with database migrations",
|
|
6
|
-
"main": "dist/
|
|
7
|
-
"types": "dist/
|
|
6
|
+
"main": "dist/mango.js",
|
|
7
|
+
"types": "dist/mango.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"mango": "./dist/cli.js"
|
|
10
|
+
},
|
|
8
11
|
"scripts": {
|
|
9
12
|
"build": "tsc",
|
|
10
|
-
"
|
|
11
|
-
"test": "tsc && node dist/test/test.js",
|
|
12
|
-
"test:ops": "tsc && node dist/test/test-operations.js",
|
|
13
|
-
"prepublishOnly": "pnpm build",
|
|
14
|
-
"migration:generate": "tsc && node dist/src/cli.js generate",
|
|
15
|
-
"migration:help": "tsc && node dist/src/cli.js help"
|
|
13
|
+
"prepublishOnly": "pnpm build"
|
|
16
14
|
},
|
|
17
15
|
"files": [
|
|
18
|
-
"dist
|
|
16
|
+
"dist",
|
|
19
17
|
"README.md",
|
|
20
18
|
"LICENSE"
|
|
21
19
|
],
|
package/dist/src/mango.d.ts
DELETED
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
import * as sql from "mysql";
|
|
2
|
-
/**
|
|
3
|
-
* MangoType - Schema builder for defining table column types
|
|
4
|
-
* Provides chainable methods to build SQL column definitions
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* const type = new MangoType();
|
|
8
|
-
* type.varchar(255).notNull().unique();
|
|
9
|
-
*/
|
|
10
|
-
declare class MangoType {
|
|
11
|
-
private query;
|
|
12
|
-
constructor();
|
|
13
|
-
/** Define an INT column */
|
|
14
|
-
int(): this;
|
|
15
|
-
/** Define a BIGINT column */
|
|
16
|
-
bigInt(): this;
|
|
17
|
-
/** Define a FLOAT column */
|
|
18
|
-
float(): this;
|
|
19
|
-
/**
|
|
20
|
-
* Define a CHAR column with fixed length
|
|
21
|
-
* @param length - The fixed character length
|
|
22
|
-
*/
|
|
23
|
-
char(length: number): this;
|
|
24
|
-
/** Define a TEXT column for large text data */
|
|
25
|
-
text(): this;
|
|
26
|
-
/** Define a DATE column (YYYY-MM-DD) */
|
|
27
|
-
date(): this;
|
|
28
|
-
/** Define a DATETIME column (YYYY-MM-DD HH:MM:SS) */
|
|
29
|
-
dateTime(): this;
|
|
30
|
-
/** Define a TIMESTAMP column (auto-updated on changes) */
|
|
31
|
-
timeStamp(): this;
|
|
32
|
-
/** Define a BOOLEAN column (stored as TINYINT(1)) */
|
|
33
|
-
boolean(): this;
|
|
34
|
-
/**
|
|
35
|
-
* Define a TINYINT column
|
|
36
|
-
* @param length - Display width (e.g., TINYINT(1))
|
|
37
|
-
*/
|
|
38
|
-
tinyInt(length: number): this;
|
|
39
|
-
/** Make column auto-incrementing (use with INT/BIGINT) */
|
|
40
|
-
autoIncrement(): this;
|
|
41
|
-
/** Mark column as primary key */
|
|
42
|
-
primaryKey(): this;
|
|
43
|
-
/**
|
|
44
|
-
* Define a VARCHAR column with variable length
|
|
45
|
-
* @param length - Maximum character length (e.g., 255)
|
|
46
|
-
*/
|
|
47
|
-
varchar(length: number): this;
|
|
48
|
-
/** Make column NOT NULL (required field) */
|
|
49
|
-
notNull(): this;
|
|
50
|
-
/** Add UNIQUE constraint (no duplicate values) */
|
|
51
|
-
unique(): this;
|
|
52
|
-
/** Get the built SQL column definition */
|
|
53
|
-
getQuery(): string;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* MangoQuery - Internal query executor
|
|
57
|
-
* Handles SQL query execution and prepared statements
|
|
58
|
-
* Automatically resets state after execution to prevent query contamination
|
|
59
|
-
*/
|
|
60
|
-
declare class MangoQuery {
|
|
61
|
-
private db;
|
|
62
|
-
query: string;
|
|
63
|
-
supplies: any;
|
|
64
|
-
/**
|
|
65
|
-
* Configure the database connection pool
|
|
66
|
-
* @param db - MySQL connection pool instance
|
|
67
|
-
*/
|
|
68
|
-
config(db: sql.Pool): void;
|
|
69
|
-
/**
|
|
70
|
-
* Execute the built query with prepared statements
|
|
71
|
-
* Automatically resets query and supplies after execution
|
|
72
|
-
* @returns Promise resolving to query results
|
|
73
|
-
*/
|
|
74
|
-
execute<T>(): Promise<T>;
|
|
75
|
-
/**
|
|
76
|
-
* Execute a custom SQL query with parameters
|
|
77
|
-
* Use for complex queries not covered by the query builder
|
|
78
|
-
* @param query - Raw SQL query string
|
|
79
|
-
* @param supplies - Array of parameter values
|
|
80
|
-
* @returns Promise resolving to query results
|
|
81
|
-
*/
|
|
82
|
-
customQuery<T>(query: string, supplies: any[]): Promise<T>;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* MangoTable<T> - Main query builder class for table operations
|
|
86
|
-
* Provides chainable methods for building SQL queries
|
|
87
|
-
* Generic type T represents the shape of table rows
|
|
88
|
-
*
|
|
89
|
-
* @example
|
|
90
|
-
* const users = new MangoTable(db, 'users', ['id', 'name', 'email']);
|
|
91
|
-
* const result = await users.selectAll().where('id', '=', 1).execute();
|
|
92
|
-
*/
|
|
93
|
-
declare class MangoTable<T> {
|
|
94
|
-
private db;
|
|
95
|
-
private tableName;
|
|
96
|
-
private tableFields;
|
|
97
|
-
private query;
|
|
98
|
-
/**
|
|
99
|
-
* Create a new table instance
|
|
100
|
-
* @param db - MySQL connection pool
|
|
101
|
-
* @param name - Table name (no spaces allowed)
|
|
102
|
-
* @param fields - Array of column names in the table
|
|
103
|
-
*/
|
|
104
|
-
constructor(db: sql.Pool, name: string, fields?: string[]);
|
|
105
|
-
/**
|
|
106
|
-
* Add new columns to an existing table
|
|
107
|
-
* Updates internal field list for validation
|
|
108
|
-
* @param fields - Object mapping column names to MangoType definitions
|
|
109
|
-
* @returns this for method chaining
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* table.addColumns({
|
|
113
|
-
* age: mango.types().int().notNull(),
|
|
114
|
-
* status: mango.types().varchar(50)
|
|
115
|
-
* }).execute();
|
|
116
|
-
*/
|
|
117
|
-
addColumns(fields: Record<string, MangoType>): this;
|
|
118
|
-
/**
|
|
119
|
-
* Remove columns from the table
|
|
120
|
-
* Validates columns exist before removal
|
|
121
|
-
* @param fields - Array of column names to remove
|
|
122
|
-
* @returns this for method chaining
|
|
123
|
-
*
|
|
124
|
-
* @example
|
|
125
|
-
* table.removeColumns(['old_field', 'deprecated_col']).execute();
|
|
126
|
-
*/
|
|
127
|
-
removeColumns(fields: string[]): this;
|
|
128
|
-
/**
|
|
129
|
-
* Select all columns from the table
|
|
130
|
-
* @returns this for method chaining
|
|
131
|
-
*
|
|
132
|
-
* @example
|
|
133
|
-
* await table.selectAll().where('active', '=', true).execute();
|
|
134
|
-
*/
|
|
135
|
-
selectAll(): this;
|
|
136
|
-
/**
|
|
137
|
-
* Select specific columns from the table
|
|
138
|
-
* Validates all columns exist before building query
|
|
139
|
-
* @param columns - Array of column names to select
|
|
140
|
-
* @returns this for method chaining
|
|
141
|
-
*
|
|
142
|
-
* @example
|
|
143
|
-
* await table.selectColumns(['id', 'name', 'email']).execute();
|
|
144
|
-
*/
|
|
145
|
-
selectColumns(columns: string[]): this;
|
|
146
|
-
selectDistinctColumns(columns: string[]): this;
|
|
147
|
-
orderBy(columnName: string): this;
|
|
148
|
-
sort(sort?: number): this;
|
|
149
|
-
limit(length: number): this;
|
|
150
|
-
offset(length: number): this;
|
|
151
|
-
insertOne(data: Record<string, any>): this;
|
|
152
|
-
insertMany(fields: string[], data?: any[][]): this;
|
|
153
|
-
getFields(): string[];
|
|
154
|
-
getName(): string;
|
|
155
|
-
truncate(): this;
|
|
156
|
-
/**
|
|
157
|
-
* Add WHERE clause to filter query results
|
|
158
|
-
* Use with comparison operators to filter rows
|
|
159
|
-
* Supports falsy values (0, false, empty string)
|
|
160
|
-
* @param field - Column name to filter on
|
|
161
|
-
* @param operator - SQL comparison operator (=, !=, <, >, LIKE, etc.)
|
|
162
|
-
* @param value - Value to compare against (any type)
|
|
163
|
-
* @returns this for method chaining
|
|
164
|
-
*
|
|
165
|
-
* @example
|
|
166
|
-
* table.selectAll().where('age', '>=', 18).execute();
|
|
167
|
-
* table.selectAll().where('active', '=', false).execute(); // Works with false!
|
|
168
|
-
* table.selectAll().where('count', '=', 0).execute(); // Works with 0!
|
|
169
|
-
*/
|
|
170
|
-
where(field: string, operator: string, value: any): this;
|
|
171
|
-
/**
|
|
172
|
-
* Add AND condition to existing WHERE clause
|
|
173
|
-
* Chain multiple conditions together
|
|
174
|
-
* @param field - Column name
|
|
175
|
-
* @param operator - SQL comparison operator
|
|
176
|
-
* @param value - Value to compare (any type including 0, false)
|
|
177
|
-
* @returns this for method chaining
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* table.selectAll()
|
|
181
|
-
* .where('age', '>=', 18)
|
|
182
|
-
* .and('active', '=', true)
|
|
183
|
-
* .execute();
|
|
184
|
-
*/
|
|
185
|
-
and(field: string, operator: string, value: any): this;
|
|
186
|
-
/**
|
|
187
|
-
* Add OR condition to existing WHERE clause
|
|
188
|
-
* Combine alternative conditions
|
|
189
|
-
* @param field - Column name
|
|
190
|
-
* @param operator - SQL comparison operator
|
|
191
|
-
* @param value - Value to compare (any type including 0, false)
|
|
192
|
-
* @returns this for method chaining
|
|
193
|
-
*
|
|
194
|
-
* @example
|
|
195
|
-
* table.selectAll()
|
|
196
|
-
* .where('role', '=', 'admin')
|
|
197
|
-
* .or('role', '=', 'moderator')
|
|
198
|
-
* .execute();
|
|
199
|
-
*/
|
|
200
|
-
or(field: string, operator: string, value: any): this;
|
|
201
|
-
update(data: Record<string, any>): this;
|
|
202
|
-
join(type: 'INNER' | 'LEFT' | 'RIGHT' | 'FULL', table: string, condition: {
|
|
203
|
-
left: string;
|
|
204
|
-
operator: string;
|
|
205
|
-
right: string;
|
|
206
|
-
}): this;
|
|
207
|
-
delete(): this;
|
|
208
|
-
whereIn(field: string, values: any[]): this;
|
|
209
|
-
whereNotIn(field: string, values: any[]): this;
|
|
210
|
-
getQuery(): MangoQuery;
|
|
211
|
-
execute(): Promise<T[]>;
|
|
212
|
-
customQuery<Type>(query: string, supplies: any[]): Promise<Type[]>;
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Mango - Main ORM class for MySQL database operations
|
|
216
|
-
* Manages connection pool and provides table instances
|
|
217
|
-
* Auto-discovers existing tables on connection
|
|
218
|
-
*
|
|
219
|
-
* @example
|
|
220
|
-
* const mango = new Mango();
|
|
221
|
-
* await mango.connect({
|
|
222
|
-
* host: 'localhost',
|
|
223
|
-
* user: 'root',
|
|
224
|
-
* password: 'pass',
|
|
225
|
-
* database: 'mydb'
|
|
226
|
-
* });
|
|
227
|
-
*
|
|
228
|
-
* const users = mango.selectTable('users');
|
|
229
|
-
* const results = await users.selectAll().execute();
|
|
230
|
-
*/
|
|
231
|
-
declare class Mango {
|
|
232
|
-
private db;
|
|
233
|
-
private tables;
|
|
234
|
-
private query;
|
|
235
|
-
connect({ host, user, password, database, connectionLimit, waitForConnection, queueLimit, connectTimeout, charset, }: {
|
|
236
|
-
host: any;
|
|
237
|
-
user: any;
|
|
238
|
-
password: any;
|
|
239
|
-
database: any;
|
|
240
|
-
connectionLimit?: number;
|
|
241
|
-
waitForConnection?: boolean;
|
|
242
|
-
queueLimit?: number;
|
|
243
|
-
connectTimeout?: number;
|
|
244
|
-
charset?: string;
|
|
245
|
-
}): Promise<this>;
|
|
246
|
-
disconnect(): Promise<void>;
|
|
247
|
-
/**
|
|
248
|
-
* Get a new MangoType instance for schema building
|
|
249
|
-
* Use when creating or modifying table columns
|
|
250
|
-
* @returns New MangoType instance for chaining
|
|
251
|
-
*
|
|
252
|
-
* @example
|
|
253
|
-
* const idField = mango.types().int().autoIncrement().primaryKey();
|
|
254
|
-
*/
|
|
255
|
-
types(): MangoType;
|
|
256
|
-
/**
|
|
257
|
-
* Get a table instance by name
|
|
258
|
-
* Returns strongly-typed table if generic provided
|
|
259
|
-
* @param name - Name of the table
|
|
260
|
-
* @returns MangoTable instance for building queries
|
|
261
|
-
*
|
|
262
|
-
* @example
|
|
263
|
-
* interface User { id: number; name: string; email: string }
|
|
264
|
-
* const users = mango.selectTable<User>('users');
|
|
265
|
-
*/
|
|
266
|
-
selectTable<T = any>(name: string): MangoTable<T>;
|
|
267
|
-
/**
|
|
268
|
-
* Get all discovered table instances
|
|
269
|
-
* @returns Array of all MangoTable instances
|
|
270
|
-
*/
|
|
271
|
-
getTables(): MangoTable<any>[];
|
|
272
|
-
createTable<T>(name: string, fields: Record<string, MangoType>): Promise<MangoTable<T>>;
|
|
273
|
-
dropTable(name: string): Promise<void>;
|
|
274
|
-
haveTable(name: string): boolean;
|
|
275
|
-
customQuery<Type>(query: string, supplies: any[]): Promise<Type>;
|
|
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
|
-
}
|
|
301
|
-
export { Mango, MangoType, MangoTable };
|
|
302
|
-
export { MangoMigration, IMangoMigrationType };
|
|
File without changes
|
|
File without changes
|