greenseed 0.1.0 → 0.1.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/dist/cli.cjs +157 -288
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +155 -286
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var dotenv = require('dotenv');
|
|
5
4
|
var sade = require('sade');
|
|
6
|
-
var path = require('path');
|
|
7
5
|
var v = require('valibot');
|
|
8
|
-
var
|
|
6
|
+
var dotenv = require('dotenv');
|
|
7
|
+
var path2 = require('path');
|
|
9
8
|
var postgres = require('postgres');
|
|
9
|
+
var fs = require('fs');
|
|
10
10
|
|
|
11
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
12
|
|
|
@@ -28,28 +28,114 @@ function _interopNamespace(e) {
|
|
|
28
28
|
return Object.freeze(n);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
|
|
32
31
|
var sade__default = /*#__PURE__*/_interopDefault(sade);
|
|
33
|
-
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
34
32
|
var v__namespace = /*#__PURE__*/_interopNamespace(v);
|
|
35
|
-
var
|
|
33
|
+
var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
|
|
34
|
+
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
36
35
|
var postgres__default = /*#__PURE__*/_interopDefault(postgres);
|
|
36
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
39
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
40
|
+
}) : x)(function(x) {
|
|
41
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
42
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
43
|
+
});
|
|
44
|
+
function connect(url) {
|
|
45
|
+
return postgres__default.default(url, { max: 10, idle_timeout: 20 });
|
|
46
|
+
}
|
|
47
|
+
async function check(sql) {
|
|
48
|
+
try {
|
|
49
|
+
await sql`select 1`;
|
|
50
|
+
} catch (err) {
|
|
51
|
+
throw new Error("Database connection failed");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function tableExists(sql, schema, table) {
|
|
55
|
+
const res = await sql`
|
|
56
|
+
select to_regclass(${schema + "." + table}) is not null as exists
|
|
57
|
+
`;
|
|
58
|
+
if (!res[0]) {
|
|
59
|
+
throw new Error("Failed checking table: " + schema + "." + table);
|
|
60
|
+
}
|
|
61
|
+
return res[0].exists;
|
|
62
|
+
}
|
|
63
|
+
async function validateTables(sql, tables) {
|
|
64
|
+
for (const t of tables) {
|
|
65
|
+
const ok = await tableExists(sql, t.schema, t.table);
|
|
66
|
+
if (!ok) {
|
|
67
|
+
throw new Error("Missing table: " + t.schema + "." + t.table);
|
|
45
68
|
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function metadata(sql, schema, table) {
|
|
72
|
+
const cols = await sql`
|
|
73
|
+
select column_name
|
|
74
|
+
from information_schema.columns
|
|
75
|
+
where table_schema = ${schema}
|
|
76
|
+
and table_name = ${table}
|
|
77
|
+
order by ordinal_position
|
|
78
|
+
`;
|
|
79
|
+
return { columns: cols.map((c) => c.column_name) };
|
|
80
|
+
}
|
|
81
|
+
async function insert(sql, schema, table, rows, columns, primaryKeys) {
|
|
82
|
+
if (primaryKeys.length === 0) {
|
|
83
|
+
throw new Error("No primary keys for " + schema + "." + table);
|
|
84
|
+
}
|
|
85
|
+
const q = await sql`
|
|
86
|
+
insert into ${sql(schema + "." + table)}
|
|
87
|
+
${sql(rows, columns)}
|
|
88
|
+
on conflict (${sql(primaryKeys)}) do nothing
|
|
89
|
+
returning ${sql(primaryKeys[0] ?? [])}
|
|
90
|
+
`;
|
|
91
|
+
return q.length;
|
|
92
|
+
}
|
|
93
|
+
function exists(p) {
|
|
94
|
+
return fs__default.default.existsSync(p);
|
|
95
|
+
}
|
|
96
|
+
function readFile(p) {
|
|
97
|
+
try {
|
|
98
|
+
return fs__default.default.readFileSync(p, "utf8");
|
|
99
|
+
} catch (err) {
|
|
100
|
+
throw new Error("Failed to read file: " + p);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function resolvePath(p) {
|
|
104
|
+
return path2__default.default.resolve(process.cwd(), p);
|
|
105
|
+
}
|
|
106
|
+
function loadJsonArray(p, onMissing) {
|
|
107
|
+
if (!exists(p)) {
|
|
108
|
+
if (onMissing === "skip") {
|
|
109
|
+
return [];
|
|
50
110
|
}
|
|
51
|
-
|
|
111
|
+
throw new Error("Source file not found: " + p);
|
|
112
|
+
}
|
|
113
|
+
const raw = readFile(p);
|
|
114
|
+
let parsed;
|
|
115
|
+
try {
|
|
116
|
+
parsed = JSON.parse(raw);
|
|
117
|
+
} catch {
|
|
118
|
+
throw new Error("Invalid JSON: " + p);
|
|
119
|
+
}
|
|
120
|
+
if (!Array.isArray(parsed)) {
|
|
121
|
+
throw new Error("Data is not an array: " + p);
|
|
52
122
|
}
|
|
123
|
+
return parsed;
|
|
124
|
+
}
|
|
125
|
+
function chunk(data, size) {
|
|
126
|
+
const out = [];
|
|
127
|
+
for (let i = 0; i < data.length; i += size) {
|
|
128
|
+
out.push(data.slice(i, i + size));
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/app.ts
|
|
134
|
+
var C = {
|
|
135
|
+
reset: "\x1B[0m",
|
|
136
|
+
green: "\x1B[32m",
|
|
137
|
+
yellow: "\x1B[33m",
|
|
138
|
+
gray: "\x1B[90m"
|
|
53
139
|
};
|
|
54
140
|
var ConfigSchema = v__namespace.object({
|
|
55
141
|
seedFileExtensions: v__namespace.array(v__namespace.picklist([".json"])),
|
|
@@ -64,286 +150,69 @@ var ConfigSchema = v__namespace.object({
|
|
|
64
150
|
})
|
|
65
151
|
)
|
|
66
152
|
});
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
} catch (err) {
|
|
75
|
-
throw new Error(`Failed to read file at ${filePath}: ${String(err)}`);
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
getExtension(filePath) {
|
|
79
|
-
return path__default.default.extname(filePath).toLowerCase();
|
|
80
|
-
},
|
|
81
|
-
resolvePath(filePath) {
|
|
82
|
-
return path__default.default.resolve(process.cwd(), filePath);
|
|
153
|
+
async function run(opts) {
|
|
154
|
+
dotenv__default.default.config();
|
|
155
|
+
const configPath = resolvePath(opts.config || "seed.config.json");
|
|
156
|
+
const raw = __require(configPath);
|
|
157
|
+
const parsed = v__namespace.safeParse(ConfigSchema, raw);
|
|
158
|
+
if (!parsed.success) {
|
|
159
|
+
throw new Error("Invalid configuration");
|
|
83
160
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const fileName = opts.config || "seed.config.json";
|
|
90
|
-
return fileSystem.resolvePath(fileName);
|
|
91
|
-
},
|
|
92
|
-
load(opts) {
|
|
93
|
-
const configPath = this.getConfigPath(opts);
|
|
94
|
-
if (!fileSystem.exists(configPath)) {
|
|
95
|
-
throw new Error(`Config file not found at ${configPath}`);
|
|
96
|
-
}
|
|
97
|
-
const content = fileSystem.read(configPath);
|
|
98
|
-
const data = parsers.json(content, path__default.default.basename(configPath));
|
|
99
|
-
const result = v__namespace.safeParse(ConfigSchema, data);
|
|
100
|
-
if (!result.success) {
|
|
101
|
-
const errors = result.issues.map((issue) => `- ${issue.message}`).join("\n");
|
|
102
|
-
throw new Error(`Invalid configuration:
|
|
103
|
-
${errors}`);
|
|
104
|
-
}
|
|
105
|
-
return result.output;
|
|
106
|
-
},
|
|
107
|
-
getDatabaseUrl(opts, config) {
|
|
108
|
-
const varName = opts.dbvar && opts.dbvar.length > 0 ? opts.dbvar : config.databaseUrlEnvVar || "DATABASE_URL";
|
|
109
|
-
const url = process.env[varName];
|
|
110
|
-
if (!url) {
|
|
111
|
-
throw new Error(
|
|
112
|
-
`Database URL environment variable "${varName}" is not set`
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
return url;
|
|
116
|
-
},
|
|
117
|
-
getConfigDir(opts) {
|
|
118
|
-
const configPath = this.getConfigPath(opts);
|
|
119
|
-
return path__default.default.dirname(configPath);
|
|
161
|
+
const config = parsed.output;
|
|
162
|
+
const dbVar = opts.dbvar && opts.dbvar.length > 0 ? opts.dbvar : config.databaseUrlEnvVar;
|
|
163
|
+
const dbUrl = process.env[dbVar];
|
|
164
|
+
if (!dbUrl) {
|
|
165
|
+
throw new Error("Missing DB env var: " + dbVar);
|
|
120
166
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
SELECT to_regclass(${schemaName + "." + tableName}) IS NOT NULL AS exists
|
|
142
|
-
`;
|
|
143
|
-
if (!result) {
|
|
144
|
-
throw new Error(
|
|
145
|
-
`Failed to check existence of table ${schemaName}.${tableName}`
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
return result.exists;
|
|
149
|
-
} catch (err) {
|
|
150
|
-
throw new Error(
|
|
151
|
-
`Failed to validate table ${schemaName}.${tableName}: ${String(err)}`
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
async validateTables(sql, tables) {
|
|
156
|
-
const checks = await Promise.all(
|
|
157
|
-
tables.map(async (t) => ({
|
|
158
|
-
table: t.table,
|
|
159
|
-
schema: t.schema,
|
|
160
|
-
exists: await this.tableExists(sql, t.table, t.schema)
|
|
161
|
-
}))
|
|
167
|
+
const sql = connect(dbUrl);
|
|
168
|
+
await check(sql);
|
|
169
|
+
await validateTables(
|
|
170
|
+
sql,
|
|
171
|
+
config.tables.map((t) => ({
|
|
172
|
+
table: t.table,
|
|
173
|
+
schema: t.schema
|
|
174
|
+
}))
|
|
175
|
+
);
|
|
176
|
+
console.log(C.gray + "Starting seed process" + C.reset);
|
|
177
|
+
for (const t of config.tables) {
|
|
178
|
+
const source = path2__default.default.resolve(path2__default.default.dirname(configPath), t.source);
|
|
179
|
+
const rows = loadJsonArray(source, config.onMissingFile || "error");
|
|
180
|
+
if (rows.length === 0) {
|
|
181
|
+
console.log(C.yellow + "Skipped " + t.table + C.reset);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const meta = await metadata(sql, t.schema, t.table);
|
|
185
|
+
const validCols = Object.keys(rows[0]).filter(
|
|
186
|
+
(c) => meta.columns.includes(c)
|
|
162
187
|
);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
select column_name
|
|
173
|
-
from information_schema.columns
|
|
174
|
-
where table_schema = ${schemaName}
|
|
175
|
-
and table_name = ${tableName}
|
|
176
|
-
order by ordinal_position
|
|
177
|
-
`;
|
|
178
|
-
const primaryKeys = await sql`
|
|
179
|
-
select a.attname as column_name
|
|
180
|
-
from pg_index i
|
|
181
|
-
join pg_attribute a on a.attrelid = i.indrelid and a.attnum = any(i.indkey)
|
|
182
|
-
join pg_class c on c.oid = i.indrelid
|
|
183
|
-
join pg_namespace n on n.oid = c.relnamespace
|
|
184
|
-
where n.nspname = ${schemaName}
|
|
185
|
-
and c.relname = ${tableName}
|
|
186
|
-
and i.indisprimary
|
|
187
|
-
`;
|
|
188
|
-
return {
|
|
189
|
-
columns: columns.map((c) => c.column_name),
|
|
190
|
-
primaryKeys: primaryKeys.map((pk) => pk.column_name)
|
|
191
|
-
};
|
|
192
|
-
} catch (err) {
|
|
193
|
-
throw new Error(
|
|
194
|
-
`Failed to get metadata for table ${schemaName}.${tableName}: ${String(err)}`
|
|
188
|
+
let inserted = 0;
|
|
189
|
+
for (const part of chunk(rows, 1e3)) {
|
|
190
|
+
inserted += await insert(
|
|
191
|
+
sql,
|
|
192
|
+
t.schema,
|
|
193
|
+
t.table,
|
|
194
|
+
part,
|
|
195
|
+
validCols,
|
|
196
|
+
t.primaryKeys
|
|
195
197
|
);
|
|
196
198
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (primaryKeys.length === 0) {
|
|
200
|
-
throw new Error(
|
|
201
|
-
`Table ${schemaName}.${tableName} has no primary keys defined`
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
const qualifiedTable = `${schemaName}.${tableName}`;
|
|
205
|
-
const result = await sql`
|
|
206
|
-
INSERT INTO ${sql(qualifiedTable)} ${sql(data, columns)}
|
|
207
|
-
ON CONFLICT (${sql(primaryKeys)}) DO NOTHING
|
|
208
|
-
RETURNING ${sql(primaryKeys[0] || [])}
|
|
209
|
-
`;
|
|
210
|
-
return result.length;
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
var dataLoader = {
|
|
214
|
-
load(sourcePath, config, configDir) {
|
|
215
|
-
const fullPath = path__default.default.isAbsolute(sourcePath) ? sourcePath : path__default.default.resolve(configDir, sourcePath);
|
|
216
|
-
if (!fileSystem.exists(fullPath)) {
|
|
217
|
-
const onMissingFile = config.onMissingFile || "error";
|
|
218
|
-
if (onMissingFile === "skip") {
|
|
219
|
-
console.warn(`Warning: Source file not found at ${fullPath}. Skipping.`);
|
|
220
|
-
return [];
|
|
221
|
-
} else {
|
|
222
|
-
throw new Error(`Source file not found at ${fullPath}`);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
const content = fileSystem.read(fullPath);
|
|
226
|
-
const ext = fileSystem.getExtension(fullPath);
|
|
227
|
-
if (ext === ".json") {
|
|
228
|
-
const data = parsers.json(content, sourcePath);
|
|
229
|
-
return parsers.validateArray(data, sourcePath);
|
|
230
|
-
}
|
|
231
|
-
throw new Error(`Unsupported file extension: ${ext}`);
|
|
232
|
-
},
|
|
233
|
-
chunkData(data, chunkSize) {
|
|
234
|
-
const chunks = [];
|
|
235
|
-
for (let i = 0; i < data.length; i += chunkSize) {
|
|
236
|
-
chunks.push(data.slice(i, i + chunkSize));
|
|
237
|
-
}
|
|
238
|
-
return chunks;
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
// src/services/seeder.ts
|
|
243
|
-
var seeder = {
|
|
244
|
-
async seedTable(sql, tableConfig, config, configDir) {
|
|
245
|
-
const data = dataLoader.load(tableConfig.source, config, configDir);
|
|
246
|
-
if (data.length === 0) {
|
|
247
|
-
return {
|
|
248
|
-
table: tableConfig.table,
|
|
249
|
-
schema: tableConfig.schema,
|
|
250
|
-
totalRecords: 0,
|
|
251
|
-
insertedRecords: 0
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
const metadata = await databaseOperations.getTableMetadata(
|
|
255
|
-
sql,
|
|
256
|
-
tableConfig.table,
|
|
257
|
-
tableConfig.schema
|
|
258
|
-
);
|
|
259
|
-
const dataColumns = Object.keys(data[0] || {});
|
|
260
|
-
const validColumns = dataColumns.filter(
|
|
261
|
-
(col) => metadata.columns.includes(col)
|
|
199
|
+
console.log(
|
|
200
|
+
C.green + t.schema + "." + t.table + ": " + inserted + "/" + rows.length + C.reset
|
|
262
201
|
);
|
|
263
|
-
if (validColumns.length === 0) {
|
|
264
|
-
throw new Error(
|
|
265
|
-
`No valid columns found in data for table ${tableConfig.schema}.${tableConfig.table}`
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
const chunks = dataLoader.chunkData(data, 1e3);
|
|
269
|
-
let insertedCount = 0;
|
|
270
|
-
for (const chunk of chunks) {
|
|
271
|
-
try {
|
|
272
|
-
const inserted = await databaseOperations.insertData(
|
|
273
|
-
sql,
|
|
274
|
-
tableConfig.table,
|
|
275
|
-
tableConfig.schema,
|
|
276
|
-
chunk,
|
|
277
|
-
validColumns,
|
|
278
|
-
tableConfig.primaryKeys
|
|
279
|
-
);
|
|
280
|
-
insertedCount += inserted;
|
|
281
|
-
} catch (err) {
|
|
282
|
-
const msg = err instanceof postgres__default.default.PostgresError ? err.message : String(err);
|
|
283
|
-
throw new Error(
|
|
284
|
-
`Failed to insert data into ${tableConfig.schema}.${tableConfig.table}: ${msg}`
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
return {
|
|
289
|
-
table: tableConfig.table,
|
|
290
|
-
schema: tableConfig.schema,
|
|
291
|
-
totalRecords: data.length,
|
|
292
|
-
insertedRecords: insertedCount
|
|
293
|
-
};
|
|
294
|
-
},
|
|
295
|
-
async execute(config, sql, configDir) {
|
|
296
|
-
const tables = config.tables.map((t) => ({
|
|
297
|
-
table: t.table,
|
|
298
|
-
schema: t.schema
|
|
299
|
-
}));
|
|
300
|
-
await databaseOperations.validateTables(sql, tables);
|
|
301
|
-
console.log("Starting seed process.");
|
|
302
|
-
for (const tableConfig of config.tables) {
|
|
303
|
-
try {
|
|
304
|
-
const result = await this.seedTable(sql, tableConfig, config, configDir);
|
|
305
|
-
if (result.totalRecords === 0) {
|
|
306
|
-
console.log(
|
|
307
|
-
`No data to insert for table "${result.schema}.${result.table}"`
|
|
308
|
-
);
|
|
309
|
-
} else {
|
|
310
|
-
console.log(
|
|
311
|
-
`Table "${result.schema}.${result.table}": Processed ${result.totalRecords} records, inserted ${result.insertedRecords} new rows.`
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
} catch (err) {
|
|
315
|
-
throw new Error(
|
|
316
|
-
`Failed to seed table "${tableConfig.schema}.${tableConfig.table}": ${String(err)}`
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
console.log("Seed process completed.");
|
|
321
|
-
}
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
// src/services/application.ts
|
|
325
|
-
var application = {
|
|
326
|
-
async run(opts) {
|
|
327
|
-
try {
|
|
328
|
-
const config = configManager.load(opts);
|
|
329
|
-
const configDir = configManager.getConfigDir(opts);
|
|
330
|
-
const dbUrl = configManager.getDatabaseUrl(opts, config);
|
|
331
|
-
const sql = databaseConnection.create(dbUrl);
|
|
332
|
-
await databaseConnection.checkConnection(sql);
|
|
333
|
-
await seeder.execute(config, sql, configDir);
|
|
334
|
-
await sql.end();
|
|
335
|
-
} catch (err) {
|
|
336
|
-
console.error(String(err));
|
|
337
|
-
process.exit(1);
|
|
338
|
-
}
|
|
339
202
|
}
|
|
340
|
-
|
|
203
|
+
await sql.end();
|
|
204
|
+
console.log(C.green + "Seed completed" + C.reset);
|
|
205
|
+
}
|
|
341
206
|
|
|
342
207
|
// src/cli.ts
|
|
343
208
|
var prog = sade__default.default("greenseed");
|
|
344
|
-
prog.command("push").option("-c, --config <file>", "
|
|
345
|
-
|
|
346
|
-
|
|
209
|
+
prog.command("push").option("-c, --config <file>", "Config file", "seed.config.json").option("-d, --dbvar <name>", "DB env var override").action(async (opts) => {
|
|
210
|
+
try {
|
|
211
|
+
await run(opts);
|
|
212
|
+
} catch (err) {
|
|
213
|
+
console.error("\x1B[31m" + String(err) + "\x1B[0m");
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
347
216
|
});
|
|
348
217
|
prog.parse(process.argv);
|
|
349
218
|
//# sourceMappingURL=cli.cjs.map
|
package/dist/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/parsers/index.ts","../src/types/index.ts","../src/utils/file-system.ts","../src/config/manager.ts","../src/core/database/connection.ts","../src/core/database/operations.ts","../src/core/loaders/data-loader.ts","../src/services/seeder.ts","../src/services/application.ts","../src/cli.ts"],"names":["v","fs","path","v2","postgres","sade","dotenv"],"mappings":"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","file":"cli.cjs","sourcesContent":["export const parsers = {\n\tjson(content: string, fileName: string): unknown {\n\t\ttry {\n\t\t\treturn JSON.parse(content)\n\t\t} catch (err) {\n\t\t\tthrow new Error(`Invalid JSON in ${fileName}: ${String(err)}`)\n\t\t}\n\t},\n\n\tvalidateArray(data: unknown, fileName: string): Record<string, any>[] {\n\t\tif (!Array.isArray(data)) {\n\t\t\tthrow new Error(`Data in ${fileName} is not an array`)\n\t\t}\n\t\treturn data as Record<string, any>[]\n\t},\n}\n","import * as v from \"valibot\"\n\nexport const ConfigSchema = v.object({\n\tseedFileExtensions: v.array(v.picklist([\".json\"])),\n\tdatabaseUrlEnvVar: v.string(),\n\tonMissingFile: v.optional(v.picklist([\"skip\", \"error\"]), \"error\"),\n\ttables: v.array(\n\t\tv.object({\n\t\t\ttable: v.string(),\n\t\t\tschema: v.optional(v.string(), \"public\"),\n\t\t\tprimaryKeys: v.array(v.string()),\n\t\t\tsource: v.string(),\n\t\t}),\n\t),\n})\n\nexport type Config = v.InferOutput<typeof ConfigSchema>\n\nexport type TableConfig = {\n\ttable: string\n\tschema: string\n\tprimaryKeys: string[]\n\tsource: string\n}\n\nexport type TableMetadata = {\n\tcolumns: string[]\n\tprimaryKeys: string[]\n}\n\nexport type SeedResult = {\n\ttable: string\n\tschema: string\n\ttotalRecords: number\n\tinsertedRecords: number\n}\n\nexport type Opts = {\n\tconfig: string\n\tdbvar?: string\n}\n","import fs from \"fs\"\nimport path from \"path\"\n\nexport const fileSystem = {\n\texists(filePath: string): boolean {\n\t\treturn fs.existsSync(filePath)\n\t},\n\n\tread(filePath: string): string {\n\t\ttry {\n\t\t\treturn fs.readFileSync(filePath, \"utf8\")\n\t\t} catch (err) {\n\t\t\tthrow new Error(`Failed to read file at ${filePath}: ${String(err)}`)\n\t\t}\n\t},\n\n\tgetExtension(filePath: string): string {\n\t\treturn path.extname(filePath).toLowerCase()\n\t},\n\n\tresolvePath(filePath: string): string {\n\t\treturn path.resolve(process.cwd(), filePath)\n\t},\n}\n","import path from \"path\"\nimport * as v from \"valibot\"\nimport { parsers } from \"../core/parsers\"\nimport type { Config, Opts } from \"../types\"\nimport { ConfigSchema } from \"../types\"\nimport { fileSystem } from \"../utils/file-system\"\n\nexport const configManager = {\n\tgetConfigPath(opts: Opts): string {\n\t\tconst fileName = opts.config || \"seed.config.json\"\n\t\treturn fileSystem.resolvePath(fileName)\n\t},\n\n\tload(opts: Opts): Config {\n\t\tconst configPath = this.getConfigPath(opts)\n\n\t\tif (!fileSystem.exists(configPath)) {\n\t\t\tthrow new Error(`Config file not found at ${configPath}`)\n\t\t}\n\n\t\tconst content = fileSystem.read(configPath)\n\t\tconst data = parsers.json(content, path.basename(configPath))\n\t\tconst result = v.safeParse(ConfigSchema, data)\n\n\t\tif (!result.success) {\n\t\t\tconst errors = result.issues\n\t\t\t\t.map((issue) => `- ${issue.message}`)\n\t\t\t\t.join(\"\\n\")\n\t\t\tthrow new Error(`Invalid configuration:\\n${errors}`)\n\t\t}\n\n\t\treturn result.output\n\t},\n\n\tgetDatabaseUrl(opts: Opts, config: Config): string {\n\t\tconst varName =\n\t\t\topts.dbvar && opts.dbvar.length > 0\n\t\t\t\t? opts.dbvar\n\t\t\t\t: config.databaseUrlEnvVar || \"DATABASE_URL\"\n\n\t\tconst url = process.env[varName]\n\t\tif (!url) {\n\t\t\tthrow new Error(\n\t\t\t\t`Database URL environment variable \"${varName}\" is not set`,\n\t\t\t)\n\t\t}\n\t\treturn url\n\t},\n\n\tgetConfigDir(opts: Opts): string {\n\t\tconst configPath = this.getConfigPath(opts)\n\t\treturn path.dirname(configPath)\n\t},\n}\n","import postgres from \"postgres\"\n\nexport const databaseConnection = {\n\tcreate(url: string): postgres.Sql {\n\t\treturn postgres(url, { max: 10, idle_timeout: 20 })\n\t},\n\n\tasync checkConnection(sql: postgres.Sql): Promise<void> {\n\t\ttry {\n\t\t\tawait sql`select 1`\n\t\t} catch (err) {\n\t\t\tconst msg =\n\t\t\t\terr instanceof postgres.PostgresError ? err.message : String(err)\n\t\t\tthrow new Error(`Failed to connect to database: ${msg}`)\n\t\t}\n\t},\n}\n","import postgres from \"postgres\"\nimport type { TableMetadata } from \"../../types\"\n\nexport const databaseOperations = {\n\tasync tableExists(\n\t\tsql: postgres.Sql,\n\t\ttableName: string,\n\t\tschemaName: string,\n\t): Promise<boolean> {\n\t\ttry {\n\t\t\tconst [result] = await sql<{ exists: boolean }[]>`\n\t\t\t\tSELECT to_regclass(${schemaName + \".\" + tableName}) IS NOT NULL AS exists\n\t\t\t`\n\n\t\t\tif (!result) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to check existence of table ${schemaName}.${tableName}`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn result.exists\n\t\t} catch (err) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to validate table ${schemaName}.${tableName}: ${String(err)}`,\n\t\t\t)\n\t\t}\n\t},\n\n\tasync validateTables(\n\t\tsql: postgres.Sql,\n\t\ttables: Array<{ table: string; schema: string }>,\n\t): Promise<void> {\n\t\tconst checks = await Promise.all(\n\t\t\ttables.map(async (t) => ({\n\t\t\t\ttable: t.table,\n\t\t\t\tschema: t.schema,\n\t\t\t\texists: await this.tableExists(sql, t.table, t.schema),\n\t\t\t})),\n\t\t)\n\n\t\tconst missing = checks.filter((c) => !c.exists)\n\t\tif (missing.length > 0) {\n\t\t\tconst missingNames = missing\n\t\t\t\t.map((m) => `${m.schema}.${m.table}`)\n\t\t\t\t.join(\", \")\n\t\t\tthrow new Error(`Missing tables: ${missingNames}`)\n\t\t}\n\t},\n\n\tasync getTableMetadata(\n\t\tsql: postgres.Sql,\n\t\ttableName: string,\n\t\tschemaName: string,\n\t): Promise<TableMetadata> {\n\t\ttry {\n\t\t\tconst columns = await sql<{ column_name: string }[]>`\n\t\t\t\tselect column_name\n\t\t\t\tfrom information_schema.columns\n\t\t\t\twhere table_schema = ${schemaName}\n\t\t\t\tand table_name = ${tableName}\n\t\t\t\torder by ordinal_position\n\t\t\t`\n\n\t\t\tconst primaryKeys = await sql<{ column_name: string }[]>`\n\t\t\t\tselect a.attname as column_name\n\t\t\t\tfrom pg_index i\n\t\t\t\tjoin pg_attribute a on a.attrelid = i.indrelid and a.attnum = any(i.indkey)\n\t\t\t\tjoin pg_class c on c.oid = i.indrelid\n\t\t\t\tjoin pg_namespace n on n.oid = c.relnamespace\n\t\t\t\twhere n.nspname = ${schemaName}\n\t\t\t\tand c.relname = ${tableName}\n\t\t\t\tand i.indisprimary\n\t\t\t`\n\n\t\t\treturn {\n\t\t\t\tcolumns: columns.map((c) => c.column_name),\n\t\t\t\tprimaryKeys: primaryKeys.map((pk) => pk.column_name),\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to get metadata for table ${schemaName}.${tableName}: ${String(err)}`,\n\t\t\t)\n\t\t}\n\t},\n\n\tasync insertData(\n\t\tsql: postgres.Sql,\n\t\ttableName: string,\n\t\tschemaName: string,\n\t\tdata: Record<string, any>[],\n\t\tcolumns: string[],\n\t\tprimaryKeys: string[],\n\t): Promise<number> {\n\t\tif (primaryKeys.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Table ${schemaName}.${tableName} has no primary keys defined`,\n\t\t\t)\n\t\t}\n\n\t\tconst qualifiedTable = `${schemaName}.${tableName}`\n\t\tconst result = await sql`\n\t\t\tINSERT INTO ${sql(qualifiedTable)} ${sql(data, columns)}\n\t\t\tON CONFLICT (${sql(primaryKeys)}) DO NOTHING\n\t\t\tRETURNING ${sql(primaryKeys[0] || [])}\n\t\t`\n\n\t\treturn result.length\n\t},\n}\n","import path from \"path\"\nimport type { Config } from \"../../types\"\nimport { fileSystem } from \"../../utils/file-system\"\nimport { parsers } from \"../parsers\"\n\nexport const dataLoader = {\n\tload(\n\t\tsourcePath: string,\n\t\tconfig: Config,\n\t\tconfigDir: string,\n\t): Record<string, any>[] {\n\t\tconst fullPath = path.isAbsolute(sourcePath)\n\t\t\t? sourcePath\n\t\t\t: path.resolve(configDir, sourcePath)\n\n\t\tif (!fileSystem.exists(fullPath)) {\n\t\t\tconst onMissingFile = config.onMissingFile || \"error\"\n\n\t\t\tif (onMissingFile === \"skip\") {\n\t\t\t\tconsole.warn(`Warning: Source file not found at ${fullPath}. Skipping.`)\n\t\t\t\treturn []\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Source file not found at ${fullPath}`)\n\t\t\t}\n\t\t}\n\n\t\tconst content = fileSystem.read(fullPath)\n\t\tconst ext = fileSystem.getExtension(fullPath)\n\n\t\tif (ext === \".json\") {\n\t\t\tconst data = parsers.json(content, sourcePath)\n\t\t\treturn parsers.validateArray(data, sourcePath)\n\t\t}\n\n\t\tthrow new Error(`Unsupported file extension: ${ext}`)\n\t},\n\n\tchunkData<T>(data: T[], chunkSize: number): T[][] {\n\t\tconst chunks: T[][] = []\n\t\tfor (let i = 0; i < data.length; i += chunkSize) {\n\t\t\tchunks.push(data.slice(i, i + chunkSize))\n\t\t}\n\t\treturn chunks\n\t},\n}\n","import postgres from \"postgres\"\nimport { databaseOperations } from \"../core/database/operations\"\nimport { dataLoader } from \"../core/loaders/data-loader\"\nimport type { Config, SeedResult, TableConfig } from \"../types\"\n\nexport const seeder = {\n\tasync seedTable(\n\t\tsql: postgres.Sql,\n\t\ttableConfig: TableConfig,\n\t\tconfig: Config,\n\t\tconfigDir: string,\n\t): Promise<SeedResult> {\n\t\tconst data = dataLoader.load(tableConfig.source, config, configDir)\n\n\t\tif (data.length === 0) {\n\t\t\treturn {\n\t\t\t\ttable: tableConfig.table,\n\t\t\t\tschema: tableConfig.schema,\n\t\t\t\ttotalRecords: 0,\n\t\t\t\tinsertedRecords: 0,\n\t\t\t}\n\t\t}\n\n\t\tconst metadata = await databaseOperations.getTableMetadata(\n\t\t\tsql,\n\t\t\ttableConfig.table,\n\t\t\ttableConfig.schema,\n\t\t)\n\n\t\tconst dataColumns = Object.keys(data[0] || {})\n\t\tconst validColumns = dataColumns.filter((col) =>\n\t\t\tmetadata.columns.includes(col),\n\t\t)\n\n\t\tif (validColumns.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`No valid columns found in data for table ${tableConfig.schema}.${tableConfig.table}`,\n\t\t\t)\n\t\t}\n\n\t\tconst chunks = dataLoader.chunkData(data, 1000)\n\t\tlet insertedCount = 0\n\n\t\tfor (const chunk of chunks) {\n\t\t\ttry {\n\t\t\t\tconst inserted = await databaseOperations.insertData(\n\t\t\t\t\tsql,\n\t\t\t\t\ttableConfig.table,\n\t\t\t\t\ttableConfig.schema,\n\t\t\t\t\tchunk,\n\t\t\t\t\tvalidColumns,\n\t\t\t\t\ttableConfig.primaryKeys,\n\t\t\t\t)\n\t\t\t\tinsertedCount += inserted\n\t\t\t} catch (err) {\n\t\t\t\tconst msg =\n\t\t\t\t\terr instanceof postgres.PostgresError ? err.message : String(err)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to insert data into ${tableConfig.schema}.${tableConfig.table}: ${msg}`,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\ttable: tableConfig.table,\n\t\t\tschema: tableConfig.schema,\n\t\t\ttotalRecords: data.length,\n\t\t\tinsertedRecords: insertedCount,\n\t\t}\n\t},\n\n\tasync execute(\n\t\tconfig: Config,\n\t\tsql: postgres.Sql,\n\t\tconfigDir: string,\n\t): Promise<void> {\n\t\tconst tables = config.tables.map((t) => ({\n\t\t\ttable: t.table,\n\t\t\tschema: t.schema,\n\t\t}))\n\t\tawait databaseOperations.validateTables(sql, tables)\n\n\t\tconsole.log(\"Starting seed process.\")\n\n\t\tfor (const tableConfig of config.tables) {\n\t\t\ttry {\n\t\t\t\tconst result = await this.seedTable(sql, tableConfig, config, configDir)\n\n\t\t\t\tif (result.totalRecords === 0) {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`No data to insert for table \"${result.schema}.${result.table}\"`,\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`Table \"${result.schema}.${result.table}\": Processed ${result.totalRecords} records, inserted ${result.insertedRecords} new rows.`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to seed table \"${tableConfig.schema}.${tableConfig.table}\": ${String(err)}`,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tconsole.log(\"Seed process completed.\")\n\t},\n}\n","import { configManager } from \"../config/manager\"\nimport { databaseConnection } from \"../core/database\"\nimport type { Opts } from \"../types\"\nimport { seeder } from \"./seeder\"\n\nexport const application = {\n\tasync run(opts: Opts): Promise<void> {\n\t\ttry {\n\t\t\tconst config = configManager.load(opts)\n\t\t\tconst configDir = configManager.getConfigDir(opts)\n\t\t\tconst dbUrl = configManager.getDatabaseUrl(opts, config)\n\t\t\tconst sql = databaseConnection.create(dbUrl)\n\n\t\t\tawait databaseConnection.checkConnection(sql)\n\t\t\tawait seeder.execute(config, sql, configDir)\n\t\t\tawait sql.end()\n\t\t} catch (err) {\n\t\t\tconsole.error(String(err))\n\t\t\tprocess.exit(1)\n\t\t}\n\t},\n}\n","#!/usr/bin/env node\nimport dotenv from \"dotenv\"\nimport sade from \"sade\"\nimport { application } from \"./services/application\"\nimport type { Opts } from \"./types\"\n\nconst prog = sade(\"greenseed\")\n\nprog\n\t.command(\"push\")\n\t.option(\"-c, --config <file>\", \"Path to config file\", \"seed.config.json\")\n\t.option(\"-d, --dbvar <name>\", \"Database URL env var name (overrides config)\")\n\t.action(async (opts: Opts) => {\n\t\tdotenv.config()\n\t\tawait application.run(opts)\n\t})\n\nprog.parse(process.argv)\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/db.ts","../src/fs.ts","../src/app.ts","../src/cli.ts"],"names":["postgres","fs","path","v","dotenv","sade"],"mappings":"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","file":"cli.cjs","sourcesContent":["import postgres from \"postgres\"\n\nexport function connect(url: string): postgres.Sql {\n\treturn postgres(url, { max: 10, idle_timeout: 20 })\n}\n\nexport async function check(sql: postgres.Sql): Promise<void> {\n\ttry {\n\t\tawait sql`select 1`\n\t} catch (err) {\n\t\tthrow new Error(\"Database connection failed\")\n\t}\n}\n\nexport async function tableExists(\n\tsql: postgres.Sql,\n\tschema: string,\n\ttable: string,\n): Promise<boolean> {\n\tconst res = await sql<{ exists: boolean }[]>`\n\t\tselect to_regclass(${schema + \".\" + table}) is not null as exists\n\t`\n\tif (!res[0]) {\n\t\tthrow new Error(\"Failed checking table: \" + schema + \".\" + table)\n\t}\n\treturn res[0].exists\n}\n\nexport async function validateTables(\n\tsql: postgres.Sql,\n\ttables: { schema: string; table: string }[],\n): Promise<void> {\n\tfor (const t of tables) {\n\t\tconst ok = await tableExists(sql, t.schema, t.table)\n\t\tif (!ok) {\n\t\t\tthrow new Error(\"Missing table: \" + t.schema + \".\" + t.table)\n\t\t}\n\t}\n}\n\nexport async function metadata(\n\tsql: postgres.Sql,\n\tschema: string,\n\ttable: string,\n): Promise<{ columns: string[] }> {\n\tconst cols = await sql<{ column_name: string }[]>`\n\t\tselect column_name\n\t\tfrom information_schema.columns\n\t\twhere table_schema = ${schema}\n\t\tand table_name = ${table}\n\t\torder by ordinal_position\n\t`\n\treturn { columns: cols.map(c => c.column_name) }\n}\n\nexport async function insert(\n\tsql: postgres.Sql,\n\tschema: string,\n\ttable: string,\n\trows: Record<string, any>[],\n\tcolumns: string[],\n\tprimaryKeys: string[],\n): Promise<number> {\n\tif (primaryKeys.length === 0) {\n\t\tthrow new Error(\"No primary keys for \" + schema + \".\" + table)\n\t}\n\n\tconst q = await sql`\n\t\tinsert into ${sql(schema + \".\" + table)}\n\t\t${sql(rows, columns)}\n\t\ton conflict (${sql(primaryKeys)}) do nothing\n\t\treturning ${sql(primaryKeys[0] ?? [])}\n\t`\n\treturn q.length\n}\n","import fs from \"fs\"\nimport path from \"path\"\n\nexport function exists(p: string): boolean {\n\treturn fs.existsSync(p)\n}\n\nexport function readFile(p: string): string {\n\ttry {\n\t\treturn fs.readFileSync(p, \"utf8\")\n\t} catch (err) {\n\t\tthrow new Error(\"Failed to read file: \" + p)\n\t}\n}\n\nexport function resolvePath(p: string): string {\n\treturn path.resolve(process.cwd(), p)\n}\n\nexport function ext(p: string): string {\n\treturn path.extname(p).toLowerCase()\n}\n\nexport function loadJsonArray(p: string, onMissing: \"skip\" | \"error\"): any[] {\n\tif (!exists(p)) {\n\t\tif (onMissing === \"skip\") {\n\t\t\treturn []\n\t\t}\n\t\tthrow new Error(\"Source file not found: \" + p)\n\t}\n\n\tconst raw = readFile(p)\n\n\tlet parsed: unknown\n\ttry {\n\t\tparsed = JSON.parse(raw)\n\t} catch {\n\t\tthrow new Error(\"Invalid JSON: \" + p)\n\t}\n\n\tif (!Array.isArray(parsed)) {\n\t\tthrow new Error(\"Data is not an array: \" + p)\n\t}\n\n\treturn parsed\n}\n\nexport function chunk<T>(data: T[], size: number): T[][] {\n\tconst out: T[][] = []\n\tfor (let i = 0; i < data.length; i += size) {\n\t\tout.push(data.slice(i, i + size))\n\t}\n\treturn out\n}\n","import * as v from \"valibot\"\nimport dotenv from \"dotenv\"\nimport path from \"path\"\nimport { connect, check, validateTables, metadata, insert } from \"./db\"\nimport { resolvePath, loadJsonArray, chunk } from \"./fs\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tgreen: \"\\x1b[32m\",\n\tyellow: \"\\x1b[33m\",\n\tred: \"\\x1b[31m\",\n\tgray: \"\\x1b[90m\",\n}\n\nconst ConfigSchema = v.object({\n\tseedFileExtensions: v.array(v.picklist([\".json\"])),\n\tdatabaseUrlEnvVar: v.string(),\n\tonMissingFile: v.optional(v.picklist([\"skip\", \"error\"]), \"error\"),\n\ttables: v.array(\n\t\tv.object({\n\t\t\ttable: v.string(),\n\t\t\tschema: v.optional(v.string(), \"public\"),\n\t\t\tprimaryKeys: v.array(v.string()),\n\t\t\tsource: v.string(),\n\t\t}),\n\t),\n})\n\ntype Opts = { config: string; dbvar?: string }\n\nexport async function run(opts: Opts): Promise<void> {\n\tdotenv.config()\n\n\tconst configPath = resolvePath(opts.config || \"seed.config.json\")\n\tconst raw = require(configPath)\n\tconst parsed = v.safeParse(ConfigSchema, raw)\n\n\tif (!parsed.success) {\n\t\tthrow new Error(\"Invalid configuration\")\n\t}\n\n\tconst config = parsed.output\n\tconst dbVar =\n\t\topts.dbvar && opts.dbvar.length > 0\n\t\t\t? opts.dbvar\n\t\t\t: config.databaseUrlEnvVar\n\n\tconst dbUrl = process.env[dbVar]\n\tif (!dbUrl) {\n\t\tthrow new Error(\"Missing DB env var: \" + dbVar)\n\t}\n\n\tconst sql = connect(dbUrl)\n\tawait check(sql)\n\n\tawait validateTables(\n\t\tsql,\n\t\tconfig.tables.map(t => ({\n\t\t\ttable: t.table,\n\t\t\tschema: t.schema,\n\t\t})),\n\t)\n\n\tconsole.log(C.gray + \"Starting seed process\" + C.reset)\n\n\tfor (const t of config.tables) {\n\t\tconst source = path.resolve(path.dirname(configPath), t.source)\n\t\tconst rows = loadJsonArray(source, config.onMissingFile || \"error\")\n\n\t\tif (rows.length === 0) {\n\t\t\tconsole.log(C.yellow + \"Skipped \" + t.table + C.reset)\n\t\t\tcontinue\n\t\t}\n\n\t\tconst meta = await metadata(sql, t.schema, t.table)\n\t\tconst validCols = Object.keys(rows[0]).filter(c =>\n\t\t\tmeta.columns.includes(c),\n\t\t)\n\n\t\tlet inserted = 0\n\t\tfor (const part of chunk(rows, 1000)) {\n\t\t\tinserted += await insert(\n\t\t\t\tsql,\n\t\t\t\tt.schema,\n\t\t\t\tt.table,\n\t\t\t\tpart,\n\t\t\t\tvalidCols,\n\t\t\t\tt.primaryKeys,\n\t\t\t)\n\t\t}\n\n\t\tconsole.log(\n\t\t\tC.green +\n\t\t\t\tt.schema +\n\t\t\t\t\".\" +\n\t\t\t\tt.table +\n\t\t\t\t\": \" +\n\t\t\t\tinserted +\n\t\t\t\t\"/\" +\n\t\t\t\trows.length +\n\t\t\t\tC.reset,\n\t\t)\n\t}\n\n\tawait sql.end()\n\tconsole.log(C.green + \"Seed completed\" + C.reset)\n}\n","#!/usr/bin/env node\nimport sade from \"sade\"\nimport { run } from \"./app\"\n\nconst prog = sade(\"greenseed\")\n\nprog\n\t.command(\"push\")\n\t.option(\"-c, --config <file>\", \"Config file\", \"seed.config.json\")\n\t.option(\"-d, --dbvar <name>\", \"DB env var override\")\n\t.action(async opts => {\n\t\ttry {\n\t\t\tawait run(opts)\n\t\t} catch (err) {\n\t\t\tconsole.error(\"\\x1b[31m\" + String(err) + \"\\x1b[0m\")\n\t\t\tprocess.exit(1)\n\t\t}\n\t})\n\nprog.parse(process.argv)\n"]}
|
package/dist/cli.js
CHANGED
|
@@ -1,26 +1,112 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import dotenv from 'dotenv';
|
|
3
2
|
import sade from 'sade';
|
|
4
|
-
import path from 'path';
|
|
5
3
|
import * as v from 'valibot';
|
|
6
|
-
import
|
|
4
|
+
import dotenv from 'dotenv';
|
|
5
|
+
import path2 from 'path';
|
|
7
6
|
import postgres from 'postgres';
|
|
7
|
+
import fs from 'fs';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
10
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
11
|
+
}) : x)(function(x) {
|
|
12
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
13
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
14
|
+
});
|
|
15
|
+
function connect(url) {
|
|
16
|
+
return postgres(url, { max: 10, idle_timeout: 20 });
|
|
17
|
+
}
|
|
18
|
+
async function check(sql) {
|
|
19
|
+
try {
|
|
20
|
+
await sql`select 1`;
|
|
21
|
+
} catch (err) {
|
|
22
|
+
throw new Error("Database connection failed");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function tableExists(sql, schema, table) {
|
|
26
|
+
const res = await sql`
|
|
27
|
+
select to_regclass(${schema + "." + table}) is not null as exists
|
|
28
|
+
`;
|
|
29
|
+
if (!res[0]) {
|
|
30
|
+
throw new Error("Failed checking table: " + schema + "." + table);
|
|
31
|
+
}
|
|
32
|
+
return res[0].exists;
|
|
33
|
+
}
|
|
34
|
+
async function validateTables(sql, tables) {
|
|
35
|
+
for (const t of tables) {
|
|
36
|
+
const ok = await tableExists(sql, t.schema, t.table);
|
|
37
|
+
if (!ok) {
|
|
38
|
+
throw new Error("Missing table: " + t.schema + "." + t.table);
|
|
21
39
|
}
|
|
22
|
-
return data;
|
|
23
40
|
}
|
|
41
|
+
}
|
|
42
|
+
async function metadata(sql, schema, table) {
|
|
43
|
+
const cols = await sql`
|
|
44
|
+
select column_name
|
|
45
|
+
from information_schema.columns
|
|
46
|
+
where table_schema = ${schema}
|
|
47
|
+
and table_name = ${table}
|
|
48
|
+
order by ordinal_position
|
|
49
|
+
`;
|
|
50
|
+
return { columns: cols.map((c) => c.column_name) };
|
|
51
|
+
}
|
|
52
|
+
async function insert(sql, schema, table, rows, columns, primaryKeys) {
|
|
53
|
+
if (primaryKeys.length === 0) {
|
|
54
|
+
throw new Error("No primary keys for " + schema + "." + table);
|
|
55
|
+
}
|
|
56
|
+
const q = await sql`
|
|
57
|
+
insert into ${sql(schema + "." + table)}
|
|
58
|
+
${sql(rows, columns)}
|
|
59
|
+
on conflict (${sql(primaryKeys)}) do nothing
|
|
60
|
+
returning ${sql(primaryKeys[0] ?? [])}
|
|
61
|
+
`;
|
|
62
|
+
return q.length;
|
|
63
|
+
}
|
|
64
|
+
function exists(p) {
|
|
65
|
+
return fs.existsSync(p);
|
|
66
|
+
}
|
|
67
|
+
function readFile(p) {
|
|
68
|
+
try {
|
|
69
|
+
return fs.readFileSync(p, "utf8");
|
|
70
|
+
} catch (err) {
|
|
71
|
+
throw new Error("Failed to read file: " + p);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function resolvePath(p) {
|
|
75
|
+
return path2.resolve(process.cwd(), p);
|
|
76
|
+
}
|
|
77
|
+
function loadJsonArray(p, onMissing) {
|
|
78
|
+
if (!exists(p)) {
|
|
79
|
+
if (onMissing === "skip") {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
throw new Error("Source file not found: " + p);
|
|
83
|
+
}
|
|
84
|
+
const raw = readFile(p);
|
|
85
|
+
let parsed;
|
|
86
|
+
try {
|
|
87
|
+
parsed = JSON.parse(raw);
|
|
88
|
+
} catch {
|
|
89
|
+
throw new Error("Invalid JSON: " + p);
|
|
90
|
+
}
|
|
91
|
+
if (!Array.isArray(parsed)) {
|
|
92
|
+
throw new Error("Data is not an array: " + p);
|
|
93
|
+
}
|
|
94
|
+
return parsed;
|
|
95
|
+
}
|
|
96
|
+
function chunk(data, size) {
|
|
97
|
+
const out = [];
|
|
98
|
+
for (let i = 0; i < data.length; i += size) {
|
|
99
|
+
out.push(data.slice(i, i + size));
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/app.ts
|
|
105
|
+
var C = {
|
|
106
|
+
reset: "\x1B[0m",
|
|
107
|
+
green: "\x1B[32m",
|
|
108
|
+
yellow: "\x1B[33m",
|
|
109
|
+
gray: "\x1B[90m"
|
|
24
110
|
};
|
|
25
111
|
var ConfigSchema = v.object({
|
|
26
112
|
seedFileExtensions: v.array(v.picklist([".json"])),
|
|
@@ -35,286 +121,69 @@ var ConfigSchema = v.object({
|
|
|
35
121
|
})
|
|
36
122
|
)
|
|
37
123
|
});
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
} catch (err) {
|
|
46
|
-
throw new Error(`Failed to read file at ${filePath}: ${String(err)}`);
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
getExtension(filePath) {
|
|
50
|
-
return path.extname(filePath).toLowerCase();
|
|
51
|
-
},
|
|
52
|
-
resolvePath(filePath) {
|
|
53
|
-
return path.resolve(process.cwd(), filePath);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// src/config/manager.ts
|
|
58
|
-
var configManager = {
|
|
59
|
-
getConfigPath(opts) {
|
|
60
|
-
const fileName = opts.config || "seed.config.json";
|
|
61
|
-
return fileSystem.resolvePath(fileName);
|
|
62
|
-
},
|
|
63
|
-
load(opts) {
|
|
64
|
-
const configPath = this.getConfigPath(opts);
|
|
65
|
-
if (!fileSystem.exists(configPath)) {
|
|
66
|
-
throw new Error(`Config file not found at ${configPath}`);
|
|
67
|
-
}
|
|
68
|
-
const content = fileSystem.read(configPath);
|
|
69
|
-
const data = parsers.json(content, path.basename(configPath));
|
|
70
|
-
const result = v.safeParse(ConfigSchema, data);
|
|
71
|
-
if (!result.success) {
|
|
72
|
-
const errors = result.issues.map((issue) => `- ${issue.message}`).join("\n");
|
|
73
|
-
throw new Error(`Invalid configuration:
|
|
74
|
-
${errors}`);
|
|
75
|
-
}
|
|
76
|
-
return result.output;
|
|
77
|
-
},
|
|
78
|
-
getDatabaseUrl(opts, config) {
|
|
79
|
-
const varName = opts.dbvar && opts.dbvar.length > 0 ? opts.dbvar : config.databaseUrlEnvVar || "DATABASE_URL";
|
|
80
|
-
const url = process.env[varName];
|
|
81
|
-
if (!url) {
|
|
82
|
-
throw new Error(
|
|
83
|
-
`Database URL environment variable "${varName}" is not set`
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
return url;
|
|
87
|
-
},
|
|
88
|
-
getConfigDir(opts) {
|
|
89
|
-
const configPath = this.getConfigPath(opts);
|
|
90
|
-
return path.dirname(configPath);
|
|
124
|
+
async function run(opts) {
|
|
125
|
+
dotenv.config();
|
|
126
|
+
const configPath = resolvePath(opts.config || "seed.config.json");
|
|
127
|
+
const raw = __require(configPath);
|
|
128
|
+
const parsed = v.safeParse(ConfigSchema, raw);
|
|
129
|
+
if (!parsed.success) {
|
|
130
|
+
throw new Error("Invalid configuration");
|
|
91
131
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
async checkConnection(sql) {
|
|
98
|
-
try {
|
|
99
|
-
await sql`select 1`;
|
|
100
|
-
} catch (err) {
|
|
101
|
-
const msg = err instanceof postgres.PostgresError ? err.message : String(err);
|
|
102
|
-
throw new Error(`Failed to connect to database: ${msg}`);
|
|
103
|
-
}
|
|
132
|
+
const config = parsed.output;
|
|
133
|
+
const dbVar = opts.dbvar && opts.dbvar.length > 0 ? opts.dbvar : config.databaseUrlEnvVar;
|
|
134
|
+
const dbUrl = process.env[dbVar];
|
|
135
|
+
if (!dbUrl) {
|
|
136
|
+
throw new Error("Missing DB env var: " + dbVar);
|
|
104
137
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
},
|
|
126
|
-
async validateTables(sql, tables) {
|
|
127
|
-
const checks = await Promise.all(
|
|
128
|
-
tables.map(async (t) => ({
|
|
129
|
-
table: t.table,
|
|
130
|
-
schema: t.schema,
|
|
131
|
-
exists: await this.tableExists(sql, t.table, t.schema)
|
|
132
|
-
}))
|
|
138
|
+
const sql = connect(dbUrl);
|
|
139
|
+
await check(sql);
|
|
140
|
+
await validateTables(
|
|
141
|
+
sql,
|
|
142
|
+
config.tables.map((t) => ({
|
|
143
|
+
table: t.table,
|
|
144
|
+
schema: t.schema
|
|
145
|
+
}))
|
|
146
|
+
);
|
|
147
|
+
console.log(C.gray + "Starting seed process" + C.reset);
|
|
148
|
+
for (const t of config.tables) {
|
|
149
|
+
const source = path2.resolve(path2.dirname(configPath), t.source);
|
|
150
|
+
const rows = loadJsonArray(source, config.onMissingFile || "error");
|
|
151
|
+
if (rows.length === 0) {
|
|
152
|
+
console.log(C.yellow + "Skipped " + t.table + C.reset);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const meta = await metadata(sql, t.schema, t.table);
|
|
156
|
+
const validCols = Object.keys(rows[0]).filter(
|
|
157
|
+
(c) => meta.columns.includes(c)
|
|
133
158
|
);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
select column_name
|
|
144
|
-
from information_schema.columns
|
|
145
|
-
where table_schema = ${schemaName}
|
|
146
|
-
and table_name = ${tableName}
|
|
147
|
-
order by ordinal_position
|
|
148
|
-
`;
|
|
149
|
-
const primaryKeys = await sql`
|
|
150
|
-
select a.attname as column_name
|
|
151
|
-
from pg_index i
|
|
152
|
-
join pg_attribute a on a.attrelid = i.indrelid and a.attnum = any(i.indkey)
|
|
153
|
-
join pg_class c on c.oid = i.indrelid
|
|
154
|
-
join pg_namespace n on n.oid = c.relnamespace
|
|
155
|
-
where n.nspname = ${schemaName}
|
|
156
|
-
and c.relname = ${tableName}
|
|
157
|
-
and i.indisprimary
|
|
158
|
-
`;
|
|
159
|
-
return {
|
|
160
|
-
columns: columns.map((c) => c.column_name),
|
|
161
|
-
primaryKeys: primaryKeys.map((pk) => pk.column_name)
|
|
162
|
-
};
|
|
163
|
-
} catch (err) {
|
|
164
|
-
throw new Error(
|
|
165
|
-
`Failed to get metadata for table ${schemaName}.${tableName}: ${String(err)}`
|
|
159
|
+
let inserted = 0;
|
|
160
|
+
for (const part of chunk(rows, 1e3)) {
|
|
161
|
+
inserted += await insert(
|
|
162
|
+
sql,
|
|
163
|
+
t.schema,
|
|
164
|
+
t.table,
|
|
165
|
+
part,
|
|
166
|
+
validCols,
|
|
167
|
+
t.primaryKeys
|
|
166
168
|
);
|
|
167
169
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (primaryKeys.length === 0) {
|
|
171
|
-
throw new Error(
|
|
172
|
-
`Table ${schemaName}.${tableName} has no primary keys defined`
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
const qualifiedTable = `${schemaName}.${tableName}`;
|
|
176
|
-
const result = await sql`
|
|
177
|
-
INSERT INTO ${sql(qualifiedTable)} ${sql(data, columns)}
|
|
178
|
-
ON CONFLICT (${sql(primaryKeys)}) DO NOTHING
|
|
179
|
-
RETURNING ${sql(primaryKeys[0] || [])}
|
|
180
|
-
`;
|
|
181
|
-
return result.length;
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
var dataLoader = {
|
|
185
|
-
load(sourcePath, config, configDir) {
|
|
186
|
-
const fullPath = path.isAbsolute(sourcePath) ? sourcePath : path.resolve(configDir, sourcePath);
|
|
187
|
-
if (!fileSystem.exists(fullPath)) {
|
|
188
|
-
const onMissingFile = config.onMissingFile || "error";
|
|
189
|
-
if (onMissingFile === "skip") {
|
|
190
|
-
console.warn(`Warning: Source file not found at ${fullPath}. Skipping.`);
|
|
191
|
-
return [];
|
|
192
|
-
} else {
|
|
193
|
-
throw new Error(`Source file not found at ${fullPath}`);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
const content = fileSystem.read(fullPath);
|
|
197
|
-
const ext = fileSystem.getExtension(fullPath);
|
|
198
|
-
if (ext === ".json") {
|
|
199
|
-
const data = parsers.json(content, sourcePath);
|
|
200
|
-
return parsers.validateArray(data, sourcePath);
|
|
201
|
-
}
|
|
202
|
-
throw new Error(`Unsupported file extension: ${ext}`);
|
|
203
|
-
},
|
|
204
|
-
chunkData(data, chunkSize) {
|
|
205
|
-
const chunks = [];
|
|
206
|
-
for (let i = 0; i < data.length; i += chunkSize) {
|
|
207
|
-
chunks.push(data.slice(i, i + chunkSize));
|
|
208
|
-
}
|
|
209
|
-
return chunks;
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
// src/services/seeder.ts
|
|
214
|
-
var seeder = {
|
|
215
|
-
async seedTable(sql, tableConfig, config, configDir) {
|
|
216
|
-
const data = dataLoader.load(tableConfig.source, config, configDir);
|
|
217
|
-
if (data.length === 0) {
|
|
218
|
-
return {
|
|
219
|
-
table: tableConfig.table,
|
|
220
|
-
schema: tableConfig.schema,
|
|
221
|
-
totalRecords: 0,
|
|
222
|
-
insertedRecords: 0
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
const metadata = await databaseOperations.getTableMetadata(
|
|
226
|
-
sql,
|
|
227
|
-
tableConfig.table,
|
|
228
|
-
tableConfig.schema
|
|
170
|
+
console.log(
|
|
171
|
+
C.green + t.schema + "." + t.table + ": " + inserted + "/" + rows.length + C.reset
|
|
229
172
|
);
|
|
230
|
-
const dataColumns = Object.keys(data[0] || {});
|
|
231
|
-
const validColumns = dataColumns.filter(
|
|
232
|
-
(col) => metadata.columns.includes(col)
|
|
233
|
-
);
|
|
234
|
-
if (validColumns.length === 0) {
|
|
235
|
-
throw new Error(
|
|
236
|
-
`No valid columns found in data for table ${tableConfig.schema}.${tableConfig.table}`
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
const chunks = dataLoader.chunkData(data, 1e3);
|
|
240
|
-
let insertedCount = 0;
|
|
241
|
-
for (const chunk of chunks) {
|
|
242
|
-
try {
|
|
243
|
-
const inserted = await databaseOperations.insertData(
|
|
244
|
-
sql,
|
|
245
|
-
tableConfig.table,
|
|
246
|
-
tableConfig.schema,
|
|
247
|
-
chunk,
|
|
248
|
-
validColumns,
|
|
249
|
-
tableConfig.primaryKeys
|
|
250
|
-
);
|
|
251
|
-
insertedCount += inserted;
|
|
252
|
-
} catch (err) {
|
|
253
|
-
const msg = err instanceof postgres.PostgresError ? err.message : String(err);
|
|
254
|
-
throw new Error(
|
|
255
|
-
`Failed to insert data into ${tableConfig.schema}.${tableConfig.table}: ${msg}`
|
|
256
|
-
);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
return {
|
|
260
|
-
table: tableConfig.table,
|
|
261
|
-
schema: tableConfig.schema,
|
|
262
|
-
totalRecords: data.length,
|
|
263
|
-
insertedRecords: insertedCount
|
|
264
|
-
};
|
|
265
|
-
},
|
|
266
|
-
async execute(config, sql, configDir) {
|
|
267
|
-
const tables = config.tables.map((t) => ({
|
|
268
|
-
table: t.table,
|
|
269
|
-
schema: t.schema
|
|
270
|
-
}));
|
|
271
|
-
await databaseOperations.validateTables(sql, tables);
|
|
272
|
-
console.log("Starting seed process.");
|
|
273
|
-
for (const tableConfig of config.tables) {
|
|
274
|
-
try {
|
|
275
|
-
const result = await this.seedTable(sql, tableConfig, config, configDir);
|
|
276
|
-
if (result.totalRecords === 0) {
|
|
277
|
-
console.log(
|
|
278
|
-
`No data to insert for table "${result.schema}.${result.table}"`
|
|
279
|
-
);
|
|
280
|
-
} else {
|
|
281
|
-
console.log(
|
|
282
|
-
`Table "${result.schema}.${result.table}": Processed ${result.totalRecords} records, inserted ${result.insertedRecords} new rows.`
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
} catch (err) {
|
|
286
|
-
throw new Error(
|
|
287
|
-
`Failed to seed table "${tableConfig.schema}.${tableConfig.table}": ${String(err)}`
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
console.log("Seed process completed.");
|
|
292
173
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
var application = {
|
|
297
|
-
async run(opts) {
|
|
298
|
-
try {
|
|
299
|
-
const config = configManager.load(opts);
|
|
300
|
-
const configDir = configManager.getConfigDir(opts);
|
|
301
|
-
const dbUrl = configManager.getDatabaseUrl(opts, config);
|
|
302
|
-
const sql = databaseConnection.create(dbUrl);
|
|
303
|
-
await databaseConnection.checkConnection(sql);
|
|
304
|
-
await seeder.execute(config, sql, configDir);
|
|
305
|
-
await sql.end();
|
|
306
|
-
} catch (err) {
|
|
307
|
-
console.error(String(err));
|
|
308
|
-
process.exit(1);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
};
|
|
174
|
+
await sql.end();
|
|
175
|
+
console.log(C.green + "Seed completed" + C.reset);
|
|
176
|
+
}
|
|
312
177
|
|
|
313
178
|
// src/cli.ts
|
|
314
179
|
var prog = sade("greenseed");
|
|
315
|
-
prog.command("push").option("-c, --config <file>", "
|
|
316
|
-
|
|
317
|
-
|
|
180
|
+
prog.command("push").option("-c, --config <file>", "Config file", "seed.config.json").option("-d, --dbvar <name>", "DB env var override").action(async (opts) => {
|
|
181
|
+
try {
|
|
182
|
+
await run(opts);
|
|
183
|
+
} catch (err) {
|
|
184
|
+
console.error("\x1B[31m" + String(err) + "\x1B[0m");
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
318
187
|
});
|
|
319
188
|
prog.parse(process.argv);
|
|
320
189
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/parsers/index.ts","../src/types/index.ts","../src/utils/file-system.ts","../src/config/manager.ts","../src/core/database/connection.ts","../src/core/database/operations.ts","../src/core/loaders/data-loader.ts","../src/services/seeder.ts","../src/services/application.ts","../src/cli.ts"],"names":["path","v2","postgres"],"mappings":"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","file":"cli.js","sourcesContent":["export const parsers = {\n\tjson(content: string, fileName: string): unknown {\n\t\ttry {\n\t\t\treturn JSON.parse(content)\n\t\t} catch (err) {\n\t\t\tthrow new Error(`Invalid JSON in ${fileName}: ${String(err)}`)\n\t\t}\n\t},\n\n\tvalidateArray(data: unknown, fileName: string): Record<string, any>[] {\n\t\tif (!Array.isArray(data)) {\n\t\t\tthrow new Error(`Data in ${fileName} is not an array`)\n\t\t}\n\t\treturn data as Record<string, any>[]\n\t},\n}\n","import * as v from \"valibot\"\n\nexport const ConfigSchema = v.object({\n\tseedFileExtensions: v.array(v.picklist([\".json\"])),\n\tdatabaseUrlEnvVar: v.string(),\n\tonMissingFile: v.optional(v.picklist([\"skip\", \"error\"]), \"error\"),\n\ttables: v.array(\n\t\tv.object({\n\t\t\ttable: v.string(),\n\t\t\tschema: v.optional(v.string(), \"public\"),\n\t\t\tprimaryKeys: v.array(v.string()),\n\t\t\tsource: v.string(),\n\t\t}),\n\t),\n})\n\nexport type Config = v.InferOutput<typeof ConfigSchema>\n\nexport type TableConfig = {\n\ttable: string\n\tschema: string\n\tprimaryKeys: string[]\n\tsource: string\n}\n\nexport type TableMetadata = {\n\tcolumns: string[]\n\tprimaryKeys: string[]\n}\n\nexport type SeedResult = {\n\ttable: string\n\tschema: string\n\ttotalRecords: number\n\tinsertedRecords: number\n}\n\nexport type Opts = {\n\tconfig: string\n\tdbvar?: string\n}\n","import fs from \"fs\"\nimport path from \"path\"\n\nexport const fileSystem = {\n\texists(filePath: string): boolean {\n\t\treturn fs.existsSync(filePath)\n\t},\n\n\tread(filePath: string): string {\n\t\ttry {\n\t\t\treturn fs.readFileSync(filePath, \"utf8\")\n\t\t} catch (err) {\n\t\t\tthrow new Error(`Failed to read file at ${filePath}: ${String(err)}`)\n\t\t}\n\t},\n\n\tgetExtension(filePath: string): string {\n\t\treturn path.extname(filePath).toLowerCase()\n\t},\n\n\tresolvePath(filePath: string): string {\n\t\treturn path.resolve(process.cwd(), filePath)\n\t},\n}\n","import path from \"path\"\nimport * as v from \"valibot\"\nimport { parsers } from \"../core/parsers\"\nimport type { Config, Opts } from \"../types\"\nimport { ConfigSchema } from \"../types\"\nimport { fileSystem } from \"../utils/file-system\"\n\nexport const configManager = {\n\tgetConfigPath(opts: Opts): string {\n\t\tconst fileName = opts.config || \"seed.config.json\"\n\t\treturn fileSystem.resolvePath(fileName)\n\t},\n\n\tload(opts: Opts): Config {\n\t\tconst configPath = this.getConfigPath(opts)\n\n\t\tif (!fileSystem.exists(configPath)) {\n\t\t\tthrow new Error(`Config file not found at ${configPath}`)\n\t\t}\n\n\t\tconst content = fileSystem.read(configPath)\n\t\tconst data = parsers.json(content, path.basename(configPath))\n\t\tconst result = v.safeParse(ConfigSchema, data)\n\n\t\tif (!result.success) {\n\t\t\tconst errors = result.issues\n\t\t\t\t.map((issue) => `- ${issue.message}`)\n\t\t\t\t.join(\"\\n\")\n\t\t\tthrow new Error(`Invalid configuration:\\n${errors}`)\n\t\t}\n\n\t\treturn result.output\n\t},\n\n\tgetDatabaseUrl(opts: Opts, config: Config): string {\n\t\tconst varName =\n\t\t\topts.dbvar && opts.dbvar.length > 0\n\t\t\t\t? opts.dbvar\n\t\t\t\t: config.databaseUrlEnvVar || \"DATABASE_URL\"\n\n\t\tconst url = process.env[varName]\n\t\tif (!url) {\n\t\t\tthrow new Error(\n\t\t\t\t`Database URL environment variable \"${varName}\" is not set`,\n\t\t\t)\n\t\t}\n\t\treturn url\n\t},\n\n\tgetConfigDir(opts: Opts): string {\n\t\tconst configPath = this.getConfigPath(opts)\n\t\treturn path.dirname(configPath)\n\t},\n}\n","import postgres from \"postgres\"\n\nexport const databaseConnection = {\n\tcreate(url: string): postgres.Sql {\n\t\treturn postgres(url, { max: 10, idle_timeout: 20 })\n\t},\n\n\tasync checkConnection(sql: postgres.Sql): Promise<void> {\n\t\ttry {\n\t\t\tawait sql`select 1`\n\t\t} catch (err) {\n\t\t\tconst msg =\n\t\t\t\terr instanceof postgres.PostgresError ? err.message : String(err)\n\t\t\tthrow new Error(`Failed to connect to database: ${msg}`)\n\t\t}\n\t},\n}\n","import postgres from \"postgres\"\nimport type { TableMetadata } from \"../../types\"\n\nexport const databaseOperations = {\n\tasync tableExists(\n\t\tsql: postgres.Sql,\n\t\ttableName: string,\n\t\tschemaName: string,\n\t): Promise<boolean> {\n\t\ttry {\n\t\t\tconst [result] = await sql<{ exists: boolean }[]>`\n\t\t\t\tSELECT to_regclass(${schemaName + \".\" + tableName}) IS NOT NULL AS exists\n\t\t\t`\n\n\t\t\tif (!result) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to check existence of table ${schemaName}.${tableName}`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn result.exists\n\t\t} catch (err) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to validate table ${schemaName}.${tableName}: ${String(err)}`,\n\t\t\t)\n\t\t}\n\t},\n\n\tasync validateTables(\n\t\tsql: postgres.Sql,\n\t\ttables: Array<{ table: string; schema: string }>,\n\t): Promise<void> {\n\t\tconst checks = await Promise.all(\n\t\t\ttables.map(async (t) => ({\n\t\t\t\ttable: t.table,\n\t\t\t\tschema: t.schema,\n\t\t\t\texists: await this.tableExists(sql, t.table, t.schema),\n\t\t\t})),\n\t\t)\n\n\t\tconst missing = checks.filter((c) => !c.exists)\n\t\tif (missing.length > 0) {\n\t\t\tconst missingNames = missing\n\t\t\t\t.map((m) => `${m.schema}.${m.table}`)\n\t\t\t\t.join(\", \")\n\t\t\tthrow new Error(`Missing tables: ${missingNames}`)\n\t\t}\n\t},\n\n\tasync getTableMetadata(\n\t\tsql: postgres.Sql,\n\t\ttableName: string,\n\t\tschemaName: string,\n\t): Promise<TableMetadata> {\n\t\ttry {\n\t\t\tconst columns = await sql<{ column_name: string }[]>`\n\t\t\t\tselect column_name\n\t\t\t\tfrom information_schema.columns\n\t\t\t\twhere table_schema = ${schemaName}\n\t\t\t\tand table_name = ${tableName}\n\t\t\t\torder by ordinal_position\n\t\t\t`\n\n\t\t\tconst primaryKeys = await sql<{ column_name: string }[]>`\n\t\t\t\tselect a.attname as column_name\n\t\t\t\tfrom pg_index i\n\t\t\t\tjoin pg_attribute a on a.attrelid = i.indrelid and a.attnum = any(i.indkey)\n\t\t\t\tjoin pg_class c on c.oid = i.indrelid\n\t\t\t\tjoin pg_namespace n on n.oid = c.relnamespace\n\t\t\t\twhere n.nspname = ${schemaName}\n\t\t\t\tand c.relname = ${tableName}\n\t\t\t\tand i.indisprimary\n\t\t\t`\n\n\t\t\treturn {\n\t\t\t\tcolumns: columns.map((c) => c.column_name),\n\t\t\t\tprimaryKeys: primaryKeys.map((pk) => pk.column_name),\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to get metadata for table ${schemaName}.${tableName}: ${String(err)}`,\n\t\t\t)\n\t\t}\n\t},\n\n\tasync insertData(\n\t\tsql: postgres.Sql,\n\t\ttableName: string,\n\t\tschemaName: string,\n\t\tdata: Record<string, any>[],\n\t\tcolumns: string[],\n\t\tprimaryKeys: string[],\n\t): Promise<number> {\n\t\tif (primaryKeys.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Table ${schemaName}.${tableName} has no primary keys defined`,\n\t\t\t)\n\t\t}\n\n\t\tconst qualifiedTable = `${schemaName}.${tableName}`\n\t\tconst result = await sql`\n\t\t\tINSERT INTO ${sql(qualifiedTable)} ${sql(data, columns)}\n\t\t\tON CONFLICT (${sql(primaryKeys)}) DO NOTHING\n\t\t\tRETURNING ${sql(primaryKeys[0] || [])}\n\t\t`\n\n\t\treturn result.length\n\t},\n}\n","import path from \"path\"\nimport type { Config } from \"../../types\"\nimport { fileSystem } from \"../../utils/file-system\"\nimport { parsers } from \"../parsers\"\n\nexport const dataLoader = {\n\tload(\n\t\tsourcePath: string,\n\t\tconfig: Config,\n\t\tconfigDir: string,\n\t): Record<string, any>[] {\n\t\tconst fullPath = path.isAbsolute(sourcePath)\n\t\t\t? sourcePath\n\t\t\t: path.resolve(configDir, sourcePath)\n\n\t\tif (!fileSystem.exists(fullPath)) {\n\t\t\tconst onMissingFile = config.onMissingFile || \"error\"\n\n\t\t\tif (onMissingFile === \"skip\") {\n\t\t\t\tconsole.warn(`Warning: Source file not found at ${fullPath}. Skipping.`)\n\t\t\t\treturn []\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Source file not found at ${fullPath}`)\n\t\t\t}\n\t\t}\n\n\t\tconst content = fileSystem.read(fullPath)\n\t\tconst ext = fileSystem.getExtension(fullPath)\n\n\t\tif (ext === \".json\") {\n\t\t\tconst data = parsers.json(content, sourcePath)\n\t\t\treturn parsers.validateArray(data, sourcePath)\n\t\t}\n\n\t\tthrow new Error(`Unsupported file extension: ${ext}`)\n\t},\n\n\tchunkData<T>(data: T[], chunkSize: number): T[][] {\n\t\tconst chunks: T[][] = []\n\t\tfor (let i = 0; i < data.length; i += chunkSize) {\n\t\t\tchunks.push(data.slice(i, i + chunkSize))\n\t\t}\n\t\treturn chunks\n\t},\n}\n","import postgres from \"postgres\"\nimport { databaseOperations } from \"../core/database/operations\"\nimport { dataLoader } from \"../core/loaders/data-loader\"\nimport type { Config, SeedResult, TableConfig } from \"../types\"\n\nexport const seeder = {\n\tasync seedTable(\n\t\tsql: postgres.Sql,\n\t\ttableConfig: TableConfig,\n\t\tconfig: Config,\n\t\tconfigDir: string,\n\t): Promise<SeedResult> {\n\t\tconst data = dataLoader.load(tableConfig.source, config, configDir)\n\n\t\tif (data.length === 0) {\n\t\t\treturn {\n\t\t\t\ttable: tableConfig.table,\n\t\t\t\tschema: tableConfig.schema,\n\t\t\t\ttotalRecords: 0,\n\t\t\t\tinsertedRecords: 0,\n\t\t\t}\n\t\t}\n\n\t\tconst metadata = await databaseOperations.getTableMetadata(\n\t\t\tsql,\n\t\t\ttableConfig.table,\n\t\t\ttableConfig.schema,\n\t\t)\n\n\t\tconst dataColumns = Object.keys(data[0] || {})\n\t\tconst validColumns = dataColumns.filter((col) =>\n\t\t\tmetadata.columns.includes(col),\n\t\t)\n\n\t\tif (validColumns.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`No valid columns found in data for table ${tableConfig.schema}.${tableConfig.table}`,\n\t\t\t)\n\t\t}\n\n\t\tconst chunks = dataLoader.chunkData(data, 1000)\n\t\tlet insertedCount = 0\n\n\t\tfor (const chunk of chunks) {\n\t\t\ttry {\n\t\t\t\tconst inserted = await databaseOperations.insertData(\n\t\t\t\t\tsql,\n\t\t\t\t\ttableConfig.table,\n\t\t\t\t\ttableConfig.schema,\n\t\t\t\t\tchunk,\n\t\t\t\t\tvalidColumns,\n\t\t\t\t\ttableConfig.primaryKeys,\n\t\t\t\t)\n\t\t\t\tinsertedCount += inserted\n\t\t\t} catch (err) {\n\t\t\t\tconst msg =\n\t\t\t\t\terr instanceof postgres.PostgresError ? err.message : String(err)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to insert data into ${tableConfig.schema}.${tableConfig.table}: ${msg}`,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\ttable: tableConfig.table,\n\t\t\tschema: tableConfig.schema,\n\t\t\ttotalRecords: data.length,\n\t\t\tinsertedRecords: insertedCount,\n\t\t}\n\t},\n\n\tasync execute(\n\t\tconfig: Config,\n\t\tsql: postgres.Sql,\n\t\tconfigDir: string,\n\t): Promise<void> {\n\t\tconst tables = config.tables.map((t) => ({\n\t\t\ttable: t.table,\n\t\t\tschema: t.schema,\n\t\t}))\n\t\tawait databaseOperations.validateTables(sql, tables)\n\n\t\tconsole.log(\"Starting seed process.\")\n\n\t\tfor (const tableConfig of config.tables) {\n\t\t\ttry {\n\t\t\t\tconst result = await this.seedTable(sql, tableConfig, config, configDir)\n\n\t\t\t\tif (result.totalRecords === 0) {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`No data to insert for table \"${result.schema}.${result.table}\"`,\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`Table \"${result.schema}.${result.table}\": Processed ${result.totalRecords} records, inserted ${result.insertedRecords} new rows.`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to seed table \"${tableConfig.schema}.${tableConfig.table}\": ${String(err)}`,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tconsole.log(\"Seed process completed.\")\n\t},\n}\n","import { configManager } from \"../config/manager\"\nimport { databaseConnection } from \"../core/database\"\nimport type { Opts } from \"../types\"\nimport { seeder } from \"./seeder\"\n\nexport const application = {\n\tasync run(opts: Opts): Promise<void> {\n\t\ttry {\n\t\t\tconst config = configManager.load(opts)\n\t\t\tconst configDir = configManager.getConfigDir(opts)\n\t\t\tconst dbUrl = configManager.getDatabaseUrl(opts, config)\n\t\t\tconst sql = databaseConnection.create(dbUrl)\n\n\t\t\tawait databaseConnection.checkConnection(sql)\n\t\t\tawait seeder.execute(config, sql, configDir)\n\t\t\tawait sql.end()\n\t\t} catch (err) {\n\t\t\tconsole.error(String(err))\n\t\t\tprocess.exit(1)\n\t\t}\n\t},\n}\n","#!/usr/bin/env node\nimport dotenv from \"dotenv\"\nimport sade from \"sade\"\nimport { application } from \"./services/application\"\nimport type { Opts } from \"./types\"\n\nconst prog = sade(\"greenseed\")\n\nprog\n\t.command(\"push\")\n\t.option(\"-c, --config <file>\", \"Path to config file\", \"seed.config.json\")\n\t.option(\"-d, --dbvar <name>\", \"Database URL env var name (overrides config)\")\n\t.action(async (opts: Opts) => {\n\t\tdotenv.config()\n\t\tawait application.run(opts)\n\t})\n\nprog.parse(process.argv)\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/db.ts","../src/fs.ts","../src/app.ts","../src/cli.ts"],"names":["path"],"mappings":"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","file":"cli.js","sourcesContent":["import postgres from \"postgres\"\n\nexport function connect(url: string): postgres.Sql {\n\treturn postgres(url, { max: 10, idle_timeout: 20 })\n}\n\nexport async function check(sql: postgres.Sql): Promise<void> {\n\ttry {\n\t\tawait sql`select 1`\n\t} catch (err) {\n\t\tthrow new Error(\"Database connection failed\")\n\t}\n}\n\nexport async function tableExists(\n\tsql: postgres.Sql,\n\tschema: string,\n\ttable: string,\n): Promise<boolean> {\n\tconst res = await sql<{ exists: boolean }[]>`\n\t\tselect to_regclass(${schema + \".\" + table}) is not null as exists\n\t`\n\tif (!res[0]) {\n\t\tthrow new Error(\"Failed checking table: \" + schema + \".\" + table)\n\t}\n\treturn res[0].exists\n}\n\nexport async function validateTables(\n\tsql: postgres.Sql,\n\ttables: { schema: string; table: string }[],\n): Promise<void> {\n\tfor (const t of tables) {\n\t\tconst ok = await tableExists(sql, t.schema, t.table)\n\t\tif (!ok) {\n\t\t\tthrow new Error(\"Missing table: \" + t.schema + \".\" + t.table)\n\t\t}\n\t}\n}\n\nexport async function metadata(\n\tsql: postgres.Sql,\n\tschema: string,\n\ttable: string,\n): Promise<{ columns: string[] }> {\n\tconst cols = await sql<{ column_name: string }[]>`\n\t\tselect column_name\n\t\tfrom information_schema.columns\n\t\twhere table_schema = ${schema}\n\t\tand table_name = ${table}\n\t\torder by ordinal_position\n\t`\n\treturn { columns: cols.map(c => c.column_name) }\n}\n\nexport async function insert(\n\tsql: postgres.Sql,\n\tschema: string,\n\ttable: string,\n\trows: Record<string, any>[],\n\tcolumns: string[],\n\tprimaryKeys: string[],\n): Promise<number> {\n\tif (primaryKeys.length === 0) {\n\t\tthrow new Error(\"No primary keys for \" + schema + \".\" + table)\n\t}\n\n\tconst q = await sql`\n\t\tinsert into ${sql(schema + \".\" + table)}\n\t\t${sql(rows, columns)}\n\t\ton conflict (${sql(primaryKeys)}) do nothing\n\t\treturning ${sql(primaryKeys[0] ?? [])}\n\t`\n\treturn q.length\n}\n","import fs from \"fs\"\nimport path from \"path\"\n\nexport function exists(p: string): boolean {\n\treturn fs.existsSync(p)\n}\n\nexport function readFile(p: string): string {\n\ttry {\n\t\treturn fs.readFileSync(p, \"utf8\")\n\t} catch (err) {\n\t\tthrow new Error(\"Failed to read file: \" + p)\n\t}\n}\n\nexport function resolvePath(p: string): string {\n\treturn path.resolve(process.cwd(), p)\n}\n\nexport function ext(p: string): string {\n\treturn path.extname(p).toLowerCase()\n}\n\nexport function loadJsonArray(p: string, onMissing: \"skip\" | \"error\"): any[] {\n\tif (!exists(p)) {\n\t\tif (onMissing === \"skip\") {\n\t\t\treturn []\n\t\t}\n\t\tthrow new Error(\"Source file not found: \" + p)\n\t}\n\n\tconst raw = readFile(p)\n\n\tlet parsed: unknown\n\ttry {\n\t\tparsed = JSON.parse(raw)\n\t} catch {\n\t\tthrow new Error(\"Invalid JSON: \" + p)\n\t}\n\n\tif (!Array.isArray(parsed)) {\n\t\tthrow new Error(\"Data is not an array: \" + p)\n\t}\n\n\treturn parsed\n}\n\nexport function chunk<T>(data: T[], size: number): T[][] {\n\tconst out: T[][] = []\n\tfor (let i = 0; i < data.length; i += size) {\n\t\tout.push(data.slice(i, i + size))\n\t}\n\treturn out\n}\n","import * as v from \"valibot\"\nimport dotenv from \"dotenv\"\nimport path from \"path\"\nimport { connect, check, validateTables, metadata, insert } from \"./db\"\nimport { resolvePath, loadJsonArray, chunk } from \"./fs\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tgreen: \"\\x1b[32m\",\n\tyellow: \"\\x1b[33m\",\n\tred: \"\\x1b[31m\",\n\tgray: \"\\x1b[90m\",\n}\n\nconst ConfigSchema = v.object({\n\tseedFileExtensions: v.array(v.picklist([\".json\"])),\n\tdatabaseUrlEnvVar: v.string(),\n\tonMissingFile: v.optional(v.picklist([\"skip\", \"error\"]), \"error\"),\n\ttables: v.array(\n\t\tv.object({\n\t\t\ttable: v.string(),\n\t\t\tschema: v.optional(v.string(), \"public\"),\n\t\t\tprimaryKeys: v.array(v.string()),\n\t\t\tsource: v.string(),\n\t\t}),\n\t),\n})\n\ntype Opts = { config: string; dbvar?: string }\n\nexport async function run(opts: Opts): Promise<void> {\n\tdotenv.config()\n\n\tconst configPath = resolvePath(opts.config || \"seed.config.json\")\n\tconst raw = require(configPath)\n\tconst parsed = v.safeParse(ConfigSchema, raw)\n\n\tif (!parsed.success) {\n\t\tthrow new Error(\"Invalid configuration\")\n\t}\n\n\tconst config = parsed.output\n\tconst dbVar =\n\t\topts.dbvar && opts.dbvar.length > 0\n\t\t\t? opts.dbvar\n\t\t\t: config.databaseUrlEnvVar\n\n\tconst dbUrl = process.env[dbVar]\n\tif (!dbUrl) {\n\t\tthrow new Error(\"Missing DB env var: \" + dbVar)\n\t}\n\n\tconst sql = connect(dbUrl)\n\tawait check(sql)\n\n\tawait validateTables(\n\t\tsql,\n\t\tconfig.tables.map(t => ({\n\t\t\ttable: t.table,\n\t\t\tschema: t.schema,\n\t\t})),\n\t)\n\n\tconsole.log(C.gray + \"Starting seed process\" + C.reset)\n\n\tfor (const t of config.tables) {\n\t\tconst source = path.resolve(path.dirname(configPath), t.source)\n\t\tconst rows = loadJsonArray(source, config.onMissingFile || \"error\")\n\n\t\tif (rows.length === 0) {\n\t\t\tconsole.log(C.yellow + \"Skipped \" + t.table + C.reset)\n\t\t\tcontinue\n\t\t}\n\n\t\tconst meta = await metadata(sql, t.schema, t.table)\n\t\tconst validCols = Object.keys(rows[0]).filter(c =>\n\t\t\tmeta.columns.includes(c),\n\t\t)\n\n\t\tlet inserted = 0\n\t\tfor (const part of chunk(rows, 1000)) {\n\t\t\tinserted += await insert(\n\t\t\t\tsql,\n\t\t\t\tt.schema,\n\t\t\t\tt.table,\n\t\t\t\tpart,\n\t\t\t\tvalidCols,\n\t\t\t\tt.primaryKeys,\n\t\t\t)\n\t\t}\n\n\t\tconsole.log(\n\t\t\tC.green +\n\t\t\t\tt.schema +\n\t\t\t\t\".\" +\n\t\t\t\tt.table +\n\t\t\t\t\": \" +\n\t\t\t\tinserted +\n\t\t\t\t\"/\" +\n\t\t\t\trows.length +\n\t\t\t\tC.reset,\n\t\t)\n\t}\n\n\tawait sql.end()\n\tconsole.log(C.green + \"Seed completed\" + C.reset)\n}\n","#!/usr/bin/env node\nimport sade from \"sade\"\nimport { run } from \"./app\"\n\nconst prog = sade(\"greenseed\")\n\nprog\n\t.command(\"push\")\n\t.option(\"-c, --config <file>\", \"Config file\", \"seed.config.json\")\n\t.option(\"-d, --dbvar <name>\", \"DB env var override\")\n\t.action(async opts => {\n\t\ttry {\n\t\t\tawait run(opts)\n\t\t} catch (err) {\n\t\t\tconsole.error(\"\\x1b[31m\" + String(err) + \"\\x1b[0m\")\n\t\t\tprocess.exit(1)\n\t\t}\n\t})\n\nprog.parse(process.argv)\n"]}
|