0.01
No commit activity in last 3 years
No release in over 3 years
Simple concurrent importer for MySQL
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

MysqlImport

Gem Version Build Status Code Climate Test Coverage Dependency Status

Simple concurrent importer for MySQL using load_data_infile2.

Installation

Add to your application's Gemfile:

gem 'mysql_import'

And bundle.

Examples

Basic Usage

For exampole, if you want to import to users table from /path/to/users.csv:

db_config = {
  host: 'localhost'
  database: 'mysql_import_test'
  username: 'root'
}
importer = MysqlImport.new(db_config)
importer.add('/path/to/users.csv')
importer.import
# => Import to `users` tables

Multiple import:

importer = MysqlImport.new(db_config)
importer.add('/path/to/users.csv')
importer.add('/path/to/groups.csv')
importer.add('/path/to/departments.csv')
importer.import
# => Import to three tables from three csv files

MysqlImport has the concurrency because it uses the parallel gem.

With import options:

importer = MysqlImport.new(db_config)
importer.add('/path/to/users1.csv', table: 'users')
importer.add('/path/to/users2.csv', table: 'users')
importer.add('/path/to/users3.csv', table: 'users')
importer.import
# => Import to `users` table from three csv files

Options

#initialize

Key that can be passed to the second argument of the option of MysqlImport#initialize is the four types.

concurrency: The number of threads to use. Ruby' GIL is released when the IO waiting occurs in mysql, you might be effective by concurrent processing. (default: 2)

importer = MysqlImport.new(db_config, concurrency: 4)

log: This is an option for the logger. (default: nil)

# File path
importer = MysqlImport.new(db_config, log: '/path/to/import.log')
# nil(This is the same as `/dev/null`)
importer = MysqlImport.new(db_config, log: nil)
# STDOUT / STDERR
importer = MysqlImport.new(db_config, log: $stdout)
# Custom logger
importer = MysqlImport.new(db_config, log: CustomLogger.new)

debug: This is a flag to the level of the logger to debug. (default: false)

importer = MysqlImport.new(db_config, log: $stdout, debug: true)

sql_opts: This is the option of import to be passed directly to the second argument of LoadDataInfile2#initialize.

See more details for import options.

https://github.com/nalabjp/load_data_infile2#sql-options

#add

The second argument of MysqlImport#add will be passed directly to the second argument of LoadDataInfile2#import.

See more details for import options.

https://github.com/nalabjp/load_data_infile2#sql-options

Filter

If you want to import only a specific file, you can specify the file.

The specification of the file will be used regular expression

String

importer = MysqlImport.new(db_config)
importer.add('/path/to/users.csv')
importer.add('/path/to/groups.csv')
importer.add('/path/to/departments.csv')
importer.import('users')
# => Only import to `users` table

Array

importer.import(['users', 'groups'])
# => Import to `users` and `groups` table

If empry:

importer.import([])
# => Do not import anything

Hook

You are able to set the hook immediately before and after import.

The hook will accept either String or Proc or Array.

String

String is evaluated directly as SQL.

importer = MysqlImport.new(db_config)
importer.add(
  '/path/to/users.csv',
  {
    before: 'TRUNCATE TABLE users;'
  }
)
importer.import
# => Truncate query is always executed before import.

Proc

If you want to make the subsequent processing based on the execution result of SQL, you should use Proc.

Arguments that are passed to Proc is an instance of LoadDataInfile2::Client, which is a subclass of Mysql2::Client.

importer = MysqlImport.new(db_config)
importer.add(
  '/path/to/users.csv',
  {
    before: ->(cli) {
      res = cli.query('SELECT COUNT(*) AS c FROM users;')
      cli.query('TRUNCATE TABLE users;') if res.first['c'] > 0
    }
  }
)
importer.import
# => If there is one or more records in `users` table, truncate query is executed.

Array

Array of elements you need to use String or Proc.

importer = MysqlImport.new(db_config)
importer.add(
  '/path/to/users.csv',
  {
    before: [
      "SET sql_mode = 'STRICT_TRANS_TABLES';",
      ->(cli) {
        res = cli.query('SELECT COUNT(*) AS c FROM users;')
        cli.query('TRUNCATE TABLE users;') if res.first['c'] > 0
      }
    ],
    after: [
      'SET @i = 0;',
      'UPDATE users SET order = (@i := @i + 1) ORDER BY name, email ASC;',
    ]
  }
)
importer.import

Skip all subsequent processing

If you want to skip all subsequent processing, you will need to raise MysqlImport::Break in Proc.

importer = MysqlImport.new(db_config)
importer.add(
  '/path/to/users.csv',
  {
    before: ->(cli) {
      res = cli.query('SELECT COUNT(*) AS c FROM users;')
      raise MysqlImport::Break if res.first['c'] > 0
    },
    after: [
      'SET @i = 0;',
      'UPDATE users SET order = (@i := @i + 1) ORDER BY name, email ASC;',
    ]
  }
)
importer.import
# => If there is one or more records in `users` table, import and after hook will be skipped.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/nalabjp/mysql_import.

License

The gem is available as open source under the terms of the MIT License.