schema-seed 0.1.7 → 0.1.8

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/bin.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import "dotenv/config";
5
5
  import { Command } from "commander";
6
6
  import {
7
- version as coreVersion,
7
+ version,
8
8
  runSeedSql,
9
9
  runSeedMongo,
10
10
  createSeedPlan,
@@ -48,15 +48,37 @@ async function loadConfig(configPath) {
48
48
  }
49
49
 
50
50
  // src/bin.ts
51
- import { writeFileSync } from "fs";
51
+ import { writeFileSync, existsSync as existsSync2 } from "fs";
52
52
  import { resolve as resolve2 } from "path";
53
53
  import { createInterface } from "readline/promises";
54
+ import { createRequire } from "module";
55
+ import { pathToFileURL } from "url";
54
56
  var program = new Command();
55
- program.name("schema-seed").description("CLI to seed your database with realistic data").version(coreVersion);
57
+ program.name("schema-seed").description("CLI to seed your database with realistic data").version(version);
56
58
  async function getAdapter(dbType, dbUrl) {
57
- const packageName = `schema-seed-adapter-${dbType}`;
59
+ const unscopedName = `schema-seed-adapter-${dbType}`;
60
+ const scopedName = `@alinazar-111/schema-seed-adapter-${dbType}`;
61
+ const tryImport = async (name) => {
62
+ try {
63
+ const cwd = process.cwd();
64
+ const require2 = createRequire(resolve2(cwd, "index.js"));
65
+ const packagePath = require2.resolve(name);
66
+ const url = pathToFileURL(packagePath).href;
67
+ return await import(url);
68
+ } catch (err) {
69
+ try {
70
+ return await import(name);
71
+ } catch (err2) {
72
+ return null;
73
+ }
74
+ }
75
+ };
76
+ const module = await tryImport(unscopedName) || await tryImport(scopedName);
77
+ if (!module) {
78
+ const installCmd = existsSync2(resolve2(process.cwd(), "pnpm-lock.yaml")) ? `pnpm add ${unscopedName}` : `npm install ${unscopedName}`;
79
+ throw new Error(`Adapter package not found. Please install it: ${installCmd}`);
80
+ }
58
81
  try {
59
- const module = await import(packageName);
60
82
  const adapterName = dbType.charAt(0).toUpperCase() + dbType.slice(1) + "Adapter";
61
83
  const AdapterClass = module[adapterName] || module.Adapter || module.default;
62
84
  if (!AdapterClass) {
@@ -64,14 +86,11 @@ async function getAdapter(dbType, dbUrl) {
64
86
  if (typeof module[factoryMethod] === "function") {
65
87
  return module[factoryMethod](dbUrl);
66
88
  }
67
- throw new Error(`Could not find adapter class or factory in ${packageName}`);
89
+ throw new Error(`Could not find adapter class or factory in ${unscopedName}`);
68
90
  }
69
91
  return new AdapterClass(dbUrl);
70
92
  } catch (err) {
71
- if (err.code === "ERR_MODULE_NOT_FOUND" || err.message.includes("Cannot find module")) {
72
- throw new Error(`Adapter not installed. Run: pnpm add ${packageName}`);
73
- }
74
- throw new Error(`Failed to load adapter ${packageName}: ${err.message}`);
93
+ throw new Error(`Failed to load adapter ${unscopedName}: ${err.message}`);
75
94
  }
76
95
  }
77
96
  function inferDbType(dbUrl) {
@@ -92,31 +111,38 @@ async function confirmAction(expected) {
92
111
  return answer === expected;
93
112
  }
94
113
  var commonOptions = (cmd) => {
95
- return cmd.option("--db <url>", "Database connection string").option("--dbType <type>", "Database type (postgres, mysql, sqlite, mssql, oracle, mongodb)").option("--config <path>", "Path to config file").option("--table <names...>", "Specific tables to seed").option("--all", "Seed all tables", true).option("--rows <number>", "Number of rows per table", (v) => parseInt(v), 10).option("--rows-per-table <json>", "JSON mapping of table names to row counts", (v) => JSON.parse(v)).option("--seed <string>", "Random seed").option("--dry-run", "Do not execute any writes").option("--truncate", "Truncate tables before seeding").option("--allow-production", "Allow running against production databases").option("--confirm <string>", "Require typed confirmation string to proceed").option("--with-parents", "Include parent tables for foreign keys").option("--out <path>", "Output report to JSON file");
114
+ return cmd.option("--db <url>", "Database connection string").option("--dbType <type>", "Database type (postgres, mysql, sqlite, mssql, oracle, mongodb)").option("--config <path>", "Path to config file").option("--table <names...>", "Specific tables to seed").option("--all", "Seed all tables").option("--rows <number>", "Number of rows per table", (v) => parseInt(v)).option("--rows-per-table <json>", "JSON mapping of table names to row counts", (v) => JSON.parse(v)).option("--seed <string>", "Random seed").option("--dry-run", "Do not execute any writes").option("--truncate", "Truncate tables before seeding").option("--allow-production", "Allow running against production databases").option("--confirm <string>", "Require typed confirmation string to proceed").option("--with-parents", "Include parent tables for foreign keys").option("--out <path>", "Output report to JSON file");
96
115
  };
97
116
  commonOptions(program.command("seed")).description("Seed the database").action(async (options) => {
98
- const config = await loadConfig(options.config);
99
- const mergedOptions = { ...config, ...options };
100
- if (options.rowsPerTable) {
101
- mergedOptions.rows = options.rowsPerTable;
102
- }
103
- if (mergedOptions.confirm && !mergedOptions.dryRun) {
104
- const confirmed = await confirmAction(mergedOptions.confirm);
105
- if (!confirmed) {
106
- console.error("\u274C Confirmation failed. Aborting.");
117
+ try {
118
+ const config = await loadConfig(options.config);
119
+ const mergedOptions = { ...config, ...options };
120
+ if (options.rows === void 0 && config.rows === void 0) {
121
+ mergedOptions.rows = 10;
122
+ }
123
+ if (options.rowsPerTable) {
124
+ mergedOptions.rows = options.rowsPerTable;
125
+ }
126
+ if (mergedOptions.confirm && !mergedOptions.dryRun) {
127
+ const confirmed = await confirmAction(mergedOptions.confirm);
128
+ if (!confirmed) {
129
+ console.error("\u274C Confirmation failed. Aborting.");
130
+ process.exit(1);
131
+ }
132
+ }
133
+ let dbUrl = mergedOptions.db;
134
+ if (mergedOptions.dbType === "mongodb" && mergedOptions.mongodb?.uri) {
135
+ dbUrl = mergedOptions.mongodb.uri;
136
+ }
137
+ if (!dbUrl) {
138
+ console.error("\u274C Error: Database connection string is required.");
139
+ console.error(" Provide it via --db flag or in your seed.config.ts file.");
140
+ if (Object.keys(config).length === 0) {
141
+ console.error(" (No config file was found in the current directory)");
142
+ }
107
143
  process.exit(1);
108
144
  }
109
- }
110
- let dbUrl = mergedOptions.db;
111
- if (mergedOptions.dbType === "mongodb" && mergedOptions.mongodb?.uri) {
112
- dbUrl = mergedOptions.mongodb.uri;
113
- }
114
- if (!dbUrl) {
115
- console.error("Error: Database connection string (--db) is required");
116
- process.exit(1);
117
- }
118
- const dbType = mergedOptions.dbType || inferDbType(dbUrl);
119
- try {
145
+ const dbType = mergedOptions.dbType || inferDbType(dbUrl);
120
146
  const adapter = await getAdapter(dbType, dbUrl);
121
147
  let report;
122
148
  if (dbType === "mongodb") {
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bin.ts","../src/config.mts"],"sourcesContent":["import 'dotenv/config'\nimport { Command } from 'commander'\nimport {\n version as coreVersion,\n runSeedSql,\n runSeedMongo,\n createSeedPlan,\n reportToConsole,\n reportToJson\n} from 'schema-seed-core'\nimport { generators, inferGenerator } from 'schema-seed-generators'\nimport { loadConfig } from './config.mjs'\nimport { writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { createInterface } from 'node:readline/promises'\n\nconst program = new Command()\n\nprogram\n .name('schema-seed')\n .description('CLI to seed your database with realistic data')\n .version(coreVersion)\n\nasync function getAdapter(dbType: string, dbUrl: string) {\n const packageName = `schema-seed-adapter-${dbType}`\n try {\n const module = await import(packageName)\n const adapterName = dbType.charAt(0).toUpperCase() + dbType.slice(1) + 'Adapter'\n const AdapterClass = module[adapterName] || module.Adapter || module.default\n\n if (!AdapterClass) {\n // Try factory function\n const factoryMethod = `create${dbType.charAt(0).toUpperCase() + dbType.slice(1)}Adapter`\n if (typeof module[factoryMethod] === 'function') {\n return module[factoryMethod](dbUrl)\n }\n throw new Error(`Could not find adapter class or factory in ${packageName}`)\n }\n\n return new AdapterClass(dbUrl)\n } catch (err: any) {\n if (err.code === 'ERR_MODULE_NOT_FOUND' || err.message.includes('Cannot find module')) {\n throw new Error(`Adapter not installed. Run: pnpm add ${packageName}`)\n }\n throw new Error(`Failed to load adapter ${packageName}: ${err.message}`)\n }\n}\n\nfunction inferDbType(dbUrl: string): string {\n if (dbUrl.startsWith('postgres://') || dbUrl.startsWith('postgresql://')) return 'postgres'\n if (dbUrl.startsWith('mysql://')) return 'mysql'\n if (dbUrl.startsWith('sqlite://') || dbUrl.endsWith('.db')) return 'sqlite'\n if (dbUrl.startsWith('mongodb://')) return 'mongodb'\n if (dbUrl.startsWith('sqlserver://')) return 'mssql'\n return 'postgres' // Default\n}\n\nasync function confirmAction(expected: string): Promise<boolean> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout\n })\n const answer = await rl.question(`⚠️ Type \"${expected}\" to confirm: `)\n rl.close()\n return answer === expected\n}\n\nconst commonOptions = (cmd: Command) => {\n return cmd\n .option('--db <url>', 'Database connection string')\n .option('--dbType <type>', 'Database type (postgres, mysql, sqlite, mssql, oracle, mongodb)')\n .option('--config <path>', 'Path to config file')\n .option('--table <names...>', 'Specific tables to seed')\n .option('--all', 'Seed all tables', true)\n .option('--rows <number>', 'Number of rows per table', (v) => parseInt(v), 10)\n .option('--rows-per-table <json>', 'JSON mapping of table names to row counts', (v) => JSON.parse(v))\n .option('--seed <string>', 'Random seed')\n .option('--dry-run', 'Do not execute any writes')\n .option('--truncate', 'Truncate tables before seeding')\n .option('--allow-production', 'Allow running against production databases')\n .option('--confirm <string>', 'Require typed confirmation string to proceed')\n .option('--with-parents', 'Include parent tables for foreign keys')\n .option('--out <path>', 'Output report to JSON file')\n}\n\ncommonOptions(program.command('seed'))\n .description('Seed the database')\n .action(async (options) => {\n const config = await loadConfig(options.config)\n const mergedOptions = { ...config, ...options }\n\n if (options.rowsPerTable) {\n mergedOptions.rows = options.rowsPerTable\n }\n\n if (mergedOptions.confirm && !mergedOptions.dryRun) {\n const confirmed = await confirmAction(mergedOptions.confirm)\n if (!confirmed) {\n console.error('❌ Confirmation failed. Aborting.')\n process.exit(1)\n }\n }\n\n let dbUrl = mergedOptions.db\n if (mergedOptions.dbType === 'mongodb' && mergedOptions.mongodb?.uri) {\n dbUrl = mergedOptions.mongodb.uri\n }\n\n if (!dbUrl) {\n console.error('Error: Database connection string (--db) is required')\n process.exit(1)\n }\n\n const dbType = mergedOptions.dbType || inferDbType(dbUrl)\n\n try {\n const adapter = await getAdapter(dbType, dbUrl)\n\n let report;\n if (dbType === 'mongodb') {\n // For MongoDB, we use the new config-based seeding\n report = await runSeedMongo(adapter as any, mergedOptions as any, {\n dryRun: mergedOptions.dryRun,\n allowProduction: mergedOptions.allowProduction\n }, { generators, inferGenerator })\n } else {\n await adapter.connect()\n const schema = await (adapter as any).introspectSchema()\n const plan = createSeedPlan(schema, mergedOptions, (adapter as any).capabilities?.deferrableConstraints)\n\n report = await runSeedSql(adapter as any, schema, plan, mergedOptions, {\n generators,\n inferGenerator,\n overrides: mergedOptions.overrides\n })\n }\n\n reportToConsole(report)\n\n if (options.out) {\n writeFileSync(resolve(process.cwd(), options.out), reportToJson(report))\n }\n } catch (err: any) {\n console.error(`\\n❌ Error: ${err.message}`)\n process.exit(1)\n }\n })\n\nprogram.command('preview')\n .description('Preview the seeding plan without executing')\n .action(async (options) => {\n // Same as seed --dry-run\n const seedCmd = program.commands.find(c => c.name() === 'seed')\n await seedCmd?.parseAsync(['--dry-run', ...process.argv.slice(3)], { from: 'user' })\n })\n\nprogram.command('reset')\n .description('Truncate all tables')\n .option('--db <url>', 'Database connection string')\n .option('--allow-production', 'Allow running against production databases')\n .action(async (options) => {\n console.log('Resetting database...')\n // Implementation would call adapter.truncateTables()\n })\n\nprogram.command('introspect')\n .description('Introspect the database schema and print as JSON')\n .option('--db <url>', 'Database connection string')\n .action(async (options) => {\n console.log('Introspecting database...')\n // Implementation would call adapter.introspectSchema()\n })\n\nprogram.parse()\n","import { createJiti } from 'jiti'\nimport { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { type SeedOptions } from 'schema-seed-core'\nimport { type MongoSeedConfig } from 'schema-seed-core/mongo'\n\nexport type Config = (SeedOptions & {\n db?: string\n dbType?: string\n overrides?: Record<string, any>\n}) | MongoSeedConfig\n\nexport async function loadConfig(configPath?: string): Promise<Config> {\n const jiti = createJiti(import.meta.url)\n\n if (configPath) {\n const fullPath = resolve(process.cwd(), configPath)\n if (!existsSync(fullPath)) {\n throw new Error(`Config file not found at ${fullPath}`)\n }\n const module = await jiti.import(fullPath) as any\n console.log(`✅ Loaded config from ${configPath}`)\n return module.default || module\n }\n\n const defaultPaths = [\n resolve(process.cwd(), 'seed.config.ts'),\n resolve(process.cwd(), 'seed.config.js'),\n resolve(process.cwd(), 'seed.config.mjs'),\n ]\n\n for (const path of defaultPaths) {\n if (existsSync(path)) {\n try {\n const module = await jiti.import(path) as any\n console.log(`✅ Loaded config from ${path}`)\n return module.default || module\n } catch (err: any) {\n throw new Error(`Failed to load config file ${path}: ${err.message}`)\n }\n }\n }\n\n return {}\n}\n"],"mappings":"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","names":["resolve"]}
1
+ {"version":3,"sources":["../src/bin.ts","../src/config.mts"],"sourcesContent":["import 'dotenv/config'\nimport { Command } from 'commander'\nimport {\n version,\n runSeedSql,\n runSeedMongo,\n createSeedPlan,\n reportToConsole,\n reportToJson\n} from 'schema-seed-core'\nimport { generators, inferGenerator } from 'schema-seed-generators'\nimport { loadConfig } from './config.mjs'\nimport { writeFileSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { createInterface } from 'node:readline/promises'\nimport { createRequire } from 'node:module'\nimport { pathToFileURL } from 'node:url'\n\nconst program = new Command()\n\nprogram\n .name('schema-seed')\n .description('CLI to seed your database with realistic data')\n .version(version)\n\nasync function getAdapter(dbType: string, dbUrl: string) {\n const unscopedName = `schema-seed-adapter-${dbType}`\n const scopedName = `@alinazar-111/schema-seed-adapter-${dbType}`\n\n const tryImport = async (name: string) => {\n try {\n const cwd = process.cwd()\n // Use createRequire to resolve the package from the current working directory\n const require = createRequire(resolve(cwd, 'index.js'))\n const packagePath = require.resolve(name)\n const url = pathToFileURL(packagePath).href\n return await import(url)\n } catch (err: any) {\n try {\n // Fallback to standard import (for globally installed adapters)\n return await import(name)\n } catch (err2: any) {\n return null\n }\n }\n }\n\n const module = (await tryImport(unscopedName)) || (await tryImport(scopedName))\n\n if (!module) {\n const installCmd = existsSync(resolve(process.cwd(), 'pnpm-lock.yaml'))\n ? `pnpm add ${unscopedName}`\n : `npm install ${unscopedName}`\n throw new Error(`Adapter package not found. Please install it: ${installCmd}`)\n }\n\n try {\n const adapterName = dbType.charAt(0).toUpperCase() + dbType.slice(1) + 'Adapter'\n const AdapterClass = module[adapterName] || module.Adapter || module.default\n\n if (!AdapterClass) {\n const factoryMethod = `create${dbType.charAt(0).toUpperCase() + dbType.slice(1)}Adapter`\n if (typeof module[factoryMethod] === 'function') {\n return module[factoryMethod](dbUrl)\n }\n throw new Error(`Could not find adapter class or factory in ${unscopedName}`)\n }\n\n return new AdapterClass(dbUrl)\n } catch (err: any) {\n throw new Error(`Failed to load adapter ${unscopedName}: ${err.message}`)\n }\n}\n\nfunction inferDbType(dbUrl: string): string {\n if (dbUrl.startsWith('postgres://') || dbUrl.startsWith('postgresql://')) return 'postgres'\n if (dbUrl.startsWith('mysql://')) return 'mysql'\n if (dbUrl.startsWith('sqlite://') || dbUrl.endsWith('.db')) return 'sqlite'\n if (dbUrl.startsWith('mongodb://')) return 'mongodb'\n if (dbUrl.startsWith('sqlserver://')) return 'mssql'\n return 'postgres' // Default\n}\n\nasync function confirmAction(expected: string): Promise<boolean> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout\n })\n const answer = await rl.question(`⚠️ Type \"${expected}\" to confirm: `)\n rl.close()\n return answer === expected\n}\n\nconst commonOptions = (cmd: Command) => {\n return cmd\n .option('--db <url>', 'Database connection string')\n .option('--dbType <type>', 'Database type (postgres, mysql, sqlite, mssql, oracle, mongodb)')\n .option('--config <path>', 'Path to config file')\n .option('--table <names...>', 'Specific tables to seed')\n .option('--all', 'Seed all tables')\n .option('--rows <number>', 'Number of rows per table', (v) => parseInt(v))\n .option('--rows-per-table <json>', 'JSON mapping of table names to row counts', (v) => JSON.parse(v))\n .option('--seed <string>', 'Random seed')\n .option('--dry-run', 'Do not execute any writes')\n .option('--truncate', 'Truncate tables before seeding')\n .option('--allow-production', 'Allow running against production databases')\n .option('--confirm <string>', 'Require typed confirmation string to proceed')\n .option('--with-parents', 'Include parent tables for foreign keys')\n .option('--out <path>', 'Output report to JSON file')\n}\n\ncommonOptions(program.command('seed'))\n .description('Seed the database')\n .action(async (options) => {\n try {\n const config = await loadConfig(options.config)\n\n // Merge options: CLI flags override config file\n const mergedOptions = { ...config, ...options }\n\n // Handle rows default (commander default was overriding config)\n if (options.rows === undefined && config.rows === undefined) {\n mergedOptions.rows = 10\n }\n\n if (options.rowsPerTable) {\n mergedOptions.rows = options.rowsPerTable\n }\n\n if (mergedOptions.confirm && !mergedOptions.dryRun) {\n const confirmed = await confirmAction(mergedOptions.confirm)\n if (!confirmed) {\n console.error('❌ Confirmation failed. Aborting.')\n process.exit(1)\n }\n }\n\n let dbUrl = mergedOptions.db\n if (mergedOptions.dbType === 'mongodb' && mergedOptions.mongodb?.uri) {\n dbUrl = mergedOptions.mongodb.uri\n }\n\n if (!dbUrl) {\n console.error('❌ Error: Database connection string is required.')\n console.error(' Provide it via --db flag or in your seed.config.ts file.')\n if (Object.keys(config).length === 0) {\n console.error(' (No config file was found in the current directory)')\n }\n process.exit(1)\n }\n\n const dbType = mergedOptions.dbType || inferDbType(dbUrl)\n const adapter = await getAdapter(dbType, dbUrl)\n\n let report;\n if (dbType === 'mongodb') {\n report = await runSeedMongo(adapter as any, mergedOptions as any, {\n dryRun: mergedOptions.dryRun,\n allowProduction: mergedOptions.allowProduction\n }, { generators, inferGenerator })\n } else {\n await adapter.connect()\n const schema = await (adapter as any).introspectSchema()\n const plan = createSeedPlan(schema, mergedOptions, (adapter as any).capabilities?.deferrableConstraints)\n\n report = await runSeedSql(adapter as any, schema, plan, mergedOptions, {\n generators,\n inferGenerator,\n overrides: mergedOptions.overrides\n })\n }\n\n reportToConsole(report)\n\n if (options.out) {\n writeFileSync(resolve(process.cwd(), options.out), reportToJson(report))\n }\n } catch (err: any) {\n console.error(`\\n❌ Error: ${err.message}`)\n process.exit(1)\n }\n })\n\nprogram.command('preview')\n .description('Preview the seeding plan without executing')\n .action(async (options) => {\n // Same as seed --dry-run\n const seedCmd = program.commands.find(c => c.name() === 'seed')\n await seedCmd?.parseAsync(['--dry-run', ...process.argv.slice(3)], { from: 'user' })\n })\n\nprogram.command('reset')\n .description('Truncate all tables')\n .option('--db <url>', 'Database connection string')\n .option('--allow-production', 'Allow running against production databases')\n .action(async (options) => {\n console.log('Resetting database...')\n // Implementation would call adapter.truncateTables()\n })\n\nprogram.command('introspect')\n .description('Introspect the database schema and print as JSON')\n .option('--db <url>', 'Database connection string')\n .action(async (options) => {\n console.log('Introspecting database...')\n // Implementation would call adapter.introspectSchema()\n })\n\nprogram.parse()\n","import { createJiti } from 'jiti'\nimport { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { type SeedOptions } from 'schema-seed-core'\nimport { type MongoSeedConfig } from 'schema-seed-core/mongo'\n\nexport type Config = (SeedOptions & {\n db?: string\n dbType?: string\n overrides?: Record<string, any>\n}) | MongoSeedConfig\n\nexport async function loadConfig(configPath?: string): Promise<Config> {\n const jiti = createJiti(import.meta.url)\n\n if (configPath) {\n const fullPath = resolve(process.cwd(), configPath)\n if (!existsSync(fullPath)) {\n throw new Error(`Config file not found at ${fullPath}`)\n }\n const module = await jiti.import(fullPath) as any\n console.log(`✅ Loaded config from ${configPath}`)\n return module.default || module\n }\n\n const defaultPaths = [\n resolve(process.cwd(), 'seed.config.ts'),\n resolve(process.cwd(), 'seed.config.js'),\n resolve(process.cwd(), 'seed.config.mjs'),\n ]\n\n for (const path of defaultPaths) {\n if (existsSync(path)) {\n try {\n const module = await jiti.import(path) as any\n console.log(`✅ Loaded config from ${path}`)\n return module.default || module\n } catch (err: any) {\n throw new Error(`Failed to load config file ${path}: ${err.message}`)\n }\n }\n }\n\n return {}\n}\n"],"mappings":"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","names":["existsSync","resolve","require"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "schema-seed",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
5
  "description": "CLI for schema-seed",
6
6
  "author": "Ali Nazar",
@@ -40,20 +40,20 @@
40
40
  "commander": "^12.1.0",
41
41
  "dotenv": "^17.2.3",
42
42
  "jiti": "^2.6.1",
43
- "schema-seed-core": "0.1.7",
44
- "schema-seed-generators": "0.1.7"
43
+ "schema-seed-core": "0.1.8",
44
+ "schema-seed-generators": "0.1.8"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/node": "^20.19.27",
48
48
  "tsup": "^8.3.5",
49
49
  "typescript": "^5.7.2",
50
50
  "vitest": "^2.1.8",
51
- "schema-seed-adapter-mongodb": "0.1.7",
52
- "schema-seed-adapter-mysql": "0.1.7",
53
- "schema-seed-adapter-postgres": "0.1.7",
54
- "schema-seed-adapter-sqlite": "0.1.7",
55
- "schema-seed-adapter-mssql": "0.1.7",
56
- "schema-seed-adapter-oracle": "0.1.7"
51
+ "schema-seed-adapter-mongodb": "0.1.8",
52
+ "schema-seed-adapter-mysql": "0.1.8",
53
+ "schema-seed-adapter-postgres": "0.1.8",
54
+ "schema-seed-adapter-sqlite": "0.1.8",
55
+ "schema-seed-adapter-mssql": "0.1.8",
56
+ "schema-seed-adapter-oracle": "0.1.8"
57
57
  },
58
58
  "scripts": {
59
59
  "build": "tsup",