diff --git a/README.md b/README.md index 65c0938..eaefcc6 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ here are some details about each config option: - rollbackDirectory: Override the default rollbacks directory name. - autoCreateRollbacks: Set to true to automatically create rollback files. - migrationsTableName: Name of the table created in your database. +- seedDirectory: Directory to use to store the seed file. # @@ -196,11 +197,16 @@ Essentially, you will need to do the following: ### `migrationsTableName` -The `migrationsTableName` option allows you to set a cusom table name in which +The `migrationsTableName` option allows you to set a custom table name in which to store migration records. Make sure that this name does not conflict with other tables in your database. Once set, there is currently no way to update this configuration option within a project. +### `seedDirectory` + +The `seedDirectory` option is how you set `seed` directory name. It should +contain `.sql` files that add data to the db. + ## Commands To view a list of commands, run: @@ -222,6 +228,7 @@ Commands: -m, make Create a migration file -r, run Run all pending migrations -rb, rollback Rollback a migration + -s, seed Run a seed file Examples: $ postgrate -h @@ -230,4 +237,5 @@ Examples: $ postgrate -m create-users-table $ postgrate -r $ postgrate -rb 1 + $ postgrate -s base-seed ``` diff --git a/src/commands/help.command.ts b/src/commands/help.command.ts index 5eb4066..c276366 100644 --- a/src/commands/help.command.ts +++ b/src/commands/help.command.ts @@ -10,6 +10,7 @@ Commands: -m, make Create a migration file -r, run Run all pending migrations -rb, rollback Rollback a migration + -s, seed Run a seed file Examples: $ postgrate -h @@ -18,5 +19,6 @@ Examples: $ postgrate -m create-users-table $ postgrate -r $ postgrate -rb 1 + $ postgrate -s base-seed `); } diff --git a/src/commands/index.ts b/src/commands/index.ts index deff11b..f3c23f2 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -4,3 +4,4 @@ export { default as run } from './run.command.js'; export { default as rollback } from './rollback.command.js'; export { default as list } from './list.command.js'; export { default as help } from './help.command.js'; +export { default as seed } from './seed.command.js'; diff --git a/src/commands/list.command.ts b/src/commands/list.command.ts index cc21adf..d9d7e0d 100644 --- a/src/commands/list.command.ts +++ b/src/commands/list.command.ts @@ -1,8 +1,9 @@ +import fs from 'fs/promises'; import config from '../config.js'; import pool from '../modules/pool.module.js'; export default async function () { - const { migrationsTableName } = config(); + const { migrationsTableName, seedDirectory } = config(); const { rows } = await pool.query( `SELECT name, id, created_at FROM ${migrationsTableName} ORDER BY id DESC`, @@ -10,13 +11,31 @@ export default async function () { if (!rows.length) { console.log('\nNo migrations found!\n'); - return; + } else { + console.log('\nMigrations:\n'); + rows.forEach((row) => { + const date = new Date(row.created_at).toLocaleDateString(); + console.log(`> ID: ${row.id}, Name: ${row.name} Created: ${date}`); + }); + } + + console.log('\n'); + + if (!seedDirectory) { + console.error(`\nNo seed directory found!\n`); + } else { + const files = await fs.readdir(seedDirectory); + + console.log('\NSeeds:\n'); + + if (files.length === 0) { + console.error(`\nNo seeds found in ${seedDirectory}\n`); + } else { + files.forEach((file) => { + console.log(`> Name: ${file}`); + }); + } } - console.log('\nMigrations:\n'); - rows.forEach((row) => { - const date = new Date(row.created_at).toLocaleDateString(); - console.log(`> ID: ${row.id}, Name: ${row.name} Created: ${date}`); - }); console.log(''); } diff --git a/src/commands/seed.command.ts b/src/commands/seed.command.ts new file mode 100644 index 0000000..53bcabd --- /dev/null +++ b/src/commands/seed.command.ts @@ -0,0 +1,43 @@ +import fsSync from 'fs'; +import fs from 'fs/promises'; +import Config from '../config'; +import { confirmation, pool } from '../modules'; + +export default async function (seedName?: string, resetOption?: boolean) { + const { rootDirectory, seedDirectory } = Config(); + if (!seedDirectory) { + console.error(`Seed directory does not exist!`); + process.exit(1); + } + if (seedName) { + const seedFilePath = `${rootDirectory}/${seedDirectory}/${seedName}.sql`; + if (!fsSync.existsSync(seedFilePath)) { + console.error(`${seedName}.sql does not exist!`); + process.exit(1); + } + const resetFilePath = `${rootDirectory}/${seedDirectory}/reset.sql`; + if (!fsSync.existsSync(resetFilePath) && resetOption) { + console.error(`reset.sql does not exist!`); + process.exit(1); + } + if (resetOption) { + await confirmation([`${seedName}.sql`, 'reset.sql']); + } else { + await confirmation(`${seedName}.sql`); + } + if(resetOption) { + const seed = await fs.readFile(resetFilePath, 'utf-8'); + await pool.query(seed); + } + const seed = await fs.readFile(seedFilePath, 'utf-8'); + await pool.query(seed); + if(resetOption) { + console.log(`\nDatabase truncated\n`); + } + console.log(`\nDatabase seeded\n`); + pool.end(); + } else { + console.error(`Please provide a seed file name!`); + process.exit(1); + } +} diff --git a/src/config.ts b/src/config.ts index b278dcc..4e6e801 100644 --- a/src/config.ts +++ b/src/config.ts @@ -25,4 +25,5 @@ export interface IConfig { rollbacksDirectory: string; autoCreateRollbacks: boolean; migrationsTableName: string; + seedDirectory?: string; } diff --git a/src/index.ts b/src/index.ts index 385ec57..09d2bea 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,8 +2,8 @@ import { parser } from './modules/index.js'; const args = process.argv.slice(2); -const [command, second] = args; +const [command, second, third] = args; -await parser({ command, second }); +await parser({ command, second, third }); process.exit(0); diff --git a/src/modules/parser.module.ts b/src/modules/parser.module.ts index 7951a88..01d2a13 100644 --- a/src/modules/parser.module.ts +++ b/src/modules/parser.module.ts @@ -1,6 +1,14 @@ -import { help, init, list, make, rollback, run } from '../commands/index.js'; - -export default async ({ command, second }: IParserInput) => { +import { + help, + init, + list, + make, + rollback, + run, + seed, +} from '../commands/index.js'; + +export default async ({ command, second, third }: IParserInput) => { switch (command) { case '-i': case 'init': @@ -32,6 +40,11 @@ export default async ({ command, second }: IParserInput) => { help(); break; + case '-s': + case 'seed': + seed(second, !!third); + break; + default: console.log(`Invalid command: ${command}`); help(); @@ -43,4 +56,5 @@ export default async ({ command, second }: IParserInput) => { interface IParserInput { command: string; second?: string; + third?: string; } diff --git a/src/tests/parser.module.test.ts b/src/tests/parser.module.test.ts index 2485949..b556523 100644 --- a/src/tests/parser.module.test.ts +++ b/src/tests/parser.module.test.ts @@ -1,5 +1,13 @@ import { expect, it, describe, vi, afterEach } from 'vitest'; -import { help, init, list, make, rollback, run } from '../commands/index.js'; +import { + help, + init, + list, + make, + rollback, + run, + seed, +} from '../commands/index.js'; import { parser } from '../modules/index.js'; describe('Parser', () => { @@ -54,6 +62,23 @@ describe('Parser', () => { expect(run).toHaveBeenCalledTimes(2); }); + it('should seed upon `seed` and `-s`', () => { + vi.mock('../commands/index.js', () => { + return { + init: vi.fn(), + make: vi.fn(), + run: vi.fn(), + seed: vi.fn(), + }; + }); + + parser({ command: 'seed' }); + expect(seed).toHaveBeenCalledTimes(1); + + parser({ command: '-s' }); + expect(seed).toHaveBeenCalledTimes(2); + }); + it('should rollback upon `rollback` and `-rb`', () => { vi.mock('../commands/index.js', () => { return { @@ -116,6 +141,7 @@ describe('Parser', () => { init: vi.fn(), make: vi.fn(), run: vi.fn(), + seed: vi.fn(), rollback: vi.fn(), list: vi.fn(), help: vi.fn(),