Comparing version 1.0.1 to 1.1.0
import fs from 'fs'; | ||
export default function () { | ||
if (!fs.existsSync('db')) { | ||
fs.mkdirSync('db'); | ||
import config from '../config.js'; | ||
export default function (createConfigFile = false) { | ||
if (createConfigFile) { | ||
fs.writeFileSync('.postgraterc', JSON.stringify({ | ||
rootDirectory: 'db', | ||
migrationsDirectory: 'migrations', | ||
rollbacksDirectory: 'rollbacks', | ||
autoCreateRollbacks: true, | ||
migrationsTableName: 'migrations', | ||
}, null, 2)); | ||
} | ||
if (!fs.existsSync('db/migrations')) { | ||
fs.mkdirSync('db/migrations', { recursive: true }); | ||
const { rootDirectory, migrationsDirectory, rollbacksDirectory, autoCreateRollbacks, } = config(); | ||
if (!fs.existsSync(rootDirectory)) { | ||
fs.mkdirSync(rootDirectory); | ||
} | ||
if (!fs.existsSync('db/rollbacks')) { | ||
fs.mkdirSync('db/rollbacks'); | ||
if (!fs.existsSync(`${rootDirectory}/${migrationsDirectory}`)) { | ||
fs.mkdirSync(`${rootDirectory}/${migrationsDirectory}`, { | ||
recursive: true, | ||
}); | ||
} | ||
if (!fs.existsSync(`${rootDirectory}/${rollbacksDirectory}`) && | ||
autoCreateRollbacks) { | ||
fs.mkdirSync(`${rootDirectory}/${rollbacksDirectory}`); | ||
} | ||
console.log(` | ||
āØ Initialized postgrate & created \`db\` folder at root of project directory! āØ | ||
āØ Initialized postgrate & created \`${rootDirectory}\` folder at root of project directory! āØ | ||
`); | ||
} |
@@ -0,4 +1,6 @@ | ||
import config from '../config.js'; | ||
import pool from '../modules/pool.module.js'; | ||
export default async function () { | ||
const { rows } = await pool.query('SELECT name, id, created_at FROM migrations ORDER BY id DESC'); | ||
const { migrationsTableName } = config(); | ||
const { rows } = await pool.query(`SELECT name, id, created_at FROM ${migrationsTableName} ORDER BY id DESC`); | ||
if (!rows.length) { | ||
@@ -5,0 +7,0 @@ console.log('\nNo migrations found!\n'); |
import fs from 'fs'; | ||
import init from './init.command.js'; | ||
import config from '../config.js'; | ||
export default function (name) { | ||
@@ -8,7 +9,18 @@ if (!name) { | ||
} | ||
const fileName = generateMigrationFileName(name); | ||
const migrationFilePath = `db/migrations/${fileName}`; | ||
const rollbackFilePath = `db/rollbacks/rb-${fileName}`; | ||
const { rootDirectory, migrationsDirectory, rollbacksDirectory, autoCreateRollbacks, migrationsTableName, } = config(); | ||
const fileName = generateMigrationFileName({ | ||
name, | ||
config: { | ||
rootDirectory, | ||
migrationsDirectory, | ||
rollbacksDirectory, | ||
autoCreateRollbacks, | ||
migrationsTableName, | ||
}, | ||
}); | ||
const migrationFilePath = `${rootDirectory}/${migrationsDirectory}/${fileName}`; | ||
const rollbackFilePath = `${rootDirectory}/${rollbacksDirectory}/rb-${fileName}`; | ||
fs.writeFileSync(migrationFilePath, ''); | ||
fs.writeFileSync(rollbackFilePath, ''); | ||
if (autoCreateRollbacks) | ||
fs.writeFileSync(rollbackFilePath, ''); | ||
console.log(` | ||
@@ -18,4 +30,4 @@ Migration + rollback file created: ${fileName} | ||
} | ||
function generateMigrationFileName(name) { | ||
if (!fs.existsSync('db/migrations')) { | ||
function generateMigrationFileName({ name, config, }) { | ||
if (!fs.existsSync(`${config.rootDirectory}/${config.migrationsDirectory}`)) { | ||
init(); | ||
@@ -22,0 +34,0 @@ } |
import fs from 'fs/promises'; | ||
import fsSync from 'fs'; | ||
import { confirmation, pool } from '../modules/index.js'; | ||
import Config from '../config.js'; | ||
export default async function (migrationId) { | ||
validate(migrationId); | ||
const name = await getMigrationRecordName(migrationId); | ||
checkRollbackFileExists(name); | ||
const config = Config(); | ||
const name = await getMigrationRecordName({ id: migrationId, config }); | ||
checkRollbackFileExists({ name, config }); | ||
await confirmation(name); | ||
await rollback({ name, migrationId }); | ||
await rollback({ name, migrationId, config }); | ||
pool.end(); | ||
@@ -18,6 +20,4 @@ } | ||
} | ||
async function getMigrationRecordName(id) { | ||
const { rows } = await pool.query('SELECT * FROM migrations WHERE id = $1', [ | ||
id, | ||
]); | ||
async function getMigrationRecordName({ id, config, }) { | ||
const { rows } = await pool.query(`SELECT * FROM ${config.migrationsTableName} WHERE id = $1`, [id]); | ||
if (!rows.length) { | ||
@@ -29,4 +29,4 @@ console.error(`\nMigration with id ${id} not found!\n`); | ||
} | ||
function checkRollbackFileExists(name) { | ||
if (!fsSync.existsSync(`db/rollbacks/rb-${name}`)) { | ||
function checkRollbackFileExists({ name, config: { rootDirectory, rollbacksDirectory }, }) { | ||
if (!fsSync.existsSync(`${rootDirectory}/${rollbacksDirectory}/rb-${name}`)) { | ||
console.error(`Rollback file ${name} does not exist`); | ||
@@ -36,7 +36,9 @@ process.exit(1); | ||
} | ||
async function rollback({ name, migrationId }) { | ||
const rollback = await fs.readFile(`db/rollbacks/rb-${name}`, 'utf-8'); | ||
async function rollback({ name, migrationId, config: { rootDirectory, migrationsTableName, rollbacksDirectory }, }) { | ||
const rollback = await fs.readFile(`${rootDirectory}/${rollbacksDirectory}/rb-${name}`, 'utf-8'); | ||
await pool.query(rollback); | ||
await pool.query('DELETE FROM migrations WHERE id = $1', [migrationId]); | ||
await pool.query(`DELETE FROM ${migrationsTableName} WHERE id = $1`, [ | ||
migrationId, | ||
]); | ||
console.log(`\nMigration ${name} rolled back\n`); | ||
} |
@@ -5,6 +5,8 @@ import fs from 'fs/promises'; | ||
import { confirmation, pool } from '../modules/index.js'; | ||
import Config from '../config.js'; | ||
export default async function () { | ||
await createMigrationTable(); | ||
await fetchHistoricMigrations(); | ||
await runMigrations(); | ||
const config = Config(); | ||
await createMigrationTable(config); | ||
await fetchHistoricMigrations(config); | ||
await runMigrations(config); | ||
return pool.end(); | ||
@@ -14,4 +16,5 @@ } | ||
const historicMigrations = new Set(); | ||
const migrationsTableQuery = ` | ||
CREATE TABLE IF NOT EXISTS migrations ( | ||
async function createMigrationTable({ migrationsTableName, }) { | ||
await pool.query(` | ||
CREATE TABLE IF NOT EXISTS ${migrationsTableName} ( | ||
id SERIAL PRIMARY KEY, | ||
@@ -22,30 +25,28 @@ name VARCHAR(255) NOT NULL, | ||
); | ||
`; | ||
async function createMigrationTable() { | ||
await pool.query(migrationsTableQuery); | ||
`); | ||
} | ||
async function fetchHistoricMigrations() { | ||
const { rows } = await pool.query('SELECT name FROM migrations'); | ||
async function fetchHistoricMigrations({ migrationsTableName, }) { | ||
const { rows } = await pool.query(`SELECT name FROM ${migrationsTableName}`); | ||
rows.forEach((row) => historicMigrations.add(row.name)); | ||
} | ||
async function getMigrationFileNames() { | ||
if (!fsSync.existsSync('db/migrations')) { | ||
async function getMigrationFileNames({ rootDirectory, migrationsDirectory, }) { | ||
if (!fsSync.existsSync(`${rootDirectory}/${migrationsDirectory}`)) { | ||
init(); | ||
} | ||
const files = await fs.readdir('db/migrations'); | ||
const files = await fs.readdir(`${rootDirectory}/${migrationsDirectory}`); | ||
return files.sort((a, b) => parseInt(a.split('-')[0]) - parseInt(b.split('-')[0])); | ||
} | ||
async function determinePendingMigrations() { | ||
const files = await getMigrationFileNames(); | ||
async function determinePendingMigrations(config) { | ||
const files = await getMigrationFileNames(config); | ||
const pendingMigrations = files.filter((file) => !historicMigrations.has(file)); | ||
return pendingMigrations; | ||
} | ||
async function runMigration(migration) { | ||
const filePath = `db/migrations/${migration}`; | ||
async function runMigration({ migration, config: { rootDirectory, migrationsDirectory, migrationsTableName }, }) { | ||
const filePath = `${rootDirectory}/${migrationsDirectory}/${migration}`; | ||
const file = await fs.readFile(filePath, 'utf-8'); | ||
await client.query(file); | ||
const { rows } = await client.query('INSERT INTO migrations (name) VALUES ($1) RETURNING id;', [migration]); | ||
const { rows } = await client.query(`INSERT INTO ${migrationsTableName} (name) VALUES ($1) RETURNING id;`, [migration]); | ||
console.log(`\tMigration ${migration} [id: ${rows[0].id}] has been executed š`); | ||
} | ||
async function transact({ pendingMigrations, }) { | ||
async function transact({ pendingMigrations, config, }) { | ||
try { | ||
@@ -55,3 +56,3 @@ await client.query('BEGIN'); | ||
for (const migration of pendingMigrations) { | ||
await runMigration(migration); | ||
await runMigration({ migration, config }); | ||
} | ||
@@ -73,4 +74,4 @@ console.log('\n'); | ||
} | ||
async function runMigrations() { | ||
const pendingMigrations = await determinePendingMigrations(); | ||
async function runMigrations(config) { | ||
const pendingMigrations = await determinePendingMigrations(config); | ||
if (!pendingMigrations.length) { | ||
@@ -82,3 +83,3 @@ console.log('\nNo migrations to run\n'); | ||
await confirmation(pendingMigrations); | ||
await transact({ pendingMigrations }); | ||
await transact({ pendingMigrations, config }); | ||
} |
#!/usr/bin/env node | ||
import { help, init, list, make, rollback, run } from './commands/index.js'; | ||
import { parser } from './modules/index.js'; | ||
const args = process.argv.slice(2); | ||
const [command, second] = args; | ||
switch (command) { | ||
case '-i': | ||
case 'init': | ||
init(); | ||
break; | ||
case '-m': | ||
case 'make': | ||
make(second); | ||
break; | ||
case '-r': | ||
case 'run': | ||
await run(); | ||
break; | ||
case '-rb': | ||
case 'rollback': | ||
await rollback(second); | ||
break; | ||
case '-l': | ||
case 'list': | ||
await list(); | ||
break; | ||
case '-h': | ||
case 'help': | ||
help(); | ||
break; | ||
default: | ||
console.log('Invalid command'); | ||
help(); | ||
process.exit(1); | ||
break; | ||
} | ||
await parser({ command, second }); | ||
process.exit(0); |
export { default as pool } from './pool.module.js'; | ||
export { default as confirmation } from './confirmation.module.js'; | ||
export { default as parser } from './parser.module.js'; |
@@ -6,3 +6,3 @@ { | ||
}, | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"exports": "./dist/bin/index.js", | ||
@@ -22,3 +22,4 @@ "description": "Simple PostgreSQL migration tool for raw-SQL loving developers.", | ||
"build": "tsc", | ||
"pretty": "prettier . --write" | ||
"pretty": "prettier . --write", | ||
"test": "vitest" | ||
}, | ||
@@ -36,3 +37,3 @@ "bin": { | ||
"typescript": "^5.3.2", | ||
"vitest": "^0.34.6" | ||
"vitest": "^1.4.0" | ||
}, | ||
@@ -39,0 +40,0 @@ "peerDependencies": { |
145
README.md
# Postgrate š | ||
A simple, intuitive postgres migration tool for | ||
Welcome to Postgrate! This documentation provides a guide to using Postgrate, a | ||
simple, intuitive postgres migration tool for | ||
[node-postgres](https://node-postgres.com/)! | ||
@@ -28,3 +29,4 @@ | ||
Once that's done, you can run the following command: | ||
After installation, run the following command to initialize Postgrate in your | ||
project directory and create necessary configuration files: | ||
@@ -39,4 +41,4 @@ ```bash | ||
command at least once before running the `rollback` command, otherwise you will | ||
encounter an error. The `init` command has been included to accomodate future | ||
plans to support a configuration file.\* | ||
encounter an error. Running the `init` command will create a `.postgraterc` file | ||
with the same defaults as though the `init` command were never run.\* | ||
@@ -71,8 +73,135 @@ To create a migration, run: | ||
## Things to Note | ||
## Configuration | ||
This package will create a table in your database called `migrations`. While we | ||
hope to make this configurable in the future, for now this package will confilct | ||
with any concurrently used package that follows a similar strategy. | ||
As of version `1.1.0`, **Postgrate** supports the use of a configuration file! | ||
In the current release, a `.postgraterc` file in the root of your project | ||
directory written in `JSON` is the supported format. | ||
Here is an example configuration file with the package defaults: | ||
```json | ||
{ | ||
"rootDirectory": "db", | ||
"migrationsDirectory": "migrations", | ||
"rollbackDirectory": "rollbacks", | ||
"autoCreateRollbacks": true, | ||
"migrationsTableName": "migrations" | ||
} | ||
``` | ||
Although detailed, option names have been chosen to facilitate intuitive | ||
understanding of what each parameter does. That said, for completeness' sake, | ||
here are some details about each config option: | ||
## Configuration Options | ||
- rootDirectory: Override the default directory name. | ||
- migrationsDirectory: Override the default migrations directory name. | ||
- 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. | ||
# | ||
### `rootDirectory` | ||
The `rootDirectory` option allows you to override the default `db` directory | ||
name that **Postgrate** creates at the root of your project. | ||
**E.g.** | ||
```json | ||
"rootDirectory": "database" // then run `$ postgrate make <your-migration-name>` | ||
``` | ||
Output: | ||
```bash | ||
database | ||
|_migrations | ||
|_<timestamp>-<your-migration-name>.sql | ||
|_rollbacks | ||
|_rb-<timestamp>-<your-migration-name>.sql | ||
``` | ||
# | ||
### `migrationsDirectory` | ||
The `migrationsDirectory` option allows you to override the default `migrations` | ||
directory name that **Postgrate** creates in the `db` (or specified as above) | ||
directory. | ||
**E.g.** | ||
```json | ||
"migrationsDirectory": "mg" | ||
``` | ||
Output: | ||
```bash | ||
db | ||
|_mg | ||
|_<timestamp>-<your-migration-name>.sql | ||
|_rollbacks | ||
|_rb-<timestamp>-<your-migration-name>.sql | ||
``` | ||
# | ||
### `rollbacksDirectory` | ||
The `rollbacksDirectory` option allows you to override the default `rollbacks` | ||
directory name that **Postgrate** creates in the `db` (or specified as above) | ||
directory. | ||
**E.g.** | ||
```json | ||
"rollbacksDirectory": "rb" | ||
``` | ||
Output: | ||
```bash | ||
db | ||
|_migrations | ||
|_<timestamp>-<your-migration-name>.sql | ||
|_rb | ||
|_rb-<timestamp>-<your-migration-name>.sql | ||
``` | ||
# | ||
### `autoCreateRollbacks` | ||
The `autoCreateRollbacks` option can either be `true` or `false`. When set to | ||
`false` a `rollbacks` directory will not be created, regardless of whether the | ||
`rollbacksDirectory` option is set to a custom value. | ||
Note that in this case, should you wish to create a rollback and use the | ||
rollback command, rollback files will have to be created manually following the | ||
formula shown in the above examples, repeated here for convenience: | ||
``` | ||
rb_<migration-timestamp>-<migration-name>.sql | ||
``` | ||
Essentially, you will need to do the following: | ||
- create a `db/rollbacks` directory: name it `rollbacks` or whatever value you | ||
assigned to the `rollbacksDirectory` config parameter | ||
- create a rollback file within the directory and name it `rb_` plus the name of | ||
the migration file you wish to rollback | ||
# | ||
### `migrationsTableName` | ||
The `migrationsTableName` option allows you to set a cusom 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. | ||
## Commands | ||
@@ -79,0 +208,0 @@ |
import fs from 'fs'; | ||
export default function (): void { | ||
if (!fs.existsSync('db')) { | ||
fs.mkdirSync('db'); | ||
import config from '../config.js'; | ||
export default function (createConfigFile = false): void { | ||
if (createConfigFile) { | ||
fs.writeFileSync( | ||
'.postgraterc', | ||
JSON.stringify( | ||
{ | ||
rootDirectory: 'db', | ||
migrationsDirectory: 'migrations', | ||
rollbacksDirectory: 'rollbacks', | ||
autoCreateRollbacks: true, | ||
migrationsTableName: 'migrations', | ||
}, | ||
null, | ||
2, | ||
), | ||
); | ||
} | ||
if (!fs.existsSync('db/migrations')) { | ||
fs.mkdirSync('db/migrations', { recursive: true }); | ||
const { | ||
rootDirectory, | ||
migrationsDirectory, | ||
rollbacksDirectory, | ||
autoCreateRollbacks, | ||
} = config(); | ||
if (!fs.existsSync(rootDirectory)) { | ||
fs.mkdirSync(rootDirectory); | ||
} | ||
if (!fs.existsSync('db/rollbacks')) { | ||
fs.mkdirSync('db/rollbacks'); | ||
if (!fs.existsSync(`${rootDirectory}/${migrationsDirectory}`)) { | ||
fs.mkdirSync(`${rootDirectory}/${migrationsDirectory}`, { | ||
recursive: true, | ||
}); | ||
} | ||
if ( | ||
!fs.existsSync(`${rootDirectory}/${rollbacksDirectory}`) && | ||
autoCreateRollbacks | ||
) { | ||
fs.mkdirSync(`${rootDirectory}/${rollbacksDirectory}`); | ||
} | ||
console.log(` | ||
āØ Initialized postgrate & created \`db\` folder at root of project directory! āØ | ||
āØ Initialized postgrate & created \`${rootDirectory}\` folder at root of project directory! āØ | ||
`); | ||
} |
@@ -0,6 +1,9 @@ | ||
import config from '../config.js'; | ||
import pool from '../modules/pool.module.js'; | ||
export default async function () { | ||
const { migrationsTableName } = config(); | ||
const { rows } = await pool.query( | ||
'SELECT name, id, created_at FROM migrations ORDER BY id DESC', | ||
`SELECT name, id, created_at FROM ${migrationsTableName} ORDER BY id DESC`, | ||
); | ||
@@ -7,0 +10,0 @@ |
import fs from 'fs'; | ||
import init from './init.command.js'; | ||
import config, { IConfig } from '../config.js'; | ||
@@ -10,8 +11,26 @@ export default function (name: string): void { | ||
const fileName = generateMigrationFileName(name); | ||
const migrationFilePath = `db/migrations/${fileName}`; | ||
const rollbackFilePath = `db/rollbacks/rb-${fileName}`; | ||
const { | ||
rootDirectory, | ||
migrationsDirectory, | ||
rollbacksDirectory, | ||
autoCreateRollbacks, | ||
migrationsTableName, | ||
} = config(); | ||
const fileName = generateMigrationFileName({ | ||
name, | ||
config: { | ||
rootDirectory, | ||
migrationsDirectory, | ||
rollbacksDirectory, | ||
autoCreateRollbacks, | ||
migrationsTableName, | ||
}, | ||
}); | ||
const migrationFilePath = `${rootDirectory}/${migrationsDirectory}/${fileName}`; | ||
const rollbackFilePath = `${rootDirectory}/${rollbacksDirectory}/rb-${fileName}`; | ||
fs.writeFileSync(migrationFilePath, ''); | ||
fs.writeFileSync(rollbackFilePath, ''); | ||
if (autoCreateRollbacks) fs.writeFileSync(rollbackFilePath, ''); | ||
@@ -25,4 +44,10 @@ console.log( | ||
function generateMigrationFileName(name: string): string { | ||
if (!fs.existsSync('db/migrations')) { | ||
function generateMigrationFileName({ | ||
name, | ||
config, | ||
}: { | ||
name: string; | ||
config: IConfig; | ||
}): string { | ||
if (!fs.existsSync(`${config.rootDirectory}/${config.migrationsDirectory}`)) { | ||
init(); | ||
@@ -29,0 +54,0 @@ } |
import fs from 'fs/promises'; | ||
import fsSync from 'fs'; | ||
import { confirmation, pool } from '../modules/index.js'; | ||
import Config, { IConfig } from '../config.js'; | ||
export default async function (migrationId: string) { | ||
validate(migrationId); | ||
const name = await getMigrationRecordName(migrationId); | ||
checkRollbackFileExists(name); | ||
const config = Config(); | ||
const name = await getMigrationRecordName({ id: migrationId, config }); | ||
checkRollbackFileExists({ name, config }); | ||
await confirmation(name); | ||
await rollback({ name, migrationId }); | ||
await rollback({ name, migrationId, config }); | ||
pool.end(); | ||
@@ -17,2 +19,3 @@ } | ||
migrationId: string; | ||
config: IConfig; | ||
} | ||
@@ -27,6 +30,13 @@ | ||
async function getMigrationRecordName(id: string): Promise<string> { | ||
const { rows } = await pool.query('SELECT * FROM migrations WHERE id = $1', [ | ||
id, | ||
]); | ||
async function getMigrationRecordName({ | ||
id, | ||
config, | ||
}: { | ||
id: string; | ||
config: IConfig; | ||
}): Promise<string> { | ||
const { rows } = await pool.query( | ||
`SELECT * FROM ${config.migrationsTableName} WHERE id = $1`, | ||
[id], | ||
); | ||
@@ -41,4 +51,10 @@ if (!rows.length) { | ||
function checkRollbackFileExists(name: string): void { | ||
if (!fsSync.existsSync(`db/rollbacks/rb-${name}`)) { | ||
function checkRollbackFileExists({ | ||
name, | ||
config: { rootDirectory, rollbacksDirectory }, | ||
}: { | ||
name: string; | ||
config: IConfig; | ||
}): void { | ||
if (!fsSync.existsSync(`${rootDirectory}/${rollbacksDirectory}/rb-${name}`)) { | ||
console.error(`Rollback file ${name} does not exist`); | ||
@@ -49,7 +65,16 @@ process.exit(1); | ||
async function rollback({ name, migrationId }: IRollback): Promise<void> { | ||
const rollback = await fs.readFile(`db/rollbacks/rb-${name}`, 'utf-8'); | ||
async function rollback({ | ||
name, | ||
migrationId, | ||
config: { rootDirectory, migrationsTableName, rollbacksDirectory }, | ||
}: IRollback): Promise<void> { | ||
const rollback = await fs.readFile( | ||
`${rootDirectory}/${rollbacksDirectory}/rb-${name}`, | ||
'utf-8', | ||
); | ||
await pool.query(rollback); | ||
await pool.query('DELETE FROM migrations WHERE id = $1', [migrationId]); | ||
await pool.query(`DELETE FROM ${migrationsTableName} WHERE id = $1`, [ | ||
migrationId, | ||
]); | ||
console.log(`\nMigration ${name} rolled back\n`); | ||
} |
@@ -5,7 +5,9 @@ import fs from 'fs/promises'; | ||
import { confirmation, pool } from '../modules/index.js'; | ||
import Config, { IConfig } from '../config.js'; | ||
export default async function () { | ||
await createMigrationTable(); | ||
await fetchHistoricMigrations(); | ||
await runMigrations(); | ||
const config = Config(); | ||
await createMigrationTable(config); | ||
await fetchHistoricMigrations(config); | ||
await runMigrations(config); | ||
@@ -18,4 +20,7 @@ return pool.end(); | ||
const migrationsTableQuery = ` | ||
CREATE TABLE IF NOT EXISTS migrations ( | ||
async function createMigrationTable({ | ||
migrationsTableName, | ||
}: IConfig): Promise<void> { | ||
await pool.query(` | ||
CREATE TABLE IF NOT EXISTS ${migrationsTableName} ( | ||
id SERIAL PRIMARY KEY, | ||
@@ -26,18 +31,20 @@ name VARCHAR(255) NOT NULL, | ||
); | ||
`; | ||
async function createMigrationTable(): Promise<void> { | ||
await pool.query(migrationsTableQuery); | ||
`); | ||
} | ||
async function fetchHistoricMigrations(): Promise<void> { | ||
const { rows } = await pool.query('SELECT name FROM migrations'); | ||
async function fetchHistoricMigrations({ | ||
migrationsTableName, | ||
}: IConfig): Promise<void> { | ||
const { rows } = await pool.query(`SELECT name FROM ${migrationsTableName}`); | ||
rows.forEach((row) => historicMigrations.add(row.name)); | ||
} | ||
async function getMigrationFileNames(): Promise<string[]> { | ||
if (!fsSync.existsSync('db/migrations')) { | ||
async function getMigrationFileNames({ | ||
rootDirectory, | ||
migrationsDirectory, | ||
}: IConfig): Promise<string[]> { | ||
if (!fsSync.existsSync(`${rootDirectory}/${migrationsDirectory}`)) { | ||
init(); | ||
} | ||
const files = await fs.readdir('db/migrations'); | ||
const files = await fs.readdir(`${rootDirectory}/${migrationsDirectory}`); | ||
return files.sort( | ||
@@ -48,4 +55,4 @@ (a, b) => parseInt(a.split('-')[0]) - parseInt(b.split('-')[0]), | ||
async function determinePendingMigrations(): Promise<string[]> { | ||
const files = await getMigrationFileNames(); | ||
async function determinePendingMigrations(config: IConfig): Promise<string[]> { | ||
const files = await getMigrationFileNames(config); | ||
const pendingMigrations = files.filter( | ||
@@ -57,8 +64,14 @@ (file) => !historicMigrations.has(file), | ||
async function runMigration(migration: string): Promise<void> { | ||
const filePath = `db/migrations/${migration}`; | ||
async function runMigration({ | ||
migration, | ||
config: { rootDirectory, migrationsDirectory, migrationsTableName }, | ||
}: { | ||
migration: string; | ||
config: IConfig; | ||
}): Promise<void> { | ||
const filePath = `${rootDirectory}/${migrationsDirectory}/${migration}`; | ||
const file = await fs.readFile(filePath, 'utf-8'); | ||
await client.query(file); | ||
const { rows } = await client.query( | ||
'INSERT INTO migrations (name) VALUES ($1) RETURNING id;', | ||
`INSERT INTO ${migrationsTableName} (name) VALUES ($1) RETURNING id;`, | ||
[migration], | ||
@@ -73,4 +86,6 @@ ); | ||
pendingMigrations, | ||
config, | ||
}: { | ||
pendingMigrations: string[]; | ||
config: IConfig; | ||
}): Promise<void> { | ||
@@ -82,3 +97,3 @@ try { | ||
for (const migration of pendingMigrations) { | ||
await runMigration(migration); | ||
await runMigration({ migration, config }); | ||
} | ||
@@ -100,4 +115,4 @@ | ||
async function runMigrations(): Promise<void> { | ||
const pendingMigrations = await determinePendingMigrations(); | ||
async function runMigrations(config: IConfig): Promise<void> { | ||
const pendingMigrations = await determinePendingMigrations(config); | ||
@@ -111,3 +126,3 @@ if (!pendingMigrations.length) { | ||
await confirmation(pendingMigrations); | ||
await transact({ pendingMigrations }); | ||
await transact({ pendingMigrations, config }); | ||
} |
#!/usr/bin/env node | ||
import { help, init, list, make, rollback, run } from './commands/index.js'; | ||
import { parser } from './modules/index.js'; | ||
@@ -7,40 +7,4 @@ const args = process.argv.slice(2); | ||
switch (command) { | ||
case '-i': | ||
case 'init': | ||
init(); | ||
break; | ||
await parser({ command, second }); | ||
case '-m': | ||
case 'make': | ||
make(second); | ||
break; | ||
case '-r': | ||
case 'run': | ||
await run(); | ||
break; | ||
case '-rb': | ||
case 'rollback': | ||
await rollback(second); | ||
break; | ||
case '-l': | ||
case 'list': | ||
await list(); | ||
break; | ||
case '-h': | ||
case 'help': | ||
help(); | ||
break; | ||
default: | ||
console.log('Invalid command'); | ||
help(); | ||
process.exit(1); | ||
break; | ||
} | ||
process.exit(0); |
export { default as pool } from './pool.module.js'; | ||
export { default as confirmation } from './confirmation.module.js'; | ||
export { default as parser } from './parser.module.js'; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38814
34
1017
234
9