nanodb-orm 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +438 -40
- package/dist/cli.d.ts +84 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +227 -149
- package/dist/cli.js.map +1 -1
- package/dist/core/connection.d.ts +6 -0
- package/dist/core/connection.d.ts.map +1 -1
- package/dist/core/connection.js +17 -3
- package/dist/core/connection.js.map +1 -1
- package/dist/index.d.ts +206 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +222 -50
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +114 -62
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +79 -44
- package/dist/init.js.map +1 -1
- package/dist/types/index.d.ts +176 -38
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/migrations.d.ts +2 -2
- package/dist/utils/migrations.d.ts.map +1 -1
- package/dist/utils/migrations.js +167 -56
- package/dist/utils/migrations.js.map +1 -1
- package/dist/utils/schema-introspection.d.ts +4 -4
- package/dist/utils/schema-introspection.d.ts.map +1 -1
- package/dist/utils/schema-introspection.js +0 -3
- package/dist/utils/schema-introspection.js.map +1 -1
- package/dist/utils/seeds.d.ts +2 -2
- package/dist/utils/seeds.d.ts.map +1 -1
- package/dist/utils/seeds.js +10 -1
- package/dist/utils/seeds.js.map +1 -1
- package/dist/utils/sync.d.ts.map +1 -1
- package/dist/utils/sync.js +11 -2
- package/dist/utils/sync.js.map +1 -1
- package/dist/utils/transactions.d.ts +85 -2
- package/dist/utils/transactions.d.ts.map +1 -1
- package/dist/utils/transactions.js +160 -8
- package/dist/utils/transactions.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -44,96 +44,41 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
44
44
|
};
|
|
45
45
|
})();
|
|
46
46
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
exports.launchStudio = launchStudio;
|
|
48
|
+
exports.runSetup = runSetup;
|
|
49
|
+
exports.runReset = runReset;
|
|
50
|
+
exports.getStatus = getStatus;
|
|
51
|
+
exports.runValidate = runValidate;
|
|
47
52
|
const child_process_1 = require("child_process");
|
|
48
53
|
const fs_1 = require("fs");
|
|
49
54
|
const path_1 = require("path");
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
async function main() {
|
|
77
|
-
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
78
|
-
console.log(HELP);
|
|
79
|
-
process.exit(0);
|
|
80
|
-
}
|
|
81
|
-
switch (command) {
|
|
82
|
-
case 'studio':
|
|
83
|
-
await launchStudio();
|
|
84
|
-
break;
|
|
85
|
-
case 'setup':
|
|
86
|
-
await runSetup();
|
|
87
|
-
break;
|
|
88
|
-
case 'reset':
|
|
89
|
-
await runReset();
|
|
90
|
-
break;
|
|
91
|
-
case 'status':
|
|
92
|
-
await showStatus();
|
|
93
|
-
break;
|
|
94
|
-
case 'validate':
|
|
95
|
-
await runValidate();
|
|
96
|
-
break;
|
|
97
|
-
default:
|
|
98
|
-
console.error(`Unknown command: ${command}`);
|
|
99
|
-
console.log(HELP);
|
|
100
|
-
process.exit(1);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
function getArg(name, defaultValue) {
|
|
104
|
-
const index = args.indexOf(`--${name}`);
|
|
105
|
-
if (index !== -1) {
|
|
106
|
-
const val = args[index + 1];
|
|
107
|
-
if (val)
|
|
108
|
-
return val;
|
|
109
|
-
}
|
|
110
|
-
return defaultValue;
|
|
111
|
-
}
|
|
112
|
-
function getDbPath() {
|
|
113
|
-
// Check for --db argument
|
|
114
|
-
let dbPath = getArg('db', '');
|
|
115
|
-
if (!dbPath) {
|
|
116
|
-
// Try common locations
|
|
117
|
-
if ((0, fs_1.existsSync)('database.db'))
|
|
118
|
-
dbPath = 'database.db';
|
|
119
|
-
else if ((0, fs_1.existsSync)('local.db'))
|
|
120
|
-
dbPath = 'local.db';
|
|
121
|
-
else if ((0, fs_1.existsSync)('test.db'))
|
|
122
|
-
dbPath = 'test.db';
|
|
123
|
-
else if ((0, fs_1.existsSync)('data.db'))
|
|
124
|
-
dbPath = 'data.db';
|
|
125
|
-
else
|
|
126
|
-
dbPath = 'database.db'; // Default
|
|
55
|
+
// ============================================================================
|
|
56
|
+
// Exported Functions
|
|
57
|
+
// ============================================================================
|
|
58
|
+
/**
|
|
59
|
+
* Launch Drizzle Studio for visual database browsing.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* import { launchStudio } from 'nanodb-orm';
|
|
64
|
+
*
|
|
65
|
+
* // Launch with defaults
|
|
66
|
+
* await launchStudio();
|
|
67
|
+
*
|
|
68
|
+
* // Launch with options
|
|
69
|
+
* await launchStudio({ dbPath: './data/app.db', port: 3000 });
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
async function launchStudio(options = {}) {
|
|
73
|
+
const dbPath = options.dbPath ?? findDbPath();
|
|
74
|
+
const port = String(options.port ?? 4983);
|
|
75
|
+
const silent = options.silent ?? false;
|
|
76
|
+
if (!silent) {
|
|
77
|
+
console.log(`\n🚀 Launching Drizzle Studio...`);
|
|
78
|
+
console.log(` Database: ${dbPath}`);
|
|
79
|
+
console.log(` URL: https://local.drizzle.studio`);
|
|
80
|
+
console.log(` Port: ${port}\n`);
|
|
127
81
|
}
|
|
128
|
-
return (0, path_1.resolve)(dbPath);
|
|
129
|
-
}
|
|
130
|
-
async function launchStudio() {
|
|
131
|
-
const dbPath = getDbPath();
|
|
132
|
-
const port = getArg('port', '4983');
|
|
133
|
-
console.log(`\n🚀 Launching Drizzle Studio...`);
|
|
134
|
-
console.log(` Database: ${dbPath}`);
|
|
135
|
-
console.log(` URL: https://local.drizzle.studio`);
|
|
136
|
-
console.log(` Port: ${port}\n`);
|
|
137
82
|
// Create temporary drizzle config
|
|
138
83
|
const configPath = (0, path_1.resolve)('.drizzle-studio.config.ts');
|
|
139
84
|
const configContent = `
|
|
@@ -149,7 +94,7 @@ export default defineConfig({
|
|
|
149
94
|
(0, fs_1.writeFileSync)(configPath, configContent);
|
|
150
95
|
// Launch drizzle-kit studio
|
|
151
96
|
const studio = (0, child_process_1.spawn)('npx', ['drizzle-kit', 'studio', '--port', port, '--config', configPath], {
|
|
152
|
-
stdio: 'inherit',
|
|
97
|
+
stdio: silent ? 'ignore' : 'inherit',
|
|
153
98
|
shell: true,
|
|
154
99
|
});
|
|
155
100
|
// Cleanup on exit
|
|
@@ -158,79 +103,112 @@ export default defineConfig({
|
|
|
158
103
|
if ((0, fs_1.existsSync)(configPath))
|
|
159
104
|
(0, fs_1.unlinkSync)(configPath);
|
|
160
105
|
}
|
|
161
|
-
catch {
|
|
106
|
+
catch {
|
|
107
|
+
// Ignore cleanup errors
|
|
108
|
+
}
|
|
162
109
|
};
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
});
|
|
167
|
-
process.on('SIGTERM', () => {
|
|
168
|
-
cleanup();
|
|
169
|
-
process.exit(0);
|
|
170
|
-
});
|
|
171
|
-
studio.on('close', (code) => {
|
|
172
|
-
cleanup();
|
|
173
|
-
process.exit(code ?? 0);
|
|
174
|
-
});
|
|
110
|
+
studio.on('close', cleanup);
|
|
111
|
+
studio.on('error', cleanup);
|
|
112
|
+
return studio;
|
|
175
113
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Run database setup (initialize schema and seed data).
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* import { runSetup } from 'nanodb-orm';
|
|
120
|
+
* await runSetup();
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
async function runSetup(silent = false) {
|
|
124
|
+
if (!silent)
|
|
125
|
+
console.log('\n📦 Running database setup...\n');
|
|
126
|
+
const { DatabaseSync } = await Promise.resolve().then(() => __importStar(require('./index')));
|
|
127
|
+
await DatabaseSync.setup();
|
|
128
|
+
if (!silent)
|
|
181
129
|
console.log('\n✅ Setup complete!\n');
|
|
182
|
-
}
|
|
183
|
-
catch (error) {
|
|
184
|
-
console.error('\n❌ Setup failed\n');
|
|
185
|
-
process.exit(1);
|
|
186
|
-
}
|
|
187
130
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Reset database (drop all tables and recreate with seed data).
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```ts
|
|
136
|
+
* import { runReset } from 'nanodb-orm';
|
|
137
|
+
* await runReset();
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
async function runReset(silent = false) {
|
|
141
|
+
if (!silent)
|
|
142
|
+
console.log('\n⚠️ Resetting database (this will delete all data)...\n');
|
|
143
|
+
const { DatabaseSync } = await Promise.resolve().then(() => __importStar(require('./index')));
|
|
144
|
+
await DatabaseSync.reset();
|
|
145
|
+
if (!silent)
|
|
193
146
|
console.log('\n✅ Reset complete!\n');
|
|
194
|
-
}
|
|
195
|
-
catch (error) {
|
|
196
|
-
console.error('\n❌ Reset failed\n');
|
|
197
|
-
process.exit(1);
|
|
198
|
-
}
|
|
199
147
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Get database status and health information.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* import { getStatus } from 'nanodb-orm';
|
|
154
|
+
*
|
|
155
|
+
* const status = await getStatus();
|
|
156
|
+
* console.log(status.healthy, status.totalRecords);
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
async function getStatus(silent = false) {
|
|
160
|
+
if (!silent)
|
|
161
|
+
console.log('\n📊 Database Status\n');
|
|
162
|
+
const { DatabaseSync, SchemaIntrospection } = await Promise.resolve().then(() => __importStar(require('./index')));
|
|
163
|
+
const health = await DatabaseSync.healthCheck();
|
|
164
|
+
const stats = SchemaIntrospection.getSchemaStats();
|
|
165
|
+
const result = {
|
|
166
|
+
healthy: health.healthy,
|
|
167
|
+
schemaValid: health.schemaValid,
|
|
168
|
+
totalTables: stats.totalTables,
|
|
169
|
+
totalRecords: health.totalRecords,
|
|
170
|
+
tables: health.tableCounts,
|
|
171
|
+
errors: health.errors,
|
|
172
|
+
};
|
|
173
|
+
if (!silent) {
|
|
174
|
+
console.log(`Healthy: ${result.healthy ? '✅ Yes' : '❌ No'}`);
|
|
175
|
+
console.log(`Schema Valid: ${result.schemaValid ? '✅ Yes' : '❌ No'}`);
|
|
176
|
+
console.log(`Total Tables: ${result.totalTables}`);
|
|
177
|
+
console.log(`Total Records: ${result.totalRecords}`);
|
|
210
178
|
console.log('');
|
|
211
179
|
console.log('Tables:');
|
|
212
|
-
for (const table of
|
|
213
|
-
const count = health.tableCounts[table] ?? 0;
|
|
180
|
+
for (const [table, count] of Object.entries(result.tables)) {
|
|
214
181
|
console.log(` ${table}: ${count} rows`);
|
|
215
182
|
}
|
|
216
|
-
if (
|
|
183
|
+
if (result.errors.length > 0) {
|
|
217
184
|
console.log('\nErrors:');
|
|
218
|
-
for (const err of
|
|
185
|
+
for (const err of result.errors) {
|
|
219
186
|
console.log(` ❌ ${err}`);
|
|
220
187
|
}
|
|
221
188
|
}
|
|
222
189
|
console.log('');
|
|
223
190
|
}
|
|
224
|
-
|
|
225
|
-
console.error('❌ Could not get status:', error instanceof Error ? error.message : error);
|
|
226
|
-
process.exit(1);
|
|
227
|
-
}
|
|
191
|
+
return result;
|
|
228
192
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Validate schema against database.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```ts
|
|
198
|
+
* import { runValidate } from 'nanodb-orm';
|
|
199
|
+
*
|
|
200
|
+
* const result = await runValidate();
|
|
201
|
+
* if (!result.isValid) {
|
|
202
|
+
* console.log('Missing tables:', result.missingTables);
|
|
203
|
+
* }
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
async function runValidate(silent = false) {
|
|
207
|
+
if (!silent)
|
|
208
|
+
console.log('\n🔍 Validating schema...\n');
|
|
209
|
+
const { SchemaIntrospection } = await Promise.resolve().then(() => __importStar(require('./index')));
|
|
210
|
+
const validation = await SchemaIntrospection.validateSchema();
|
|
211
|
+
if (!silent) {
|
|
234
212
|
if (validation.isValid) {
|
|
235
213
|
console.log('✅ Schema is valid!\n');
|
|
236
214
|
}
|
|
@@ -255,16 +233,116 @@ async function runValidate() {
|
|
|
255
233
|
}
|
|
256
234
|
}
|
|
257
235
|
console.log('');
|
|
258
|
-
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return validation;
|
|
239
|
+
}
|
|
240
|
+
// ============================================================================
|
|
241
|
+
// Internal Helpers
|
|
242
|
+
// ============================================================================
|
|
243
|
+
function findDbPath() {
|
|
244
|
+
if ((0, fs_1.existsSync)('database.db'))
|
|
245
|
+
return (0, path_1.resolve)('database.db');
|
|
246
|
+
if ((0, fs_1.existsSync)('local.db'))
|
|
247
|
+
return (0, path_1.resolve)('local.db');
|
|
248
|
+
if ((0, fs_1.existsSync)('test.db'))
|
|
249
|
+
return (0, path_1.resolve)('test.db');
|
|
250
|
+
if ((0, fs_1.existsSync)('data.db'))
|
|
251
|
+
return (0, path_1.resolve)('data.db');
|
|
252
|
+
return (0, path_1.resolve)('database.db');
|
|
253
|
+
}
|
|
254
|
+
function getArg(args, name, defaultValue) {
|
|
255
|
+
const index = args.indexOf(`--${name}`);
|
|
256
|
+
if (index !== -1) {
|
|
257
|
+
const val = args[index + 1];
|
|
258
|
+
if (val)
|
|
259
|
+
return val;
|
|
260
|
+
}
|
|
261
|
+
return defaultValue;
|
|
262
|
+
}
|
|
263
|
+
// ============================================================================
|
|
264
|
+
// CLI Entry Point
|
|
265
|
+
// ============================================================================
|
|
266
|
+
const HELP = `
|
|
267
|
+
nanodb-orm CLI
|
|
268
|
+
|
|
269
|
+
Usage: nanodb [command] [options]
|
|
270
|
+
|
|
271
|
+
Commands:
|
|
272
|
+
studio Launch Drizzle Studio (visual database browser)
|
|
273
|
+
setup Initialize database schema and seed data
|
|
274
|
+
reset Drop all tables and recreate
|
|
275
|
+
status Show database health and stats
|
|
276
|
+
validate Validate schema against database
|
|
277
|
+
help Show this help message
|
|
278
|
+
|
|
279
|
+
Options:
|
|
280
|
+
--db <path> Database file path (default: database.db)
|
|
281
|
+
--port <num> Studio port (default: 4983)
|
|
282
|
+
|
|
283
|
+
Examples:
|
|
284
|
+
nanodb studio
|
|
285
|
+
nanodb studio --port 3000
|
|
286
|
+
nanodb setup
|
|
287
|
+
nanodb status
|
|
288
|
+
`;
|
|
289
|
+
async function main() {
|
|
290
|
+
const args = process.argv.slice(2);
|
|
291
|
+
const command = args[0];
|
|
292
|
+
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
293
|
+
console.log(HELP);
|
|
294
|
+
process.exit(0);
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
switch (command) {
|
|
298
|
+
case 'studio': {
|
|
299
|
+
const dbPath = getArg(args, 'db', '');
|
|
300
|
+
const port = parseInt(getArg(args, 'port', '4983'), 10);
|
|
301
|
+
const studio = await launchStudio({
|
|
302
|
+
dbPath: dbPath || undefined,
|
|
303
|
+
port
|
|
304
|
+
});
|
|
305
|
+
// Handle CLI-specific cleanup
|
|
306
|
+
const cleanup = () => {
|
|
307
|
+
studio.kill();
|
|
308
|
+
process.exit(0);
|
|
309
|
+
};
|
|
310
|
+
process.on('SIGINT', cleanup);
|
|
311
|
+
process.on('SIGTERM', cleanup);
|
|
312
|
+
studio.on('close', (code) => process.exit(code ?? 0));
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
case 'setup':
|
|
316
|
+
await runSetup();
|
|
317
|
+
break;
|
|
318
|
+
case 'reset':
|
|
319
|
+
await runReset();
|
|
320
|
+
break;
|
|
321
|
+
case 'status':
|
|
322
|
+
await getStatus();
|
|
323
|
+
break;
|
|
324
|
+
case 'validate': {
|
|
325
|
+
const result = await runValidate();
|
|
326
|
+
if (!result.isValid)
|
|
327
|
+
process.exit(1);
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
default:
|
|
331
|
+
console.error(`Unknown command: ${command}`);
|
|
332
|
+
console.log(HELP);
|
|
333
|
+
process.exit(1);
|
|
259
334
|
}
|
|
260
335
|
}
|
|
261
336
|
catch (error) {
|
|
262
|
-
console.error('❌
|
|
337
|
+
console.error('❌ Command failed:', error instanceof Error ? error.message : error);
|
|
263
338
|
process.exit(1);
|
|
264
339
|
}
|
|
265
340
|
}
|
|
266
|
-
main
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
341
|
+
// Only run CLI if this is the main module
|
|
342
|
+
if (require.main === module) {
|
|
343
|
+
main().catch((err) => {
|
|
344
|
+
console.error('CLI Error:', err);
|
|
345
|
+
process.exit(1);
|
|
346
|
+
});
|
|
347
|
+
}
|
|
270
348
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../cli.ts"],"names":[],"mappings":";;AACA;;;;;;;;;GASG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,12 @@ type DrizzleInstance = ReturnType<typeof drizzle>;
|
|
|
3
3
|
/**
|
|
4
4
|
* Thread-safe singleton database connection manager.
|
|
5
5
|
* Supports both Turso (remote) and local SQLite databases.
|
|
6
|
+
*
|
|
7
|
+
* Environment variables:
|
|
8
|
+
* - `TURSO_CONNECTION_URL` + `TURSO_AUTH_TOKEN`: Use Turso remote database
|
|
9
|
+
* - `FORCE_LOCAL_DB=true`: Force local SQLite mode
|
|
10
|
+
* - `DATABASE_PATH`: Custom path for local database (default: database.db)
|
|
11
|
+
* - `NODE_ENV=test`: Use isolated test database
|
|
6
12
|
*/
|
|
7
13
|
export declare class DatabaseConnection {
|
|
8
14
|
private static instance;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../core/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../core/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAI7C,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAElD;;;;;;;;;GASG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgC;IACvD,OAAO,CAAC,MAAM,CAAC,OAAO,CAAyC;IAE/D,+DAA+D;WAClD,WAAW,IAAI,OAAO,CAAC,eAAe,CAAC;IAcpD,uCAAuC;mBAClB,gBAAgB;IA4BrC,yCAAyC;IACzC,MAAM,CAAC,KAAK,IAAI,IAAI;IAKpB,mCAAmC;IACnC,MAAM,CAAC,WAAW,IAAI,OAAO;CAG9B"}
|
package/dist/core/connection.js
CHANGED
|
@@ -7,6 +7,12 @@ const config_1 = require("./config");
|
|
|
7
7
|
/**
|
|
8
8
|
* Thread-safe singleton database connection manager.
|
|
9
9
|
* Supports both Turso (remote) and local SQLite databases.
|
|
10
|
+
*
|
|
11
|
+
* Environment variables:
|
|
12
|
+
* - `TURSO_CONNECTION_URL` + `TURSO_AUTH_TOKEN`: Use Turso remote database
|
|
13
|
+
* - `FORCE_LOCAL_DB=true`: Force local SQLite mode
|
|
14
|
+
* - `DATABASE_PATH`: Custom path for local database (default: database.db)
|
|
15
|
+
* - `NODE_ENV=test`: Use isolated test database
|
|
10
16
|
*/
|
|
11
17
|
class DatabaseConnection {
|
|
12
18
|
/** Get the database connection instance (creates if needed) */
|
|
@@ -27,10 +33,17 @@ class DatabaseConnection {
|
|
|
27
33
|
/** Create a new database connection */
|
|
28
34
|
static async createConnection() {
|
|
29
35
|
// Test environment: use isolated local database
|
|
30
|
-
if (process.env.NODE_ENV === 'test'
|
|
31
|
-
const dbName = process.env.JEST_WORKER_ID
|
|
36
|
+
if (process.env.NODE_ENV === 'test') {
|
|
37
|
+
const dbName = process.env.JEST_WORKER_ID
|
|
38
|
+
? `test-${process.env.JEST_WORKER_ID}.db`
|
|
39
|
+
: (process.env.DATABASE_PATH ?? 'test.db');
|
|
32
40
|
return (0, libsql_1.drizzle)((0, client_1.createClient)({ url: `file:${dbName}` }));
|
|
33
41
|
}
|
|
42
|
+
// Force local mode: use DATABASE_PATH or default
|
|
43
|
+
if (process.env.FORCE_LOCAL_DB === 'true') {
|
|
44
|
+
const dbPath = process.env.DATABASE_PATH ?? 'database.db';
|
|
45
|
+
return (0, libsql_1.drizzle)((0, client_1.createClient)({ url: `file:${dbPath}` }));
|
|
46
|
+
}
|
|
34
47
|
// Production: try Turso first, fallback to local SQLite
|
|
35
48
|
try {
|
|
36
49
|
const config = (0, config_1.getDatabaseConfig)();
|
|
@@ -40,7 +53,8 @@ class DatabaseConnection {
|
|
|
40
53
|
}));
|
|
41
54
|
}
|
|
42
55
|
catch {
|
|
43
|
-
|
|
56
|
+
const dbPath = process.env.DATABASE_PATH ?? 'database.db';
|
|
57
|
+
return (0, libsql_1.drizzle)((0, client_1.createClient)({ url: `file:${dbPath}` }));
|
|
44
58
|
}
|
|
45
59
|
}
|
|
46
60
|
/** Reset the connection (for testing) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../core/connection.ts"],"names":[],"mappings":";;;AAAA,+CAA6C;AAC7C,2CAA8C;AAC9C,qCAA6C;
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../core/connection.ts"],"names":[],"mappings":";;;AAAA,+CAA6C;AAC7C,2CAA8C;AAC9C,qCAA6C;AAI7C;;;;;;;;;GASG;AACH,MAAa,kBAAkB;IAI7B,+DAA+D;IAC/D,MAAM,CAAC,KAAK,CAAC,WAAW;QACtB,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC;QACxC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC;QAEtC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAEvC,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC;YACnC,OAAO,IAAI,CAAC,QAAQ,CAAC;QACvB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;IACH,CAAC;IAED,uCAAuC;IAC/B,MAAM,CAAC,KAAK,CAAC,gBAAgB;QACnC,gDAAgD;QAChD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YACpC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc;gBACvC,CAAC,CAAC,QAAQ,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK;gBACzC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,SAAS,CAAC,CAAC;YAC7C,OAAO,IAAA,gBAAO,EAAC,IAAA,qBAAY,EAAC,EAAE,GAAG,EAAE,QAAQ,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1D,CAAC;QAED,iDAAiD;QACjD,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,MAAM,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,aAAa,CAAC;YAC1D,OAAO,IAAA,gBAAO,EAAC,IAAA,qBAAY,EAAC,EAAE,GAAG,EAAE,QAAQ,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1D,CAAC;QAED,wDAAwD;QACxD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAA,0BAAiB,GAAE,CAAC;YACnC,OAAO,IAAA,gBAAO,EAAC,IAAA,qBAAY,EAAC;gBAC1B,GAAG,EAAE,MAAM,CAAC,aAAa;gBACzB,SAAS,EAAE,MAAM,CAAC,SAAS;aAC5B,CAAC,CAAC,CAAC;QACN,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,aAAa,CAAC;YAC1D,OAAO,IAAA,gBAAO,EAAC,IAAA,qBAAY,EAAC,EAAE,GAAG,EAAE,QAAQ,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,yCAAyC;IACzC,MAAM,CAAC,KAAK;QACV,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,mCAAmC;IACnC,MAAM,CAAC,WAAW;QAChB,OAAO,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC;IAChC,CAAC;;AAzDH,gDA0DC;AAzDgB,2BAAQ,GAA2B,IAAI,CAAC;AACxC,0BAAO,GAAoC,IAAI,CAAC"}
|