myq 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +45 -3
- data/contrib/completion/_myq +3 -0
- data/lib/myq.rb +3 -2
- data/lib/myq/commands.rb +115 -39
- data/lib/myq/core.rb +251 -0
- data/lib/myq/version.rb +1 -1
- data/myq.gemspec +1 -0
- data/sample/activerecord.erb +3 -0
- metadata +19 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: a8b3fd06c82c8b6f9b0ceaeeda5cb83cda1fc660
         | 
| 4 | 
            +
              data.tar.gz: 81876b670a2ad08727a1dcc51b9cdca95661bd48
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 8de83b6f92794318e946a9016e78c5e208774e696fca4ad1bc69a990c3bdc4a64c01b910274e80c33733dd176e59db1d13acdc9e77f15701148a48d377b17b0c
         | 
| 7 | 
            +
              data.tar.gz: f63fcfbc45251d1eeead3f7fedbf3232c3cf6d3de882253f5361e6b694b51cc005fdb365a6640805436a41bfc3afb5d716995eb2bd5c5e1329cac39cff913f4c
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # Myq
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            mysql to json utility
         | 
| 4 4 |  | 
| 5 5 | 
             
            ## Installation
         | 
| 6 6 |  | 
| @@ -18,7 +18,7 @@ Or install it yourself as: | |
| 18 18 |  | 
| 19 19 | 
             
            ## Setting
         | 
| 20 20 |  | 
| 21 | 
            -
            Create $HOME/.database.yml
         | 
| 21 | 
            +
            Create $HOME/.database.yml(rails format)
         | 
| 22 22 | 
             
            ```yml
         | 
| 23 23 | 
             
            default:
         | 
| 24 24 | 
             
              database: test
         | 
| @@ -37,7 +37,49 @@ staging: | |
| 37 37 |  | 
| 38 38 | 
             
            ## Usage
         | 
| 39 39 |  | 
| 40 | 
            -
             | 
| 40 | 
            +
            ```bash
         | 
| 41 | 
            +
            Commands:
         | 
| 42 | 
            +
              myq --dbs                                          # show databases
         | 
| 43 | 
            +
              myq --ps                                           # show processlist
         | 
| 44 | 
            +
              myq --set -v key=value; -v, --variables=key:value  # set global variable
         | 
| 45 | 
            +
              myq --template [erb]                               # generate template by schema info
         | 
| 46 | 
            +
              myq -C                                             # mysql console
         | 
| 47 | 
            +
              myq -D                                             # mysql dump
         | 
| 48 | 
            +
              myq -I [table]                                     # bulk insert json, auto create table!
         | 
| 49 | 
            +
              myq -R                                             # mysql restore
         | 
| 50 | 
            +
              myq -c [table name] -k [group by keys]             # count record, group by keys
         | 
| 51 | 
            +
              myq -f [file]                                      # query by sql file
         | 
| 52 | 
            +
              myq -l [table name]                                # show table info
         | 
| 53 | 
            +
              myq -q [sql]                                       # inline query
         | 
| 54 | 
            +
              myq -s [table name]                                # sampling query, default limit 10
         | 
| 55 | 
            +
              myq -v [like query]                                # show variables
         | 
| 56 | 
            +
              myq create_db [database]                           # mysql console
         | 
| 57 | 
            +
              myq help [COMMAND]                                 # Describe available commands or one specific command
         | 
| 58 | 
            +
              myq version                                        # show version
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            Options:
         | 
| 61 | 
            +
              -p, [--profile=PROFILE]        # profile by .database.yml
         | 
| 62 | 
            +
                                             # Default: default
         | 
| 63 | 
            +
              -P, [--pretty], [--no-pretty]  # pretty print
         | 
| 64 | 
            +
              --config, [--config=CONFIG]    # config file
         | 
| 65 | 
            +
                                             # Default: /Users/toyama-h/.database.yml
         | 
| 66 | 
            +
            ```
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            ## Exsample
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            ### run query
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            ```bash
         | 
| 73 | 
            +
            $ myq -q "select * from access limit 10"
         | 
