@deessejs/collections 0.3.0 → 0.4.0

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.js CHANGED
@@ -37,167 +37,173 @@ __export(cli_exports, {
37
37
  validatePath: () => validatePath
38
38
  });
39
39
  module.exports = __toCommonJS(cli_exports);
40
- var import_process2 = __toESM(require("process"));
40
+ var import_process = __toESM(require("process"));
41
41
 
42
42
  // src/migrations.ts
43
- var import_child_process = require("child_process");
44
- var import_path = require("path");
45
- var import_process = __toESM(require("process"));
46
- function runCommand(command, args, options = {}) {
47
- return new Promise((resolve2, reject) => {
48
- if (options.verbose) {
49
- console.log(`[collections] Running: ${command} ${args.join(" ")}`);
50
- }
51
- const child = (0, import_child_process.spawn)(command, args, {
52
- stdio: options.verbose ? "inherit" : "pipe",
53
- shell: true,
54
- cwd: import_process.default.cwd()
55
- });
56
- let output = "";
57
- if (!options.verbose) {
58
- child.stdout?.on("data", (data) => {
59
- output += data.toString();
60
- });
61
- child.stderr?.on("data", (data) => {
62
- output += data.toString();
63
- });
64
- }
65
- child.on("close", (code) => {
66
- if (code === 0) {
67
- resolve2(code ?? 0);
68
- } else {
69
- reject(new Error(`Command failed with code ${code}: ${output}`));
70
- }
71
- });
72
- child.on("error", (error) => {
73
- reject(error);
74
- });
75
- });
76
- }
77
- function buildDrizzleConfig(options) {
78
- const config = {
79
- dialect: "postgresql",
80
- schema: options.schemaPath,
81
- out: options.out,
82
- dbCredentials: {
83
- url: options.dbUrl
84
- }
43
+ var import_node_postgres = require("drizzle-orm/node-postgres");
44
+
45
+ // src/schema.ts
46
+ var import_pg_core = require("drizzle-orm/pg-core");
47
+ var buildTable = (collection) => {
48
+ const columns = {
49
+ // Add default id column
50
+ id: (0, import_pg_core.serial)("id").primaryKey()
85
51
  };
86
- if (options.migrationsTable) {
87
- config.migrations = {
88
- table: options.migrationsTable
89
- };
52
+ for (const [fieldName, fieldDef] of Object.entries(collection.fields)) {
53
+ if (fieldName === "id") continue;
54
+ const fieldType = fieldDef.fieldType;
55
+ const fieldTypeName = fieldType.name || fieldType.type || "text";
56
+ switch (fieldTypeName) {
57
+ case "text":
58
+ columns[fieldName] = (0, import_pg_core.text)(fieldName);
59
+ break;
60
+ case "varchar":
61
+ columns[fieldName] = (0, import_pg_core.varchar)(fieldName, { length: 255 });
62
+ break;
63
+ case "number":
64
+ case "integer":
65
+ columns[fieldName] = (0, import_pg_core.integer)(fieldName);
66
+ break;
67
+ case "boolean":
68
+ columns[fieldName] = (0, import_pg_core.boolean)(fieldName);
69
+ break;
70
+ case "timestamp":
71
+ columns[fieldName] = (0, import_pg_core.timestamp)(fieldName);
72
+ break;
73
+ case "uuid":
74
+ columns[fieldName] = (0, import_pg_core.uuid)(fieldName);
75
+ break;
76
+ default:
77
+ columns[fieldName] = (0, import_pg_core.text)(fieldName);
78
+ }
79
+ }
80
+ return (0, import_pg_core.pgTable)(collection.slug, columns);
81
+ };
82
+ var buildSchema = (collections) => {
83
+ const tables = {};
84
+ for (const coll of collections) {
85
+ tables[coll.slug] = buildTable(coll);
90
86
  }
91
- return JSON.stringify(config, null, 2);
87
+ return tables;
88
+ };
89
+
90
+ // src/migrations.ts
91
+ async function getDrizzleKitApi() {
92
+ const api = require("drizzle-kit/api");
93
+ return api;
92
94
  }
93
- var push = async (adapter, _collections, options = {}) => {
94
- const {
95
- verbose = false,
96
- dryRun = false,
97
- out = "./drizzle",
98
- configPath = "./collections/config.ts",
99
- migrationsTable = "__drizzle_collections"
100
- } = options;
101
- const configContent = buildDrizzleConfig({
102
- out,
103
- schemaPath: configPath,
104
- dbUrl: adapter.config.url,
105
- migrationsTable
106
- });
107
- const drizzleConfigPath = (0, import_path.resolve)(import_process.default.cwd(), "./drizzle.config.json");
108
- const { writeFileSync, unlinkSync } = await import("fs");
109
- try {
110
- writeFileSync(drizzleConfigPath, configContent);
111
- const args = ["drizzle-kit", "push"];
112
- if (dryRun) {
113
- args.push("--dry-run");
114
- }
115
- if (verbose) {
116
- args.push("--verbose");
95
+ var push = async (adapter, collections, options = {}) => {
96
+ const { verbose = false, dryRun = false } = options;
97
+ const schema = buildSchema(collections);
98
+ const pool = await adapter.getPool();
99
+ const db = (0, import_node_postgres.drizzle)(pool, { schema });
100
+ const { pushSchema } = await getDrizzleKitApi();
101
+ if (verbose) {
102
+ console.log("[collections] Building schema from collections...");
103
+ console.log("[collections] Tables:", Object.keys(schema).join(", "));
104
+ }
105
+ const result = await pushSchema(schema, db);
106
+ if (verbose) {
107
+ if (result.warnings.length > 0) {
108
+ console.log("[collections] Warnings:");
109
+ result.warnings.forEach((w) => console.log(" -", w));
117
110
  }
118
- await runCommand("npx", args, { verbose });
111
+ console.log("[collections] Statements to execute:", result.statementsToExecute.length);
112
+ }
113
+ if (dryRun) {
114
+ console.log("[collections] Dry run - not applying changes");
119
115
  if (verbose) {
120
- console.log("[collections] Schema pushed successfully");
121
- }
122
- } finally {
123
- try {
124
- unlinkSync(drizzleConfigPath);
125
- } catch {
116
+ console.log("[collections] SQL statements:");
117
+ result.statementsToExecute.forEach((stmt) => console.log(" ", stmt));
126
118
  }
119
+ return;
120
+ }
121
+ await result.apply();
122
+ if (verbose) {
123
+ console.log("[collections] Schema pushed successfully");
127
124
  }
128
125
  };
129
- var generate = async (adapter, _collections, options = {}) => {
130
- const {
131
- verbose = false,
132
- out = "./drizzle",
133
- configPath = "./collections/config.ts",
134
- migrationsTable = "__drizzle_collections"
135
- } = options;
136
- const configContent = buildDrizzleConfig({
137
- out,
138
- schemaPath: configPath,
139
- dbUrl: adapter.config.url,
140
- migrationsTable
141
- });
142
- const drizzleConfigPath = (0, import_path.resolve)(import_process.default.cwd(), "./drizzle.config.json");
143
- const { writeFileSync, unlinkSync } = await import("fs");
126
+ var generate = async (_adapter, collections, options = {}) => {
127
+ const { verbose = false, out = "./drizzle" } = options;
128
+ const schema = buildSchema(collections);
129
+ const { generateDrizzleJson } = await getDrizzleKitApi();
130
+ if (verbose) {
131
+ console.log("[collections] Building schema from collections...");
132
+ console.log("[collections] Tables:", Object.keys(schema).join(", "));
133
+ }
134
+ const currentSnapshot = generateDrizzleJson(schema);
135
+ if (verbose) {
136
+ console.log("[collections] Current snapshot ID:", currentSnapshot.id);
137
+ }
138
+ const migrationSQL = [
139
+ "-- Generated migration",
140
+ `-- Snapshot: ${currentSnapshot.id}`,
141
+ "",
142
+ "-- Tables will be created based on current collections schema",
143
+ ...currentSnapshot.tables?.map((table) => `-- Table: ${table}`) ?? []
144
+ ];
145
+ const { writeFileSync, mkdirSync } = await import("fs");
144
146
  try {
145
- writeFileSync(drizzleConfigPath, configContent);
146
- const args = ["drizzle-kit", "generate"];
147
- if (verbose) {
148
- args.push("--verbose");
149
- }
150
- await runCommand("npx", args, { verbose });
151
- if (verbose) {
152
- console.log("[collections] Migrations generated successfully");
153
- }
154
- } finally {
155
- try {
156
- unlinkSync(drizzleConfigPath);
157
- } catch {
158
- }
147
+ mkdirSync(out, { recursive: true });
148
+ } catch {
149
+ }
150
+ const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
151
+ const filename = `${out}/migration-${timestamp2}.sql`;
152
+ writeFileSync(filename, migrationSQL.join("\n"));
153
+ if (verbose) {
154
+ console.log("[collections] Migration written to:", filename);
159
155
  }
160
156
  };
161
157
  var migrate = async (adapter, options = {}) => {
162
- const {
163
- verbose = false,
164
- out = "./drizzle",
165
- configPath = "./collections/config.ts",
166
- migrationsTable = "__drizzle_collections"
167
- } = options;
168
- const configContent = buildDrizzleConfig({
169
- out,
170
- schemaPath: configPath,
171
- dbUrl: adapter.config.url,
172
- migrationsTable
173
- });
174
- const drizzleConfigPath = (0, import_path.resolve)(import_process.default.cwd(), "./drizzle.config.json");
175
- const { writeFileSync, unlinkSync } = await import("fs");
158
+ const { verbose = false } = options;
159
+ const pool = await adapter.getPool();
160
+ if (verbose) {
161
+ console.log("[collections] Applying migrations...");
162
+ }
163
+ const { readdirSync, readFileSync } = await import("fs");
164
+ const migrationsPath = adapter.config.migrationsPath ?? "./migrations";
176
165
  try {
177
- writeFileSync(drizzleConfigPath, configContent);
178
- const args = ["drizzle-kit", "migrate"];
179
- if (verbose) {
180
- args.push("--verbose");
166
+ const files = readdirSync(migrationsPath).filter((f) => f.endsWith(".sql")).sort();
167
+ if (files.length === 0) {
168
+ if (verbose) {
169
+ console.log("[collections] No migration files found");
170
+ }
171
+ return;
172
+ }
173
+ for (const file of files) {
174
+ if (verbose) {
175
+ console.log("[collections] Applying migration:", file);
176
+ }
177
+ const sql = readFileSync(`${migrationsPath}/${file}`, "utf-8");
178
+ await pool.query(sql);
181
179
  }
182
- await runCommand("npx", args, { verbose });
183
180
  if (verbose) {
184
181
  console.log("[collections] Migrations applied successfully");
185
182
  }
186
- } finally {
187
- try {
188
- unlinkSync(drizzleConfigPath);
189
- } catch {
183
+ } catch (error) {
184
+ if (verbose) {
185
+ console.log("[collections] No migrations directory or error:", error);
190
186
  }
191
187
  }
192
188
  };
193
189
 
194
190
  // src/adapter.ts
195
191
  var pgAdapter = (config) => {
192
+ let pool = null;
196
193
  return {
197
194
  type: "postgres",
198
195
  config: {
199
196
  url: config.url,
200
197
  migrationsPath: config.migrationsPath ?? "./migrations"
198
+ },
199
+ getPool: async () => {
200
+ if (!pool) {
201
+ const { Pool } = await import("pg");
202
+ pool = new Pool({
203
+ connectionString: config.url
204
+ });
205
+ }
206
+ return pool;
201
207
  }
202
208
  };
203
209
  };
@@ -215,11 +221,9 @@ Commands:
215
221
  db:migrate Apply pending migrations
216
222
 
217
223
  Global Options:
218
- --config <path> Path to collections config file (default: ./collections/config.ts)
219
- --out <path> Output directory for migrations (default: ./drizzle)
220
- --migrations-table Custom migrations table name (default: __drizzle_collections)
221
- --verbose Enable verbose output
222
- --dry-run Dry run mode (only for db:push)
224
+ --out <path> Output directory for migrations (default: ./drizzle)
225
+ --verbose Enable verbose output
226
+ --dry-run Dry run mode (only for db:push)
223
227
 
224
228
  Examples:
225
229
  collections db:push
@@ -227,23 +231,20 @@ Examples:
227
231
  collections db:generate
228
232
  collections db:migrate --verbose
229
233
  collections db:push --dry-run
230
- collections db:push --config ./my-config.ts --out ./my-drizzle
231
234
  `);
232
235
  }
233
236
  function validatePath(path, name) {
234
237
  if (path.includes("..")) {
235
238
  console.error(`Error: ${name} path cannot contain ".." (path traversal not allowed)`);
236
- import_process2.default.exit(1);
239
+ import_process.default.exit(1);
237
240
  }
238
241
  }
239
242
  function parseArgs() {
240
- const args = import_process2.default.argv.slice(2);
243
+ const args = import_process.default.argv.slice(2);
241
244
  const options = {
242
245
  verbose: false,
243
246
  dryRun: false,
244
- out: "./drizzle",
245
- configPath: "./collections/config.ts",
246
- migrationsTable: "__drizzle_collections"
247
+ out: "./drizzle"
247
248
  };
248
249
  let command = null;
249
250
  let dryRunWarningShown = false;
@@ -264,24 +265,13 @@ function parseArgs() {
264
265
  if (!outValue || outValue.startsWith("-")) {
265
266
  console.error("Error: --out requires a value");
266
267
  printUsage();
267
- import_process2.default.exit(1);
268
+ import_process.default.exit(1);
268
269
  }
269
270
  validatePath(outValue, "--out");
270
271
  options.out = outValue;
271
- } else if (arg === "--config" || arg === "-c") {
272
- const configValue = args[++i];
273
- if (!configValue || configValue.startsWith("-")) {
274
- console.error("Error: --config requires a value");
275
- printUsage();
276
- import_process2.default.exit(1);
277
- }
278
- validatePath(configValue, "--config");
279
- options.configPath = configValue;
280
- } else if (arg === "--migrations-table") {
281
- options.migrationsTable = args[++i];
282
272
  } else if (arg === "--help" || arg === "-h") {
283
273
  printUsage();
284
- import_process2.default.exit(0);
274
+ import_process.default.exit(0);
285
275
  }
286
276
  }
287
277
  return { command, options };
@@ -291,7 +281,7 @@ async function main() {
291
281
  if (!command) {
292
282
  console.error("Error: No command specified");
293
283
  printUsage();
294
- import_process2.default.exit(1);
284
+ import_process.default.exit(1);
295
285
  }
296
286
  if (options.verbose) {
297
287
  console.log("[collections] Command:", command);
@@ -301,11 +291,11 @@ async function main() {
301
291
  console.warn("Warning: --dry-run is only applicable to db:push command, ignoring");
302
292
  options.dryRun = false;
303
293
  }
304
- const dbUrl = import_process2.default.env.DATABASE_URL;
294
+ const dbUrl = import_process.default.env.DATABASE_URL;
305
295
  if (!dbUrl) {
306
296
  console.error("Error: DATABASE_URL environment variable is required");
307
297
  console.error('Set it with: export DATABASE_URL="postgres://user:pass@localhost:5432/db"');
308
- import_process2.default.exit(1);
298
+ import_process.default.exit(1);
309
299
  }
310
300
  const adapter = pgAdapter({ url: dbUrl });
311
301
  try {
@@ -334,14 +324,14 @@ async function main() {
334
324
  default:
335
325
  console.error(`Error: Unknown command "${command}"`);
336
326
  printUsage();
337
- import_process2.default.exit(1);
327
+ import_process.default.exit(1);
338
328
  }
339
329
  } catch (error) {
340
330
  console.error("Error:", error instanceof Error ? error.message : error);
341
- import_process2.default.exit(1);
331
+ import_process.default.exit(1);
342
332
  }
343
333
  }
344
- if (import_process2.default.argv[1]?.includes("cli")) {
334
+ if (import_process.default.argv[1]?.includes("cli")) {
345
335
  main();
346
336
  }
347
337
  // Annotate the CommonJS export names for ESM import in node:
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/migrations.ts","../src/adapter.ts"],"sourcesContent":["#!/usr/bin/env node\r\n\r\n/**\r\n * CLI entry point for @deessejs/collections\r\n *\r\n * Provides commands for database migrations and schema management\r\n */\r\n\r\nimport process from 'process'\r\n\r\nimport { push, generate, migrate, type MigrationOptions } from './migrations'\r\nimport { pgAdapter } from './adapter'\r\n\r\n/**\r\n * Print usage information\r\n */\r\nfunction printUsage(): void {\r\n console.log(`\r\n@deessejs/collections CLI\r\n\r\nUsage: collections <command> [options]\r\n\r\nCommands:\r\n db:push Push schema to database (development mode)\r\n db:generate Generate migration files\r\n db:migrate Apply pending migrations\r\n\r\nGlobal Options:\r\n --config <path> Path to collections config file (default: ./collections/config.ts)\r\n --out <path> Output directory for migrations (default: ./drizzle)\r\n --migrations-table Custom migrations table name (default: __drizzle_collections)\r\n --verbose Enable verbose output\r\n --dry-run Dry run mode (only for db:push)\r\n\r\nExamples:\r\n collections db:push\r\n collections db:push --verbose\r\n collections db:generate\r\n collections db:migrate --verbose\r\n collections db:push --dry-run\r\n collections db:push --config ./my-config.ts --out ./my-drizzle\r\n`)\r\n}\r\n\r\n/**\r\n * Validate path to prevent path traversal attacks\r\n */\r\nfunction validatePath(path: string, name: string): void {\r\n if (path.includes('..')) {\r\n console.error(`Error: ${name} path cannot contain \"..\" (path traversal not allowed)`)\r\n process.exit(1)\r\n }\r\n}\r\n\r\n/**\r\n * Parse command line arguments\r\n */\r\nfunction parseArgs(): {\r\n command: string | null\r\n options: MigrationOptions\r\n} {\r\n const args = process.argv.slice(2)\r\n const options: MigrationOptions = {\r\n verbose: false,\r\n dryRun: false,\r\n out: './drizzle',\r\n configPath: './collections/config.ts',\r\n migrationsTable: '__drizzle_collections'\r\n }\r\n\r\n let command: string | null = null\r\n let dryRunWarningShown = false\r\n\r\n for (let i = 0; i < args.length; i++) {\r\n const arg = args[i]\r\n\r\n if (arg === 'db:push' || arg === 'db:generate' || arg === 'db:migrate') {\r\n command = arg\r\n } else if (arg === '--verbose' || arg === '-v') {\r\n options.verbose = true\r\n } else if (arg === '--dry-run') {\r\n options.dryRun = true\r\n // Warn if --dry-run is used with non-push command\r\n if (command && command !== 'db:push' && !dryRunWarningShown) {\r\n console.warn('Warning: --dry-run is only applicable to db:push command')\r\n dryRunWarningShown = true\r\n }\r\n } else if (arg === '--out' || arg === '-o') {\r\n const outValue = args[++i]\r\n if (!outValue || outValue.startsWith('-')) {\r\n console.error('Error: --out requires a value')\r\n printUsage()\r\n process.exit(1)\r\n }\r\n validatePath(outValue, '--out')\r\n options.out = outValue\r\n } else if (arg === '--config' || arg === '-c') {\r\n const configValue = args[++i]\r\n if (!configValue || configValue.startsWith('-')) {\r\n console.error('Error: --config requires a value')\r\n printUsage()\r\n process.exit(1)\r\n }\r\n validatePath(configValue, '--config')\r\n options.configPath = configValue\r\n } else if (arg === '--migrations-table') {\r\n options.migrationsTable = args[++i]\r\n } else if (arg === '--help' || arg === '-h') {\r\n printUsage()\r\n process.exit(0)\r\n }\r\n }\r\n\r\n return { command, options }\r\n}\r\n\r\n/**\r\n * Main CLI function\r\n */\r\nasync function main(): Promise<void> {\r\n const { command, options } = parseArgs()\r\n\r\n if (!command) {\r\n console.error('Error: No command specified')\r\n printUsage()\r\n process.exit(1)\r\n }\r\n\r\n if (options.verbose) {\r\n console.log('[collections] Command:', command)\r\n console.log('[collections] Options:', options)\r\n }\r\n\r\n // Validate --dry-run is only used with db:push\r\n if (options.dryRun && command !== 'db:push') {\r\n console.warn('Warning: --dry-run is only applicable to db:push command, ignoring')\r\n options.dryRun = false\r\n }\r\n\r\n // Get database URL from environment or prompt\r\n const dbUrl = process.env.DATABASE_URL\r\n if (!dbUrl) {\r\n console.error('Error: DATABASE_URL environment variable is required')\r\n console.error('Set it with: export DATABASE_URL=\"postgres://user:pass@localhost:5432/db\"')\r\n process.exit(1)\r\n }\r\n\r\n const adapter = pgAdapter({ url: dbUrl })\r\n\r\n try {\r\n switch (command) {\r\n case 'db:push':\r\n if (options.verbose) {\r\n console.log('[collections] Pushing schema to database...')\r\n }\r\n await push(adapter, [], options)\r\n console.log('Schema pushed successfully')\r\n break\r\n\r\n case 'db:generate':\r\n if (options.verbose) {\r\n console.log('[collections] Generating migrations...')\r\n }\r\n await generate(adapter, [], options)\r\n console.log('Migrations generated successfully')\r\n break\r\n\r\n case 'db:migrate':\r\n if (options.verbose) {\r\n console.log('[collections] Applying migrations...')\r\n }\r\n await migrate(adapter, options)\r\n console.log('Migrations applied successfully')\r\n break\r\n\r\n default:\r\n console.error(`Error: Unknown command \"${command}\"`)\r\n printUsage()\r\n process.exit(1)\r\n }\r\n } catch (error) {\r\n console.error('Error:', error instanceof Error ? error.message : error)\r\n process.exit(1)\r\n }\r\n}\r\n\r\n// Export for testing\r\nexport { main, parseArgs, printUsage, validatePath }\r\n\r\n// Run if executed directly (not when imported for tests)\r\nif (process.argv[1]?.includes('cli')) {\r\n main()\r\n}\r\n","import { spawn } from 'child_process'\r\nimport { resolve } from 'path'\r\nimport process from 'process'\r\n\r\nimport type { PgAdapter } from './adapter'\r\nimport type { Collection } from './collection'\r\n\r\n/**\r\n * Migration options\r\n */\r\nexport type MigrationOptions = {\r\n /** Path to the config file */\r\n configPath?: string\r\n /** Output directory for generated files */\r\n out?: string\r\n /** Enable verbose output */\r\n verbose?: boolean\r\n /** Dry run mode - don't apply changes */\r\n dryRun?: boolean\r\n /** Custom migrations table name */\r\n migrationsTable?: string\r\n}\r\n\r\n/**\r\n * Run a command and return a promise\r\n */\r\nfunction runCommand(command: string, args: string[], options: { verbose?: boolean } = {}): Promise<number> {\r\n return new Promise((resolve, reject) => {\r\n if (options.verbose) {\r\n console.log(`[collections] Running: ${command} ${args.join(' ')}`)\r\n }\r\n\r\n const child = spawn(command, args, {\r\n stdio: options.verbose ? 'inherit' : 'pipe',\r\n shell: true,\r\n cwd: process.cwd()\r\n })\r\n\r\n let output = ''\r\n if (!options.verbose) {\r\n child.stdout?.on('data', (data) => {\r\n output += data.toString()\r\n })\r\n child.stderr?.on('data', (data) => {\r\n output += data.toString()\r\n })\r\n }\r\n\r\n child.on('close', (code) => {\r\n if (code === 0) {\r\n resolve(code ?? 0)\r\n } else {\r\n reject(new Error(`Command failed with code ${code}: ${output}`))\r\n }\r\n })\r\n\r\n child.on('error', (error) => {\r\n reject(error)\r\n })\r\n })\r\n}\r\n\r\n/**\r\n * Build drizzle-kit config file content\r\n */\r\nfunction buildDrizzleConfig(options: {\r\n out: string\r\n schemaPath: string\r\n dbUrl: string\r\n migrationsTable?: string\r\n}): string {\r\n const config: Record<string, unknown> = {\r\n dialect: 'postgresql',\r\n schema: options.schemaPath,\r\n out: options.out,\r\n dbCredentials: {\r\n url: options.dbUrl\r\n }\r\n }\r\n\r\n if (options.migrationsTable) {\r\n config.migrations = {\r\n table: options.migrationsTable\r\n }\r\n }\r\n\r\n return JSON.stringify(config, null, 2)\r\n}\r\n\r\n/**\r\n * Push schema to database (development mode)\r\n *\r\n * Uses drizzle-kit CLI to push schema changes to the database\r\n */\r\nexport const push = async (\r\n adapter: PgAdapter,\r\n _collections: Collection[],\r\n options: MigrationOptions = {}\r\n): Promise<void> => {\r\n const {\r\n verbose = false,\r\n dryRun = false,\r\n out = './drizzle',\r\n configPath = './collections/config.ts',\r\n migrationsTable = '__drizzle_collections'\r\n } = options\r\n\r\n // Build temporary drizzle config\r\n const configContent = buildDrizzleConfig({\r\n out,\r\n schemaPath: configPath,\r\n dbUrl: adapter.config.url,\r\n migrationsTable\r\n })\r\n\r\n const drizzleConfigPath = resolve(process.cwd(), './drizzle.config.json')\r\n const { writeFileSync, unlinkSync } = await import('fs')\r\n\r\n try {\r\n // Write config file\r\n writeFileSync(drizzleConfigPath, configContent)\r\n\r\n const args = ['drizzle-kit', 'push']\r\n\r\n if (dryRun) {\r\n args.push('--dry-run')\r\n }\r\n\r\n if (verbose) {\r\n args.push('--verbose')\r\n }\r\n\r\n await runCommand('npx', args, { verbose })\r\n\r\n if (verbose) {\r\n console.log('[collections] Schema pushed successfully')\r\n }\r\n } finally {\r\n // Cleanup config file\r\n try {\r\n unlinkSync(drizzleConfigPath)\r\n } catch {\r\n // Ignore cleanup errors\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Generate migration files\r\n *\r\n * Uses drizzle-kit CLI to create migration files\r\n */\r\nexport const generate = async (\r\n adapter: PgAdapter,\r\n _collections: Collection[],\r\n options: MigrationOptions = {}\r\n): Promise<void> => {\r\n const {\r\n verbose = false,\r\n out = './drizzle',\r\n configPath = './collections/config.ts',\r\n migrationsTable = '__drizzle_collections'\r\n } = options\r\n\r\n // Build temporary drizzle config\r\n const configContent = buildDrizzleConfig({\r\n out,\r\n schemaPath: configPath,\r\n dbUrl: adapter.config.url,\r\n migrationsTable\r\n })\r\n\r\n const drizzleConfigPath = resolve(process.cwd(), './drizzle.config.json')\r\n const { writeFileSync, unlinkSync } = await import('fs')\r\n\r\n try {\r\n // Write config file\r\n writeFileSync(drizzleConfigPath, configContent)\r\n\r\n const args = ['drizzle-kit', 'generate']\r\n\r\n if (verbose) {\r\n args.push('--verbose')\r\n }\r\n\r\n await runCommand('npx', args, { verbose })\r\n\r\n if (verbose) {\r\n console.log('[collections] Migrations generated successfully')\r\n }\r\n } finally {\r\n // Cleanup config file\r\n try {\r\n unlinkSync(drizzleConfigPath)\r\n } catch {\r\n // Ignore cleanup errors\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Apply migrations\r\n *\r\n * Uses drizzle-kit CLI to apply pending migrations\r\n */\r\nexport const migrate = async (\r\n adapter: PgAdapter,\r\n options: MigrationOptions = {}\r\n): Promise<void> => {\r\n const {\r\n verbose = false,\r\n out = './drizzle',\r\n configPath = './collections/config.ts',\r\n migrationsTable = '__drizzle_collections'\r\n } = options\r\n\r\n // Build temporary drizzle config\r\n const configContent = buildDrizzleConfig({\r\n out,\r\n schemaPath: configPath,\r\n dbUrl: adapter.config.url,\r\n migrationsTable\r\n })\r\n\r\n const drizzleConfigPath = resolve(process.cwd(), './drizzle.config.json')\r\n const { writeFileSync, unlinkSync } = await import('fs')\r\n\r\n try {\r\n // Write config file\r\n writeFileSync(drizzleConfigPath, configContent)\r\n\r\n const args = ['drizzle-kit', 'migrate']\r\n\r\n if (verbose) {\r\n args.push('--verbose')\r\n }\r\n\r\n await runCommand('npx', args, { verbose })\r\n\r\n if (verbose) {\r\n console.log('[collections] Migrations applied successfully')\r\n }\r\n } finally {\r\n // Cleanup config file\r\n try {\r\n unlinkSync(drizzleConfigPath)\r\n } catch {\r\n // Ignore cleanup errors\r\n }\r\n }\r\n}\r\n","/**\r\n * PostgreSQL adapter configuration\r\n */\r\nexport type PgAdapterConfig = {\r\n url: string\r\n migrationsPath?: string\r\n}\r\n\r\n/**\r\n * PostgreSQL adapter\r\n */\r\nexport interface PgAdapter {\r\n type: 'postgres'\r\n config: PgAdapterConfig\r\n}\r\n\r\n/**\r\n * Database adapter type\r\n */\r\nexport type DatabaseAdapter = PgAdapter\r\n\r\n/**\r\n * Creates a PostgreSQL adapter\r\n *\r\n * @example\r\n * const adapter = pgAdapter({\r\n * url: 'postgres://user:pass@localhost:5432/db'\r\n * })\r\n */\r\nexport const pgAdapter = (config: PgAdapterConfig): PgAdapter => {\r\n return {\r\n type: 'postgres',\r\n config: {\r\n url: config.url,\r\n migrationsPath: config.migrationsPath ?? './migrations'\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["import_process","resolve","process","process","process"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/migrations.ts","../src/schema.ts","../src/adapter.ts"],"sourcesContent":["#!/usr/bin/env node\r\n\r\n/**\r\n * CLI entry point for @deessejs/collections\r\n *\r\n * Provides commands for database migrations and schema management\r\n */\r\n\r\nimport process from 'process'\r\n\r\nimport { push, generate, migrate, type MigrationOptions } from './migrations'\r\nimport { pgAdapter } from './adapter'\r\n\r\n/**\r\n * Print usage information\r\n */\r\nfunction printUsage(): void {\r\n console.log(`\r\n@deessejs/collections CLI\r\n\r\nUsage: collections <command> [options]\r\n\r\nCommands:\r\n db:push Push schema to database (development mode)\r\n db:generate Generate migration files\r\n db:migrate Apply pending migrations\r\n\r\nGlobal Options:\r\n --out <path> Output directory for migrations (default: ./drizzle)\r\n --verbose Enable verbose output\r\n --dry-run Dry run mode (only for db:push)\r\n\r\nExamples:\r\n collections db:push\r\n collections db:push --verbose\r\n collections db:generate\r\n collections db:migrate --verbose\r\n collections db:push --dry-run\r\n`)\r\n}\r\n\r\n/**\r\n * Validate path to prevent path traversal attacks\r\n */\r\nfunction validatePath(path: string, name: string): void {\r\n if (path.includes('..')) {\r\n console.error(`Error: ${name} path cannot contain \"..\" (path traversal not allowed)`)\r\n process.exit(1)\r\n }\r\n}\r\n\r\n/**\r\n * Parse command line arguments\r\n */\r\nfunction parseArgs(): {\r\n command: string | null\r\n options: MigrationOptions\r\n} {\r\n const args = process.argv.slice(2)\r\n const options: MigrationOptions = {\r\n verbose: false,\r\n dryRun: false,\r\n out: './drizzle'\r\n }\r\n\r\n let command: string | null = null\r\n let dryRunWarningShown = false\r\n\r\n for (let i = 0; i < args.length; i++) {\r\n const arg = args[i]\r\n\r\n if (arg === 'db:push' || arg === 'db:generate' || arg === 'db:migrate') {\r\n command = arg\r\n } else if (arg === '--verbose' || arg === '-v') {\r\n options.verbose = true\r\n } else if (arg === '--dry-run') {\r\n options.dryRun = true\r\n // Warn if --dry-run is used with non-push command\r\n if (command && command !== 'db:push' && !dryRunWarningShown) {\r\n console.warn('Warning: --dry-run is only applicable to db:push command')\r\n dryRunWarningShown = true\r\n }\r\n } else if (arg === '--out' || arg === '-o') {\r\n const outValue = args[++i]\r\n if (!outValue || outValue.startsWith('-')) {\r\n console.error('Error: --out requires a value')\r\n printUsage()\r\n process.exit(1)\r\n }\r\n validatePath(outValue, '--out')\r\n options.out = outValue\r\n } else if (arg === '--help' || arg === '-h') {\r\n printUsage()\r\n process.exit(0)\r\n }\r\n }\r\n\r\n return { command, options }\r\n}\r\n\r\n/**\r\n * Main CLI function\r\n */\r\nasync function main(): Promise<void> {\r\n const { command, options } = parseArgs()\r\n\r\n if (!command) {\r\n console.error('Error: No command specified')\r\n printUsage()\r\n process.exit(1)\r\n }\r\n\r\n if (options.verbose) {\r\n console.log('[collections] Command:', command)\r\n console.log('[collections] Options:', options)\r\n }\r\n\r\n // Validate --dry-run is only used with db:push\r\n if (options.dryRun && command !== 'db:push') {\r\n console.warn('Warning: --dry-run is only applicable to db:push command, ignoring')\r\n options.dryRun = false\r\n }\r\n\r\n // Get database URL from environment or prompt\r\n const dbUrl = process.env.DATABASE_URL\r\n if (!dbUrl) {\r\n console.error('Error: DATABASE_URL environment variable is required')\r\n console.error('Set it with: export DATABASE_URL=\"postgres://user:pass@localhost:5432/db\"')\r\n process.exit(1)\r\n }\r\n\r\n const adapter = pgAdapter({ url: dbUrl })\r\n\r\n try {\r\n switch (command) {\r\n case 'db:push':\r\n if (options.verbose) {\r\n console.log('[collections] Pushing schema to database...')\r\n }\r\n await push(adapter, [], options)\r\n console.log('Schema pushed successfully')\r\n break\r\n\r\n case 'db:generate':\r\n if (options.verbose) {\r\n console.log('[collections] Generating migrations...')\r\n }\r\n await generate(adapter, [], options)\r\n console.log('Migrations generated successfully')\r\n break\r\n\r\n case 'db:migrate':\r\n if (options.verbose) {\r\n console.log('[collections] Applying migrations...')\r\n }\r\n await migrate(adapter, options)\r\n console.log('Migrations applied successfully')\r\n break\r\n\r\n default:\r\n console.error(`Error: Unknown command \"${command}\"`)\r\n printUsage()\r\n process.exit(1)\r\n }\r\n } catch (error) {\r\n console.error('Error:', error instanceof Error ? error.message : error)\r\n process.exit(1)\r\n }\r\n}\r\n\r\n// Export for testing\r\nexport { main, parseArgs, printUsage, validatePath }\r\n\r\n// Run if executed directly (not when imported for tests)\r\nif (process.argv[1]?.includes('cli')) {\r\n main()\r\n}\r\n","import { drizzle } from 'drizzle-orm/node-postgres'\r\n\r\nimport type { PgAdapter } from './adapter'\r\nimport type { Collection } from './collection'\r\nimport { buildSchema } from './schema'\r\n\r\n/**\r\n * Get drizzle-kit API lazily to avoid import errors during module load\r\n */\r\nasync function getDrizzleKitApi() {\r\n // eslint-disable-next-line @typescript-eslint/no-var-requires\r\n const api = require('drizzle-kit/api')\r\n return api\r\n}\r\n\r\n/**\r\n * Migration options\r\n */\r\nexport type MigrationOptions = {\r\n /** Output directory for generated files */\r\n out?: string\r\n /** Enable verbose output */\r\n verbose?: boolean\r\n /** Dry run mode - don't apply changes */\r\n dryRun?: boolean\r\n}\r\n\r\n/**\r\n * Push schema to database (development mode)\r\n *\r\n * Uses drizzle-kit programmatic API to push schema changes to the database\r\n *\r\n * @example\r\n * import { push } from '@deessejs/collections'\r\n * import { pgAdapter } from '@deessejs/collections'\r\n *\r\n * const adapter = pgAdapter({ url: process.env.DATABASE_URL })\r\n * await push(adapter, collections)\r\n */\r\nexport const push = async (\r\n adapter: PgAdapter,\r\n collections: Collection[],\r\n options: MigrationOptions = {}\r\n): Promise<void> => {\r\n const { verbose = false, dryRun = false } = options\r\n\r\n // Build schema from collections\r\n const schema = buildSchema(collections)\r\n\r\n // Get pool and create drizzle instance\r\n const pool = await adapter.getPool()\r\n const db = drizzle(pool, { schema })\r\n\r\n // Use drizzle-kit API\r\n const { pushSchema } = await getDrizzleKitApi()\r\n\r\n if (verbose) {\r\n console.log('[collections] Building schema from collections...')\r\n console.log('[collections] Tables:', Object.keys(schema).join(', '))\r\n }\r\n\r\n // Use pushSchema directly\r\n const result = await pushSchema(schema as Record<string, unknown>, db)\r\n\r\n if (verbose) {\r\n if (result.warnings.length > 0) {\r\n console.log('[collections] Warnings:')\r\n result.warnings.forEach((w: string) => console.log(' -', w))\r\n }\r\n console.log('[collections] Statements to execute:', result.statementsToExecute.length)\r\n }\r\n\r\n if (dryRun) {\r\n console.log('[collections] Dry run - not applying changes')\r\n if (verbose) {\r\n console.log('[collections] SQL statements:')\r\n result.statementsToExecute.forEach((stmt: string) => console.log(' ', stmt))\r\n }\r\n return\r\n }\r\n\r\n // Apply changes\r\n await result.apply()\r\n\r\n if (verbose) {\r\n console.log('[collections] Schema pushed successfully')\r\n }\r\n}\r\n\r\n/**\r\n * Generate migration files\r\n *\r\n * Uses drizzle-kit programmatic API to generate migration SQL files\r\n *\r\n * @example\r\n * import { generate } from '@deessejs/collections'\r\n * import { pgAdapter } from '@deessejs/collections'\r\n *\r\n * const adapter = pgAdapter({ url: process.env.DATABASE_URL })\r\n * await generate(adapter, collections, { out: './migrations' })\r\n */\r\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\r\nexport const generate = async (\r\n _adapter: PgAdapter,\r\n collections: Collection[],\r\n options: MigrationOptions = {}\r\n): Promise<void> => {\r\n const { verbose = false, out = './drizzle' } = options\r\n\r\n // Build schema from collections\r\n const schema = buildSchema(collections)\r\n\r\n // Use drizzle-kit API\r\n const { generateDrizzleJson } = await getDrizzleKitApi()\r\n\r\n if (verbose) {\r\n console.log('[collections] Building schema from collections...')\r\n console.log('[collections] Tables:', Object.keys(schema).join(', '))\r\n }\r\n\r\n // Generate current schema snapshot\r\n const currentSnapshot = generateDrizzleJson(schema as Record<string, unknown>)\r\n\r\n // For now, we'll create a basic migration\r\n // In a full implementation, we'd need to:\r\n // 1. Read existing migrations from the database\r\n // 2. Get the previous snapshot\r\n // 3. Generate migration between prev and current\r\n\r\n if (verbose) {\r\n console.log('[collections] Current snapshot ID:', currentSnapshot.id)\r\n }\r\n\r\n // For simplicity, we'll just output the current schema as a migration\r\n // This is a simplified version - full implementation would track migrations\r\n const migrationSQL = [\r\n '-- Generated migration',\r\n `-- Snapshot: ${currentSnapshot.id}`,\r\n '',\r\n '-- Tables will be created based on current collections schema',\r\n ...currentSnapshot.tables?.map((table: string) => `-- Table: ${table}`) ?? []\r\n ]\r\n\r\n // Write to file\r\n const { writeFileSync, mkdirSync } = await import('fs')\r\n try {\r\n mkdirSync(out, { recursive: true })\r\n } catch {\r\n // Directory might already exist\r\n }\r\n\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-')\r\n const filename = `${out}/migration-${timestamp}.sql`\r\n\r\n writeFileSync(filename, migrationSQL.join('\\n'))\r\n\r\n if (verbose) {\r\n console.log('[collections] Migration written to:', filename)\r\n }\r\n}\r\n\r\n/**\r\n * Apply migrations\r\n *\r\n * Uses drizzle-kit programmatic API to apply pending migrations\r\n *\r\n * @example\r\n * import { migrate } from '@deessejs/collections'\r\n * import { pgAdapter } from '@deessejs/collections'\r\n *\r\n * const adapter = pgAdapter({ url: process.env.DATABASE_URL })\r\n * await migrate(adapter)\r\n */\r\nexport const migrate = async (\r\n adapter: PgAdapter,\r\n options: MigrationOptions = {}\r\n): Promise<void> => {\r\n const { verbose = false } = options\r\n\r\n // Get pool\r\n const pool = await adapter.getPool()\r\n\r\n if (verbose) {\r\n console.log('[collections] Applying migrations...')\r\n }\r\n\r\n // For migrations, we use the same approach as push\r\n // The migrations table tracks which migrations have been applied\r\n // This is a simplified version\r\n\r\n // Get all migration files\r\n const { readdirSync, readFileSync } = await import('fs')\r\n const migrationsPath = adapter.config.migrationsPath ?? './migrations'\r\n\r\n try {\r\n const files = readdirSync(migrationsPath)\r\n .filter(f => f.endsWith('.sql'))\r\n .sort()\r\n\r\n if (files.length === 0) {\r\n if (verbose) {\r\n console.log('[collections] No migration files found')\r\n }\r\n return\r\n }\r\n\r\n // Execute each migration\r\n for (const file of files) {\r\n if (verbose) {\r\n console.log('[collections] Applying migration:', file)\r\n }\r\n\r\n const sql = readFileSync(`${migrationsPath}/${file}`, 'utf-8')\r\n await pool.query(sql)\r\n }\r\n\r\n if (verbose) {\r\n console.log('[collections] Migrations applied successfully')\r\n }\r\n } catch (error) {\r\n if (verbose) {\r\n console.log('[collections] No migrations directory or error:', error)\r\n }\r\n // If no migrations directory, just return\r\n }\r\n}\r\n","import { pgTable, serial, text, timestamp, uuid, varchar, boolean, integer } from 'drizzle-orm/pg-core'\r\n\r\nimport type { Collection } from './collection'\r\n\r\n/**\r\n * Build Drizzle table from collection definition\r\n */\r\nexport const buildTable = (collection: Collection) => {\r\n // Build columns object\r\n const columns: Record<string, unknown> = {\r\n // Add default id column\r\n id: serial('id').primaryKey()\r\n }\r\n\r\n // Build columns from fields\r\n for (const [fieldName, fieldDef] of Object.entries(collection.fields)) {\r\n // Skip the id field if explicitly defined in fields\r\n if (fieldName === 'id') continue\r\n\r\n const fieldType = fieldDef.fieldType as { name?: string; type?: string }\r\n const fieldTypeName = fieldType.name || fieldType.type || 'text'\r\n\r\n switch (fieldTypeName) {\r\n case 'text':\r\n columns[fieldName] = text(fieldName)\r\n break\r\n case 'varchar':\r\n columns[fieldName] = varchar(fieldName, { length: 255 })\r\n break\r\n case 'number':\r\n case 'integer':\r\n columns[fieldName] = integer(fieldName)\r\n break\r\n case 'boolean':\r\n columns[fieldName] = boolean(fieldName)\r\n break\r\n case 'timestamp':\r\n columns[fieldName] = timestamp(fieldName)\r\n break\r\n case 'uuid':\r\n columns[fieldName] = uuid(fieldName)\r\n break\r\n default:\r\n columns[fieldName] = text(fieldName)\r\n }\r\n }\r\n\r\n return pgTable(collection.slug, columns as Record<string, ReturnType<typeof text>>)\r\n}\r\n\r\n/**\r\n * Build all tables from collections\r\n */\r\nexport const buildSchema = (collections: Collection[]) => {\r\n const tables: Record<string, ReturnType<typeof pgTable>> = {}\r\n\r\n for (const coll of collections) {\r\n tables[coll.slug] = buildTable(coll)\r\n }\r\n\r\n return tables\r\n}\r\n","/**\r\n * PostgreSQL adapter configuration\r\n */\r\nexport type PgAdapterConfig = {\r\n url: string\r\n migrationsPath?: string\r\n}\r\n\r\n/**\r\n * PostgreSQL adapter\r\n *\r\n * @example\r\n * const adapter = pgAdapter({\r\n * url: 'postgres://user:pass@localhost:5432/db'\r\n * })\r\n *\r\n * // Get pool for drizzle\r\n * const pool = adapter.getPool()\r\n */\r\nexport interface PgAdapter {\r\n type: 'postgres'\r\n config: PgAdapterConfig\r\n /** Get the underlying connection pool */\r\n getPool: () => Promise<import('pg').Pool>\r\n}\r\n\r\n/**\r\n * Database adapter type\r\n */\r\nexport type DatabaseAdapter = PgAdapter\r\n\r\n/**\r\n * Creates a PostgreSQL adapter\r\n *\r\n * @example\r\n * const adapter = pgAdapter({\r\n * url: 'postgres://user:pass@localhost:5432/db'\r\n * })\r\n *\r\n * // Get pool for drizzle\r\n * const pool = await adapter.getPool()\r\n */\r\nexport const pgAdapter = (config: PgAdapterConfig): PgAdapter => {\r\n let pool: import('pg').Pool | null = null\r\n\r\n return {\r\n type: 'postgres',\r\n config: {\r\n url: config.url,\r\n migrationsPath: config.migrationsPath ?? './migrations'\r\n },\r\n getPool: async () => {\r\n if (!pool) {\r\n const { Pool } = await import('pg')\r\n pool = new Pool({\r\n connectionString: config.url\r\n })\r\n }\r\n return pool\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["timestamp","process","process"]}