csv2psql 0.0.9 → 0.0.10
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/.gemspec +3 -0
- data/.rspec +3 -0
- data/.yardopts +15 -0
- data/Gemfile +2 -0
- data/README.md +42 -2
- data/Rakefile +17 -14
- data/TODO.md +4 -1
- data/bin/csv2psql +3 -1
- data/data/sample_semicolons.csv +3 -0
- data/lib/csv2psql/analyzer/types/bigint.rb +10 -0
- data/lib/csv2psql/analyzer/types/character.rb +8 -0
- data/lib/csv2psql/analyzer/types/decimal.rb +10 -0
- data/lib/csv2psql/analyzer/types/null.rb +8 -0
- data/lib/csv2psql/analyzer/types/string.rb +37 -0
- data/lib/csv2psql/analyzer/types/uuid.rb +9 -0
- data/lib/csv2psql/cli/app.rb +15 -1
- data/lib/csv2psql/cli/cli.rb +27 -3
- data/lib/csv2psql/cli/cmd/analyze_cmd.rb +55 -12
- data/lib/csv2psql/cli/cmd/convert_cmd.rb +39 -39
- data/lib/csv2psql/cli/cmd/version_cmd.rb +6 -4
- data/lib/csv2psql/cli/shared.rb +51 -7
- data/lib/csv2psql/generator/generator.rb +1 -1
- data/lib/csv2psql/output/output.rb +1 -1
- data/lib/csv2psql/processor/processor.rb +29 -12
- data/lib/csv2psql/version.rb +2 -2
- data/spec/cli/app_spec.rb +9 -0
- data/spec/cli/cmd/analyze_cmd_spec.rb +29 -0
- data/spec/cli/cmd/convert_cmd_spec.rb +36 -0
- data/spec/cli/cmd/version_cmd_spec.rb +9 -0
- data/spec/helpers/cli_helper.rb +31 -0
- data/spec/spec_helper.rb +7 -2
- metadata +59 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 017e866dc4a84a448f04c6d360ee95d215b8e6bc
|
|
4
|
+
data.tar.gz: 036e31c4b92508fb0d66942779378c8b11f46d94
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6910eb4b0578c3a5699b494673e61f3dec5c1f98c0fe503e359e27e4804d8739258ec0fc8db6effed1df08728bae21b0cec63d02caccb6d1cea2933602e459ad
|
|
7
|
+
data.tar.gz: dc146c73e70760956c91a7b947eac86fb3d1f212f997c117ddea8b3a2b22be6ae402d15f1400107b565411c946235e6f86598e1fe5dccea6cf3c47fa92ee5c79
|
data/.gemspec
CHANGED
|
@@ -29,8 +29,11 @@ Gem::Specification.new do |s|
|
|
|
29
29
|
s.add_dependency 'rake', '~> 10.3', '>= 10.3.2'
|
|
30
30
|
s.add_dependency 'terminal-table', '~> 1.4', '>= 1.4.5'
|
|
31
31
|
|
|
32
|
+
s.add_development_dependency 'codeclimate-test-reporter', '~> 0.4', '>= 0.4.0'
|
|
32
33
|
s.add_development_dependency 'coveralls', '~> 0.7', '>= 0.7.0r'
|
|
34
|
+
s.add_development_dependency "redcarpet", "~> 3.1.1" if RUBY_PLATFORM != 'java'
|
|
33
35
|
s.add_development_dependency 'rspec', '~> 3.0', '>= 3.0.0'
|
|
34
36
|
s.add_development_dependency 'rubocop', '~> 0.24', '>= 0.24.0'
|
|
35
37
|
s.add_development_dependency 'simplecov', '~> 0.8', '>= 0.8.2'
|
|
38
|
+
s.add_development_dependency 'yard', '~> 0.8.7.3'
|
|
36
39
|
end
|
data/.rspec
ADDED
data/.yardopts
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Tool for transforming CSV into SQL statements
|
|
|
15
15
|
[](https://travis-ci.org/korczis/csv2psql)
|
|
16
16
|
[](https://codeclimate.com/github/korczis/csv2psql)
|
|
17
17
|
[](https://gemnasium.com/korczis/csv2psql)
|
|
18
|
-
|
|
18
|
+
[](https://coveralls.io/r/korczis/csv2psql?branch=master)
|
|
19
19
|
|
|
20
20
|
## Features
|
|
21
21
|
|
|
@@ -48,7 +48,7 @@ csv2psql convert data/sample.csv
|
|
|
48
48
|
csv2psql help
|
|
49
49
|
|
|
50
50
|
NAME
|
|
51
|
-
csv2psql - csv2psql 0.0.
|
|
51
|
+
csv2psql - csv2psql 0.0.9 (Codename: Flying fish)
|
|
52
52
|
|
|
53
53
|
SYNOPSIS
|
|
54
54
|
csv2psql [global options] command [command options] [arguments...]
|
|
@@ -61,11 +61,27 @@ GLOBAL OPTIONS
|
|
|
61
61
|
-s, --separator=arg - Line separator (default: auto)
|
|
62
62
|
|
|
63
63
|
COMMANDS
|
|
64
|
+
analyze - Analyze csv file
|
|
64
65
|
convert - Convert csv file
|
|
65
66
|
help - Shows a list of commands or help for one command
|
|
66
67
|
version - Print version info
|
|
67
68
|
```
|
|
68
69
|
|
|
70
|
+
**Analyze help**
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
csv2psql help analyze
|
|
74
|
+
|
|
75
|
+
NAME
|
|
76
|
+
analyze - Analyze csv file
|
|
77
|
+
|
|
78
|
+
SYNOPSIS
|
|
79
|
+
csv2psql [global options] analyze [command options]
|
|
80
|
+
|
|
81
|
+
COMMAND OPTIONS
|
|
82
|
+
-f, --format=arg - Output format (default: json)
|
|
83
|
+
```
|
|
84
|
+
|
|
69
85
|
**Convert help**
|
|
70
86
|
|
|
71
87
|
```
|
|
@@ -180,6 +196,30 @@ COMMIT;
|
|
|
180
196
|
csv2psql convert --create-table --drop-table --truncate-table --no-transaction -t test data/cia-data-all.csv | psql
|
|
181
197
|
```
|
|
182
198
|
|
|
199
|
+
**Analyze CSV - Show as table**
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
csv2psql analyze --format=table tmp/sfpd_incident_2013.csv
|
|
203
|
+
|
|
204
|
+
+------------+--------+-----------+---------+------+--------+------+
|
|
205
|
+
| tmp/sfpd_incident_2013.csv |
|
|
206
|
+
+------------+--------+-----------+---------+------+--------+------+
|
|
207
|
+
| column | Bigint | Character | Decimal | Null | String | Uuid |
|
|
208
|
+
+------------+--------+-----------+---------+------+--------+------+
|
|
209
|
+
| IncidntNum | 132145 | 0 | 0 | 0 | 132145 | 0 |
|
|
210
|
+
| Category | 0 | 0 | 0 | 0 | 132145 | 0 |
|
|
211
|
+
| Descript | 0 | 0 | 0 | 0 | 132145 | 0 |
|
|
212
|
+
| DayOfWeek | 0 | 0 | 0 | 0 | 132145 | 0 |
|
|
213
|
+
| Date | 0 | 0 | 0 | 0 | 132145 | 0 |
|
|
214
|
+
| Time | 0 | 0 | 0 | 0 | 132145 | 0 |
|
|
215
|
+
| PdDistrict | 0 | 0 | 0 | 0 | 132145 | 0 |
|
|
216
|
+
| Resolution | 0 | 0 | 0 | 0 | 132145 | 0 |
|
|
217
|
+
| Location | 0 | 0 | 0 | 0 | 132145 | 0 |
|
|
218
|
+
| X | 0 | 0 | 132145 | 0 | 132145 | 0 |
|
|
219
|
+
| Y | 0 | 0 | 132145 | 0 | 132145 | 0 |
|
|
220
|
+
+------------+--------+-----------+---------+------+--------+------+
|
|
221
|
+
```
|
|
222
|
+
|
|
183
223
|
## Contributing to csv2psql
|
|
184
224
|
|
|
185
225
|
- Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
data/Rakefile
CHANGED
|
@@ -3,18 +3,21 @@
|
|
|
3
3
|
require 'rubygems'
|
|
4
4
|
|
|
5
5
|
require 'bundler/setup'
|
|
6
|
-
require 'bundler/gem_tasks'
|
|
7
6
|
|
|
8
7
|
require 'coveralls/rake/task'
|
|
9
8
|
|
|
10
9
|
require 'rspec/core/rake_task'
|
|
11
10
|
|
|
11
|
+
require 'yard'
|
|
12
|
+
|
|
12
13
|
Coveralls::RakeTask.new
|
|
13
14
|
|
|
14
15
|
RSpec::Core::RakeTask.new(:test)
|
|
15
16
|
|
|
16
17
|
desc 'Run continuous integration test'
|
|
17
18
|
task :ci do
|
|
19
|
+
token = 'f9c7d31fe9fb2808cbb21642c4d1d20d1bfc1ba0d6321b10d7edf5725a5c8473'
|
|
20
|
+
ENV['CODECLIMATE_REPO_TOKEN'] = token
|
|
18
21
|
Rake::Task['test:unit'].invoke
|
|
19
22
|
# unless ENV['TRAVIS'] == 'true' && ENV['TRAVIS_SECURE_ENV_VARS'] == 'false'
|
|
20
23
|
# Rake::Task['test:integration'].invoke
|
|
@@ -25,7 +28,11 @@ end
|
|
|
25
28
|
|
|
26
29
|
desc 'Run Rubocop'
|
|
27
30
|
task :cop do
|
|
28
|
-
exec 'rubocop lib/'
|
|
31
|
+
exec 'rubocop lib/ spec/ templates/ Gemfile Rakefile'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
namespace :gem do
|
|
35
|
+
require 'bundler/gem_tasks'
|
|
29
36
|
end
|
|
30
37
|
|
|
31
38
|
namespace :test do
|
|
@@ -34,17 +41,12 @@ namespace :test do
|
|
|
34
41
|
t.pattern = 'spec/unit/**/*.rb'
|
|
35
42
|
end
|
|
36
43
|
|
|
37
|
-
desc
|
|
38
|
-
RSpec::Core::RakeTask.new(:cop) do |
|
|
44
|
+
desc 'Run coding style tests'
|
|
45
|
+
RSpec::Core::RakeTask.new(:cop) do |_t|
|
|
39
46
|
Rake::Task['cop'].invoke
|
|
40
47
|
end
|
|
41
48
|
|
|
42
|
-
task :
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
desc 'Get all tasks'
|
|
46
|
-
task :tasklist do
|
|
47
|
-
puts Rake.application.tasks
|
|
49
|
+
task all: [:unit, :cop]
|
|
48
50
|
end
|
|
49
51
|
|
|
50
52
|
task :usage do
|
|
@@ -52,8 +54,9 @@ task :usage do
|
|
|
52
54
|
# puts "No rake task specified so listing them ..."
|
|
53
55
|
# Rake.application['tasklist'].invoke
|
|
54
56
|
end
|
|
55
|
-
task :default => [:usage]
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
YARD::Rake::YardocTask.new
|
|
59
|
+
|
|
60
|
+
task default: [:usage]
|
|
61
|
+
|
|
62
|
+
Rake.application['usage'].invoke if __FILE__ == $PROGRAM_NAME
|
data/TODO.md
CHANGED
|
@@ -4,9 +4,12 @@ List od task to do
|
|
|
4
4
|
|
|
5
5
|
## Tasks
|
|
6
6
|
|
|
7
|
+
- Offset, Limit
|
|
8
|
+
- Custom types
|
|
7
9
|
- Column names override
|
|
8
10
|
- Data type detection
|
|
9
11
|
- Include/Exclude columns
|
|
10
12
|
- Column datatype guesser (with sha based caching of results)
|
|
11
13
|
- Templates override
|
|
12
|
-
- Custom row
|
|
14
|
+
- Custom row formatter - no need to override templates
|
|
15
|
+
- Transformers
|
data/bin/csv2psql
CHANGED
|
@@ -5,6 +5,8 @@ module Csv2Psql
|
|
|
5
5
|
# Bigint value matcher
|
|
6
6
|
class Bigint
|
|
7
7
|
TYPE = :bigint
|
|
8
|
+
CLASS = :numeric
|
|
9
|
+
WEIGHT = 4
|
|
8
10
|
|
|
9
11
|
attr_reader :count, :min, :max
|
|
10
12
|
|
|
@@ -24,6 +26,14 @@ module Csv2Psql
|
|
|
24
26
|
val.to_i
|
|
25
27
|
end
|
|
26
28
|
|
|
29
|
+
def to_h
|
|
30
|
+
{
|
|
31
|
+
count: @count,
|
|
32
|
+
min: @min,
|
|
33
|
+
max: @max
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
27
37
|
def update(val)
|
|
28
38
|
@count += 1
|
|
29
39
|
@min = val if @min.nil? || val < @min
|
|
@@ -5,6 +5,8 @@ module Csv2Psql
|
|
|
5
5
|
# Character value matcher
|
|
6
6
|
class Character
|
|
7
7
|
TYPE = :bigint
|
|
8
|
+
CLASS = :character
|
|
9
|
+
WEIGHT = 2
|
|
8
10
|
|
|
9
11
|
attr_reader :count
|
|
10
12
|
|
|
@@ -17,6 +19,12 @@ module Csv2Psql
|
|
|
17
19
|
return unless match
|
|
18
20
|
@count += 1
|
|
19
21
|
end
|
|
22
|
+
|
|
23
|
+
def to_h
|
|
24
|
+
{
|
|
25
|
+
count: @count
|
|
26
|
+
}
|
|
27
|
+
end
|
|
20
28
|
end
|
|
21
29
|
end
|
|
22
30
|
end
|
|
@@ -5,6 +5,8 @@ module Csv2Psql
|
|
|
5
5
|
# Decimal value matcher
|
|
6
6
|
class Decimal
|
|
7
7
|
TYPE = :decimal
|
|
8
|
+
CLASS = :numeric
|
|
9
|
+
WEIGHT = 3
|
|
8
10
|
|
|
9
11
|
attr_reader :count, :min, :max
|
|
10
12
|
|
|
@@ -24,6 +26,14 @@ module Csv2Psql
|
|
|
24
26
|
val.to_f
|
|
25
27
|
end
|
|
26
28
|
|
|
29
|
+
def to_h
|
|
30
|
+
{
|
|
31
|
+
count: @count,
|
|
32
|
+
min: @min,
|
|
33
|
+
max: @max
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
27
37
|
def update(val)
|
|
28
38
|
@count += 1
|
|
29
39
|
@min = val if @min.nil? || val < @min
|
|
@@ -5,6 +5,8 @@ module Csv2Psql
|
|
|
5
5
|
# Null value matcher
|
|
6
6
|
class Null
|
|
7
7
|
TYPE = :null
|
|
8
|
+
CLASS = nil # TODO: Maybe use better class for Null type?
|
|
9
|
+
WEIGHT = 0
|
|
8
10
|
|
|
9
11
|
attr_reader :count
|
|
10
12
|
|
|
@@ -17,6 +19,12 @@ module Csv2Psql
|
|
|
17
19
|
return unless match
|
|
18
20
|
@count += 1
|
|
19
21
|
end
|
|
22
|
+
|
|
23
|
+
def to_h
|
|
24
|
+
{
|
|
25
|
+
count: @count
|
|
26
|
+
}
|
|
27
|
+
end
|
|
20
28
|
end
|
|
21
29
|
end
|
|
22
30
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Csv2Psql
|
|
4
|
+
module Analyzers
|
|
5
|
+
# UUID value matcher
|
|
6
|
+
class String
|
|
7
|
+
TYPE = :string
|
|
8
|
+
CLASS = :character
|
|
9
|
+
WEIGHT = 1
|
|
10
|
+
|
|
11
|
+
attr_reader :count, :min, :max
|
|
12
|
+
|
|
13
|
+
def initialize
|
|
14
|
+
@count = 0
|
|
15
|
+
@min = nil
|
|
16
|
+
@max = nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def analyze(val)
|
|
20
|
+
match = val.is_a?(::String)
|
|
21
|
+
return unless match
|
|
22
|
+
len = val.length
|
|
23
|
+
@min = len if @min.nil? || len < @min
|
|
24
|
+
@max = len if @max.nil? || len > @max
|
|
25
|
+
@count += 1
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_h
|
|
29
|
+
{
|
|
30
|
+
count: @count,
|
|
31
|
+
min: @min,
|
|
32
|
+
max: @max
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -5,6 +5,9 @@ module Csv2Psql
|
|
|
5
5
|
# UUID value matcher
|
|
6
6
|
class Uuid
|
|
7
7
|
TYPE = :uuid
|
|
8
|
+
CLASS = :uuid
|
|
9
|
+
WEIGHT = 5
|
|
10
|
+
|
|
8
11
|
RE = /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/ # rubocop:disable Metrics/LineLength
|
|
9
12
|
|
|
10
13
|
attr_reader :count
|
|
@@ -18,6 +21,12 @@ module Csv2Psql
|
|
|
18
21
|
return if match.nil?
|
|
19
22
|
@count += 1
|
|
20
23
|
end
|
|
24
|
+
|
|
25
|
+
def to_h
|
|
26
|
+
{
|
|
27
|
+
count: @count
|
|
28
|
+
}
|
|
29
|
+
end
|
|
21
30
|
end
|
|
22
31
|
end
|
|
23
32
|
end
|
data/lib/csv2psql/cli/app.rb
CHANGED
|
@@ -29,6 +29,12 @@ cmds = {
|
|
|
29
29
|
default_value: Csv2Psql::Processor::DEFAULT_OPTIONS[:delimiter]
|
|
30
30
|
},
|
|
31
31
|
|
|
32
|
+
l: {
|
|
33
|
+
desc: 'How many rows process',
|
|
34
|
+
type: Integer,
|
|
35
|
+
default_value: -1
|
|
36
|
+
},
|
|
37
|
+
|
|
32
38
|
q: {
|
|
33
39
|
desc: 'Quoting character',
|
|
34
40
|
type: String,
|
|
@@ -39,13 +45,21 @@ cmds = {
|
|
|
39
45
|
desc: 'Line separator',
|
|
40
46
|
type: String,
|
|
41
47
|
default_value: Csv2Psql::Processor::DEFAULT_OPTIONS[:separator]
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
'skip' => {
|
|
51
|
+
desc: 'How many rows skip',
|
|
52
|
+
type: Integer,
|
|
53
|
+
default_value: -1
|
|
42
54
|
}
|
|
43
55
|
}
|
|
44
56
|
|
|
45
57
|
switch [:h, :header], cmds[:h]
|
|
46
58
|
flag [:d, :delimiter], cmds[:d]
|
|
59
|
+
flag [:l, :limit], cmds[:l]
|
|
47
60
|
flag [:q, :quote], cmds[:q]
|
|
48
61
|
flag [:s, :separator], cmds[:s]
|
|
62
|
+
flag [:skip], cmds['skip']
|
|
49
63
|
|
|
50
64
|
module Csv2Psql
|
|
51
65
|
# Apollon CLI
|
|
@@ -66,4 +80,4 @@ module Csv2Psql
|
|
|
66
80
|
end
|
|
67
81
|
end
|
|
68
82
|
|
|
69
|
-
launch
|
|
83
|
+
launch if __FILE__ == $PROGRAM_NAME
|
data/lib/csv2psql/cli/cli.rb
CHANGED
|
@@ -1,7 +1,31 @@
|
|
|
1
1
|
# encoding: UTF-8
|
|
2
2
|
|
|
3
|
-
require '
|
|
3
|
+
require 'gli'
|
|
4
|
+
require 'pp'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
# Define Csv2Psql::Cli as GLI Wrapper
|
|
7
|
+
module Csv2Psql
|
|
8
|
+
# CLI/GLI Wrapper
|
|
9
|
+
module Cli
|
|
10
|
+
include GLI::App
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
# Require shared part of GLI::App - flags, meta, etc
|
|
13
|
+
require_relative 'shared.rb'
|
|
14
|
+
|
|
15
|
+
# Require Hooks
|
|
16
|
+
# require_relative 'hooks.rb'
|
|
17
|
+
|
|
18
|
+
base = File.join(File.dirname(__FILE__), 'cmd')
|
|
19
|
+
Dir[base + '/**/*.rb'].each do |f|
|
|
20
|
+
require f
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# GLI::App.commands_from(File.join(File.dirname(__FILE__), 'cmd'))
|
|
24
|
+
|
|
25
|
+
def self.main(args = ARGV)
|
|
26
|
+
run(args)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Csv2Psql::Cli.main(ARGV) if __FILE__ == $PROGRAM_NAME
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
3
|
require 'gli'
|
|
4
|
+
require 'json'
|
|
4
5
|
require 'pp'
|
|
5
6
|
require 'terminal-table'
|
|
6
7
|
|
|
@@ -10,23 +11,65 @@ require_relative '../shared'
|
|
|
10
11
|
require_relative '../../convert/convert'
|
|
11
12
|
require_relative '../../processor/processor'
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
Csv2Psql::Cli.module_eval do
|
|
15
|
+
formats = {
|
|
16
|
+
'json' => lambda do |res|
|
|
17
|
+
res.files.each do |_fname, results|
|
|
18
|
+
results[:columns].each do |_k, v|
|
|
19
|
+
v.each do |d, det|
|
|
20
|
+
v[d] = det.to_h
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
JSON.pretty_generate(res.files)
|
|
26
|
+
end,
|
|
27
|
+
|
|
28
|
+
'table' => lambda do |res|
|
|
29
|
+
res.files.map do |file, details|
|
|
30
|
+
header = ['column'] + res.analyzers.map { |a| a[:name] }
|
|
31
|
+
|
|
32
|
+
rows = details[:columns].map do |k, v|
|
|
33
|
+
[k] + v.keys.map { |name| v[name].count }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Terminal::Table.new title: file, headings: header, rows: rows
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
cmds = {
|
|
42
|
+
f: {
|
|
43
|
+
desc: 'Output format',
|
|
44
|
+
type: String,
|
|
45
|
+
default_value: formats.keys.first
|
|
46
|
+
}
|
|
47
|
+
}
|
|
17
48
|
|
|
18
|
-
|
|
19
|
-
|
|
49
|
+
desc 'Analyze csv file'
|
|
50
|
+
command :analyze do |c|
|
|
51
|
+
c.flag [:f, :format], cmds[:f]
|
|
20
52
|
|
|
21
|
-
|
|
22
|
-
|
|
53
|
+
c.action do |global_options, options, args|
|
|
54
|
+
fail ArgumentError, 'No file to analyze specified' if args.empty?
|
|
23
55
|
|
|
24
|
-
|
|
25
|
-
|
|
56
|
+
opts = {}.merge(global_options).merge(options)
|
|
57
|
+
res = Csv2Psql::Convert.analyze(args, opts)
|
|
58
|
+
|
|
59
|
+
formater = formats[opts[:format]]
|
|
60
|
+
if formater.nil?
|
|
61
|
+
fmters = formats.keys.join(', ')
|
|
62
|
+
fail ArgumentError, "Wrong formatter specified, can be: #{fmters}"
|
|
26
63
|
end
|
|
27
64
|
|
|
28
|
-
|
|
29
|
-
|
|
65
|
+
output = formater.call(res)
|
|
66
|
+
if output.is_a?(Array)
|
|
67
|
+
output.each do |o|
|
|
68
|
+
puts o
|
|
69
|
+
end
|
|
70
|
+
else
|
|
71
|
+
puts output
|
|
72
|
+
end
|
|
30
73
|
end
|
|
31
74
|
end
|
|
32
75
|
end
|
|
@@ -8,48 +8,48 @@ require_relative '../shared'
|
|
|
8
8
|
require_relative '../../convert/convert'
|
|
9
9
|
require_relative '../../processor/processor'
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
11
|
+
Csv2Psql::Cli.module_eval do
|
|
12
|
+
cmds = {
|
|
13
|
+
t: {
|
|
14
|
+
desc: 'Table to insert to',
|
|
15
|
+
type: String,
|
|
16
|
+
default_value: Csv2Psql::Processor::DEFAULT_OPTIONS[:table]
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
transaction: {
|
|
20
|
+
desc: 'Import in transaction block',
|
|
21
|
+
default_value: Csv2Psql::Processor::DEFAULT_OPTIONS[:transaction]
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
'create-table' => {
|
|
25
|
+
desc: 'Crate SQL Table before inserts',
|
|
26
|
+
default_value: Csv2Psql::Processor::DEFAULT_OPTIONS['create-table']
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
'drop-table' => {
|
|
30
|
+
desc: 'Drop SQL Table before inserts',
|
|
31
|
+
default_value: Csv2Psql::Processor::DEFAULT_OPTIONS['drop-table']
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
'truncate-table' => {
|
|
35
|
+
desc: 'Truncate SQL Table before inserts',
|
|
36
|
+
default_value: Csv2Psql::Processor::DEFAULT_OPTIONS['truncate-table']
|
|
37
|
+
}
|
|
36
38
|
}
|
|
37
|
-
}
|
|
38
39
|
|
|
39
|
-
desc 'Convert csv file'
|
|
40
|
-
command :convert do |c|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
desc 'Convert csv file'
|
|
41
|
+
command :convert do |c|
|
|
42
|
+
c.flag [:t, :table], cmds[:t]
|
|
43
|
+
c.switch [:transaction], cmds[:transaction]
|
|
44
|
+
c.switch ['create-table'], cmds['create-table']
|
|
45
|
+
c.switch ['drop-table'], cmds['drop-table']
|
|
46
|
+
c.switch ['truncate-table'], cmds['truncate-table']
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
c.action do |global_options, options, args|
|
|
49
|
+
fail ArgumentError, 'No file to convert specified' if args.empty?
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
opts = {}.merge(global_options).merge(options)
|
|
52
|
+
Csv2Psql::Convert.convert(args, opts)
|
|
53
|
+
end
|
|
52
54
|
end
|
|
53
55
|
end
|
|
54
|
-
|
|
55
|
-
# default_command :convert
|
|
@@ -8,9 +8,11 @@ require_relative '../../version'
|
|
|
8
8
|
|
|
9
9
|
require_relative '../shared'
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
Csv2Psql::Cli.module_eval do
|
|
12
|
+
desc 'Print version info'
|
|
13
|
+
command :version do |c|
|
|
14
|
+
c.action do |_global_options, _options, _args|
|
|
15
|
+
pp Csv2Psql::VERSION
|
|
16
|
+
end
|
|
15
17
|
end
|
|
16
18
|
end
|
data/lib/csv2psql/cli/shared.rb
CHANGED
|
@@ -2,11 +2,55 @@
|
|
|
2
2
|
|
|
3
3
|
require 'gli'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
require_relative '../version'
|
|
6
|
+
require_relative '../processor/processor'
|
|
7
|
+
|
|
8
|
+
include GLI::App
|
|
9
|
+
|
|
10
|
+
Csv2Psql::Cli.module_eval do
|
|
11
|
+
program_desc "csv2psql #{Csv2Psql::VERSION} (Codename: #{Csv2Psql::CODENAME})"
|
|
12
|
+
|
|
13
|
+
cmds = {
|
|
14
|
+
h: {
|
|
15
|
+
desc: 'Header row included',
|
|
16
|
+
default_value: Csv2Psql::Processor::DEFAULT_OPTIONS[:header]
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
d: {
|
|
20
|
+
desc: 'Column delimiter',
|
|
21
|
+
type: String,
|
|
22
|
+
default_value: Csv2Psql::Processor::DEFAULT_OPTIONS[:delimiter]
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
l: {
|
|
26
|
+
desc: 'How many rows process',
|
|
27
|
+
type: Integer,
|
|
28
|
+
default_value: -1
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
q: {
|
|
32
|
+
desc: 'Quoting character',
|
|
33
|
+
type: String,
|
|
34
|
+
default_value: Csv2Psql::Processor::DEFAULT_OPTIONS[:quote]
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
s: {
|
|
38
|
+
desc: 'Line separator',
|
|
39
|
+
type: String,
|
|
40
|
+
default_value: Csv2Psql::Processor::DEFAULT_OPTIONS[:separator]
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
'skip' => {
|
|
44
|
+
desc: 'How many rows skip',
|
|
45
|
+
type: Integer,
|
|
46
|
+
default_value: -1
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
switch [:h, :header], cmds[:h]
|
|
51
|
+
flag [:d, :delimiter], cmds[:d]
|
|
52
|
+
flag [:l, :limit], cmds[:l]
|
|
53
|
+
flag [:q, :quote], cmds[:q]
|
|
54
|
+
flag [:s, :separator], cmds[:s]
|
|
55
|
+
flag [:skip], cmds['skip']
|
|
12
56
|
end
|
|
@@ -10,7 +10,7 @@ require_relative '../helpers/csv_helper'
|
|
|
10
10
|
require_relative '../helpers/erb_helper'
|
|
11
11
|
|
|
12
12
|
module Csv2Psql
|
|
13
|
-
#
|
|
13
|
+
# SQL Code generator
|
|
14
14
|
class Generator
|
|
15
15
|
BASE_DIR = File.join(File.dirname(__FILE__), '..', '..', '..')
|
|
16
16
|
TEMPLATE_DIR = File.join(BASE_DIR, 'templates')
|
|
@@ -33,25 +33,42 @@ module Csv2Psql
|
|
|
33
33
|
|
|
34
34
|
def analyze(paths, opts = {})
|
|
35
35
|
with_paths(paths, opts) do |data|
|
|
36
|
-
path
|
|
37
|
-
row = data[:row]
|
|
38
|
-
analyzer.analyze(path, row, opts)
|
|
36
|
+
analyzer.analyze(data[:path], data[:row], opts)
|
|
39
37
|
end
|
|
40
38
|
analyzer
|
|
41
39
|
end
|
|
42
40
|
|
|
43
41
|
def convert(paths, opts = {})
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
details = {}
|
|
46
43
|
with_paths(paths, opts) do |data|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
create_converted_header(details, data, opts)
|
|
45
|
+
|
|
46
|
+
output.write generator.format_row(data[:row], opts)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def create_converted_header(details, data, opts = {})
|
|
51
|
+
detail = get_file_details(details, data[:path])
|
|
52
|
+
unless detail[:header] # rubocop:disable Style/GuardClause
|
|
53
|
+
generator.create_sql_script(data[:path], data[:row], opts)
|
|
54
|
+
detail[:header] = true
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def create_file_details(files, path)
|
|
59
|
+
files[path] = {
|
|
60
|
+
header: false,
|
|
61
|
+
lines: 0,
|
|
62
|
+
line: 0
|
|
63
|
+
}
|
|
64
|
+
files[path]
|
|
65
|
+
end
|
|
53
66
|
|
|
54
|
-
|
|
67
|
+
def get_file_details(files, path)
|
|
68
|
+
if files.key?(path)
|
|
69
|
+
files[path]
|
|
70
|
+
else
|
|
71
|
+
create_file_details(files, path)
|
|
55
72
|
end
|
|
56
73
|
end
|
|
57
74
|
|
data/lib/csv2psql/version.rb
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require_relative '../../../lib/csv2psql/cli/cli'
|
|
4
|
+
|
|
5
|
+
describe 'csv2psql analyze' do
|
|
6
|
+
it 'help analyze' do
|
|
7
|
+
run_cli(%w(help analyze))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'analyze data/cia-data-all.csv' do
|
|
11
|
+
run_cli(%w(analyze data/cia-data-all.csv))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'analyze data/sample.csv' do
|
|
15
|
+
run_cli(%w(analyze data/sample.csv))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it '--delimiter ";" analyze data/sample.csv' do
|
|
19
|
+
run_cli(%w(analyze --delimiter ";" data/sample_semicolon.csv))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'analyze --format json data/sample.csv' do
|
|
23
|
+
run_cli(%w(analyze --format json data/sample.csv))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'analyze --format table data/sample.csv' do
|
|
27
|
+
run_cli(%w(analyze --format table data/sample.csv))
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require_relative '../../../lib/csv2psql/cli/cli'
|
|
4
|
+
|
|
5
|
+
describe 'csv2psql convert' do
|
|
6
|
+
it 'help convert' do
|
|
7
|
+
run_cli(%w(help convert))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'convert data/cia-data-all.csv' do
|
|
11
|
+
run_cli(%w(convert data/cia-data-all.csv))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'convert data/sample.csv' do
|
|
15
|
+
run_cli(%w(convert data/sample.csv))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'convert --drop-table data/sample.csv' do
|
|
19
|
+
run_cli(%w(convert --drop-table data/sample.csv))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'convert --drop-table --create-table data/sample.csv' do
|
|
23
|
+
run_cli(%w(convert --drop-table --create-table data/sample.csv))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'convert --drop-table --create-table --truncate-table data/sample.csv' do
|
|
27
|
+
args = %w(
|
|
28
|
+
convert
|
|
29
|
+
--drop-table
|
|
30
|
+
--create-table
|
|
31
|
+
--truncate-table
|
|
32
|
+
data/sample.csv
|
|
33
|
+
)
|
|
34
|
+
run_cli(args)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require_relative '../../lib/csv2psql/cli/cli'
|
|
4
|
+
|
|
5
|
+
# CliHelper
|
|
6
|
+
module CliHelper
|
|
7
|
+
# Execute block and capture its stdou
|
|
8
|
+
# @param block Block to be executed with stdout redirected
|
|
9
|
+
# @returns Captured output as string
|
|
10
|
+
def capture_stdout(&block)
|
|
11
|
+
original_stdout = $stdout
|
|
12
|
+
$stdout = fake = StringIO.new
|
|
13
|
+
begin
|
|
14
|
+
block.call if block_given?
|
|
15
|
+
ensure
|
|
16
|
+
$stdout = original_stdout
|
|
17
|
+
end
|
|
18
|
+
fake.string
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Run CLI with arguments and return captured stdout
|
|
22
|
+
# @param args Arguments
|
|
23
|
+
# @return Captured stdout
|
|
24
|
+
def run_cli(args = [])
|
|
25
|
+
old = $PROGRAM_NAME
|
|
26
|
+
$PROGRAM_NAME = 'csv2psql'
|
|
27
|
+
res = capture_stdout { Csv2Psql::Cli.main(args) }
|
|
28
|
+
$PROGRAM_NAME = old
|
|
29
|
+
res
|
|
30
|
+
end
|
|
31
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# encoding: UTF-8
|
|
2
2
|
|
|
3
|
+
require 'codeclimate-test-reporter'
|
|
3
4
|
require 'simplecov'
|
|
4
5
|
require 'rspec'
|
|
5
6
|
require 'coveralls'
|
|
6
7
|
require 'pathname'
|
|
7
8
|
|
|
9
|
+
CodeClimate::TestReporter.start
|
|
10
|
+
|
|
8
11
|
Coveralls.wear_merged!
|
|
9
12
|
|
|
10
13
|
# Automagically include all helpers/*_helper.rb
|
|
@@ -15,7 +18,9 @@ Dir.glob(base + 'helpers/*_helper.rb').each do |file|
|
|
|
15
18
|
end
|
|
16
19
|
|
|
17
20
|
RSpec.configure do |config|
|
|
18
|
-
config.
|
|
21
|
+
config.include CliHelper
|
|
22
|
+
|
|
23
|
+
config.filter_run_excluding broken: true
|
|
19
24
|
|
|
20
25
|
config.before(:all) do
|
|
21
26
|
# TODO: Fully setup global environment
|
|
@@ -41,4 +46,4 @@ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
|
|
41
46
|
|
|
42
47
|
SimpleCov.start do
|
|
43
48
|
add_filter 'spec/'
|
|
44
|
-
end
|
|
49
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: csv2psql
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tomas Korcak
|
|
@@ -98,6 +98,26 @@ dependencies:
|
|
|
98
98
|
- - ">="
|
|
99
99
|
- !ruby/object:Gem::Version
|
|
100
100
|
version: 1.4.5
|
|
101
|
+
- !ruby/object:Gem::Dependency
|
|
102
|
+
name: codeclimate-test-reporter
|
|
103
|
+
requirement: !ruby/object:Gem::Requirement
|
|
104
|
+
requirements:
|
|
105
|
+
- - "~>"
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
version: '0.4'
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: 0.4.0
|
|
111
|
+
type: :development
|
|
112
|
+
prerelease: false
|
|
113
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0.4'
|
|
118
|
+
- - ">="
|
|
119
|
+
- !ruby/object:Gem::Version
|
|
120
|
+
version: 0.4.0
|
|
101
121
|
- !ruby/object:Gem::Dependency
|
|
102
122
|
name: coveralls
|
|
103
123
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -118,6 +138,20 @@ dependencies:
|
|
|
118
138
|
- - ">="
|
|
119
139
|
- !ruby/object:Gem::Version
|
|
120
140
|
version: 0.7.0r
|
|
141
|
+
- !ruby/object:Gem::Dependency
|
|
142
|
+
name: redcarpet
|
|
143
|
+
requirement: !ruby/object:Gem::Requirement
|
|
144
|
+
requirements:
|
|
145
|
+
- - "~>"
|
|
146
|
+
- !ruby/object:Gem::Version
|
|
147
|
+
version: 3.1.1
|
|
148
|
+
type: :development
|
|
149
|
+
prerelease: false
|
|
150
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
151
|
+
requirements:
|
|
152
|
+
- - "~>"
|
|
153
|
+
- !ruby/object:Gem::Version
|
|
154
|
+
version: 3.1.1
|
|
121
155
|
- !ruby/object:Gem::Dependency
|
|
122
156
|
name: rspec
|
|
123
157
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -178,6 +212,20 @@ dependencies:
|
|
|
178
212
|
- - ">="
|
|
179
213
|
- !ruby/object:Gem::Version
|
|
180
214
|
version: 0.8.2
|
|
215
|
+
- !ruby/object:Gem::Dependency
|
|
216
|
+
name: yard
|
|
217
|
+
requirement: !ruby/object:Gem::Requirement
|
|
218
|
+
requirements:
|
|
219
|
+
- - "~>"
|
|
220
|
+
- !ruby/object:Gem::Version
|
|
221
|
+
version: 0.8.7.3
|
|
222
|
+
type: :development
|
|
223
|
+
prerelease: false
|
|
224
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
225
|
+
requirements:
|
|
226
|
+
- - "~>"
|
|
227
|
+
- !ruby/object:Gem::Version
|
|
228
|
+
version: 0.8.7.3
|
|
181
229
|
description: CSV to SQL conversion tool with user friendly CLI
|
|
182
230
|
email: korczis@gmail.com
|
|
183
231
|
executables:
|
|
@@ -187,7 +235,9 @@ extra_rdoc_files: []
|
|
|
187
235
|
files:
|
|
188
236
|
- ".gemspec"
|
|
189
237
|
- ".gitignore"
|
|
238
|
+
- ".rspec"
|
|
190
239
|
- ".travis.yml"
|
|
240
|
+
- ".yardopts"
|
|
191
241
|
- Gemfile
|
|
192
242
|
- LICENSE
|
|
193
243
|
- README.md
|
|
@@ -196,12 +246,14 @@ files:
|
|
|
196
246
|
- bin/csv2psql
|
|
197
247
|
- data/cia-data-all.csv
|
|
198
248
|
- data/sample.csv
|
|
249
|
+
- data/sample_semicolons.csv
|
|
199
250
|
- lib/csv2psql.rb
|
|
200
251
|
- lib/csv2psql/analyzer/analyzer.rb
|
|
201
252
|
- lib/csv2psql/analyzer/types/bigint.rb
|
|
202
253
|
- lib/csv2psql/analyzer/types/character.rb
|
|
203
254
|
- lib/csv2psql/analyzer/types/decimal.rb
|
|
204
255
|
- lib/csv2psql/analyzer/types/null.rb
|
|
256
|
+
- lib/csv2psql/analyzer/types/string.rb
|
|
205
257
|
- lib/csv2psql/analyzer/types/uuid.rb
|
|
206
258
|
- lib/csv2psql/cli/app.rb
|
|
207
259
|
- lib/csv2psql/cli/cli.rb
|
|
@@ -219,6 +271,11 @@ files:
|
|
|
219
271
|
- lib/csv2psql/output/output.rb
|
|
220
272
|
- lib/csv2psql/processor/processor.rb
|
|
221
273
|
- lib/csv2psql/version.rb
|
|
274
|
+
- spec/cli/app_spec.rb
|
|
275
|
+
- spec/cli/cmd/analyze_cmd_spec.rb
|
|
276
|
+
- spec/cli/cmd/convert_cmd_spec.rb
|
|
277
|
+
- spec/cli/cmd/version_cmd_spec.rb
|
|
278
|
+
- spec/helpers/cli_helper.rb
|
|
222
279
|
- spec/spec_helper.rb
|
|
223
280
|
- templates/create_table.sql.erb
|
|
224
281
|
- templates/drop_table.sql.erb
|
|
@@ -249,3 +306,4 @@ signing_key:
|
|
|
249
306
|
specification_version: 4
|
|
250
307
|
summary: Tool for converting CSV into SQL statements
|
|
251
308
|
test_files: []
|
|
309
|
+
has_rdoc:
|