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