@3lineas/d1-orm 1.0.7 → 1.0.8

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.
@@ -0,0 +1,781 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/cli/commands/init.ts
27
+ var fs = __toESM(require("fs"), 1);
28
+ var path = __toESM(require("path"), 1);
29
+ var p = __toESM(require("@clack/prompts"), 1);
30
+ async function init() {
31
+ p.intro("Initializing D1 ORM...");
32
+ const s = p.spinner();
33
+ s.start("Scanning project structure...");
34
+ const srcPath = path.join(process.cwd(), "src");
35
+ const useSrc = fs.existsSync(srcPath) && fs.lstatSync(srcPath).isDirectory();
36
+ const baseDatabasePath = useSrc ? "src/database" : "database";
37
+ const modelsPath = path.join(baseDatabasePath, "models");
38
+ const migrationsPath = path.join(baseDatabasePath, "migrations");
39
+ const seedersPath = path.join(baseDatabasePath, "seeders");
40
+ const folders = [modelsPath, migrationsPath, seedersPath];
41
+ folders.forEach((folder) => {
42
+ const fullPath = path.join(process.cwd(), folder);
43
+ if (!fs.existsSync(fullPath)) {
44
+ fs.mkdirSync(fullPath, { recursive: true });
45
+ p.log.step(`Created directory: ${folder}`);
46
+ } else {
47
+ p.log.info(`Directory already exists: ${folder}`);
48
+ }
49
+ });
50
+ s.message("Generating example files...");
51
+ const userModelContent = `import { Model } from '@3lineas/d1-orm';
52
+
53
+ export class User extends Model {
54
+ // protected static table = 'users';
55
+
56
+ declare id: number;
57
+ declare name: string;
58
+ declare email: string;
59
+ declare password?: string;
60
+ declare created_at: string;
61
+ declare updated_at: string;
62
+ }
63
+ `;
64
+ const userModelPath = path.join(process.cwd(), modelsPath, "User.ts");
65
+ if (!fs.existsSync(userModelPath)) {
66
+ fs.writeFileSync(userModelPath, userModelContent);
67
+ p.log.step(`Created model: ${modelsPath}/User.ts`);
68
+ }
69
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").split(".")[0].replace("T", "_");
70
+ const migrationName = `${timestamp}_create_users_table.ts`;
71
+ const migrationContent = `import { Blueprint, Schema } from '@3lineas/d1-orm';
72
+
73
+ export const up = async () => {
74
+ return Schema.create('users', (table: Blueprint) => {
75
+ table.id();
76
+ table.string('name');
77
+ table.string('email').unique();
78
+ table.string('password').nullable();
79
+ table.timestamps();
80
+ });
81
+ };
82
+
83
+ export const down = async () => {
84
+ return Schema.dropIfExists('users');
85
+ };
86
+ `;
87
+ const fullMigrationsPath = path.join(
88
+ process.cwd(),
89
+ migrationsPath,
90
+ migrationName
91
+ );
92
+ if (!fs.existsSync(fullMigrationsPath)) {
93
+ fs.writeFileSync(fullMigrationsPath, migrationContent);
94
+ p.log.step(`Created migration: ${migrationsPath}/${migrationName}`);
95
+ }
96
+ const seederContent = `import { User } from '../models/User.ts';
97
+
98
+ export const seed = async () => {
99
+ await User.create({
100
+ name: 'John Doe',
101
+ email: 'john@example.com',
102
+ password: 'password'
103
+ });
104
+ };
105
+ `;
106
+ const fullSeederPath = path.join(process.cwd(), seedersPath, "UserSeeder.ts");
107
+ if (!fs.existsSync(fullSeederPath)) {
108
+ fs.writeFileSync(fullSeederPath, seederContent);
109
+ p.log.step(`Created seeder: ${seedersPath}/UserSeeder.ts`);
110
+ }
111
+ const configContent = `export default {
112
+ binding: 'DB', // Name of the D1 binding in wrangler.jsonc/toml
113
+ };
114
+ `;
115
+ const configFilePath = path.join(
116
+ process.cwd(),
117
+ baseDatabasePath,
118
+ "config.ts"
119
+ );
120
+ if (!fs.existsSync(configFilePath)) {
121
+ fs.writeFileSync(configFilePath, configContent);
122
+ p.log.step(`Created config: ${baseDatabasePath}/config.ts`);
123
+ }
124
+ const packageJsonPath = path.join(process.cwd(), "package.json");
125
+ if (fs.existsSync(packageJsonPath)) {
126
+ try {
127
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
128
+ if (!packageJson.scripts) {
129
+ packageJson.scripts = {};
130
+ }
131
+ if (!packageJson.scripts.orm) {
132
+ packageJson.scripts.orm = "d1-orm";
133
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
134
+ p.log.step('Added "orm" script to package.json');
135
+ }
136
+ } catch (e) {
137
+ p.log.error(`Failed to update package.json: ${e}`);
138
+ }
139
+ }
140
+ s.stop("Initialization complete!");
141
+ p.outro("D1 ORM is ready to use.");
142
+ }
143
+
144
+ // src/cli/commands/make-model.ts
145
+ var fs3 = __toESM(require("fs"), 1);
146
+ var path3 = __toESM(require("path"), 1);
147
+ var p3 = __toESM(require("@clack/prompts"), 1);
148
+
149
+ // src/cli/commands/make-migration.ts
150
+ var fs2 = __toESM(require("fs"), 1);
151
+ var path2 = __toESM(require("path"), 1);
152
+ var p2 = __toESM(require("@clack/prompts"), 1);
153
+ async function makeMigration(name) {
154
+ const isStandalone = !name;
155
+ if (isStandalone) {
156
+ p2.intro("Creating a new migration...");
157
+ }
158
+ let migrationName = name;
159
+ if (!migrationName) {
160
+ migrationName = await p2.text({
161
+ message: "What should the migration be named?",
162
+ placeholder: "e.g. create_users_table",
163
+ validate: (value) => {
164
+ if (!value) return "Please enter a name.";
165
+ }
166
+ });
167
+ if (p2.isCancel(migrationName)) {
168
+ p2.cancel("Operation cancelled.");
169
+ return;
170
+ }
171
+ }
172
+ const srcMigrationsDir = path2.join(process.cwd(), "src/database/migrations");
173
+ const rootMigrationsDir = path2.join(process.cwd(), "database/migrations");
174
+ const migrationsDir = fs2.existsSync(srcMigrationsDir) ? "src/database/migrations" : "database/migrations";
175
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").split(".")[0].replace("T", "_");
176
+ const filename = `${timestamp}_${migrationName}.ts`;
177
+ const targetPath = path2.join(process.cwd(), migrationsDir, filename);
178
+ const template = `import { Blueprint, Schema } from '@3lineas/d1-orm';
179
+
180
+ export const up = async () => {
181
+ return Schema.create('${migrationName.replace("create_", "").replace("_table", "")}', (table: Blueprint) => {
182
+ table.id();
183
+ table.timestamps();
184
+ });
185
+ };
186
+
187
+ export const down = async () => {
188
+ return Schema.dropIfExists('${migrationName.replace("create_", "").replace("_table", "")}');
189
+ };
190
+ `;
191
+ if (!fs2.existsSync(path2.join(process.cwd(), migrationsDir))) {
192
+ fs2.mkdirSync(path2.join(process.cwd(), migrationsDir), {
193
+ recursive: true
194
+ });
195
+ }
196
+ if (fs2.existsSync(targetPath)) {
197
+ p2.log.error(`Migration ${filename} already exists.`);
198
+ if (isStandalone) p2.outro("Process aborted.");
199
+ return;
200
+ }
201
+ fs2.writeFileSync(targetPath, template);
202
+ p2.log.success(`Created migration: ${migrationsDir}/${filename}`);
203
+ if (isStandalone) {
204
+ p2.outro("Migration generated successfully!");
205
+ }
206
+ }
207
+
208
+ // src/cli/commands/make-model.ts
209
+ async function makeModel(name) {
210
+ p3.intro("Creating a new model...");
211
+ let modelName = name;
212
+ if (!modelName) {
213
+ modelName = await p3.text({
214
+ message: "What should the model be named?",
215
+ placeholder: "e.g. Flight",
216
+ validate: (value) => {
217
+ if (!value) return "Please enter a name.";
218
+ }
219
+ });
220
+ if (p3.isCancel(modelName)) {
221
+ p3.cancel("Operation cancelled.");
222
+ return;
223
+ }
224
+ }
225
+ const modelPath = await findModelsPath() || "src/database/models";
226
+ const filename = `${modelName}.ts`;
227
+ const targetPath = path3.join(process.cwd(), modelPath, filename);
228
+ const template = `import { Model } from '@3lineas/d1-orm';
229
+
230
+ export class ${modelName} extends Model {
231
+ // protected static table = '${modelName.toLowerCase()}s';
232
+
233
+ // declare id: number;
234
+ // declare created_at: string;
235
+ // declare updated_at: string;
236
+ }
237
+ `;
238
+ if (fs3.existsSync(targetPath)) {
239
+ p3.log.error(`Model ${filename} already exists at ${modelPath}.`);
240
+ p3.outro("Process aborted.");
241
+ return;
242
+ }
243
+ if (!fs3.existsSync(path3.join(process.cwd(), modelPath))) {
244
+ fs3.mkdirSync(path3.join(process.cwd(), modelPath), { recursive: true });
245
+ }
246
+ fs3.writeFileSync(targetPath, template);
247
+ p3.log.success(`Created model: ${modelPath}/${filename}`);
248
+ const options = await p3.multiselect({
249
+ message: "Would you like to create any of the following?",
250
+ options: [
251
+ { value: "migration", label: "Migration" },
252
+ { value: "seeder", label: "Database Seeder" }
253
+ ],
254
+ required: false
255
+ });
256
+ if (p3.isCancel(options)) {
257
+ p3.cancel("Operation cancelled.");
258
+ return;
259
+ }
260
+ if (options.includes("migration")) {
261
+ const migrationName = `create_${modelName.toLowerCase()}s_table`;
262
+ await makeMigration(migrationName);
263
+ }
264
+ if (options.includes("seeder")) {
265
+ await makeSeeder(modelName, modelPath);
266
+ }
267
+ p3.outro("Model generation complete!");
268
+ }
269
+ async function findModelsPath() {
270
+ const commonPaths = [
271
+ "src/database/models",
272
+ "database/models",
273
+ "src/models",
274
+ "models",
275
+ "app/Models"
276
+ ];
277
+ for (const p7 of commonPaths) {
278
+ if (fs3.existsSync(path3.join(process.cwd(), p7))) return p7;
279
+ }
280
+ return null;
281
+ }
282
+ async function makeSeeder(modelName, modelPath) {
283
+ const srcPath = path3.join(process.cwd(), "src");
284
+ const useSrc = fs3.existsSync(srcPath) && fs3.lstatSync(srcPath).isDirectory();
285
+ const seederDir = useSrc ? path3.join(process.cwd(), "src/database/seeders") : path3.join(process.cwd(), "database/seeders");
286
+ const seederName = `${modelName}Seeder.ts`;
287
+ const targetPath = path3.join(seederDir, seederName);
288
+ if (!fs3.existsSync(seederDir)) {
289
+ fs3.mkdirSync(seederDir, { recursive: true });
290
+ }
291
+ const relativeModelPath = path3.relative(seederDir, path3.join(process.cwd(), modelPath, modelName)).replace(/\\/g, "/");
292
+ const template = `import { ${modelName} } from '${relativeModelPath}.ts';
293
+
294
+ export const seed = async () => {
295
+ // await ${modelName}.create({ ... });
296
+ };
297
+ `;
298
+ if (fs3.existsSync(targetPath)) {
299
+ p3.log.warn(`Seeder ${seederName} already exists.`);
300
+ return;
301
+ }
302
+ fs3.writeFileSync(targetPath, template);
303
+ p3.log.success(`Created seeder: database/seeders/${seederName}`);
304
+ }
305
+
306
+ // src/cli/commands/migrate.ts
307
+ var fs6 = __toESM(require("fs"), 1);
308
+ var path6 = __toESM(require("path"), 1);
309
+ var import_child_process2 = require("child_process");
310
+ var p5 = __toESM(require("@clack/prompts"), 1);
311
+
312
+ // src/cli/utils/config.ts
313
+ var fs4 = __toESM(require("fs"), 1);
314
+ var path4 = __toESM(require("path"), 1);
315
+ var Config = class {
316
+ /**
317
+ * Detect the D1 database binding from Wrangler configuration or d1-orm config.
318
+ *
319
+ * @returns The binding name (e.g., "DB").
320
+ */
321
+ static getD1Binding() {
322
+ const srcConfig = path4.join(process.cwd(), "src/database/config.ts");
323
+ const rootConfig = path4.join(process.cwd(), "database/config.ts");
324
+ const configPath = fs4.existsSync(srcConfig) ? srcConfig : fs4.existsSync(rootConfig) ? rootConfig : null;
325
+ if (configPath) {
326
+ const content = fs4.readFileSync(configPath, "utf-8");
327
+ const match = content.match(/binding\s*:\s*["'](.+?)["']/);
328
+ if (match) return match[1];
329
+ }
330
+ const wranglerPaths = ["wrangler.jsonc", "wrangler.json", "wrangler.toml"];
331
+ for (const configName of wranglerPaths) {
332
+ const fullPath = path4.join(process.cwd(), configName);
333
+ if (fs4.existsSync(fullPath)) {
334
+ const content = fs4.readFileSync(fullPath, "utf-8");
335
+ if (configName.endsWith(".json") || configName.endsWith(".jsonc")) {
336
+ try {
337
+ const jsonStr = content.replace(/\/\/.*|\/\*[\s\S]*?\*\//g, "");
338
+ const config = JSON.parse(jsonStr);
339
+ const d1Databases = config.d1_databases;
340
+ if (Array.isArray(d1Databases) && d1Databases.length > 0) {
341
+ return d1Databases[0].binding || "DB";
342
+ }
343
+ } catch (e) {
344
+ }
345
+ }
346
+ if (configName.endsWith(".toml")) {
347
+ const match = content.match(/binding\s*=\s*["'](.+?)["']/);
348
+ if (match) return match[1];
349
+ }
350
+ }
351
+ }
352
+ return "DB";
353
+ }
354
+ /**
355
+ * Detect if the project is ESM.
356
+ */
357
+ static isESM() {
358
+ const pkgPath = path4.join(process.cwd(), "package.json");
359
+ if (fs4.existsSync(pkgPath)) {
360
+ try {
361
+ const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
362
+ return pkg.type === "module";
363
+ } catch (e) {
364
+ return false;
365
+ }
366
+ }
367
+ return false;
368
+ }
369
+ };
370
+
371
+ // src/cli/commands/seed.ts
372
+ var fs5 = __toESM(require("fs"), 1);
373
+ var path5 = __toESM(require("path"), 1);
374
+
375
+ // src/core/connection.ts
376
+ var Connection = class {
377
+ /**
378
+ * The underlying D1Database instance.
379
+ */
380
+ db;
381
+ /**
382
+ * Create a new Connection instance.
383
+ *
384
+ * @param database - The D1Database instance.
385
+ */
386
+ constructor(database) {
387
+ this.db = database;
388
+ }
389
+ /**
390
+ * Execute a SELECT statement.
391
+ *
392
+ * @param query - The SQL query string.
393
+ * @param bindings - The parameter bindings.
394
+ * @returns A promise that resolves to an array of results.
395
+ */
396
+ async select(query, bindings = []) {
397
+ const stmt = this.db.prepare(query).bind(...bindings);
398
+ const result = await stmt.all();
399
+ return result.results || [];
400
+ }
401
+ /**
402
+ * Execute an INSERT statement.
403
+ *
404
+ * @param query - The SQL query string.
405
+ * @param bindings - The parameter bindings.
406
+ * @returns A promise that resolves to true on success.
407
+ */
408
+ async insert(query, bindings = []) {
409
+ const stmt = this.db.prepare(query).bind(...bindings);
410
+ const result = await stmt.run();
411
+ return result.success;
412
+ }
413
+ /**
414
+ * Execute an UPDATE statement.
415
+ *
416
+ * @param query - The SQL query string.
417
+ * @param bindings - The parameter bindings.
418
+ * @returns A promise that resolves to true on success.
419
+ */
420
+ async update(query, bindings = []) {
421
+ const stmt = this.db.prepare(query).bind(...bindings);
422
+ const result = await stmt.run();
423
+ return result.success;
424
+ }
425
+ /**
426
+ * Execute a DELETE statement.
427
+ *
428
+ * @param query - The SQL query string.
429
+ * @param bindings - The parameter bindings.
430
+ * @returns A promise that resolves to true on success.
431
+ */
432
+ async delete(query, bindings = []) {
433
+ const stmt = this.db.prepare(query).bind(...bindings);
434
+ const result = await stmt.run();
435
+ return result.success;
436
+ }
437
+ /**
438
+ * Execute an arbitrary SQL statement.
439
+ *
440
+ * @param query - The SQL query string.
441
+ * @param bindings - The parameter bindings.
442
+ * @returns A promise that resolves to true on success.
443
+ */
444
+ async statement(query, bindings = []) {
445
+ const stmt = this.db.prepare(query).bind(...bindings);
446
+ const result = await stmt.run();
447
+ return result.success;
448
+ }
449
+ };
450
+
451
+ // src/core/database.ts
452
+ var Database = class _Database {
453
+ /**
454
+ * Symbol for global singleton access.
455
+ */
456
+ static INSTANCE_KEY = /* @__PURE__ */ Symbol.for("d1-orm-instance");
457
+ /**
458
+ * The active database connection.
459
+ */
460
+ connection;
461
+ /**
462
+ * Private constructor to enforce singleton pattern.
463
+ *
464
+ * @param d1 - The D1Database instance from Cloudflare.
465
+ */
466
+ constructor(d1) {
467
+ this.connection = new Connection(d1);
468
+ }
469
+ /**
470
+ * Setup the database connection.
471
+ *
472
+ * @param d1 - The D1Database instance from Cloudflare environment (env.DB).
473
+ */
474
+ static setup(d1) {
475
+ globalThis[_Database.INSTANCE_KEY] = new _Database(d1);
476
+ }
477
+ /**
478
+ * Get the singleton Database instance.
479
+ *
480
+ * @throws Error if setup() has not been called and auto-init fails.
481
+ * @returns The Database instance.
482
+ */
483
+ static getInstance() {
484
+ const instance = globalThis[_Database.INSTANCE_KEY];
485
+ if (!instance) {
486
+ if (globalThis["DB"] && typeof globalThis["DB"].prepare === "function") {
487
+ _Database.setup(globalThis["DB"]);
488
+ return globalThis[_Database.INSTANCE_KEY];
489
+ }
490
+ throw new Error(
491
+ "Database not initialized. Call Database.setup(env.DB) first or ensure your D1 binding is named 'DB'."
492
+ );
493
+ }
494
+ return instance;
495
+ }
496
+ };
497
+
498
+ // src/cli/cli-connection.ts
499
+ var import_child_process = require("child_process");
500
+ var CLIConnection = class {
501
+ constructor(dbName = "DB", isRemote = false) {
502
+ this.dbName = dbName;
503
+ this.isRemote = isRemote;
504
+ }
505
+ prepare(query) {
506
+ return new CLIPREparedStatement(query, this.dbName, this.isRemote);
507
+ }
508
+ async dump() {
509
+ throw new Error("dump() is not supported in CLI mode.");
510
+ }
511
+ async batch(statements) {
512
+ const results = [];
513
+ for (const stmt of statements) {
514
+ results.push(await stmt.run());
515
+ }
516
+ return results;
517
+ }
518
+ async exec(query) {
519
+ const start = Date.now();
520
+ await this.executeWrangler(query);
521
+ return {
522
+ count: 1,
523
+ // Approximation
524
+ duration: Date.now() - start
525
+ };
526
+ }
527
+ executeWrangler(sql) {
528
+ const flag = this.isRemote ? "--remote" : "--local";
529
+ const command2 = `npx wrangler d1 execute ${this.dbName} --command "${sql.replace(/"/g, '\\"')}" ${flag} --json`;
530
+ try {
531
+ const output = (0, import_child_process.execSync)(command2, {
532
+ encoding: "utf-8",
533
+ stdio: ["ignore", "pipe", "inherit"]
534
+ });
535
+ const jsonStart = output.indexOf("[");
536
+ if (jsonStart !== -1) {
537
+ return JSON.parse(output.substring(jsonStart));
538
+ }
539
+ return null;
540
+ } catch (e) {
541
+ console.error(`Error executing wrangler command: ${command2}`);
542
+ throw e;
543
+ }
544
+ }
545
+ };
546
+ var CLIPREparedStatement = class {
547
+ constructor(query, dbName, isRemote) {
548
+ this.query = query;
549
+ this.dbName = dbName;
550
+ this.isRemote = isRemote;
551
+ }
552
+ bindings = [];
553
+ bind(...values) {
554
+ this.bindings = values;
555
+ return this;
556
+ }
557
+ resolveQuery() {
558
+ let sql = this.query;
559
+ this.bindings.forEach((value) => {
560
+ const formattedValue = typeof value === "string" ? `'${value.replace(/'/g, "''")}'` : value;
561
+ sql = sql.replace("?", String(formattedValue));
562
+ });
563
+ return sql;
564
+ }
565
+ async first(colName) {
566
+ const result = await this.all();
567
+ const firstRow = result.results[0] || null;
568
+ if (firstRow && colName) {
569
+ return firstRow[colName];
570
+ }
571
+ return firstRow;
572
+ }
573
+ async run() {
574
+ return this.all();
575
+ }
576
+ async all() {
577
+ const sql = this.resolveQuery();
578
+ const flag = this.isRemote ? "--remote" : "--local";
579
+ const command2 = `npx wrangler d1 execute ${this.dbName} --command "${sql.replace(/"/g, '\\"')}" ${flag} --json`;
580
+ try {
581
+ const output = (0, import_child_process.execSync)(command2, {
582
+ encoding: "utf-8",
583
+ stdio: ["ignore", "pipe", "pipe"]
584
+ });
585
+ const jsonStart = output.indexOf("[");
586
+ if (jsonStart !== -1) {
587
+ const results = JSON.parse(output.substring(jsonStart));
588
+ const primaryResult = results[0];
589
+ return {
590
+ results: primaryResult.results || [],
591
+ success: primaryResult.success ?? true,
592
+ meta: primaryResult.meta || {}
593
+ };
594
+ }
595
+ return { results: [], success: true, meta: {} };
596
+ } catch (e) {
597
+ return { results: [], success: false, meta: {}, error: e.message };
598
+ }
599
+ }
600
+ async raw() {
601
+ const result = await this.all();
602
+ return result.results;
603
+ }
604
+ };
605
+
606
+ // src/cli/commands/seed.ts
607
+ var p4 = __toESM(require("@clack/prompts"), 1);
608
+ async function seed(args2) {
609
+ p4.intro("Seeding database...");
610
+ const srcSeedersDir = path5.join(process.cwd(), "src/database/seeders");
611
+ const rootSeedersDir = path5.join(process.cwd(), "database/seeders");
612
+ const seedersDir = fs5.existsSync(srcSeedersDir) ? srcSeedersDir : rootSeedersDir;
613
+ if (!fs5.existsSync(seedersDir)) {
614
+ p4.log.warn(
615
+ `No seeders directory found (checked ${srcSeedersDir} and ${rootSeedersDir}).`
616
+ );
617
+ p4.outro("Nothing to seed.");
618
+ return;
619
+ }
620
+ const isRemote = args2.includes("--remote");
621
+ const dbName = Config.getD1Binding();
622
+ const s = p4.spinner();
623
+ s.start(`Initializing ORM (Binding: ${dbName})...`);
624
+ try {
625
+ const connection = new CLIConnection(dbName, isRemote);
626
+ Database.setup(connection);
627
+ s.stop(`ORM initialized successfully with binding "${dbName}".`);
628
+ const files = fs5.readdirSync(seedersDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js")).sort();
629
+ if (files.length === 0) {
630
+ p4.log.info("No seeder files found.");
631
+ p4.outro("Seeding complete.");
632
+ return;
633
+ }
634
+ for (const file of files) {
635
+ s.start(`Running seeder: ${file}`);
636
+ const filePath = path5.join(seedersDir, file);
637
+ try {
638
+ const seeder = await import(filePath);
639
+ if (seeder.seed) {
640
+ await seeder.seed(Database.getInstance());
641
+ s.stop(`Completed: ${file}`);
642
+ } else {
643
+ s.stop(`Skipped: ${file} (no seed function)`, 1);
644
+ }
645
+ } catch (error) {
646
+ s.stop(`Failed: ${file}`, 1);
647
+ p4.log.error(`Error running seeder ${file}: ${error}`);
648
+ }
649
+ }
650
+ p4.outro("Seeding completed successfully.");
651
+ } catch (error) {
652
+ s.stop("Initialization failed.", 1);
653
+ p4.log.error(`Seeding error: ${error}`);
654
+ }
655
+ }
656
+
657
+ // src/cli/commands/migrate.ts
658
+ async function migrate(args2) {
659
+ p5.intro("Running migrations...");
660
+ const srcMigrationsDir = path6.join(process.cwd(), "src/database/migrations");
661
+ const rootMigrationsDir = path6.join(process.cwd(), "database/migrations");
662
+ const migrationsDir = fs6.existsSync(srcMigrationsDir) ? srcMigrationsDir : rootMigrationsDir;
663
+ if (!fs6.existsSync(migrationsDir)) {
664
+ p5.log.warn(
665
+ `No migrations directory found (checked ${srcMigrationsDir} and ${rootMigrationsDir}).`
666
+ );
667
+ p5.outro("Nothing to migrate.");
668
+ return;
669
+ }
670
+ const files = fs6.readdirSync(migrationsDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js")).sort();
671
+ if (files.length === 0) {
672
+ p5.log.info("No migration files found.");
673
+ p5.outro("Migrations complete.");
674
+ return;
675
+ }
676
+ const s = p5.spinner();
677
+ const dbName = Config.getD1Binding();
678
+ for (const file of files) {
679
+ s.start(`Processing migration: ${file} (Binding: ${dbName})`);
680
+ const filePath = path6.join(migrationsDir, file);
681
+ try {
682
+ const migration = await import(filePath);
683
+ if (migration.up) {
684
+ const sql = await migration.up();
685
+ if (sql) {
686
+ const isRemote = args2.includes("--remote");
687
+ const command2 = isRemote ? "--remote" : "--local";
688
+ try {
689
+ const execCmd = `npx wrangler d1 execute ${dbName} --command "${sql.replace(/"/g, '\\"')}" ${command2}`;
690
+ (0, import_child_process2.execSync)(execCmd, { stdio: "pipe" });
691
+ s.stop(`Migrated: ${file}`);
692
+ } catch (e) {
693
+ s.stop(`Failed: ${file}`, 1);
694
+ p5.log.error(`Failed to execute migration: ${file}`);
695
+ throw e;
696
+ }
697
+ } else {
698
+ s.stop(`Skipped (no SQL): ${file}`);
699
+ }
700
+ } else {
701
+ s.stop(`Skipped (no up function): ${file}`);
702
+ }
703
+ } catch (error) {
704
+ s.stop(`Error: ${file}`, 1);
705
+ p5.log.error(`Error processing migration ${file}: ${error}`);
706
+ }
707
+ }
708
+ p5.outro("All migrations executed.");
709
+ if (args2.includes("--seed")) {
710
+ await seed(args2);
711
+ }
712
+ }
713
+
714
+ // src/cli/commands/migrate-fresh.ts
715
+ var import_child_process3 = require("child_process");
716
+ var p6 = __toESM(require("@clack/prompts"), 1);
717
+ async function migrateFresh(args2) {
718
+ p6.intro("Resetting database...");
719
+ const isRemote = args2.includes("--remote");
720
+ const dbName = Config.getD1Binding();
721
+ const flag = isRemote ? "--remote" : "--local";
722
+ const s = p6.spinner();
723
+ s.start("Scanning for tables to drop...");
724
+ try {
725
+ 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`;
726
+ const output = (0, import_child_process3.execSync)(listTablesCmd, {
727
+ encoding: "utf-8",
728
+ stdio: ["ignore", "pipe", "inherit"]
729
+ });
730
+ const jsonStart = output.indexOf("[");
731
+ if (jsonStart !== -1) {
732
+ const results = JSON.parse(output.substring(jsonStart));
733
+ const tables = results[0]?.results || [];
734
+ if (tables.length > 0) {
735
+ s.message(`Dropping ${tables.length} tables...`);
736
+ const dropCommands = tables.map((t) => `DROP TABLE IF EXISTS ${t.name};`).join(" ");
737
+ const dropCmd = `npx wrangler d1 execute ${dbName} --command "${dropCommands}" ${flag}`;
738
+ (0, import_child_process3.execSync)(dropCmd, { stdio: "pipe" });
739
+ s.stop("All tables dropped successfully.");
740
+ } else {
741
+ s.stop("No tables found to drop.");
742
+ }
743
+ } else {
744
+ s.stop("Unexpected output from wrangler while listing tables.", 1);
745
+ }
746
+ await migrate(args2);
747
+ } catch (error) {
748
+ s.stop("Process failed.", 1);
749
+ p6.log.error(`Error during migrate:fresh: ${error}`);
750
+ }
751
+ }
752
+
753
+ // src/cli/index.ts
754
+ var args = process.argv.slice(2);
755
+ var command = args[0];
756
+ var param = args[1];
757
+ switch (command) {
758
+ case "init":
759
+ init();
760
+ break;
761
+ case "make:model":
762
+ makeModel(param);
763
+ break;
764
+ case "make:migration":
765
+ makeMigration(param);
766
+ break;
767
+ case "migrate":
768
+ migrate(args);
769
+ break;
770
+ case "migrate:fresh":
771
+ migrateFresh(args);
772
+ break;
773
+ case "db:seed":
774
+ seed(args);
775
+ break;
776
+ default:
777
+ console.log(
778
+ "Available commands: init, make:model, make:migration, migrate, migrate:fresh, db:seed"
779
+ );
780
+ break;
781
+ }