Git Product home page Git Product logo

leapfrogtechnology / sync-db Goto Github PK

View Code? Open in Web Editor NEW
32.0 14.0 15.0 2.71 MB

Utility to synchronize relational database objects across databases.

Home Page: https://www.npmjs.com/package/@leapfrogtechnology/sync-db

License: MIT License

JavaScript 0.12% Batchfile 0.02% TypeScript 97.93% Shell 1.93%
database sync db sql database-objects hacktoberfest migrations database-migrations cli

sync-db's Introduction

sync-db

Command line utility to synchronize and version control relational database objects across databases.

Version Travis PRs Welcome LICENSE

Installation

Using npm:

$ npm install @leapfrogtechnology/sync-db

You can install it globally as well.

$ npm install -g @leapfrogtechnology/sync-db

Drivers Installation

You'll need to install the database driver specific to your project separately.

For instance - if your project uses MSSQL, you will need to do:

$ yarn add mssql

This utility uses Knex under the hood so these are the supported drivers.

Usage

You can use sync-db both as a CLI utility and programmatically.

$ npm install -g @leapfrogtechnology/sync-db
$ sync-db COMMAND
running command...
$ sync-db (-v|--version|version)
@leapfrogtechnology/sync-db/2.1.1 linux-x64 node-v20.12.2
$ sync-db --help [COMMAND]
USAGE
  $ sync-db COMMAND
...

Commands

When installed globally, you can invoke the CLI directly.

The CLI exposes a single command sync-db that runs synchronize operation based on your configuration.

sync-db

USAGE
  $ sync-db

See code: src/commands/index.ts

sync-db help [COMMAND]

display help for sync-db

USAGE
  $ sync-db help [COMMAND]

ARGUMENTS
  COMMAND  command to show help for

OPTIONS
  --all  see all commands in CLI

See code: @oclif/plugin-help

sync-db make NAME

Make migration files from the template.

USAGE
  $ sync-db make NAME

ARGUMENTS
  NAME  Object or filename to generate.

OPTIONS
  -c, --config=config        Custom configuration file.
  -t, --type=TYPE            [default: migration] Type of file to generate.
  --create                   Generate create table stub.
  --object-name=object-name  Name of table/view/routine to migrate.

See code: src/commands/make.ts

sync-db make-publish

Publish migration templates files.

USAGE
  $ sync-db make-publish

OPTIONS
  -c, --config=config  Custom configuration file.

See code: src/commands/make-publish.ts

sync-db migrate-latest

Run the migrations up to the latest changes.

USAGE
  $ sync-db migrate-latest

OPTIONS
  -c, --config=config         Custom configuration file.
  --connection-resolver=PATH  Path to the connection resolver.
  --dry-run                   Dry run migration.
  --only=CONNECTION_ID(s)     Filter provided connection(s). Comma separated ids eg: id1,id2

See code: src/commands/migrate-latest.ts

sync-db migrate-list

List all the migrations.

USAGE
  $ sync-db migrate-list

OPTIONS
  -c, --config=config         Custom configuration file.
  --connection-resolver=PATH  Path to the connection resolver.
  --only=CONNECTION_ID(s)     Filter provided connection(s). Comma separated ids eg: id1,id2

See code: src/commands/migrate-list.ts

sync-db migrate-rollback

Rollback migrations up to the last run batch.

USAGE
  $ sync-db migrate-rollback

OPTIONS
  -c, --config=config         Custom configuration file.
  --connection-resolver=PATH  Path to the connection resolver.
  --dry-run                   Dry run rollback.
  --only=CONNECTION_ID(s)     Filter provided connection(s). Comma separated ids eg: id1,id2

See code: src/commands/migrate-rollback.ts

sync-db prune

Drop all the synchronized db objects except the ones created via migrations.

USAGE
  $ sync-db prune

OPTIONS
  -c, --config=config         Custom configuration file.
  --connection-resolver=PATH  Path to the connection resolver.
  --dry-run                   Dry run prune.
  --only=CONNECTION_ID(s)     Filter provided connection(s). Comma separated ids eg: id1,id2

See code: src/commands/prune.ts

sync-db synchronize

