pg-seed-kit 0.0.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 +132 -0
- package/bin/pg-seed-kit.js +2 -0
- package/dist/adapters/drizzle.cjs +53 -0
- package/dist/adapters/drizzle.d.cts +25 -0
- package/dist/adapters/drizzle.d.ts +25 -0
- package/dist/adapters/drizzle.js +28 -0
- package/dist/adapters/prisma.cjs +45 -0
- package/dist/adapters/prisma.d.cts +22 -0
- package/dist/adapters/prisma.d.ts +22 -0
- package/dist/adapters/prisma.js +20 -0
- package/dist/adapters/sequelize.cjs +41 -0
- package/dist/adapters/sequelize.d.cts +21 -0
- package/dist/adapters/sequelize.d.ts +21 -0
- package/dist/adapters/sequelize.js +16 -0
- package/dist/adapters/typeorm.cjs +40 -0
- package/dist/adapters/typeorm.d.cts +18 -0
- package/dist/adapters/typeorm.d.ts +18 -0
- package/dist/adapters/typeorm.js +15 -0
- package/dist/chunk-KMXBCJZY.js +247 -0
- package/dist/cli/index.cjs +385 -0
- package/dist/cli/index.d.cts +2 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +143 -0
- package/dist/index.cjs +286 -0
- package/dist/index.d.cts +43 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +16 -0
- package/dist/types-CCBHgrLA.d.cts +57 -0
- package/dist/types-CCBHgrLA.d.ts +57 -0
- package/package.json +127 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getSeederStatuses,
|
|
3
|
+
loadConfig,
|
|
4
|
+
resetSeeder,
|
|
5
|
+
runPendingSeeders,
|
|
6
|
+
runSeederByName
|
|
7
|
+
} from "../chunk-KMXBCJZY.js";
|
|
8
|
+
|
|
9
|
+
// src/cli/create.ts
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import path from "path";
|
|
12
|
+
var TEMPLATE = `const seed = async (): Promise<void> => {
|
|
13
|
+
// TODO: implement this seeder.
|
|
14
|
+
// Keep it idempotent so re-runs are safe: check-before-insert,
|
|
15
|
+
// or \`INSERT ... ON CONFLICT DO NOTHING\`.
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default seed;
|
|
19
|
+
`;
|
|
20
|
+
function generateTimestamp() {
|
|
21
|
+
const now = /* @__PURE__ */ new Date();
|
|
22
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
23
|
+
return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
24
|
+
}
|
|
25
|
+
async function createSeeder(name) {
|
|
26
|
+
const config = await loadConfig();
|
|
27
|
+
const timestamp = generateTimestamp();
|
|
28
|
+
const filename = `${timestamp}-${name}.seeder.ts`;
|
|
29
|
+
const filepath = path.join(config.seedersPath, filename);
|
|
30
|
+
if (!fs.existsSync(config.seedersPath)) {
|
|
31
|
+
fs.mkdirSync(config.seedersPath, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
fs.writeFileSync(filepath, TEMPLATE);
|
|
34
|
+
console.log(`Created: ${filepath}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/cli/commands.ts
|
|
38
|
+
function printUsage() {
|
|
39
|
+
console.log("Usage:");
|
|
40
|
+
console.log(" pg-seed-kit create <name> Create a new seeder file");
|
|
41
|
+
console.log(" pg-seed-kit status List seeders and statuses");
|
|
42
|
+
console.log(" pg-seed-kit run [name] Run pending seeders or one seeder");
|
|
43
|
+
console.log(" pg-seed-kit reset <name> Mark a seeder as pending");
|
|
44
|
+
console.log("");
|
|
45
|
+
console.log("Connection: your config must export an async connect() that returns an adapter.");
|
|
46
|
+
}
|
|
47
|
+
async function withAdapter(action) {
|
|
48
|
+
const config = await loadConfig();
|
|
49
|
+
if (!config.connect) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
"pg-seed-kit: this command needs a database connection. Export an async connect() from your config that returns an adapter."
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
const adapter = await config.connect();
|
|
55
|
+
try {
|
|
56
|
+
return await action({ adapter });
|
|
57
|
+
} finally {
|
|
58
|
+
await adapter.close?.();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function printStatuses(statuses) {
|
|
62
|
+
if (statuses.length === 0) {
|
|
63
|
+
console.log("No seeders found.");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
for (const status of statuses) {
|
|
67
|
+
const executedAt = status.executedAt ? ` ${status.executedAt.toISOString()}` : "";
|
|
68
|
+
const error = status.error ? ` - ${status.error}` : "";
|
|
69
|
+
console.log(`${status.status.padEnd(7)} ${status.name}${executedAt}${error}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function printRunResults(results) {
|
|
73
|
+
if (results.length === 0) {
|
|
74
|
+
console.log("No seeders found.");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
for (const result of results) {
|
|
78
|
+
const error = result.error ? ` - ${result.error}` : "";
|
|
79
|
+
console.log(`${result.status.padEnd(7)} ${result.name}${error}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function runCli(args = process.argv.slice(2)) {
|
|
83
|
+
const command = args[0];
|
|
84
|
+
if (!command || command === "--help" || command === "-h") {
|
|
85
|
+
printUsage();
|
|
86
|
+
return command ? 0 : 1;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
switch (command) {
|
|
90
|
+
case "create": {
|
|
91
|
+
const name = args[1];
|
|
92
|
+
if (!name) {
|
|
93
|
+
console.error("Error: seeder name is required.");
|
|
94
|
+
console.error("Usage: pg-seed-kit create <name>");
|
|
95
|
+
return 1;
|
|
96
|
+
}
|
|
97
|
+
await createSeeder(name);
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
case "status": {
|
|
101
|
+
await withAdapter(async (overrides) => {
|
|
102
|
+
const statuses = await getSeederStatuses(overrides);
|
|
103
|
+
printStatuses(statuses);
|
|
104
|
+
});
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
case "run": {
|
|
108
|
+
let results = [];
|
|
109
|
+
const name = args[1];
|
|
110
|
+
await withAdapter(async (overrides) => {
|
|
111
|
+
results = name ? await runSeederByName(name, overrides) : await runPendingSeeders(overrides);
|
|
112
|
+
printRunResults(results);
|
|
113
|
+
});
|
|
114
|
+
return results.some((result) => result.status === "failed") ? 1 : 0;
|
|
115
|
+
}
|
|
116
|
+
case "reset": {
|
|
117
|
+
const name = args[1];
|
|
118
|
+
if (!name) {
|
|
119
|
+
console.error("Error: seeder name is required.");
|
|
120
|
+
console.error("Usage: pg-seed-kit reset <name>");
|
|
121
|
+
return 1;
|
|
122
|
+
}
|
|
123
|
+
await withAdapter(async (overrides) => {
|
|
124
|
+
await resetSeeder(name, overrides);
|
|
125
|
+
console.log(`Reset: ${name}`);
|
|
126
|
+
});
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
default:
|
|
130
|
+
console.error(`Unknown command: "${command}"`);
|
|
131
|
+
printUsage();
|
|
132
|
+
return 1;
|
|
133
|
+
}
|
|
134
|
+
} catch (err) {
|
|
135
|
+
console.error(err?.message || String(err));
|
|
136
|
+
return 1;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/cli/index.ts
|
|
141
|
+
runCli().then((exitCode) => {
|
|
142
|
+
process.exitCode = exitCode;
|
|
143
|
+
});
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
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 src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
getSeederStatuses: () => getSeederStatuses,
|
|
34
|
+
loadConfig: () => loadConfig,
|
|
35
|
+
resetSeeder: () => resetSeeder,
|
|
36
|
+
resolveSeedersPath: () => resolveSeedersPath,
|
|
37
|
+
runPendingSeeders: () => runPendingSeeders,
|
|
38
|
+
runSeederByName: () => runSeederByName
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(src_exports);
|
|
41
|
+
|
|
42
|
+
// src/runner.ts
|
|
43
|
+
var import_fs2 = __toESM(require("fs"), 1);
|
|
44
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
45
|
+
var import_url2 = require("url");
|
|
46
|
+
|
|
47
|
+
// src/dynamic-import.ts
|
|
48
|
+
var dynamicImport = new Function("specifier", "return import(specifier);");
|
|
49
|
+
|
|
50
|
+
// src/config.ts
|
|
51
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
52
|
+
var import_path = __toESM(require("path"), 1);
|
|
53
|
+
var import_url = require("url");
|
|
54
|
+
var DEFAULT_TABLE_NAME = "seeders";
|
|
55
|
+
var DEFAULT_FILE_PATTERN = /^\d{14}-.+\.seeder\.(ts|js|mjs|cjs)$/;
|
|
56
|
+
var CONFIG_FILES = ["pg-seed-kit.config.js", "pg-seed-kit.config.cjs", "pg-seed-kit.config.mjs"];
|
|
57
|
+
async function loadConfigFromFile(cwd) {
|
|
58
|
+
for (const filename of CONFIG_FILES) {
|
|
59
|
+
const filepath = import_path.default.resolve(cwd, filename);
|
|
60
|
+
if (import_fs.default.existsSync(filepath)) {
|
|
61
|
+
const loaded = await dynamicImport((0, import_url.pathToFileURL)(filepath).href);
|
|
62
|
+
return loaded.default ?? loaded;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const pkgPath = import_path.default.resolve(cwd, "package.json");
|
|
66
|
+
if (import_fs.default.existsSync(pkgPath)) {
|
|
67
|
+
const pkg = JSON.parse(import_fs.default.readFileSync(pkgPath, "utf-8"));
|
|
68
|
+
if (pkg["pg-seed-kit"]) {
|
|
69
|
+
return pkg["pg-seed-kit"];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
function isResolver(value) {
|
|
75
|
+
return typeof value === "function";
|
|
76
|
+
}
|
|
77
|
+
async function loadConfig(overrides) {
|
|
78
|
+
const cwd = process.cwd();
|
|
79
|
+
const fileConfig = await loadConfigFromFile(cwd);
|
|
80
|
+
const merged = { ...fileConfig, ...overrides };
|
|
81
|
+
if (!merged.seedersPath) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
'pg-seed-kit: "seedersPath" is required. Provide it via pg-seed-kit.config.js, package.json, or inline config.'
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const rawPath = isResolver(merged.seedersPath) ? merged.seedersPath() : merged.seedersPath;
|
|
87
|
+
if (typeof rawPath !== "string" || rawPath.length === 0) {
|
|
88
|
+
throw new Error('pg-seed-kit: "seedersPath" must resolve to a non-empty string.');
|
|
89
|
+
}
|
|
90
|
+
const seedersPath = import_path.default.isAbsolute(rawPath) ? rawPath : import_path.default.resolve(cwd, rawPath);
|
|
91
|
+
return {
|
|
92
|
+
seedersPath,
|
|
93
|
+
tableName: merged.tableName ?? DEFAULT_TABLE_NAME,
|
|
94
|
+
filePattern: merged.filePattern ?? DEFAULT_FILE_PATTERN,
|
|
95
|
+
adapter: merged.adapter,
|
|
96
|
+
connect: merged.connect
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function resolveSeedersPath(opts) {
|
|
100
|
+
return () => {
|
|
101
|
+
if (opts.srcWhen && opts.srcWhen()) return opts.src;
|
|
102
|
+
const argvFile = process.argv[1] || "";
|
|
103
|
+
if (/[\\/]dist[\\/]/.test(argvFile)) return opts.dist;
|
|
104
|
+
const isTsRuntime = /\.(ts|tsx)$/.test(argvFile) || Boolean(
|
|
105
|
+
process._preload_modules?.some(
|
|
106
|
+
(m) => /tsx|ts-node/.test(m)
|
|
107
|
+
)
|
|
108
|
+
) || Boolean(process.env.TS_NODE_DEV) || Boolean(process.env.TSX);
|
|
109
|
+
return isTsRuntime ? opts.src : opts.dist;
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/tracker.ts
|
|
114
|
+
var ensuredTables = /* @__PURE__ */ new Set();
|
|
115
|
+
function quoteIdentifier(name) {
|
|
116
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`pg-seed-kit: invalid table name "${name}". Use only letters, digits, and underscores (must not start with a digit).`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return `"${name}"`;
|
|
122
|
+
}
|
|
123
|
+
function toRecord(row) {
|
|
124
|
+
return {
|
|
125
|
+
name: row.name,
|
|
126
|
+
executedAt: row.executed_at,
|
|
127
|
+
status: row.status,
|
|
128
|
+
error: row.error ?? void 0
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
async function ensureTable(adapter, tableName) {
|
|
132
|
+
if (ensuredTables.has(tableName)) return;
|
|
133
|
+
const table = quoteIdentifier(tableName);
|
|
134
|
+
await adapter.query(
|
|
135
|
+
`CREATE TABLE IF NOT EXISTS ${table} (
|
|
136
|
+
name TEXT PRIMARY KEY,
|
|
137
|
+
executed_at TIMESTAMPTZ NOT NULL,
|
|
138
|
+
status TEXT NOT NULL,
|
|
139
|
+
error TEXT
|
|
140
|
+
)`
|
|
141
|
+
);
|
|
142
|
+
ensuredTables.add(tableName);
|
|
143
|
+
}
|
|
144
|
+
async function getExecutedSeeders(adapter, tableName) {
|
|
145
|
+
const table = quoteIdentifier(tableName);
|
|
146
|
+
const rows = await adapter.query(
|
|
147
|
+
`SELECT name, executed_at, status, error FROM ${table} WHERE status = 'success'`
|
|
148
|
+
);
|
|
149
|
+
return rows.map(toRecord);
|
|
150
|
+
}
|
|
151
|
+
async function getAllTrackedSeeders(adapter, tableName) {
|
|
152
|
+
const table = quoteIdentifier(tableName);
|
|
153
|
+
const rows = await adapter.query(
|
|
154
|
+
`SELECT name, executed_at, status, error FROM ${table}`
|
|
155
|
+
);
|
|
156
|
+
return rows.map(toRecord);
|
|
157
|
+
}
|
|
158
|
+
async function upsertSeederRecord(adapter, tableName, record) {
|
|
159
|
+
const table = quoteIdentifier(tableName);
|
|
160
|
+
await adapter.query(
|
|
161
|
+
`INSERT INTO ${table} (name, executed_at, status, error)
|
|
162
|
+
VALUES ($1, $2, $3, $4)
|
|
163
|
+
ON CONFLICT (name) DO UPDATE
|
|
164
|
+
SET executed_at = EXCLUDED.executed_at,
|
|
165
|
+
status = EXCLUDED.status,
|
|
166
|
+
error = EXCLUDED.error`,
|
|
167
|
+
[record.name, record.executedAt, record.status, record.error ?? null]
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
async function deleteSeederRecord(adapter, tableName, name) {
|
|
171
|
+
const table = quoteIdentifier(tableName);
|
|
172
|
+
await adapter.query(`DELETE FROM ${table} WHERE name = $1`, [name]);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/runner.ts
|
|
176
|
+
function requireAdapter(config) {
|
|
177
|
+
if (!config.adapter) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
"pg-seed-kit: an adapter is required. Pass { adapter } to the runner, or expose one from your config (the CLI builds it via `connect`)."
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
return config.adapter;
|
|
183
|
+
}
|
|
184
|
+
function getSeederFiles(config) {
|
|
185
|
+
if (!import_fs2.default.existsSync(config.seedersPath)) {
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
return import_fs2.default.readdirSync(config.seedersPath).filter((f) => config.filePattern.test(f)).sort();
|
|
189
|
+
}
|
|
190
|
+
async function loadSeeder(name, filepath) {
|
|
191
|
+
const seederModule = await dynamicImport((0, import_url2.pathToFileURL)(filepath).href);
|
|
192
|
+
const seederFn = seederModule.default ?? seederModule;
|
|
193
|
+
if (typeof seederFn !== "function") {
|
|
194
|
+
throw new Error(`Seeder "${name}" does not export a function`);
|
|
195
|
+
}
|
|
196
|
+
return seederFn;
|
|
197
|
+
}
|
|
198
|
+
async function runSingleSeeder(adapter, name, filepath, tableName, results) {
|
|
199
|
+
try {
|
|
200
|
+
const seederFn = await loadSeeder(name, filepath);
|
|
201
|
+
await seederFn();
|
|
202
|
+
await upsertSeederRecord(adapter, tableName, {
|
|
203
|
+
name,
|
|
204
|
+
executedAt: /* @__PURE__ */ new Date(),
|
|
205
|
+
status: "success"
|
|
206
|
+
});
|
|
207
|
+
results.push({ name, status: "success" });
|
|
208
|
+
console.log(`[pg-seed-kit] "${name}" ran successfully`);
|
|
209
|
+
} catch (err) {
|
|
210
|
+
const errorMessage = err?.message || String(err);
|
|
211
|
+
await upsertSeederRecord(adapter, tableName, {
|
|
212
|
+
name,
|
|
213
|
+
executedAt: /* @__PURE__ */ new Date(),
|
|
214
|
+
status: "failed",
|
|
215
|
+
error: errorMessage
|
|
216
|
+
});
|
|
217
|
+
results.push({ name, status: "failed", error: errorMessage });
|
|
218
|
+
console.error(`[pg-seed-kit] "${name}" failed: ${errorMessage}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async function runPendingSeeders(overrides) {
|
|
222
|
+
const config = await loadConfig(overrides);
|
|
223
|
+
const adapter = requireAdapter(config);
|
|
224
|
+
await ensureTable(adapter, config.tableName);
|
|
225
|
+
const files = getSeederFiles(config);
|
|
226
|
+
const executed = await getExecutedSeeders(adapter, config.tableName);
|
|
227
|
+
const executedNames = new Set(executed.map((s) => s.name));
|
|
228
|
+
const results = [];
|
|
229
|
+
for (const file of files) {
|
|
230
|
+
const name = import_path2.default.basename(file, import_path2.default.extname(file));
|
|
231
|
+
if (executedNames.has(name)) {
|
|
232
|
+
results.push({ name, status: "skipped" });
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const filepath = import_path2.default.join(config.seedersPath, file);
|
|
236
|
+
await runSingleSeeder(adapter, name, filepath, config.tableName, results);
|
|
237
|
+
}
|
|
238
|
+
return results;
|
|
239
|
+
}
|
|
240
|
+
async function runSeederByName(seederName, overrides) {
|
|
241
|
+
const config = await loadConfig(overrides);
|
|
242
|
+
const adapter = requireAdapter(config);
|
|
243
|
+
await ensureTable(adapter, config.tableName);
|
|
244
|
+
const files = getSeederFiles(config);
|
|
245
|
+
const file = files.find((f) => import_path2.default.basename(f, import_path2.default.extname(f)) === seederName);
|
|
246
|
+
if (!file) {
|
|
247
|
+
throw new Error(`Seeder "${seederName}" not found`);
|
|
248
|
+
}
|
|
249
|
+
const results = [];
|
|
250
|
+
const filepath = import_path2.default.join(config.seedersPath, file);
|
|
251
|
+
await runSingleSeeder(adapter, seederName, filepath, config.tableName, results);
|
|
252
|
+
return results;
|
|
253
|
+
}
|
|
254
|
+
async function getSeederStatuses(overrides) {
|
|
255
|
+
const config = await loadConfig(overrides);
|
|
256
|
+
const adapter = requireAdapter(config);
|
|
257
|
+
await ensureTable(adapter, config.tableName);
|
|
258
|
+
const files = getSeederFiles(config);
|
|
259
|
+
const tracked = await getAllTrackedSeeders(adapter, config.tableName);
|
|
260
|
+
const trackedMap = new Map(tracked.map((s) => [s.name, s]));
|
|
261
|
+
return files.map((f) => {
|
|
262
|
+
const name = import_path2.default.basename(f, import_path2.default.extname(f));
|
|
263
|
+
const record = trackedMap.get(name);
|
|
264
|
+
return {
|
|
265
|
+
name,
|
|
266
|
+
status: record?.status ?? "pending",
|
|
267
|
+
executedAt: record?.executedAt ?? null,
|
|
268
|
+
error: record?.error ?? null
|
|
269
|
+
};
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
async function resetSeeder(seederName, overrides) {
|
|
273
|
+
const config = await loadConfig(overrides);
|
|
274
|
+
const adapter = requireAdapter(config);
|
|
275
|
+
await ensureTable(adapter, config.tableName);
|
|
276
|
+
await deleteSeederRecord(adapter, config.tableName, seederName);
|
|
277
|
+
}
|
|
278
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
279
|
+
0 && (module.exports = {
|
|
280
|
+
getSeederStatuses,
|
|
281
|
+
loadConfig,
|
|
282
|
+
resetSeeder,
|
|
283
|
+
resolveSeedersPath,
|
|
284
|
+
runPendingSeeders,
|
|
285
|
+
runSeederByName
|
|
286
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { P as PgSeederConfig, S as SeederStatus, a as SeederRunResult, R as ResolvedPgSeederConfig, b as SeedersPathResolver } from './types-CCBHgrLA.cjs';
|
|
2
|
+
export { A as Adapter } from './types-CCBHgrLA.cjs';
|
|
3
|
+
|
|
4
|
+
declare function runPendingSeeders(overrides?: Partial<PgSeederConfig>): Promise<SeederRunResult[]>;
|
|
5
|
+
declare function runSeederByName(seederName: string, overrides?: Partial<PgSeederConfig>): Promise<SeederRunResult[]>;
|
|
6
|
+
declare function getSeederStatuses(overrides?: Partial<PgSeederConfig>): Promise<SeederStatus[]>;
|
|
7
|
+
declare function resetSeeder(seederName: string, overrides?: Partial<PgSeederConfig>): Promise<void>;
|
|
8
|
+
|
|
9
|
+
declare function loadConfig(overrides?: Partial<PgSeederConfig>): Promise<ResolvedPgSeederConfig>;
|
|
10
|
+
/**
|
|
11
|
+
* Pick between a `src/` and `dist/` seeders directory based on the current
|
|
12
|
+
* runtime. Detection order:
|
|
13
|
+
*
|
|
14
|
+
* 1. If `srcWhen` returns `true`, use `src`.
|
|
15
|
+
* 2. Otherwise, if the entrypoint script lives inside a `dist` directory
|
|
16
|
+
* (e.g. `node dist/...`), use `dist`.
|
|
17
|
+
* 3. Otherwise, if the entrypoint ends with `.ts`/`.tsx` or is loaded via
|
|
18
|
+
* `tsx`/`ts-node`, use `src`.
|
|
19
|
+
* 4. Fall back to `dist`.
|
|
20
|
+
*
|
|
21
|
+
* Keeping seeders in the same module graph as the app avoids duplicate entity
|
|
22
|
+
* or model registration in TypeORM and Sequelize.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // pg-seed-kit.config.js
|
|
26
|
+
* import path from 'path';
|
|
27
|
+
* import { resolveSeedersPath } from 'pg-seed-kit';
|
|
28
|
+
*
|
|
29
|
+
* export default {
|
|
30
|
+
* seedersPath: resolveSeedersPath({
|
|
31
|
+
* src: path.join(process.cwd(), 'src/db/seeders'),
|
|
32
|
+
* dist: path.join(process.cwd(), 'dist/db/seeders'),
|
|
33
|
+
* }),
|
|
34
|
+
* };
|
|
35
|
+
*/
|
|
36
|
+
declare function resolveSeedersPath(opts: {
|
|
37
|
+
src: string;
|
|
38
|
+
dist: string;
|
|
39
|
+
/** Optional override (e.g. read NODE_ENV). Returning `true` forces `src`. */
|
|
40
|
+
srcWhen?: () => boolean;
|
|
41
|
+
}): SeedersPathResolver;
|
|
42
|
+
|
|
43
|
+
export { PgSeederConfig, ResolvedPgSeederConfig, SeederRunResult, SeederStatus, SeedersPathResolver, getSeederStatuses, loadConfig, resetSeeder, resolveSeedersPath, runPendingSeeders, runSeederByName };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { P as PgSeederConfig, S as SeederStatus, a as SeederRunResult, R as ResolvedPgSeederConfig, b as SeedersPathResolver } from './types-CCBHgrLA.js';
|
|
2
|
+
export { A as Adapter } from './types-CCBHgrLA.js';
|
|
3
|
+
|
|
4
|
+
declare function runPendingSeeders(overrides?: Partial<PgSeederConfig>): Promise<SeederRunResult[]>;
|
|
5
|
+
declare function runSeederByName(seederName: string, overrides?: Partial<PgSeederConfig>): Promise<SeederRunResult[]>;
|
|
6
|
+
declare function getSeederStatuses(overrides?: Partial<PgSeederConfig>): Promise<SeederStatus[]>;
|
|
7
|
+
declare function resetSeeder(seederName: string, overrides?: Partial<PgSeederConfig>): Promise<void>;
|
|
8
|
+
|
|
9
|
+
declare function loadConfig(overrides?: Partial<PgSeederConfig>): Promise<ResolvedPgSeederConfig>;
|
|
10
|
+
/**
|
|
11
|
+
* Pick between a `src/` and `dist/` seeders directory based on the current
|
|
12
|
+
* runtime. Detection order:
|
|
13
|
+
*
|
|
14
|
+
* 1. If `srcWhen` returns `true`, use `src`.
|
|
15
|
+
* 2. Otherwise, if the entrypoint script lives inside a `dist` directory
|
|
16
|
+
* (e.g. `node dist/...`), use `dist`.
|
|
17
|
+
* 3. Otherwise, if the entrypoint ends with `.ts`/`.tsx` or is loaded via
|
|
18
|
+
* `tsx`/`ts-node`, use `src`.
|
|
19
|
+
* 4. Fall back to `dist`.
|
|
20
|
+
*
|
|
21
|
+
* Keeping seeders in the same module graph as the app avoids duplicate entity
|
|
22
|
+
* or model registration in TypeORM and Sequelize.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // pg-seed-kit.config.js
|
|
26
|
+
* import path from 'path';
|
|
27
|
+
* import { resolveSeedersPath } from 'pg-seed-kit';
|
|
28
|
+
*
|
|
29
|
+
* export default {
|
|
30
|
+
* seedersPath: resolveSeedersPath({
|
|
31
|
+
* src: path.join(process.cwd(), 'src/db/seeders'),
|
|
32
|
+
* dist: path.join(process.cwd(), 'dist/db/seeders'),
|
|
33
|
+
* }),
|
|
34
|
+
* };
|
|
35
|
+
*/
|
|
36
|
+
declare function resolveSeedersPath(opts: {
|
|
37
|
+
src: string;
|
|
38
|
+
dist: string;
|
|
39
|
+
/** Optional override (e.g. read NODE_ENV). Returning `true` forces `src`. */
|
|
40
|
+
srcWhen?: () => boolean;
|
|
41
|
+
}): SeedersPathResolver;
|
|
42
|
+
|
|
43
|
+
export { PgSeederConfig, ResolvedPgSeederConfig, SeederRunResult, SeederStatus, SeedersPathResolver, getSeederStatuses, loadConfig, resetSeeder, resolveSeedersPath, runPendingSeeders, runSeederByName };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getSeederStatuses,
|
|
3
|
+
loadConfig,
|
|
4
|
+
resetSeeder,
|
|
5
|
+
resolveSeedersPath,
|
|
6
|
+
runPendingSeeders,
|
|
7
|
+
runSeederByName
|
|
8
|
+
} from "./chunk-KMXBCJZY.js";
|
|
9
|
+
export {
|
|
10
|
+
getSeederStatuses,
|
|
11
|
+
loadConfig,
|
|
12
|
+
resetSeeder,
|
|
13
|
+
resolveSeedersPath,
|
|
14
|
+
runPendingSeeders,
|
|
15
|
+
runSeederByName
|
|
16
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single abstraction the core depends on. An adapter exposes one method,
|
|
3
|
+
* `query`, that runs parameterized SQL (Postgres `$1`, `$2`, ... placeholders)
|
|
4
|
+
* against a live connection and returns the result rows.
|
|
5
|
+
*
|
|
6
|
+
* pg-seed-kit ships no database driver of its own: adapters are built on top of
|
|
7
|
+
* the connection your ORM already owns (see `pg-seed-kit/typeorm`,
|
|
8
|
+
* `pg-seed-kit/prisma`, and friends). The adapter is used only for the library's
|
|
9
|
+
* own tracking table; your seeders talk to the database through your ORM.
|
|
10
|
+
*/
|
|
11
|
+
interface Adapter {
|
|
12
|
+
query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
13
|
+
/** Optional teardown, invoked by the CLI after a standalone run. */
|
|
14
|
+
close?(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* `seedersPath` may be a static string or a function evaluated lazily when a
|
|
18
|
+
* runner is invoked. The function form lets consumers choose between a `src/`
|
|
19
|
+
* tree (loaded by tsx/ts-node in development) and a `dist/` tree (loaded by
|
|
20
|
+
* `node dist/...` in production), keeping seeders in the same module graph as
|
|
21
|
+
* the rest of the app.
|
|
22
|
+
*/
|
|
23
|
+
type SeedersPathResolver = () => string;
|
|
24
|
+
interface PgSeederConfig {
|
|
25
|
+
seedersPath: string | SeedersPathResolver;
|
|
26
|
+
/** Table used to track seeder execution. Defaults to `seeders`. */
|
|
27
|
+
tableName?: string;
|
|
28
|
+
filePattern?: RegExp;
|
|
29
|
+
/** A live adapter. Provide this when calling the API from your running app. */
|
|
30
|
+
adapter?: Adapter;
|
|
31
|
+
/**
|
|
32
|
+
* Used by the CLI only: connects the ORM and returns an adapter. Lets the
|
|
33
|
+
* standalone CLI open a connection in its own process, then close it.
|
|
34
|
+
*/
|
|
35
|
+
connect?: () => Promise<Adapter>;
|
|
36
|
+
}
|
|
37
|
+
/** Internal shape after `loadConfig` has resolved any function form. */
|
|
38
|
+
interface ResolvedPgSeederConfig {
|
|
39
|
+
seedersPath: string;
|
|
40
|
+
tableName: string;
|
|
41
|
+
filePattern: RegExp;
|
|
42
|
+
adapter?: Adapter;
|
|
43
|
+
connect?: () => Promise<Adapter>;
|
|
44
|
+
}
|
|
45
|
+
interface SeederRunResult {
|
|
46
|
+
name: string;
|
|
47
|
+
status: 'success' | 'failed' | 'skipped';
|
|
48
|
+
error?: string;
|
|
49
|
+
}
|
|
50
|
+
interface SeederStatus {
|
|
51
|
+
name: string;
|
|
52
|
+
status: 'success' | 'failed' | 'pending';
|
|
53
|
+
executedAt: Date | null;
|
|
54
|
+
error: string | null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type { Adapter as A, PgSeederConfig as P, ResolvedPgSeederConfig as R, SeederStatus as S, SeederRunResult as a, SeedersPathResolver as b };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single abstraction the core depends on. An adapter exposes one method,
|
|
3
|
+
* `query`, that runs parameterized SQL (Postgres `$1`, `$2`, ... placeholders)
|
|
4
|
+
* against a live connection and returns the result rows.
|
|
5
|
+
*
|
|
6
|
+
* pg-seed-kit ships no database driver of its own: adapters are built on top of
|
|
7
|
+
* the connection your ORM already owns (see `pg-seed-kit/typeorm`,
|
|
8
|
+
* `pg-seed-kit/prisma`, and friends). The adapter is used only for the library's
|
|
9
|
+
* own tracking table; your seeders talk to the database through your ORM.
|
|
10
|
+
*/
|
|
11
|
+
interface Adapter {
|
|
12
|
+
query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
13
|
+
/** Optional teardown, invoked by the CLI after a standalone run. */
|
|
14
|
+
close?(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* `seedersPath` may be a static string or a function evaluated lazily when a
|
|
18
|
+
* runner is invoked. The function form lets consumers choose between a `src/`
|
|
19
|
+
* tree (loaded by tsx/ts-node in development) and a `dist/` tree (loaded by
|
|
20
|
+
* `node dist/...` in production), keeping seeders in the same module graph as
|
|
21
|
+
* the rest of the app.
|
|
22
|
+
*/
|
|
23
|
+
type SeedersPathResolver = () => string;
|
|
24
|
+
interface PgSeederConfig {
|
|
25
|
+
seedersPath: string | SeedersPathResolver;
|
|
26
|
+
/** Table used to track seeder execution. Defaults to `seeders`. */
|
|
27
|
+
tableName?: string;
|
|
28
|
+
filePattern?: RegExp;
|
|
29
|
+
/** A live adapter. Provide this when calling the API from your running app. */
|
|
30
|
+
adapter?: Adapter;
|
|
31
|
+
/**
|
|
32
|
+
* Used by the CLI only: connects the ORM and returns an adapter. Lets the
|
|
33
|
+
* standalone CLI open a connection in its own process, then close it.
|
|
34
|
+
*/
|
|
35
|
+
connect?: () => Promise<Adapter>;
|
|
36
|
+
}
|
|
37
|
+
/** Internal shape after `loadConfig` has resolved any function form. */
|
|
38
|
+
interface ResolvedPgSeederConfig {
|
|
39
|
+
seedersPath: string;
|
|
40
|
+
tableName: string;
|
|
41
|
+
filePattern: RegExp;
|
|
42
|
+
adapter?: Adapter;
|
|
43
|
+
connect?: () => Promise<Adapter>;
|
|
44
|
+
}
|
|
45
|
+
interface SeederRunResult {
|
|
46
|
+
name: string;
|
|
47
|
+
status: 'success' | 'failed' | 'skipped';
|
|
48
|
+
error?: string;
|
|
49
|
+
}
|
|
50
|
+
interface SeederStatus {
|
|
51
|
+
name: string;
|
|
52
|
+
status: 'success' | 'failed' | 'pending';
|
|
53
|
+
executedAt: Date | null;
|
|
54
|
+
error: string | null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type { Adapter as A, PgSeederConfig as P, ResolvedPgSeederConfig as R, SeederStatus as S, SeederRunResult as a, SeedersPathResolver as b };
|