rdb_csv 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f4dd0b5ba83e5aa0e4fa4a2e0f73b9471bc5f31a3eb5bbd6b2e7df073187e6c2
4
- data.tar.gz: b18926dfa955cea6d3d4a7eaeaea53a1b4c97cc851e842770edf801552f4e6d7
3
+ metadata.gz: 49500956b9723214a17c58ea2511214c3b8d35f0734ed92609b14336e987cca6
4
+ data.tar.gz: 41896be81f877579013ce1d98410b413ad12b205e417817d6abd391f29a7feb2
5
5
  SHA512:
6
- metadata.gz: 6ceb4b90f759b5d0060f018bc63da88a7f840b0cd9d67985d625b31469e9552a64a676fd2edf1e3daabaf9e678f8e854b4608a1f0c1baa77e9a45d6845384f3c
7
- data.tar.gz: 16e8714188a2b7d7ff93c1fadb1345eb01906454107a2375107e512eca49c52713d12aa33ae554eb08182b5bf8d8a73325986dcc78ef6b8c4ae617100c74b16e
6
+ metadata.gz: fb447a0deab272668e546f3f067ad08957e2e7c6d1257b7fe76d22895a77e5f85ffb51ea61370ca3402f390b73555702ef1c8f24956ff7fed8e17ca5b9056e13
7
+ data.tar.gz: 4a9b3d811aa1ff10abded0c5e857c367cc50e9c28404d9138774ac47d5e50c86fc0021c8b9b0a3699057c8f7e1be51c23e7a781a8796116ac9714aaebd8ea1a0
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ vendor/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 2.0.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rdb_csv.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,34 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rdb_csv (0.4.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.3)
10
+ rake (12.3.2)
11
+ rspec (3.8.0)
12
+ rspec-core (~> 3.8.0)
13
+ rspec-expectations (~> 3.8.0)
14
+ rspec-mocks (~> 3.8.0)
15
+ rspec-core (3.8.0)
16
+ rspec-support (~> 3.8.0)
17
+ rspec-expectations (3.8.3)
18
+ diff-lcs (>= 1.2.0, < 2.0)
19
+ rspec-support (~> 3.8.0)
20
+ rspec-mocks (3.8.0)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.8.0)
23
+ rspec-support (3.8.0)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ rake
30
+ rdb_csv!
31
+ rspec
32
+
33
+ BUNDLED WITH
34
+ 2.0.1
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 longicorn
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # RdbCSV
2
+
3
+ RDB dumped csv/tsv can be read and write.
4
+
5
+ Rdbcsv supoorts mainly MySQL and PostgreSQL within reasonable range.
6
+
7
+ ## Requirements
8
+ - Ruby 2.4+
9
+
10
+ ## Installation
11
+
12
+ ```
13
+ gem install rdb_csv
14
+ ```
15
+
16
+ or, add this line in your Gemfile
17
+
18
+ ```
19
+ gem 'rdb_csv'
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ `RdbCSV` is similar to the standard CSV class.
25
+
26
+ database type: argment `db`. The default is to use standard CSV class.
27
+
28
+ delimiter type: argment `delimiter` The default is to use `\t`, because the dafault delimiter for dump data is `\t`.
29
+
30
+ ### MySQL
31
+
32
+ Use `INTO OUTFILE` to safely dump CSV,TSV on MySQL.
33
+
34
+ ```ruby
35
+ require 'rdb_csv'
36
+
37
+ # TSV
38
+ tsv_path = "your_dump_file_path.tsv"
39
+ RdbCSV.open(tsv_path, db: :mysql, delimiter: "\t") do |tsv|
40
+ tsv.each do |row|
41
+ p row
42
+ end
43
+ end
44
+
45
+ # CSV
46
+ csv_path = "your_dump_file_path.tsv"
47
+ RdbCSV.open(csv_path, db: :mysql, delimiter: ",") do |csv|
48
+ csv.each do |row|
49
+ p row
50
+ end
51
+ end
52
+
53
+ # Use foreach
54
+ RdbCSV.foreach(csv_path, db: :mysql, delimiter: ",") do |row|
55
+ p row
56
+ end
57
+ ```
58
+
59
+ ### PostgreSQl
60
+ Use `COPY` to safely dump CSV,TSV on PostgreSQL.
61
+
62
+ ```ruby
63
+ require 'rdb_csv'
64
+
65
+ # TSV
66
+ tsv_path = "your_dump_file_path.tsv"
67
+ RdbCSV.foreach(tsv_path, db: :postgresql, delimiter: "\t") do |row|
68
+ p row
69
+ end
70
+
71
+ # CSV
72
+ csv_path = "your_dump_file_path.csv"
73
+ RdbCSV.foreach(csv_path, db: :postgresql, delimiter: ",") do |row|
74
+ p row
75
+ end
76
+ ```
77
+
78
+ ### Convert MySQL to PostgreSQl
79
+
80
+ ```ruby
81
+ require 'rdb_csv'
82
+
83
+ mysql_rows = []
84
+
85
+ mysql_tsv_path = "your_mysql_dump_file_path.tsv"
86
+ RdbCSV.foreach(mysql_tsv_path, db: :mysql, delimiter: "\t") do |row|
87
+ mysql_rows << row
88
+ end
89
+
90
+ postgres_tsv_path = "your_postgres_dump_file_path.tsv"
91
+ RdbCSV.open(postgres_tsv_path, "w", db: :postgresql, delimiter: "\t") do |tsv|
92
+ mysql_rows.each do |mysql_row|
93
+ tsv << mysql_row
94
+ end
95
+ end
96
+ ```
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rdb_csv"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/rdb_csv.rb ADDED
@@ -0,0 +1,123 @@
1
+ require 'csv'
2
+ require 'rdb_csv/reader'
3
+ require 'rdb_csv/row'
4
+
5
+ class RdbCSV
6
+ class CSV
7
+ include RdbCSVReader
8
+ include RdbCSVRow
9
+
10
+ def initialize(f, mode, options)
11
+ @f = f
12
+ @mode = options[:mode]
13
+ @db = options[:db]
14
+ @delimiter = options[:delimiter] || "\t"
15
+ @escape = "\\"
16
+ @linefeed = "\n"
17
+ quote = options[:quote] || '"'
18
+
19
+ # quote option is valid only mysql
20
+ @quote = options[:db] == :mysql ? quote : '"'
21
+ end
22
+
23
+ def each
24
+ raise IOError if @mode == 'w'
25
+
26
+ reader = Reader.new(@f, @db, @delimiter, escape: @escape, linefeed: @linefeed, quote: @quote)
27
+
28
+ reader.each_line do |row|
29
+ yield row.unescape(@escape, @db, @delimiter)
30
+ end
31
+ end
32
+
33
+ WRITE_BUFFER_SIZE = 1000
34
+
35
+ def <<(array)
36
+ raise IOError if @mode == 'r'
37
+
38
+ @lines ||= []
39
+
40
+ row = Row.new(array)
41
+ line = row.join(@escape, @db, @delimiter)
42
+ @lines << line + @linefeed
43
+ buffer_write if @lines.size >= WRITE_BUFFER_SIZE
44
+ end
45
+
46
+ def buffer_write
47
+ return if @lines.nil? || @lines.size.zero?
48
+
49
+ @f.write(@lines.join)
50
+ @lines = []
51
+ end
52
+ end
53
+
54
+ def self.open(file, mode = 'r', options)
55
+ db = options[:db] || :default
56
+ delimiter = options[:delimiter] || "\t"
57
+ quote = options[:delimiter] || '"'
58
+
59
+ case mode
60
+ when 'r'
61
+ if db == :default
62
+ ::CSV.open(file, mode, col_sep: delimiter) do |csv|
63
+ yield csv
64
+ end
65
+ else
66
+ File.open(file) do |f|
67
+ csv = CSV.new(f, mode, db: db, delimiter: delimiter, quote: quote)
68
+ yield csv
69
+ end
70
+ end
71
+ when 'w'
72
+ if db == :default
73
+ ::CSV.open(file, mode, col_sep: delimiter) do |csv|
74
+ yield csv
75
+ end
76
+ else
77
+ File.open(file, 'w') do |f|
78
+ csv = CSV.new(f, mode, db: db, delimiter: delimiter, quote: quote)
79
+ yield csv
80
+
81
+ csv.buffer_write
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ def self.foreach(file, options)
88
+ open(file, options) do |csv|
89
+ csv.each do |row|
90
+ yield row
91
+ end
92
+ end
93
+ end
94
+
95
+ def self.parse(str, options)
96
+ db = options[:db] || :default
97
+ delimiter = options[:delimiter] || "\t"
98
+ quote = options[:delimiter] || '"'
99
+
100
+ if options.key?(:db)
101
+ reader = CSV.new(str, 'r', db: db, delimiter: delimiter, quote: quote)
102
+ else
103
+ reader = ::CSV.parse(str, col_sep: delimiter)
104
+ end
105
+
106
+ rows = []
107
+ reader.each do |row|
108
+ if block_given?
109
+ yield row
110
+ else
111
+ rows << row
112
+ end
113
+ end
114
+
115
+ return rows unless block_given?
116
+ end
117
+
118
+ def self.parse_line(line, options)
119
+ ary = nil
120
+ parse(line, options).each{|row| ary = row; break}
121
+ return ary
122
+ end
123
+ end
@@ -0,0 +1,73 @@
1
+ module RdbCSVReader
2
+ class Reader
3
+ def initialize(fp, db, delimiter, options)
4
+ @fp = fp
5
+ @db = db
6
+ @delimiter = delimiter
7
+ @escape = options[:escape] || "\\" # 1 char
8
+ @linefeed = options[:linefeed] || "\n"
9
+ @quote = options[:quote] || '"'
10
+ end
11
+
12
+ def each_line
13
+ str = ''
14
+ row = []
15
+ quote_num = 0
16
+
17
+ each_char do |char|
18
+ if quote_num > 0
19
+ if str[-1] == @quote && char == @quote
20
+ quote_num -= 1
21
+ elsif str[-1] != @quote && char == @quote
22
+ quote_num -= 1
23
+ elsif char == @quote
24
+ quote_num += 1
25
+ end
26
+ str += char
27
+ else
28
+ if char == @delimiter
29
+ row << str
30
+ str = ''
31
+ elsif char == @linefeed
32
+ row << str
33
+ yield RdbCSV::CSV::Row.new(row)
34
+ row = []
35
+ str = ''
36
+ else
37
+ quote_num += 1 if (str.size == 0 || str[0] == @quote) && char == @quote
38
+ str += char
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def each_char
47
+ str = ''
48
+ @fp.each_char do |char|
49
+ if str[-1] == @escape
50
+ str += char
51
+ yield str
52
+ str = ''
53
+ next
54
+ end
55
+
56
+ str += char
57
+
58
+ if str[@linefeed.size-1..-1] == @linefeed
59
+ yield str
60
+ str = ''
61
+ next
62
+ end
63
+
64
+ if str[-1] != @escape
65
+ yield str
66
+ str = ''
67
+ end
68
+ end
69
+
70
+ yield str unless str.empty?
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,121 @@
1
+ module RdbCSVRow
2
+ class Row < Array
3
+ def unescape(escape_char, db, delimiter)
4
+ send("unescape_#{db}").map{|v|v.to_i.to_s == v ? v.to_i : v rescue v}
5
+ end
6
+
7
+ def join(escape_char, db, delimiter)
8
+ escape(escape_char, db, delimiter).to_a.join(delimiter)
9
+ end
10
+
11
+ private
12
+
13
+ def unescape_default
14
+ self
15
+ end
16
+
17
+ def unescape_mysql
18
+ row = self
19
+ if @quote
20
+ row = row.map{|v|v.match?(/^#{@quote}.*?#{@quote}$/m) ? v[1..-2].gsub(/#{@quote}#{@quote}/o, @quote) : v}
21
+ end
22
+ row.map{|v|v.nil? ? nil : v.gsub(/\\\\/o, '\\')
23
+ .gsub(/\\n/o, "\n")
24
+ .gsub(/\\\n/o, "\n")
25
+ .gsub(/\\r/o, "\r")
26
+ .gsub(/\\t/o, "\t")
27
+ .gsub(/\\0/o, "\0")
28
+ .gsub(/\\,/o, ",")
29
+ }
30
+ .map{|v|v=="\\N" ? nil : v}
31
+ .map{|v|v=="NULL" ? nil : v}
32
+ end
33
+
34
+ def unescape_postgresql
35
+ self.map{|v|v.gsub(/\\0/o, "\0")}
36
+ .map{|v|v.match?(/^".*?"$/om) ? v[1..-2].gsub(/""/, '"') : (v == '' ? nil : v)}
37
+ end
38
+
39
+ def escape(escape_char, db, delimiter)
40
+ send("escape_#{db}", escape_char, delimiter)
41
+ end
42
+
43
+ def escape_default(escape_char, delimiter)
44
+ self
45
+ end
46
+
47
+ def escape_mysql(escape_char, delimiter)
48
+ case delimiter
49
+ when "\t" # tsv
50
+ self.map do |column|
51
+ case column
52
+ when nil
53
+ "NULL"
54
+ when String
55
+ str = ""
56
+ column.each_char do |char|
57
+ case char
58
+ when escape_char
59
+ str += char*2
60
+ when "\n"
61
+ str += "#{escape_char}n"
62
+ when "\t"
63
+ str += "#{escape_char}t"
64
+ when "\0"
65
+ str += "#{escape_char}0"
66
+ else
67
+ str += char
68
+ end
69
+ end
70
+ str
71
+ else
72
+ column
73
+ end
74
+ end
75
+ when "," # csv
76
+ self.map do |column|
77
+ case column
78
+ when nil
79
+ "#{escape_char}N"
80
+ when String
81
+ str = ""
82
+ column.each_char do |char|
83
+ case char
84
+ when escape_char
85
+ str += char*2
86
+ when "\n"
87
+ str += "#{escape_char}\n"
88
+ when "\0"
89
+ str += "#{escape_char}0"
90
+ when delimiter
91
+ str += "#{escape_char}#{delimiter}"
92
+ else
93
+ str += char
94
+ end
95
+ end
96
+ str
97
+ else
98
+ column
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ def escape_postgresql(escape_char, delimiter)
105
+ self.map do |v|
106
+ if v == ''
107
+ '""'
108
+ elsif v.nil?
109
+ ''
110
+ elsif v.kind_of?(String)
111
+ v = v.gsub(/\0/o, "#{escape_char}#{escape_char}0")
112
+ v = v.gsub(/"/o, '""') if v.include?('"')
113
+ v = "\"#{v}\"" if v.match?(/"|\r|\n|#{delimiter}/)
114
+ v
115
+ else
116
+ v
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,3 @@
1
+ class RdbCSV
2
+ VERSION = "0.4.0"
3
+ end
data/rdb_csv.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "rdb_csv/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "rdb_csv"
7
+ spec.version = RdbCSV::VERSION
8
+ spec.authors = ["longicorn"]
9
+ spec.email = ["longicorn.c@gmail.com"]
10
+
11
+ spec.summary = %q{RDB dumped csv/tsv can be read and write.}
12
+ spec.description = %q{Rdbcsv supoorts mainly MySQL and PostgreSQL within reasonable range.}
13
+ spec.homepage = "https://github.com/longicorn/rdb_csv"
14
+ spec.license = 'MIT'
15
+
16
+ spec.require_paths = ["lib"]
17
+ spec.files = `git ls-files`.split($/)
18
+
19
+ spec.add_development_dependency "rspec"
20
+ spec.add_development_dependency "rake"
21
+ end
@@ -0,0 +1,7 @@
1
+ 1,abcdefg,ABCNDEFG,1,1,2018-12-12 02:26:06,2018-12-12 02:26:06,2018-12-12 02:26:06
2
+ 2,abc\
3
+
4
+ 3,abc defg,ABC\,DEFG,\N,-1,2018-12-12 02:26:06,2018-12-12 02:26:06,2018-12-12 02:26:06
5
+ 4,abc\\defg,ABC"DEFG,\N,-1,2018-12-12 02:26:06,2018-12-12 02:26:06,2018-12-12 02:26:06
6
+ 5,'abcdefg,ABC'DEFG,\N,-1,2018-12-12 02:26:06,2018-12-12 02:26:06,2018-12-12 02:26:06
7
+ 6,\N,,\N,\N,2018-12-12 02:26:06,2018-12-12 02:26:06,2018-12-12 02:26:06
@@ -0,0 +1,6 @@
1
+ 1 abcdefg ABCNDEFG 1 1 2018-12-12 02:26:06 2018-12-12 02:26:06 2018-12-12 02:26:06
2
+ 2 abc\n
3
+ 3 abc\tdefg ABC,DEFG NULL -1 2018-12-12 02:26:06 2018-12-12 02:26:06 2018-12-12 02:26:06
4
+ 4 abc\\defg ABC"DEFG NULL -1 2018-12-12 02:26:06 2018-12-12 02:26:06 2018-12-12 02:26:06
5
+ 5 'abcdefg ABC'DEFG NULL -1 2018-12-12 02:26:06 2018-12-12 02:26:06 2018-12-12 02:26:06
6
+ 6 NULL NULL NULL 2018-12-12 02:26:06 2018-12-12 02:26:06 2018-12-12 02:26:06
@@ -0,0 +1,4 @@
1
+ abcdefg,hijkmnl,opqrstu,vwxyz
2
+ あいうえお,かきくけこ,さしすせそ,たちつてと
3
+ "あいうえお
4
+ かきくけこ",さしすせそ,たちつてと
@@ -0,0 +1,4 @@
1
+ abcdefg hijkmnl opqrstu vwxyz
2
+ あいうえお かきくけこ さしすせそ たちつてと
3
+ "あいうえお
4
+ かきくけこ" さしすせそ たちつてと
@@ -0,0 +1,8 @@
1
+ id,text0,text1,flag,point,inserted_at,created_at,updated_at
2
+ 1,abcdefg,ABCNDEFG,t,1,2018-12-18 04:18:24.181256,2018-12-18 04:18:24.18319,2018-12-18 04:18:24.18319
3
+ 2,"abc
4
+
5
+ 3,abc defg,"ABC,DEFG",,-1,2018-12-18 04:18:24.202638,2018-12-18 04:18:24.203768,2018-12-18 04:18:24.203768
6
+ 4,abc\defg,"ABC""DEFG",,-1,2018-12-18 04:18:24.207705,2018-12-18 04:18:24.20904,2018-12-18 04:18:24.20904
7
+ 5,'abcdefg,ABC'DEFG,,-1,2018-12-18 04:18:24.207705,2018-12-18 04:18:24.20904,2018-12-18 04:18:24.20904
8
+ 6,,"",,,2018-12-18 04:18:24.213643,2018-12-18 04:18:24.215238,2018-12-18 04:18:24.215238
@@ -0,0 +1,8 @@
1
+ id text0 text1 flag point inserted_at created_at updated_at
2
+ 1 abcdefg ABCNDEFG t 1 2018-12-18 04:18:24.181256 2018-12-18 04:18:24.18319 2018-12-18 04:18:24.18319
3
+ 2 "abc
4
+
5
+ 3 "abc defg" ABC,DEFG -1 2018-12-18 04:18:24.202638 2018-12-18 04:18:24.203768 2018-12-18 04:18:24.203768
6
+ 4 abc\defg "ABC""DEFG" -1 2018-12-18 04:18:24.207705 2018-12-18 04:18:24.20904 2018-12-18 04:18:24.20904
7
+ 5 'abcdefg ABC'DEFG -1 2018-12-18 04:18:24.207705 2018-12-18 04:18:24.20904 2018-12-18 04:18:24.20904
8
+ 6 "" 2018-12-18 04:18:24.213643 2018-12-18 04:18:24.215238 2018-12-18 04:18:24.215238
@@ -0,0 +1,37 @@
1
+ # Load test
2
+
3
+ ## MySQL
4
+ ```
5
+ $ cp spec/load/docker/docker-compose.mysql.yml docker-compose.yml
6
+ $ sudo docker-compose up -d
7
+ $ mysql -h 127.0.0.1 -P 3306 -u docker -p < spec/load/create_table.mysql.sql
8
+ ```
9
+
10
+ load csv
11
+ ```
12
+ $ mysql -h 127.0.0.1 -P 3306 -u docker -p < spec/load/load.mysql.csv.sql
13
+ ```
14
+
15
+ load tsv
16
+ ```
17
+ $ mysql -h 127.0.0.1 -P 3306 -u docker -p < spec/load/load.mysql.tsv.sql
18
+ ```
19
+
20
+ ## PostgreSQL
21
+ ```
22
+ $ cp spec/load/docker/docker-compose.postgresql.yml docker-compose.yml
23
+ $ sudo docker-compose up -d
24
+ $ mysql -h 127.0.0.1 -P 3306 -u docker -p < spec/load/create_table.postgresql.sql
25
+ ```
26
+
27
+ load csv
28
+ ```
29
+ $ sudo docker cp spec/fixtures/postgresql.csv <CONTAINER ID>:/tmp/postgresql.csv
30
+ $ psql -h 127.0.0.1 -p 5432 -U docker < spec/load/load.postgresql.csv.sql
31
+ ```
32
+
33
+ load tsv
34
+ ```
35
+ $ sudo docker cp spec/fixtures/postgresql.tsv <CONTAINER ID>:/tmp/postgresql.csv
36
+ $ psql -h 127.0.0.1 -p 5432 -U docker < spec/load/load.postgresql.tsv.sql
37
+ ```
@@ -0,0 +1 @@
1
+ create table test (id int, text0 varchar(255), text1 varchar(255), flag tinyint(1), point int, inserted_at datetime, created_at datetime, updated_at datetime) CHARSET=utf8mb4;
@@ -0,0 +1 @@
1
+ create table test (id int, text0 varchar(255), text1 varchar(255), flag boolean, point int, inserted_at timestamp, created_at timestamp, updated_at timestamp);
@@ -0,0 +1,16 @@
1
+ version: '3'
2
+
3
+ services:
4
+ db:
5
+ image: mysql:5.7
6
+ container_name: rdb_csv_mysql
7
+ environment:
8
+ MYSQL_ROOT_PASSWORD: root
9
+ MYSQL_DATABASE: test
10
+ MYSQL_USER: docker
11
+ MYSQL_PASSWORD: password
12
+ command:
13
+ - --character-set-server=utf8mb4
14
+ - --collation-server=utf8mb4_unicode_ci
15
+ ports:
16
+ - 3306:3306
@@ -0,0 +1,10 @@
1
+ version: '3'
2
+
3
+ services:
4
+ postgres:
5
+ image: postgres
6
+ environment:
7
+ POSTGRES_USER: docker
8
+ POSTGRES_PASSWORD: password
9
+ ports:
10
+ - -5432:5432
@@ -0,0 +1 @@
1
+ LOAD DATA LOCAL INFILE "./spec/fixtures/mysql.csv" INTO TABLE test FIELDS TERMINATED BY ',';
@@ -0,0 +1 @@
1
+ LOAD DATA LOCAL INFILE "./spec/fixtures/mysql.tsv" INTO TABLE test FIELDS TERMINATED BY '\t';
@@ -0,0 +1 @@
1
+ COPY test FROM '/tmp/postgresql.csv' WITH CSV HEADER;
@@ -0,0 +1 @@
1
+ COPY test FROM '/tmp/postgresql.tsv' WITH CSV HEADER DELIMITER E'\t';
@@ -0,0 +1,512 @@
1
+ require 'fileutils'
2
+ require 'csv'
3
+
4
+ RSpec.describe RdbCSV do
5
+ before do
6
+ FileUtils.mkdir_p("tmp")
7
+ end
8
+
9
+ after do
10
+ FileUtils.rm_rf("tmp")
11
+ end
12
+
13
+ it "Check version number" do
14
+ expect(RdbCSV::VERSION).to eq "0.4.0"
15
+ end
16
+
17
+ describe "normal data" do
18
+ let(:check_rows) {[["abcdefg","hijkmnl","opqrstu","vwxyz"],
19
+ ["あいうえお","かきくけこ","さしすせそ","たちつてと"],
20
+ ["あいうえお\nかきくけこ","さしすせそ","たちつてと"]
21
+ ]}
22
+
23
+ describe "Read csv" do
24
+ it "open" do
25
+ read_rows = []
26
+ path = "spec/fixtures/normal.csv"
27
+
28
+ RdbCSV.open(path, delimiter: ",") do |csv|
29
+ csv.each do |row|
30
+ read_rows << row
31
+ end
32
+ end
33
+
34
+ expect(read_rows).to eq check_rows
35
+ end
36
+
37
+ it "foreach" do
38
+ read_rows = []
39
+ path = "spec/fixtures/normal.csv"
40
+
41
+ RdbCSV.foreach(path, delimiter: ",") do |row|
42
+ read_rows << row
43
+ end
44
+
45
+ expect(read_rows).to eq check_rows
46
+ end
47
+
48
+ it "parse without block" do
49
+ read_rows = []
50
+ path = "spec/fixtures/normal.csv"
51
+
52
+ str = File.read(path)
53
+ read_rows = RdbCSV.parse(str, delimiter: ",")
54
+
55
+ expect(read_rows).to eq check_rows
56
+ end
57
+
58
+ it "parse with block" do
59
+ read_rows = []
60
+ path = "spec/fixtures/normal.csv"
61
+
62
+ str = File.read(path)
63
+ RdbCSV.parse(str, delimiter: ",").each do |row|
64
+ read_rows << row
65
+ end
66
+
67
+ expect(read_rows).to eq check_rows
68
+ end
69
+
70
+ it "parse_line" do
71
+ read_rows = []
72
+ path = "spec/fixtures/normal.csv"
73
+
74
+ str = File.read(path)
75
+ read_rows = RdbCSV.parse_line(str, delimiter: ",")
76
+
77
+ expect(read_rows).to eq check_rows[0]
78
+ end
79
+ end
80
+
81
+ describe "Read tsv" do
82
+ it "open" do
83
+ read_rows = []
84
+ path = "spec/fixtures/normal.tsv"
85
+
86
+ RdbCSV.open(path, delimiter: "\t") do |tsv|
87
+ tsv.each do |row|
88
+ read_rows << row
89
+ end
90
+ end
91
+
92
+ expect(read_rows).to eq check_rows
93
+ end
94
+
95
+ it "foreach" do
96
+ read_rows = []
97
+ path = "spec/fixtures/normal.tsv"
98
+
99
+ RdbCSV.foreach(path, delimiter: "\t") do |row|
100
+ read_rows << row
101
+ end
102
+
103
+ expect(read_rows).to eq check_rows
104
+ end
105
+
106
+ it "parse without block" do
107
+ read_rows = []
108
+ path = "spec/fixtures/normal.tsv"
109
+
110
+ str = File.read(path)
111
+ read_rows = RdbCSV.parse(str, delimiter: "\t")
112
+
113
+ expect(read_rows).to eq check_rows
114
+ end
115
+
116
+ it "parse with block" do
117
+ read_rows = []
118
+ path = "spec/fixtures/normal.tsv"
119
+
120
+ str = File.read(path)
121
+ RdbCSV.parse(str, delimiter: "\t").each do |row|
122
+ read_rows << row
123
+ end
124
+
125
+ expect(read_rows).to eq check_rows
126
+ end
127
+
128
+ it "parse_line" do
129
+ read_rows = []
130
+ path = "spec/fixtures/normal.tsv"
131
+
132
+ str = File.read(path)
133
+ read_rows = RdbCSV.parse_line(str, delimiter: "\t")
134
+
135
+ expect(read_rows).to eq check_rows[0]
136
+ end
137
+ end
138
+
139
+ it "Write csv" do
140
+ read_rows = []
141
+ path = "tmp/normal.csv"
142
+
143
+ RdbCSV.open(path, 'w', delimiter: ",") do |csv|
144
+ check_rows.each do |row|
145
+ csv << row
146
+ end
147
+ end
148
+
149
+ RdbCSV.open(path, delimiter: ",") do |csv|
150
+ csv.each do |row|
151
+ read_rows << row
152
+ end
153
+ end
154
+
155
+ expect(read_rows).to eq check_rows
156
+ end
157
+
158
+ it "Write csv" do
159
+ read_rows = []
160
+ path = "tmp/normal.csv"
161
+
162
+ RdbCSV.open(path, 'w', delimiter: "\t") do |csv|
163
+ check_rows.each do |row|
164
+ csv << row
165
+ end
166
+ end
167
+
168
+ RdbCSV.open(path, delimiter: "\t") do |csv|
169
+ csv.each do |row|
170
+ read_rows << row
171
+ end
172
+ end
173
+
174
+ expect(read_rows).to eq check_rows
175
+ end
176
+ end
177
+
178
+ describe "MySQL data" do
179
+ let(:check_rows) {[[1, "abcdefg", "ABCNDEFG", 1, 1, "2018-12-12 02:26:06", "2018-12-12 02:26:06", "2018-12-12 02:26:06"],
180
+ [2, "abc\n\rdefg", "ABC\u0000DEFG", 0, 0, "2018-12-12 02:26:06", "2018-12-12 02:26:06", "2018-12-12 02:26:06"],
181
+ [3, "abc\tdefg", "ABC,DEFG", nil, -1, "2018-12-12 02:26:06", "2018-12-12 02:26:06", "2018-12-12 02:26:06"],
182
+ [4, "abc\\defg", "ABC\"DEFG", nil, -1, "2018-12-12 02:26:06", "2018-12-12 02:26:06", "2018-12-12 02:26:06"],
183
+ [5, "'abcdefg", "ABC'DEFG", nil, -1, "2018-12-12 02:26:06", "2018-12-12 02:26:06", "2018-12-12 02:26:06"],
184
+ [6, nil, "", nil, nil, "2018-12-12 02:26:06", "2018-12-12 02:26:06", "2018-12-12 02:26:06"]
185
+ ]}
186
+
187
+ describe "Read csv" do
188
+ it "open" do
189
+ read_rows = []
190
+ path = "spec/fixtures/mysql.csv"
191
+
192
+ RdbCSV.open(path, db: :mysql, delimiter: ",") do |csv|
193
+ csv.each do |row|
194
+ read_rows << row
195
+ end
196
+ end
197
+
198
+ expect(read_rows).to eq check_rows
199
+ end
200
+
201
+ it "foreach" do
202
+ read_rows = []
203
+ path = "spec/fixtures/mysql.csv"
204
+
205
+ RdbCSV.foreach(path, db: :mysql, delimiter: ",") do |row|
206
+ read_rows << row
207
+ end
208
+
209
+ expect(read_rows).to eq check_rows
210
+ end
211
+
212
+ it "parse without block" do
213
+ read_rows = []
214
+ path = "spec/fixtures/mysql.csv"
215
+
216
+ str = File.read(path)
217
+ read_rows = RdbCSV.parse(str, db: :mysql, delimiter: ",")
218
+
219
+ expect(read_rows).to eq check_rows
220
+ end
221
+
222
+ it "parse with block" do
223
+ read_rows = []
224
+ path = "spec/fixtures/mysql.csv"
225
+
226
+ str = File.read(path)
227
+ RdbCSV.parse(str, db: :mysql, delimiter: ",").each do |row|
228
+ read_rows << row
229
+ end
230
+
231
+ expect(read_rows).to eq check_rows
232
+ end
233
+
234
+ it "parse_line" do
235
+ read_rows = []
236
+ path = "spec/fixtures/mysql.csv"
237
+
238
+ str = File.read(path)
239
+ read_rows = RdbCSV.parse_line(str, db: :mysql, delimiter: ",")
240
+
241
+ expect(read_rows).to eq check_rows[0]
242
+ end
243
+ end
244
+
245
+ describe "Read tsv" do
246
+ it "open" do
247
+ read_rows = []
248
+ path = "spec/fixtures/mysql.tsv"
249
+
250
+ RdbCSV.open(path, db: :mysql, delimiter: "\t") do |tsv|
251
+ tsv.each do |row|
252
+ read_rows << row
253
+ end
254
+ end
255
+
256
+ expect(read_rows).to eq check_rows
257
+ end
258
+
259
+ it "foreach" do
260
+ read_rows = []
261
+ path = "spec/fixtures/mysql.tsv"
262
+
263
+ RdbCSV.foreach(path, db: :mysql, delimiter: "\t") do |row|
264
+ read_rows << row
265
+ end
266
+
267
+ expect(read_rows).to eq check_rows
268
+ end
269
+
270
+ it "parse without block" do
271
+ read_rows = []
272
+ path = "spec/fixtures/mysql.tsv"
273
+
274
+ str = File.read(path)
275
+ read_rows = RdbCSV.parse(str, db: :mysql, delimiter: "\t")
276
+
277
+ expect(read_rows).to eq check_rows
278
+ end
279
+
280
+ it "parse with block" do
281
+ read_rows = []
282
+ path = "spec/fixtures/mysql.tsv"
283
+
284
+ str = File.read(path)
285
+ RdbCSV.parse(str, db: :mysql, delimiter: "\t").each do |row|
286
+ read_rows << row
287
+ end
288
+
289
+ expect(read_rows).to eq check_rows
290
+ end
291
+
292
+ it "parse_line" do
293
+ read_rows = []
294
+ path = "spec/fixtures/mysql.tsv"
295
+
296
+ str = File.read(path)
297
+ read_rows = RdbCSV.parse_line(str, db: :mysql, delimiter: "\t")
298
+
299
+ expect(read_rows).to eq check_rows[0]
300
+ end
301
+ end
302
+
303
+ it "Write csv" do
304
+ read_rows = []
305
+ path = "tmp/mysql.csv"
306
+
307
+ RdbCSV.open(path, 'w', db: :mysql, delimiter: ",") do |csv|
308
+ check_rows.each do |row|
309
+ csv << row
310
+ end
311
+ end
312
+
313
+ RdbCSV.open(path, db: :mysql, delimiter: ",") do |csv|
314
+ csv.each do |row|
315
+ read_rows << row
316
+ end
317
+ end
318
+
319
+ expect(read_rows).to eq check_rows
320
+ end
321
+
322
+ it "Write tsv" do
323
+ read_rows = []
324
+ path = "tmp/mysql.tsv"
325
+
326
+ RdbCSV.open(path, 'w', db: :mysql, delimiter: "\t") do |tsv|
327
+ check_rows.each do |row|
328
+ tsv << row
329
+ end
330
+ end
331
+
332
+ RdbCSV.open(path, db: :mysql, delimiter: "\t") do |tsv|
333
+ tsv.each do |row|
334
+ read_rows << row
335
+ end
336
+ end
337
+
338
+ expect(read_rows).to eq check_rows
339
+ end
340
+ end
341
+
342
+ describe "PostgreSQL data" do
343
+ let(:check_rows) {[["id", "text0", "text1", "flag", "point", "inserted_at", "created_at", "updated_at"],
344
+ [1, "abcdefg", "ABCNDEFG", "t", 1, "2018-12-18 04:18:24.181256",
345
+ "2018-12-18 04:18:24.18319", "2018-12-18 04:18:24.18319"],
346
+ [2, "abc\n\rdefg", "ABC\u0000DEFG", "f", 0,
347
+ "2018-12-18 04:18:24.19734", "2018-12-18 04:18:24.198651", "2018-12-18 04:18:24.198651"],
348
+ [3, "abc\tdefg", "ABC,DEFG", nil, -1,
349
+ "2018-12-18 04:18:24.202638", "2018-12-18 04:18:24.203768", "2018-12-18 04:18:24.203768"],
350
+ [4, "abc\\defg", "ABC\"DEFG", nil, -1,
351
+ "2018-12-18 04:18:24.207705", "2018-12-18 04:18:24.20904", "2018-12-18 04:18:24.20904"],
352
+ [5, "'abcdefg", "ABC'DEFG", nil, -1,
353
+ "2018-12-18 04:18:24.207705", "2018-12-18 04:18:24.20904", "2018-12-18 04:18:24.20904"],
354
+ [6, nil, "", nil, nil,
355
+ "2018-12-18 04:18:24.213643", "2018-12-18 04:18:24.215238", "2018-12-18 04:18:24.215238"]
356
+ ]}
357
+
358
+ describe "Read csv" do
359
+ it "open" do
360
+ read_rows = []
361
+ path = "spec/fixtures/postgresql.csv"
362
+
363
+ RdbCSV.open(path, db: :postgresql, delimiter: ",") do |csv|
364
+ csv.each do |row|
365
+ read_rows << row
366
+ end
367
+ end
368
+
369
+ expect(read_rows).to eq check_rows
370
+ end
371
+
372
+ it "foreach" do
373
+ read_rows = []
374
+ path = "spec/fixtures/postgresql.csv"
375
+
376
+ RdbCSV.foreach(path, db: :postgresql, delimiter: ",") do |row|
377
+ read_rows << row
378
+ end
379
+
380
+ expect(read_rows).to eq check_rows
381
+ end
382
+
383
+ it "parse without block" do
384
+ read_rows = []
385
+ path = "spec/fixtures/postgresql.csv"
386
+
387
+ str = File.read(path)
388
+ read_rows = RdbCSV.parse(str, db: :postgresql, delimiter: ",")
389
+
390
+ expect(read_rows).to eq check_rows
391
+ end
392
+
393
+ it "parse with block" do
394
+ read_rows = []
395
+ path = "spec/fixtures/postgresql.csv"
396
+
397
+ str = File.read(path)
398
+ RdbCSV.parse(str, db: :postgresql, delimiter: ",").each do |row|
399
+ read_rows << row
400
+ end
401
+
402
+ expect(read_rows).to eq check_rows
403
+ end
404
+
405
+ it "parse_line" do
406
+ read_rows = []
407
+ path = "spec/fixtures/postgresql.csv"
408
+
409
+ str = File.read(path)
410
+ read_rows = RdbCSV.parse_line(str, db: :postgresql, delimiter: ",")
411
+
412
+ expect(read_rows).to eq check_rows[0]
413
+ end
414
+ end
415
+
416
+ describe "Read tsv" do
417
+ it "open" do
418
+ read_rows = []
419
+ path = "spec/fixtures/postgresql.tsv"
420
+
421
+ RdbCSV.open(path, db: :postgresql, delimiter: "\t") do |tsv|
422
+ tsv.each do |row|
423
+ read_rows << row
424
+ end
425
+ end
426
+
427
+ expect(read_rows).to eq check_rows
428
+ end
429
+
430
+ it "foreach" do
431
+ read_rows = []
432
+ path = "spec/fixtures/postgresql.tsv"
433
+
434
+ RdbCSV.foreach(path, db: :postgresql, delimiter: "\t") do |row|
435
+ read_rows << row
436
+ end
437
+
438
+ expect(read_rows).to eq check_rows
439
+ end
440
+
441
+ it "parse without block" do
442
+ read_rows = []
443
+ path = "spec/fixtures/postgresql.tsv"
444
+
445
+ str = File.read(path)
446
+ read_rows = RdbCSV.parse(str, db: :postgresql, delimiter: "\t")
447
+
448
+ expect(read_rows).to eq check_rows
449
+ end
450
+
451
+ it "parse with block" do
452
+ read_rows = []
453
+ path = "spec/fixtures/postgresql.tsv"
454
+
455
+ str = File.read(path)
456
+ RdbCSV.parse(str, db: :postgresql, delimiter: "\t").each do |row|
457
+ read_rows << row
458
+ end
459
+
460
+ expect(read_rows).to eq check_rows
461
+ end
462
+
463
+ it "parse_line" do
464
+ read_rows = []
465
+ path = "spec/fixtures/postgresql.tsv"
466
+
467
+ str = File.read(path)
468
+ read_rows = RdbCSV.parse_line(str, db: :postgresql, delimiter: "\t")
469
+
470
+ expect(read_rows).to eq check_rows[0]
471
+ end
472
+ end
473
+
474
+ it "Write csv" do
475
+ read_rows = []
476
+ path = "tmp/postgresql.csv"
477
+
478
+ RdbCSV.open(path, 'w', db: :postgresql, delimiter: ",") do |csv|
479
+ check_rows.each do |row|
480
+ csv << row
481
+ end
482
+ end
483
+
484
+ RdbCSV.open(path, db: :postgresql, delimiter: ",") do |csv|
485
+ csv.each do |row|
486
+ read_rows << row
487
+ end
488
+ end
489
+
490
+ expect(read_rows).to eq check_rows
491
+ end
492
+
493
+ it "Write tsv" do
494
+ read_rows = []
495
+ path = "tmp/postgresql.tsv"
496
+
497
+ RdbCSV.open(path, 'w', db: :postgresql, delimiter: ",") do |tsv|
498
+ check_rows.each do |row|
499
+ tsv << row
500
+ end
501
+ end
502
+
503
+ RdbCSV.open(path, db: :postgresql, delimiter: ",") do |tsv|
504
+ tsv.each do |row|
505
+ read_rows << row
506
+ end
507
+ end
508
+
509
+ expect(read_rows).to eq check_rows
510
+ end
511
+ end
512
+ end
@@ -0,0 +1,14 @@
1
+ require "bundler/setup"
2
+ require_relative "../lib/rdb_csv.rb"
3
+
4
+ RSpec.configure do |config|
5
+ # Enable flags like --only-failures and --next-failure
6
+ config.example_status_persistence_file_path = ".rspec_status"
7
+
8
+ # Disable RSpec exposing methods globally on `Module` and `main`
9
+ config.disable_monkey_patching!
10
+
11
+ config.expect_with :rspec do |c|
12
+ c.syntax = :expect
13
+ end
14
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rdb_csv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - longicorn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-26 00:00:00.000000000 Z
11
+ date: 2019-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -44,7 +44,39 @@ email:
44
44
  executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
- files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".rspec"
50
+ - ".travis.yml"
51
+ - Gemfile
52
+ - Gemfile.lock
53
+ - LICENSE
54
+ - README.md
55
+ - Rakefile
56
+ - bin/console
57
+ - bin/setup
58
+ - lib/rdb_csv.rb
59
+ - lib/rdb_csv/reader.rb
60
+ - lib/rdb_csv/row.rb
61
+ - lib/rdb_csv/version.rb
62
+ - rdb_csv.gemspec
63
+ - spec/fixtures/mysql.csv
64
+ - spec/fixtures/mysql.tsv
65
+ - spec/fixtures/normal.csv
66
+ - spec/fixtures/normal.tsv
67
+ - spec/fixtures/postgresql.csv
68
+ - spec/fixtures/postgresql.tsv
69
+ - spec/load/README.md
70
+ - spec/load/create_table.mysql.sql
71
+ - spec/load/create_table.postgresql.sql
72
+ - spec/load/docker/docker-compose.mysql.yml
73
+ - spec/load/docker/docker-compose.postgresql.yml
74
+ - spec/load/load.mysql.csv.sql
75
+ - spec/load/load.mysql.tsv.sql
76
+ - spec/load/load.postgresql.csv.sql
77
+ - spec/load/load.postgresql.tsv.sql
78
+ - spec/rdb_csv_spec.rb
79
+ - spec/spec_helper.rb
48
80
  homepage: https://github.com/longicorn/rdb_csv
49
81
  licenses:
50
82
  - MIT