Synchronize all the configured database connections.

USAGE
  $ sync-db synchronize

OPTIONS
  -c, --config=config         Custom configuration file.
  -f, --force                 Force synchronization.
  --connection-resolver=PATH  Path to the connection resolver.
  --dry-run                   Dry run synchronization.
  --only=CONNECTION_ID(s)     Filter provided connection(s). Comma separated ids eg: id1,id2
  --skip-migration            Skip running migrations.

See code: src/commands/synchronize.ts

Refer to the examples section below for full example with CLI usage.

Programmatic Usage

You may use programmatic API as shown below in case you need better flexibility based on your needs.

import { synchronize, loadConfig, resolveConnections } from '@leapfrogtechnology/sync-db';

(async () => {
  const config = await loadConfig(); // Load sync-db.yml
  const connections = await resolveConnections(); // Load connections.sync-db.json

  // Invoke the command.
  await synchronize(config, connections);
})();

You can also pass your own database connection (eg: Knex connection) instead of resolving connections.sync-db.json file.

import { knex } from 'knex';
import { synchronize, loadConfig } from '@leapfrogtechnology/sync-db';

(async () => {
  const config = await loadConfig(); // Load sync-db.yml
  const connection = knex({
    // Your Knex connection instance.
    client: 'mssql',
    connection: {
      host: 'host',
      user: 'userName',
      password: 'password',
      database: 'dbName'
    }
  });
  const options = { force: false };

  // Invoke the command.
  await synchronize(config, connection, options);
})();

Configuration

  1. Sync Configuration
  2. Database Connections

1. Sync Configuration

sync-db expects the configuration file sync-db.yml to be present in your working directory. This holds all your configurations.

sync-db.yml

# Base path for the SQL source files.
basePath: /path/to/sql

sql:
  - schema/<schema_name>.sql
  - function/<schema_name>/<function_name>.sql.drop # While synchronizing this will only be dropped, not synced.
  - procedure/<schema_name>/<procedure_name>.sql

Configuration Options

  • basePath (string) - Base directory to hold all your SQL & migrations codebase (default: "src").

  • sql (array) - A series of SQL file paths that are to be run in ordered sequence (top to bottom), based on dependency. It should be noted that the source files needs to follow this convention of directory hierarchy. File paths listed here are relative to ${basePath}/sql value.

  • migration (array) - Migrations specific configurations.

    • sourceType (string) - Type of migration file. Value defaults to sql. - example: javascript, typescript.
    • tableName (string) - Custom name for table to store migrations meta data.
  • connectionResolver (string) - Connection resolver file name optional if connections are resolved using connections.sync-db.json.

2. Database Connections

Database connections are configured in connections.sync-db.json file in your project root directory as shown below.

Since it contains all your database credentials, it is recommended that you DO NOT COMMIT it to VCS.

connections.sync-db.json

{
  "connections": [
    {
      "id": "db1",
      "host": "localhost",
      "port": 1433,
      "user": "db1user",
      "database": "db1",
      "password": "password",
      "client": "mssql"
    }
  ]
}

Note: The connections key expects an array, so you can also provide multiple databases and sync-db ensures your configured db objects are synced across all these databases.

Connection using connection-resolver.js

File consists a resolve function which returns an array of connections to the databases. Add the resolver file name to connectionResolver field in sync-db.yml.

Caveat

Setup and Teardown steps aren't always run within a single transaction. You need to pass the transaction instance object explicitly to make sure this happens.

await db.transaction(async trx => {
  // Rollback and create all db objects using config.
  await synchronize(config, trx);
});

Examples

  1. Node MSSQL JavaScript Sample
  2. Node MSSQL TypeScript Sample
  3. Node MSSQL Programmatic Usage Sample
  4. Node PostgreSQL JavaScript Sample
  5. Node PostgreSQL TypeScript Sample

Changelog

Check the CHANGELOG for release history.

Contributing

Feel free to send pull requests.

Development

Setting up

# Clone the repository.
$ git clone https://github.com/leapfrogtechnology/sync-db.git

# Go to the project directory.
$ cd sync-db

# Install dependencies. (Notice that we use yarn for this.)
$ yarn

Building / Testing

