From 3ac2d4755fba88280119201f1630bc64ae4ff6c3 Mon Sep 17 00:00:00 2001 From: Mia Fallon Date: Sun, 14 Apr 2024 14:07:27 -0400 Subject: [PATCH 1/4] Added basic seed functionality --- README.md | 8 +++++++- src/commands/help.command.ts | 2 ++ src/commands/index.ts | 1 + src/commands/seed.command.ts | 22 ++++++++++++++++++++++ src/config.ts | 1 + src/modules/parser.module.ts | 15 ++++++++++++++- src/tests/parser.module.test.ts | 28 +++++++++++++++++++++++++++- 7 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 src/commands/seed.command.ts diff --git a/README.md b/README.md index 65c0938..50531c7 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 can contain +a file called `seed.sql` that you can run to seed data into the database. + ## Commands To view a list of commands, run: diff --git a/src/commands/help.command.ts b/src/commands/help.command.ts index 5eb4066..06f5102 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 Seed the database with seed.sql Examples: $ postgrate -h @@ -18,5 +19,6 @@ Examples: $ postgrate -m create-users-table $ postgrate -r $ postgrate -rb 1 + $ postgrate -s `); } 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/seed.command.ts b/src/commands/seed.command.ts new file mode 100644 index 0000000..2e6b13f --- /dev/null +++ b/src/commands/seed.command.ts @@ -0,0 +1,22 @@ +import fsSync from 'fs'; +import fs from 'fs/promises'; +import Config from '../config'; +import { confirmation, pool } from '../modules'; + +export default async function () { + const { rootDirectory, seedDirectory } = Config(); + if (!seedDirectory) { + console.error(`Seed directory does not exist!`); + process.exit(1); + } + const seedFilePath = `${rootDirectory}/${seedDirectory}/seed.sql`; + if (!fsSync.existsSync(seedFilePath)) { + console.error(`seed.sql does not exist!`); + process.exit(1); + } + await confirmation('seed.sql'); + const seed = await fs.readFile(seedFilePath, 'utf-8'); + await pool.query(seed); + console.log(`\nDatabase seeded\n`); + pool.end(); +} 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/modules/parser.module.ts b/src/modules/parser.module.ts index 7951a88..b0b3daf 100644 --- a/src/modules/parser.module.ts +++ b/src/modules/parser.module.ts @@ -1,4 +1,12 @@ -import { help, init, list, make, rollback, run } from '../commands/index.js'; +import { + help, + init, + list, + make, + rollback, + run, + seed, +} from '../commands/index.js'; export default async ({ command, second }: IParserInput) => { switch (command) { @@ -32,6 +40,11 @@ export default async ({ command, second }: IParserInput) => { help(); break; + case '-s': + case 'seed': + seed(); + break; + default: console.log(`Invalid command: ${command}`); help(); 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(), From dcc75c4072f279b43ca1f3afd41e331e82c196df Mon Sep 17 00:00:00 2001 From: Mia Fallon Date: Tue, 16 Apr 2024 13:03:59 -0400 Subject: [PATCH 2/4] Added option to pass in file for seeds instead of hardcoding the file name --- README.md | 6 ++++-- src/commands/help.command.ts | 4 ++-- src/commands/list.command.ts | 33 ++++++++++++++++++++++++++------- src/commands/seed.command.ts | 23 ++++++++++++++--------- 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 50531c7..eaefcc6 100644 --- a/README.md +++ b/README.md @@ -204,8 +204,8 @@ this configuration option within a project. ### `seedDirectory` -The `seedDirectory` option is how you set `seed` directory name. It can contain -a file called `seed.sql` that you can run to seed data into the database. +The `seedDirectory` option is how you set `seed` directory name. It should +contain `.sql` files that add data to the db. ## Commands @@ -228,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 @@ -236,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 06f5102..c276366 100644 --- a/src/commands/help.command.ts +++ b/src/commands/help.command.ts @@ -10,7 +10,7 @@ Commands: -m, make Create a migration file -r, run Run all pending migrations -rb, rollback Rollback a migration - -s, seed Seed the database with seed.sql + -s, seed Run a seed file Examples: $ postgrate -h @@ -19,6 +19,6 @@ Examples: $ postgrate -m create-users-table $ postgrate -r $ postgrate -rb 1 - $ postgrate -s + $ postgrate -s base-seed `); } diff --git a/src/commands/list.command.ts b/src/commands/list.command.ts index cc21adf..cea0bef 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('\nMigrations:\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 index 2e6b13f..2119a30 100644 --- a/src/commands/seed.command.ts +++ b/src/commands/seed.command.ts @@ -3,20 +3,25 @@ import fs from 'fs/promises'; import Config from '../config'; import { confirmation, pool } from '../modules'; -export default async function () { +export default async function (seedName?: string) { const { rootDirectory, seedDirectory } = Config(); if (!seedDirectory) { console.error(`Seed directory does not exist!`); process.exit(1); } - const seedFilePath = `${rootDirectory}/${seedDirectory}/seed.sql`; - if (!fsSync.existsSync(seedFilePath)) { - console.error(`seed.sql does not exist!`); + if (seedName) { + const seedFilePath = `${rootDirectory}/${seedDirectory}/${seedName}.sql`; + if (!fsSync.existsSync(seedFilePath)) { + console.error(`${seedName}.sql does not exist!`); + process.exit(1); + } + await confirmation('seed.sql'); + const seed = await fs.readFile(seedFilePath, 'utf-8'); + await pool.query(seed); + console.log(`\nDatabase seeded\n`); + pool.end(); + } else { + console.error(`Please provide a seed file name!`); process.exit(1); } - await confirmation('seed.sql'); - const seed = await fs.readFile(seedFilePath, 'utf-8'); - await pool.query(seed); - console.log(`\nDatabase seeded\n`); - pool.end(); } From c47a8dfa2d3eff4955bf53a9b9710c031813d7f3 Mon Sep 17 00:00:00 2001 From: Mia Fallon Date: Tue, 16 Apr 2024 13:09:46 -0400 Subject: [PATCH 3/4] Added reset option, TODO: implement db wipe --- src/commands/list.command.ts | 2 +- src/commands/seed.command.ts | 4 ++-- src/index.ts | 4 ++-- src/modules/parser.module.ts | 5 +++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/commands/list.command.ts b/src/commands/list.command.ts index cea0bef..d9d7e0d 100644 --- a/src/commands/list.command.ts +++ b/src/commands/list.command.ts @@ -26,7 +26,7 @@ export default async function () { } else { const files = await fs.readdir(seedDirectory); - console.log('\nMigrations:\n'); + console.log('\NSeeds:\n'); if (files.length === 0) { console.error(`\nNo seeds found in ${seedDirectory}\n`); diff --git a/src/commands/seed.command.ts b/src/commands/seed.command.ts index 2119a30..30a626e 100644 --- a/src/commands/seed.command.ts +++ b/src/commands/seed.command.ts @@ -3,7 +3,7 @@ import fs from 'fs/promises'; import Config from '../config'; import { confirmation, pool } from '../modules'; -export default async function (seedName?: string) { +export default async function (seedName?: string, resetOption?: boolean) { const { rootDirectory, seedDirectory } = Config(); if (!seedDirectory) { console.error(`Seed directory does not exist!`); @@ -15,7 +15,7 @@ export default async function (seedName?: string) { console.error(`${seedName}.sql does not exist!`); process.exit(1); } - await confirmation('seed.sql'); + await confirmation(`${seedName}.sql`); const seed = await fs.readFile(seedFilePath, 'utf-8'); await pool.query(seed); console.log(`\nDatabase seeded\n`); 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 b0b3daf..01d2a13 100644 --- a/src/modules/parser.module.ts +++ b/src/modules/parser.module.ts @@ -8,7 +8,7 @@ import { seed, } from '../commands/index.js'; -export default async ({ command, second }: IParserInput) => { +export default async ({ command, second, third }: IParserInput) => { switch (command) { case '-i': case 'init': @@ -42,7 +42,7 @@ export default async ({ command, second }: IParserInput) => { case '-s': case 'seed': - seed(); + seed(second, !!third); break; default: @@ -56,4 +56,5 @@ export default async ({ command, second }: IParserInput) => { interface IParserInput { command: string; second?: string; + third?: string; } From 3cbd6cc4c49f36d819925bf92fcacf2aad23dd54 Mon Sep 17 00:00:00 2001 From: Mia Fallon Date: Tue, 16 Apr 2024 13:20:39 -0400 Subject: [PATCH 4/4] Added functionality to run a reset.sql that resets the database --- src/commands/seed.command.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/commands/seed.command.ts b/src/commands/seed.command.ts index 30a626e..53bcabd 100644 --- a/src/commands/seed.command.ts +++ b/src/commands/seed.command.ts @@ -15,9 +15,25 @@ export default async function (seedName?: string, resetOption?: boolean) { console.error(`${seedName}.sql does not exist!`); process.exit(1); } - await confirmation(`${seedName}.sql`); + 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 {