@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.
- package/README.md +41 -148
- package/dist/chunk-N3G6NOJP.js +127 -0
- package/dist/cli/index.cjs +781 -0
- package/dist/cli/index.js +244 -254
- package/dist/{index.mjs → index.cjs} +159 -14
- package/dist/{index.d.mts → index.d.cts} +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +6 -157
- package/package.json +2 -2
- package/dist/chunk-5BBZKUNZ.mjs +0 -147
- package/dist/cli/index.mjs +0 -559
- /package/dist/cli/{index.d.mts → index.d.cts} +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -1,58 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
));
|
|
2
|
+
import {
|
|
3
|
+
Database
|
|
4
|
+
} from "../chunk-N3G6NOJP.js";
|
|
25
5
|
|
|
26
6
|
// src/cli/commands/init.ts
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import * as p from "@clack/prompts";
|
|
30
10
|
async function init() {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const defaultModelsPath = "src/models";
|
|
42
|
-
const userModelsPath = await question(
|
|
43
|
-
`Where would you like to install your models? (default: ${defaultModelsPath}): `
|
|
44
|
-
) || defaultModelsPath;
|
|
45
|
-
rl.close();
|
|
46
|
-
const folders = [userModelsPath, "database/migrations", "database/seeders"];
|
|
11
|
+
p.intro("Initializing D1 ORM...");
|
|
12
|
+
const s = p.spinner();
|
|
13
|
+
s.start("Scanning project structure...");
|
|
14
|
+
const srcPath = path.join(process.cwd(), "src");
|
|
15
|
+
const useSrc = fs.existsSync(srcPath) && fs.lstatSync(srcPath).isDirectory();
|
|
16
|
+
const baseDatabasePath = useSrc ? "src/database" : "database";
|
|
17
|
+
const modelsPath = path.join(baseDatabasePath, "models");
|
|
18
|
+
const migrationsPath = path.join(baseDatabasePath, "migrations");
|
|
19
|
+
const seedersPath = path.join(baseDatabasePath, "seeders");
|
|
20
|
+
const folders = [modelsPath, migrationsPath, seedersPath];
|
|
47
21
|
folders.forEach((folder) => {
|
|
48
22
|
const fullPath = path.join(process.cwd(), folder);
|
|
49
23
|
if (!fs.existsSync(fullPath)) {
|
|
50
24
|
fs.mkdirSync(fullPath, { recursive: true });
|
|
51
|
-
|
|
25
|
+
p.log.step(`Created directory: ${folder}`);
|
|
52
26
|
} else {
|
|
53
|
-
|
|
27
|
+
p.log.info(`Directory already exists: ${folder}`);
|
|
54
28
|
}
|
|
55
29
|
});
|
|
30
|
+
s.message("Generating example files...");
|
|
56
31
|
const userModelContent = `import { Model } from '@3lineas/d1-orm';
|
|
57
32
|
|
|
58
33
|
export class User extends Model {
|
|
@@ -66,10 +41,10 @@ export class User extends Model {
|
|
|
66
41
|
declare updated_at: string;
|
|
67
42
|
}
|
|
68
43
|
`;
|
|
69
|
-
const userModelPath = path.join(process.cwd(),
|
|
44
|
+
const userModelPath = path.join(process.cwd(), modelsPath, "User.ts");
|
|
70
45
|
if (!fs.existsSync(userModelPath)) {
|
|
71
46
|
fs.writeFileSync(userModelPath, userModelContent);
|
|
72
|
-
|
|
47
|
+
p.log.step(`Created model: ${modelsPath}/User.ts`);
|
|
73
48
|
}
|
|
74
49
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").split(".")[0].replace("T", "_");
|
|
75
50
|
const migrationName = `${timestamp}_create_users_table.ts`;
|
|
@@ -89,19 +64,16 @@ export const down = async () => {
|
|
|
89
64
|
return Schema.dropIfExists('users');
|
|
90
65
|
};
|
|
91
66
|
`;
|
|
92
|
-
const
|
|
67
|
+
const fullMigrationsPath = path.join(
|
|
93
68
|
process.cwd(),
|
|
94
|
-
|
|
69
|
+
migrationsPath,
|
|
95
70
|
migrationName
|
|
96
71
|
);
|
|
97
|
-
if (!fs.existsSync(
|
|
98
|
-
fs.writeFileSync(
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
const seederContent = `import { User } from '
|
|
102
|
-
path.join(process.cwd(), "database/seeders"),
|
|
103
|
-
path.join(process.cwd(), userModelsPath, "User")
|
|
104
|
-
).replace(/\\/g, "/")}.ts';
|
|
72
|
+
if (!fs.existsSync(fullMigrationsPath)) {
|
|
73
|
+
fs.writeFileSync(fullMigrationsPath, migrationContent);
|
|
74
|
+
p.log.step(`Created migration: ${migrationsPath}/${migrationName}`);
|
|
75
|
+
}
|
|
76
|
+
const seederContent = `import { User } from '../models/User.ts';
|
|
105
77
|
|
|
106
78
|
export const seed = async () => {
|
|
107
79
|
await User.create({
|
|
@@ -111,14 +83,23 @@ export const seed = async () => {
|
|
|
111
83
|
});
|
|
112
84
|
};
|
|
113
85
|
`;
|
|
114
|
-
const
|
|
86
|
+
const fullSeederPath = path.join(process.cwd(), seedersPath, "UserSeeder.ts");
|
|
87
|
+
if (!fs.existsSync(fullSeederPath)) {
|
|
88
|
+
fs.writeFileSync(fullSeederPath, seederContent);
|
|
89
|
+
p.log.step(`Created seeder: ${seedersPath}/UserSeeder.ts`);
|
|
90
|
+
}
|
|
91
|
+
const configContent = `export default {
|
|
92
|
+
binding: 'DB', // Name of the D1 binding in wrangler.jsonc/toml
|
|
93
|
+
};
|
|
94
|
+
`;
|
|
95
|
+
const configFilePath = path.join(
|
|
115
96
|
process.cwd(),
|
|
116
|
-
|
|
117
|
-
"
|
|
97
|
+
baseDatabasePath,
|
|
98
|
+
"config.ts"
|
|
118
99
|
);
|
|
119
|
-
if (!fs.existsSync(
|
|
120
|
-
fs.writeFileSync(
|
|
121
|
-
|
|
100
|
+
if (!fs.existsSync(configFilePath)) {
|
|
101
|
+
fs.writeFileSync(configFilePath, configContent);
|
|
102
|
+
p.log.step(`Created config: ${baseDatabasePath}/config.ts`);
|
|
122
103
|
}
|
|
123
104
|
const packageJsonPath = path.join(process.cwd(), "package.json");
|
|
124
105
|
if (fs.existsSync(packageJsonPath)) {
|
|
@@ -130,43 +111,50 @@ export const seed = async () => {
|
|
|
130
111
|
if (!packageJson.scripts.orm) {
|
|
131
112
|
packageJson.scripts.orm = "d1-orm";
|
|
132
113
|
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
133
|
-
|
|
134
|
-
} else {
|
|
135
|
-
console.log('"orm" script already exists in package.json');
|
|
114
|
+
p.log.step('Added "orm" script to package.json');
|
|
136
115
|
}
|
|
137
116
|
} catch (e) {
|
|
138
|
-
|
|
117
|
+
p.log.error(`Failed to update package.json: ${e}`);
|
|
139
118
|
}
|
|
140
119
|
}
|
|
120
|
+
s.stop("Initialization complete!");
|
|
121
|
+
p.outro("D1 ORM is ready to use.");
|
|
141
122
|
}
|
|
142
123
|
|
|
143
124
|
// src/cli/commands/make-model.ts
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
125
|
+
import * as fs3 from "fs";
|
|
126
|
+
import * as path3 from "path";
|
|
127
|
+
import * as p3 from "@clack/prompts";
|
|
147
128
|
|
|
148
129
|
// src/cli/commands/make-migration.ts
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
130
|
+
import * as fs2 from "fs";
|
|
131
|
+
import * as path2 from "path";
|
|
132
|
+
import * as p2 from "@clack/prompts";
|
|
152
133
|
async function makeMigration(name) {
|
|
134
|
+
const isStandalone = !name;
|
|
135
|
+
if (isStandalone) {
|
|
136
|
+
p2.intro("Creating a new migration...");
|
|
137
|
+
}
|
|
153
138
|
let migrationName = name;
|
|
154
139
|
if (!migrationName) {
|
|
155
|
-
migrationName = await
|
|
140
|
+
migrationName = await p2.text({
|
|
156
141
|
message: "What should the migration be named?",
|
|
157
142
|
placeholder: "e.g. create_users_table",
|
|
158
143
|
validate: (value) => {
|
|
159
144
|
if (!value) return "Please enter a name.";
|
|
160
145
|
}
|
|
161
146
|
});
|
|
162
|
-
if (
|
|
163
|
-
|
|
147
|
+
if (p2.isCancel(migrationName)) {
|
|
148
|
+
p2.cancel("Operation cancelled.");
|
|
164
149
|
return;
|
|
165
150
|
}
|
|
166
151
|
}
|
|
152
|
+
const srcMigrationsDir = path2.join(process.cwd(), "src/database/migrations");
|
|
153
|
+
const rootMigrationsDir = path2.join(process.cwd(), "database/migrations");
|
|
154
|
+
const migrationsDir = fs2.existsSync(srcMigrationsDir) ? "src/database/migrations" : "database/migrations";
|
|
167
155
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").split(".")[0].replace("T", "_");
|
|
168
156
|
const filename = `${timestamp}_${migrationName}.ts`;
|
|
169
|
-
const targetPath = path2.join(process.cwd(),
|
|
157
|
+
const targetPath = path2.join(process.cwd(), migrationsDir, filename);
|
|
170
158
|
const template = `import { Blueprint, Schema } from '@3lineas/d1-orm';
|
|
171
159
|
|
|
172
160
|
export const up = async () => {
|
|
@@ -180,36 +168,41 @@ export const down = async () => {
|
|
|
180
168
|
return Schema.dropIfExists('${migrationName.replace("create_", "").replace("_table", "")}');
|
|
181
169
|
};
|
|
182
170
|
`;
|
|
183
|
-
if (!fs2.existsSync(path2.join(process.cwd(),
|
|
184
|
-
fs2.mkdirSync(path2.join(process.cwd(),
|
|
171
|
+
if (!fs2.existsSync(path2.join(process.cwd(), migrationsDir))) {
|
|
172
|
+
fs2.mkdirSync(path2.join(process.cwd(), migrationsDir), {
|
|
185
173
|
recursive: true
|
|
186
174
|
});
|
|
187
175
|
}
|
|
188
176
|
if (fs2.existsSync(targetPath)) {
|
|
189
|
-
|
|
177
|
+
p2.log.error(`Migration ${filename} already exists.`);
|
|
178
|
+
if (isStandalone) p2.outro("Process aborted.");
|
|
190
179
|
return;
|
|
191
180
|
}
|
|
192
181
|
fs2.writeFileSync(targetPath, template);
|
|
193
|
-
|
|
182
|
+
p2.log.success(`Created migration: ${migrationsDir}/${filename}`);
|
|
183
|
+
if (isStandalone) {
|
|
184
|
+
p2.outro("Migration generated successfully!");
|
|
185
|
+
}
|
|
194
186
|
}
|
|
195
187
|
|
|
196
188
|
// src/cli/commands/make-model.ts
|
|
197
189
|
async function makeModel(name) {
|
|
190
|
+
p3.intro("Creating a new model...");
|
|
198
191
|
let modelName = name;
|
|
199
192
|
if (!modelName) {
|
|
200
|
-
modelName = await
|
|
193
|
+
modelName = await p3.text({
|
|
201
194
|
message: "What should the model be named?",
|
|
202
195
|
placeholder: "e.g. Flight",
|
|
203
196
|
validate: (value) => {
|
|
204
197
|
if (!value) return "Please enter a name.";
|
|
205
198
|
}
|
|
206
199
|
});
|
|
207
|
-
if (
|
|
208
|
-
|
|
200
|
+
if (p3.isCancel(modelName)) {
|
|
201
|
+
p3.cancel("Operation cancelled.");
|
|
209
202
|
return;
|
|
210
203
|
}
|
|
211
204
|
}
|
|
212
|
-
const modelPath = await findModelsPath() || "src/models";
|
|
205
|
+
const modelPath = await findModelsPath() || "src/database/models";
|
|
213
206
|
const filename = `${modelName}.ts`;
|
|
214
207
|
const targetPath = path3.join(process.cwd(), modelPath, filename);
|
|
215
208
|
const template = `import { Model } from '@3lineas/d1-orm';
|
|
@@ -223,15 +216,16 @@ export class ${modelName} extends Model {
|
|
|
223
216
|
}
|
|
224
217
|
`;
|
|
225
218
|
if (fs3.existsSync(targetPath)) {
|
|
226
|
-
|
|
219
|
+
p3.log.error(`Model ${filename} already exists at ${modelPath}.`);
|
|
220
|
+
p3.outro("Process aborted.");
|
|
227
221
|
return;
|
|
228
222
|
}
|
|
229
223
|
if (!fs3.existsSync(path3.join(process.cwd(), modelPath))) {
|
|
230
224
|
fs3.mkdirSync(path3.join(process.cwd(), modelPath), { recursive: true });
|
|
231
225
|
}
|
|
232
226
|
fs3.writeFileSync(targetPath, template);
|
|
233
|
-
|
|
234
|
-
const options = await
|
|
227
|
+
p3.log.success(`Created model: ${modelPath}/${filename}`);
|
|
228
|
+
const options = await p3.multiselect({
|
|
235
229
|
message: "Would you like to create any of the following?",
|
|
236
230
|
options: [
|
|
237
231
|
{ value: "migration", label: "Migration" },
|
|
@@ -239,8 +233,8 @@ export class ${modelName} extends Model {
|
|
|
239
233
|
],
|
|
240
234
|
required: false
|
|
241
235
|
});
|
|
242
|
-
if (
|
|
243
|
-
|
|
236
|
+
if (p3.isCancel(options)) {
|
|
237
|
+
p3.cancel("Operation cancelled.");
|
|
244
238
|
return;
|
|
245
239
|
}
|
|
246
240
|
if (options.includes("migration")) {
|
|
@@ -250,18 +244,25 @@ export class ${modelName} extends Model {
|
|
|
250
244
|
if (options.includes("seeder")) {
|
|
251
245
|
await makeSeeder(modelName, modelPath);
|
|
252
246
|
}
|
|
247
|
+
p3.outro("Model generation complete!");
|
|
253
248
|
}
|
|
254
249
|
async function findModelsPath() {
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
250
|
+
const commonPaths = [
|
|
251
|
+
"src/database/models",
|
|
252
|
+
"database/models",
|
|
253
|
+
"src/models",
|
|
254
|
+
"models",
|
|
255
|
+
"app/Models"
|
|
256
|
+
];
|
|
257
|
+
for (const p7 of commonPaths) {
|
|
258
|
+
if (fs3.existsSync(path3.join(process.cwd(), p7))) return p7;
|
|
260
259
|
}
|
|
261
260
|
return null;
|
|
262
261
|
}
|
|
263
262
|
async function makeSeeder(modelName, modelPath) {
|
|
264
|
-
const
|
|
263
|
+
const srcPath = path3.join(process.cwd(), "src");
|
|
264
|
+
const useSrc = fs3.existsSync(srcPath) && fs3.lstatSync(srcPath).isDirectory();
|
|
265
|
+
const seederDir = useSrc ? path3.join(process.cwd(), "src/database/seeders") : path3.join(process.cwd(), "database/seeders");
|
|
265
266
|
const seederName = `${modelName}Seeder.ts`;
|
|
266
267
|
const targetPath = path3.join(seederDir, seederName);
|
|
267
268
|
if (!fs3.existsSync(seederDir)) {
|
|
@@ -275,142 +276,84 @@ export const seed = async () => {
|
|
|
275
276
|
};
|
|
276
277
|
`;
|
|
277
278
|
if (fs3.existsSync(targetPath)) {
|
|
278
|
-
|
|
279
|
+
p3.log.warn(`Seeder ${seederName} already exists.`);
|
|
279
280
|
return;
|
|
280
281
|
}
|
|
281
282
|
fs3.writeFileSync(targetPath, template);
|
|
282
|
-
|
|
283
|
+
p3.log.success(`Created seeder: database/seeders/${seederName}`);
|
|
283
284
|
}
|
|
284
285
|
|
|
285
286
|
// src/cli/commands/migrate.ts
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
287
|
+
import * as fs6 from "fs";
|
|
288
|
+
import * as path6 from "path";
|
|
289
|
+
import { execSync as execSync2 } from "child_process";
|
|
290
|
+
import * as p5 from "@clack/prompts";
|
|
289
291
|
|
|
290
|
-
// src/cli/
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
}
|
|
292
|
+
// src/cli/utils/config.ts
|
|
293
|
+
import * as fs4 from "fs";
|
|
294
|
+
import * as path4 from "path";
|
|
295
|
+
var Config = class {
|
|
308
296
|
/**
|
|
309
|
-
*
|
|
297
|
+
* Detect the D1 database binding from Wrangler configuration or d1-orm config.
|
|
310
298
|
*
|
|
311
|
-
* @
|
|
312
|
-
* @param bindings - The parameter bindings.
|
|
313
|
-
* @returns A promise that resolves to an array of results.
|
|
299
|
+
* @returns The binding name (e.g., "DB").
|
|
314
300
|
*/
|
|
315
|
-
|
|
316
|
-
const
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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);
|
|
301
|
+
static getD1Binding() {
|
|
302
|
+
const srcConfig = path4.join(process.cwd(), "src/database/config.ts");
|
|
303
|
+
const rootConfig = path4.join(process.cwd(), "database/config.ts");
|
|
304
|
+
const configPath = fs4.existsSync(srcConfig) ? srcConfig : fs4.existsSync(rootConfig) ? rootConfig : null;
|
|
305
|
+
if (configPath) {
|
|
306
|
+
const content = fs4.readFileSync(configPath, "utf-8");
|
|
307
|
+
const match = content.match(/binding\s*:\s*["'](.+?)["']/);
|
|
308
|
+
if (match) return match[1];
|
|
309
|
+
}
|
|
310
|
+
const wranglerPaths = ["wrangler.jsonc", "wrangler.json", "wrangler.toml"];
|
|
311
|
+
for (const configName of wranglerPaths) {
|
|
312
|
+
const fullPath = path4.join(process.cwd(), configName);
|
|
313
|
+
if (fs4.existsSync(fullPath)) {
|
|
314
|
+
const content = fs4.readFileSync(fullPath, "utf-8");
|
|
315
|
+
if (configName.endsWith(".json") || configName.endsWith(".jsonc")) {
|
|
316
|
+
try {
|
|
317
|
+
const jsonStr = content.replace(/\/\/.*|\/\*[\s\S]*?\*\//g, "");
|
|
318
|
+
const config = JSON.parse(jsonStr);
|
|
319
|
+
const d1Databases = config.d1_databases;
|
|
320
|
+
if (Array.isArray(d1Databases) && d1Databases.length > 0) {
|
|
321
|
+
return d1Databases[0].binding || "DB";
|
|
322
|
+
}
|
|
323
|
+
} catch (e) {
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (configName.endsWith(".toml")) {
|
|
327
|
+
const match = content.match(/binding\s*=\s*["'](.+?)["']/);
|
|
328
|
+
if (match) return match[1];
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return "DB";
|
|
395
333
|
}
|
|
396
334
|
/**
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
* @throws Error if setup() has not been called.
|
|
400
|
-
* @returns The Database instance.
|
|
335
|
+
* Detect if the project is ESM.
|
|
401
336
|
*/
|
|
402
|
-
static
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
337
|
+
static isESM() {
|
|
338
|
+
const pkgPath = path4.join(process.cwd(), "package.json");
|
|
339
|
+
if (fs4.existsSync(pkgPath)) {
|
|
340
|
+
try {
|
|
341
|
+
const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
|
|
342
|
+
return pkg.type === "module";
|
|
343
|
+
} catch (e) {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
407
346
|
}
|
|
408
|
-
return
|
|
347
|
+
return false;
|
|
409
348
|
}
|
|
410
349
|
};
|
|
411
350
|
|
|
351
|
+
// src/cli/commands/seed.ts
|
|
352
|
+
import * as fs5 from "fs";
|
|
353
|
+
import * as path5 from "path";
|
|
354
|
+
|
|
412
355
|
// src/cli/cli-connection.ts
|
|
413
|
-
|
|
356
|
+
import { execSync } from "child_process";
|
|
414
357
|
var CLIConnection = class {
|
|
415
358
|
constructor(dbName = "DB", isRemote = false) {
|
|
416
359
|
this.dbName = dbName;
|
|
@@ -442,7 +385,7 @@ var CLIConnection = class {
|
|
|
442
385
|
const flag = this.isRemote ? "--remote" : "--local";
|
|
443
386
|
const command2 = `npx wrangler d1 execute ${this.dbName} --command "${sql.replace(/"/g, '\\"')}" ${flag} --json`;
|
|
444
387
|
try {
|
|
445
|
-
const output =
|
|
388
|
+
const output = execSync(command2, {
|
|
446
389
|
encoding: "utf-8",
|
|
447
390
|
stdio: ["ignore", "pipe", "inherit"]
|
|
448
391
|
});
|
|
@@ -492,7 +435,7 @@ var CLIPREparedStatement = class {
|
|
|
492
435
|
const flag = this.isRemote ? "--remote" : "--local";
|
|
493
436
|
const command2 = `npx wrangler d1 execute ${this.dbName} --command "${sql.replace(/"/g, '\\"')}" ${flag} --json`;
|
|
494
437
|
try {
|
|
495
|
-
const output =
|
|
438
|
+
const output = execSync(command2, {
|
|
496
439
|
encoding: "utf-8",
|
|
497
440
|
stdio: ["ignore", "pipe", "pipe"]
|
|
498
441
|
});
|
|
@@ -518,83 +461,126 @@ var CLIPREparedStatement = class {
|
|
|
518
461
|
};
|
|
519
462
|
|
|
520
463
|
// src/cli/commands/seed.ts
|
|
464
|
+
import * as p4 from "@clack/prompts";
|
|
521
465
|
async function seed(args2) {
|
|
522
|
-
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
466
|
+
p4.intro("Seeding database...");
|
|
467
|
+
const srcSeedersDir = path5.join(process.cwd(), "src/database/seeders");
|
|
468
|
+
const rootSeedersDir = path5.join(process.cwd(), "database/seeders");
|
|
469
|
+
const seedersDir = fs5.existsSync(srcSeedersDir) ? srcSeedersDir : rootSeedersDir;
|
|
470
|
+
if (!fs5.existsSync(seedersDir)) {
|
|
471
|
+
p4.log.warn(
|
|
472
|
+
`No seeders directory found (checked ${srcSeedersDir} and ${rootSeedersDir}).`
|
|
473
|
+
);
|
|
474
|
+
p4.outro("Nothing to seed.");
|
|
526
475
|
return;
|
|
527
476
|
}
|
|
528
477
|
const isRemote = args2.includes("--remote");
|
|
529
|
-
const dbName =
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
478
|
+
const dbName = Config.getD1Binding();
|
|
479
|
+
const s = p4.spinner();
|
|
480
|
+
s.start(`Initializing ORM (Binding: ${dbName})...`);
|
|
481
|
+
try {
|
|
482
|
+
const connection = new CLIConnection(dbName, isRemote);
|
|
483
|
+
Database.setup(connection);
|
|
484
|
+
s.stop(`ORM initialized successfully with binding "${dbName}".`);
|
|
485
|
+
const files = fs5.readdirSync(seedersDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js")).sort();
|
|
486
|
+
if (files.length === 0) {
|
|
487
|
+
p4.log.info("No seeder files found.");
|
|
488
|
+
p4.outro("Seeding complete.");
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
for (const file of files) {
|
|
492
|
+
s.start(`Running seeder: ${file}`);
|
|
493
|
+
const filePath = path5.join(seedersDir, file);
|
|
494
|
+
try {
|
|
495
|
+
const seeder = await import(filePath);
|
|
496
|
+
if (seeder.seed) {
|
|
497
|
+
await seeder.seed(Database.getInstance());
|
|
498
|
+
s.stop(`Completed: ${file}`);
|
|
499
|
+
} else {
|
|
500
|
+
s.stop(`Skipped: ${file} (no seed function)`, 1);
|
|
501
|
+
}
|
|
502
|
+
} catch (error) {
|
|
503
|
+
s.stop(`Failed: ${file}`, 1);
|
|
504
|
+
p4.log.error(`Error running seeder ${file}: ${error}`);
|
|
542
505
|
}
|
|
543
|
-
} catch (error) {
|
|
544
|
-
console.error(`Error running seeder ${file}:`, error);
|
|
545
506
|
}
|
|
507
|
+
p4.outro("Seeding completed successfully.");
|
|
508
|
+
} catch (error) {
|
|
509
|
+
s.stop("Initialization failed.", 1);
|
|
510
|
+
p4.log.error(`Seeding error: ${error}`);
|
|
546
511
|
}
|
|
547
512
|
}
|
|
548
513
|
|
|
549
514
|
// src/cli/commands/migrate.ts
|
|
550
515
|
async function migrate(args2) {
|
|
551
|
-
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
|
|
516
|
+
p5.intro("Running migrations...");
|
|
517
|
+
const srcMigrationsDir = path6.join(process.cwd(), "src/database/migrations");
|
|
518
|
+
const rootMigrationsDir = path6.join(process.cwd(), "database/migrations");
|
|
519
|
+
const migrationsDir = fs6.existsSync(srcMigrationsDir) ? srcMigrationsDir : rootMigrationsDir;
|
|
520
|
+
if (!fs6.existsSync(migrationsDir)) {
|
|
521
|
+
p5.log.warn(
|
|
522
|
+
`No migrations directory found (checked ${srcMigrationsDir} and ${rootMigrationsDir}).`
|
|
523
|
+
);
|
|
524
|
+
p5.outro("Nothing to migrate.");
|
|
555
525
|
return;
|
|
556
526
|
}
|
|
557
|
-
const files =
|
|
527
|
+
const files = fs6.readdirSync(migrationsDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js")).sort();
|
|
528
|
+
if (files.length === 0) {
|
|
529
|
+
p5.log.info("No migration files found.");
|
|
530
|
+
p5.outro("Migrations complete.");
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
const s = p5.spinner();
|
|
534
|
+
const dbName = Config.getD1Binding();
|
|
558
535
|
for (const file of files) {
|
|
559
|
-
|
|
560
|
-
const filePath =
|
|
536
|
+
s.start(`Processing migration: ${file} (Binding: ${dbName})`);
|
|
537
|
+
const filePath = path6.join(migrationsDir, file);
|
|
561
538
|
try {
|
|
562
539
|
const migration = await import(filePath);
|
|
563
540
|
if (migration.up) {
|
|
564
541
|
const sql = await migration.up();
|
|
565
542
|
if (sql) {
|
|
566
543
|
const isRemote = args2.includes("--remote");
|
|
567
|
-
const dbName = "DB";
|
|
568
544
|
const command2 = isRemote ? "--remote" : "--local";
|
|
569
545
|
try {
|
|
570
546
|
const execCmd = `npx wrangler d1 execute ${dbName} --command "${sql.replace(/"/g, '\\"')}" ${command2}`;
|
|
571
|
-
|
|
572
|
-
|
|
547
|
+
execSync2(execCmd, { stdio: "pipe" });
|
|
548
|
+
s.stop(`Migrated: ${file}`);
|
|
573
549
|
} catch (e) {
|
|
574
|
-
|
|
550
|
+
s.stop(`Failed: ${file}`, 1);
|
|
551
|
+
p5.log.error(`Failed to execute migration: ${file}`);
|
|
575
552
|
throw e;
|
|
576
553
|
}
|
|
554
|
+
} else {
|
|
555
|
+
s.stop(`Skipped (no SQL): ${file}`);
|
|
577
556
|
}
|
|
557
|
+
} else {
|
|
558
|
+
s.stop(`Skipped (no up function): ${file}`);
|
|
578
559
|
}
|
|
579
560
|
} catch (error) {
|
|
580
|
-
|
|
561
|
+
s.stop(`Error: ${file}`, 1);
|
|
562
|
+
p5.log.error(`Error processing migration ${file}: ${error}`);
|
|
581
563
|
}
|
|
582
564
|
}
|
|
565
|
+
p5.outro("All migrations executed.");
|
|
583
566
|
if (args2.includes("--seed")) {
|
|
584
567
|
await seed(args2);
|
|
585
568
|
}
|
|
586
569
|
}
|
|
587
570
|
|
|
588
571
|
// src/cli/commands/migrate-fresh.ts
|
|
589
|
-
|
|
572
|
+
import { execSync as execSync3 } from "child_process";
|
|
573
|
+
import * as p6 from "@clack/prompts";
|
|
590
574
|
async function migrateFresh(args2) {
|
|
591
|
-
|
|
575
|
+
p6.intro("Resetting database...");
|
|
592
576
|
const isRemote = args2.includes("--remote");
|
|
593
|
-
const dbName =
|
|
577
|
+
const dbName = Config.getD1Binding();
|
|
594
578
|
const flag = isRemote ? "--remote" : "--local";
|
|
579
|
+
const s = p6.spinner();
|
|
580
|
+
s.start("Scanning for tables to drop...");
|
|
595
581
|
try {
|
|
596
582
|
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 = (
|
|
583
|
+
const output = execSync3(listTablesCmd, {
|
|
598
584
|
encoding: "utf-8",
|
|
599
585
|
stdio: ["ignore", "pipe", "inherit"]
|
|
600
586
|
});
|
|
@@ -603,17 +589,21 @@ async function migrateFresh(args2) {
|
|
|
603
589
|
const results = JSON.parse(output.substring(jsonStart));
|
|
604
590
|
const tables = results[0]?.results || [];
|
|
605
591
|
if (tables.length > 0) {
|
|
592
|
+
s.message(`Dropping ${tables.length} tables...`);
|
|
606
593
|
const dropCommands = tables.map((t) => `DROP TABLE IF EXISTS ${t.name};`).join(" ");
|
|
607
594
|
const dropCmd = `npx wrangler d1 execute ${dbName} --command "${dropCommands}" ${flag}`;
|
|
608
|
-
|
|
609
|
-
|
|
595
|
+
execSync3(dropCmd, { stdio: "pipe" });
|
|
596
|
+
s.stop("All tables dropped successfully.");
|
|
610
597
|
} else {
|
|
611
|
-
|
|
598
|
+
s.stop("No tables found to drop.");
|
|
612
599
|
}
|
|
600
|
+
} else {
|
|
601
|
+
s.stop("Unexpected output from wrangler while listing tables.", 1);
|
|
613
602
|
}
|
|
614
603
|
await migrate(args2);
|
|
615
604
|
} catch (error) {
|
|
616
|
-
|
|
605
|
+
s.stop("Process failed.", 1);
|
|
606
|
+
p6.log.error(`Error during migrate:fresh: ${error}`);
|
|
617
607
|
}
|
|
618
608
|
}
|
|
619
609
|
|