# Generate build.
$ yarn build

# Run tests
$ yarn test

# Invoke the CLI locally (development mode).
$ bin/run-dev.sh

Release

Publish a new version.

Create a PR updating version in package.json to master.

License

Licensed under The MIT License.

FOSSA Status

sync-db's People

Contributors

cham11ng avatar dependabot[bot] avatar fossabot avatar kabirbaidhya avatar kshitish182 avatar leapfrog-bot avatar mesaugat avatar parwatcodes avatar prabeshpd avatar safalpandey avatar samirsilwal avatar sarojrana avatar sbimochan avatar shradayshakya avatar silwalanish avatar soneshaps avatar thesamiroli avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sync-db's Issues

Get access to `setup` and `teardown` methods from cli

I have a use case where I need to run the teardown script again after run and post_sync scripts have completed.

I think we need to provide access to the teardown and setup steps independently as well.

Something like:

  1. teardown
    # Rolls back all the db objects
    $ sync-db --teardown
  2. setup
    # Creates all the db objects
    $ sync-db --setup
  3. setup
    # Rolls back and Creates all the db objects
    $ sync-db

Ability to use a custom connection resolver

Current Behavior

For sync-db CLI, the only way to provide database connections is through the connections.sync-db.json. There's no other way.

If you need to resolve connections in any other way (eg: retrieve it from a different service or network), you'll need to use the Programmatic API and write your own code to do so - which is the only workaround.

Proposal

Need an ability to define and use a custom connection resolver which resolves the database connections for the CLI.

What is a resolver?
A resolver is a javascript file resolver.js that exposes a method to resolve connections.

How would you define a resolver?
Create a connections.resolver.js that exports a function named resolve which return a Promise that resolves to a lis

// connections.resolver.js

/**
 * Resolve a list of database connections.
 *
 * @returns {Promise<ConnectionConfig[]>}
 */
export function resolve() {
  // Do something here to resolve your database connections.
  const connections = [ ... ];

  return connections;
}

Or, this should be supported too.

// connections.resolver.js

exports.resolve = function() {
  // Do something here to resolve your database connections.
  const connections = [ ... ];

  return connections;
};

Use Cases

How database credentials are managed, is user-specific and might differ from project to project. For example - some might use it via environment variables, or a .env file and in case there are multiple databases, they might have a json file similar to connections.sync-db.json file.

In addition, you might need to fetch these creds from external services like Vault or AWS Secret Manager which would definitely be the case if you have a fully cloud native infrastructure.

All of these use cases are possible using a custom resolver file, where user themselves provide us how to resolve their database connections - it could be from other files, configurations or from across the network or services.

Other Requirements

  1. This should be an opt-in feature. A resolver file is used only if connections.resolver.js exists in the CWD.
  2. Using a resolver would be mutually exclusive to using the connections.sync-db.json; it should not use that file if resolver exists.
  3. Validate the resolver definition and database connections (against the schema) before proceeding further in the synchronization process.

Reference

See how connections are resolved now here ๐Ÿ‘‰ https://github.com/leapfrogtechnology/sync-db/blob/master/src/config.ts#L32-L56.

Add new example project based on postgres

Add new example project based on postgres.

Requirements

  1. Add the sample project under examples/node-app-pg
  2. Make it similar to the MSSQL example here but use postgres insteaad of MSSQL.
  3. Requires all the functionalities, docs, migrations like what the mssql example has.
  4. Add the new example link under the main README here

One time batch job and preparation SQL scripts

Feature Discussion

Batch jobs with preparation scripts

Problem background

One common use case is to run one-time batch job or data operation - which is a series of SQL scripts to be run on N databases.

Consider these examples:

  • ETL job running a series of data transformation logic (procedure calls) on source tables to prepare destination tables with processed data
  • data analysis - series of data processing (procedure calls) to analyse the data from tables and write analysed outputs to destination tables.
  • or any kind of batch data operations job

In these kinds of jobs, the logical components are not needed in the DB once the job is complete so they could be dropped.

Proposed Implementation

Example of the config of how we can achieve this.

