Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow to provide migrations manually #911

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import runner from './runner'
import { Migration } from './migration'
import { RunnerOption, MigrationBuilder, PgType } from './types'
import { RunnerOption, MigrationBuilder, MigrationBuilderActions, PgType } from './types'
import PgLiteral from './operations/PgLiteral'
import {
PgLiteralValue,
Expand Down Expand Up @@ -119,10 +119,11 @@ import {
} from './operations/viewsMaterializedTypes'

export {
PgType,
PgLiteral,
Migration,
PgType,
MigrationBuilder,
MigrationBuilderActions,
RunnerOption,
PgLiteralValue,
Value,
Expand Down
39 changes: 31 additions & 8 deletions src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
MigrationDirection,
RunnerOptionClient,
RunnerOptionUrl,
RunnerOptionMigrations,
RunnerOption,
Logger,
} from './types'
Expand All @@ -20,19 +21,41 @@ const idColumn = 'id'
const nameColumn = 'name'
const runOnColumn = 'run_on'

const isMigrationsOptions = (options: unknown): options is RunnerOptionMigrations =>
!!(options as RunnerOptionMigrations).migrations

const importMigration = async (
filePath: string,
module: string | MigrationBuilderActions | (() => MigrationBuilderActions | Promise<MigrationBuilderActions>),
): Promise<MigrationBuilderActions> => {
if (typeof module === 'string') {
// eslint-disable-next-line global-require,import/no-dynamic-require,security/detect-non-literal-require
return require(path.relative(__dirname, filePath))
}

if (typeof module === 'function') {
// eslint-disable-next-line no-return-await
return await module()
}

return module
}

const loadMigrations = async (db: DBConnection, options: RunnerOption, logger: Logger) => {
try {
let shorthands: ColumnDefinitions = {}
const files = await loadMigrationFiles(options.dir, options.ignorePattern)

const files = isMigrationsOptions(options)
? options.migrations
: Object.fromEntries(
(await loadMigrationFiles(options.dir, options.ignorePattern)).map((f) => [`${options.dir}/${f}`, f]),
)

return (
await Promise.all(
files.map(async (file) => {
const filePath = `${options.dir}/${file}`
const actions: MigrationBuilderActions =
path.extname(filePath) === '.sql'
? await migrateSqlFile(filePath)
: // eslint-disable-next-line global-require,import/no-dynamic-require,security/detect-non-literal-require
require(path.relative(__dirname, filePath))
Object.entries(files).map(async ([filePath, module]) => {
const actions =
path.extname(filePath) === '.sql' ? await migrateSqlFile(filePath) : await importMigration(filePath, module)
shorthands = { ...shorthands, ...actions.shorthands }
return new Migration(
db,
Expand Down
35 changes: 26 additions & 9 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,6 @@ export interface RunnerOptionConfig {
* @default 'public'
*/
schema?: string | string[]
/**
* The directory containing your migration files.
*/
dir: string
/**
* Check order of migrations before running them.
*/
Expand All @@ -235,10 +231,6 @@ export interface RunnerOptionConfig {
* Treats `count` as timestamp.
*/
timestamp?: boolean
/**
* Regex pattern for file names to ignore (ignores files starting with `.` by default).
*/
ignorePattern?: string
/**
* Run only migration with this name.
*/
Expand Down Expand Up @@ -284,6 +276,29 @@ export interface RunnerOptionConfig {
verbose?: boolean
}

export interface RunnerOptionDir {
/**
* The directory containing your migration files.
*/
dir: string
/**
* Regex pattern for file names to ignore (ignores files starting with `.` by default).
*/
ignorePattern?: string
}

export interface RunnerOptionMigrations {
/**
* A dictionary containing migrations to run.
*
* The object can follow th
*/
migrations: Record<
string,
string | MigrationBuilderActions | (() => MigrationBuilderActions | Promise<MigrationBuilderActions>)
>
}

export interface RunnerOptionUrl {
/**
* Connection string or client config which is passed to [new pg.Client](https://node-postgres.com/api/client#constructor)
Expand All @@ -300,4 +315,6 @@ export interface RunnerOptionClient {
dbClient: ClientBase
}

export type RunnerOption = RunnerOptionConfig & (RunnerOptionClient | RunnerOptionUrl)
export type RunnerOption = RunnerOptionConfig &
(RunnerOptionClient | RunnerOptionUrl) &
(RunnerOptionDir | RunnerOptionMigrations)
3 changes: 2 additions & 1 deletion test/ts/customRunner.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { resolve } from 'path'
import { Client } from 'pg'
import runner, { RunnerOption } from '../../dist'
import { RunnerOptionDir, RunnerOptionMigrations } from '../../dist/types'

type TestOptions = {
count?: number
Expand All @@ -13,7 +14,7 @@ type Options = ({ databaseUrl: string } & TestOptions) | ({ dbClient: Client } &
/* eslint-disable no-console */
// eslint-disable-next-line import/prefer-default-export
export const run = async (options: Options): Promise<boolean> => {
const opts: Omit<RunnerOption, 'direction'> & Options = {
const opts: Omit<RunnerOption, 'direction'> & Options & (RunnerOptionDir | RunnerOptionMigrations) = {
migrationsTable: 'migrations',
dir: resolve(__dirname, 'migrations'),
expectedUpLength: 2,
Expand Down