fast_innodb_import 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
  require "fast_innodb_import"
3
3
 
4
- FastInnodbImport.new(ARGV).execute
4
+ FastInnodbImport.execute(ARGV, $stdout)
@@ -3,36 +3,27 @@ $:.unshift(File.dirname(__FILE__)) unless
3
3
 
4
4
  require "mysql2"
5
5
  class FastInnodbImport
6
- VERSION = '0.0.1'
6
+ VERSION = '0.0.2'
7
7
  CMD_MAPPING = { "u" => :username, "h" => :host, "d" => :database, "p" => "password" }
8
8
 
9
- def initialize(argv = {})
10
- @options = options_from_argv(argv)
9
+ attr_accessor :options, :stream
10
+
11
+ def initialize(options = {})
12
+ self.options = options
13
+ end
14
+
15
+ def self.execute(argv, stream = nil)
16
+ importer = self.new(options_from_argv(argv))
17
+ importer.stream = stream
18
+ importer.execute
11
19
  end
12
20
 
13
21
  def execute
14
- print_usage_and_exit if missing_options?
22
+ print_usage_and_exit_if_missing_options
15
23
  file_paths.each do |path|
16
24
  import_data_from_file_path(path)
17
25
  end
18
26
  end
19
-
20
- private
21
- def index_definitions_from_table(table)
22
- query("SHOW CREATE TABLE #{table}").to_a.first["Create Table"].split("\n").map do |line|
23
- if line.match(/^\s*KEY \`(.*?)\` \((.*?)\)/)
24
- { :name => $1, :columns => $2 }
25
- end
26
- end.compact
27
- end
28
-
29
- def index_drop_statement_for_table(table_name)
30
- "ALTER TABLE #{table_name} " + index_definitions_from_table(table_name).map { |config| "\nDROP INDEX #{config[:name]}" }.join(", ")
31
- end
32
-
33
- def index_create_statement_for_table(table_name)
34
- "ALTER TABLE #{table_name} " + index_definitions_from_table(table_name).map { |config| "\nADD INDEX #{config[:name]} (#{config[:columns]})" }.join(", ")
35
- end
36
27
 
37
28
  def import_data_from_file_path(path)
38
29
  file_path = File.expand_path(path)
@@ -40,54 +31,57 @@ private
40
31
  table_name = table_name_from_file_path(file_path)
41
32
  wc = `wc -l #{file_path}`.strip.to_i
42
33
  started = Time.now
43
- print "import %d rows from %s: " % [wc, file_path]
44
- $stdout.flush
34
+ if stream
35
+ stream.print "import %d rows from %s: " % [wc, file_path] if stream
36
+ stream.flush
37
+ end
45
38
 
46
39
  # create drop and create statements as long as we can
47
40
  drop_statement = index_drop_statement_for_table(table_name)
48
41
  create_statement = index_create_statement_for_table(table_name)
49
42
 
50
43
  query("TRUNCATE `#{table_name}`")
44
+ query(drop_statement) if drop_keys?
45
+ `#{self.class.import_command_prefix_from_options(options)} #{file_path}`
46
+ query(create_statement) if drop_keys?
51
47
 
52
- # drop keys if asked
53
- if drop_keys?
54
- query(drop_statement)
55
- end
56
-
57
- query("LOAD DATA INFILE '#{file_path}' INTO TABLE `#{table_name}`")
58
-
59
- # recreate keys if asked
60
- if drop_keys?
61
- query(create_statement)
48
+ # print stats if stream given
49
+ if stream
50
+ diff = Time.now - started
51
+ per_sec = wc / diff
52
+ stream.puts "%d (%d/sec)" % [diff, per_sec]
62
53
  end
63
-
64
- # print stats
65
- diff = Time.now - started
66
- per_sec = wc / diff
67
- puts "%d (%d/sec)" % [diff, per_sec]
68
54
  end
69
55
 
70
- def missing_options?
71
- !file_paths.respond_to?(:empty?) || file_paths.empty?
56
+ def options
57
+ @options || {}
72
58
  end
73
59
 
74
- def db_options
75
- @options[:db] if @options
76
- end
77
-
78
- def table_name_from_file_path(path)
79
- File.basename(path).gsub(".txt", "")
60
+ def self.options_from_argv(argv)
61
+ options = { :db => {} }
62
+ %w(u h d p).each do |key|
63
+ if idx = argv.index("-#{key}")
64
+ value = argv.at(idx + 1)
65
+ options[:db][CMD_MAPPING[key]] = value if !value.match(/^\-/)
66
+ argv.delete_at(idx)
67
+ argv.delete_at(idx)
68
+ end
69
+ end
70
+ options[:drop_keys] = argv.delete("--without-drop-keys").nil?
71
+ options[:file_paths] = argv
72
+ options
80
73
  end
81
-
82
- def file_paths
83
- @options[:file_paths] if @options
74
+
75
+ private
76
+ def print_usage_and_exit_if_missing_options
77
+ self.class.print_usage_and_exit if missing_options?
84
78
  end
85
79
 
86
- def drop_keys?
87
- @options[:drop_keys] if @options
80
+ def missing_options?
81
+ !file_paths.respond_to?(:empty?) || file_paths.empty? || db_options[:username].nil? || db_options[:database].nil?
88
82
  end
89
83
 
90
- def print_usage_and_exit
84
+ def self.print_usage_and_exit
91
85
  puts "Usage: #{File.basename(__FILE__)} [OPTIONS] [dumpfile]"
92
86
  puts " -h Database Host"
93
87
  puts " -u Database User"
@@ -97,19 +91,46 @@ private
97
91
  exit
98
92
  end
99
93
 
100
- def options_from_argv(argv)
101
- options = { :db => {} }
102
- %w(u h d p).each do |key|
103
- if idx = argv.index("-#{key}")
104
- value = argv.at(idx + 1)
105
- options[:db][CMD_MAPPING[key]] = value if !value.match(/^\-/)
106
- argv.delete_at(idx)
107
- argv.delete_at(idx)
94
+ def index_definitions_from_table(table)
95
+ query("SHOW CREATE TABLE #{table}").to_a.first["Create Table"].split("\n").map do |line|
96
+ if line.match(/^\s*KEY \`(.*?)\` \((.*?)\)/)
97
+ { :name => $1, :columns => $2 }
108
98
  end
99
+ end.compact
100
+ end
101
+
102
+ def index_drop_statement_for_table(table_name)
103
+ "ALTER TABLE #{table_name} " + index_definitions_from_table(table_name).map { |config| "\nDROP INDEX #{config[:name]}" }.join(", ")
104
+ end
105
+
106
+ def index_create_statement_for_table(table_name)
107
+ "ALTER TABLE #{table_name} " + index_definitions_from_table(table_name).map { |config| "\nADD INDEX #{config[:name]} (#{config[:columns]})" }.join(", ")
108
+ end
109
+
110
+ def db_options
111
+ options[:db] || {}
112
+ end
113
+
114
+ def self.import_command_prefix_from_options(options)
115
+ cmd = "mysqlimport -L"
116
+ if db_options = options[:db]
117
+ cmd << " -u #{db_options[:username]}" if db_options[:username]
118
+ cmd << " -p#{db_options[:password]}" if db_options[:password]
119
+ cmd << " #{db_options[:database]}" if db_options[:database]
109
120
  end
110
- options[:drop_keys] = argv.delete("--without-drop-keys").nil?
111
- options[:file_paths] = argv
112
- options
121
+ cmd
122
+ end
123
+
124
+ def table_name_from_file_path(path)
125
+ File.basename(path).gsub(".txt", "")
126
+ end
127
+
128
+ def file_paths
129
+ options[:file_paths]
130
+ end
131
+
132
+ def drop_keys?
133
+ options[:drop_keys]
113
134
  end
114
135
 
115
136
  def client
@@ -1,11 +1,50 @@
1
- require File.dirname(__FILE__) + '/spec_helper.rb'
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require "fileutils"
2
3
 
3
4
  # Time to add your specs!
4
5
  # http://rspec.info/
5
6
  describe "Place your specs here" do
6
-
7
- it "find this spec in spec directory" do
8
- # violated "Be sure to write your specs"
7
+ { { :username => "root" } => "-u root",
8
+ { :username => "root", :database => "some_db" } => "-u root some_db",
9
+ { :username => "root", :password => "secret", :database => "some_db" } => "-u root -psecret some_db",
10
+ }.each do |db_options, string|
11
+ it "should constract the correct mysqlimport command prefix for db_options #{db_options.inspect}" do
12
+ FastInnodbImport.send(:import_command_prefix_from_options, { :db => db_options }).should == "mysqlimport -L #{string}"
13
+ end
9
14
  end
10
15
 
16
+ describe "import from a file" do
17
+ before(:each) do
18
+ @database = "fast_innodb_import_test"
19
+ @username = "root"
20
+ @client = Mysql2::Client.new(:database => @database, :username => @username)
21
+ @client.query("TRUNCATE albums")
22
+ violated if @client.query("SELECT * FROM albums").to_a.length != 0
23
+ end
24
+
25
+ it "should import a dummy file" do
26
+ importer = FastInnodbImport.new(:db => { :username => @username, :database => @database })
27
+ importer.import_data_from_file_path("spec/fixtures/albums.txt")
28
+ @client.query("SELECT * FROM albums ORDER BY id").to_a.should == [
29
+ { "id" => 1, "artist_name" => "Jay-Z", "title" => "Black Album" },
30
+ { "id" => 2, "artist_name" => "Mos Def", "title" => "Black on Both Sides" },
31
+ ]
32
+ end
33
+
34
+ it "should write log to stream" do
35
+ FileUtils.rm_f("tmp/import.log")
36
+ stream = File.open("tmp/import.log", "w")
37
+ importer = FastInnodbImport.new(:db => { :username => @username, :database => @database })
38
+ importer.stream = stream
39
+ importer.import_data_from_file_path("spec/fixtures/albums.txt")
40
+ stream.close
41
+ File.read("tmp/import.log").should match(/import 2 rows .*?\/spec\/fixtures\/albums\.txt: \d+ \(\d+\/sec\)/)
42
+ FileUtils.rm_f("tmp/import.log")
43
+ end
44
+
45
+ it "should import data when called with ARGV options" do
46
+ FastInnodbImport.execute(["-u", @username, "-d", @database, "spec/fixtures/albums.txt"])
47
+ @client.query("SELECT * FROM albums").to_a.length.should == 2
48
+ end
49
+ end
11
50
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Tobias Schwab
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-09-22 00:00:00 +02:00
17
+ date: 2010-09-23 00:00:00 +02:00
18
18
  default_executable: fast_innodb_import
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency