prisma-sharding 0.0.5 → 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/README.md +102 -1
- package/dist/cli/migrate.js +181 -75
- package/dist/cli/studio.js +600 -59
- package/dist/cli/test.js +27 -21
- package/dist/cli/update.js +196 -80
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +19 -1
- package/dist/index.mjs +19 -1
- package/package.json +2 -1
package/dist/cli/test.js
CHANGED
|
@@ -25,6 +25,31 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
|
|
26
26
|
// src/cli/test.ts
|
|
27
27
|
var import_config = require("dotenv/config");
|
|
28
|
+
|
|
29
|
+
// src/cli/utils/shards.ts
|
|
30
|
+
var NO_SHARDS_CONFIGURED_MESSAGE = "No shards configured. Set SHARD_COUNT and SHARD_N_URL environment variables.";
|
|
31
|
+
var getShardConfigResult = (env = process.env) => {
|
|
32
|
+
const shards = [];
|
|
33
|
+
const missingShardIds = [];
|
|
34
|
+
const shardCount = parseInt(env.SHARD_COUNT || "0", 10);
|
|
35
|
+
for (let i = 1; i <= shardCount; i++) {
|
|
36
|
+
const url = env[`SHARD_${i}_URL`];
|
|
37
|
+
if (url) {
|
|
38
|
+
shards.push({ id: `shard_${i}`, index: i - 1, url });
|
|
39
|
+
} else {
|
|
40
|
+
missingShardIds.push(`shard_${i}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (shards.length === 0 && env.DATABASE_URL) {
|
|
44
|
+
shards.push({ id: "shard_1", index: 0, url: env.DATABASE_URL });
|
|
45
|
+
}
|
|
46
|
+
return { shards, missingShardIds };
|
|
47
|
+
};
|
|
48
|
+
var getShardConfigs = (env = process.env) => {
|
|
49
|
+
return getShardConfigResult(env).shards;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// src/cli/test.ts
|
|
28
53
|
var results = [];
|
|
29
54
|
var testUsers = [];
|
|
30
55
|
var TEST_USER_COUNT = 24;
|
|
@@ -39,20 +64,6 @@ ${"=".repeat(60)}
|
|
|
39
64
|
${"=".repeat(60)}`),
|
|
40
65
|
detail: (msg) => console.log(` ${msg}`)
|
|
41
66
|
};
|
|
42
|
-
var getShardConfigs = () => {
|
|
43
|
-
const shards = [];
|
|
44
|
-
const shardCount = parseInt(process.env.SHARD_COUNT || "0", 10);
|
|
45
|
-
for (let i = 1; i <= shardCount; i++) {
|
|
46
|
-
const url = process.env[`SHARD_${i}_URL`];
|
|
47
|
-
if (url) {
|
|
48
|
-
shards.push({ id: `shard_${i}`, url });
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
if (shards.length === 0 && process.env.DATABASE_URL) {
|
|
52
|
-
shards.push({ id: "shard_1", url: process.env.DATABASE_URL });
|
|
53
|
-
}
|
|
54
|
-
return shards;
|
|
55
|
-
};
|
|
56
67
|
var runTest = async (name, testFn) => {
|
|
57
68
|
const start = Date.now();
|
|
58
69
|
try {
|
|
@@ -139,11 +150,7 @@ var executeSqlWithPsql = (url, sql) => {
|
|
|
139
150
|
shell: true,
|
|
140
151
|
stdio: ["pipe", "pipe", "pipe"]
|
|
141
152
|
});
|
|
142
|
-
let stdout = "";
|
|
143
153
|
let stderr = "";
|
|
144
|
-
psql.stdout?.on("data", (data) => {
|
|
145
|
-
stdout += data.toString();
|
|
146
|
-
});
|
|
147
154
|
psql.stderr?.on("data", (data) => {
|
|
148
155
|
stderr += data.toString();
|
|
149
156
|
});
|
|
@@ -188,9 +195,8 @@ var runTests = async () => {
|
|
|
188
195
|
console.log(` \u2022 Test Users: ${TEST_USER_COUNT}`);
|
|
189
196
|
console.log(` \u2022 Test Table: ${testTableName}`);
|
|
190
197
|
if (shards.length === 0) {
|
|
191
|
-
console.error(
|
|
192
|
-
|
|
193
|
-
);
|
|
198
|
+
console.error(`
|
|
199
|
+
\u274C ${NO_SHARDS_CONFIGURED_MESSAGE}`);
|
|
194
200
|
process.exit(1);
|
|
195
201
|
}
|
|
196
202
|
const pgAvailable = await getPgClient();
|
package/dist/cli/update.js
CHANGED
|
@@ -25,109 +25,225 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
|
|
26
26
|
// src/cli/update.ts
|
|
27
27
|
var import_config = require("dotenv/config");
|
|
28
|
+
|
|
29
|
+
// src/utils/env.ts
|
|
30
|
+
var parseBooleanEnv = (name, defaultValue, env = process.env) => {
|
|
31
|
+
const value = env[name]?.trim();
|
|
32
|
+
if (value === void 0 || value === "") {
|
|
33
|
+
return defaultValue;
|
|
34
|
+
}
|
|
35
|
+
return ["1", "true", "yes", "on"].includes(value.toLowerCase());
|
|
36
|
+
};
|
|
37
|
+
var isVerboseEnv = (names, env = process.env) => names.some((name) => parseBooleanEnv(name, false, env));
|
|
38
|
+
|
|
39
|
+
// src/cli/utils/command.ts
|
|
28
40
|
var import_child_process = require("child_process");
|
|
29
41
|
var import_path = __toESM(require("path"));
|
|
30
|
-
var
|
|
42
|
+
var getNpxCommand = () => process.platform === "win32" ? "npx.cmd" : "npx";
|
|
43
|
+
var runCommand = (command, args, options = {}) => {
|
|
44
|
+
return new Promise((resolve) => {
|
|
45
|
+
let stdout = "";
|
|
46
|
+
let stderr = "";
|
|
47
|
+
let settled = false;
|
|
48
|
+
const child = (0, import_child_process.spawn)(command, args, {
|
|
49
|
+
env: options.env || process.env,
|
|
50
|
+
cwd: import_path.default.resolve(options.cwd || process.cwd()),
|
|
51
|
+
shell: false,
|
|
52
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
53
|
+
});
|
|
54
|
+
const settle = (result) => {
|
|
55
|
+
if (!settled) {
|
|
56
|
+
settled = true;
|
|
57
|
+
resolve(result);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
child.stdout?.on("data", (data) => {
|
|
61
|
+
const output = data.toString();
|
|
62
|
+
stdout += output;
|
|
63
|
+
if (options.verbose) {
|
|
64
|
+
process.stdout.write(output);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
child.stderr?.on("data", (data) => {
|
|
68
|
+
const output = data.toString();
|
|
69
|
+
stderr += output;
|
|
70
|
+
if (options.verbose) {
|
|
71
|
+
process.stderr.write(output);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
child.once("error", (error) => {
|
|
75
|
+
settle({
|
|
76
|
+
success: false,
|
|
77
|
+
stdout,
|
|
78
|
+
stderr,
|
|
79
|
+
error: error.message
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
child.once("close", (exitCode) => {
|
|
83
|
+
settle({
|
|
84
|
+
success: exitCode === 0,
|
|
85
|
+
stdout,
|
|
86
|
+
stderr,
|
|
87
|
+
exitCode,
|
|
88
|
+
error: exitCode === 0 ? void 0 : stderr.trim() || stdout.trim() || `Command exited with code ${exitCode}`
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
var runPrismaCommand = (args, options = {}) => runCommand(getNpxCommand(), ["prisma", ...args], options);
|
|
94
|
+
|
|
95
|
+
// src/cli/utils/output.ts
|
|
96
|
+
var import_readline = __toESM(require("readline"));
|
|
97
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
98
|
+
var printCliHeader = (icon, title) => {
|
|
99
|
+
console.log(`${icon} ${title}
|
|
100
|
+
`);
|
|
101
|
+
};
|
|
102
|
+
var printCliRow = (icon, label, message) => {
|
|
103
|
+
console.log(`${icon} ${label} ${message}`);
|
|
104
|
+
};
|
|
105
|
+
var printVerboseHint = () => {
|
|
106
|
+
console.log("\nRun with SHARD_CLI_VERBOSE=true for details.");
|
|
107
|
+
};
|
|
108
|
+
var createCliLoader = (label, message, enabled = true) => {
|
|
109
|
+
const animated = enabled && Boolean(process.stdout.isTTY);
|
|
110
|
+
let frameIndex = 0;
|
|
111
|
+
let timer;
|
|
112
|
+
let finished = false;
|
|
113
|
+
const clear = () => {
|
|
114
|
+
if (animated) {
|
|
115
|
+
import_readline.default.clearLine(process.stdout, 0);
|
|
116
|
+
import_readline.default.cursorTo(process.stdout, 0);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const render = () => {
|
|
120
|
+
clear();
|
|
121
|
+
process.stdout.write(`${SPINNER_FRAMES[frameIndex]} ${label} ${message}`);
|
|
122
|
+
frameIndex = (frameIndex + 1) % SPINNER_FRAMES.length;
|
|
123
|
+
};
|
|
124
|
+
if (animated) {
|
|
125
|
+
render();
|
|
126
|
+
timer = setInterval(render, 80);
|
|
127
|
+
}
|
|
128
|
+
const finish = (icon, finalMessage) => {
|
|
129
|
+
if (finished) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
finished = true;
|
|
133
|
+
if (timer) {
|
|
134
|
+
clearInterval(timer);
|
|
135
|
+
}
|
|
136
|
+
clear();
|
|
137
|
+
printCliRow(icon, label, finalMessage);
|
|
138
|
+
};
|
|
139
|
+
return {
|
|
140
|
+
succeed: (finalMessage) => finish("\u2705", finalMessage),
|
|
141
|
+
fail: (finalMessage) => finish("\u274C", finalMessage)
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// src/cli/utils/shards.ts
|
|
146
|
+
var NO_SHARDS_CONFIGURED_MESSAGE = "No shards configured. Set SHARD_COUNT and SHARD_N_URL environment variables.";
|
|
147
|
+
var getShardConfigResult = (env = process.env) => {
|
|
31
148
|
const shards = [];
|
|
32
|
-
const
|
|
149
|
+
const missingShardIds = [];
|
|
150
|
+
const shardCount = parseInt(env.SHARD_COUNT || "0", 10);
|
|
33
151
|
for (let i = 1; i <= shardCount; i++) {
|
|
34
|
-
const url =
|
|
152
|
+
const url = env[`SHARD_${i}_URL`];
|
|
35
153
|
if (url) {
|
|
36
|
-
shards.push({ id: `shard_${i}`, url });
|
|
154
|
+
shards.push({ id: `shard_${i}`, index: i - 1, url });
|
|
155
|
+
} else {
|
|
156
|
+
missingShardIds.push(`shard_${i}`);
|
|
37
157
|
}
|
|
38
158
|
}
|
|
39
|
-
if (shards.length === 0 &&
|
|
40
|
-
shards.push({ id: "shard_1", url:
|
|
159
|
+
if (shards.length === 0 && env.DATABASE_URL) {
|
|
160
|
+
shards.push({ id: "shard_1", index: 0, url: env.DATABASE_URL });
|
|
41
161
|
}
|
|
42
|
-
return shards;
|
|
162
|
+
return { shards, missingShardIds };
|
|
43
163
|
};
|
|
44
|
-
var
|
|
45
|
-
return
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
164
|
+
var getShardConfigs = (env = process.env) => {
|
|
165
|
+
return getShardConfigResult(env).shards;
|
|
166
|
+
};
|
|
167
|
+
var maskShardUrl = (url) => {
|
|
168
|
+
try {
|
|
169
|
+
const parsed = new URL(url);
|
|
170
|
+
if (parsed.password) {
|
|
171
|
+
parsed.password = "***";
|
|
172
|
+
}
|
|
173
|
+
return parsed.toString();
|
|
174
|
+
} catch {
|
|
175
|
+
return url.replace(/:[^:@]+@/, ":***@");
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// src/cli/utils/prisma.ts
|
|
180
|
+
var syncShardSchemas = async (shards, extraArgs, verbose) => {
|
|
181
|
+
const results = [];
|
|
182
|
+
for (const shard of shards) {
|
|
183
|
+
const loader = createCliLoader(shard.id, "Syncing", !verbose);
|
|
184
|
+
if (verbose) {
|
|
185
|
+
console.log(`
|
|
186
|
+
Syncing ${shard.id}...`);
|
|
187
|
+
console.log(`Database: ${maskShardUrl(shard.url)}
|
|
188
|
+
`);
|
|
189
|
+
}
|
|
190
|
+
const result = await runPrismaCommand(
|
|
191
|
+
["db", "push", "--accept-data-loss", ...extraArgs],
|
|
192
|
+
{
|
|
193
|
+
env: { ...process.env, DATABASE_URL: shard.url },
|
|
194
|
+
verbose
|
|
66
195
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
196
|
+
);
|
|
197
|
+
if (verbose && result.error && !result.stderr.trim() && !result.stdout.trim()) {
|
|
198
|
+
console.error(result.error);
|
|
199
|
+
}
|
|
200
|
+
results.push({ shardId: shard.id, success: result.success });
|
|
201
|
+
if (result.success) {
|
|
202
|
+
loader.succeed("Synced");
|
|
203
|
+
} else {
|
|
204
|
+
loader.fail("Failed");
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return results;
|
|
72
208
|
};
|
|
209
|
+
|
|
210
|
+
// src/cli/update.ts
|
|
73
211
|
var updateAll = async () => {
|
|
74
|
-
|
|
75
|
-
console.log("\u{1F504} PRISMA SHARDING UPDATE");
|
|
76
|
-
console.log("=".repeat(60) + "\n");
|
|
77
|
-
console.log("\u{1F6E0}\uFE0F Step 1: Generating Prisma Client Types...");
|
|
78
|
-
const genResult = await runCommand("npx", ["prisma", "generate"]);
|
|
79
|
-
if (!genResult.success) {
|
|
80
|
-
console.error("\n\u274C Failed to generate client. Aborting migration.");
|
|
81
|
-
process.exit(1);
|
|
82
|
-
}
|
|
83
|
-
console.log("\u2705 Client types generated successfully.\n");
|
|
212
|
+
const verbose = isVerboseEnv(["SHARD_UPDATE_VERBOSE", "SHARD_CLI_VERBOSE"]);
|
|
84
213
|
const shards = getShardConfigs();
|
|
85
214
|
const extraArgs = process.argv.slice(2);
|
|
86
|
-
|
|
87
|
-
console.log(`\u{1F4CA} Total shards to migrate: ${shards.length}`);
|
|
88
|
-
if (extraArgs.length > 0) {
|
|
89
|
-
console.log(`\u{1F527} Using flags: ${extraArgs.join(" ")}`);
|
|
90
|
-
}
|
|
91
|
-
console.log("");
|
|
215
|
+
printCliHeader("\u{1F504}", "Prisma Sharding Update");
|
|
92
216
|
if (shards.length === 0) {
|
|
93
|
-
|
|
94
|
-
"\u274C No shards configured. Set SHARD_COUNT and SHARD_N_URL environment variables."
|
|
95
|
-
);
|
|
217
|
+
printCliRow("\u274C", "config", NO_SHARDS_CONFIGURED_MESSAGE);
|
|
96
218
|
process.exit(1);
|
|
97
219
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
results.push({ shardId: shard.id, success: true, output });
|
|
220
|
+
if (verbose) {
|
|
221
|
+
console.log("Generating Prisma Client...\n");
|
|
222
|
+
}
|
|
223
|
+
const generateLoader = createCliLoader("client", "Generating", !verbose);
|
|
224
|
+
const generateResult = await runPrismaCommand(["generate"], { verbose });
|
|
225
|
+
if (verbose && generateResult.error && !generateResult.stderr.trim() && !generateResult.stdout.trim()) {
|
|
226
|
+
console.error(generateResult.error);
|
|
227
|
+
}
|
|
228
|
+
if (!generateResult.success) {
|
|
229
|
+
generateLoader.fail("Generation failed");
|
|
230
|
+
if (!verbose) {
|
|
231
|
+
printVerboseHint();
|
|
111
232
|
}
|
|
233
|
+
process.exit(1);
|
|
112
234
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
const failed = results.filter((r) => !r.success).length;
|
|
118
|
-
results.forEach((result) => {
|
|
119
|
-
const status = result.success ? "\u2705" : "\u274C";
|
|
120
|
-
console.log(` ${status} ${result.shardId}`);
|
|
121
|
-
});
|
|
122
|
-
console.log(`
|
|
123
|
-
Total: ${results.length} | Success: ${successful} | Failed: ${failed}`);
|
|
235
|
+
generateLoader.succeed("Generated");
|
|
236
|
+
const results = await syncShardSchemas(shards, extraArgs, verbose);
|
|
237
|
+
const successful = results.filter((result) => result.success).length;
|
|
238
|
+
const failed = results.length - successful;
|
|
124
239
|
if (failed > 0) {
|
|
125
|
-
|
|
240
|
+
if (!verbose) {
|
|
241
|
+
printVerboseHint();
|
|
242
|
+
}
|
|
126
243
|
process.exit(1);
|
|
127
244
|
}
|
|
128
|
-
console.log("\n\u2728 All updates completed successfully!");
|
|
129
245
|
};
|
|
130
246
|
updateAll().catch((error) => {
|
|
131
|
-
console.error(
|
|
247
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
132
248
|
process.exit(1);
|
|
133
249
|
});
|
package/dist/index.d.mts
CHANGED
|
@@ -68,6 +68,10 @@ declare class PrismaSharding<TClient> {
|
|
|
68
68
|
getShardById(shardId: string): TClient;
|
|
69
69
|
getShardWithInfo(key: string): ShardResult<TClient>;
|
|
70
70
|
getRandomShard(): TClient;
|
|
71
|
+
/**
|
|
72
|
+
* Returns both the random shard client and its shardId.
|
|
73
|
+
* Used when the shardId must be stored on the user record for future routing.
|
|
74
|
+
*/
|
|
71
75
|
getRandomShardWithInfo(): ShardResult<TClient>;
|
|
72
76
|
findFirst<T>(finder: (client: TClient) => Promise<T | null>): Promise<FindFirstResult<T, TClient>>;
|
|
73
77
|
runOnAll<T>(operation: (client: TClient, shardId: string) => Promise<T>): Promise<T[]>;
|
package/dist/index.d.ts
CHANGED
|
@@ -68,6 +68,10 @@ declare class PrismaSharding<TClient> {
|
|
|
68
68
|
getShardById(shardId: string): TClient;
|
|
69
69
|
getShardWithInfo(key: string): ShardResult<TClient>;
|
|
70
70
|
getRandomShard(): TClient;
|
|
71
|
+
/**
|
|
72
|
+
* Returns both the random shard client and its shardId.
|
|
73
|
+
* Used when the shardId must be stored on the user record for future routing.
|
|
74
|
+
*/
|
|
71
75
|
getRandomShardWithInfo(): ShardResult<TClient>;
|
|
72
76
|
findFirst<T>(finder: (client: TClient) => Promise<T | null>): Promise<FindFirstResult<T, TClient>>;
|
|
73
77
|
runOnAll<T>(operation: (client: TClient, shardId: string) => Promise<T>): Promise<T[]>;
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,15 @@ __export(index_exports, {
|
|
|
33
33
|
});
|
|
34
34
|
module.exports = __toCommonJS(index_exports);
|
|
35
35
|
|
|
36
|
+
// src/utils/env.ts
|
|
37
|
+
var parseBooleanEnv = (name, defaultValue, env = process.env) => {
|
|
38
|
+
const value = env[name]?.trim();
|
|
39
|
+
if (value === void 0 || value === "") {
|
|
40
|
+
return defaultValue;
|
|
41
|
+
}
|
|
42
|
+
return ["1", "true", "yes", "on"].includes(value.toLowerCase());
|
|
43
|
+
};
|
|
44
|
+
|
|
36
45
|
// src/utils/index.ts
|
|
37
46
|
function hashString(str) {
|
|
38
47
|
let hash = 0;
|
|
@@ -47,8 +56,13 @@ function validateUrl(url) {
|
|
|
47
56
|
return url.startsWith("postgresql://") || url.startsWith("postgres://");
|
|
48
57
|
}
|
|
49
58
|
function createDefaultLogger() {
|
|
59
|
+
const verbose = parseBooleanEnv("PRISMA_SHARDING_VERBOSE", false);
|
|
50
60
|
return {
|
|
51
|
-
info: (msg) =>
|
|
61
|
+
info: (msg) => {
|
|
62
|
+
if (verbose) {
|
|
63
|
+
console.log(`[PrismaSharding] ${msg}`);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
52
66
|
warn: (msg) => console.warn(`[PrismaSharding] ${msg}`),
|
|
53
67
|
error: (msg) => console.error(`[PrismaSharding] ${msg}`)
|
|
54
68
|
};
|
|
@@ -416,6 +430,10 @@ var PrismaSharding = class {
|
|
|
416
430
|
const shardId = this.router.getRandomShardId();
|
|
417
431
|
return this.manager.getClient(shardId);
|
|
418
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Returns both the random shard client and its shardId.
|
|
435
|
+
* Used when the shardId must be stored on the user record for future routing.
|
|
436
|
+
*/
|
|
419
437
|
getRandomShardWithInfo() {
|
|
420
438
|
this.ensureConnected();
|
|
421
439
|
const shardId = this.router.getRandomShardId();
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
// src/utils/env.ts
|
|
2
|
+
var parseBooleanEnv = (name, defaultValue, env = process.env) => {
|
|
3
|
+
const value = env[name]?.trim();
|
|
4
|
+
if (value === void 0 || value === "") {
|
|
5
|
+
return defaultValue;
|
|
6
|
+
}
|
|
7
|
+
return ["1", "true", "yes", "on"].includes(value.toLowerCase());
|
|
8
|
+
};
|
|
9
|
+
|
|
1
10
|
// src/utils/index.ts
|
|
2
11
|
function hashString(str) {
|
|
3
12
|
let hash = 0;
|
|
@@ -12,8 +21,13 @@ function validateUrl(url) {
|
|
|
12
21
|
return url.startsWith("postgresql://") || url.startsWith("postgres://");
|
|
13
22
|
}
|
|
14
23
|
function createDefaultLogger() {
|
|
24
|
+
const verbose = parseBooleanEnv("PRISMA_SHARDING_VERBOSE", false);
|
|
15
25
|
return {
|
|
16
|
-
info: (msg) =>
|
|
26
|
+
info: (msg) => {
|
|
27
|
+
if (verbose) {
|
|
28
|
+
console.log(`[PrismaSharding] ${msg}`);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
17
31
|
warn: (msg) => console.warn(`[PrismaSharding] ${msg}`),
|
|
18
32
|
error: (msg) => console.error(`[PrismaSharding] ${msg}`)
|
|
19
33
|
};
|
|
@@ -381,6 +395,10 @@ var PrismaSharding = class {
|
|
|
381
395
|
const shardId = this.router.getRandomShardId();
|
|
382
396
|
return this.manager.getClient(shardId);
|
|
383
397
|
}
|
|
398
|
+
/**
|
|
399
|
+
* Returns both the random shard client and its shardId.
|
|
400
|
+
* Used when the shardId must be stored on the user record for future routing.
|
|
401
|
+
*/
|
|
384
402
|
getRandomShardWithInfo() {
|
|
385
403
|
this.ensureConnected();
|
|
386
404
|
const shardId = this.router.getRandomShardId();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prisma-sharding",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Lightweight database sharding library for Prisma with connection pooling and health monitoring",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"build:cli": "tsup src/cli/migrate.ts src/cli/studio.ts src/cli/test.ts src/cli/update.ts --format cjs --outDir dist/cli",
|
|
41
41
|
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
42
42
|
"lint": "eslint src --ext .ts",
|
|
43
|
+
"test": "yarn build && node --test test/*.test.js",
|
|
43
44
|
"typecheck": "tsc --noEmit",
|
|
44
45
|
"prepublishOnly": "yarn build",
|
|
45
46
|
"patch": "yarn version --patch && yarn publish",
|