| 74 | 
            +
            [{"host":"48.189.196.32","user":"-","method":"POST","referer":"-","path":"/search/?c=Games+Sports","size":133,"code":200,"agent":"Mozilla/4.0 (compatible; MSIE ","updated_at":"2014-03-01 19:03:38 +0900"},{"host":"128.24.107.59","user":"-","method":"GET","referer":"-","path":"/category/electronics","size":70,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.1; W","updated_at":"2014-03-01 19:03:38 +0900"},{"host":"144.102.28.67","user":"-","method":"GET","referer":"/category/office","path":"/item/games/4274","size":59,"code":200,"agent":"Mozilla/4.0 (compatible; MSIE ","updated_at":"2014-03-01 19:03:38 +0900"},{"host":"100.129.167.163","user":"-","method":"GET","referer":"/category/books","path":"/item/electronics/4570","size":139,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.0; r","updated_at":"2014-03-01 19:03:38 +0900"},{"host":"132.189.67.199","user":"-","method":"POST","referer":"-","path":"/search/?c=Finance","size":116,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.0) A","updated_at":"2014-03-01 19:03:38 +0900"},{"host":"176.147.148.79","user":"-","method":"GET","referer":"/category/software","path":"/item/jewelry/4592","size":78,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.1; W","updated_at":"2014-03-01 19:03:39 +0900"},{"host":"200.48.189.175","user":"-","method":"GET","referer":"-","path":"/category/software","size":85,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.0; r","updated_at":"2014-03-01 19:03:39 +0900"},{"host":"220.111.122.175","user":"-","method":"GET","referer":"/category/software","path":"/category/networking","size":43,"code":200,"agent":"Mozilla/5.0 (compatible; Googl","updated_at":"2014-03-01 19:03:39 +0900"},{"host":"220.117.150.167","user":"-","method":"GET","referer":"-","path":"/category/electronics","size":109,"code":200,"agent":"Mozilla/4.0 (compatible; MSIE ","updated_at":"2014-03-01 19:03:39 +0900"},{"host":"176.93.131.44","user":"-","method":"POST","referer":"/category/music","path":"/search/?c=Toys","size":60,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.1; W","updated_at":"2014-03-01 19:03:39 +0900"}]
         | 
| 75 | 
            +
            ```
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            ### sampling query
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            ```bash
         | 
| 80 | 
            +
            $ myq -s access
         | 
| 81 | 
            +
            [{"host":"48.189.196.32","user":"-","method":"POST","referer":"-","path":"/search/?c=Games+Sports","size":133,"code":200,"agent":"Mozilla/4.0 (compatible; MSIE ","updated_at":"2014-03-01 19:03:38 +0900"},{"host":"128.24.107.59","user":"-","method":"GET","referer":"-","path":"/category/electronics","size":70,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.1; W","updated_at":"2014-03-01 19:03:38 +0900"},{"host":"144.102.28.67","user":"-","method":"GET","referer":"/category/office","path":"/item/games/4274","size":59,"code":200,"agent":"Mozilla/4.0 (compatible; MSIE ","updated_at":"2014-03-01 19:03:38 +0900"},{"host":"100.129.167.163","user":"-","method":"GET","referer":"/category/books","path":"/item/electronics/4570","size":139,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.0; r","updated_at":"2014-03-01 19:03:38 +0900"},{"host":"132.189.67.199","user":"-","method":"POST","referer":"-","path":"/search/?c=Finance","size":116,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.0) A","updated_at":"2014-03-01 19:03:38 +0900"},{"host":"176.147.148.79","user":"-","method":"GET","referer":"/category/software","path":"/item/jewelry/4592","size":78,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.1; W","updated_at":"2014-03-01 19:03:39 +0900"},{"host":"200.48.189.175","user":"-","method":"GET","referer":"-","path":"/category/software","size":85,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.0; r","updated_at":"2014-03-01 19:03:39 +0900"},{"host":"220.111.122.175","user":"-","method":"GET","referer":"/category/software","path":"/category/networking","size":43,"code":200,"agent":"Mozilla/5.0 (compatible; Googl","updated_at":"2014-03-01 19:03:39 +0900"},{"host":"220.117.150.167","user":"-","method":"GET","referer":"-","path":"/category/electronics","size":109,"code":200,"agent":"Mozilla/4.0 (compatible; MSIE ","updated_at":"2014-03-01 19:03:39 +0900"},{"host":"176.93.131.44","user":"-","method":"POST","referer":"/category/music","path":"/search/?c=Toys","size":60,"code":200,"agent":"Mozilla/5.0 (Windows NT 6.1; W","updated_at":"2014-03-01 19:03:39 +0900"}]
         | 
| 82 | 
            +
            ```
         | 
| 41 83 |  | 
| 42 84 | 
             
            ## Contributing
         | 
| 43 85 |  | 
    
        data/lib/myq.rb
    CHANGED
    
    
    
        data/lib/myq/commands.rb
    CHANGED
    
    | @@ -1,74 +1,150 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 2 | 
             
            # coding: utf-8
         | 
| 3 3 | 
             
            require 'thor'
         | 
| 4 | 
            -
            require 'mysql2-cs-bind'
         | 
| 5 4 | 
             
            require 'yajl'
         | 
| 6 | 
            -
            require 'yaml'
         | 
| 7 5 |  | 
| 8 6 | 
             
            module Myq
         | 
| 9 7 | 
             
              class Commands < Thor
         | 
| 10 | 
            -
                class_option : | 
| 11 | 
            -
                class_option : | 
| 12 | 
            -
                class_option : | 
| 13 | 
            -
                 | 
| 14 | 
            -
                class_option :database, aliases: '-d', type: :string, desc: 'database'
         | 
| 15 | 
            -
                class_option :profile, aliases: '--pr', type: :string, default: 'default', desc: 'profile by .database.yml'
         | 
| 8 | 
            +
                class_option :profile, aliases: '-p', type: :string, default: 'default', desc: 'profile by .database.yml'
         | 
| 9 | 
            +
                class_option :pretty, aliases: '-P', type: :boolean, default: false, desc: 'pretty print'
         | 
| 10 | 
            +
                class_option :config, aliases: '--config', type: :string, default: "#{ENV['HOME']}/.database.yml", desc: 'config file'
         | 
| 11 | 
            +
                map '--ps' => :processlist
         | 
| 16 12 | 
             
                map '-q' => :query_inline
         | 
| 13 | 
            +
                map '-c' => :count
         | 
| 17 14 | 
             
                map '-f' => :query_file
         | 
| 18 15 | 
             
                map '-s' => :sample
         | 
| 19 | 
            -
                map '- | 
| 16 | 
            +
                map '-l' => :show_table
         | 
| 17 | 
            +
                map '--dbs' => :show_databases
         | 
| 18 | 
            +
                map '-v' => :show_variables
         | 
| 19 | 
            +
                map '-I' => :bulk_insert_json
         | 
| 20 | 
            +
                map '-V' => :version
         | 
| 21 | 
            +
                map '--set' => :set_variable
         | 
| 22 | 
            +
                map '-C' => :console
         | 
| 23 | 
            +
                map '-D' => :dump
         | 
| 24 | 
            +
                map '-R' => :restore
         | 
| 25 | 
            +
                map '--template' => :template
         | 
| 20 26 |  | 
| 21 27 | 
             
                def initialize(args = [], options = {}, config = {})
         | 
| 22 28 | 
             
                  super(args, options, config)
         | 
| 23 | 
            -
                  global_options = config[:shell].base.options
         | 
| 24 | 
            -
                   | 
| 25 | 
            -
                    data = YAML.load_file("#{ENV['HOME']}/.database.yml")[global_options['profile']]
         | 
| 26 | 
            -
                    host = data['host']
         | 
| 27 | 
            -
                    username = data['username']
         | 
| 28 | 
            -
                    password = data['password']
         | 
| 29 | 
            -
                    database = data['database']
         | 
| 30 | 
            -
                    port = data['port']
         | 
| 31 | 
            -
                  else
         | 
| 32 | 
            -
                    host = global_options['host']
         | 
| 33 | 
            -
                    username = global_options['username']
         | 
| 34 | 
            -
                    password = global_options['password']
         | 
| 35 | 
            -
                    database = global_options['database']
         | 
| 36 | 
            -
                    port = global_options['port']
         | 
| 37 | 
            -
                  end
         | 
| 38 | 
            -
                  @client = Mysql2::Client.new(host: host, username: username, password: password, database: database, port: port)
         | 
| 29 | 
            +
                  @global_options = config[:shell].base.options
         | 
| 30 | 
            +
                  @core = Myq::Core.new(get_profile(@global_options))
         | 
| 39 31 | 
             
                end
         | 
| 40 32 |  | 
| 41 | 
            -
                desc  | 
| 33 | 
            +
                desc '-q [sql]', 'inline query'
         | 
| 34 | 
            +
                option :interval, type: :numeric, default: 0, aliases: '-i', desc: 'loop interval'
         | 
| 42 35 | 
             
                def query_inline(query)
         | 
| 43 | 
            -
                   | 
| 36 | 
            +
                  loop do
         | 
| 37 | 
            +
                    puts_json(@core.query(query))
         | 
| 38 | 
            +
                    break if options['interval'] == 0
         | 
| 39 | 
            +
                    sleep options['interval']
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                desc '-I [table]', 'bulk insert json, auto create table!'
         | 
| 44 | 
            +
                option :update_columns, type: :array, aliases: '-u', default: [], desc: 'on duplicate key update columns'
         | 
| 45 | 
            +
                def bulk_insert_json(table)
         | 
| 46 | 
            +
                  data = @core.parse_json(STDIN.read)
         | 
| 47 | 
            +
                  sql = @core.make_bulk_insert_sql(table, data, options['update_columns'])
         | 
| 48 | 
            +
                  @core.query_single(sql)
         | 
| 44 49 | 
             
                end
         | 
| 45 50 |  | 
| 46 | 
            -
                desc  | 
| 51 | 
            +
                desc '-f [file]', 'query by sql file'
         | 
| 47 52 | 
             
                def query_file(file)
         | 
| 48 | 
            -
                  query(File.read(file))
         | 
| 53 | 
            +
                  puts_json(@core.query(File.read(file)))
         | 
| 49 54 | 
             
                end
         | 
| 50 55 |  | 
| 51 | 
            -
                desc  | 
| 56 | 
            +
                desc '-s [table name]', 'sampling query, default limit 10'
         | 
| 57 | 
            +
                option :where, type: :hash, default: nil,  aliases: '-w', desc: 'id'
         | 
| 52 58 | 
             
                option :limit, type: :numeric, default: 10, aliases: '-n', desc: 'limit count'
         | 
| 59 | 
            +
                option :all, type: :boolean, default: false, aliases: '-a', desc: 'all'
         | 
| 53 60 | 
             
                def sample(table)
         | 
| 54 | 
            -
                   | 
| 61 | 
            +
                  limit = options['all'] ? "" : "limit #{options['limit']}"
         | 
| 62 | 
            +
                  where = options['where'].nil? ? "" : "where #{options['where'].map{ |k, v| k + ' = ' + v }.join(' and ') }"
         | 
| 63 | 
            +
                  puts_json(@core.query("select * from #{table} #{where} order by id desc #{limit}"))
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                desc '-c [table name] -k [group by keys]', 'count record, group by keys'
         | 
| 67 | 
            +
                option :keys, type: :array, aliases: '-k', default: [], desc: 'group by keys'
         | 
| 68 | 
            +
                def count(table)
         | 
| 69 | 
            +
                  puts_json(@core.count(table, options['keys']))
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                desc '-l [table name]', 'show table info '
         | 
| 73 | 
            +
                def show_table(table_name = nil)
         | 
| 74 | 
            +
                  puts_json(@core.tables(table_name))
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                desc '--dbs', 'show databases'
         | 
| 78 | 
            +
                def show_databases
         | 
| 79 | 
            +
                  puts_json(@core.databases)
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                desc '--ps', 'show processlist'
         | 
| 83 | 
            +
                def processlist
         | 
| 84 | 
            +
                  puts_json(@core.processlist)
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                desc '-v [like query]', 'show variables '
         | 
| 88 | 
            +
                def show_variables(like = nil)
         | 
| 89 | 
            +
                  puts_json(@core.variables(like))
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                desc '--template [erb]', 'show variables '
         | 
| 93 | 
            +
                option :output_template, aliases: '-o', type: :string, default: Dir.pwd, desc: 'output directory'
         | 
| 94 | 
            +
                option :format, aliases: '--format [camelcase or underscore]', type: :string, default: nil, desc: 'filename format'
         | 
| 95 | 
            +
                def template(template_path)
         | 
| 96 | 
            +
                  @core.render_template(template_path, options['output_template'], options['format'])
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                desc '-C', 'mysql console'
         | 
| 100 | 
            +
                def console
         | 
| 101 | 
            +
                  @core.console
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                desc '-D', 'mysql dump'
         | 
| 105 | 
            +
                def dump(filepath = "#{@profile['database']}.dump")
         | 
| 106 | 
            +
                  @core.dump(filepath)
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                desc '-R', 'mysql restore'
         | 
| 110 | 
            +
                def restore(filepath = "#{@profile['database']}.dump")
         | 
| 111 | 
            +
                  @core.restore(filepath)
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                desc 'create_db [database]', 'create database'
         | 
| 115 | 
            +
                def create_db(database)
         | 
| 116 | 
            +
                  @core.create_database_utf8(database)
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                desc '--set -v key=value;', 'set global variable'
         | 
| 120 | 
            +
                option :variables, type: :hash, aliases: '-v', required: true, desc: 'set variables'
         | 
| 121 | 
            +
                def set_variable(key = nil, value = nil)
         | 
| 122 | 
            +
                  options['variables'].each do |k, v|
         | 
| 123 | 
            +
                    @core.query("SET GLOBAL #{k}=#{v}")
         | 
| 124 | 
            +
                  end
         | 
| 55 125 | 
             
                end
         | 
| 56 126 |  | 
| 57 | 
            -
                desc  | 
| 127 | 
            +
                desc 'version', 'show version'
         | 
| 58 128 | 
             
                def version
         | 
| 59 129 | 
             
                  puts VERSION
         | 
| 130 | 
            +
                  puts `mysql -V`
         | 
| 60 131 | 
             
                end
         | 
| 61 132 |  | 
| 62 133 | 
             
                private
         | 
| 63 134 |  | 
| 64 | 
            -
                def  | 
| 65 | 
            -
                   | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
                     | 
| 69 | 
            -
             | 
| 70 | 
            -
                    end
         | 
| 135 | 
            +
                def get_profile(options)
         | 
| 136 | 
            +
                  if File.exist?(options['config'])
         | 
| 137 | 
            +
                    profile = YAML.load_file(options['config'])[options['profile']]
         | 
| 138 | 
            +
                  else
         | 
| 139 | 
            +
                    puts "please create #{ENV['HOME']}/.database.yml"
         | 
| 140 | 
            +
                    exit 1
         | 
| 71 141 | 
             
                  end
         | 
| 142 | 
            +
                  profile
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                def puts_json(object)
         | 
| 146 | 
            +
                  puts Yajl::Encoder.encode(object, pretty: @global_options['pretty'])
         | 
| 72 147 | 
             
                end
         | 
| 148 | 
            +
             | 
| 73 149 | 
             
              end
         | 
| 74 150 | 
             
            end
         | 
    
        data/lib/myq/core.rb
    ADDED
    
    | @@ -0,0 +1,251 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # coding: utf-8
         | 
| 3 | 
            +
            require 'mysql2-cs-bind'
         | 
| 4 | 
            +
            require 'active_support/core_ext/string'
         | 
| 5 | 
            +
            require 'yaml'
         | 
| 6 | 
            +
            require 'yajl'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module Myq
         | 
| 9 | 
            +
              class Core
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(profile)
         | 
| 12 | 
            +
                  @profile = profile
         | 
| 13 | 
            +
                  @client = Mysql2::Client.new(profile)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def make_bulk_insert_sql(table, data, update_columns)
         | 
| 17 | 
            +
                  first = data.class == Array ? data.first : data
         | 
| 18 | 
            +
                  auto_create_table(table, first)
         | 
| 19 | 
            +
                  columns = table_info(table).to_a
         | 
| 20 | 
            +
                  values_array = []
         | 
| 21 | 
            +
                  if data.class == Array
         | 
| 22 | 
            +
                    data.each do |record|
         | 
| 23 | 
            +
                      values_array << to_value_string(columns, record)
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
                  else
         | 
| 26 | 
            +
                    values_array << to_value_string(columns, data)
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                  sql = %Q{
         | 
| 29 | 
            +
                  INSERT INTO #{table}
         | 
| 30 | 
            +
                  (#{columns.map { |column| "\`" + column['COLUMN_NAME'] + "\`" }.join(',')})
         | 
| 31 | 
            +
                  VALUES
         | 
| 32 | 
            +
                  #{values_array.join(",\n")}
         | 
| 33 | 
            +
                  #{make_duplicate_key_update_sql(update_columns)}
         | 
| 34 | 
            +
                  }
         | 
| 35 | 
            +
                  sql
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def make_duplicate_key_update_sql(update_columns)
         | 
| 39 | 
            +
                  return "" if update_columns.empty?
         | 
| 40 | 
            +
                  updates = []
         | 
| 41 | 
            +
                  update_columns.each do |update_column|
         | 
| 42 | 
            +
                    updates << "#{update_column}=VALUES(\`#{update_column}\`)"
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                  "ON DUPLICATE KEY UPDATE " + updates.join(', ')
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def to_value_string(columns, record)
         | 
| 48 | 
            +
                  values_string = columns.map do |column|
         | 
| 49 | 
            +
                    generate_value(record, column)
         | 
| 50 | 
            +
                  end.join(',')
         | 
| 51 | 
            +
                  '(' + values_string + ')'
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def query(query)
         | 
| 55 | 
            +
                  result = []
         | 
| 56 | 
            +
                  query.split(';').each do |sql|
         | 
| 57 | 
            +
                    next if sql.blank?
         | 
| 58 | 
            +
                    res = @client.xquery(sql)
         | 
| 59 | 
            +
                    next if res.nil?
         | 
| 60 | 
            +
                    res.each do |record|
         | 
| 61 | 
            +
                      result << record
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                  result
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                def count(table, keys)
         | 
| 68 | 
            +
                  select_query = keys.empty? ? '' : "#{keys.join(',')},"
         | 
| 69 | 
            +
                  group_by_query = keys.empty? ? '' : "group by #{keys.join(',')}"
         | 
| 70 | 
            +
                  query(%Q{select #{select_query} count(*) as count from #{table} #{group_by_query} order by count desc})
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def query_single(query)
         | 
| 74 | 
            +
                  begin
         | 
| 75 | 
            +
                    res = @client.xquery(query)
         | 
| 76 | 
            +
                  rescue => e
         | 
| 77 | 
            +
                    puts "\n#{e.message}\n#{e.backtrace.join("\n")}"
         | 
| 78 | 
            +
                    puts query
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                def auto_create_table(table, hash)
         | 
| 83 | 
            +
                  res = table_info(table)
         | 
| 84 | 
            +
                  if res.size == 0
         | 
| 85 | 
            +
                    create_table_sql = %Q{CREATE TABLE #{table} (\n#{generate_create_table(hash)}\n)}
         | 
| 86 | 
            +
                    query(create_table_sql)
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                def create_database_utf8(database)
         | 
| 91 | 
            +
                  @client.xquery("CREATE DATABASE #{database} CHARACTER SET 'UTF8'")
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                def tables(table_name)
         | 
| 95 | 
            +
                  if table_name.nil?
         | 
| 96 | 
            +
                    query('SELECT * FROM INFORMATION_SCHEMA.TABLES')
         | 
| 97 | 
            +
                  else
         | 
| 98 | 
            +
                    query("show full columns from #{table_name}")
         | 
| 99 | 
            +
                  end
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                def databases
         | 
| 103 | 
            +
                  query('show databases')
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                def processlist
         | 
| 107 | 
            +
                  query('SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST')
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                def table_info(table)
         | 
| 111 | 
            +
                  @client.xquery("SELECT * FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '#{table}'")
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                def generate_value(record, column)
         | 
| 115 | 
            +
                  value = record[column['COLUMN_NAME']]
         | 
| 116 | 
            +
                  return 'NULL' if value.nil?
         | 
| 117 | 
            +
                  if value.class == String
         | 
| 118 | 
            +
                    # is_time_format
         | 
| 119 | 
            +
                    time = to_time_or_nil(value)
         | 
| 120 | 
            +
                    if !time.nil?
         | 
| 121 | 
            +
                      return "'" + time.strftime('%Y-%m-%d %H:%M:%S') + "'"
         | 
| 122 | 
            +
                    end
         | 
| 123 | 
            +
                    max_length = column['CHARACTER_MAXIMUM_LENGTH']
         | 
| 124 | 
            +
                    return "'" + Mysql2::Client.escape(value) + "'" if max_length.nil?
         | 
| 125 | 
            +
                    value = value.size > max_length ? value.slice(0, max_length) : value
         | 
| 126 | 
            +
                    return "'" + Mysql2::Client.escape(value) + "'"
         | 
| 127 | 
            +
                  elsif value.class == Hash
         | 
| 128 | 
            +
                    escaped = Mysql2::Client.escape(Yajl::Encoder.encode(value))
         | 
| 129 | 
            +
                    return "'" + escaped + "'"
         | 
| 130 | 
            +
                  end
         | 
| 131 | 
            +
                  "'#{value}'"
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                def generate_create_table(hash)
         | 
| 135 | 
            +
                  results = hash.map do |k, v|
         | 
| 136 | 
            +
                    generate_alter(k, v)
         | 
| 137 | 
            +
                  end
         | 
| 138 | 
            +
                  results << 'id integer NOT NULL auto_increment PRIMARY KEY' unless hash.keys.map(&:downcase).include?('id')
         | 
| 139 | 
            +
                  results.compact.join(",\n")
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                def generate_alter(k, v)
         | 
| 143 | 
            +
                  if v.nil?
         | 
| 144 | 
            +
                    "\`#{k}\` varchar(255)"
         | 
| 145 | 
            +
                  elsif k =~ /^id$/i
         | 
| 146 | 
            +
                    "\`id\` integer NOT NULL auto_increment PRIMARY KEY"
         | 
| 147 | 
            +
                  elsif v.class == String
         | 
| 148 | 
            +
                    to_time_or_nil(v).nil? ? "\`#{k}\` varchar(255)" : "\`#{k}\` datetime"
         | 
| 149 | 
            +
                  elsif v.class == Fixnum
         | 
| 150 | 
            +
                    "\`#{k}\` integer"
         | 
| 151 | 
            +
                  elsif v.class == Array
         | 
| 152 | 
            +
                    "\`#{k}\` text"
         | 
| 153 | 
            +
                  elsif v.class == Hash
         | 
| 154 | 
            +
                    "\`#{k}\` text"
         | 
| 155 | 
            +
                  elsif v.respond_to?(:strftime)
         | 
| 156 | 
            +
                    "\`#{k}\` datetime"
         | 
| 157 | 
            +
                  end
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                def to_time_or_nil(value)
         | 
| 161 | 
            +
                  return nil if value.slice(0, 4) !~ /^[0-9][0-9][0-9][0-9]/
         | 
| 162 | 
            +
                  begin
         | 
| 163 | 
            +
                    time = value.to_time
         | 
| 164 | 
            +
                    time.to_i >= 0 ? time : nil
         | 
| 165 | 
            +
                  rescue => e
         | 
| 166 | 
            +
                    nil
         | 
| 167 | 
            +
                  end
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                def parse_json(buffer)
         | 
| 171 | 
            +
                  begin
         | 
| 172 | 
            +
                    data = Yajl::Parser.parse(buffer)
         | 
| 173 | 
            +
                  rescue => e
         | 
| 174 | 
            +
                    data = []
         | 
| 175 | 
            +
                    buffer.split("\n").each do |line|
         | 
| 176 | 
            +
                      data << Yajl::Parser.parse(line)
         | 
| 177 | 
            +
                    end
         | 
| 178 | 
            +
                  end
         | 
| 179 | 
            +
                  data
         | 
| 180 | 
            +
                end
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                def variables(like = nil)
         | 
| 183 | 
            +
                  if like.nil?
         | 
| 184 | 
            +
                    query('SHOW VARIABLES')
         | 
| 185 | 
            +
                  else
         | 
| 186 | 
            +
                    query("SHOW VARIABLES LIKE '%#{like}%'")
         | 
| 187 | 
            +
                  end
         | 
| 188 | 
            +
                end
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                def render_template(template_path = nil, output_template, format)
         | 
| 191 | 
            +
                  system 'mkdir -p ' + File.dirname(output_template)
         | 
| 192 | 
            +
                  database = @profile['database']
         | 
| 193 | 
            +
                  tables = @client.xquery("SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = '#{database}'")
         | 
| 194 | 
            +
                  tables.each do |table|
         | 
| 195 | 
            +
                    table_name = table['TABLE_NAME']
         | 
| 196 | 
            +
                    sql = %Q{SELECT * FROM INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '#{database}' and TABLE_NAME = '#{table_name}'}
         | 
| 197 | 
            +
                    columns = @client.xquery(sql)
         | 
| 198 | 
            +
                    filepath = sprintf(output_template, parse_table(table_name, format))
         | 
| 199 | 
            +
                    filewrite = File.open(filepath,'w')
         | 
| 200 | 
            +
                    filewrite.puts ERB.new(File.read(template_path)).result(binding)
         | 
| 201 | 
            +
                    filewrite.close
         | 
| 202 | 
            +
                    puts "create #{table_name} => #{filepath}"
         | 
| 203 | 
            +
                  end
         | 
| 204 | 
            +
                end
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                def console
         | 
| 207 | 
            +
                  cmd = <<-EOF
         | 
| 208 | 
            +
                  mysql -A\
         | 
| 209 | 
            +
                  -u #{@profile['username']}\
         | 
| 210 | 
            +
                  -h #{@profile['host']}\
         | 
| 211 | 
            +
                  -p #{@profile['database']}\
         | 
| 212 | 
            +
                  --password='#{@profile['password']}'
         | 
| 213 | 
            +
                  EOF
         | 
| 214 | 
            +
                  system(cmd)
         | 
| 215 | 
            +
                end
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                def dump(filepath = "#{@profile['database']}.dump")
         | 
| 218 | 
            +
                  cmd = <<-EOF
         | 
| 219 | 
            +
                  mysqldump \
         | 
| 220 | 
            +
                  -u #{@profile['username']}\
         | 
| 221 | 
            +
                  -h #{@profile['host']}\
         | 
| 222 | 
            +
                  -p #{@profile['database']}\
         | 
| 223 | 
            +
                  --password='#{@profile['password']}'\
         | 
| 224 | 
            +
                  --default-character-set=binary\
         | 
| 225 | 
            +
                   > #{filepath}
         | 
| 226 | 
            +
                  EOF
         | 
| 227 | 
            +
                  system(cmd)
         | 
| 228 | 
            +
                end
         | 
| 229 | 
            +
             | 
| 230 | 
            +
                def restore(filepath = "#{@profile['database']}.dump")
         | 
| 231 | 
            +
                  cmd = <<-EOF
         | 
| 232 | 
            +
                  mysql -A\
         | 
| 233 | 
            +
                  -u #{@profile['username']}\
         | 
| 234 | 
            +
                  -h #{@profile['host']}\
         | 
| 235 | 
            +
                  -p #{@profile['database']}\
         | 
| 236 | 
            +
                  --password='#{@profile['password']}'\
         | 
| 237 | 
            +
                  --default-character-set=binary\
         | 
| 238 | 
            +
                  -f < #{filepath}
         | 
| 239 | 
            +
                  EOF
         | 
| 240 | 
            +
                  system(cmd)
         | 
| 241 | 
            +
                end
         | 
| 242 | 
            +
             | 
| 243 | 
            +
                private
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                def parse_table(table_name, format)
         | 
| 246 | 
            +
                  return table_name if format.nil?
         | 
| 247 | 
            +
                  eval("table_name.#{format}")
         | 
| 248 | 
            +
                end
         | 
| 249 | 
            +
             | 
| 250 | 
            +
              end
         | 
| 251 | 
            +
            end
         | 
    
        data/lib/myq/version.rb
    CHANGED
    
    
    
        data/myq.gemspec
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: myq
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0 | 
| 4 | 
            +
              version: 1.0.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - toyama0919
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2014- | 
| 11 | 
            +
            date: 2014-04-13 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -80,6 +80,20 @@ dependencies: | |
| 80 80 | 
             
                - - ">="
         | 
| 81 81 | 
             
                  - !ruby/object:Gem::Version
         | 
| 82 82 | 
             
                    version: '0'
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: activesupport
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - ">="
         | 
| 88 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                    version: '0'
         | 
| 90 | 
            +
              type: :runtime
         | 
| 91 | 
            +
              prerelease: false
         | 
| 92 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - ">="
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: '0'
         | 
| 83 97 | 
             
            description: Command-line MYSQL TO JSON processor.
         | 
| 84 98 | 
             
            email:
         | 
| 85 99 | 
             
            - toyama0919@gmail.com
         | 
| @@ -94,10 +108,13 @@ files: | |
| 94 108 | 
             
            - README.md
         | 
| 95 109 | 
             
            - Rakefile
         | 
| 96 110 | 
             
            - bin/myq
         | 
| 111 | 
            +
            - contrib/completion/_myq
         | 
| 97 112 | 
             
            - lib/myq.rb
         | 
| 98 113 | 
             
            - lib/myq/commands.rb
         | 
| 114 | 
            +
            - lib/myq/core.rb
         | 
| 99 115 | 
             
            - lib/myq/version.rb
         | 
| 100 116 | 
             
            - myq.gemspec
         | 
| 117 | 
            +
            - sample/activerecord.erb
         | 
| 101 118 | 
             
            homepage: ''
         | 
| 102 119 | 
             
            licenses:
         | 
| 103 120 | 
             
            - MIT
         |