ilana-orm 1.0.17 → 1.0.19
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 +293 -37
- package/cli/ilana.js +60 -158
- package/database/connection.d.ts +3 -0
- package/database/connection.js +40 -1
- package/database/schema-builder.js +4 -0
- package/ilana.config.js +1 -1
- package/index.d.ts +17 -0
- package/index.edge.js +10 -0
- package/index.edge.mjs +37 -0
- package/index.js +6 -2
- package/index.mjs +2 -0
- package/jest.config.js +4 -0
- package/orm/Errors.js +18 -0
- package/orm/F.js +22 -0
- package/orm/Factory.js +49 -12
- package/orm/MigrationRunner.js +16 -48
- package/orm/Model.d.ts +25 -1
- package/orm/Model.js +219 -19
- package/orm/QueryBuilder.d.ts +18 -0
- package/orm/QueryBuilder.js +109 -3
- package/package.json +6 -1
package/cli/ilana.js
CHANGED
|
@@ -127,7 +127,10 @@ import Database from 'ilana-orm/database/connection.js';
|
|
|
127
127
|
const config = {
|
|
128
128
|
default: process.env.DB_CONNECTION || 'mysql',
|
|
129
129
|
timezone: process.env.DB_TIMEZONE || 'UTC',
|
|
130
|
-
|
|
130
|
+
|
|
131
|
+
// Set to true (or use process.env.NODE_ENV === 'development') to log all SQL queries
|
|
132
|
+
logging: false,
|
|
133
|
+
|
|
131
134
|
connections: {
|
|
132
135
|
sqlite: {
|
|
133
136
|
client: 'sqlite3',
|
|
@@ -136,7 +139,7 @@ const config = {
|
|
|
136
139
|
},
|
|
137
140
|
useNullAsDefault: true
|
|
138
141
|
},
|
|
139
|
-
|
|
142
|
+
|
|
140
143
|
mysql: {
|
|
141
144
|
client: 'mysql2',
|
|
142
145
|
connection: {
|
|
@@ -148,7 +151,7 @@ const config = {
|
|
|
148
151
|
timezone: process.env.DB_TIMEZONE || 'UTC'
|
|
149
152
|
}
|
|
150
153
|
},
|
|
151
|
-
|
|
154
|
+
|
|
152
155
|
postgres: {
|
|
153
156
|
client: 'pg',
|
|
154
157
|
connection: {
|
|
@@ -160,12 +163,12 @@ const config = {
|
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
},
|
|
163
|
-
|
|
166
|
+
|
|
164
167
|
migrations: {
|
|
165
168
|
directory: './${structure.databaseDir}/migrations',
|
|
166
169
|
tableName: 'migrations'
|
|
167
170
|
},
|
|
168
|
-
|
|
171
|
+
|
|
169
172
|
seeds: {
|
|
170
173
|
directory: './${structure.databaseDir}/seeds'
|
|
171
174
|
}
|
|
@@ -186,7 +189,10 @@ const Database = require('ilana-orm/database/connection');
|
|
|
186
189
|
const config = {
|
|
187
190
|
default: process.env.DB_CONNECTION || 'mysql',
|
|
188
191
|
timezone: process.env.DB_TIMEZONE || 'UTC',
|
|
189
|
-
|
|
192
|
+
|
|
193
|
+
// Set to true (or use process.env.NODE_ENV === 'development') to log all SQL queries
|
|
194
|
+
logging: false,
|
|
195
|
+
|
|
190
196
|
connections: {
|
|
191
197
|
sqlite: {
|
|
192
198
|
client: 'sqlite3',
|
|
@@ -195,7 +201,7 @@ const config = {
|
|
|
195
201
|
},
|
|
196
202
|
useNullAsDefault: true
|
|
197
203
|
},
|
|
198
|
-
|
|
204
|
+
|
|
199
205
|
mysql: {
|
|
200
206
|
client: 'mysql2',
|
|
201
207
|
connection: {
|
|
@@ -207,7 +213,7 @@ const config = {
|
|
|
207
213
|
timezone: process.env.DB_TIMEZONE || 'UTC'
|
|
208
214
|
}
|
|
209
215
|
},
|
|
210
|
-
|
|
216
|
+
|
|
211
217
|
postgres: {
|
|
212
218
|
client: 'pg',
|
|
213
219
|
connection: {
|
|
@@ -219,12 +225,12 @@ const config = {
|
|
|
219
225
|
}
|
|
220
226
|
}
|
|
221
227
|
},
|
|
222
|
-
|
|
228
|
+
|
|
223
229
|
migrations: {
|
|
224
230
|
directory: './${structure.databaseDir}/migrations',
|
|
225
231
|
tableName: 'migrations'
|
|
226
232
|
},
|
|
227
|
-
|
|
233
|
+
|
|
228
234
|
seeds: {
|
|
229
235
|
directory: './${structure.databaseDir}/seeds'
|
|
230
236
|
}
|
|
@@ -277,90 +283,20 @@ function getModelTemplate(className, tableName) {
|
|
|
277
283
|
|
|
278
284
|
if (isTypeScriptProject()) {
|
|
279
285
|
return `import Model from 'ilana-orm/orm/Model';
|
|
280
|
-
// import { MoneyCast, EncryptedCast } from 'ilana-orm/orm/CustomCasts';
|
|
281
286
|
|
|
282
287
|
export default class ${className} extends Model {
|
|
283
288
|
protected static table = '${tableName}';
|
|
284
|
-
protected static
|
|
285
|
-
protected static softDeletes = false;
|
|
286
|
-
|
|
287
|
-
// For UUID primary keys, uncomment:
|
|
288
|
-
// protected static keyType = 'string' as const;
|
|
289
|
-
// protected static incrementing = false;
|
|
290
|
-
|
|
291
|
-
protected fillable: string[] = [];
|
|
292
|
-
protected hidden: string[] = [];
|
|
293
|
-
protected appends: string[] = [];
|
|
294
|
-
protected casts = {
|
|
295
|
-
// Basic casts
|
|
296
|
-
// is_active: 'boolean' as const,
|
|
297
|
-
// metadata: 'json' as const,
|
|
298
|
-
// tags: 'array' as const,
|
|
299
|
-
|
|
300
|
-
// Custom casts
|
|
301
|
-
// price: new MoneyCast(),
|
|
302
|
-
// secret: new EncryptedCast('your-key'),
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
// Define relationships here
|
|
306
|
-
// example() {
|
|
307
|
-
// return this.hasMany(RelatedModel, 'foreign_key');
|
|
308
|
-
// }
|
|
309
|
-
|
|
310
|
-
// Define scopes here
|
|
311
|
-
// static scopeActive(query: any) {
|
|
312
|
-
// query.where('is_active', true);
|
|
313
|
-
// }
|
|
314
|
-
|
|
315
|
-
// Register for polymorphic relationships
|
|
316
|
-
// static {
|
|
317
|
-
// this.register();
|
|
318
|
-
// }
|
|
289
|
+
protected static fillable: string[] = [];
|
|
319
290
|
}
|
|
320
291
|
`;
|
|
321
292
|
}
|
|
322
293
|
|
|
323
294
|
if (isESModule) {
|
|
324
295
|
return `import Model from 'ilana-orm/orm/Model';
|
|
325
|
-
// import { MoneyCast, EncryptedCast } from 'ilana-orm/orm/CustomCasts';
|
|
326
296
|
|
|
327
297
|
class ${className} extends Model {
|
|
328
298
|
static table = '${tableName}';
|
|
329
|
-
static
|
|
330
|
-
static softDeletes = false;
|
|
331
|
-
|
|
332
|
-
// For UUID primary keys, uncomment:
|
|
333
|
-
// static keyType = 'string';
|
|
334
|
-
// static incrementing = false;
|
|
335
|
-
|
|
336
|
-
fillable = [];
|
|
337
|
-
hidden = [];
|
|
338
|
-
appends = [];
|
|
339
|
-
casts = {
|
|
340
|
-
// Basic casts
|
|
341
|
-
// is_active: 'boolean',
|
|
342
|
-
// metadata: 'json',
|
|
343
|
-
// tags: 'array',
|
|
344
|
-
|
|
345
|
-
// Custom casts
|
|
346
|
-
// price: new MoneyCast(),
|
|
347
|
-
// secret: new EncryptedCast('your-key'),
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
// Define relationships here
|
|
351
|
-
// example() {
|
|
352
|
-
// return this.hasMany(RelatedModel, 'foreign_key');
|
|
353
|
-
// }
|
|
354
|
-
|
|
355
|
-
// Define scopes here
|
|
356
|
-
// static scopeActive(query) {
|
|
357
|
-
// query.where('is_active', true);
|
|
358
|
-
// }
|
|
359
|
-
|
|
360
|
-
// Register for polymorphic relationships
|
|
361
|
-
// static {
|
|
362
|
-
// this.register();
|
|
363
|
-
// }
|
|
299
|
+
static fillable = [];
|
|
364
300
|
}
|
|
365
301
|
|
|
366
302
|
export default ${className};
|
|
@@ -368,45 +304,10 @@ export default ${className};
|
|
|
368
304
|
}
|
|
369
305
|
|
|
370
306
|
return `const Model = require('ilana-orm/orm/Model');
|
|
371
|
-
// const { MoneyCast, EncryptedCast } = require('ilana-orm/orm/CustomCasts');
|
|
372
307
|
|
|
373
308
|
class ${className} extends Model {
|
|
374
309
|
static table = '${tableName}';
|
|
375
|
-
static
|
|
376
|
-
static softDeletes = false;
|
|
377
|
-
|
|
378
|
-
// For UUID primary keys, uncomment:
|
|
379
|
-
// static keyType = 'string';
|
|
380
|
-
// static incrementing = false;
|
|
381
|
-
|
|
382
|
-
fillable = [];
|
|
383
|
-
hidden = [];
|
|
384
|
-
appends = [];
|
|
385
|
-
casts = {
|
|
386
|
-
// Basic casts
|
|
387
|
-
// is_active: 'boolean',
|
|
388
|
-
// metadata: 'json',
|
|
389
|
-
// tags: 'array',
|
|
390
|
-
|
|
391
|
-
// Custom casts
|
|
392
|
-
// price: new MoneyCast(),
|
|
393
|
-
// secret: new EncryptedCast('your-key'),
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
// Define relationships here
|
|
397
|
-
// example() {
|
|
398
|
-
// return this.hasMany(RelatedModel, 'foreign_key');
|
|
399
|
-
// }
|
|
400
|
-
|
|
401
|
-
// Define scopes here
|
|
402
|
-
// static scopeActive(query) {
|
|
403
|
-
// query.where('is_active', true);
|
|
404
|
-
// }
|
|
405
|
-
|
|
406
|
-
// Register for polymorphic relationships
|
|
407
|
-
// static {
|
|
408
|
-
// this.register();
|
|
409
|
-
// }
|
|
310
|
+
static fillable = [];
|
|
410
311
|
}
|
|
411
312
|
|
|
412
313
|
module.exports = ${className};
|
|
@@ -421,11 +322,7 @@ function getPivotModelTemplate(className, tableName) {
|
|
|
421
322
|
|
|
422
323
|
export default class ${className} extends Model {
|
|
423
324
|
protected static table = '${tableName}';
|
|
424
|
-
protected static
|
|
425
|
-
|
|
426
|
-
protected fillable: string[] = [];
|
|
427
|
-
|
|
428
|
-
// Define pivot relationships here
|
|
325
|
+
protected static fillable: string[] = [];
|
|
429
326
|
}
|
|
430
327
|
`;
|
|
431
328
|
}
|
|
@@ -435,11 +332,7 @@ export default class ${className} extends Model {
|
|
|
435
332
|
|
|
436
333
|
class ${className} extends Model {
|
|
437
334
|
static table = '${tableName}';
|
|
438
|
-
static
|
|
439
|
-
|
|
440
|
-
fillable = [];
|
|
441
|
-
|
|
442
|
-
// Define pivot relationships here
|
|
335
|
+
static fillable = [];
|
|
443
336
|
}
|
|
444
337
|
|
|
445
338
|
export default ${className};
|
|
@@ -450,11 +343,7 @@ export default ${className};
|
|
|
450
343
|
|
|
451
344
|
class ${className} extends Model {
|
|
452
345
|
static table = '${tableName}';
|
|
453
|
-
static
|
|
454
|
-
|
|
455
|
-
fillable = [];
|
|
456
|
-
|
|
457
|
-
// Define pivot relationships here
|
|
346
|
+
static fillable = [];
|
|
458
347
|
}
|
|
459
348
|
|
|
460
349
|
module.exports = ${className};
|
|
@@ -471,29 +360,27 @@ function generateFactory(className) {
|
|
|
471
360
|
}
|
|
472
361
|
|
|
473
362
|
const modelPath = structure.hasSrc ? `../models/${className}.js` : `../../models/${className}.js`;
|
|
363
|
+
const isESModule = isESModuleProject();
|
|
474
364
|
const template = isTypeScriptProject() ?
|
|
475
365
|
`import { defineFactory } from 'ilana-orm/orm/Factory.js';
|
|
476
366
|
import ${className} from '${modelPath}';
|
|
477
367
|
|
|
478
368
|
export default defineFactory(${className}, (faker) => ({
|
|
479
|
-
// Define your factory attributes here
|
|
480
369
|
// name: faker.person.fullName(),
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
370
|
+
}));
|
|
371
|
+
` : isESModule ?
|
|
372
|
+
`import { defineFactory } from 'ilana-orm/orm/Factory';
|
|
373
|
+
import ${className} from '${modelPath}';
|
|
374
|
+
|
|
375
|
+
export default defineFactory(${className}, (faker) => ({
|
|
376
|
+
// name: faker.person.fullName(),
|
|
485
377
|
}));
|
|
486
378
|
` :
|
|
487
379
|
`const { defineFactory } = require('ilana-orm/orm/Factory');
|
|
488
380
|
const ${className} = require('${modelPath.replace('.js', '')}');
|
|
489
381
|
|
|
490
382
|
module.exports = defineFactory(${className}, (faker) => ({
|
|
491
|
-
// Define your factory attributes here
|
|
492
383
|
// name: faker.person.fullName(),
|
|
493
|
-
// email: faker.internet.email(),
|
|
494
|
-
}))
|
|
495
|
-
.state('example', (faker) => ({
|
|
496
|
-
// Define state modifications here
|
|
497
384
|
}));
|
|
498
385
|
`;
|
|
499
386
|
|
|
@@ -511,34 +398,38 @@ function generateSeeder(className) {
|
|
|
511
398
|
}
|
|
512
399
|
|
|
513
400
|
const modelPath = structure.hasSrc ? `../models/${className}.js` : `../../models/${className}.js`;
|
|
401
|
+
const isESModule = isESModuleProject();
|
|
514
402
|
const template = isTypeScriptProject() ?
|
|
515
403
|
`import Seeder from 'ilana-orm/orm/Seeder.js';
|
|
404
|
+
import { factory } from 'ilana-orm/orm/Factory.js';
|
|
516
405
|
import ${className} from '${modelPath}';
|
|
517
406
|
import '../factories/${className}Factory.js';
|
|
518
407
|
|
|
519
408
|
export default class ${className}Seeder extends Seeder {
|
|
520
409
|
async run(): Promise<void> {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
410
|
+
await factory(${className}).times(10).create();
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
` : isESModule ?
|
|
414
|
+
`import Seeder from 'ilana-orm/orm/Seeder';
|
|
415
|
+
import { factory } from 'ilana-orm/orm/Factory';
|
|
416
|
+
import ${className} from '${modelPath}';
|
|
417
|
+
import '../factories/${className}Factory.js';
|
|
525
418
|
|
|
526
|
-
|
|
419
|
+
export default class ${className}Seeder extends Seeder {
|
|
420
|
+
async run() {
|
|
421
|
+
await factory(${className}).times(10).create();
|
|
527
422
|
}
|
|
528
423
|
}
|
|
529
424
|
` :
|
|
530
425
|
`const Seeder = require('ilana-orm/orm/Seeder');
|
|
426
|
+
const { factory } = require('ilana-orm/orm/Factory');
|
|
531
427
|
const ${className} = require('${modelPath.replace('.js', '')}');
|
|
532
428
|
require('../factories/${className}Factory');
|
|
533
429
|
|
|
534
430
|
class ${className}Seeder extends Seeder {
|
|
535
431
|
async run() {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
// Create sample data
|
|
539
|
-
await ${className}.factory().times(10).create();
|
|
540
|
-
|
|
541
|
-
console.log('${className}s seeded successfully');
|
|
432
|
+
await factory(${className}).times(10).create();
|
|
542
433
|
}
|
|
543
434
|
}
|
|
544
435
|
|
|
@@ -823,13 +714,13 @@ function parseMigrationsForTable(tableName, migrationsDir) {
|
|
|
823
714
|
|
|
824
715
|
// Match column definitions: table.string('col'), table.integer('col').nullable(), etc.
|
|
825
716
|
const colRegex = new RegExp(
|
|
826
|
-
`${alias}\\.(\\w+)\\s*\\(\\s*['"]([^'"]+)['"](
|
|
717
|
+
`${alias}\\.(\\w+)\\s*\\(\\s*['"]([^'"]+)['"]([^)]*)\\)([^;\\n]*)`,
|
|
827
718
|
'g'
|
|
828
719
|
);
|
|
829
720
|
|
|
830
721
|
let colMatch;
|
|
831
722
|
while ((colMatch = colRegex.exec(block)) !== null) {
|
|
832
|
-
const [, method, colName, rest] = colMatch;
|
|
723
|
+
const [, method, colName, args, rest] = colMatch;
|
|
833
724
|
const knexDef = KNEX_COLUMN_MAP[method];
|
|
834
725
|
if (!knexDef) continue;
|
|
835
726
|
|
|
@@ -837,7 +728,17 @@ function parseMigrationsForTable(tableName, migrationsDir) {
|
|
|
837
728
|
const isNotNullable = /\.notNullable\(\)/.test(rest);
|
|
838
729
|
const nullable = isNullable ? true : isNotNullable ? false : knexDef.nullable;
|
|
839
730
|
|
|
840
|
-
columns
|
|
731
|
+
// For enum columns, extract the values array and build a union type
|
|
732
|
+
let tsType = knexDef.type;
|
|
733
|
+
if (method === 'enum') {
|
|
734
|
+
const valuesMatch = args.match(/\[([^\]]+)\]/);
|
|
735
|
+
if (valuesMatch) {
|
|
736
|
+
const values = [...valuesMatch[1].matchAll(/['"]([^'"]+)['"]/g)].map(m => `'${m[1]}'`);
|
|
737
|
+
if (values.length) tsType = values.join(' | ');
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
columns[colName] = { type: tsType, nullable };
|
|
841
742
|
}
|
|
842
743
|
}
|
|
843
744
|
}
|
|
@@ -1574,4 +1475,5 @@ if (require.main === module) {
|
|
|
1574
1475
|
main();
|
|
1575
1476
|
}
|
|
1576
1477
|
|
|
1577
|
-
module.exports = commands;
|
|
1478
|
+
module.exports = commands;
|
|
1479
|
+
module.exports._templates = { getModelTemplate, getPivotModelTemplate };
|
package/database/connection.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Knex } from 'knex';
|
|
|
2
2
|
|
|
3
3
|
export interface DatabaseConfig {
|
|
4
4
|
default: string;
|
|
5
|
+
logging?: boolean;
|
|
5
6
|
connections: {
|
|
6
7
|
[name: string]: Knex.Config;
|
|
7
8
|
};
|
|
@@ -27,6 +28,8 @@ export default class Database {
|
|
|
27
28
|
private static _currentTransaction: Knex.Transaction | null;
|
|
28
29
|
|
|
29
30
|
static configure(config: DatabaseConfig): void;
|
|
31
|
+
static enableLogging(): void;
|
|
32
|
+
static disableLogging(): void;
|
|
30
33
|
static connection(name?: string): Knex;
|
|
31
34
|
static getDefaultConnection(): string;
|
|
32
35
|
static hasConnection(name: string): boolean;
|
package/database/connection.js
CHANGED
|
@@ -3,11 +3,33 @@ const knex = require('knex');
|
|
|
3
3
|
class Database {
|
|
4
4
|
static connections = new Map();
|
|
5
5
|
static _currentTransaction = null;
|
|
6
|
+
static _logging = false;
|
|
7
|
+
|
|
8
|
+
static enableLogging() {
|
|
9
|
+
this._logging = true;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static disableLogging() {
|
|
13
|
+
this._logging = false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static _log(sql, bindings, ms) {
|
|
17
|
+
if (!this._logging) return;
|
|
18
|
+
const bound = sql.replace(/\?/g, () => {
|
|
19
|
+
const val = bindings?.shift();
|
|
20
|
+
if (val === null || val === undefined) return 'NULL';
|
|
21
|
+
if (typeof val === 'string') return `'${val}'`;
|
|
22
|
+
return val;
|
|
23
|
+
});
|
|
24
|
+
const time = ms !== undefined ? ` \x1b[90m— ${ms}ms\x1b[0m` : '';
|
|
25
|
+
console.log(`\x1b[36m[IlanaORM]\x1b[0m ${bound}${time}`);
|
|
26
|
+
}
|
|
6
27
|
|
|
7
28
|
static configure(config) {
|
|
8
29
|
this.config = config;
|
|
9
30
|
this.defaultConnection = config.default;
|
|
10
|
-
|
|
31
|
+
if (config.logging) this._logging = true;
|
|
32
|
+
|
|
11
33
|
// Initialize all configured connections
|
|
12
34
|
for (const [name, connConfig] of Object.entries(config.connections)) {
|
|
13
35
|
try {
|
|
@@ -21,6 +43,23 @@ class Database {
|
|
|
21
43
|
directory: './seeds'
|
|
22
44
|
}
|
|
23
45
|
});
|
|
46
|
+
|
|
47
|
+
// Attach query logger
|
|
48
|
+
connection.on('query', (query) => {
|
|
49
|
+
this._queryStart = Date.now();
|
|
50
|
+
this._pendingQuery = query.sql;
|
|
51
|
+
this._pendingBindings = [...(query.bindings || [])];
|
|
52
|
+
});
|
|
53
|
+
connection.on('query-response', (response, query) => {
|
|
54
|
+
const ms = Date.now() - (this._queryStart || Date.now());
|
|
55
|
+
this._log(query.sql, [...(query.bindings || [])], ms);
|
|
56
|
+
});
|
|
57
|
+
connection.on('query-error', (error, query) => {
|
|
58
|
+
if (this._logging) {
|
|
59
|
+
console.error(`\x1b[36m[IlanaORM]\x1b[0m \x1b[31mERROR\x1b[0m ${query.sql}`);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
24
63
|
this.connections.set(name, connection);
|
|
25
64
|
} catch (error) {
|
|
26
65
|
if (error.code === 'MODULE_NOT_FOUND' && error.message.includes(connConfig.client)) {
|
|
@@ -207,6 +207,10 @@ class SchemaBuilder {
|
|
|
207
207
|
return Promise.resolve();
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
enableVectorExtension() {
|
|
211
|
+
return this.knex.raw('CREATE EXTENSION IF NOT EXISTS vector');
|
|
212
|
+
}
|
|
213
|
+
|
|
210
214
|
createEnum(name, values) {
|
|
211
215
|
if (this.knex.client.config.client === 'pg') {
|
|
212
216
|
return this.knex.raw(`CREATE TYPE ${name} AS ENUM (${values.map(v => `'${v}'`).join(', ')})`);
|
package/ilana.config.js
CHANGED
package/index.d.ts
CHANGED
|
@@ -5,5 +5,22 @@ export { default as Database } from './database/connection';
|
|
|
5
5
|
export * from './orm/Relation';
|
|
6
6
|
export * from './orm/CustomCasts';
|
|
7
7
|
|
|
8
|
+
export declare class FExpression {
|
|
9
|
+
constructor(column: string);
|
|
10
|
+
plus(n: number): any;
|
|
11
|
+
minus(n: number): any;
|
|
12
|
+
times(n: number): any;
|
|
13
|
+
divide(n: number): any;
|
|
14
|
+
}
|
|
15
|
+
export declare function F(column: string): FExpression;
|
|
16
|
+
|
|
17
|
+
export declare class ModelNotFoundException extends Error {
|
|
18
|
+
name: 'ModelNotFoundException';
|
|
19
|
+
model: string;
|
|
20
|
+
id?: any;
|
|
21
|
+
constructor(model: string, id?: any);
|
|
22
|
+
toResponse(): { status: 404; message: string };
|
|
23
|
+
}
|
|
24
|
+
|
|
8
25
|
// Default export
|
|
9
26
|
export { default } from './orm/Model';
|
package/index.edge.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Edge runtime entry point — no auto-loading of ilana.config.js.
|
|
2
|
+
// Use this when running in Cloudflare Workers, Deno, Bun, or Next.js edge routes.
|
|
3
|
+
// You must call Database.configure(config) explicitly before using any models.
|
|
4
|
+
//
|
|
5
|
+
// import { Model, Database } from 'ilana-orm/edge';
|
|
6
|
+
// Database.configure({ default: 'pg', connections: { pg: { ... } } });
|
|
7
|
+
|
|
8
|
+
'use strict';
|
|
9
|
+
global.__ILANA_EDGE__ = true;
|
|
10
|
+
module.exports = require('./index.js');
|
package/index.edge.mjs
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Edge runtime entry point — ESM wrapper.
|
|
2
|
+
// Sets __ILANA_EDGE__ before any model is loaded so the auto-loader is skipped.
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
|
|
6
|
+
globalThis.__ILANA_EDGE__ = true;
|
|
7
|
+
const exports = require('./index.js');
|
|
8
|
+
|
|
9
|
+
export const {
|
|
10
|
+
Model,
|
|
11
|
+
QueryBuilder,
|
|
12
|
+
Collection,
|
|
13
|
+
Database,
|
|
14
|
+
DB,
|
|
15
|
+
SchemaBuilder,
|
|
16
|
+
MigrationRunner,
|
|
17
|
+
Seeder,
|
|
18
|
+
Factory,
|
|
19
|
+
defineFactory,
|
|
20
|
+
ModelNotFoundException,
|
|
21
|
+
F,
|
|
22
|
+
HasOne,
|
|
23
|
+
HasMany,
|
|
24
|
+
BelongsTo,
|
|
25
|
+
BelongsToMany,
|
|
26
|
+
HasManyThrough,
|
|
27
|
+
MorphTo,
|
|
28
|
+
MorphOne,
|
|
29
|
+
MorphMany,
|
|
30
|
+
MoneyCast,
|
|
31
|
+
EncryptedCast,
|
|
32
|
+
JsonCast,
|
|
33
|
+
ArrayCast,
|
|
34
|
+
DateCast,
|
|
35
|
+
} = exports;
|
|
36
|
+
|
|
37
|
+
export default exports.Model;
|
package/index.js
CHANGED
|
@@ -10,6 +10,8 @@ const Seeder = require('./orm/Seeder');
|
|
|
10
10
|
const Factory = require('./orm/Factory');
|
|
11
11
|
const Relation = require('./orm/Relation');
|
|
12
12
|
const CustomCasts = require('./orm/CustomCasts');
|
|
13
|
+
const { ModelNotFoundException } = require('./orm/Errors');
|
|
14
|
+
const { F } = require('./orm/F');
|
|
13
15
|
|
|
14
16
|
module.exports = {
|
|
15
17
|
Model,
|
|
@@ -22,11 +24,13 @@ module.exports = {
|
|
|
22
24
|
Seeder,
|
|
23
25
|
Factory: Factory.Factory,
|
|
24
26
|
defineFactory: Factory.defineFactory,
|
|
25
|
-
|
|
27
|
+
ModelNotFoundException,
|
|
28
|
+
F,
|
|
29
|
+
|
|
26
30
|
// Relationships
|
|
27
31
|
MorphOne: Relation.MorphOne,
|
|
28
32
|
...Relation,
|
|
29
|
-
|
|
33
|
+
|
|
30
34
|
// Custom Casts
|
|
31
35
|
...CustomCasts
|
|
32
36
|
};
|
package/index.mjs
CHANGED
package/jest.config.js
ADDED
package/orm/Errors.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class ModelNotFoundException extends Error {
|
|
2
|
+
constructor(model, id) {
|
|
3
|
+
const message = id !== undefined
|
|
4
|
+
? `${model} with id ${id} not found`
|
|
5
|
+
: `${model} not found`;
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'ModelNotFoundException';
|
|
8
|
+
this.model = model;
|
|
9
|
+
this.id = id;
|
|
10
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, ModelNotFoundException);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
toResponse() {
|
|
14
|
+
return { status: 404, message: this.message };
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = { ModelNotFoundException };
|
package/orm/F.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const Database = require('../database/connection');
|
|
2
|
+
|
|
3
|
+
class FExpression {
|
|
4
|
+
constructor(column) {
|
|
5
|
+
this.column = column;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
_raw(op, n) {
|
|
9
|
+
return Database.raw(`?? ${op} ?`, [this.column, n]);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
plus(n) { return this._raw('+', n); }
|
|
13
|
+
minus(n) { return this._raw('-', n); }
|
|
14
|
+
times(n) { return this._raw('*', n); }
|
|
15
|
+
divide(n) { return this._raw('/', n); }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function F(column) {
|
|
19
|
+
return new FExpression(column);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = { F, FExpression };
|