csv2psql 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/korczis/csv2psql.svg?branch=master)](https://travis-ci.org/korczis/csv2psql)
|
16
16
|
[![Code Climate](https://codeclimate.com/github/korczis/csv2psql/badges/gpa.svg)](https://codeclimate.com/github/korczis/csv2psql)
|
17
17
|
[![Dependency Status](https://gemnasium.com/korczis/csv2psql.svg)](https://gemnasium.com/korczis/csv2psql)
|
18
|
-
|
18
|
+
[![Coverage Status](https://coveralls.io/repos/korczis/csv2psql/badge.png?branch=master)](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:
|