@shogo-ai/db 1.4.1
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 +21 -0
- package/README.md +24 -0
- package/dist/index.cjs +314 -0
- package/dist/index.d.cts +172 -0
- package/dist/index.d.ts +172 -0
- package/dist/index.js +272 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shogo Technologies, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
<!-- Copyright (C) 2026 Shogo Technologies, Inc. -->
|
|
3
|
+
|
|
4
|
+
# @shogo-ai/db
|
|
5
|
+
|
|
6
|
+
Prisma adapter helpers — auto-detects PostgreSQL/SQLite/libSQL from
|
|
7
|
+
`DATABASE_URL` and wires up the right driver. The actual Prisma client
|
|
8
|
+
generation stays your project's concern; this package just gives you a
|
|
9
|
+
one-line `createPrismaClient(PrismaClient)` factory.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun add @shogo-ai/db @prisma/client
|
|
15
|
+
# Plus the adapter you actually use:
|
|
16
|
+
bun add @prisma/adapter-pg # for postgres://...
|
|
17
|
+
bun add @prisma/adapter-libsql # for file://... or libsql://...
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Adapters are optional peers — install only the ones you need.
|
|
21
|
+
|
|
22
|
+
## License
|
|
23
|
+
|
|
24
|
+
MIT — see [LICENSE](./LICENSE).
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
createAdapterSync: () => createAdapterSync,
|
|
34
|
+
createDatabaseAdapter: () => createDatabaseAdapter,
|
|
35
|
+
createPrismaClient: () => createPrismaClient,
|
|
36
|
+
createPrismaClientSync: () => createPrismaClientSync,
|
|
37
|
+
detectProvider: () => detectProvider,
|
|
38
|
+
detectSchemaProvider: () => detectSchemaProvider,
|
|
39
|
+
getCurrentProvider: () => getCurrentProvider,
|
|
40
|
+
getTestDatabaseUrl: () => getTestDatabaseUrl,
|
|
41
|
+
isPostgres: () => isPostgres,
|
|
42
|
+
isTestMode: () => isTestMode,
|
|
43
|
+
restoreSchema: () => restoreSchema,
|
|
44
|
+
transformSchema: () => transformSchema,
|
|
45
|
+
transformSchemaFile: () => transformSchemaFile
|
|
46
|
+
});
|
|
47
|
+
module.exports = __toCommonJS(index_exports);
|
|
48
|
+
|
|
49
|
+
// src/adapters.ts
|
|
50
|
+
function detectProvider(url) {
|
|
51
|
+
const envProvider = process.env.DATABASE_PROVIDER?.toLowerCase();
|
|
52
|
+
if (envProvider === "sqlite") return "sqlite";
|
|
53
|
+
if (envProvider === "postgresql" || envProvider === "postgres") return "postgresql";
|
|
54
|
+
const connectionUrl = url ?? process.env.DATABASE_URL ?? "";
|
|
55
|
+
if (connectionUrl.startsWith("file:") || connectionUrl.endsWith(".db")) {
|
|
56
|
+
return "sqlite";
|
|
57
|
+
}
|
|
58
|
+
if (connectionUrl.startsWith("postgres://") || connectionUrl.startsWith("postgresql://")) {
|
|
59
|
+
return "postgresql";
|
|
60
|
+
}
|
|
61
|
+
return "postgresql";
|
|
62
|
+
}
|
|
63
|
+
async function createDatabaseAdapter(config = "auto") {
|
|
64
|
+
const options = typeof config === "string" ? { provider: config } : config;
|
|
65
|
+
const url = options.url ?? process.env.DATABASE_URL ?? "";
|
|
66
|
+
const provider = options.provider === "auto" || !options.provider ? detectProvider(url) : options.provider;
|
|
67
|
+
console.log(`[shogo/db] Creating ${provider} adapter`);
|
|
68
|
+
if (provider === "sqlite") {
|
|
69
|
+
return createSqliteAdapter(url || "file:./dev.db");
|
|
70
|
+
} else {
|
|
71
|
+
return createPostgresAdapter(url);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function createPostgresAdapter(connectionString) {
|
|
75
|
+
try {
|
|
76
|
+
const module2 = await import("@prisma/adapter-pg");
|
|
77
|
+
const PrismaPg = module2.PrismaPg || module2.default?.PrismaPg;
|
|
78
|
+
return new PrismaPg({ connectionString });
|
|
79
|
+
} catch (error) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
"Failed to create PostgreSQL adapter. Make sure @prisma/adapter-pg is installed.\nRun: bun add @prisma/adapter-pg"
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function createSqliteAdapter(url) {
|
|
86
|
+
try {
|
|
87
|
+
const module2 = await import("@prisma/adapter-libsql");
|
|
88
|
+
const PrismaLibSql = module2.PrismaLibSql || module2.default?.PrismaLibSql;
|
|
89
|
+
return new PrismaLibSql({ url });
|
|
90
|
+
} catch (error) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
"Failed to create SQLite adapter. Make sure @prisma/adapter-libsql is installed.\nRun: bun add @prisma/adapter-libsql"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
var globalForPrisma = globalThis;
|
|
97
|
+
async function createPrismaClient(PrismaClientClass, config = {}) {
|
|
98
|
+
if (globalForPrisma.__shogo_prisma) {
|
|
99
|
+
return globalForPrisma.__shogo_prisma;
|
|
100
|
+
}
|
|
101
|
+
const adapter = await createDatabaseAdapter(config);
|
|
102
|
+
const log = config.log ?? (process.env.NODE_ENV === "development" ? ["warn", "error"] : ["error"]);
|
|
103
|
+
const client = new PrismaClientClass({
|
|
104
|
+
adapter,
|
|
105
|
+
log
|
|
106
|
+
});
|
|
107
|
+
if (process.env.NODE_ENV !== "production") {
|
|
108
|
+
globalForPrisma.__shogo_prisma = client;
|
|
109
|
+
}
|
|
110
|
+
return client;
|
|
111
|
+
}
|
|
112
|
+
function createAdapterSync(config = {}) {
|
|
113
|
+
const url = config.url ?? process.env.DATABASE_URL ?? "";
|
|
114
|
+
const provider = config.provider === "auto" || !config.provider ? detectProvider(url) : config.provider;
|
|
115
|
+
console.log(`[shogo/db] Creating ${provider} adapter (sync)`);
|
|
116
|
+
if (provider === "sqlite") {
|
|
117
|
+
try {
|
|
118
|
+
const module2 = require("@prisma/adapter-libsql");
|
|
119
|
+
const PrismaLibSql = module2.PrismaLibSql || module2.default?.PrismaLibSql;
|
|
120
|
+
return new PrismaLibSql({ url: url || "file:./dev.db" });
|
|
121
|
+
} catch {
|
|
122
|
+
throw new Error(
|
|
123
|
+
"SQLite adapter not found. Install it with: bun add @prisma/adapter-libsql"
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
try {
|
|
128
|
+
const module2 = require("@prisma/adapter-pg");
|
|
129
|
+
const PrismaPg = module2.PrismaPg || module2.default?.PrismaPg;
|
|
130
|
+
return new PrismaPg({ connectionString: url });
|
|
131
|
+
} catch {
|
|
132
|
+
throw new Error(
|
|
133
|
+
"PostgreSQL adapter not found. Install it with: bun add @prisma/adapter-pg"
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function createPrismaClientSync(PrismaClientClass, config = {}) {
|
|
139
|
+
if (globalForPrisma.__shogo_prisma) {
|
|
140
|
+
return globalForPrisma.__shogo_prisma;
|
|
141
|
+
}
|
|
142
|
+
const adapter = createAdapterSync(config);
|
|
143
|
+
const log = config.log ?? (process.env.NODE_ENV === "development" ? ["warn", "error"] : ["error"]);
|
|
144
|
+
const client = new PrismaClientClass({
|
|
145
|
+
adapter,
|
|
146
|
+
log
|
|
147
|
+
});
|
|
148
|
+
if (process.env.NODE_ENV !== "production") {
|
|
149
|
+
globalForPrisma.__shogo_prisma = client;
|
|
150
|
+
}
|
|
151
|
+
return client;
|
|
152
|
+
}
|
|
153
|
+
function isTestMode() {
|
|
154
|
+
return detectProvider() === "sqlite";
|
|
155
|
+
}
|
|
156
|
+
function isPostgres() {
|
|
157
|
+
return detectProvider() === "postgresql";
|
|
158
|
+
}
|
|
159
|
+
function getTestDatabaseUrl() {
|
|
160
|
+
return "file:./test.db";
|
|
161
|
+
}
|
|
162
|
+
function getCurrentProvider() {
|
|
163
|
+
return detectProvider();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/schema-transformer.ts
|
|
167
|
+
var import_fs = require("fs");
|
|
168
|
+
var import_child_process = require("child_process");
|
|
169
|
+
var import_path = require("path");
|
|
170
|
+
var POSTGRES_TO_SQLITE_TRANSFORMS = [
|
|
171
|
+
// uuid() is PostgreSQL-specific, use cuid() for compatibility
|
|
172
|
+
{ pattern: /@default\(uuid\(\)\)/g, replacement: "@default(cuid())" },
|
|
173
|
+
// dbgenerated() with PostgreSQL-specific functions
|
|
174
|
+
{ pattern: /@default\(dbgenerated\("gen_random_uuid\(\)"\)\)/g, replacement: "@default(cuid())" },
|
|
175
|
+
// auto() is PostgreSQL-specific for autoincrement
|
|
176
|
+
{ pattern: /@default\(auto\(\)\)/g, replacement: "@default(autoincrement())" },
|
|
177
|
+
// Remove @db.* native type annotations (SQLite doesn't support these)
|
|
178
|
+
{ pattern: /@db\.\w+(\([^)]*\))?/g, replacement: "" }
|
|
179
|
+
];
|
|
180
|
+
var SQLITE_TO_POSTGRES_TRANSFORMS = [
|
|
181
|
+
// autoincrement() is SQLite-specific, use auto() for PostgreSQL
|
|
182
|
+
{ pattern: /@default\(autoincrement\(\)\)/g, replacement: "@default(auto())" }
|
|
183
|
+
];
|
|
184
|
+
function detectSchemaProvider(schemaContent) {
|
|
185
|
+
if (schemaContent.includes('provider = "postgresql"') || schemaContent.includes("provider = 'postgresql'")) {
|
|
186
|
+
return "postgresql";
|
|
187
|
+
}
|
|
188
|
+
if (schemaContent.includes('provider = "sqlite"') || schemaContent.includes("provider = 'sqlite'")) {
|
|
189
|
+
return "sqlite";
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
function transformSchema(schemaContent, targetProvider) {
|
|
194
|
+
const currentProvider = detectSchemaProvider(schemaContent);
|
|
195
|
+
const warnings = [];
|
|
196
|
+
if (currentProvider === targetProvider) {
|
|
197
|
+
return { content: schemaContent, warnings: [] };
|
|
198
|
+
}
|
|
199
|
+
let result = schemaContent;
|
|
200
|
+
if (targetProvider === "sqlite") {
|
|
201
|
+
result = result.replace(/provider\s*=\s*"postgresql"/g, 'provider = "sqlite"');
|
|
202
|
+
} else {
|
|
203
|
+
result = result.replace(/provider\s*=\s*"sqlite"/g, 'provider = "postgresql"');
|
|
204
|
+
}
|
|
205
|
+
const transforms = targetProvider === "sqlite" ? POSTGRES_TO_SQLITE_TRANSFORMS : SQLITE_TO_POSTGRES_TRANSFORMS;
|
|
206
|
+
for (const { pattern, replacement } of transforms) {
|
|
207
|
+
const matches = result.match(pattern);
|
|
208
|
+
if (matches && matches.length > 0) {
|
|
209
|
+
if (pattern.source.includes("db\\.")) {
|
|
210
|
+
warnings.push(`Removed PostgreSQL-specific @db.* annotations for SQLite`);
|
|
211
|
+
}
|
|
212
|
+
result = result.replace(pattern, replacement);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
result = result.replace(/ +/g, " ");
|
|
216
|
+
return { content: result, warnings };
|
|
217
|
+
}
|
|
218
|
+
async function transformSchemaFile(options) {
|
|
219
|
+
const {
|
|
220
|
+
schemaPath,
|
|
221
|
+
targetProvider,
|
|
222
|
+
generate = true,
|
|
223
|
+
push = false,
|
|
224
|
+
databaseUrl,
|
|
225
|
+
verbose = false
|
|
226
|
+
} = options;
|
|
227
|
+
const absolutePath = (0, import_path.resolve)(process.cwd(), schemaPath);
|
|
228
|
+
if (!(0, import_fs.existsSync)(absolutePath)) {
|
|
229
|
+
throw new Error(`Schema file not found: ${absolutePath}`);
|
|
230
|
+
}
|
|
231
|
+
const originalContent = (0, import_fs.readFileSync)(absolutePath, "utf-8");
|
|
232
|
+
const originalProvider = detectSchemaProvider(originalContent);
|
|
233
|
+
if (!originalProvider) {
|
|
234
|
+
throw new Error("Could not detect database provider in schema");
|
|
235
|
+
}
|
|
236
|
+
const { content: newContent, warnings } = transformSchema(originalContent, targetProvider);
|
|
237
|
+
const modified = newContent !== originalContent;
|
|
238
|
+
if (modified) {
|
|
239
|
+
(0, import_fs.writeFileSync)(absolutePath, newContent, "utf-8");
|
|
240
|
+
if (verbose) {
|
|
241
|
+
console.log(`Transformed schema from ${originalProvider} to ${targetProvider}`);
|
|
242
|
+
}
|
|
243
|
+
} else if (verbose) {
|
|
244
|
+
console.log(`Schema already using ${targetProvider} provider`);
|
|
245
|
+
}
|
|
246
|
+
const env = { ...process.env };
|
|
247
|
+
if (targetProvider === "sqlite") {
|
|
248
|
+
env.DATABASE_URL = databaseUrl || "file:./test.db";
|
|
249
|
+
} else if (databaseUrl) {
|
|
250
|
+
env.DATABASE_URL = databaseUrl;
|
|
251
|
+
}
|
|
252
|
+
const schemaDir = (0, import_path.dirname)(absolutePath);
|
|
253
|
+
if (generate) {
|
|
254
|
+
if (verbose) {
|
|
255
|
+
console.log("Running prisma generate...");
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
(0, import_child_process.execSync)("bun x prisma generate", {
|
|
259
|
+
cwd: schemaDir,
|
|
260
|
+
env,
|
|
261
|
+
stdio: verbose ? "inherit" : "pipe"
|
|
262
|
+
});
|
|
263
|
+
} catch (error) {
|
|
264
|
+
throw new Error(`prisma generate failed: ${error}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (push) {
|
|
268
|
+
if (verbose) {
|
|
269
|
+
console.log("Running prisma db push...");
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
(0, import_child_process.execSync)("bun x prisma db push", {
|
|
273
|
+
cwd: schemaDir,
|
|
274
|
+
env,
|
|
275
|
+
stdio: verbose ? "inherit" : "pipe"
|
|
276
|
+
});
|
|
277
|
+
} catch (error) {
|
|
278
|
+
throw new Error(`prisma db push failed: ${error}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
modified,
|
|
283
|
+
originalProvider,
|
|
284
|
+
newProvider: targetProvider,
|
|
285
|
+
schemaPath: absolutePath,
|
|
286
|
+
warnings
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
async function restoreSchema(schemaPath, verbose = false) {
|
|
290
|
+
await transformSchemaFile({
|
|
291
|
+
schemaPath,
|
|
292
|
+
targetProvider: "postgresql",
|
|
293
|
+
generate: true,
|
|
294
|
+
push: false,
|
|
295
|
+
verbose
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
299
|
+
0 && (module.exports = {
|
|
300
|
+
createAdapterSync,
|
|
301
|
+
createDatabaseAdapter,
|
|
302
|
+
createPrismaClient,
|
|
303
|
+
createPrismaClientSync,
|
|
304
|
+
detectProvider,
|
|
305
|
+
detectSchemaProvider,
|
|
306
|
+
getCurrentProvider,
|
|
307
|
+
getTestDatabaseUrl,
|
|
308
|
+
isPostgres,
|
|
309
|
+
isTestMode,
|
|
310
|
+
restoreSchema,
|
|
311
|
+
transformSchema,
|
|
312
|
+
transformSchemaFile
|
|
313
|
+
});
|
|
314
|
+
//# sourceMappingURL=index.cjs.map
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shogo Database Adapters
|
|
3
|
+
*
|
|
4
|
+
* Provides flexible database adapter support for Prisma.
|
|
5
|
+
* Allows easy switching between PostgreSQL (production) and SQLite (testing/development).
|
|
6
|
+
*
|
|
7
|
+
* The adapter auto-detects the database type from DATABASE_URL or DATABASE_PROVIDER,
|
|
8
|
+
* making it easy to run the same code against different databases.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // In your src/lib/db.ts
|
|
13
|
+
* import { createPrismaClient } from '@shogo-ai/sdk/db'
|
|
14
|
+
* import { PrismaClient } from '../generated/prisma/client'
|
|
15
|
+
*
|
|
16
|
+
* // Auto-detects PostgreSQL vs SQLite based on DATABASE_URL
|
|
17
|
+
* export const prisma = await createPrismaClient(PrismaClient)
|
|
18
|
+
*
|
|
19
|
+
* // For testing with SQLite:
|
|
20
|
+
* // DATABASE_URL=file:./test.db bun test
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
type DatabaseProvider$1 = 'postgresql' | 'sqlite' | 'auto';
|
|
24
|
+
interface DatabaseAdapterConfig {
|
|
25
|
+
/**
|
|
26
|
+
* Database provider to use
|
|
27
|
+
* - 'postgresql': Use PostgreSQL adapter (requires @prisma/adapter-pg)
|
|
28
|
+
* - 'sqlite': Use SQLite adapter (requires @prisma/adapter-libsql)
|
|
29
|
+
* - 'auto': Auto-detect based on DATABASE_PROVIDER env var or DATABASE_URL format
|
|
30
|
+
*/
|
|
31
|
+
provider?: DatabaseProvider$1;
|
|
32
|
+
/**
|
|
33
|
+
* Connection string (defaults to DATABASE_URL env var)
|
|
34
|
+
*/
|
|
35
|
+
url?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Prisma log levels
|
|
38
|
+
*/
|
|
39
|
+
log?: ('query' | 'info' | 'warn' | 'error')[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Detect database provider from connection string
|
|
43
|
+
*/
|
|
44
|
+
declare function detectProvider(url?: string): 'postgresql' | 'sqlite';
|
|
45
|
+
/**
|
|
46
|
+
* Create a database adapter based on configuration
|
|
47
|
+
*
|
|
48
|
+
* @param config - Configuration options or provider string
|
|
49
|
+
* @returns Promise resolving to the appropriate Prisma adapter
|
|
50
|
+
*/
|
|
51
|
+
declare function createDatabaseAdapter(config?: DatabaseAdapterConfig | DatabaseProvider$1): Promise<any>;
|
|
52
|
+
/**
|
|
53
|
+
* Create a Prisma client with auto-detected adapter (async)
|
|
54
|
+
*
|
|
55
|
+
* This is the main entry point for database access. It:
|
|
56
|
+
* 1. Auto-detects PostgreSQL vs SQLite from DATABASE_URL
|
|
57
|
+
* 2. Creates the appropriate adapter
|
|
58
|
+
* 3. Caches the client globally to prevent connection exhaustion
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import { createPrismaClient } from '@shogo-ai/sdk/db'
|
|
63
|
+
* import { PrismaClient } from '../generated/prisma/client'
|
|
64
|
+
*
|
|
65
|
+
* export const prisma = await createPrismaClient(PrismaClient)
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
declare function createPrismaClient<T>(PrismaClientClass: new (options: any) => T, config?: DatabaseAdapterConfig): Promise<T>;
|
|
69
|
+
/**
|
|
70
|
+
* Create a database adapter synchronously (uses require)
|
|
71
|
+
*
|
|
72
|
+
* This is useful when you need synchronous initialization.
|
|
73
|
+
* Falls back gracefully if the adapter package is not installed.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* import { createAdapterSync } from '@shogo-ai/sdk/db'
|
|
78
|
+
* import { PrismaClient } from '../generated/prisma/client'
|
|
79
|
+
*
|
|
80
|
+
* const adapter = createAdapterSync()
|
|
81
|
+
* export const prisma = new PrismaClient({ adapter })
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
declare function createAdapterSync(config?: DatabaseAdapterConfig): any;
|
|
85
|
+
/**
|
|
86
|
+
* Create a Prisma client synchronously with auto-detected adapter
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* import { createPrismaClientSync } from '@shogo-ai/sdk/db'
|
|
91
|
+
* import { PrismaClient } from '../generated/prisma/client'
|
|
92
|
+
*
|
|
93
|
+
* export const prisma = createPrismaClientSync(PrismaClient)
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
declare function createPrismaClientSync<T>(PrismaClientClass: new (options: any) => T, config?: DatabaseAdapterConfig): T;
|
|
97
|
+
/**
|
|
98
|
+
* Check if running in test/SQLite mode
|
|
99
|
+
*/
|
|
100
|
+
declare function isTestMode(): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Check if running with PostgreSQL
|
|
103
|
+
*/
|
|
104
|
+
declare function isPostgres(): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Get recommended DATABASE_URL for testing with SQLite
|
|
107
|
+
*/
|
|
108
|
+
declare function getTestDatabaseUrl(): string;
|
|
109
|
+
/**
|
|
110
|
+
* Get the current database provider
|
|
111
|
+
*/
|
|
112
|
+
declare function getCurrentProvider(): DatabaseProvider$1;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Prisma Schema Transformer
|
|
116
|
+
*
|
|
117
|
+
* Transforms Prisma schemas between PostgreSQL and SQLite providers,
|
|
118
|
+
* handling dialect-specific differences.
|
|
119
|
+
*
|
|
120
|
+
* This enables a workflow where:
|
|
121
|
+
* - Production uses PostgreSQL
|
|
122
|
+
* - Tests can run with SQLite (fast, no infrastructure)
|
|
123
|
+
* - Tests can also run with PostgreSQL (for integration testing)
|
|
124
|
+
*/
|
|
125
|
+
type DatabaseProvider = 'postgresql' | 'sqlite';
|
|
126
|
+
interface TransformOptions {
|
|
127
|
+
/** Path to the Prisma schema file */
|
|
128
|
+
schemaPath: string;
|
|
129
|
+
/** Target database provider */
|
|
130
|
+
targetProvider: DatabaseProvider;
|
|
131
|
+
/** Run prisma generate after transformation */
|
|
132
|
+
generate?: boolean;
|
|
133
|
+
/** Run prisma db push after transformation (useful for SQLite) */
|
|
134
|
+
push?: boolean;
|
|
135
|
+
/** DATABASE_URL to use (defaults to file:./test.db for SQLite) */
|
|
136
|
+
databaseUrl?: string;
|
|
137
|
+
/** Print verbose output */
|
|
138
|
+
verbose?: boolean;
|
|
139
|
+
}
|
|
140
|
+
interface TransformResult {
|
|
141
|
+
/** Whether the schema was modified */
|
|
142
|
+
modified: boolean;
|
|
143
|
+
/** The original provider */
|
|
144
|
+
originalProvider: DatabaseProvider;
|
|
145
|
+
/** The new provider */
|
|
146
|
+
newProvider: DatabaseProvider;
|
|
147
|
+
/** Path to the schema file */
|
|
148
|
+
schemaPath: string;
|
|
149
|
+
/** Any warnings generated during transformation */
|
|
150
|
+
warnings: string[];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Detect the current provider in a schema
|
|
154
|
+
*/
|
|
155
|
+
declare function detectSchemaProvider(schemaContent: string): DatabaseProvider | null;
|
|
156
|
+
/**
|
|
157
|
+
* Transform a Prisma schema from one provider to another
|
|
158
|
+
*/
|
|
159
|
+
declare function transformSchema(schemaContent: string, targetProvider: DatabaseProvider): {
|
|
160
|
+
content: string;
|
|
161
|
+
warnings: string[];
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Transform schema and optionally run Prisma commands
|
|
165
|
+
*/
|
|
166
|
+
declare function transformSchemaFile(options: TransformOptions): Promise<TransformResult>;
|
|
167
|
+
/**
|
|
168
|
+
* Restore schema to PostgreSQL (the canonical provider)
|
|
169
|
+
*/
|
|
170
|
+
declare function restoreSchema(schemaPath: string, verbose?: boolean): Promise<void>;
|
|
171
|
+
|
|
172
|
+
export { type DatabaseAdapterConfig, type DatabaseProvider$1 as DatabaseProvider, type TransformOptions, type TransformResult, createAdapterSync, createDatabaseAdapter, createPrismaClient, createPrismaClientSync, detectProvider, detectSchemaProvider, getCurrentProvider, getTestDatabaseUrl, isPostgres, isTestMode, restoreSchema, transformSchema, transformSchemaFile };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shogo Database Adapters
|
|
3
|
+
*
|
|
4
|
+
* Provides flexible database adapter support for Prisma.
|
|
5
|
+
* Allows easy switching between PostgreSQL (production) and SQLite (testing/development).
|
|
6
|
+
*
|
|
7
|
+
* The adapter auto-detects the database type from DATABASE_URL or DATABASE_PROVIDER,
|
|
8
|
+
* making it easy to run the same code against different databases.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // In your src/lib/db.ts
|
|
13
|
+
* import { createPrismaClient } from '@shogo-ai/sdk/db'
|
|
14
|
+
* import { PrismaClient } from '../generated/prisma/client'
|
|
15
|
+
*
|
|
16
|
+
* // Auto-detects PostgreSQL vs SQLite based on DATABASE_URL
|
|
17
|
+
* export const prisma = await createPrismaClient(PrismaClient)
|
|
18
|
+
*
|
|
19
|
+
* // For testing with SQLite:
|
|
20
|
+
* // DATABASE_URL=file:./test.db bun test
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
type DatabaseProvider$1 = 'postgresql' | 'sqlite' | 'auto';
|
|
24
|
+
interface DatabaseAdapterConfig {
|
|
25
|
+
/**
|
|
26
|
+
* Database provider to use
|
|
27
|
+
* - 'postgresql': Use PostgreSQL adapter (requires @prisma/adapter-pg)
|
|
28
|
+
* - 'sqlite': Use SQLite adapter (requires @prisma/adapter-libsql)
|
|
29
|
+
* - 'auto': Auto-detect based on DATABASE_PROVIDER env var or DATABASE_URL format
|
|
30
|
+
*/
|
|
31
|
+
provider?: DatabaseProvider$1;
|
|
32
|
+
/**
|
|
33
|
+
* Connection string (defaults to DATABASE_URL env var)
|
|
34
|
+
*/
|
|
35
|
+
url?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Prisma log levels
|
|
38
|
+
*/
|
|
39
|
+
log?: ('query' | 'info' | 'warn' | 'error')[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Detect database provider from connection string
|
|
43
|
+
*/
|
|
44
|
+
declare function detectProvider(url?: string): 'postgresql' | 'sqlite';
|
|
45
|
+
/**
|
|
46
|
+
* Create a database adapter based on configuration
|
|
47
|
+
*
|
|
48
|
+
* @param config - Configuration options or provider string
|
|
49
|
+
* @returns Promise resolving to the appropriate Prisma adapter
|
|
50
|
+
*/
|
|
51
|
+
declare function createDatabaseAdapter(config?: DatabaseAdapterConfig | DatabaseProvider$1): Promise<any>;
|
|
52
|
+
/**
|
|
53
|
+
* Create a Prisma client with auto-detected adapter (async)
|
|
54
|
+
*
|
|
55
|
+
* This is the main entry point for database access. It:
|
|
56
|
+
* 1. Auto-detects PostgreSQL vs SQLite from DATABASE_URL
|
|
57
|
+
* 2. Creates the appropriate adapter
|
|
58
|
+
* 3. Caches the client globally to prevent connection exhaustion
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import { createPrismaClient } from '@shogo-ai/sdk/db'
|
|
63
|
+
* import { PrismaClient } from '../generated/prisma/client'
|
|
64
|
+
*
|
|
65
|
+
* export const prisma = await createPrismaClient(PrismaClient)
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
declare function createPrismaClient<T>(PrismaClientClass: new (options: any) => T, config?: DatabaseAdapterConfig): Promise<T>;
|
|
69
|
+
/**
|
|
70
|
+
* Create a database adapter synchronously (uses require)
|
|
71
|
+
*
|
|
72
|
+
* This is useful when you need synchronous initialization.
|
|
73
|
+
* Falls back gracefully if the adapter package is not installed.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* import { createAdapterSync } from '@shogo-ai/sdk/db'
|
|
78
|
+
* import { PrismaClient } from '../generated/prisma/client'
|
|
79
|
+
*
|
|
80
|
+
* const adapter = createAdapterSync()
|
|
81
|
+
* export const prisma = new PrismaClient({ adapter })
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
declare function createAdapterSync(config?: DatabaseAdapterConfig): any;
|
|
85
|
+
/**
|
|
86
|
+
* Create a Prisma client synchronously with auto-detected adapter
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* import { createPrismaClientSync } from '@shogo-ai/sdk/db'
|
|
91
|
+
* import { PrismaClient } from '../generated/prisma/client'
|
|
92
|
+
*
|
|
93
|
+
* export const prisma = createPrismaClientSync(PrismaClient)
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
declare function createPrismaClientSync<T>(PrismaClientClass: new (options: any) => T, config?: DatabaseAdapterConfig): T;
|
|
97
|
+
/**
|
|
98
|
+
* Check if running in test/SQLite mode
|
|
99
|
+
*/
|
|
100
|
+
declare function isTestMode(): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Check if running with PostgreSQL
|
|
103
|
+
*/
|
|
104
|
+
declare function isPostgres(): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Get recommended DATABASE_URL for testing with SQLite
|
|
107
|
+
*/
|
|
108
|
+
declare function getTestDatabaseUrl(): string;
|
|
109
|
+
/**
|
|
110
|
+
* Get the current database provider
|
|
111
|
+
*/
|
|
112
|
+
declare function getCurrentProvider(): DatabaseProvider$1;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Prisma Schema Transformer
|
|
116
|
+
*
|
|
117
|
+
* Transforms Prisma schemas between PostgreSQL and SQLite providers,
|
|
118
|
+
* handling dialect-specific differences.
|
|
119
|
+
*
|
|
120
|
+
* This enables a workflow where:
|
|
121
|
+
* - Production uses PostgreSQL
|
|
122
|
+
* - Tests can run with SQLite (fast, no infrastructure)
|
|
123
|
+
* - Tests can also run with PostgreSQL (for integration testing)
|
|
124
|
+
*/
|
|
125
|
+
type DatabaseProvider = 'postgresql' | 'sqlite';
|
|
126
|
+
interface TransformOptions {
|
|
127
|
+
/** Path to the Prisma schema file */
|
|
128
|
+
schemaPath: string;
|
|
129
|
+
/** Target database provider */
|
|
130
|
+
targetProvider: DatabaseProvider;
|
|
131
|
+
/** Run prisma generate after transformation */
|
|
132
|
+
generate?: boolean;
|
|
133
|
+
/** Run prisma db push after transformation (useful for SQLite) */
|
|
134
|
+
push?: boolean;
|
|
135
|
+
/** DATABASE_URL to use (defaults to file:./test.db for SQLite) */
|
|
136
|
+
databaseUrl?: string;
|
|
137
|
+
/** Print verbose output */
|
|
138
|
+
verbose?: boolean;
|
|
139
|
+
}
|
|
140
|
+
interface TransformResult {
|
|
141
|
+
/** Whether the schema was modified */
|
|
142
|
+
modified: boolean;
|
|
143
|
+
/** The original provider */
|
|
144
|
+
originalProvider: DatabaseProvider;
|
|
145
|
+
/** The new provider */
|
|
146
|
+
newProvider: DatabaseProvider;
|
|
147
|
+
/** Path to the schema file */
|
|
148
|
+
schemaPath: string;
|
|
149
|
+
/** Any warnings generated during transformation */
|
|
150
|
+
warnings: string[];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Detect the current provider in a schema
|
|
154
|
+
*/
|
|
155
|
+
declare function detectSchemaProvider(schemaContent: string): DatabaseProvider | null;
|
|
156
|
+
/**
|
|
157
|
+
* Transform a Prisma schema from one provider to another
|
|
158
|
+
*/
|
|
159
|
+
declare function transformSchema(schemaContent: string, targetProvider: DatabaseProvider): {
|
|
160
|
+
content: string;
|
|
161
|
+
warnings: string[];
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Transform schema and optionally run Prisma commands
|
|
165
|
+
*/
|
|
166
|
+
declare function transformSchemaFile(options: TransformOptions): Promise<TransformResult>;
|
|
167
|
+
/**
|
|
168
|
+
* Restore schema to PostgreSQL (the canonical provider)
|
|
169
|
+
*/
|
|
170
|
+
declare function restoreSchema(schemaPath: string, verbose?: boolean): Promise<void>;
|
|
171
|
+
|
|
172
|
+
export { type DatabaseAdapterConfig, type DatabaseProvider$1 as DatabaseProvider, type TransformOptions, type TransformResult, createAdapterSync, createDatabaseAdapter, createPrismaClient, createPrismaClientSync, detectProvider, detectSchemaProvider, getCurrentProvider, getTestDatabaseUrl, isPostgres, isTestMode, restoreSchema, transformSchema, transformSchemaFile };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/adapters.ts
|
|
9
|
+
function detectProvider(url) {
|
|
10
|
+
const envProvider = process.env.DATABASE_PROVIDER?.toLowerCase();
|
|
11
|
+
if (envProvider === "sqlite") return "sqlite";
|
|
12
|
+
if (envProvider === "postgresql" || envProvider === "postgres") return "postgresql";
|
|
13
|
+
const connectionUrl = url ?? process.env.DATABASE_URL ?? "";
|
|
14
|
+
if (connectionUrl.startsWith("file:") || connectionUrl.endsWith(".db")) {
|
|
15
|
+
return "sqlite";
|
|
16
|
+
}
|
|
17
|
+
if (connectionUrl.startsWith("postgres://") || connectionUrl.startsWith("postgresql://")) {
|
|
18
|
+
return "postgresql";
|
|
19
|
+
}
|
|
20
|
+
return "postgresql";
|
|
21
|
+
}
|
|
22
|
+
async function createDatabaseAdapter(config = "auto") {
|
|
23
|
+
const options = typeof config === "string" ? { provider: config } : config;
|
|
24
|
+
const url = options.url ?? process.env.DATABASE_URL ?? "";
|
|
25
|
+
const provider = options.provider === "auto" || !options.provider ? detectProvider(url) : options.provider;
|
|
26
|
+
console.log(`[shogo/db] Creating ${provider} adapter`);
|
|
27
|
+
if (provider === "sqlite") {
|
|
28
|
+
return createSqliteAdapter(url || "file:./dev.db");
|
|
29
|
+
} else {
|
|
30
|
+
return createPostgresAdapter(url);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function createPostgresAdapter(connectionString) {
|
|
34
|
+
try {
|
|
35
|
+
const module = await import("@prisma/adapter-pg");
|
|
36
|
+
const PrismaPg = module.PrismaPg || module.default?.PrismaPg;
|
|
37
|
+
return new PrismaPg({ connectionString });
|
|
38
|
+
} catch (error) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
"Failed to create PostgreSQL adapter. Make sure @prisma/adapter-pg is installed.\nRun: bun add @prisma/adapter-pg"
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function createSqliteAdapter(url) {
|
|
45
|
+
try {
|
|
46
|
+
const module = await import("@prisma/adapter-libsql");
|
|
47
|
+
const PrismaLibSql = module.PrismaLibSql || module.default?.PrismaLibSql;
|
|
48
|
+
return new PrismaLibSql({ url });
|
|
49
|
+
} catch (error) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
"Failed to create SQLite adapter. Make sure @prisma/adapter-libsql is installed.\nRun: bun add @prisma/adapter-libsql"
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
var globalForPrisma = globalThis;
|
|
56
|
+
async function createPrismaClient(PrismaClientClass, config = {}) {
|
|
57
|
+
if (globalForPrisma.__shogo_prisma) {
|
|
58
|
+
return globalForPrisma.__shogo_prisma;
|
|
59
|
+
}
|
|
60
|
+
const adapter = await createDatabaseAdapter(config);
|
|
61
|
+
const log = config.log ?? (process.env.NODE_ENV === "development" ? ["warn", "error"] : ["error"]);
|
|
62
|
+
const client = new PrismaClientClass({
|
|
63
|
+
adapter,
|
|
64
|
+
log
|
|
65
|
+
});
|
|
66
|
+
if (process.env.NODE_ENV !== "production") {
|
|
67
|
+
globalForPrisma.__shogo_prisma = client;
|
|
68
|
+
}
|
|
69
|
+
return client;
|
|
70
|
+
}
|
|
71
|
+
function createAdapterSync(config = {}) {
|
|
72
|
+
const url = config.url ?? process.env.DATABASE_URL ?? "";
|
|
73
|
+
const provider = config.provider === "auto" || !config.provider ? detectProvider(url) : config.provider;
|
|
74
|
+
console.log(`[shogo/db] Creating ${provider} adapter (sync)`);
|
|
75
|
+
if (provider === "sqlite") {
|
|
76
|
+
try {
|
|
77
|
+
const module = __require("@prisma/adapter-libsql");
|
|
78
|
+
const PrismaLibSql = module.PrismaLibSql || module.default?.PrismaLibSql;
|
|
79
|
+
return new PrismaLibSql({ url: url || "file:./dev.db" });
|
|
80
|
+
} catch {
|
|
81
|
+
throw new Error(
|
|
82
|
+
"SQLite adapter not found. Install it with: bun add @prisma/adapter-libsql"
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
try {
|
|
87
|
+
const module = __require("@prisma/adapter-pg");
|
|
88
|
+
const PrismaPg = module.PrismaPg || module.default?.PrismaPg;
|
|
89
|
+
return new PrismaPg({ connectionString: url });
|
|
90
|
+
} catch {
|
|
91
|
+
throw new Error(
|
|
92
|
+
"PostgreSQL adapter not found. Install it with: bun add @prisma/adapter-pg"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function createPrismaClientSync(PrismaClientClass, config = {}) {
|
|
98
|
+
if (globalForPrisma.__shogo_prisma) {
|
|
99
|
+
return globalForPrisma.__shogo_prisma;
|
|
100
|
+
}
|
|
101
|
+
const adapter = createAdapterSync(config);
|
|
102
|
+
const log = config.log ?? (process.env.NODE_ENV === "development" ? ["warn", "error"] : ["error"]);
|
|
103
|
+
const client = new PrismaClientClass({
|
|
104
|
+
adapter,
|
|
105
|
+
log
|
|
106
|
+
});
|
|
107
|
+
if (process.env.NODE_ENV !== "production") {
|
|
108
|
+
globalForPrisma.__shogo_prisma = client;
|
|
109
|
+
}
|
|
110
|
+
return client;
|
|
111
|
+
}
|
|
112
|
+
function isTestMode() {
|
|
113
|
+
return detectProvider() === "sqlite";
|
|
114
|
+
}
|
|
115
|
+
function isPostgres() {
|
|
116
|
+
return detectProvider() === "postgresql";
|
|
117
|
+
}
|
|
118
|
+
function getTestDatabaseUrl() {
|
|
119
|
+
return "file:./test.db";
|
|
120
|
+
}
|
|
121
|
+
function getCurrentProvider() {
|
|
122
|
+
return detectProvider();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/schema-transformer.ts
|
|
126
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
127
|
+
import { execSync } from "child_process";
|
|
128
|
+
import { resolve, dirname } from "path";
|
|
129
|
+
var POSTGRES_TO_SQLITE_TRANSFORMS = [
|
|
130
|
+
// uuid() is PostgreSQL-specific, use cuid() for compatibility
|
|
131
|
+
{ pattern: /@default\(uuid\(\)\)/g, replacement: "@default(cuid())" },
|
|
132
|
+
// dbgenerated() with PostgreSQL-specific functions
|
|
133
|
+
{ pattern: /@default\(dbgenerated\("gen_random_uuid\(\)"\)\)/g, replacement: "@default(cuid())" },
|
|
134
|
+
// auto() is PostgreSQL-specific for autoincrement
|
|
135
|
+
{ pattern: /@default\(auto\(\)\)/g, replacement: "@default(autoincrement())" },
|
|
136
|
+
// Remove @db.* native type annotations (SQLite doesn't support these)
|
|
137
|
+
{ pattern: /@db\.\w+(\([^)]*\))?/g, replacement: "" }
|
|
138
|
+
];
|
|
139
|
+
var SQLITE_TO_POSTGRES_TRANSFORMS = [
|
|
140
|
+
// autoincrement() is SQLite-specific, use auto() for PostgreSQL
|
|
141
|
+
{ pattern: /@default\(autoincrement\(\)\)/g, replacement: "@default(auto())" }
|
|
142
|
+
];
|
|
143
|
+
function detectSchemaProvider(schemaContent) {
|
|
144
|
+
if (schemaContent.includes('provider = "postgresql"') || schemaContent.includes("provider = 'postgresql'")) {
|
|
145
|
+
return "postgresql";
|
|
146
|
+
}
|
|
147
|
+
if (schemaContent.includes('provider = "sqlite"') || schemaContent.includes("provider = 'sqlite'")) {
|
|
148
|
+
return "sqlite";
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
function transformSchema(schemaContent, targetProvider) {
|
|
153
|
+
const currentProvider = detectSchemaProvider(schemaContent);
|
|
154
|
+
const warnings = [];
|
|
155
|
+
if (currentProvider === targetProvider) {
|
|
156
|
+
return { content: schemaContent, warnings: [] };
|
|
157
|
+
}
|
|
158
|
+
let result = schemaContent;
|
|
159
|
+
if (targetProvider === "sqlite") {
|
|
160
|
+
result = result.replace(/provider\s*=\s*"postgresql"/g, 'provider = "sqlite"');
|
|
161
|
+
} else {
|
|
162
|
+
result = result.replace(/provider\s*=\s*"sqlite"/g, 'provider = "postgresql"');
|
|
163
|
+
}
|
|
164
|
+
const transforms = targetProvider === "sqlite" ? POSTGRES_TO_SQLITE_TRANSFORMS : SQLITE_TO_POSTGRES_TRANSFORMS;
|
|
165
|
+
for (const { pattern, replacement } of transforms) {
|
|
166
|
+
const matches = result.match(pattern);
|
|
167
|
+
if (matches && matches.length > 0) {
|
|
168
|
+
if (pattern.source.includes("db\\.")) {
|
|
169
|
+
warnings.push(`Removed PostgreSQL-specific @db.* annotations for SQLite`);
|
|
170
|
+
}
|
|
171
|
+
result = result.replace(pattern, replacement);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
result = result.replace(/ +/g, " ");
|
|
175
|
+
return { content: result, warnings };
|
|
176
|
+
}
|
|
177
|
+
async function transformSchemaFile(options) {
|
|
178
|
+
const {
|
|
179
|
+
schemaPath,
|
|
180
|
+
targetProvider,
|
|
181
|
+
generate = true,
|
|
182
|
+
push = false,
|
|
183
|
+
databaseUrl,
|
|
184
|
+
verbose = false
|
|
185
|
+
} = options;
|
|
186
|
+
const absolutePath = resolve(process.cwd(), schemaPath);
|
|
187
|
+
if (!existsSync(absolutePath)) {
|
|
188
|
+
throw new Error(`Schema file not found: ${absolutePath}`);
|
|
189
|
+
}
|
|
190
|
+
const originalContent = readFileSync(absolutePath, "utf-8");
|
|
191
|
+
const originalProvider = detectSchemaProvider(originalContent);
|
|
192
|
+
if (!originalProvider) {
|
|
193
|
+
throw new Error("Could not detect database provider in schema");
|
|
194
|
+
}
|
|
195
|
+
const { content: newContent, warnings } = transformSchema(originalContent, targetProvider);
|
|
196
|
+
const modified = newContent !== originalContent;
|
|
197
|
+
if (modified) {
|
|
198
|
+
writeFileSync(absolutePath, newContent, "utf-8");
|
|
199
|
+
if (verbose) {
|
|
200
|
+
console.log(`Transformed schema from ${originalProvider} to ${targetProvider}`);
|
|
201
|
+
}
|
|
202
|
+
} else if (verbose) {
|
|
203
|
+
console.log(`Schema already using ${targetProvider} provider`);
|
|
204
|
+
}
|
|
205
|
+
const env = { ...process.env };
|
|
206
|
+
if (targetProvider === "sqlite") {
|
|
207
|
+
env.DATABASE_URL = databaseUrl || "file:./test.db";
|
|
208
|
+
} else if (databaseUrl) {
|
|
209
|
+
env.DATABASE_URL = databaseUrl;
|
|
210
|
+
}
|
|
211
|
+
const schemaDir = dirname(absolutePath);
|
|
212
|
+
if (generate) {
|
|
213
|
+
if (verbose) {
|
|
214
|
+
console.log("Running prisma generate...");
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
execSync("bun x prisma generate", {
|
|
218
|
+
cwd: schemaDir,
|
|
219
|
+
env,
|
|
220
|
+
stdio: verbose ? "inherit" : "pipe"
|
|
221
|
+
});
|
|
222
|
+
} catch (error) {
|
|
223
|
+
throw new Error(`prisma generate failed: ${error}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (push) {
|
|
227
|
+
if (verbose) {
|
|
228
|
+
console.log("Running prisma db push...");
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
execSync("bun x prisma db push", {
|
|
232
|
+
cwd: schemaDir,
|
|
233
|
+
env,
|
|
234
|
+
stdio: verbose ? "inherit" : "pipe"
|
|
235
|
+
});
|
|
236
|
+
} catch (error) {
|
|
237
|
+
throw new Error(`prisma db push failed: ${error}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
modified,
|
|
242
|
+
originalProvider,
|
|
243
|
+
newProvider: targetProvider,
|
|
244
|
+
schemaPath: absolutePath,
|
|
245
|
+
warnings
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
async function restoreSchema(schemaPath, verbose = false) {
|
|
249
|
+
await transformSchemaFile({
|
|
250
|
+
schemaPath,
|
|
251
|
+
targetProvider: "postgresql",
|
|
252
|
+
generate: true,
|
|
253
|
+
push: false,
|
|
254
|
+
verbose
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
export {
|
|
258
|
+
createAdapterSync,
|
|
259
|
+
createDatabaseAdapter,
|
|
260
|
+
createPrismaClient,
|
|
261
|
+
createPrismaClientSync,
|
|
262
|
+
detectProvider,
|
|
263
|
+
detectSchemaProvider,
|
|
264
|
+
getCurrentProvider,
|
|
265
|
+
getTestDatabaseUrl,
|
|
266
|
+
isPostgres,
|
|
267
|
+
isTestMode,
|
|
268
|
+
restoreSchema,
|
|
269
|
+
transformSchema,
|
|
270
|
+
transformSchemaFile
|
|
271
|
+
};
|
|
272
|
+
//# sourceMappingURL=index.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shogo-ai/db",
|
|
3
|
+
"version": "1.4.1",
|
|
4
|
+
"description": "Shogo DB — Prisma adapter helpers for PostgreSQL/SQLite/libSQL with auto-detection from DATABASE_URL.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.cjs",
|
|
8
|
+
"module": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"sideEffects": false,
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"require": "./dist/index.cjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist/**/*.js",
|
|
20
|
+
"dist/**/*.cjs",
|
|
21
|
+
"dist/**/*.d.ts",
|
|
22
|
+
"dist/**/*.d.cts"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"test": "bun --no-env-file test src/"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@prisma/adapter-pg": "^7.3.0",
|
|
32
|
+
"@prisma/adapter-libsql": ">=0.0.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"@prisma/adapter-pg": {
|
|
36
|
+
"optional": true
|
|
37
|
+
},
|
|
38
|
+
"@prisma/adapter-libsql": {
|
|
39
|
+
"optional": true
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@prisma/adapter-libsql": "^7.3.0",
|
|
44
|
+
"@types/node": "^25.5.0",
|
|
45
|
+
"tsup": "^8.0.0",
|
|
46
|
+
"typescript": "^6.0.2"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"keywords": [
|
|
52
|
+
"shogo",
|
|
53
|
+
"prisma",
|
|
54
|
+
"postgres",
|
|
55
|
+
"sqlite",
|
|
56
|
+
"libsql"
|
|
57
|
+
],
|
|
58
|
+
"author": "Shogo Labs",
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git+https://github.com/shogo-labs/shogo-ai.git",
|
|
62
|
+
"directory": "packages/db"
|
|
63
|
+
},
|
|
64
|
+
"homepage": "https://github.com/shogo-labs/shogo-ai/tree/main/packages/db#readme",
|
|
65
|
+
"bugs": {
|
|
66
|
+
"url": "https://github.com/shogo-labs/shogo-ai/issues"
|
|
67
|
+
}
|
|
68
|
+
}
|