@stacksjs/database 0.70.88 → 0.70.91
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/dist/auth-tables.d.ts +60 -0
- package/dist/auth-tables.js +220 -0
- package/dist/class-seeder.d.ts +65 -0
- package/dist/class-seeder.js +116 -0
- package/dist/column.d.ts +17 -0
- package/dist/column.js +26 -0
- package/dist/custom/audits.d.ts +16 -0
- package/dist/custom/audits.js +57 -0
- package/dist/custom/errors.d.ts +1 -0
- package/dist/custom/errors.js +48 -0
- package/dist/custom/index.d.ts +3 -0
- package/dist/custom/index.js +3 -0
- package/dist/custom/jobs.d.ts +3 -0
- package/dist/custom/jobs.js +449 -0
- package/dist/database.d.ts +89 -0
- package/dist/database.js +178 -0
- package/dist/defaults.d.ts +48 -0
- package/dist/defaults.js +48 -0
- package/dist/driver-config.d.ts +149 -0
- package/dist/driver-config.js +144 -0
- package/dist/drivers/defaults/index.d.ts +2 -0
- package/dist/drivers/defaults/index.js +2 -0
- package/dist/drivers/defaults/passwords.d.ts +4 -0
- package/dist/drivers/defaults/passwords.js +106 -0
- package/dist/drivers/defaults/traits.d.ts +33 -0
- package/dist/drivers/defaults/traits.js +1125 -0
- package/dist/drivers/dynamodb.d.ts +200 -0
- package/dist/drivers/dynamodb.js +607 -0
- package/dist/drivers/helpers.d.ts +35 -0
- package/dist/drivers/helpers.js +206 -0
- package/dist/drivers/index.d.ts +16 -0
- package/dist/drivers/index.js +9 -0
- package/dist/drivers/mysql.d.ts +7 -0
- package/dist/drivers/mysql.js +322 -0
- package/dist/drivers/postgres.d.ts +7 -0
- package/dist/drivers/postgres.js +411 -0
- package/dist/drivers/sqlite.d.ts +20 -0
- package/dist/drivers/sqlite.js +397 -0
- package/dist/factory.d.ts +41 -0
- package/dist/factory.js +51 -0
- package/dist/fk-audit.d.ts +101 -0
- package/dist/fk-audit.js +181 -0
- package/dist/index.d.ts +149 -0
- package/dist/index.js +55 -0
- package/dist/migration-lock.d.ts +23 -0
- package/dist/migration-lock.js +143 -0
- package/dist/migrations.d.ts +76 -0
- package/dist/migrations.js +549 -0
- package/dist/notification-tables.d.ts +20 -0
- package/dist/notification-tables.js +54 -0
- package/dist/query-logger.d.ts +26 -0
- package/dist/query-logger.js +213 -0
- package/dist/query-parser.d.ts +4 -0
- package/dist/query-parser.js +93 -0
- package/dist/rbac-tables.d.ts +17 -0
- package/dist/rbac-tables.js +84 -0
- package/dist/safe-migrations.d.ts +72 -0
- package/dist/safe-migrations.js +59 -0
- package/dist/schema.d.ts +4 -0
- package/dist/schema.js +10 -0
- package/dist/seed-scaffold.d.ts +34 -0
- package/dist/seed-scaffold.js +144 -0
- package/dist/seeder.d.ts +116 -0
- package/dist/seeder.js +363 -0
- package/dist/sql-helpers.d.ts +33 -0
- package/dist/sql-helpers.js +24 -0
- package/dist/table.d.ts +7 -0
- package/dist/table.js +26 -0
- package/dist/tools/setup.d.ts +1 -0
- package/dist/tools/setup.js +6 -0
- package/dist/transaction-context.d.ts +52 -0
- package/dist/transaction-context.js +62 -0
- package/dist/types.d.ts +151 -0
- package/dist/types.js +23 -0
- package/dist/unique-audit.d.ts +60 -0
- package/dist/unique-audit.js +174 -0
- package/dist/utils.d.ts +189 -0
- package/dist/utils.js +163 -0
- package/dist/uuid-columns.d.ts +22 -0
- package/dist/uuid-columns.js +68 -0
- package/dist/validators.d.ts +26 -0
- package/dist/validators.js +122 -0
- package/package.json +11 -11
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import { err, ok } from "@stacksjs/error-handling";
|
|
2
|
+
import { existsSync, readdirSync, writeFileSync, mkdirSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import Database from "bun:sqlite";
|
|
6
|
+
import { env as envVars } from "@stacksjs/env";
|
|
7
|
+
function getDriver() {
|
|
8
|
+
return envVars.DB_CONNECTION || "sqlite";
|
|
9
|
+
}
|
|
10
|
+
function getMigrationsPath() {
|
|
11
|
+
return join(process.cwd(), "database", "migrations");
|
|
12
|
+
}
|
|
13
|
+
function hasJobsMigrationBeenCreated() {
|
|
14
|
+
try {
|
|
15
|
+
const migrationsPath = getMigrationsPath();
|
|
16
|
+
if (!existsSync(migrationsPath))
|
|
17
|
+
return !1;
|
|
18
|
+
return readdirSync(migrationsPath).some((file) => file.includes("create-jobs-table"));
|
|
19
|
+
} catch {
|
|
20
|
+
return !1;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function jobBatchesTableExists() {
|
|
24
|
+
const sqlitePath = getDatabasePath();
|
|
25
|
+
if (existsSync(sqlitePath))
|
|
26
|
+
try {
|
|
27
|
+
const sqlite = new Database(sqlitePath), result = sqlite.query("SELECT name FROM sqlite_master WHERE type='table' AND name='job_batches'").get();
|
|
28
|
+
sqlite.close();
|
|
29
|
+
return result !== null;
|
|
30
|
+
} catch {}
|
|
31
|
+
if (getDriver() !== "sqlite")
|
|
32
|
+
try {
|
|
33
|
+
const { db } = await import("../utils");
|
|
34
|
+
await db.selectFrom("job_batches").select("id").limit(1).execute();
|
|
35
|
+
return !0;
|
|
36
|
+
} catch {
|
|
37
|
+
return !1;
|
|
38
|
+
}
|
|
39
|
+
return !1;
|
|
40
|
+
}
|
|
41
|
+
function getDatabasePath() {
|
|
42
|
+
const appRoot = envVars.APP_ROOT || process.cwd();
|
|
43
|
+
return join(appRoot, "database", "stacks.sqlite");
|
|
44
|
+
}
|
|
45
|
+
async function jobsTableExists() {
|
|
46
|
+
const driver = getDriver(), sqlitePath = getDatabasePath();
|
|
47
|
+
if (existsSync(sqlitePath))
|
|
48
|
+
try {
|
|
49
|
+
const sqlite = new Database(sqlitePath), result = sqlite.query("SELECT name FROM sqlite_master WHERE type='table' AND name='jobs'").get();
|
|
50
|
+
sqlite.close();
|
|
51
|
+
return result !== null;
|
|
52
|
+
} catch {}
|
|
53
|
+
if (driver !== "sqlite")
|
|
54
|
+
try {
|
|
55
|
+
const { db } = await import("../utils");
|
|
56
|
+
await db.selectFrom("jobs").select("id").limit(1).execute();
|
|
57
|
+
return !0;
|
|
58
|
+
} catch {
|
|
59
|
+
return !1;
|
|
60
|
+
}
|
|
61
|
+
return !1;
|
|
62
|
+
}
|
|
63
|
+
export async function createJobsMigration() {
|
|
64
|
+
try {
|
|
65
|
+
const driver = getDriver();
|
|
66
|
+
if (["sqlite", "mysql", "postgres"].includes(driver)) {
|
|
67
|
+
if (!hasJobsMigrationBeenCreated()) {
|
|
68
|
+
let migrationContent = "";
|
|
69
|
+
if (driver === "sqlite")
|
|
70
|
+
migrationContent = `-- Create jobs table
|
|
71
|
+
CREATE TABLE IF NOT EXISTS jobs (
|
|
72
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
73
|
+
queue TEXT NOT NULL DEFAULT 'default',
|
|
74
|
+
payload TEXT NOT NULL,
|
|
75
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
76
|
+
reserved_at INTEGER,
|
|
77
|
+
available_at INTEGER,
|
|
78
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
79
|
+
updated_at DATETIME
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
-- Create failed_jobs table
|
|
83
|
+
CREATE TABLE IF NOT EXISTS failed_jobs (
|
|
84
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
85
|
+
uuid TEXT NOT NULL,
|
|
86
|
+
connection TEXT NOT NULL,
|
|
87
|
+
queue TEXT NOT NULL,
|
|
88
|
+
payload TEXT NOT NULL,
|
|
89
|
+
exception TEXT NOT NULL,
|
|
90
|
+
failed_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
-- Create job_batches table
|
|
94
|
+
-- then_handler / catch_handler / finally_handler columns persist
|
|
95
|
+
-- the terminal handlers across worker restarts
|
|
96
|
+
-- (stacksjs/stacks#1883). Each holds JSON for one
|
|
97
|
+
-- PersistentBatchHandler. Nullable so callers that only use the
|
|
98
|
+
-- in-memory then(fn) API does not need to populate them.
|
|
99
|
+
CREATE TABLE IF NOT EXISTS job_batches (
|
|
100
|
+
id TEXT PRIMARY KEY,
|
|
101
|
+
name TEXT NOT NULL DEFAULT '',
|
|
102
|
+
total_jobs INTEGER NOT NULL DEFAULT 0,
|
|
103
|
+
pending_jobs INTEGER NOT NULL DEFAULT 0,
|
|
104
|
+
failed_jobs INTEGER NOT NULL DEFAULT 0,
|
|
105
|
+
failed_job_ids TEXT NOT NULL DEFAULT '[]',
|
|
106
|
+
options TEXT,
|
|
107
|
+
cancelled_at DATETIME,
|
|
108
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
109
|
+
finished_at DATETIME,
|
|
110
|
+
then_handler TEXT,
|
|
111
|
+
catch_handler TEXT,
|
|
112
|
+
finally_handler TEXT
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
-- Dead-letter queue (stacksjs/stacks#1885). Jobs that have already
|
|
116
|
+
-- been retried and failed again land here instead of cycling back
|
|
117
|
+
-- through the queue. \`reason\` distinguishes "repeat-failure" from
|
|
118
|
+
-- "poison-detected" / "circuit-broken" for operator triage.
|
|
119
|
+
CREATE TABLE IF NOT EXISTS dead_letter_jobs (
|
|
120
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
121
|
+
uuid TEXT NOT NULL,
|
|
122
|
+
connection TEXT NOT NULL,
|
|
123
|
+
queue TEXT NOT NULL,
|
|
124
|
+
payload TEXT NOT NULL,
|
|
125
|
+
exception TEXT NOT NULL,
|
|
126
|
+
reason TEXT NOT NULL,
|
|
127
|
+
total_failures INTEGER NOT NULL DEFAULT 1,
|
|
128
|
+
first_failed_at DATETIME,
|
|
129
|
+
last_failed_at DATETIME,
|
|
130
|
+
dead_lettered_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
-- Poison-message quarantine (stacksjs/stacks#1885). Tracks
|
|
134
|
+
-- failure counts per (jobName + payload-hash) over a rolling
|
|
135
|
+
-- window. When the count breaches the configured threshold, new
|
|
136
|
+
-- dispatches of that exact job+payload combination go directly to
|
|
137
|
+
-- the DLQ instead of the queue.
|
|
138
|
+
CREATE TABLE IF NOT EXISTS job_quarantine (
|
|
139
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
140
|
+
job_name TEXT NOT NULL,
|
|
141
|
+
payload_hash TEXT NOT NULL,
|
|
142
|
+
failure_count INTEGER NOT NULL DEFAULT 0,
|
|
143
|
+
window_start DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
144
|
+
quarantined_at DATETIME,
|
|
145
|
+
UNIQUE(job_name, payload_hash)
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
-- Per-queue circuit-breaker state (stacksjs/stacks#1885). Tracks
|
|
149
|
+
-- success/failure counts in a rolling window so the worker can
|
|
150
|
+
-- pause a queue with a sustained high failure rate. Reads + writes
|
|
151
|
+
-- are best-effort; a missing row means "not tripped".
|
|
152
|
+
CREATE TABLE IF NOT EXISTS queue_circuit_state (
|
|
153
|
+
queue_name TEXT PRIMARY KEY,
|
|
154
|
+
success_count INTEGER NOT NULL DEFAULT 0,
|
|
155
|
+
failure_count INTEGER NOT NULL DEFAULT 0,
|
|
156
|
+
window_start DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
157
|
+
paused_at DATETIME,
|
|
158
|
+
resume_at DATETIME
|
|
159
|
+
);
|
|
160
|
+
`;
|
|
161
|
+
else if (driver === "mysql")
|
|
162
|
+
migrationContent = `-- Create jobs table
|
|
163
|
+
CREATE TABLE IF NOT EXISTS jobs (
|
|
164
|
+
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
165
|
+
queue VARCHAR(255) NOT NULL DEFAULT 'default',
|
|
166
|
+
payload LONGTEXT NOT NULL,
|
|
167
|
+
attempts INT NOT NULL DEFAULT 0,
|
|
168
|
+
reserved_at INT UNSIGNED NULL,
|
|
169
|
+
available_at INT UNSIGNED NULL,
|
|
170
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
171
|
+
updated_at TIMESTAMP NULL
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
-- Create failed_jobs table
|
|
175
|
+
CREATE TABLE IF NOT EXISTS failed_jobs (
|
|
176
|
+
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
177
|
+
uuid VARCHAR(255) NOT NULL,
|
|
178
|
+
connection VARCHAR(255) NOT NULL,
|
|
179
|
+
queue VARCHAR(255) NOT NULL,
|
|
180
|
+
payload LONGTEXT NOT NULL,
|
|
181
|
+
exception LONGTEXT NOT NULL,
|
|
182
|
+
failed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
-- Create job_batches table
|
|
186
|
+
-- then_handler / catch_handler / finally_handler persist
|
|
187
|
+
-- terminal handlers across worker restarts (stacksjs/stacks#1883).
|
|
188
|
+
CREATE TABLE IF NOT EXISTS job_batches (
|
|
189
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
190
|
+
name VARCHAR(255) NOT NULL DEFAULT '',
|
|
191
|
+
total_jobs INT NOT NULL DEFAULT 0,
|
|
192
|
+
pending_jobs INT NOT NULL DEFAULT 0,
|
|
193
|
+
failed_jobs INT NOT NULL DEFAULT 0,
|
|
194
|
+
failed_job_ids LONGTEXT NOT NULL,
|
|
195
|
+
options LONGTEXT,
|
|
196
|
+
cancelled_at TIMESTAMP NULL,
|
|
197
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
198
|
+
finished_at TIMESTAMP NULL,
|
|
199
|
+
then_handler LONGTEXT,
|
|
200
|
+
catch_handler LONGTEXT,
|
|
201
|
+
finally_handler LONGTEXT
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
-- DLQ + poison-quarantine + circuit-breaker (stacksjs/stacks#1885)
|
|
205
|
+
CREATE TABLE IF NOT EXISTS dead_letter_jobs (
|
|
206
|
+
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
207
|
+
uuid VARCHAR(255) NOT NULL,
|
|
208
|
+
connection VARCHAR(255) NOT NULL,
|
|
209
|
+
queue VARCHAR(255) NOT NULL,
|
|
210
|
+
payload LONGTEXT NOT NULL,
|
|
211
|
+
exception LONGTEXT NOT NULL,
|
|
212
|
+
reason VARCHAR(64) NOT NULL,
|
|
213
|
+
total_failures INT NOT NULL DEFAULT 1,
|
|
214
|
+
first_failed_at TIMESTAMP NULL,
|
|
215
|
+
last_failed_at TIMESTAMP NULL,
|
|
216
|
+
dead_lettered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
CREATE TABLE IF NOT EXISTS job_quarantine (
|
|
220
|
+
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
221
|
+
job_name VARCHAR(255) NOT NULL,
|
|
222
|
+
payload_hash VARCHAR(64) NOT NULL,
|
|
223
|
+
failure_count INT NOT NULL DEFAULT 0,
|
|
224
|
+
window_start TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
225
|
+
quarantined_at TIMESTAMP NULL,
|
|
226
|
+
UNIQUE KEY job_quarantine_unique (job_name, payload_hash)
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
CREATE TABLE IF NOT EXISTS queue_circuit_state (
|
|
230
|
+
queue_name VARCHAR(255) PRIMARY KEY,
|
|
231
|
+
success_count INT NOT NULL DEFAULT 0,
|
|
232
|
+
failure_count INT NOT NULL DEFAULT 0,
|
|
233
|
+
window_start TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
234
|
+
paused_at TIMESTAMP NULL,
|
|
235
|
+
resume_at TIMESTAMP NULL
|
|
236
|
+
);
|
|
237
|
+
`;
|
|
238
|
+
else if (driver === "postgres")
|
|
239
|
+
migrationContent = `-- Create jobs table
|
|
240
|
+
CREATE TABLE IF NOT EXISTS jobs (
|
|
241
|
+
id SERIAL PRIMARY KEY,
|
|
242
|
+
queue VARCHAR(255) NOT NULL DEFAULT 'default',
|
|
243
|
+
payload TEXT NOT NULL,
|
|
244
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
245
|
+
reserved_at INTEGER,
|
|
246
|
+
available_at INTEGER,
|
|
247
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
248
|
+
updated_at TIMESTAMP
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
-- Create failed_jobs table
|
|
252
|
+
CREATE TABLE IF NOT EXISTS failed_jobs (
|
|
253
|
+
id SERIAL PRIMARY KEY,
|
|
254
|
+
uuid VARCHAR(255) NOT NULL,
|
|
255
|
+
connection VARCHAR(255) NOT NULL,
|
|
256
|
+
queue VARCHAR(255) NOT NULL,
|
|
257
|
+
payload TEXT NOT NULL,
|
|
258
|
+
exception TEXT NOT NULL,
|
|
259
|
+
failed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
-- Create job_batches table
|
|
263
|
+
-- then_handler / catch_handler / finally_handler persist
|
|
264
|
+
-- terminal handlers across worker restarts (stacksjs/stacks#1883).
|
|
265
|
+
CREATE TABLE IF NOT EXISTS job_batches (
|
|
266
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
267
|
+
name VARCHAR(255) NOT NULL DEFAULT '',
|
|
268
|
+
total_jobs INTEGER NOT NULL DEFAULT 0,
|
|
269
|
+
pending_jobs INTEGER NOT NULL DEFAULT 0,
|
|
270
|
+
failed_jobs INTEGER NOT NULL DEFAULT 0,
|
|
271
|
+
failed_job_ids TEXT NOT NULL DEFAULT '[]',
|
|
272
|
+
options TEXT,
|
|
273
|
+
cancelled_at TIMESTAMP,
|
|
274
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
275
|
+
finished_at TIMESTAMP,
|
|
276
|
+
then_handler TEXT,
|
|
277
|
+
catch_handler TEXT,
|
|
278
|
+
finally_handler TEXT
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
-- DLQ + poison-quarantine + circuit-breaker (stacksjs/stacks#1885)
|
|
282
|
+
CREATE TABLE IF NOT EXISTS dead_letter_jobs (
|
|
283
|
+
id SERIAL PRIMARY KEY,
|
|
284
|
+
uuid VARCHAR(255) NOT NULL,
|
|
285
|
+
connection VARCHAR(255) NOT NULL,
|
|
286
|
+
queue VARCHAR(255) NOT NULL,
|
|
287
|
+
payload TEXT NOT NULL,
|
|
288
|
+
exception TEXT NOT NULL,
|
|
289
|
+
reason VARCHAR(64) NOT NULL,
|
|
290
|
+
total_failures INTEGER NOT NULL DEFAULT 1,
|
|
291
|
+
first_failed_at TIMESTAMP,
|
|
292
|
+
last_failed_at TIMESTAMP,
|
|
293
|
+
dead_lettered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
CREATE TABLE IF NOT EXISTS job_quarantine (
|
|
297
|
+
id SERIAL PRIMARY KEY,
|
|
298
|
+
job_name VARCHAR(255) NOT NULL,
|
|
299
|
+
payload_hash VARCHAR(64) NOT NULL,
|
|
300
|
+
failure_count INTEGER NOT NULL DEFAULT 0,
|
|
301
|
+
window_start TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
302
|
+
quarantined_at TIMESTAMP,
|
|
303
|
+
UNIQUE (job_name, payload_hash)
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
CREATE TABLE IF NOT EXISTS queue_circuit_state (
|
|
307
|
+
queue_name VARCHAR(255) PRIMARY KEY,
|
|
308
|
+
success_count INTEGER NOT NULL DEFAULT 0,
|
|
309
|
+
failure_count INTEGER NOT NULL DEFAULT 0,
|
|
310
|
+
window_start TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
311
|
+
paused_at TIMESTAMP,
|
|
312
|
+
resume_at TIMESTAMP
|
|
313
|
+
);
|
|
314
|
+
`;
|
|
315
|
+
const migrationFileName = `${new Date().getTime().toString()}-create-jobs-table.sql`, migrationsPath = getMigrationsPath();
|
|
316
|
+
if (!existsSync(migrationsPath))
|
|
317
|
+
mkdirSync(migrationsPath, { recursive: !0 });
|
|
318
|
+
const migrationFilePath = join(migrationsPath, migrationFileName);
|
|
319
|
+
writeFileSync(migrationFilePath, migrationContent);
|
|
320
|
+
console.log("\u2713 Created jobs migration file");
|
|
321
|
+
} else
|
|
322
|
+
console.log("\u2713 Jobs migration file already exists");
|
|
323
|
+
if (!await jobsTableExists()) {
|
|
324
|
+
console.log(" Running migration...");
|
|
325
|
+
const sqlitePath = getDatabasePath();
|
|
326
|
+
if (driver === "sqlite" || existsSync(sqlitePath)) {
|
|
327
|
+
const sqlite = new Database(sqlitePath);
|
|
328
|
+
sqlite.run(`CREATE TABLE IF NOT EXISTS jobs (
|
|
329
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
330
|
+
queue TEXT NOT NULL DEFAULT 'default',
|
|
331
|
+
payload TEXT NOT NULL,
|
|
332
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
333
|
+
reserved_at INTEGER,
|
|
334
|
+
available_at INTEGER,
|
|
335
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
336
|
+
updated_at DATETIME
|
|
337
|
+
)`);
|
|
338
|
+
sqlite.run(`CREATE TABLE IF NOT EXISTS failed_jobs (
|
|
339
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
340
|
+
uuid TEXT NOT NULL,
|
|
341
|
+
connection TEXT NOT NULL,
|
|
342
|
+
queue TEXT NOT NULL,
|
|
343
|
+
payload TEXT NOT NULL,
|
|
344
|
+
exception TEXT NOT NULL,
|
|
345
|
+
failed_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
346
|
+
)`);
|
|
347
|
+
sqlite.close();
|
|
348
|
+
} else if (driver === "mysql") {
|
|
349
|
+
const { db } = await import("../utils");
|
|
350
|
+
await db.unsafe(`CREATE TABLE IF NOT EXISTS jobs (
|
|
351
|
+
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
352
|
+
queue VARCHAR(255) NOT NULL DEFAULT 'default',
|
|
353
|
+
payload LONGTEXT NOT NULL,
|
|
354
|
+
attempts INT NOT NULL DEFAULT 0,
|
|
355
|
+
reserved_at INT UNSIGNED NULL,
|
|
356
|
+
available_at INT UNSIGNED NULL,
|
|
357
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
358
|
+
updated_at TIMESTAMP NULL
|
|
359
|
+
)`).execute();
|
|
360
|
+
await db.unsafe(`CREATE TABLE IF NOT EXISTS failed_jobs (
|
|
361
|
+
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
362
|
+
uuid VARCHAR(255) NOT NULL,
|
|
363
|
+
connection VARCHAR(255) NOT NULL,
|
|
364
|
+
queue VARCHAR(255) NOT NULL,
|
|
365
|
+
payload LONGTEXT NOT NULL,
|
|
366
|
+
exception LONGTEXT NOT NULL,
|
|
367
|
+
failed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
368
|
+
)`).execute();
|
|
369
|
+
} else if (driver === "postgres") {
|
|
370
|
+
const { db } = await import("../utils");
|
|
371
|
+
await db.unsafe(`CREATE TABLE IF NOT EXISTS jobs (
|
|
372
|
+
id SERIAL PRIMARY KEY,
|
|
373
|
+
queue VARCHAR(255) NOT NULL DEFAULT 'default',
|
|
374
|
+
payload TEXT NOT NULL,
|
|
375
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
376
|
+
reserved_at INTEGER,
|
|
377
|
+
available_at INTEGER,
|
|
378
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
379
|
+
updated_at TIMESTAMP
|
|
380
|
+
)`).execute();
|
|
381
|
+
await db.unsafe(`CREATE TABLE IF NOT EXISTS failed_jobs (
|
|
382
|
+
id SERIAL PRIMARY KEY,
|
|
383
|
+
uuid VARCHAR(255) NOT NULL,
|
|
384
|
+
connection VARCHAR(255) NOT NULL,
|
|
385
|
+
queue VARCHAR(255) NOT NULL,
|
|
386
|
+
payload TEXT NOT NULL,
|
|
387
|
+
exception TEXT NOT NULL,
|
|
388
|
+
failed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
389
|
+
)`).execute();
|
|
390
|
+
}
|
|
391
|
+
console.log("\u2713 Jobs and failed_jobs tables created");
|
|
392
|
+
} else
|
|
393
|
+
console.log("\u2713 Jobs tables already exist");
|
|
394
|
+
if (!await jobBatchesTableExists()) {
|
|
395
|
+
console.log(" Creating job_batches table...");
|
|
396
|
+
const sqlitePath = getDatabasePath();
|
|
397
|
+
if (driver === "sqlite" || existsSync(sqlitePath)) {
|
|
398
|
+
const sqlite = new Database(sqlitePath);
|
|
399
|
+
sqlite.run(`CREATE TABLE IF NOT EXISTS job_batches (
|
|
400
|
+
id TEXT PRIMARY KEY,
|
|
401
|
+
name TEXT NOT NULL DEFAULT '',
|
|
402
|
+
total_jobs INTEGER NOT NULL DEFAULT 0,
|
|
403
|
+
pending_jobs INTEGER NOT NULL DEFAULT 0,
|
|
404
|
+
failed_jobs INTEGER NOT NULL DEFAULT 0,
|
|
405
|
+
failed_job_ids TEXT NOT NULL DEFAULT '[]',
|
|
406
|
+
options TEXT,
|
|
407
|
+
cancelled_at DATETIME,
|
|
408
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
409
|
+
finished_at DATETIME
|
|
410
|
+
)`);
|
|
411
|
+
sqlite.close();
|
|
412
|
+
} else if (driver === "mysql") {
|
|
413
|
+
const { db } = await import("../utils");
|
|
414
|
+
await db.unsafe(`CREATE TABLE IF NOT EXISTS job_batches (
|
|
415
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
416
|
+
name VARCHAR(255) NOT NULL DEFAULT '',
|
|
417
|
+
total_jobs INT NOT NULL DEFAULT 0,
|
|
418
|
+
pending_jobs INT NOT NULL DEFAULT 0,
|
|
419
|
+
failed_jobs INT NOT NULL DEFAULT 0,
|
|
420
|
+
failed_job_ids LONGTEXT NOT NULL,
|
|
421
|
+
options LONGTEXT,
|
|
422
|
+
cancelled_at TIMESTAMP NULL,
|
|
423
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
424
|
+
finished_at TIMESTAMP NULL
|
|
425
|
+
)`).execute();
|
|
426
|
+
} else if (driver === "postgres") {
|
|
427
|
+
const { db } = await import("../utils");
|
|
428
|
+
await db.unsafe(`CREATE TABLE IF NOT EXISTS job_batches (
|
|
429
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
430
|
+
name VARCHAR(255) NOT NULL DEFAULT '',
|
|
431
|
+
total_jobs INTEGER NOT NULL DEFAULT 0,
|
|
432
|
+
pending_jobs INTEGER NOT NULL DEFAULT 0,
|
|
433
|
+
failed_jobs INTEGER NOT NULL DEFAULT 0,
|
|
434
|
+
failed_job_ids TEXT NOT NULL DEFAULT '[]',
|
|
435
|
+
options TEXT,
|
|
436
|
+
cancelled_at TIMESTAMP,
|
|
437
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
438
|
+
finished_at TIMESTAMP
|
|
439
|
+
)`).execute();
|
|
440
|
+
}
|
|
441
|
+
console.log("\u2713 job_batches table created");
|
|
442
|
+
} else
|
|
443
|
+
console.log("\u2713 job_batches table already exists");
|
|
444
|
+
}
|
|
445
|
+
return ok("Migration created and executed.");
|
|
446
|
+
} catch (error) {
|
|
447
|
+
return err(error instanceof Error ? error : Error(String(error)));
|
|
448
|
+
}
|
|
449
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { createQueryBuilder } from '@stacksjs/query-builder';
|
|
2
|
+
import type { QueryBuilderConfig, StacksDialect } from '@stacksjs/query-builder';
|
|
3
|
+
/**
|
|
4
|
+
* Create a database connection with the given options
|
|
5
|
+
*/
|
|
6
|
+
export declare function createDatabase(options: DatabaseOptions): Database;
|
|
7
|
+
/**
|
|
8
|
+
* Create a SQLite database connection
|
|
9
|
+
*/
|
|
10
|
+
export declare function createSqliteDatabase(database: string, options?: Partial<Omit<DatabaseOptions, 'driver' | 'connection'>>): Database;
|
|
11
|
+
/**
|
|
12
|
+
* Create a PostgreSQL database connection
|
|
13
|
+
*/
|
|
14
|
+
export declare function createPostgresDatabase(connection: DatabaseConnectionConfig, options?: Partial<Omit<DatabaseOptions, 'driver' | 'connection'>>): Database;
|
|
15
|
+
/**
|
|
16
|
+
* Create a MySQL database connection
|
|
17
|
+
*/
|
|
18
|
+
export declare function createMysqlDatabase(connection: DatabaseConnectionConfig, options?: Partial<Omit<DatabaseOptions, 'driver' | 'connection'>>): Database;
|
|
19
|
+
export declare interface DatabaseConnectionConfig {
|
|
20
|
+
database: string
|
|
21
|
+
host?: string
|
|
22
|
+
port?: number
|
|
23
|
+
username?: string
|
|
24
|
+
password?: string
|
|
25
|
+
url?: string
|
|
26
|
+
}
|
|
27
|
+
export declare interface DatabaseOptions {
|
|
28
|
+
driver: StacksDialect
|
|
29
|
+
connection: DatabaseConnectionConfig
|
|
30
|
+
verbose?: boolean
|
|
31
|
+
timestamps?: {
|
|
32
|
+
createdAt?: string
|
|
33
|
+
updatedAt?: string
|
|
34
|
+
defaultOrderColumn?: string
|
|
35
|
+
}
|
|
36
|
+
softDeletes?: {
|
|
37
|
+
enabled?: boolean
|
|
38
|
+
column?: string
|
|
39
|
+
defaultFilter?: boolean
|
|
40
|
+
}
|
|
41
|
+
hooks?: QueryBuilderConfig['hooks']
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Database class for managing database connections
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* // Initialize with SQLite
|
|
49
|
+
* const db = new Database({
|
|
50
|
+
* driver: 'sqlite',
|
|
51
|
+
* connection: { database: 'database/app.sqlite' }
|
|
52
|
+
* })
|
|
53
|
+
*
|
|
54
|
+
* // Initialize with PostgreSQL
|
|
55
|
+
* const db = new Database({
|
|
56
|
+
* driver: 'postgres',
|
|
57
|
+
* connection: {
|
|
58
|
+
* database: 'myapp',
|
|
59
|
+
* host: 'localhost',
|
|
60
|
+
* port: 5432,
|
|
61
|
+
* username: 'postgres',
|
|
62
|
+
* password: 'secret'
|
|
63
|
+
* }
|
|
64
|
+
* })
|
|
65
|
+
*
|
|
66
|
+
* // Use the query builder
|
|
67
|
+
* const users = await db.query.selectFrom('users').where('active', '=', true).get()
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare class Database {
|
|
71
|
+
constructor(options: DatabaseOptions);
|
|
72
|
+
get driver(): StacksDialect;
|
|
73
|
+
get connection(): DatabaseConnectionConfig;
|
|
74
|
+
get isInitialized(): boolean;
|
|
75
|
+
get query(): ReturnType<typeof createQueryBuilder>;
|
|
76
|
+
initialize(): void;
|
|
77
|
+
switchDriver(driver: StacksDialect, connection: DatabaseConnectionConfig): void;
|
|
78
|
+
close(): Promise<void>;
|
|
79
|
+
static fromConfig(config: {
|
|
80
|
+
default: StacksDialect
|
|
81
|
+
connections: {
|
|
82
|
+
sqlite?: { database: string }
|
|
83
|
+
mysql?: { name: string, host?: string, port?: number, username?: string, password?: string }
|
|
84
|
+
singlestore?: { name: string, host?: string, port?: number, username?: string, password?: string }
|
|
85
|
+
postgres?: { name: string, host?: string, port?: number, username?: string, password?: string }
|
|
86
|
+
}
|
|
87
|
+
}, env?: string): Database;
|
|
88
|
+
static fromEnv(): Database;
|
|
89
|
+
}
|