fast_innodb_import 0.0.1 → 0.0.2

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.
@@ -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