sql:
  prep:
    # These are the preparation scripts or the dependencies required by the batch script
    - schema/transformation.sql
    - view/transformation/view1.sql
    - view/transformation/view1.sql
    - function/transformation/some_func.sql
    - procedure/transformation/proc1.sql
    - procedure/transformation/proc2.sql

hooks:
  script:
   # The actual batch script or a series of these
    - scripts/run_transform.sql

Steps

  • drop (if exists) the objects under sql.prep in reverse order
  • create the objects under sql.prep in the normal order
  • run the sql scripts hooks.script
  • drop (if exists) the objects under sql.prep in reverse order

This isn't a database synchronization operation but a general batch job running mechanism.

TLDR - no db objects exists in the db once the batch job (script) is executed.

@mesaugat @SafalPandey Let me know what do you think?

Logs are misleading in rollback / teardown stage

Issue

When the folder names where the database objects are in do not match one of procedure, schema, view or function, the logs explicitly say Rolling back <object name> and Executed: <xx> ms However the objects aren't removed from the database.

Expected behavior

I think it should raise an error instead. We need to make it clear that the directory name did not match the expected convention and raise an error if rollback script is not executed.

Log trail

  sync-db:db1 Synchronize database +0ms
  sync-db:db1 Running rollback on a database: db1 +0ms
  sync-db:db1 Rolling back: etl.noop +0ms
  sync-db:db1 Executed:   +48ms
  sync-db:db1 Rolling back: etl +0ms
  sync-db:db1 Executed:   +2ms
  sync-db:db1 Finished running rollback +273ms
  sync-db:db1 Running setup +0ms
  sync-db:db1 Running schemas/etl.sql +0ms
  sync-db:db1 Running procedures/etl/noop.sql +0ms
  sync-db Error caught:  { TransactionError: Transaction has been aborted.
...

Error when removed migration field from sync-db.yml

  • yml configuration i used with sync-db version ---> 1.0.0-experimental.20200628
    Capture

Scenario:

  • while trying just to synchronize some tables, didn't want any migration to run
  • so i simply removed migration field in yml config and ran synchronize command but it errored out as shown below:
    Capture1

So it looks like migration field is a compulsary in yml right now and had to use --skip-migration option as way around.

cc @kabirbaidhya

Release version 1.0.0

sync-db has been fairly stable and is being used in production for quite a while. With the recent bug fixes it seems more and more likely that we should get it out of beta and take it to v1.0.0.

Word on the street: If we want to make @dependabot happy, we can fix the security warnings and release version 1.0.0 to the world.

Remove support for Node 10

Node 10 has already dropped active support and it's security support is ending in a few months time.

endoflife date_nodejs

  • Update package.json engine version to use Node 12 LTS and above
  • Remove Node 10 from .travis.yml and include Node 12, 14
  • Upgrade packages that don't support Node 12

New CLI arg to generate connections file using the environment variables

CLI Usage

$ sync-db --generate-connections

Requirements

  1. Introduce a CLI argument / flag --generate-connections that if invoked with - should generate a connections.sync-db.json file.
  2. The file should be generated in the path same as sync-db.yml.
  3. If successful it should print out a message with the generated file path.
  4. In case of failure it should display the error message of why it failed.
  5. Use these environment variables to get the credentials:
    • DB_HOST - Database Host
    • DB_PASSWORD - Password
    • DB_NAME - Database name
    • DB_USERNAME - Database username
    • DB_PORT - Port
    • DB_CLIENT - Database client eg: mssql, mysql
    • DB_ENCRYPTION - Boolean value to set whether or not to use encrypted connection. Should be false by default unless explicitly set as true.

Proof of concept / demo - the feature explained above should work in the same way as this demo bash script below.

echo '{
  "connections": [
    {
      "client": "'$DB_CLIENT'",
      "host": "'"$DB_HOST"'",
      "port": '"$DB_PORT"',
      "user": "'"$DB_USERNAME"'",
      "password": "'"$DB_PASSWORD"'",
      "database": "'"$DB_NAME"'",
      "options": {
        "encrypt": '"${DB_ENCRYPTION:=false}"'
      }
    }
  ]
}' > 'connections.sync-db.json'

Simplify all the examples and bump sync-db to latest version

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.