@3lineas/d1-orm 1.0.4 → 1.0.6

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 CHANGED
@@ -208,6 +208,31 @@ pnpm orm migrate
208
208
 
209
209
  # Remote (Production)
210
210
  pnpm orm migrate --remote
211
+
212
+ # Run migrations and then seed
213
+ pnpm orm migrate --seed
214
+ ```
215
+
216
+ #### Reset Database
217
+
218
+ Drop all tables and re-run all migrations.
219
+
220
+ ```bash
221
+ pnpm orm migrate:fresh
222
+
223
+ # Reset and seed
224
+ pnpm orm migrate:fresh --seed
225
+ ```
226
+
227
+ #### Seed Database
228
+
229
+ Run seeders defined in `database/seeders`.
230
+
231
+ ```bash
232
+ pnpm orm db:seed
233
+
234
+ # Remote
235
+ pnpm orm db:seed --remote
211
236
  ```
212
237
 
213
238
  > **Note:** Local migrations require `wrangler` to be configured and running in your environment.
@@ -0,0 +1,147 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
5
+ var __commonJS = (cb, mod) => function __require() {
6
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
7
+ };
8
+
9
+ // src/core/connection.ts
10
+ var Connection;
11
+ var init_connection = __esm({
12
+ "src/core/connection.ts"() {
13
+ "use strict";
14
+ Connection = class {
15
+ /**
16
+ * The underlying D1Database instance.
17
+ */
18
+ db;
19
+ /**
20
+ * Create a new Connection instance.
21
+ *
22
+ * @param database - The D1Database instance.
23
+ */
24
+ constructor(database) {
25
+ this.db = database;
26
+ }
27
+ /**
28
+ * Execute a SELECT statement.
29
+ *
30
+ * @param query - The SQL query string.
31
+ * @param bindings - The parameter bindings.
32
+ * @returns A promise that resolves to an array of results.
33
+ */
34
+ async select(query, bindings = []) {
35
+ const stmt = this.db.prepare(query).bind(...bindings);
36
+ const result = await stmt.all();
37
+ return result.results || [];
38
+ }
39
+ /**
40
+ * Execute an INSERT statement.
41
+ *
42
+ * @param query - The SQL query string.
43
+ * @param bindings - The parameter bindings.
44
+ * @returns A promise that resolves to true on success.
45
+ */
46
+ async insert(query, bindings = []) {
47
+ const stmt = this.db.prepare(query).bind(...bindings);
48
+ const result = await stmt.run();
49
+ return result.success;
50
+ }
51
+ /**
52
+ * Execute an UPDATE statement.
53
+ *
54
+ * @param query - The SQL query string.
55
+ * @param bindings - The parameter bindings.
56
+ * @returns A promise that resolves to true on success.
57
+ */
58
+ async update(query, bindings = []) {
59
+ const stmt = this.db.prepare(query).bind(...bindings);
60
+ const result = await stmt.run();
61
+ return result.success;
62
+ }
63
+ /**
64
+ * Execute a DELETE statement.
65
+ *
66
+ * @param query - The SQL query string.
67
+ * @param bindings - The parameter bindings.
68
+ * @returns A promise that resolves to true on success.
69
+ */
70
+ async delete(query, bindings = []) {
71
+ const stmt = this.db.prepare(query).bind(...bindings);
72
+ const result = await stmt.run();
73
+ return result.success;
74
+ }
75
+ /**
76
+ * Execute an arbitrary SQL statement.
77
+ *
78
+ * @param query - The SQL query string.
79
+ * @param bindings - The parameter bindings.
80
+ * @returns A promise that resolves to true on success.
81
+ */
82
+ async statement(query, bindings = []) {
83
+ const stmt = this.db.prepare(query).bind(...bindings);
84
+ const result = await stmt.run();
85
+ return result.success;
86
+ }
87
+ };
88
+ }
89
+ });
90
+
91
+ // src/core/database.ts
92
+ var Database;
93
+ var init_database = __esm({
94
+ "src/core/database.ts"() {
95
+ "use strict";
96
+ init_connection();
97
+ Database = class _Database {
98
+ /**
99
+ * The singleton instance of the Database.
100
+ */
101
+ static instance;
102
+ /**
103
+ * The active database connection.
104
+ */
105
+ connection;
106
+ /**
107
+ * Private constructor to enforce singleton pattern.
108
+ *
109
+ * @param d1 - The D1Database instance from Cloudflare.
110
+ */
111
+ constructor(d1) {
112
+ this.connection = new Connection(d1);
113
+ }
114
+ /**
115
+ * Setup the database connection.
116
+ *
117
+ * @param d1 - The D1Database instance from Cloudflare environment (env.DB).
118
+ */
119
+ static setup(d1) {
120
+ _Database.instance = new _Database(d1);
121
+ }
122
+ /**
123
+ * Get the singleton Database instance.
124
+ *
125
+ * @throws Error if setup() has not been called.
126
+ * @returns The Database instance.
127
+ */
128
+ static getInstance() {
129
+ if (!_Database.instance) {
130
+ throw new Error(
131
+ "Database not initialized. Call Database.setup(env.DB) first."
132
+ );
133
+ }
134
+ return _Database.instance;
135
+ }
136
+ };
137
+ }
138
+ });
139
+
140
+ export {
141
+ __esm,
142
+ __commonJS,
143
+ Connection,
144
+ init_connection,
145
+ Database,
146
+ init_database
147
+ };
package/dist/cli/index.js CHANGED
@@ -283,20 +283,281 @@ export const seed = async () => {
283
283
  }
284
284
 
285
285
  // src/cli/commands/migrate.ts
286
+ var fs5 = __toESM(require("fs"));
287
+ var path5 = __toESM(require("path"));
288
+ var import_child_process2 = require("child_process");
289
+
290
+ // src/cli/commands/seed.ts
286
291
  var fs4 = __toESM(require("fs"));
287
292
  var path4 = __toESM(require("path"));
293
+
294
+ // src/core/connection.ts
295
+ var Connection = class {
296
+ /**
297
+ * The underlying D1Database instance.
298
+ */
299
+ db;
300
+ /**
301
+ * Create a new Connection instance.
302
+ *
303
+ * @param database - The D1Database instance.
304
+ */
305
+ constructor(database) {
306
+ this.db = database;
307
+ }
308
+ /**
309
+ * Execute a SELECT statement.
310
+ *
311
+ * @param query - The SQL query string.
312
+ * @param bindings - The parameter bindings.
313
+ * @returns A promise that resolves to an array of results.
314
+ */
315
+ async select(query, bindings = []) {
316
+ const stmt = this.db.prepare(query).bind(...bindings);
317
+ const result = await stmt.all();
318
+ return result.results || [];
319
+ }
320
+ /**
321
+ * Execute an INSERT statement.
322
+ *
323
+ * @param query - The SQL query string.
324
+ * @param bindings - The parameter bindings.
325
+ * @returns A promise that resolves to true on success.
326
+ */
327
+ async insert(query, bindings = []) {
328
+ const stmt = this.db.prepare(query).bind(...bindings);
329
+ const result = await stmt.run();
330
+ return result.success;
331
+ }
332
+ /**
333
+ * Execute an UPDATE statement.
334
+ *
335
+ * @param query - The SQL query string.
336
+ * @param bindings - The parameter bindings.
337
+ * @returns A promise that resolves to true on success.
338
+ */
339
+ async update(query, bindings = []) {
340
+ const stmt = this.db.prepare(query).bind(...bindings);
341
+ const result = await stmt.run();
342
+ return result.success;
343
+ }
344
+ /**
345
+ * Execute a DELETE statement.
346
+ *
347
+ * @param query - The SQL query string.
348
+ * @param bindings - The parameter bindings.
349
+ * @returns A promise that resolves to true on success.
350
+ */
351
+ async delete(query, bindings = []) {
352
+ const stmt = this.db.prepare(query).bind(...bindings);
353
+ const result = await stmt.run();
354
+ return result.success;
355
+ }
356
+ /**
357
+ * Execute an arbitrary SQL statement.
358
+ *
359
+ * @param query - The SQL query string.
360
+ * @param bindings - The parameter bindings.
361
+ * @returns A promise that resolves to true on success.
362
+ */
363
+ async statement(query, bindings = []) {
364
+ const stmt = this.db.prepare(query).bind(...bindings);
365
+ const result = await stmt.run();
366
+ return result.success;
367
+ }
368
+ };
369
+
370
+ // src/core/database.ts
371
+ var Database = class _Database {
372
+ /**
373
+ * The singleton instance of the Database.
374
+ */
375
+ static instance;
376
+ /**
377
+ * The active database connection.
378
+ */
379
+ connection;
380
+ /**
381
+ * Private constructor to enforce singleton pattern.
382
+ *
383
+ * @param d1 - The D1Database instance from Cloudflare.
384
+ */
385
+ constructor(d1) {
386
+ this.connection = new Connection(d1);
387
+ }
388
+ /**
389
+ * Setup the database connection.
390
+ *
391
+ * @param d1 - The D1Database instance from Cloudflare environment (env.DB).
392
+ */
393
+ static setup(d1) {
394
+ _Database.instance = new _Database(d1);
395
+ }
396
+ /**
397
+ * Get the singleton Database instance.
398
+ *
399
+ * @throws Error if setup() has not been called.
400
+ * @returns The Database instance.
401
+ */
402
+ static getInstance() {
403
+ if (!_Database.instance) {
404
+ throw new Error(
405
+ "Database not initialized. Call Database.setup(env.DB) first."
406
+ );
407
+ }
408
+ return _Database.instance;
409
+ }
410
+ };
411
+
412
+ // src/cli/cli-connection.ts
288
413
  var import_child_process = require("child_process");
414
+ var CLIConnection = class {
415
+ constructor(dbName = "DB", isRemote = false) {
416
+ this.dbName = dbName;
417
+ this.isRemote = isRemote;
418
+ }
419
+ prepare(query) {
420
+ return new CLIPREparedStatement(query, this.dbName, this.isRemote);
421
+ }
422
+ async dump() {
423
+ throw new Error("dump() is not supported in CLI mode.");
424
+ }
425
+ async batch(statements) {
426
+ const results = [];
427
+ for (const stmt of statements) {
428
+ results.push(await stmt.run());
429
+ }
430
+ return results;
431
+ }
432
+ async exec(query) {
433
+ const start = Date.now();
434
+ await this.executeWrangler(query);
435
+ return {
436
+ count: 1,
437
+ // Approximation
438
+ duration: Date.now() - start
439
+ };
440
+ }
441
+ executeWrangler(sql) {
442
+ const flag = this.isRemote ? "--remote" : "--local";
443
+ const command2 = `npx wrangler d1 execute ${this.dbName} --command "${sql.replace(/"/g, '\\"')}" ${flag} --json`;
444
+ try {
445
+ const output = (0, import_child_process.execSync)(command2, {
446
+ encoding: "utf-8",
447
+ stdio: ["ignore", "pipe", "inherit"]
448
+ });
449
+ const jsonStart = output.indexOf("[");
450
+ if (jsonStart !== -1) {
451
+ return JSON.parse(output.substring(jsonStart));
452
+ }
453
+ return null;
454
+ } catch (e) {
455
+ console.error(`Error executing wrangler command: ${command2}`);
456
+ throw e;
457
+ }
458
+ }
459
+ };
460
+ var CLIPREparedStatement = class {
461
+ constructor(query, dbName, isRemote) {
462
+ this.query = query;
463
+ this.dbName = dbName;
464
+ this.isRemote = isRemote;
465
+ }
466
+ bindings = [];
467
+ bind(...values) {
468
+ this.bindings = values;
469
+ return this;
470
+ }
471
+ resolveQuery() {
472
+ let sql = this.query;
473
+ this.bindings.forEach((value) => {
474
+ const formattedValue = typeof value === "string" ? `'${value.replace(/'/g, "''")}'` : value;
475
+ sql = sql.replace("?", String(formattedValue));
476
+ });
477
+ return sql;
478
+ }
479
+ async first(colName) {
480
+ const result = await this.all();
481
+ const firstRow = result.results[0] || null;
482
+ if (firstRow && colName) {
483
+ return firstRow[colName];
484
+ }
485
+ return firstRow;
486
+ }
487
+ async run() {
488
+ return this.all();
489
+ }
490
+ async all() {
491
+ const sql = this.resolveQuery();
492
+ const flag = this.isRemote ? "--remote" : "--local";
493
+ const command2 = `npx wrangler d1 execute ${this.dbName} --command "${sql.replace(/"/g, '\\"')}" ${flag} --json`;
494
+ try {
495
+ const output = (0, import_child_process.execSync)(command2, {
496
+ encoding: "utf-8",
497
+ stdio: ["ignore", "pipe", "pipe"]
498
+ });
499
+ const jsonStart = output.indexOf("[");
500
+ if (jsonStart !== -1) {
501
+ const results = JSON.parse(output.substring(jsonStart));
502
+ const primaryResult = results[0];
503
+ return {
504
+ results: primaryResult.results || [],
505
+ success: primaryResult.success ?? true,
506
+ meta: primaryResult.meta || {}
507
+ };
508
+ }
509
+ return { results: [], success: true, meta: {} };
510
+ } catch (e) {
511
+ return { results: [], success: false, meta: {}, error: e.message };
512
+ }
513
+ }
514
+ async raw() {
515
+ const result = await this.all();
516
+ return result.results;
517
+ }
518
+ };
519
+
520
+ // src/cli/commands/seed.ts
521
+ async function seed(args2) {
522
+ console.log("Seeding database...");
523
+ const seedersDir = path4.join(process.cwd(), "database/seeders");
524
+ if (!fs4.existsSync(seedersDir)) {
525
+ console.log("No seeders directory found.");
526
+ return;
527
+ }
528
+ const isRemote = args2.includes("--remote");
529
+ const dbName = "DB";
530
+ Database.setup(new CLIConnection(dbName, isRemote));
531
+ const files = fs4.readdirSync(seedersDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js")).sort();
532
+ for (const file of files) {
533
+ console.log(`Running seeder: ${file}`);
534
+ const filePath = path4.join(seedersDir, file);
535
+ try {
536
+ const seeder = await import(filePath);
537
+ if (seeder.seed) {
538
+ await seeder.seed();
539
+ console.log(`Seeder ${file} completed successfully.`);
540
+ } else {
541
+ console.warn(`Seeder ${file} does not export a seed function.`);
542
+ }
543
+ } catch (error) {
544
+ console.error(`Error running seeder ${file}:`, error);
545
+ }
546
+ }
547
+ }
548
+
549
+ // src/cli/commands/migrate.ts
289
550
  async function migrate(args2) {
290
551
  console.log("Running migrations...");
291
- const migrationsDir = path4.join(process.cwd(), "database/migrations");
292
- if (!fs4.existsSync(migrationsDir)) {
552
+ const migrationsDir = path5.join(process.cwd(), "database/migrations");
553
+ if (!fs5.existsSync(migrationsDir)) {
293
554
  console.log("No migrations directory found.");
294
555
  return;
295
556
  }
296
- const files = fs4.readdirSync(migrationsDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js")).sort();
557
+ const files = fs5.readdirSync(migrationsDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js")).sort();
297
558
  for (const file of files) {
298
559
  console.log(`Processing migration: ${file}`);
299
- const filePath = path4.join(migrationsDir, file);
560
+ const filePath = path5.join(migrationsDir, file);
300
561
  try {
301
562
  const migration = await import(filePath);
302
563
  if (migration.up) {
@@ -308,7 +569,7 @@ async function migrate(args2) {
308
569
  try {
309
570
  const execCmd = `npx wrangler d1 execute ${dbName} --command "${sql.replace(/"/g, '\\"')}" ${command2}`;
310
571
  console.log(`Executing: ${execCmd}`);
311
- (0, import_child_process.execSync)(execCmd, { stdio: "inherit" });
572
+ (0, import_child_process2.execSync)(execCmd, { stdio: "inherit" });
312
573
  } catch (e) {
313
574
  console.error(`Failed to execute migration: ${file}`);
314
575
  throw e;
@@ -319,6 +580,44 @@ async function migrate(args2) {
319
580
  console.error(`Error processing migration ${file}:`, error);
320
581
  }
321
582
  }
583
+ if (args2.includes("--seed")) {
584
+ await seed(args2);
585
+ }
586
+ }
587
+
588
+ // src/cli/commands/migrate-fresh.ts
589
+ var import_child_process3 = require("child_process");
590
+ async function migrateFresh(args2) {
591
+ console.log("Dropping all tables...");
592
+ const isRemote = args2.includes("--remote");
593
+ const dbName = "DB";
594
+ const flag = isRemote ? "--remote" : "--local";
595
+ try {
596
+ const listTablesCmd = `npx wrangler d1 execute ${dbName} --command "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_cf_%'" ${flag} --json`;
597
+ const output = (0, import_child_process3.execSync)(listTablesCmd, {
598
+ encoding: "utf-8",
599
+ stdio: ["ignore", "pipe", "inherit"]
600
+ });
601
+ const jsonStart = output.indexOf("[");
602
+ if (jsonStart !== -1) {
603
+ const results = JSON.parse(output.substring(jsonStart));
604
+ const tables = results[0]?.results || [];
605
+ if (tables.length > 0) {
606
+ const dropCommands = tables.map((t) => `DROP TABLE IF EXISTS ${t.name};`).join(" ");
607
+ const dropCmd = `npx wrangler d1 execute ${dbName} --command "${dropCommands}" ${flag}`;
608
+ console.log("Executing drop tables...");
609
+ (0, import_child_process3.execSync)(dropCmd, { stdio: "inherit" });
610
+ } else {
611
+ console.log("No tables found to drop.");
612
+ }
613
+ }
614
+ await migrate(args2);
615
+ if (args2.includes("--seed")) {
616
+ await seed(args2);
617
+ }
618
+ } catch (error) {
619
+ console.error("Error during migrate:fresh:", error);
620
+ }
322
621
  }
323
622
 
324
623
  // src/cli/index.ts
@@ -336,13 +635,17 @@ switch (command) {
336
635
  makeMigration(param);
337
636
  break;
338
637
  case "migrate":
339
- const isLocal = args.includes("--local");
340
- const isRemote = args.includes("--remote");
341
638
  migrate(args);
342
639
  break;
640
+ case "migrate:fresh":
641
+ migrateFresh(args);
642
+ break;
643
+ case "db:seed":
644
+ seed(args);
645
+ break;
343
646
  default:
344
647
  console.log(
345
- "Available commands: init, make:model, make:migration, migrate"
648
+ "Available commands: init, make:model, make:migration, migrate, migrate:fresh, db:seed"
346
649
  );
347
650
  break;
348
651
  }
@@ -1,8 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ Database,
3
4
  __commonJS,
4
- __esm
5
- } from "../chunk-X6BYQHVC.mjs";
5
+ __esm,
6
+ init_database
7
+ } from "../chunk-5BBZKUNZ.mjs";
6
8
 
7
9
  // src/cli/commands/init.ts
8
10
  import * as fs from "fs";
@@ -277,21 +279,173 @@ var init_make_model = __esm({
277
279
  }
278
280
  });
279
281
 
280
- // src/cli/commands/migrate.ts
282
+ // src/cli/cli-connection.ts
283
+ import { execSync } from "child_process";
284
+ var CLIConnection, CLIPREparedStatement;
285
+ var init_cli_connection = __esm({
286
+ "src/cli/cli-connection.ts"() {
287
+ "use strict";
288
+ CLIConnection = class {
289
+ constructor(dbName = "DB", isRemote = false) {
290
+ this.dbName = dbName;
291
+ this.isRemote = isRemote;
292
+ }
293
+ prepare(query) {
294
+ return new CLIPREparedStatement(query, this.dbName, this.isRemote);
295
+ }
296
+ async dump() {
297
+ throw new Error("dump() is not supported in CLI mode.");
298
+ }
299
+ async batch(statements) {
300
+ const results = [];
301
+ for (const stmt of statements) {
302
+ results.push(await stmt.run());
303
+ }
304
+ return results;
305
+ }
306
+ async exec(query) {
307
+ const start = Date.now();
308
+ await this.executeWrangler(query);
309
+ return {
310
+ count: 1,
311
+ // Approximation
312
+ duration: Date.now() - start
313
+ };
314
+ }
315
+ executeWrangler(sql) {
316
+ const flag = this.isRemote ? "--remote" : "--local";
317
+ const command = `npx wrangler d1 execute ${this.dbName} --command "${sql.replace(/"/g, '\\"')}" ${flag} --json`;
318
+ try {
319
+ const output = execSync(command, {
320
+ encoding: "utf-8",
321
+ stdio: ["ignore", "pipe", "inherit"]
322
+ });
323
+ const jsonStart = output.indexOf("[");
324
+ if (jsonStart !== -1) {
325
+ return JSON.parse(output.substring(jsonStart));
326
+ }
327
+ return null;
328
+ } catch (e) {
329
+ console.error(`Error executing wrangler command: ${command}`);
330
+ throw e;
331
+ }
332
+ }
333
+ };
334
+ CLIPREparedStatement = class {
335
+ constructor(query, dbName, isRemote) {
336
+ this.query = query;
337
+ this.dbName = dbName;
338
+ this.isRemote = isRemote;
339
+ }
340
+ bindings = [];
341
+ bind(...values) {
342
+ this.bindings = values;
343
+ return this;
344
+ }
345
+ resolveQuery() {
346
+ let sql = this.query;
347
+ this.bindings.forEach((value) => {
348
+ const formattedValue = typeof value === "string" ? `'${value.replace(/'/g, "''")}'` : value;
349
+ sql = sql.replace("?", String(formattedValue));
350
+ });
351
+ return sql;
352
+ }
353
+ async first(colName) {
354
+ const result = await this.all();
355
+ const firstRow = result.results[0] || null;
356
+ if (firstRow && colName) {
357
+ return firstRow[colName];
358
+ }
359
+ return firstRow;
360
+ }
361
+ async run() {
362
+ return this.all();
363
+ }
364
+ async all() {
365
+ const sql = this.resolveQuery();
366
+ const flag = this.isRemote ? "--remote" : "--local";
367
+ const command = `npx wrangler d1 execute ${this.dbName} --command "${sql.replace(/"/g, '\\"')}" ${flag} --json`;
368
+ try {
369
+ const output = execSync(command, {
370
+ encoding: "utf-8",
371
+ stdio: ["ignore", "pipe", "pipe"]
372
+ });
373
+ const jsonStart = output.indexOf("[");
374
+ if (jsonStart !== -1) {
375
+ const results = JSON.parse(output.substring(jsonStart));
376
+ const primaryResult = results[0];
377
+ return {
378
+ results: primaryResult.results || [],
379
+ success: primaryResult.success ?? true,
380
+ meta: primaryResult.meta || {}
381
+ };
382
+ }
383
+ return { results: [], success: true, meta: {} };
384
+ } catch (e) {
385
+ return { results: [], success: false, meta: {}, error: e.message };
386
+ }
387
+ }
388
+ async raw() {
389
+ const result = await this.all();
390
+ return result.results;
391
+ }
392
+ };
393
+ }
394
+ });
395
+
396
+ // src/cli/commands/seed.ts
281
397
  import * as fs4 from "fs";
282
398
  import * as path4 from "path";
283
- import { execSync } from "child_process";
399
+ async function seed(args) {
400
+ console.log("Seeding database...");
401
+ const seedersDir = path4.join(process.cwd(), "database/seeders");
402
+ if (!fs4.existsSync(seedersDir)) {
403
+ console.log("No seeders directory found.");
404
+ return;
405
+ }
406
+ const isRemote = args.includes("--remote");
407
+ const dbName = "DB";
408
+ Database.setup(new CLIConnection(dbName, isRemote));
409
+ const files = fs4.readdirSync(seedersDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js")).sort();
410
+ for (const file of files) {
411
+ console.log(`Running seeder: ${file}`);
412
+ const filePath = path4.join(seedersDir, file);
413
+ try {
414
+ const seeder = await import(filePath);
415
+ if (seeder.seed) {
416
+ await seeder.seed();
417
+ console.log(`Seeder ${file} completed successfully.`);
418
+ } else {
419
+ console.warn(`Seeder ${file} does not export a seed function.`);
420
+ }
421
+ } catch (error) {
422
+ console.error(`Error running seeder ${file}:`, error);
423
+ }
424
+ }
425
+ }
426
+ var init_seed = __esm({
427
+ "src/cli/commands/seed.ts"() {
428
+ "use strict";
429
+ init_database();
430
+ init_cli_connection();
431
+ }
432
+ });
433
+
434
+ // src/cli/commands/migrate.ts
435
+ import * as fs5 from "fs";
436
+ import * as path5 from "path";
437
+ import { execSync as execSync2 } from "child_process";
284
438
  async function migrate(args) {
285
439
  console.log("Running migrations...");
286
- const migrationsDir = path4.join(process.cwd(), "database/migrations");
287
- if (!fs4.existsSync(migrationsDir)) {
440
+ const migrationsDir = path5.join(process.cwd(), "database/migrations");
441
+ if (!fs5.existsSync(migrationsDir)) {
288
442
  console.log("No migrations directory found.");
289
443
  return;
290
444
  }
291
- const files = fs4.readdirSync(migrationsDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js")).sort();
445
+ const files = fs5.readdirSync(migrationsDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js")).sort();
292
446
  for (const file of files) {
293
447
  console.log(`Processing migration: ${file}`);
294
- const filePath = path4.join(migrationsDir, file);
448
+ const filePath = path5.join(migrationsDir, file);
295
449
  try {
296
450
  const migration = await import(filePath);
297
451
  if (migration.up) {
@@ -303,7 +457,7 @@ async function migrate(args) {
303
457
  try {
304
458
  const execCmd = `npx wrangler d1 execute ${dbName} --command "${sql.replace(/"/g, '\\"')}" ${command}`;
305
459
  console.log(`Executing: ${execCmd}`);
306
- execSync(execCmd, { stdio: "inherit" });
460
+ execSync2(execCmd, { stdio: "inherit" });
307
461
  } catch (e) {
308
462
  console.error(`Failed to execute migration: ${file}`);
309
463
  throw e;
@@ -314,10 +468,56 @@ async function migrate(args) {
314
468
  console.error(`Error processing migration ${file}:`, error);
315
469
  }
316
470
  }
471
+ if (args.includes("--seed")) {
472
+ await seed(args);
473
+ }
317
474
  }
318
475
  var init_migrate = __esm({
319
476
  "src/cli/commands/migrate.ts"() {
320
477
  "use strict";
478
+ init_seed();
479
+ }
480
+ });
481
+
482
+ // src/cli/commands/migrate-fresh.ts
483
+ import { execSync as execSync3 } from "child_process";
484
+ async function migrateFresh(args) {
485
+ console.log("Dropping all tables...");
486
+ const isRemote = args.includes("--remote");
487
+ const dbName = "DB";
488
+ const flag = isRemote ? "--remote" : "--local";
489
+ try {
490
+ const listTablesCmd = `npx wrangler d1 execute ${dbName} --command "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_cf_%'" ${flag} --json`;
491
+ const output = execSync3(listTablesCmd, {
492
+ encoding: "utf-8",
493
+ stdio: ["ignore", "pipe", "inherit"]
494
+ });
495
+ const jsonStart = output.indexOf("[");
496
+ if (jsonStart !== -1) {
497
+ const results = JSON.parse(output.substring(jsonStart));
498
+ const tables = results[0]?.results || [];
499
+ if (tables.length > 0) {
500
+ const dropCommands = tables.map((t) => `DROP TABLE IF EXISTS ${t.name};`).join(" ");
501
+ const dropCmd = `npx wrangler d1 execute ${dbName} --command "${dropCommands}" ${flag}`;
502
+ console.log("Executing drop tables...");
503
+ execSync3(dropCmd, { stdio: "inherit" });
504
+ } else {
505
+ console.log("No tables found to drop.");
506
+ }
507
+ }
508
+ await migrate(args);
509
+ if (args.includes("--seed")) {
510
+ await seed(args);
511
+ }
512
+ } catch (error) {
513
+ console.error("Error during migrate:fresh:", error);
514
+ }
515
+ }
516
+ var init_migrate_fresh = __esm({
517
+ "src/cli/commands/migrate-fresh.ts"() {
518
+ "use strict";
519
+ init_migrate();
520
+ init_seed();
321
521
  }
322
522
  });
323
523
 
@@ -328,6 +528,8 @@ var require_cli = __commonJS({
328
528
  init_make_model();
329
529
  init_make_migration();
330
530
  init_migrate();
531
+ init_migrate_fresh();
532
+ init_seed();
331
533
  var args = process.argv.slice(2);
332
534
  var command = args[0];
333
535
  var param = args[1];
@@ -342,13 +544,17 @@ var require_cli = __commonJS({
342
544
  makeMigration(param);
343
545
  break;
344
546
  case "migrate":
345
- const isLocal = args.includes("--local");
346
- const isRemote = args.includes("--remote");
347
547
  migrate(args);
348
548
  break;
549
+ case "migrate:fresh":
550
+ migrateFresh(args);
551
+ break;
552
+ case "db:seed":
553
+ seed(args);
554
+ break;
349
555
  default:
350
556
  console.log(
351
- "Available commands: init, make:model, make:migration, migrate"
557
+ "Available commands: init, make:model, make:migration, migrate, migrate:fresh, db:seed"
352
558
  );
353
559
  break;
354
560
  }
package/dist/index.d.mts CHANGED
@@ -465,16 +465,64 @@ declare class ModelQueryBuilder<T extends Model> extends QueryBuilder {
465
465
  getModel(): typeof Model;
466
466
  }
467
467
 
468
+ /**
469
+ * Represents a database column definition.
470
+ */
471
+ declare class Column {
472
+ protected name: string;
473
+ protected type: string;
474
+ protected isNullable: boolean;
475
+ protected isUnique: boolean;
476
+ protected defaultValue: any;
477
+ constructor(name: string, type: string);
478
+ /**
479
+ * Set the column as nullable.
480
+ */
481
+ nullable(): this;
482
+ /**
483
+ * Set the column as unique.
484
+ */
485
+ unique(): this;
486
+ /**
487
+ * Set the default value for the column.
488
+ */
489
+ default(value: any): this;
490
+ /**
491
+ * Convert the column definition to SQL.
492
+ */
493
+ toSql(): string;
494
+ }
495
+ /**
496
+ * Schema Blueprint for defining tables.
497
+ */
468
498
  declare class Blueprint {
469
499
  protected table: string;
470
- protected columns: string[];
500
+ protected columns: (Column | string)[];
471
501
  protected commands: string[];
472
502
  constructor(table: string);
503
+ /**
504
+ * Add an auto-incrementing ID column.
505
+ */
473
506
  id(): this;
474
- string(column: string, length?: number): this;
475
- integer(column: string): this;
476
- boolean(column: string): this;
507
+ /**
508
+ * Add a string (TEXT) column.
509
+ */
510
+ string(column: string): Column;
511
+ /**
512
+ * Add an integer column.
513
+ */
514
+ integer(column: string): Column;
515
+ /**
516
+ * Add a boolean column.
517
+ */
518
+ boolean(column: string): Column;
519
+ /**
520
+ * Add created_at and updated_at timestamp columns.
521
+ */
477
522
  timestamps(): this;
523
+ /**
524
+ * Convert the blueprint to a set of SQL statements.
525
+ */
478
526
  toSql(): string[];
479
527
  }
480
528
 
@@ -483,4 +531,4 @@ declare class Schema {
483
531
  static dropIfExists(table: string): string;
484
532
  }
485
533
 
486
- export { BelongsTo, Blueprint, Connection, type D1Database, type D1ExecResult, type D1PreparedStatement, type D1Result, type D1Value, Database, HasMany, HasOne, Model, ModelQueryBuilder, QueryBuilder, Relationship, Schema };
534
+ export { BelongsTo, Blueprint, Column, Connection, type D1Database, type D1ExecResult, type D1PreparedStatement, type D1Result, type D1Value, Database, HasMany, HasOne, Model, ModelQueryBuilder, QueryBuilder, Relationship, Schema };
package/dist/index.d.ts CHANGED
@@ -465,16 +465,64 @@ declare class ModelQueryBuilder<T extends Model> extends QueryBuilder {
465
465
  getModel(): typeof Model;
466
466
  }
467
467
 
468
+ /**
469
+ * Represents a database column definition.
470
+ */
471
+ declare class Column {
472
+ protected name: string;
473
+ protected type: string;
474
+ protected isNullable: boolean;
475
+ protected isUnique: boolean;
476
+ protected defaultValue: any;
477
+ constructor(name: string, type: string);
478
+ /**
479
+ * Set the column as nullable.
480
+ */
481
+ nullable(): this;
482
+ /**
483
+ * Set the column as unique.
484
+ */
485
+ unique(): this;
486
+ /**
487
+ * Set the default value for the column.
488
+ */
489
+ default(value: any): this;
490
+ /**
491
+ * Convert the column definition to SQL.
492
+ */
493
+ toSql(): string;
494
+ }
495
+ /**
496
+ * Schema Blueprint for defining tables.
497
+ */
468
498
  declare class Blueprint {
469
499
  protected table: string;
470
- protected columns: string[];
500
+ protected columns: (Column | string)[];
471
501
  protected commands: string[];
472
502
  constructor(table: string);
503
+ /**
504
+ * Add an auto-incrementing ID column.
505
+ */
473
506
  id(): this;
474
- string(column: string, length?: number): this;
475
- integer(column: string): this;
476
- boolean(column: string): this;
507
+ /**
508
+ * Add a string (TEXT) column.
509
+ */
510
+ string(column: string): Column;
511
+ /**
512
+ * Add an integer column.
513
+ */
514
+ integer(column: string): Column;
515
+ /**
516
+ * Add a boolean column.
517
+ */
518
+ boolean(column: string): Column;
519
+ /**
520
+ * Add created_at and updated_at timestamp columns.
521
+ */
477
522
  timestamps(): this;
523
+ /**
524
+ * Convert the blueprint to a set of SQL statements.
525
+ */
478
526
  toSql(): string[];
479
527
  }
480
528
 
@@ -483,4 +531,4 @@ declare class Schema {
483
531
  static dropIfExists(table: string): string;
484
532
  }
485
533
 
486
- export { BelongsTo, Blueprint, Connection, type D1Database, type D1ExecResult, type D1PreparedStatement, type D1Result, type D1Value, Database, HasMany, HasOne, Model, ModelQueryBuilder, QueryBuilder, Relationship, Schema };
534
+ export { BelongsTo, Blueprint, Column, Connection, type D1Database, type D1ExecResult, type D1PreparedStatement, type D1Result, type D1Value, Database, HasMany, HasOne, Model, ModelQueryBuilder, QueryBuilder, Relationship, Schema };
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  BelongsTo: () => BelongsTo,
24
24
  Blueprint: () => Blueprint,
25
+ Column: () => Column,
25
26
  Connection: () => Connection,
26
27
  Database: () => Database,
27
28
  HasMany: () => HasMany,
@@ -716,6 +717,55 @@ var Model = class {
716
717
  };
717
718
 
718
719
  // src/database/blueprint.ts
720
+ var Column = class {
721
+ name;
722
+ type;
723
+ isNullable = false;
724
+ isUnique = false;
725
+ defaultValue = null;
726
+ constructor(name, type) {
727
+ this.name = name;
728
+ this.type = type;
729
+ }
730
+ /**
731
+ * Set the column as nullable.
732
+ */
733
+ nullable() {
734
+ this.isNullable = true;
735
+ return this;
736
+ }
737
+ /**
738
+ * Set the column as unique.
739
+ */
740
+ unique() {
741
+ this.isUnique = true;
742
+ return this;
743
+ }
744
+ /**
745
+ * Set the default value for the column.
746
+ */
747
+ default(value) {
748
+ this.defaultValue = value;
749
+ return this;
750
+ }
751
+ /**
752
+ * Convert the column definition to SQL.
753
+ */
754
+ toSql() {
755
+ let sql = `${this.name} ${this.type}`;
756
+ if (this.isUnique) {
757
+ sql += " UNIQUE";
758
+ }
759
+ if (!this.isNullable) {
760
+ sql += " NOT NULL";
761
+ }
762
+ if (this.defaultValue !== null) {
763
+ const formattedValue = typeof this.defaultValue === "string" ? `'${this.defaultValue}'` : this.defaultValue;
764
+ sql += ` DEFAULT ${formattedValue}`;
765
+ }
766
+ return sql;
767
+ }
768
+ };
719
769
  var Blueprint = class {
720
770
  table;
721
771
  columns = [];
@@ -723,30 +773,55 @@ var Blueprint = class {
723
773
  constructor(table) {
724
774
  this.table = table;
725
775
  }
776
+ /**
777
+ * Add an auto-incrementing ID column.
778
+ */
726
779
  id() {
727
780
  this.columns.push("id INTEGER PRIMARY KEY AUTOINCREMENT");
728
781
  return this;
729
782
  }
730
- string(column, length) {
731
- this.columns.push(`${column} TEXT`);
732
- return this;
783
+ /**
784
+ * Add a string (TEXT) column.
785
+ */
786
+ string(column) {
787
+ const col = new Column(column, "TEXT");
788
+ this.columns.push(col);
789
+ return col;
733
790
  }
791
+ /**
792
+ * Add an integer column.
793
+ */
734
794
  integer(column) {
735
- this.columns.push(`${column} INTEGER`);
736
- return this;
795
+ const col = new Column(column, "INTEGER");
796
+ this.columns.push(col);
797
+ return col;
737
798
  }
799
+ /**
800
+ * Add a boolean column.
801
+ */
738
802
  boolean(column) {
739
- this.columns.push(`${column} BOOLEAN`);
740
- return this;
803
+ const col = new Column(column, "BOOLEAN");
804
+ this.columns.push(col);
805
+ return col;
741
806
  }
807
+ /**
808
+ * Add created_at and updated_at timestamp columns.
809
+ */
742
810
  timestamps() {
743
811
  this.columns.push("created_at DATETIME DEFAULT CURRENT_TIMESTAMP");
744
812
  this.columns.push("updated_at DATETIME DEFAULT CURRENT_TIMESTAMP");
745
813
  return this;
746
814
  }
815
+ /**
816
+ * Convert the blueprint to a set of SQL statements.
817
+ */
747
818
  toSql() {
748
819
  if (this.columns.length > 0) {
749
- const cols = this.columns.join(", ");
820
+ const colDefinitions = this.columns.map((col) => {
821
+ if (typeof col === "string") return col;
822
+ return col.toSql();
823
+ });
824
+ const cols = colDefinitions.join(", ");
750
825
  return [`CREATE TABLE IF NOT EXISTS ${this.table} (${cols})`];
751
826
  }
752
827
  return this.commands;
@@ -768,6 +843,7 @@ var Schema = class {
768
843
  0 && (module.exports = {
769
844
  BelongsTo,
770
845
  Blueprint,
846
+ Column,
771
847
  Connection,
772
848
  Database,
773
849
  HasMany,
package/dist/index.mjs CHANGED
@@ -1,80 +1,12 @@
1
- import "./chunk-X6BYQHVC.mjs";
1
+ import {
2
+ Connection,
3
+ Database,
4
+ init_connection,
5
+ init_database
6
+ } from "./chunk-5BBZKUNZ.mjs";
2
7
 
3
- // src/core/connection.ts
4
- var Connection = class {
5
- /**
6
- * The underlying D1Database instance.
7
- */
8
- db;
9
- /**
10
- * Create a new Connection instance.
11
- *
12
- * @param database - The D1Database instance.
13
- */
14
- constructor(database) {
15
- this.db = database;
16
- }
17
- /**
18
- * Execute a SELECT statement.
19
- *
20
- * @param query - The SQL query string.
21
- * @param bindings - The parameter bindings.
22
- * @returns A promise that resolves to an array of results.
23
- */
24
- async select(query, bindings = []) {
25
- const stmt = this.db.prepare(query).bind(...bindings);
26
- const result = await stmt.all();
27
- return result.results || [];
28
- }
29
- /**
30
- * Execute an INSERT statement.
31
- *
32
- * @param query - The SQL query string.
33
- * @param bindings - The parameter bindings.
34
- * @returns A promise that resolves to true on success.
35
- */
36
- async insert(query, bindings = []) {
37
- const stmt = this.db.prepare(query).bind(...bindings);
38
- const result = await stmt.run();
39
- return result.success;
40
- }
41
- /**
42
- * Execute an UPDATE statement.
43
- *
44
- * @param query - The SQL query string.
45
- * @param bindings - The parameter bindings.
46
- * @returns A promise that resolves to true on success.
47
- */
48
- async update(query, bindings = []) {
49
- const stmt = this.db.prepare(query).bind(...bindings);
50
- const result = await stmt.run();
51
- return result.success;
52
- }
53
- /**
54
- * Execute a DELETE statement.
55
- *
56
- * @param query - The SQL query string.
57
- * @param bindings - The parameter bindings.
58
- * @returns A promise that resolves to true on success.
59
- */
60
- async delete(query, bindings = []) {
61
- const stmt = this.db.prepare(query).bind(...bindings);
62
- const result = await stmt.run();
63
- return result.success;
64
- }
65
- /**
66
- * Execute an arbitrary SQL statement.
67
- *
68
- * @param query - The SQL query string.
69
- * @param bindings - The parameter bindings.
70
- * @returns A promise that resolves to true on success.
71
- */
72
- async statement(query, bindings = []) {
73
- const stmt = this.db.prepare(query).bind(...bindings);
74
- const result = await stmt.run();
75
- return result.success;
76
- }
77
- };
8
+ // src/index.ts
9
+ init_connection();
78
10
 
79
11
  // src/core/query-builder.ts
80
12
  var QueryBuilder = class {
@@ -342,47 +274,11 @@ var ModelQueryBuilder = class extends QueryBuilder {
342
274
  }
343
275
  };
344
276
 
345
- // src/core/database.ts
346
- var Database = class _Database {
347
- /**
348
- * The singleton instance of the Database.
349
- */
350
- static instance;
351
- /**
352
- * The active database connection.
353
- */
354
- connection;
355
- /**
356
- * Private constructor to enforce singleton pattern.
357
- *
358
- * @param d1 - The D1Database instance from Cloudflare.
359
- */
360
- constructor(d1) {
361
- this.connection = new Connection(d1);
362
- }
363
- /**
364
- * Setup the database connection.
365
- *
366
- * @param d1 - The D1Database instance from Cloudflare environment (env.DB).
367
- */
368
- static setup(d1) {
369
- _Database.instance = new _Database(d1);
370
- }
371
- /**
372
- * Get the singleton Database instance.
373
- *
374
- * @throws Error if setup() has not been called.
375
- * @returns The Database instance.
376
- */
377
- static getInstance() {
378
- if (!_Database.instance) {
379
- throw new Error(
380
- "Database not initialized. Call Database.setup(env.DB) first."
381
- );
382
- }
383
- return _Database.instance;
384
- }
385
- };
277
+ // src/index.ts
278
+ init_database();
279
+
280
+ // src/models/model.ts
281
+ init_database();
386
282
 
387
283
  // src/core/relationships/relationship.ts
388
284
  var Relationship = class {
@@ -682,6 +578,55 @@ var Model = class {
682
578
  };
683
579
 
684
580
  // src/database/blueprint.ts
581
+ var Column = class {
582
+ name;
583
+ type;
584
+ isNullable = false;
585
+ isUnique = false;
586
+ defaultValue = null;
587
+ constructor(name, type) {
588
+ this.name = name;
589
+ this.type = type;
590
+ }
591
+ /**
592
+ * Set the column as nullable.
593
+ */
594
+ nullable() {
595
+ this.isNullable = true;
596
+ return this;
597
+ }
598
+ /**
599
+ * Set the column as unique.
600
+ */
601
+ unique() {
602
+ this.isUnique = true;
603
+ return this;
604
+ }
605
+ /**
606
+ * Set the default value for the column.
607
+ */
608
+ default(value) {
609
+ this.defaultValue = value;
610
+ return this;
611
+ }
612
+ /**
613
+ * Convert the column definition to SQL.
614
+ */
615
+ toSql() {
616
+ let sql = `${this.name} ${this.type}`;
617
+ if (this.isUnique) {
618
+ sql += " UNIQUE";
619
+ }
620
+ if (!this.isNullable) {
621
+ sql += " NOT NULL";
622
+ }
623
+ if (this.defaultValue !== null) {
624
+ const formattedValue = typeof this.defaultValue === "string" ? `'${this.defaultValue}'` : this.defaultValue;
625
+ sql += ` DEFAULT ${formattedValue}`;
626
+ }
627
+ return sql;
628
+ }
629
+ };
685
630
  var Blueprint = class {
686
631
  table;
687
632
  columns = [];
@@ -689,30 +634,55 @@ var Blueprint = class {
689
634
  constructor(table) {
690
635
  this.table = table;
691
636
  }
637
+ /**
638
+ * Add an auto-incrementing ID column.
639
+ */
692
640
  id() {
693
641
  this.columns.push("id INTEGER PRIMARY KEY AUTOINCREMENT");
694
642
  return this;
695
643
  }
696
- string(column, length) {
697
- this.columns.push(`${column} TEXT`);
698
- return this;
644
+ /**
645
+ * Add a string (TEXT) column.
646
+ */
647
+ string(column) {
648
+ const col = new Column(column, "TEXT");
649
+ this.columns.push(col);
650
+ return col;
699
651
  }
652
+ /**
653
+ * Add an integer column.
654
+ */
700
655
  integer(column) {
701
- this.columns.push(`${column} INTEGER`);
702
- return this;
656
+ const col = new Column(column, "INTEGER");
657
+ this.columns.push(col);
658
+ return col;
703
659
  }
660
+ /**
661
+ * Add a boolean column.
662
+ */
704
663
  boolean(column) {
705
- this.columns.push(`${column} BOOLEAN`);
706
- return this;
664
+ const col = new Column(column, "BOOLEAN");
665
+ this.columns.push(col);
666
+ return col;
707
667
  }
668
+ /**
669
+ * Add created_at and updated_at timestamp columns.
670
+ */
708
671
  timestamps() {
709
672
  this.columns.push("created_at DATETIME DEFAULT CURRENT_TIMESTAMP");
710
673
  this.columns.push("updated_at DATETIME DEFAULT CURRENT_TIMESTAMP");
711
674
  return this;
712
675
  }
676
+ /**
677
+ * Convert the blueprint to a set of SQL statements.
678
+ */
713
679
  toSql() {
714
680
  if (this.columns.length > 0) {
715
- const cols = this.columns.join(", ");
681
+ const colDefinitions = this.columns.map((col) => {
682
+ if (typeof col === "string") return col;
683
+ return col.toSql();
684
+ });
685
+ const cols = colDefinitions.join(", ");
716
686
  return [`CREATE TABLE IF NOT EXISTS ${this.table} (${cols})`];
717
687
  }
718
688
  return this.commands;
@@ -733,6 +703,7 @@ var Schema = class {
733
703
  export {
734
704
  BelongsTo,
735
705
  Blueprint,
706
+ Column,
736
707
  Connection,
737
708
  Database,
738
709
  HasMany,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3lineas/d1-orm",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "A lightweight and powerful ORM for Cloudflare D1, inspired by Laravel Eloquent.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1,12 +0,0 @@
1
- var __getOwnPropNames = Object.getOwnPropertyNames;
2
- var __esm = (fn, res) => function __init() {
3
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
- };
5
- var __commonJS = (cb, mod) => function __require() {
6
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
7
- };
8
-
9
- export {
10
- __esm,
11
- __commonJS
12
- };