greenseed 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -35,6 +35,12 @@ var path2__default = /*#__PURE__*/_interopDefault(path2);
35
35
  var postgres__default = /*#__PURE__*/_interopDefault(postgres);
36
36
  var fs__default = /*#__PURE__*/_interopDefault(fs);
37
37
 
38
+ var C = {
39
+ reset: "\x1B[0m",
40
+ dim: "\x1B[2m",
41
+ red: "\x1B[31m"
42
+ };
43
+ var logError = (msg) => console.error(`${C.red}\u2717${C.reset} ${C.dim}${msg}${C.reset}`);
38
44
  function connect(url) {
39
45
  return postgres__default.default(url, { max: 10, idle_timeout: 20 });
40
46
  }
@@ -42,7 +48,8 @@ async function check(sql) {
42
48
  try {
43
49
  await sql`select 1`;
44
50
  } catch (err) {
45
- throw new Error("Database connection failed");
51
+ logError("Database connection failed");
52
+ throw new Error("Failed to connect to database");
46
53
  }
47
54
  }
48
55
  async function tableExists(sql, schema, table) {
@@ -50,7 +57,8 @@ async function tableExists(sql, schema, table) {
50
57
  select to_regclass(${'"' + schema + '"."' + table + '"'}) is not null as exists
51
58
  `;
52
59
  if (!res[0]) {
53
- throw new Error("Failed checking table: " + schema + "." + table);
60
+ logError(`Failed to check table: ${schema}.${table}`);
61
+ throw new Error(`Table check failed: ${schema}.${table}`);
54
62
  }
55
63
  return res[0].exists;
56
64
  }
@@ -58,7 +66,8 @@ async function validateTables(sql, tables) {
58
66
  for (const t of tables) {
59
67
  const ok = await tableExists(sql, t.schema, t.table);
60
68
  if (!ok) {
61
- throw new Error("Missing table: " + t.schema + "." + t.table);
69
+ logError(`Table does not exist: ${t.schema}.${t.table}`);
70
+ throw new Error(`Missing table: ${t.schema}.${t.table}`);
62
71
  }
63
72
  }
64
73
  }
@@ -72,18 +81,42 @@ async function metadata(sql, schema, table) {
72
81
  `;
73
82
  return { columns: cols.map((c) => c.column_name) };
74
83
  }
75
- async function insert(sql, schema, table, rows, columns, primaryKeys) {
84
+ async function insert(sql, schema, table, rows, columns, primaryKeys, updateOnConflict) {
76
85
  if (primaryKeys.length === 0) {
77
- throw new Error("No primary keys for " + schema + "." + table);
86
+ logError(`No primary keys defined for ${schema}.${table}`);
87
+ throw new Error(`No primary keys for ${schema}.${table}`);
88
+ }
89
+ const updateCols = updateOnConflict.filter(
90
+ (col) => !primaryKeys.includes(col)
91
+ );
92
+ let q;
93
+ if (updateCols.length > 0) {
94
+ const updates = Object.fromEntries(
95
+ updateCols.map((col) => [col, sql`excluded.${sql(col)}`])
96
+ );
97
+ q = await sql`
98
+ insert into ${sql(schema + "." + table)}
99
+ ${sql(rows, columns)}
100
+ on conflict (${sql(primaryKeys)}) do update set
101
+ ${sql(updates)}
102
+ returning ${sql(primaryKeys[0] ?? [])}
103
+ `;
104
+ } else {
105
+ q = await sql`
106
+ insert into ${sql(schema + "." + table)}
107
+ ${sql(rows, columns)}
108
+ on conflict (${sql(primaryKeys)}) do nothing
109
+ returning ${sql(primaryKeys[0] ?? [])}
110
+ `;
78
111
  }
79
- const q = await sql`
80
- insert into ${sql(schema + "." + table)}
81
- ${sql(rows, columns)}
82
- on conflict (${sql(primaryKeys)}) do nothing
83
- returning ${sql(primaryKeys[0] ?? [])}
84
- `;
85
112
  return q.length;
86
113
  }
114
+ var C2 = {
115
+ reset: "\x1B[0m",
116
+ dim: "\x1B[2m",
117
+ red: "\x1B[31m"
118
+ };
119
+ var logError2 = (msg) => console.error(`${C2.red}\u2717${C2.reset} ${C2.dim}${msg}${C2.reset}`);
87
120
  function exists(p) {
88
121
  return fs__default.default.existsSync(p);
89
122
  }
@@ -91,7 +124,8 @@ function readFile(p) {
91
124
  try {
92
125
  return fs__default.default.readFileSync(p, "utf8");
93
126
  } catch (err) {
94
- throw new Error("Failed to read file: " + p);
127
+ logError2(`Failed to read file: ${p}`);
128
+ throw new Error(`File read error: ${p}`);
95
129
  }
96
130
  }
97
131
  function resolvePath(p) {
@@ -102,17 +136,20 @@ function loadJsonArray(p, onMissing) {
102
136
  if (onMissing === "skip") {
103
137
  return [];
104
138
  }
105
- throw new Error("Source file not found: " + p);
139
+ logError2(`Source file not found: ${p}`);
140
+ throw new Error(`Missing file: ${p}`);
106
141
  }
107
142
  const raw = readFile(p);
108
143
  let parsed;
109
144
  try {
110
145
  parsed = JSON.parse(raw);
111
146
  } catch {
112
- throw new Error("Invalid JSON: " + p);
147
+ logError2(`Invalid JSON in file: ${p}`);
148
+ throw new Error(`JSON parse error: ${p}`);
113
149
  }
114
150
  if (!Array.isArray(parsed)) {
115
- throw new Error("Data is not an array: " + p);
151
+ logError2(`Expected array but got ${typeof parsed}: ${p}`);
152
+ throw new Error(`Invalid data format: ${p}`);
116
153
  }
117
154
  return parsed;
118
155
  }
@@ -125,11 +162,33 @@ function chunk(data, size) {
125
162
  }
126
163
 
127
164
  // src/app.ts
128
- var C = {
165
+ var C3 = {
129
166
  reset: "\x1B[0m",
167
+ bold: "\x1B[1m",
168
+ dim: "\x1B[2m",
130
169
  green: "\x1B[32m",
131
170
  yellow: "\x1B[33m",
132
- gray: "\x1B[90m"
171
+ blue: "\x1B[34m",
172
+ cyan: "\x1B[36m",
173
+ red: "\x1B[31m"};
174
+ var log = {
175
+ info: (msg) => console.log(`${C3.blue}\u2139${C3.reset} ${msg}`),
176
+ success: (msg) => console.log(`${C3.green}\u2713${C3.reset} ${msg}`),
177
+ warn: (msg) => console.log(`${C3.yellow}\u26A0${C3.reset} ${msg}`),
178
+ error: (msg) => console.log(`${C3.red}\u2717${C3.reset} ${msg}`),
179
+ dim: (msg) => console.log(`${C3.dim}${msg}${C3.reset}`),
180
+ header: (msg) => console.log(`
181
+ ${C3.bold}${C3.cyan}${msg}${C3.reset}
182
+ `),
183
+ table: (label, value) => console.log(` ${C3.dim}${label}:${C3.reset} ${C3.bold}${value}${C3.reset}`),
184
+ progress: (current, total, label) => {
185
+ const percentage = Math.round(current / total * 100);
186
+ const bar = "\u2588".repeat(Math.floor(percentage / 5));
187
+ const empty = "\u2591".repeat(20 - Math.floor(percentage / 5));
188
+ console.log(
189
+ ` ${C3.cyan}${bar}${empty}${C3.reset} ${C3.bold}${percentage}%${C3.reset} ${C3.dim}(${current}/${total})${C3.reset} ${label}`
190
+ );
191
+ }
133
192
  };
134
193
  var ConfigSchema = v__namespace.object({
135
194
  seedFileExtensions: v__namespace.array(v__namespace.picklist([".json"])),
@@ -140,13 +199,15 @@ var ConfigSchema = v__namespace.object({
140
199
  table: v__namespace.string(),
141
200
  schema: v__namespace.optional(v__namespace.string(), "public"),
142
201
  primaryKeys: v__namespace.array(v__namespace.string()),
143
- source: v__namespace.string()
202
+ source: v__namespace.string(),
203
+ updateOnConflict: v__namespace.optional(v__namespace.nullable(v__namespace.array(v__namespace.string())), null)
144
204
  })
145
205
  )
146
206
  });
147
207
  async function run(opts) {
148
208
  dotenv__default.default.config();
149
209
  const configPath = resolvePath(opts.config || "seed.config.json");
210
+ log.header("\u{1F331} GreenSeed");
150
211
  let raw;
151
212
  try {
152
213
  raw = JSON.parse(readFile(configPath));
@@ -165,6 +226,8 @@ async function run(opts) {
165
226
  if (!dbUrl) {
166
227
  throw new Error("Missing DB env var: " + dbVar);
167
228
  }
229
+ log.info(`Using config: ${C3.dim}${configPath}${C3.reset}`);
230
+ log.info(`Database: ${C3.dim}${dbVar}${C3.reset}`);
168
231
  const sql = connect(dbUrl);
169
232
  await check(sql);
170
233
  await validateTables(
@@ -174,18 +237,20 @@ async function run(opts) {
174
237
  schema: t.schema
175
238
  }))
176
239
  );
177
- console.log(C.gray + "Starting seed process" + C.reset);
240
+ log.success("Database connection established");
241
+ log.header("Seeding Tables");
178
242
  for (const t of config.tables) {
179
243
  const source = path2__default.default.resolve(path2__default.default.dirname(configPath), t.source);
180
244
  const rows = loadJsonArray(source, config.onMissingFile || "error");
181
245
  if (rows.length === 0) {
182
- console.log(C.yellow + "Skipped " + t.table + C.reset);
246
+ log.warn(`Skipped ${C3.bold}${t.schema}.${t.table}${C3.reset} (no data)`);
183
247
  continue;
184
248
  }
185
249
  const meta = await metadata(sql, t.schema, t.table);
186
250
  const validCols = Object.keys(rows[0]).filter(
187
251
  (c) => meta.columns.includes(c)
188
252
  );
253
+ log.info(`Seeding ${C3.bold}${t.schema}.${t.table}${C3.reset}`);
189
254
  let inserted = 0;
190
255
  for (const part of chunk(rows, 1e3)) {
191
256
  inserted += await insert(
@@ -194,16 +259,35 @@ async function run(opts) {
194
259
  t.table,
195
260
  part,
196
261
  validCols,
197
- t.primaryKeys
262
+ t.primaryKeys,
263
+ t.updateOnConflict || []
264
+ );
265
+ }
266
+ const hasConflict = t.updateOnConflict && t.updateOnConflict.length > 0;
267
+ const action = hasConflict ? "upserted" : "inserted";
268
+ const skipped = rows.length - inserted;
269
+ if (inserted === rows.length) {
270
+ log.success(
271
+ `${C3.bold}${t.schema}.${t.table}${C3.reset} ${C3.green}${action} ${inserted} rows${C3.reset}`
272
+ );
273
+ } else {
274
+ log.success(
275
+ `${C3.bold}${t.schema}.${t.table}${C3.reset} ${C3.green}${action} ${inserted}${C3.reset}${C3.dim}, skipped ${skipped}${C3.reset}`
198
276
  );
199
277
  }
200
- console.log(
201
- C.green + t.schema + "." + t.table + ": " + inserted + "/" + rows.length + C.reset
202
- );
203
278
  }
204
279
  await sql.end();
205
- console.log(C.green + "Seed completed" + C.reset);
280
+ log.header("Summary");
281
+ log.success(
282
+ `Seeded ${C3.bold}${config.tables.length}${C3.reset} table${config.tables.length === 1 ? "" : "s"}`
283
+ );
206
284
  }
285
+ var C4 = {
286
+ reset: "\x1B[0m",
287
+ dim: "\x1B[2m",
288
+ red: "\x1B[31m"
289
+ };
290
+ var logError3 = (msg) => console.error(`${C4.red}\u2717${C4.reset} ${C4.dim}${msg}${C4.reset}`);
207
291
  var DEFAULT_CONFIG = {
208
292
  seedFileExtensions: [".json"],
209
293
  databaseUrlEnvVar: "DATABASE_URL",
@@ -213,14 +297,16 @@ var DEFAULT_CONFIG = {
213
297
  table: "example_table",
214
298
  schema: "public",
215
299
  primaryKeys: ["id"],
216
- source: "./data/example_table.json"
300
+ source: "./data/example_table.json",
301
+ updateOnConflict: []
217
302
  }
218
303
  ]
219
304
  };
220
305
  function init(configPath) {
221
306
  const resolved = path2__default.default.resolve(process.cwd(), configPath);
222
307
  if (fs__default.default.existsSync(resolved)) {
223
- throw new Error("Config already exists: " + resolved);
308
+ logError3(`Config file already exists: ${resolved}`);
309
+ throw new Error(`Config already exists: ${resolved}`);
224
310
  }
225
311
  fs__default.default.writeFileSync(
226
312
  resolved,
@@ -230,21 +316,30 @@ function init(configPath) {
230
316
  }
231
317
 
232
318
  // src/cli.ts
319
+ var C5 = {
320
+ reset: "\x1B[0m",
321
+ bold: "\x1B[1m",
322
+ green: "\x1B[32m",
323
+ red: "\x1B[31m"
324
+ };
325
+ var logError4 = (err) => console.error(`${C5.red}${C5.bold}Error:${C5.reset} ${String(err)}`);
233
326
  var prog = sade__default.default("greenseed");
234
327
  prog.command("push").option("-c, --config <file>", "Config file", "seed.config.json").option("-d, --dbvar <name>", "DB env var override").action(async (opts) => {
235
328
  try {
236
329
  await run(opts);
237
330
  } catch (err) {
238
- console.error("\x1B[31m" + String(err) + "\x1B[0m");
331
+ logError4(err);
239
332
  process.exit(1);
240
333
  }
241
334
  });
242
335
  prog.command("init").option("-c, --config <file>", "Config file", "seed.config.json").action((opts) => {
243
336
  try {
244
337
  init(opts.config);
245
- console.log("\x1B[32mConfig created: " + opts.config + "\x1B[0m");
338
+ console.log(
339
+ `${C5.green}\u2713${C5.reset} Config created: ${C5.bold}${opts.config}${C5.reset}`
340
+ );
246
341
  } catch (err) {
247
- console.error("\x1B[31m" + String(err) + "\x1B[0m");
342
+ logError4(err);
248
343
  process.exit(1);
249
344
  }
250
345
  });
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/db.ts","../src/fs.ts","../src/app.ts","../src/init.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, readFile } 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\n\tlet raw: unknown\n\ttry {\n\t\traw = JSON.parse(readFile(configPath))\n\t} catch (e) {\n\t\tthrow new Error(\n\t\t\t`Failed to load config at ${configPath}: ${e instanceof Error ? e.message : String(e)}`,\n\t\t)\n\t}\n\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 ? opts.dbvar : 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","import fs from \"fs\"\nimport path from \"path\"\n\nconst DEFAULT_CONFIG = {\n\tseedFileExtensions: [\".json\"],\n\tdatabaseUrlEnvVar: \"DATABASE_URL\",\n\tonMissingFile: \"error\",\n\ttables: [\n\t\t{\n\t\t\ttable: \"example_table\",\n\t\t\tschema: \"public\",\n\t\t\tprimaryKeys: [\"id\"],\n\t\t\tsource: \"./data/example_table.json\",\n\t\t},\n\t],\n}\n\nexport function init(configPath: string): void {\n\tconst resolved = path.resolve(process.cwd(), configPath)\n\n\tif (fs.existsSync(resolved)) {\n\t\tthrow new Error(\"Config already exists: \" + resolved)\n\t}\n\n\tfs.writeFileSync(\n\t\tresolved,\n\t\tJSON.stringify(DEFAULT_CONFIG, null, 2) + \"\\n\",\n\t\t\"utf8\",\n\t)\n}\n","#!/usr/bin/env node\nimport sade from \"sade\"\nimport { run } from \"./app\"\nimport { init } from \"./init\"\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\n\t.command(\"init\")\n\t.option(\"-c, --config <file>\", \"Config file\", \"seed.config.json\")\n\t.action((opts) => {\n\t\ttry {\n\t\t\tinit(opts.config)\n\t\t\tconsole.log(\"\\x1b[32mConfig created: \" + opts.config + \"\\x1b[0m\")\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"]}
1
+ {"version":3,"sources":["../src/db.ts","../src/fs.ts","../src/app.ts","../src/init.ts","../src/cli.ts"],"names":["postgres","C","logError","fs","path","v","dotenv","sade"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,IAAM,CAAA,GAAI;AAAA,EACT,KAAA,EAAO,SAAA;AAAA,EACP,GAAA,EAAK,SAAA;AAAA,EACL,GAAA,EAAK;AACN,CAAA;AAEA,IAAM,WAAW,CAAC,GAAA,KACjB,QAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,GAAG,CAAA,MAAA,EAAI,EAAE,KAAK,CAAA,CAAA,EAAI,EAAE,GAAG,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,CAAE,KAAK,CAAA,CAAE,CAAA;AAEtD,SAAS,QAAQ,GAAA,EAA2B;AAClD,EAAA,OAAOA,0BAAS,GAAA,EAAK,EAAE,KAAK,EAAA,EAAI,YAAA,EAAc,IAAI,CAAA;AACnD;AAEA,eAAsB,MAAM,GAAA,EAAkC;AAC7D,EAAA,IAAI;AACH,IAAA,MAAM,GAAA,CAAA,QAAA,CAAA;AAAA,EACP,SAAS,GAAA,EAAK;AACb,IAAA,QAAA,CAAS,4BAA4B,CAAA;AACrC,IAAA,MAAM,IAAI,MAAM,+BAA+B,CAAA;AAAA,EAChD;AACD;AAEA,eAAsB,WAAA,CACrB,GAAA,EACA,MAAA,EACA,KAAA,EACmB;AACnB,EAAA,MAAM,MAAM,MAAM,GAAA;AAAA,qBAAA,EACI,GAAA,GAAM,MAAA,GAAS,KAAA,GAAQ,KAAA,GAAQ,GAAG,CAAA;AAAA,CAAA,CAAA;AAExD,EAAA,IAAI,CAAC,GAAA,CAAI,CAAC,CAAA,EAAG;AACZ,IAAA,QAAA,CAAS,CAAA,uBAAA,EAA0B,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE,CAAA;AACpD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,oBAAA,EAAuB,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE,CAAA;AAAA,EACzD;AACA,EAAA,OAAO,GAAA,CAAI,CAAC,CAAA,CAAE,MAAA;AACf;AAEA,eAAsB,cAAA,CACrB,KACA,MAAA,EACgB;AAChB,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACvB,IAAA,MAAM,KAAK,MAAM,WAAA,CAAY,KAAK,CAAA,CAAE,MAAA,EAAQ,EAAE,KAAK,CAAA;AACnD,IAAA,IAAI,CAAC,EAAA,EAAI;AACR,MAAA,QAAA,CAAS,yBAAyB,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,CAAA,CAAE,KAAK,CAAA,CAAE,CAAA;AACvD,MAAA,MAAM,IAAI,MAAM,CAAA,eAAA,EAAkB,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,CAAA,CAAE,KAAK,CAAA,CAAE,CAAA;AAAA,IACxD;AAAA,EACD;AACD;AAEA,eAAsB,QAAA,CACrB,GAAA,EACA,MAAA,EACA,KAAA,EACiC;AACjC,EAAA,MAAM,OAAO,MAAM,GAAA;AAAA;AAAA;AAAA,uBAAA,EAGK,MAAM;AAAA,mBAAA,EACV,KAAK;AAAA;AAAA,CAAA,CAAA;AAGzB,EAAA,OAAO,EAAE,SAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,CAAA,EAAE;AAClD;AAEA,eAAsB,OACrB,GAAA,EACA,MAAA,EACA,OACA,IAAA,EACA,OAAA,EACA,aACA,gBAAA,EACkB;AAClB,EAAA,IAAI,WAAA,CAAY,WAAW,CAAA,EAAG;AAC7B,IAAA,QAAA,CAAS,CAAA,4BAAA,EAA+B,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE,CAAA;AACzD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,oBAAA,EAAuB,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE,CAAA;AAAA,EACzD;AAEA,EAAA,MAAM,aAAa,gBAAA,CAAiB,MAAA;AAAA,IACnC,CAAC,GAAA,KAAQ,CAAC,WAAA,CAAY,SAAS,GAAG;AAAA,GACnC;AAEA,EAAA,IAAI,CAAA;AACJ,EAAA,IAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AAC1B,IAAA,MAAM,UAAU,MAAA,CAAO,WAAA;AAAA,MACtB,UAAA,CAAW,GAAA,CAAI,CAAC,GAAA,KAAQ,CAAC,GAAA,EAAK,GAAA,CAAA,SAAA,EAAe,GAAA,CAAI,GAAG,CAAC,CAAA,CAAE,CAAC;AAAA,KACzD;AAEA,IAAA,CAAA,GAAI,MAAM,GAAA;AAAA,eAAA,EACK,GAAA,CAAI,MAAA,GAAS,GAAA,GAAM,KAAK,CAAC;AAAA,GAAA,EACrC,GAAA,CAAI,IAAA,EAAM,OAAO,CAAC;AAAA,gBAAA,EACL,GAAA,CAAI,WAAW,CAAC,CAAA;AAAA,GAAA,EAC7B,GAAA,CAAI,OAAO,CAAC;AAAA,aAAA,EACF,IAAI,WAAA,CAAY,CAAC,CAAA,IAAK,EAAE,CAAC;AAAA,EAAA,CAAA;AAAA,EAEvC,CAAA,MAAO;AACN,IAAA,CAAA,GAAI,MAAM,GAAA;AAAA,eAAA,EACK,GAAA,CAAI,MAAA,GAAS,GAAA,GAAM,KAAK,CAAC;AAAA,GAAA,EACrC,GAAA,CAAI,IAAA,EAAM,OAAO,CAAC;AAAA,gBAAA,EACL,GAAA,CAAI,WAAW,CAAC,CAAA;AAAA,aAAA,EACnB,IAAI,WAAA,CAAY,CAAC,CAAA,IAAK,EAAE,CAAC;AAAA,EAAA,CAAA;AAAA,EAEvC;AACA,EAAA,OAAO,CAAA,CAAE,MAAA;AACV;ACxGA,IAAMC,EAAAA,GAAI;AAAA,EACT,KAAA,EAAO,SAAA;AAAA,EACP,GAAA,EAAK,SAAA;AAAA,EACL,GAAA,EAAK;AACN,CAAA;AAEA,IAAMC,YAAW,CAAC,GAAA,KACjB,QAAQ,KAAA,CAAM,CAAA,EAAGD,GAAE,GAAG,CAAA,MAAA,EAAIA,GAAE,KAAK,CAAA,CAAA,EAAIA,GAAE,GAAG,CAAA,EAAG,GAAG,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,CAAE,CAAA;AAEtD,SAAS,OAAO,CAAA,EAAoB;AAC1C,EAAA,OAAOE,mBAAA,CAAG,WAAW,CAAC,CAAA;AACvB;AAEO,SAAS,SAAS,CAAA,EAAmB;AAC3C,EAAA,IAAI;AACH,IAAA,OAAOA,mBAAA,CAAG,YAAA,CAAa,CAAA,EAAG,MAAM,CAAA;AAAA,EACjC,SAAS,GAAA,EAAK;AACb,IAAAD,SAAAA,CAAS,CAAA,qBAAA,EAAwB,CAAC,CAAA,CAAE,CAAA;AACpC,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,CAAC,CAAA,CAAE,CAAA;AAAA,EACxC;AACD;AAEO,SAAS,YAAY,CAAA,EAAmB;AAC9C,EAAA,OAAOE,sBAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,GAAA,IAAO,CAAC,CAAA;AACrC;AAMO,SAAS,aAAA,CAAc,GAAW,SAAA,EAAoC;AAC5E,EAAA,IAAI,CAAC,MAAA,CAAO,CAAC,CAAA,EAAG;AACf,IAAA,IAAI,cAAc,MAAA,EAAQ;AACzB,MAAA,OAAO,EAAC;AAAA,IACT;AACA,IAAAF,SAAAA,CAAS,CAAA,uBAAA,EAA0B,CAAC,CAAA,CAAE,CAAA;AACtC,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,cAAA,EAAiB,CAAC,CAAA,CAAE,CAAA;AAAA,EACrC;AAEA,EAAA,MAAM,GAAA,GAAM,SAAS,CAAC,CAAA;AAEtB,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACH,IAAA,MAAA,GAAS,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,EACxB,CAAA,CAAA,MAAQ;AACP,IAAAA,SAAAA,CAAS,CAAA,sBAAA,EAAyB,CAAC,CAAA,CAAE,CAAA;AACrC,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kBAAA,EAAqB,CAAC,CAAA,CAAE,CAAA;AAAA,EACzC;AAEA,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC3B,IAAAA,UAAS,CAAA,uBAAA,EAA0B,OAAO,MAAM,CAAA,EAAA,EAAK,CAAC,CAAA,CAAE,CAAA;AACxD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,CAAC,CAAA,CAAE,CAAA;AAAA,EAC5C;AAEA,EAAA,OAAO,MAAA;AACR;AAEO,SAAS,KAAA,CAAS,MAAW,IAAA,EAAqB;AACxD,EAAA,MAAM,MAAa,EAAC;AACpB,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,MAAA,EAAQ,KAAK,IAAA,EAAM;AAC3C,IAAA,GAAA,CAAI,KAAK,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,CAAA,GAAI,IAAI,CAAC,CAAA;AAAA,EACjC;AACA,EAAA,OAAO,GAAA;AACR;;;AC5DA,IAAMD,EAAAA,GAAI;AAAA,EACT,KAAA,EAAO,SAAA;AAAA,EACP,IAAA,EAAM,SAAA;AAAA,EACN,GAAA,EAAK,SAAA;AAAA,EACL,KAAA,EAAO,UAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,IAAA,EAAM,UAAA;AAAA,EACN,IAAA,EAAM,UAAA;AAAA,EACN,GAAA,EAAK,UAEN,CAAA;AAEA,IAAM,GAAA,GAAM;AAAA,EACX,IAAA,EAAM,CAAC,GAAA,KAAgB,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAGA,EAAAA,CAAE,IAAI,CAAA,MAAA,EAAIA,EAAAA,CAAE,KAAK,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA;AAAA,EAChE,OAAA,EAAS,CAAC,GAAA,KAAgB,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,MAAA,EAAIA,EAAAA,CAAE,KAAK,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA;AAAA,EACpE,IAAA,EAAM,CAAC,GAAA,KAAgB,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAGA,EAAAA,CAAE,MAAM,CAAA,MAAA,EAAIA,EAAAA,CAAE,KAAK,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA;AAAA,EAClE,KAAA,EAAO,CAAC,GAAA,KAAgB,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAGA,EAAAA,CAAE,GAAG,CAAA,MAAA,EAAIA,EAAAA,CAAE,KAAK,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA;AAAA,EAChE,GAAA,EAAK,CAAC,GAAA,KAAgB,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAGA,EAAAA,CAAE,GAAG,CAAA,EAAG,GAAG,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,CAAE,CAAA;AAAA,EAC5D,MAAA,EAAQ,CAAC,GAAA,KACR,OAAA,CAAQ,GAAA,CAAI;AAAA,EAAKA,EAAAA,CAAE,IAAI,CAAA,EAAGA,EAAAA,CAAE,IAAI,CAAA,EAAG,GAAG,CAAA,EAAGA,EAAAA,CAAE,KAAK;AAAA,CAAI,CAAA;AAAA,EACrD,KAAA,EAAO,CAAC,KAAA,EAAe,KAAA,KACtB,QAAQ,GAAA,CAAI,CAAA,EAAA,EAAKA,EAAAA,CAAE,GAAG,CAAA,EAAG,KAAK,IAAIA,EAAAA,CAAE,KAAK,IAAIA,EAAAA,CAAE,IAAI,GAAG,KAAK,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,CAAE,CAAA;AAAA,EACxE,QAAA,EAAU,CAAC,OAAA,EAAiB,KAAA,EAAe,KAAA,KAAkB;AAC5D,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,CAAO,OAAA,GAAU,QAAS,GAAG,CAAA;AACrD,IAAA,MAAM,MAAM,QAAA,CAAI,MAAA,CAAO,KAAK,KAAA,CAAM,UAAA,GAAa,CAAC,CAAC,CAAA;AACjD,IAAA,MAAM,KAAA,GAAQ,SAAI,MAAA,CAAO,EAAA,GAAK,KAAK,KAAA,CAAM,UAAA,GAAa,CAAC,CAAC,CAAA;AACxD,IAAA,OAAA,CAAQ,GAAA;AAAA,MACP,CAAA,EAAA,EAAKA,EAAAA,CAAE,IAAI,CAAA,EAAG,GAAG,CAAA,EAAG,KAAK,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,CAAA,EAAIA,EAAAA,CAAE,IAAI,CAAA,EAAG,UAAU,CAAA,CAAA,EAAIA,EAAAA,CAAE,KAAK,CAAA,CAAA,EAAIA,EAAAA,CAAE,GAAG,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAIA,EAAAA,CAAE,KAAK,IAAI,KAAK,CAAA;AAAA,KACvH;AAAA,EACD;AACD,CAAA;AAEA,IAAM,eAAiBI,YAAA,CAAA,MAAA,CAAO;AAAA,EAC7B,oBAAsBA,YAAA,CAAA,KAAA,CAAQA,YAAA,CAAA,QAAA,CAAS,CAAC,OAAO,CAAC,CAAC,CAAA;AAAA,EACjD,mBAAqBA,YAAA,CAAA,MAAA,EAAO;AAAA,EAC5B,aAAA,EAAiBA,sBAAWA,YAAA,CAAA,QAAA,CAAS,CAAC,QAAQ,OAAO,CAAC,GAAG,OAAO,CAAA;AAAA,EAChE,MAAA,EAAUA,YAAA,CAAA,KAAA;AAAA,IACPA,YAAA,CAAA,MAAA,CAAO;AAAA,MACR,OAASA,YAAA,CAAA,MAAA,EAAO;AAAA,MAChB,MAAA,EAAUA,YAAA,CAAA,QAAA,CAAWA,YAAA,CAAA,MAAA,EAAO,EAAG,QAAQ,CAAA;AAAA,MACvC,WAAA,EAAeA,YAAA,CAAA,KAAA,CAAQA,YAAA,CAAA,MAAA,EAAQ,CAAA;AAAA,MAC/B,QAAUA,YAAA,CAAA,MAAA,EAAO;AAAA,MACjB,gBAAA,EAAoBA,sBAAWA,YAAA,CAAA,QAAA,CAAWA,YAAA,CAAA,KAAA,CAAQA,qBAAQ,CAAC,GAAG,IAAI;AAAA,KAClE;AAAA;AAEH,CAAC,CAAA;AAID,eAAsB,IAAI,IAAA,EAA2B;AACpD,EAAAC,uBAAA,CAAO,MAAA,EAAO;AAEd,EAAA,MAAM,UAAA,GAAa,WAAA,CAAY,IAAA,CAAK,MAAA,IAAU,kBAAkB,CAAA;AAEhE,EAAA,GAAA,CAAI,OAAO,qBAAc,CAAA;AAEzB,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACH,IAAA,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,UAAU,CAAC,CAAA;AAAA,EACtC,SAAS,CAAA,EAAG;AACX,IAAA,MAAM,IAAI,KAAA;AAAA,MACT,CAAA,yBAAA,EAA4B,UAAU,CAAA,EAAA,EAAK,CAAA,YAAa,QAAQ,CAAA,CAAE,OAAA,GAAU,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,KACtF;AAAA,EACD;AAEA,EAAA,MAAM,MAAA,GAAWD,YAAA,CAAA,SAAA,CAAU,YAAA,EAAc,GAAG,CAAA;AAE5C,EAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACpB,IAAA,MAAM,IAAI,MAAM,uBAAuB,CAAA;AAAA,EACxC;AAEA,EAAA,MAAM,SAAS,MAAA,CAAO,MAAA;AACtB,EAAA,MAAM,KAAA,GACL,KAAK,KAAA,IAAS,IAAA,CAAK,MAAM,MAAA,GAAS,CAAA,GAAI,IAAA,CAAK,KAAA,GAAQ,MAAA,CAAO,iBAAA;AAE3D,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA;AAC/B,EAAA,IAAI,CAAC,KAAA,EAAO;AACX,IAAA,MAAM,IAAI,KAAA,CAAM,sBAAA,GAAyB,KAAK,CAAA;AAAA,EAC/C;AAEA,EAAA,GAAA,CAAI,IAAA,CAAK,iBAAiBJ,EAAAA,CAAE,GAAG,GAAG,UAAU,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,CAAE,CAAA;AACxD,EAAA,GAAA,CAAI,IAAA,CAAK,aAAaA,EAAAA,CAAE,GAAG,GAAG,KAAK,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,CAAE,CAAA;AAE/C,EAAA,MAAM,GAAA,GAAM,QAAQ,KAAK,CAAA;AACzB,EAAA,MAAM,MAAM,GAAG,CAAA;AAEf,EAAA,MAAM,cAAA;AAAA,IACL,GAAA;AAAA,IACA,MAAA,CAAO,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MACzB,OAAO,CAAA,CAAE,KAAA;AAAA,MACT,QAAQ,CAAA,CAAE;AAAA,KACX,CAAE;AAAA,GACH;AAEA,EAAA,GAAA,CAAI,QAAQ,iCAAiC,CAAA;AAC7C,EAAA,GAAA,CAAI,OAAO,gBAAgB,CAAA;AAE3B,EAAA,KAAA,MAAW,CAAA,IAAK,OAAO,MAAA,EAAQ;AAC9B,IAAA,MAAM,MAAA,GAASG,uBAAK,OAAA,CAAQA,sBAAAA,CAAK,QAAQ,UAAU,CAAA,EAAG,EAAE,MAAM,CAAA;AAC9D,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,MAAA,EAAQ,MAAA,CAAO,iBAAiB,OAAO,CAAA;AAElE,IAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACtB,MAAA,GAAA,CAAI,IAAA,CAAK,CAAA,QAAA,EAAWH,EAAAA,CAAE,IAAI,CAAA,EAAG,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,CAAA,CAAE,KAAK,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,UAAA,CAAY,CAAA;AACtE,MAAA;AAAA,IACD;AAEA,IAAA,MAAM,OAAO,MAAM,QAAA,CAAS,KAAK,CAAA,CAAE,MAAA,EAAQ,EAAE,KAAK,CAAA;AAClD,IAAA,MAAM,YAAY,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,CAAC,CAAC,CAAA,CAAE,MAAA;AAAA,MAAO,CAAC,CAAA,KAC9C,IAAA,CAAK,OAAA,CAAQ,SAAS,CAAC;AAAA,KACxB;AAEA,IAAA,GAAA,CAAI,IAAA,CAAK,CAAA,QAAA,EAAWA,EAAAA,CAAE,IAAI,CAAA,EAAG,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,CAAA,CAAE,KAAK,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,CAAE,CAAA;AAE5D,IAAA,IAAI,QAAA,GAAW,CAAA;AACf,IAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,CAAM,IAAA,EAAM,GAAI,CAAA,EAAG;AACrC,MAAA,QAAA,IAAY,MAAM,MAAA;AAAA,QACjB,GAAA;AAAA,QACA,CAAA,CAAE,MAAA;AAAA,QACF,CAAA,CAAE,KAAA;AAAA,QACF,IAAA;AAAA,QACA,SAAA;AAAA,QACA,CAAA,CAAE,WAAA;AAAA,QACF,CAAA,CAAE,oBAAoB;AAAC,OACxB;AAAA,IACD;AAEA,IAAA,MAAM,WAAA,GAAc,CAAA,CAAE,gBAAA,IAAoB,CAAA,CAAE,iBAAiB,MAAA,GAAS,CAAA;AACtE,IAAA,MAAM,MAAA,GAAS,cAAc,UAAA,GAAa,UAAA;AAC1C,IAAA,MAAM,OAAA,GAAU,KAAK,MAAA,GAAS,QAAA;AAE9B,IAAA,IAAI,QAAA,KAAa,KAAK,MAAA,EAAQ;AAC7B,MAAA,GAAA,CAAI,OAAA;AAAA,QACH,CAAA,EAAGA,GAAE,IAAI,CAAA,EAAG,EAAE,MAAM,CAAA,CAAA,EAAI,EAAE,KAAK,CAAA,EAAGA,GAAE,KAAK,CAAA,CAAA,EAAIA,GAAE,KAAK,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,QAAQ,CAAA,KAAA,EAAQA,EAAAA,CAAE,KAAK,CAAA;AAAA,OACzF;AAAA,IACD,CAAA,MAAO;AACN,MAAA,GAAA,CAAI,OAAA;AAAA,QACH,CAAA,EAAGA,EAAAA,CAAE,IAAI,CAAA,EAAG,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,CAAA,CAAE,KAAK,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,CAAA,EAAIA,EAAAA,CAAE,KAAK,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,QAAQ,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,EAAGA,EAAAA,CAAE,GAAG,CAAA,UAAA,EAAa,OAAO,CAAA,EAAGA,GAAE,KAAK,CAAA;AAAA,OAC1H;AAAA,IACD;AAAA,EACD;AAEA,EAAA,MAAM,IAAI,GAAA,EAAI;AAEd,EAAA,GAAA,CAAI,OAAO,SAAS,CAAA;AACpB,EAAA,GAAA,CAAI,OAAA;AAAA,IACH,UAAUA,EAAAA,CAAE,IAAI,CAAA,EAAG,MAAA,CAAO,OAAO,MAAM,CAAA,EAAGA,EAAAA,CAAE,KAAK,SAAS,MAAA,CAAO,MAAA,CAAO,MAAA,KAAW,CAAA,GAAI,KAAK,GAAG,CAAA;AAAA,GAChG;AACD;ACtJA,IAAMA,EAAAA,GAAI;AAAA,EACT,KAAA,EAAO,SAAA;AAAA,EACP,GAAA,EAAK,SAAA;AAAA,EACL,GAAA,EAAK;AACN,CAAA;AAEA,IAAMC,YAAW,CAAC,GAAA,KACjB,QAAQ,KAAA,CAAM,CAAA,EAAGD,GAAE,GAAG,CAAA,MAAA,EAAIA,GAAE,KAAK,CAAA,CAAA,EAAIA,GAAE,GAAG,CAAA,EAAG,GAAG,CAAA,EAAGA,EAAAA,CAAE,KAAK,CAAA,CAAE,CAAA;AAE7D,IAAM,cAAA,GAAiB;AAAA,EACtB,kBAAA,EAAoB,CAAC,OAAO,CAAA;AAAA,EAC5B,iBAAA,EAAmB,cAAA;AAAA,EACnB,aAAA,EAAe,OAAA;AAAA,EACf,MAAA,EAAQ;AAAA,IACP;AAAA,MACC,KAAA,EAAO,eAAA;AAAA,MACP,MAAA,EAAQ,QAAA;AAAA,MACR,WAAA,EAAa,CAAC,IAAI,CAAA;AAAA,MAClB,MAAA,EAAQ,2BAAA;AAAA,MACR,kBAAkB;AAAC;AACpB;AAEF,CAAA;AAEO,SAAS,KAAK,UAAA,EAA0B;AAC9C,EAAA,MAAM,WAAWG,sBAAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,GAAA,IAAO,UAAU,CAAA;AAEvD,EAAA,IAAID,mBAAAA,CAAG,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC5B,IAAAD,SAAAA,CAAS,CAAA,4BAAA,EAA+B,QAAQ,CAAA,CAAE,CAAA;AAClD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uBAAA,EAA0B,QAAQ,CAAA,CAAE,CAAA;AAAA,EACrD;AAEA,EAAAC,mBAAAA,CAAG,aAAA;AAAA,IACF,QAAA;AAAA,IACA,IAAA,CAAK,SAAA,CAAU,cAAA,EAAgB,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA;AAAA,IAC1C;AAAA,GACD;AACD;;;ACnCA,IAAMF,EAAAA,GAAI;AAAA,EACT,KAAA,EAAO,SAAA;AAAA,EACP,IAAA,EAAM,SAAA;AAAA,EACN,KAAA,EAAO,UAAA;AAAA,EACP,GAAA,EAAK;AACN,CAAA;AAEA,IAAMC,YAAW,CAAC,GAAA,KACjB,QAAQ,KAAA,CAAM,CAAA,EAAGD,GAAE,GAAG,CAAA,EAAGA,EAAAA,CAAE,IAAI,SAASA,EAAAA,CAAE,KAAK,IAAI,MAAA,CAAO,GAAG,CAAC,CAAA,CAAE,CAAA;AAEjE,IAAM,IAAA,GAAOM,sBAAK,WAAW,CAAA;AAE7B,IAAA,CACE,OAAA,CAAQ,MAAM,CAAA,CACd,MAAA,CAAO,uBAAuB,aAAA,EAAe,kBAAkB,CAAA,CAC/D,MAAA,CAAO,oBAAA,EAAsB,qBAAqB,CAAA,CAClD,MAAA,CAAO,OAAO,IAAA,KAAS;AACvB,EAAA,IAAI;AACH,IAAA,MAAM,IAAI,IAAI,CAAA;AAAA,EACf,SAAS,GAAA,EAAK;AACb,IAAAL,UAAS,GAAG,CAAA;AACZ,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EACf;AACD,CAAC,CAAA;AAEF,IAAA,CACE,OAAA,CAAQ,MAAM,CAAA,CACd,MAAA,CAAO,qBAAA,EAAuB,eAAe,kBAAkB,CAAA,CAC/D,MAAA,CAAO,CAAC,IAAA,KAAS;AACjB,EAAA,IAAI;AACH,IAAA,IAAA,CAAK,KAAK,MAAM,CAAA;AAChB,IAAA,OAAA,CAAQ,GAAA;AAAA,MACP,CAAA,EAAGD,EAAAA,CAAE,KAAK,CAAA,MAAA,EAAIA,GAAE,KAAK,CAAA,iBAAA,EAAoBA,EAAAA,CAAE,IAAI,CAAA,EAAG,IAAA,CAAK,MAAM,CAAA,EAAGA,GAAE,KAAK,CAAA;AAAA,KACxE;AAAA,EACD,SAAS,GAAA,EAAK;AACb,IAAAC,UAAS,GAAG,CAAA;AACZ,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EACf;AACD,CAAC,CAAA;AAEF,IAAA,CAAK,KAAA,CAAM,QAAQ,IAAI,CAAA","file":"cli.cjs","sourcesContent":["import postgres from \"postgres\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tdim: \"\\x1b[2m\",\n\tred: \"\\x1b[31m\",\n}\n\nconst logError = (msg: string) =>\n\tconsole.error(`${C.red}✗${C.reset} ${C.dim}${msg}${C.reset}`)\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\tlogError(\"Database connection failed\")\n\t\tthrow new Error(\"Failed to connect to database\")\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\tlogError(`Failed to check table: ${schema}.${table}`)\n\t\tthrow new Error(`Table check failed: ${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\tlogError(`Table does not exist: ${t.schema}.${t.table}`)\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\tupdateOnConflict: string[],\n): Promise<number> {\n\tif (primaryKeys.length === 0) {\n\t\tlogError(`No primary keys defined for ${schema}.${table}`)\n\t\tthrow new Error(`No primary keys for ${schema}.${table}`)\n\t}\n\n\tconst updateCols = updateOnConflict.filter(\n\t\t(col) => !primaryKeys.includes(col),\n\t)\n\n\tlet q\n\tif (updateCols.length > 0) {\n\t\tconst updates = Object.fromEntries(\n\t\t\tupdateCols.map((col) => [col, sql`excluded.${sql(col)}`]),\n\t\t)\n\n\t\tq = await sql`\n\t\t\tinsert into ${sql(schema + \".\" + table)}\n\t\t\t${sql(rows, columns)}\n\t\t\ton conflict (${sql(primaryKeys)}) do update set\n\t\t\t${sql(updates)}\n\t\t\treturning ${sql(primaryKeys[0] ?? [])}\n\t\t`\n\t} else {\n\t\tq = await sql`\n\t\t\tinsert into ${sql(schema + \".\" + table)}\n\t\t\t${sql(rows, columns)}\n\t\t\ton conflict (${sql(primaryKeys)}) do nothing\n\t\t\treturning ${sql(primaryKeys[0] ?? [])}\n\t\t`\n\t}\n\treturn q.length\n}\n","import fs from \"fs\"\nimport path from \"path\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tdim: \"\\x1b[2m\",\n\tred: \"\\x1b[31m\",\n}\n\nconst logError = (msg: string) =>\n\tconsole.error(`${C.red}✗${C.reset} ${C.dim}${msg}${C.reset}`)\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\tlogError(`Failed to read file: ${p}`)\n\t\tthrow new Error(`File read error: ${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\tlogError(`Source file not found: ${p}`)\n\t\tthrow new Error(`Missing file: ${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\tlogError(`Invalid JSON in file: ${p}`)\n\t\tthrow new Error(`JSON parse error: ${p}`)\n\t}\n\n\tif (!Array.isArray(parsed)) {\n\t\tlogError(`Expected array but got ${typeof parsed}: ${p}`)\n\t\tthrow new Error(`Invalid data format: ${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, readFile } from \"./fs\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tbold: \"\\x1b[1m\",\n\tdim: \"\\x1b[2m\",\n\tgreen: \"\\x1b[32m\",\n\tyellow: \"\\x1b[33m\",\n\tblue: \"\\x1b[34m\",\n\tcyan: \"\\x1b[36m\",\n\tred: \"\\x1b[31m\",\n\tgray: \"\\x1b[90m\",\n}\n\nconst log = {\n\tinfo: (msg: string) => console.log(`${C.blue}ℹ${C.reset} ${msg}`),\n\tsuccess: (msg: string) => console.log(`${C.green}✓${C.reset} ${msg}`),\n\twarn: (msg: string) => console.log(`${C.yellow}⚠${C.reset} ${msg}`),\n\terror: (msg: string) => console.log(`${C.red}✗${C.reset} ${msg}`),\n\tdim: (msg: string) => console.log(`${C.dim}${msg}${C.reset}`),\n\theader: (msg: string) =>\n\t\tconsole.log(`\\n${C.bold}${C.cyan}${msg}${C.reset}\\n`),\n\ttable: (label: string, value: string | number) =>\n\t\tconsole.log(` ${C.dim}${label}:${C.reset} ${C.bold}${value}${C.reset}`),\n\tprogress: (current: number, total: number, label: string) => {\n\t\tconst percentage = Math.round((current / total) * 100)\n\t\tconst bar = \"█\".repeat(Math.floor(percentage / 5))\n\t\tconst empty = \"░\".repeat(20 - Math.floor(percentage / 5))\n\t\tconsole.log(\n\t\t\t` ${C.cyan}${bar}${empty}${C.reset} ${C.bold}${percentage}%${C.reset} ${C.dim}(${current}/${total})${C.reset} ${label}`,\n\t\t)\n\t},\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\tupdateOnConflict: v.optional(v.nullable(v.array(v.string())), null),\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\n\tlog.header(\"🌱 GreenSeed\")\n\n\tlet raw: unknown\n\ttry {\n\t\traw = JSON.parse(readFile(configPath))\n\t} catch (e) {\n\t\tthrow new Error(\n\t\t\t`Failed to load config at ${configPath}: ${e instanceof Error ? e.message : String(e)}`,\n\t\t)\n\t}\n\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 ? opts.dbvar : 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\tlog.info(`Using config: ${C.dim}${configPath}${C.reset}`)\n\tlog.info(`Database: ${C.dim}${dbVar}${C.reset}`)\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\tlog.success(\"Database connection established\")\n\tlog.header(\"Seeding Tables\")\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\tlog.warn(`Skipped ${C.bold}${t.schema}.${t.table}${C.reset} (no data)`)\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\tlog.info(`Seeding ${C.bold}${t.schema}.${t.table}${C.reset}`)\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\tt.updateOnConflict || [],\n\t\t\t)\n\t\t}\n\n\t\tconst hasConflict = t.updateOnConflict && t.updateOnConflict.length > 0\n\t\tconst action = hasConflict ? \"upserted\" : \"inserted\"\n\t\tconst skipped = rows.length - inserted\n\n\t\tif (inserted === rows.length) {\n\t\t\tlog.success(\n\t\t\t\t`${C.bold}${t.schema}.${t.table}${C.reset} ${C.green}${action} ${inserted} rows${C.reset}`,\n\t\t\t)\n\t\t} else {\n\t\t\tlog.success(\n\t\t\t\t`${C.bold}${t.schema}.${t.table}${C.reset} ${C.green}${action} ${inserted}${C.reset}${C.dim}, skipped ${skipped}${C.reset}`,\n\t\t\t)\n\t\t}\n\t}\n\n\tawait sql.end()\n\n\tlog.header(\"Summary\")\n\tlog.success(\n\t\t`Seeded ${C.bold}${config.tables.length}${C.reset} table${config.tables.length === 1 ? \"\" : \"s\"}`,\n\t)\n}\n","import fs from \"fs\"\nimport path from \"path\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tdim: \"\\x1b[2m\",\n\tred: \"\\x1b[31m\",\n}\n\nconst logError = (msg: string) =>\n\tconsole.error(`${C.red}✗${C.reset} ${C.dim}${msg}${C.reset}`)\n\nconst DEFAULT_CONFIG = {\n\tseedFileExtensions: [\".json\"],\n\tdatabaseUrlEnvVar: \"DATABASE_URL\",\n\tonMissingFile: \"error\",\n\ttables: [\n\t\t{\n\t\t\ttable: \"example_table\",\n\t\t\tschema: \"public\",\n\t\t\tprimaryKeys: [\"id\"],\n\t\t\tsource: \"./data/example_table.json\",\n\t\t\tupdateOnConflict: [],\n\t\t},\n\t],\n}\n\nexport function init(configPath: string): void {\n\tconst resolved = path.resolve(process.cwd(), configPath)\n\n\tif (fs.existsSync(resolved)) {\n\t\tlogError(`Config file already exists: ${resolved}`)\n\t\tthrow new Error(`Config already exists: ${resolved}`)\n\t}\n\n\tfs.writeFileSync(\n\t\tresolved,\n\t\tJSON.stringify(DEFAULT_CONFIG, null, 2) + \"\\n\",\n\t\t\"utf8\",\n\t)\n}\n","#!/usr/bin/env node\nimport sade from \"sade\"\nimport { run } from \"./app\"\nimport { init } from \"./init\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tbold: \"\\x1b[1m\",\n\tgreen: \"\\x1b[32m\",\n\tred: \"\\x1b[31m\",\n}\n\nconst logError = (err: unknown) =>\n\tconsole.error(`${C.red}${C.bold}Error:${C.reset} ${String(err)}`)\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\tlogError(err)\n\t\t\tprocess.exit(1)\n\t\t}\n\t})\n\nprog\n\t.command(\"init\")\n\t.option(\"-c, --config <file>\", \"Config file\", \"seed.config.json\")\n\t.action((opts) => {\n\t\ttry {\n\t\t\tinit(opts.config)\n\t\t\tconsole.log(\n\t\t\t\t`${C.green}✓${C.reset} Config created: ${C.bold}${opts.config}${C.reset}`,\n\t\t\t)\n\t\t} catch (err) {\n\t\t\tlogError(err)\n\t\t\tprocess.exit(1)\n\t\t}\n\t})\n\nprog.parse(process.argv)\n"]}
package/dist/cli.js CHANGED
@@ -6,6 +6,12 @@ import path2 from 'path';
6
6
  import postgres from 'postgres';
7
7
  import fs from 'fs';
8
8
 
9
+ var C = {
10
+ reset: "\x1B[0m",
11
+ dim: "\x1B[2m",
12
+ red: "\x1B[31m"
13
+ };
14
+ var logError = (msg) => console.error(`${C.red}\u2717${C.reset} ${C.dim}${msg}${C.reset}`);
9
15
  function connect(url) {
10
16
  return postgres(url, { max: 10, idle_timeout: 20 });
11
17
  }
@@ -13,7 +19,8 @@ async function check(sql) {
13
19
  try {
14
20
  await sql`select 1`;
15
21
  } catch (err) {
16
- throw new Error("Database connection failed");
22
+ logError("Database connection failed");
23
+ throw new Error("Failed to connect to database");
17
24
  }
18
25
  }
19
26
  async function tableExists(sql, schema, table) {
@@ -21,7 +28,8 @@ async function tableExists(sql, schema, table) {
21
28
  select to_regclass(${'"' + schema + '"."' + table + '"'}) is not null as exists
22
29
  `;
23
30
  if (!res[0]) {
24
- throw new Error("Failed checking table: " + schema + "." + table);
31
+ logError(`Failed to check table: ${schema}.${table}`);
32
+ throw new Error(`Table check failed: ${schema}.${table}`);
25
33
  }
26
34
  return res[0].exists;
27
35
  }
@@ -29,7 +37,8 @@ async function validateTables(sql, tables) {
29
37
  for (const t of tables) {
30
38
  const ok = await tableExists(sql, t.schema, t.table);
31
39
  if (!ok) {
32
- throw new Error("Missing table: " + t.schema + "." + t.table);
40
+ logError(`Table does not exist: ${t.schema}.${t.table}`);
41
+ throw new Error(`Missing table: ${t.schema}.${t.table}`);
33
42
  }
34
43
  }
35
44
  }
@@ -43,18 +52,42 @@ async function metadata(sql, schema, table) {
43
52
  `;
44
53
  return { columns: cols.map((c) => c.column_name) };
45
54
  }
46
- async function insert(sql, schema, table, rows, columns, primaryKeys) {
55
+ async function insert(sql, schema, table, rows, columns, primaryKeys, updateOnConflict) {
47
56
  if (primaryKeys.length === 0) {
48
- throw new Error("No primary keys for " + schema + "." + table);
57
+ logError(`No primary keys defined for ${schema}.${table}`);
58
+ throw new Error(`No primary keys for ${schema}.${table}`);
59
+ }
60
+ const updateCols = updateOnConflict.filter(
61
+ (col) => !primaryKeys.includes(col)
62
+ );
63
+ let q;
64
+ if (updateCols.length > 0) {
65
+ const updates = Object.fromEntries(
66
+ updateCols.map((col) => [col, sql`excluded.${sql(col)}`])
67
+ );
68
+ q = await sql`
69
+ insert into ${sql(schema + "." + table)}
70
+ ${sql(rows, columns)}
71
+ on conflict (${sql(primaryKeys)}) do update set
72
+ ${sql(updates)}
73
+ returning ${sql(primaryKeys[0] ?? [])}
74
+ `;
75
+ } else {
76
+ q = await sql`
77
+ insert into ${sql(schema + "." + table)}
78
+ ${sql(rows, columns)}
79
+ on conflict (${sql(primaryKeys)}) do nothing
80
+ returning ${sql(primaryKeys[0] ?? [])}
81
+ `;
49
82
  }
50
- const q = await sql`
51
- insert into ${sql(schema + "." + table)}
52
- ${sql(rows, columns)}
53
- on conflict (${sql(primaryKeys)}) do nothing
54
- returning ${sql(primaryKeys[0] ?? [])}
55
- `;
56
83
  return q.length;
57
84
  }
85
+ var C2 = {
86
+ reset: "\x1B[0m",
87
+ dim: "\x1B[2m",
88
+ red: "\x1B[31m"
89
+ };
90
+ var logError2 = (msg) => console.error(`${C2.red}\u2717${C2.reset} ${C2.dim}${msg}${C2.reset}`);
58
91
  function exists(p) {
59
92
  return fs.existsSync(p);
60
93
  }
@@ -62,7 +95,8 @@ function readFile(p) {
62
95
  try {
63
96
  return fs.readFileSync(p, "utf8");
64
97
  } catch (err) {
65
- throw new Error("Failed to read file: " + p);
98
+ logError2(`Failed to read file: ${p}`);
99
+ throw new Error(`File read error: ${p}`);
66
100
  }
67
101
  }
68
102
  function resolvePath(p) {
@@ -73,17 +107,20 @@ function loadJsonArray(p, onMissing) {
73
107
  if (onMissing === "skip") {
74
108
  return [];
75
109
  }
76
- throw new Error("Source file not found: " + p);
110
+ logError2(`Source file not found: ${p}`);
111
+ throw new Error(`Missing file: ${p}`);
77
112
  }
78
113
  const raw = readFile(p);
79
114
  let parsed;
80
115
  try {
81
116
  parsed = JSON.parse(raw);
82
117
  } catch {
83
- throw new Error("Invalid JSON: " + p);
118
+ logError2(`Invalid JSON in file: ${p}`);
119
+ throw new Error(`JSON parse error: ${p}`);
84
120
  }
85
121
  if (!Array.isArray(parsed)) {
86
- throw new Error("Data is not an array: " + p);
122
+ logError2(`Expected array but got ${typeof parsed}: ${p}`);
123
+ throw new Error(`Invalid data format: ${p}`);
87
124
  }
88
125
  return parsed;
89
126
  }
@@ -96,11 +133,33 @@ function chunk(data, size) {
96
133
  }
97
134
 
98
135
  // src/app.ts
99
- var C = {
136
+ var C3 = {
100
137
  reset: "\x1B[0m",
138
+ bold: "\x1B[1m",
139
+ dim: "\x1B[2m",
101
140
  green: "\x1B[32m",
102
141
  yellow: "\x1B[33m",
103
- gray: "\x1B[90m"
142
+ blue: "\x1B[34m",
143
+ cyan: "\x1B[36m",
144
+ red: "\x1B[31m"};
145
+ var log = {
146
+ info: (msg) => console.log(`${C3.blue}\u2139${C3.reset} ${msg}`),
147
+ success: (msg) => console.log(`${C3.green}\u2713${C3.reset} ${msg}`),
148
+ warn: (msg) => console.log(`${C3.yellow}\u26A0${C3.reset} ${msg}`),
149
+ error: (msg) => console.log(`${C3.red}\u2717${C3.reset} ${msg}`),
150
+ dim: (msg) => console.log(`${C3.dim}${msg}${C3.reset}`),
151
+ header: (msg) => console.log(`
152
+ ${C3.bold}${C3.cyan}${msg}${C3.reset}
153
+ `),
154
+ table: (label, value) => console.log(` ${C3.dim}${label}:${C3.reset} ${C3.bold}${value}${C3.reset}`),
155
+ progress: (current, total, label) => {
156
+ const percentage = Math.round(current / total * 100);
157
+ const bar = "\u2588".repeat(Math.floor(percentage / 5));
158
+ const empty = "\u2591".repeat(20 - Math.floor(percentage / 5));
159
+ console.log(
160
+ ` ${C3.cyan}${bar}${empty}${C3.reset} ${C3.bold}${percentage}%${C3.reset} ${C3.dim}(${current}/${total})${C3.reset} ${label}`
161
+ );
162
+ }
104
163
  };
105
164
  var ConfigSchema = v.object({
106
165
  seedFileExtensions: v.array(v.picklist([".json"])),
@@ -111,13 +170,15 @@ var ConfigSchema = v.object({
111
170
  table: v.string(),
112
171
  schema: v.optional(v.string(), "public"),
113
172
  primaryKeys: v.array(v.string()),
114
- source: v.string()
173
+ source: v.string(),
174
+ updateOnConflict: v.optional(v.nullable(v.array(v.string())), null)
115
175
  })
116
176
  )
117
177
  });
118
178
  async function run(opts) {
119
179
  dotenv.config();
120
180
  const configPath = resolvePath(opts.config || "seed.config.json");
181
+ log.header("\u{1F331} GreenSeed");
121
182
  let raw;
122
183
  try {
123
184
  raw = JSON.parse(readFile(configPath));
@@ -136,6 +197,8 @@ async function run(opts) {
136
197
  if (!dbUrl) {
137
198
  throw new Error("Missing DB env var: " + dbVar);
138
199
  }
200
+ log.info(`Using config: ${C3.dim}${configPath}${C3.reset}`);
201
+ log.info(`Database: ${C3.dim}${dbVar}${C3.reset}`);
139
202
  const sql = connect(dbUrl);
140
203
  await check(sql);
141
204
  await validateTables(
@@ -145,18 +208,20 @@ async function run(opts) {
145
208
  schema: t.schema
146
209
  }))
147
210
  );
148
- console.log(C.gray + "Starting seed process" + C.reset);
211
+ log.success("Database connection established");
212
+ log.header("Seeding Tables");
149
213
  for (const t of config.tables) {
150
214
  const source = path2.resolve(path2.dirname(configPath), t.source);
151
215
  const rows = loadJsonArray(source, config.onMissingFile || "error");
152
216
  if (rows.length === 0) {
153
- console.log(C.yellow + "Skipped " + t.table + C.reset);
217
+ log.warn(`Skipped ${C3.bold}${t.schema}.${t.table}${C3.reset} (no data)`);
154
218
  continue;
155
219
  }
156
220
  const meta = await metadata(sql, t.schema, t.table);
157
221
  const validCols = Object.keys(rows[0]).filter(
158
222
  (c) => meta.columns.includes(c)
159
223
  );
224
+ log.info(`Seeding ${C3.bold}${t.schema}.${t.table}${C3.reset}`);
160
225
  let inserted = 0;
161
226
  for (const part of chunk(rows, 1e3)) {
162
227
  inserted += await insert(
@@ -165,16 +230,35 @@ async function run(opts) {
165
230
  t.table,
166
231
  part,
167
232
  validCols,
168
- t.primaryKeys
233
+ t.primaryKeys,
234
+ t.updateOnConflict || []
235
+ );
236
+ }
237
+ const hasConflict = t.updateOnConflict && t.updateOnConflict.length > 0;
238
+ const action = hasConflict ? "upserted" : "inserted";
239
+ const skipped = rows.length - inserted;
240
+ if (inserted === rows.length) {
241
+ log.success(
242
+ `${C3.bold}${t.schema}.${t.table}${C3.reset} ${C3.green}${action} ${inserted} rows${C3.reset}`
243
+ );
244
+ } else {
245
+ log.success(
246
+ `${C3.bold}${t.schema}.${t.table}${C3.reset} ${C3.green}${action} ${inserted}${C3.reset}${C3.dim}, skipped ${skipped}${C3.reset}`
169
247
  );
170
248
  }
171
- console.log(
172
- C.green + t.schema + "." + t.table + ": " + inserted + "/" + rows.length + C.reset
173
- );
174
249
  }
175
250
  await sql.end();
176
- console.log(C.green + "Seed completed" + C.reset);
251
+ log.header("Summary");
252
+ log.success(
253
+ `Seeded ${C3.bold}${config.tables.length}${C3.reset} table${config.tables.length === 1 ? "" : "s"}`
254
+ );
177
255
  }
256
+ var C4 = {
257
+ reset: "\x1B[0m",
258
+ dim: "\x1B[2m",
259
+ red: "\x1B[31m"
260
+ };
261
+ var logError3 = (msg) => console.error(`${C4.red}\u2717${C4.reset} ${C4.dim}${msg}${C4.reset}`);
178
262
  var DEFAULT_CONFIG = {
179
263
  seedFileExtensions: [".json"],
180
264
  databaseUrlEnvVar: "DATABASE_URL",
@@ -184,14 +268,16 @@ var DEFAULT_CONFIG = {
184
268
  table: "example_table",
185
269
  schema: "public",
186
270
  primaryKeys: ["id"],
187
- source: "./data/example_table.json"
271
+ source: "./data/example_table.json",
272
+ updateOnConflict: []
188
273
  }
189
274
  ]
190
275
  };
191
276
  function init(configPath) {
192
277
  const resolved = path2.resolve(process.cwd(), configPath);
193
278
  if (fs.existsSync(resolved)) {
194
- throw new Error("Config already exists: " + resolved);
279
+ logError3(`Config file already exists: ${resolved}`);
280
+ throw new Error(`Config already exists: ${resolved}`);
195
281
  }
196
282
  fs.writeFileSync(
197
283
  resolved,
@@ -201,21 +287,30 @@ function init(configPath) {
201
287
  }
202
288
 
203
289
  // src/cli.ts
290
+ var C5 = {
291
+ reset: "\x1B[0m",
292
+ bold: "\x1B[1m",
293
+ green: "\x1B[32m",
294
+ red: "\x1B[31m"
295
+ };
296
+ var logError4 = (err) => console.error(`${C5.red}${C5.bold}Error:${C5.reset} ${String(err)}`);
204
297
  var prog = sade("greenseed");
205
298
  prog.command("push").option("-c, --config <file>", "Config file", "seed.config.json").option("-d, --dbvar <name>", "DB env var override").action(async (opts) => {
206
299
  try {
207
300
  await run(opts);
208
301
  } catch (err) {
209
- console.error("\x1B[31m" + String(err) + "\x1B[0m");
302
+ logError4(err);
210
303
  process.exit(1);
211
304
  }
212
305
  });
213
306
  prog.command("init").option("-c, --config <file>", "Config file", "seed.config.json").action((opts) => {
214
307
  try {
215
308
  init(opts.config);
216
- console.log("\x1B[32mConfig created: " + opts.config + "\x1B[0m");
309
+ console.log(
310
+ `${C5.green}\u2713${C5.reset} Config created: ${C5.bold}${opts.config}${C5.reset}`
311
+ );
217
312
  } catch (err) {
218
- console.error("\x1B[31m" + String(err) + "\x1B[0m");
313
+ logError4(err);
219
314
  process.exit(1);
220
315
  }
221
316
  });
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/db.ts","../src/fs.ts","../src/app.ts","../src/init.ts","../src/cli.ts"],"names":["path","fs"],"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, readFile } 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\n\tlet raw: unknown\n\ttry {\n\t\traw = JSON.parse(readFile(configPath))\n\t} catch (e) {\n\t\tthrow new Error(\n\t\t\t`Failed to load config at ${configPath}: ${e instanceof Error ? e.message : String(e)}`,\n\t\t)\n\t}\n\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 ? opts.dbvar : 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","import fs from \"fs\"\nimport path from \"path\"\n\nconst DEFAULT_CONFIG = {\n\tseedFileExtensions: [\".json\"],\n\tdatabaseUrlEnvVar: \"DATABASE_URL\",\n\tonMissingFile: \"error\",\n\ttables: [\n\t\t{\n\t\t\ttable: \"example_table\",\n\t\t\tschema: \"public\",\n\t\t\tprimaryKeys: [\"id\"],\n\t\t\tsource: \"./data/example_table.json\",\n\t\t},\n\t],\n}\n\nexport function init(configPath: string): void {\n\tconst resolved = path.resolve(process.cwd(), configPath)\n\n\tif (fs.existsSync(resolved)) {\n\t\tthrow new Error(\"Config already exists: \" + resolved)\n\t}\n\n\tfs.writeFileSync(\n\t\tresolved,\n\t\tJSON.stringify(DEFAULT_CONFIG, null, 2) + \"\\n\",\n\t\t\"utf8\",\n\t)\n}\n","#!/usr/bin/env node\nimport sade from \"sade\"\nimport { run } from \"./app\"\nimport { init } from \"./init\"\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\n\t.command(\"init\")\n\t.option(\"-c, --config <file>\", \"Config file\", \"seed.config.json\")\n\t.action((opts) => {\n\t\ttry {\n\t\t\tinit(opts.config)\n\t\t\tconsole.log(\"\\x1b[32mConfig created: \" + opts.config + \"\\x1b[0m\")\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"]}
1
+ {"version":3,"sources":["../src/db.ts","../src/fs.ts","../src/app.ts","../src/init.ts","../src/cli.ts"],"names":["C","logError","path","fs"],"mappings":"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","file":"cli.js","sourcesContent":["import postgres from \"postgres\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tdim: \"\\x1b[2m\",\n\tred: \"\\x1b[31m\",\n}\n\nconst logError = (msg: string) =>\n\tconsole.error(`${C.red}✗${C.reset} ${C.dim}${msg}${C.reset}`)\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\tlogError(\"Database connection failed\")\n\t\tthrow new Error(\"Failed to connect to database\")\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\tlogError(`Failed to check table: ${schema}.${table}`)\n\t\tthrow new Error(`Table check failed: ${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\tlogError(`Table does not exist: ${t.schema}.${t.table}`)\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\tupdateOnConflict: string[],\n): Promise<number> {\n\tif (primaryKeys.length === 0) {\n\t\tlogError(`No primary keys defined for ${schema}.${table}`)\n\t\tthrow new Error(`No primary keys for ${schema}.${table}`)\n\t}\n\n\tconst updateCols = updateOnConflict.filter(\n\t\t(col) => !primaryKeys.includes(col),\n\t)\n\n\tlet q\n\tif (updateCols.length > 0) {\n\t\tconst updates = Object.fromEntries(\n\t\t\tupdateCols.map((col) => [col, sql`excluded.${sql(col)}`]),\n\t\t)\n\n\t\tq = await sql`\n\t\t\tinsert into ${sql(schema + \".\" + table)}\n\t\t\t${sql(rows, columns)}\n\t\t\ton conflict (${sql(primaryKeys)}) do update set\n\t\t\t${sql(updates)}\n\t\t\treturning ${sql(primaryKeys[0] ?? [])}\n\t\t`\n\t} else {\n\t\tq = await sql`\n\t\t\tinsert into ${sql(schema + \".\" + table)}\n\t\t\t${sql(rows, columns)}\n\t\t\ton conflict (${sql(primaryKeys)}) do nothing\n\t\t\treturning ${sql(primaryKeys[0] ?? [])}\n\t\t`\n\t}\n\treturn q.length\n}\n","import fs from \"fs\"\nimport path from \"path\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tdim: \"\\x1b[2m\",\n\tred: \"\\x1b[31m\",\n}\n\nconst logError = (msg: string) =>\n\tconsole.error(`${C.red}✗${C.reset} ${C.dim}${msg}${C.reset}`)\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\tlogError(`Failed to read file: ${p}`)\n\t\tthrow new Error(`File read error: ${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\tlogError(`Source file not found: ${p}`)\n\t\tthrow new Error(`Missing file: ${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\tlogError(`Invalid JSON in file: ${p}`)\n\t\tthrow new Error(`JSON parse error: ${p}`)\n\t}\n\n\tif (!Array.isArray(parsed)) {\n\t\tlogError(`Expected array but got ${typeof parsed}: ${p}`)\n\t\tthrow new Error(`Invalid data format: ${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, readFile } from \"./fs\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tbold: \"\\x1b[1m\",\n\tdim: \"\\x1b[2m\",\n\tgreen: \"\\x1b[32m\",\n\tyellow: \"\\x1b[33m\",\n\tblue: \"\\x1b[34m\",\n\tcyan: \"\\x1b[36m\",\n\tred: \"\\x1b[31m\",\n\tgray: \"\\x1b[90m\",\n}\n\nconst log = {\n\tinfo: (msg: string) => console.log(`${C.blue}ℹ${C.reset} ${msg}`),\n\tsuccess: (msg: string) => console.log(`${C.green}✓${C.reset} ${msg}`),\n\twarn: (msg: string) => console.log(`${C.yellow}⚠${C.reset} ${msg}`),\n\terror: (msg: string) => console.log(`${C.red}✗${C.reset} ${msg}`),\n\tdim: (msg: string) => console.log(`${C.dim}${msg}${C.reset}`),\n\theader: (msg: string) =>\n\t\tconsole.log(`\\n${C.bold}${C.cyan}${msg}${C.reset}\\n`),\n\ttable: (label: string, value: string | number) =>\n\t\tconsole.log(` ${C.dim}${label}:${C.reset} ${C.bold}${value}${C.reset}`),\n\tprogress: (current: number, total: number, label: string) => {\n\t\tconst percentage = Math.round((current / total) * 100)\n\t\tconst bar = \"█\".repeat(Math.floor(percentage / 5))\n\t\tconst empty = \"░\".repeat(20 - Math.floor(percentage / 5))\n\t\tconsole.log(\n\t\t\t` ${C.cyan}${bar}${empty}${C.reset} ${C.bold}${percentage}%${C.reset} ${C.dim}(${current}/${total})${C.reset} ${label}`,\n\t\t)\n\t},\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\tupdateOnConflict: v.optional(v.nullable(v.array(v.string())), null),\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\n\tlog.header(\"🌱 GreenSeed\")\n\n\tlet raw: unknown\n\ttry {\n\t\traw = JSON.parse(readFile(configPath))\n\t} catch (e) {\n\t\tthrow new Error(\n\t\t\t`Failed to load config at ${configPath}: ${e instanceof Error ? e.message : String(e)}`,\n\t\t)\n\t}\n\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 ? opts.dbvar : 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\tlog.info(`Using config: ${C.dim}${configPath}${C.reset}`)\n\tlog.info(`Database: ${C.dim}${dbVar}${C.reset}`)\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\tlog.success(\"Database connection established\")\n\tlog.header(\"Seeding Tables\")\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\tlog.warn(`Skipped ${C.bold}${t.schema}.${t.table}${C.reset} (no data)`)\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\tlog.info(`Seeding ${C.bold}${t.schema}.${t.table}${C.reset}`)\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\tt.updateOnConflict || [],\n\t\t\t)\n\t\t}\n\n\t\tconst hasConflict = t.updateOnConflict && t.updateOnConflict.length > 0\n\t\tconst action = hasConflict ? \"upserted\" : \"inserted\"\n\t\tconst skipped = rows.length - inserted\n\n\t\tif (inserted === rows.length) {\n\t\t\tlog.success(\n\t\t\t\t`${C.bold}${t.schema}.${t.table}${C.reset} ${C.green}${action} ${inserted} rows${C.reset}`,\n\t\t\t)\n\t\t} else {\n\t\t\tlog.success(\n\t\t\t\t`${C.bold}${t.schema}.${t.table}${C.reset} ${C.green}${action} ${inserted}${C.reset}${C.dim}, skipped ${skipped}${C.reset}`,\n\t\t\t)\n\t\t}\n\t}\n\n\tawait sql.end()\n\n\tlog.header(\"Summary\")\n\tlog.success(\n\t\t`Seeded ${C.bold}${config.tables.length}${C.reset} table${config.tables.length === 1 ? \"\" : \"s\"}`,\n\t)\n}\n","import fs from \"fs\"\nimport path from \"path\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tdim: \"\\x1b[2m\",\n\tred: \"\\x1b[31m\",\n}\n\nconst logError = (msg: string) =>\n\tconsole.error(`${C.red}✗${C.reset} ${C.dim}${msg}${C.reset}`)\n\nconst DEFAULT_CONFIG = {\n\tseedFileExtensions: [\".json\"],\n\tdatabaseUrlEnvVar: \"DATABASE_URL\",\n\tonMissingFile: \"error\",\n\ttables: [\n\t\t{\n\t\t\ttable: \"example_table\",\n\t\t\tschema: \"public\",\n\t\t\tprimaryKeys: [\"id\"],\n\t\t\tsource: \"./data/example_table.json\",\n\t\t\tupdateOnConflict: [],\n\t\t},\n\t],\n}\n\nexport function init(configPath: string): void {\n\tconst resolved = path.resolve(process.cwd(), configPath)\n\n\tif (fs.existsSync(resolved)) {\n\t\tlogError(`Config file already exists: ${resolved}`)\n\t\tthrow new Error(`Config already exists: ${resolved}`)\n\t}\n\n\tfs.writeFileSync(\n\t\tresolved,\n\t\tJSON.stringify(DEFAULT_CONFIG, null, 2) + \"\\n\",\n\t\t\"utf8\",\n\t)\n}\n","#!/usr/bin/env node\nimport sade from \"sade\"\nimport { run } from \"./app\"\nimport { init } from \"./init\"\n\nconst C = {\n\treset: \"\\x1b[0m\",\n\tbold: \"\\x1b[1m\",\n\tgreen: \"\\x1b[32m\",\n\tred: \"\\x1b[31m\",\n}\n\nconst logError = (err: unknown) =>\n\tconsole.error(`${C.red}${C.bold}Error:${C.reset} ${String(err)}`)\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\tlogError(err)\n\t\t\tprocess.exit(1)\n\t\t}\n\t})\n\nprog\n\t.command(\"init\")\n\t.option(\"-c, --config <file>\", \"Config file\", \"seed.config.json\")\n\t.action((opts) => {\n\t\ttry {\n\t\t\tinit(opts.config)\n\t\t\tconsole.log(\n\t\t\t\t`${C.green}✓${C.reset} Config created: ${C.bold}${opts.config}${C.reset}`,\n\t\t\t)\n\t\t} catch (err) {\n\t\t\tlogError(err)\n\t\t\tprocess.exit(1)\n\t\t}\n\t})\n\nprog.parse(process.argv)\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "greenseed",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "author": "Mohit Khatri",
5
5
  "main": "./dist/cli.js",
6
6
  "module": "./dist/index.js",