Skip to content
This repository has been archived by the owner on May 19, 2023. It is now read-only.

feat: db migrations #269

Merged
merged 18 commits into from
Nov 12, 2020
Merged
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
2 changes: 1 addition & 1 deletion DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ npm install -g @rsksmart/rif-marketplace-cache
First synchronize database scheme:

```bash
$ rif-marketplace-cache db-sync --config ./path/to/custom_config
$ rif-marketplace-cache db-migration --up --config ./path/to/custom_config
```

Pre-fetch all previous events:
Expand Down
35 changes: 24 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,8 @@ $ npm install -g @rsksmart/rif-marketplace-cache
// Connection to your database
$ export RIFM_DB=postgres://user:pass@localhost/db

// Sync the schema of database
$ rif-marketplace-cache db-sync
// Database migrations
$ rif-marketplace-cache db-migration --up

// Connection to your blockchain provider
$ export RIFM_PROVIDER=ws://localhost:8545
Expand All @@ -405,26 +405,39 @@ For some more details on how to deploy this server please see [Deployment guide]

### Commands
<!-- commands -->
* [`rif-marketplace-cache db-sync`](#rif-marketplace-cache-db-sync)
* [`rif-marketplace-cache db-migration`](#rif-marketplace-cache-db-migration)
* [`rif-marketplace-cache precache [SERVICE]`](#rif-marketplace-cache-precache-service)
* [`rif-marketplace-cache purge [SERVICE]`](#rif-marketplace-cache-purge-service)
* [`rif-marketplace-cache start`](#rif-marketplace-cache-start)

#### `rif-marketplace-cache db-sync`
#### `rif-marketplace-cache db-migration`

synchronize database schema

```
USAGE
$ rif-marketplace-cache db-sync
$ rif-marketplace-cache db-migration

OPTIONS
--config=config path to JSON config file to load
--db=db database connection URI
--force removes all tables and recreates them
--log=error|warn|info|debug [default: error] what level of information to log
--log-filter=log-filter what components should be logged (+-, chars allowed)
--log-path=log-path log to file, default is STDOUT
-d, --down Undo db migrations
-d, --generate=generate Generate migrations using template [--generate=migration_name]
-m, --migration=migration Migration file
-t, --to=to Migrate to
-u, --up Migrate DB
--config=config path to JSON config file to load
--db=db database connection URI
--log=error|warn|info|verbose|debug [default: warn] what level of information to log
--log-filter=log-filter what components should be logged (+-, chars allowed)
--log-path=log-path log to file, default is STDOUT

EXAMPLES
$ rif-marketplace-cache db --up
$ rif-marketplace-cache db --down
$ rif-marketplace-cache db --up --to 0-test
$ rif-marketplace-cache --up --migrations 01-test --migrations 02-test
$ rif-marketplace-cache --up --db ./test.sqlite --to 09-test
$ rif-marketplace-cache --down --db ./test.sqlite --to 09-test
$ rif-pinning db --generate my_first_migration
```

#### `rif-marketplace-cache precache [SERVICE]`
Expand Down
58 changes: 58 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"sequelize-typescript": "^2.0.0-beta.0",
"sql-formatter": "^2.3.3",
"sqlite3": "^5.0.0",
"umzug": "^2.3.0",
"web3-core": "^1.3.0",
"web3-eth": "^1.3.0",
"web3-eth-contract": "^1.3.0",
Expand Down Expand Up @@ -117,6 +118,7 @@
"@types/sinon": "^9.0.3",
"@types/sinon-chai": "^3.2.4",
"@types/sql-formatter": "^2.3.0",
"@types/umzug": "^2.2.3",
"@types/validator": "^13.1.0",
"bignumber.js": "^9.0.0",
"chai": "^4.2.0",
Expand Down
166 changes: 166 additions & 0 deletions src/cli/db-migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import fs from 'fs'
nduchak marked this conversation as resolved.
Show resolved Hide resolved
import path from 'path'
import { flags } from '@oclif/command'
import { OutputFlags } from '@oclif/parser'

import DbMigration from '../migrations'
import { BaseCLICommand } from '../utils'
import { sequelizeFactory } from '../sequelize'
import config from 'config'

const MigrationTemplate = `import { QueryInterface } from 'sequelize'
import { Sequelize } from 'sequelize-typescript'

export default {
// eslint-disable-next-line require-await
async up (queryInterface: QueryInterface, sequelize: Sequelize): Promise<void> {
return Promise.reject(Error('Not implemented'))
},
// eslint-disable-next-line require-await
async down (queryInterface: QueryInterface, sequelize: Sequelize): Promise<void> {
return Promise.reject(Error('Not implemented'))
}
}
`

export default class DbMigrationCommand extends BaseCLICommand {
static hidden: boolean;
static flags = {
...BaseCLICommand.flags,
db: flags.string({ description: 'database connection URI', env: 'RIFM_DB' }),
up: flags.boolean({
char: 'u',
description: 'Migrate DB',
exclusive: ['down', 'generate']
}),
down: flags.boolean({
char: 'd',
description: 'Undo db migrations',
exclusive: ['up', 'generate']
}),
generate: flags.string({
char: 'd',
description: 'Generate migrations using template [--generate=migration_name]',
exclusive: ['up', 'down']
}),
to: flags.string({
char: 't',
description: 'Migrate to'
}),
migration: flags.string({
char: 'm',
description: 'Migration file',
multiple: true
})
}

static description = 'DB migrations'

static examples = [
'$ rif-marketplace-cache db --up',
'$ rif-marketplace-cache db --down',
'$ rif-marketplace-cache db --up --to 0-test',
'$ rif-marketplace-cache --up --migrations 01-test --migrations 02-test',
'$ rif-marketplace-cache --up --db ./test.sqlite --to 09-test',
'$ rif-marketplace-cache --down --db ./test.sqlite --to 09-test',
'$ rif-pinning db --generate my_first_migration'
]

private migration: DbMigration | undefined

protected resolveDbPath (db: string): string {
if (!db) {
return path.resolve(this.config.dataDir, config.get<string>('db'))
}

const parsed = path.parse(db)

// File name
if (!parsed.dir) {
return path.resolve(
this.config.dataDir,
parsed.ext
? db
: `${parsed.base}.sqlite`
)
} else {
if (db[db.length - 1] === '/') {
throw new Error('Path should include the file name')
}
return path.resolve(`${db}${parsed.ext ? '' : '.sqlite'}`)
}
}

async migrate (migrations?: string[], options?: { to: string }): Promise<void> {
if (!(await this.migration!.pending()).length) {
this.log('No pending migrations found')
this.exit()
}

this.log('DB migrations')
await this.migration!.up(options)
this.log('Done')
}

async undo (migrations?: string[], options?: { to: string }): Promise<void> {
if (!(await this.migration!.executed()).length) {
this.log('No executed migrations found')
this.exit()
}

this.log('Undo DB migrations')
await this.migration!.down(options)
this.log('Done')
}

generateMigration (name: string): void {
const migrationsFolder = path.resolve(process.cwd(), './migrations')
const scriptsFolder = path.resolve(process.cwd(), './migrations/scripts')
const fileName = `./${Date.now()}-${name}.ts`
const filePath = path.resolve(scriptsFolder, fileName)

if (!fs.existsSync(migrationsFolder)) {
throw new Error('Migrations folder not found. Please run command from project root and make sure that you have \'migrations\' folder setup')
}

this.log(`Creating migration ${fileName}`)

if (!fs.existsSync(scriptsFolder)) {
fs.mkdirSync(scriptsFolder)
}

fs.writeFileSync(filePath, MigrationTemplate)
this.log('Done')
}

async run (): Promise<void> {
const { flags: originalFlags } = this.parse(DbMigrationCommand)
const parsedFlags = originalFlags as OutputFlags<typeof DbMigrationCommand.flags>

if (parsedFlags.db) {
config.util.extendDeep(config, { db: this.resolveDbPath(parsedFlags.db) })
}

if (parsedFlags.generate) {
this.generateMigration(parsedFlags.generate)
}

// Init database connection
const sequelize = sequelizeFactory()
this.migration = new DbMigration(sequelize)

if (!parsedFlags.up && !parsedFlags.down && !parsedFlags.generate) {
throw new Error('One of \'--generate, --up, --down\' required')
}

if (parsedFlags.up) {
await this.migrate(parsedFlags.migration, parsedFlags)
}

if (parsedFlags.down) {
await this.undo(parsedFlags.migration, parsedFlags)
}

this.exit()
}
}
29 changes: 0 additions & 29 deletions src/cli/db-sync.ts

This file was deleted.

Loading