csvql 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 810630ed534c79a2a4fa99ccf6757950352ae6eb
4
- data.tar.gz: e11f9a88105893d4aea8eef4b1c47d949fd83ca4
3
+ metadata.gz: 6154147fd2ece48902d1e4494b7d248cd125f9ab
4
+ data.tar.gz: 492d8e597c6c1e657b2efdfdadc48f9e4c4e6ad5
5
5
  SHA512:
6
- metadata.gz: 1419f89fb4e2a4d484169348ffa1ff26ae8d6e2f465680c2651ea1f38810d13fa78dce29f63ee3a4e69974f70f1dc6e8e912050e3aa5e3cda07dabb61e69492a
7
- data.tar.gz: da76917a1a2e45ebd1b11cce12a02e0da70dfded8c52fcb239a769a6b4e13004652e96b8520a9199d806828566c70a0349eebc922874b4e0435ddfd885d35056
6
+ metadata.gz: 578f5cedc8514c6df4790cfd821b98b075095cce9a6838fc865f8e2d5939864eb1c36151bcd78d6c2ee604ea9263bd56f6552986dde98381f30af8333bd3e624
7
+ data.tar.gz: 49956fd0295eaf4d7813038ac4f7ab1b5655c2044ce98d193e5143699850eb40798a0a28d11b4d1771b47987351ebea57b86b5fed96c15c7bb923cfe0bd42487
data/lib/csvql/csvql.rb CHANGED
@@ -1,16 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
- require 'csv'
5
- require 'nkf'
6
4
  require 'tempfile'
7
- require 'optparse'
8
5
  require 'sqlite3'
9
6
 
10
7
  module Csvql
11
8
  class TableHandler
12
9
  def initialize(path, console)
13
- @db_file = if path && path.size > 0
10
+ @db_file = if path && path.strip.size > 0
14
11
  path
15
12
  elsif console
16
13
  @tmp_file = Tempfile.new("csvql").path
@@ -20,26 +17,11 @@ module Csvql
20
17
  @db = SQLite3::Database.new(@db_file)
21
18
  end
22
19
 
23
- def create_table(cols, header, table_name="tbl", schema=nil)
24
- @col_size = cols.size
20
+ def create_table(schema, table_name="tbl")
21
+ @col_name = schema.split(",").map {|c| c.split.first.strip }
22
+ @col_size = @col_name.size
25
23
  @table_name = table_name
26
- if schema
27
- file = File.expand_path(schema)
28
- col = if File.exist?(file)
29
- File.open(file).read
30
- else
31
- schema
32
- end
33
- @col_name = col.split(",").map {|c| c.split.first.strip }
34
- else
35
- @col_name = if header
36
- cols
37
- else
38
- @col_size.times.map {|i| "c#{i}" }
39
- end
40
- col = @col_name.map {|c| "#{c} NONE" }.join(",")
41
- end
42
- sql = "CREATE TABLE IF NOT EXISTS #{@table_name} (#{col})"
24
+ sql = "CREATE TABLE IF NOT EXISTS #{@table_name} (#{schema})"
43
25
  @db.execute(sql)
44
26
  end
45
27
 
@@ -62,13 +44,8 @@ module Csvql
62
44
  @pre.execute(cols)
63
45
  end
64
46
 
65
- def exec(sql, dlm="|")
66
- if dlm.downcase == 'tab'
67
- dlm = "\t"
68
- end
69
- @db.execute(sql) do |row|
70
- puts row.join(dlm)
71
- end
47
+ def exec(sql)
48
+ @db.execute(sql)
72
49
  end
73
50
 
74
51
  def open_console
@@ -76,80 +53,4 @@ module Csvql
76
53
  File.delete(@tmp_file) if @tmp_file
77
54
  end
78
55
  end
79
-
80
- class << self
81
- def option_parse(argv)
82
- opt = OptionParser.new
83
- option = {}
84
-
85
- # default
86
- option[:header] = true
87
-
88
- opt.banner = "Usage: csvql [csvfile] [options]"
89
- opt.on("--console", "After all commands are run, open sqlite3 console with this data") {|v| option[:console] = v }
90
- opt.on("--[no-]header", "Treat file as having the first row as a header row") {|v| option[:header] = v }
91
- opt.on('--output-dlm="|"', "Output delimiter (|)") {|v| option[:output_dlm] = v }
92
- opt.on("--save-to=FILE", "If set, sqlite3 db is left on disk at this path") {|v| option[:save_to] = v }
93
- opt.on("--append", "Append mode (not dropping any tables)") {|v| option[:append] = v }
94
- opt.on("--skip-comment", "Skip comment lines start with '#'") {|v| option[:skip_comment] = v }
95
- opt.on("--source=FILE", "Source file to load, or defaults to stdin") {|v| option[:source] = v }
96
- opt.on("--sql=SQL", "SQL Command(s) to run on the data") {|v| option[:sql] = v }
97
- opt.on("--select=COLUMN", "Select column (*)") {|v| option[:select] = v }
98
- opt.on("--schema=FILE or STRING", "Specify a table schema") {|v| option[:schema] = v }
99
- opt.on("--where=COND", "Where clause") {|v| option[:where] = v }
100
- opt.on("--table-name=NAME", "Override the default table name (tbl)") {|v| option[:table_name] = v }
101
- opt.on("--verbose", "Enable verbose logging") {|v| option[:verbose] = v }
102
- opt.parse!(argv)
103
-
104
- option[:source] ||= argv[0]
105
- # option[:where] ||= argv[1]
106
- option[:table_name] ||= "tbl"
107
- option[:output_dlm] ||= "|"
108
- option
109
- end
110
-
111
- def run(argv)
112
- option = option_parse(argv)
113
- if option[:console] && option[:source] == nil
114
- puts "Can not open console with pipe input, read a file instead"
115
- exit 1
116
- end
117
- if option[:sql] && (option[:select] || option[:where])
118
- puts "Can not use --sql option and --select|--where option at the same time."
119
- exit 1
120
- end
121
-
122
- csvfile = option[:source] ? File.open(option[:source]) : $stdin
123
-
124
- tbl = TableHandler.new(option[:save_to], option[:console])
125
- tbl.drop_table(option[:table_name]) unless option[:append]
126
- tbl.exec("PRAGMA synchronous=OFF")
127
- tbl.exec("BEGIN TRANSACTION")
128
- csvfile.each.with_index(1) do |line,i|
129
- line = NKF.nkf('-w', line).strip
130
- next if line.size == 0
131
- next if option[:skip_comment] && line.start_with?("#")
132
- row = line.parse_csv
133
- if i == 1
134
- tbl.create_table(row, option[:header], option[:table_name], option[:schema])
135
- next if option[:header]
136
- end
137
- tbl.insert(row, i)
138
- end
139
- tbl.exec("COMMIT TRANSACTION")
140
-
141
- if option[:sql]
142
- sql = option[:sql]
143
- elsif option[:select] || option[:where]
144
- option[:select] ||= "*"
145
- sql = "select #{option[:select]} from #{option[:table_name]}"
146
- if option[:where]
147
- sql += " where (#{option[:where]})"
148
- end
149
- end
150
-
151
- tbl.exec(sql, option[:output_dlm]) if sql
152
- tbl.open_console if option[:console]
153
- end
154
- end
155
56
  end
data/lib/csvql/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Csvql
2
- VERSION = "0.1.7"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/csvql.rb CHANGED
@@ -1,6 +1,109 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'csv'
4
+ require 'nkf'
5
+ require 'optparse'
6
+
1
7
  require "csvql/csvql"
2
8
  require "csvql/version"
3
9
 
4
10
  module Csvql
5
- # Your code goes here...
11
+ class << self
12
+ def option_parse(argv)
13
+ opt = OptionParser.new
14
+ option = {}
15
+
16
+ # default
17
+ option[:header] = true
18
+
19
+ opt.banner = "Usage: csvql [csvfile] [options]"
20
+ opt.on("--console", "After all commands are run, open sqlite3 console with this data") {|v| option[:console] = v }
21
+ opt.on("--[no-]header", "Treat file as having the first row as a header row") {|v| option[:header] = v }
22
+ opt.on('--output-dlm="|"', "Output delimiter (|)") {|v| option[:output_dlm] = v }
23
+ opt.on("--save-to=FILE", "If set, sqlite3 db is left on disk at this path") {|v| option[:save_to] = v }
24
+ opt.on("--append", "Append mode (not dropping any tables)") {|v| option[:append] = v }
25
+ opt.on("--skip-comment", "Skip comment lines start with '#'") {|v| option[:skip_comment] = v }
26
+ opt.on("--source=FILE", "Source file to load, or defaults to stdin") {|v| option[:source] = v }
27
+ opt.on("--sql=SQL", "SQL Command(s) to run on the data") {|v| option[:sql] = v }
28
+ opt.on("--select=COLUMN", "Select column (*)") {|v| option[:select] = v }
29
+ opt.on("--schema=FILE or STRING", "Specify a table schema") {|v| option[:schema] = v }
30
+ opt.on("--where=COND", "Where clause") {|v| option[:where] = v }
31
+ opt.on("--table-name=NAME", "Override the default table name (tbl)") {|v| option[:table_name] = v }
32
+ opt.on("--verbose", "Enable verbose logging") {|v| option[:verbose] = v }
33
+ opt.parse!(argv)
34
+
35
+ option[:source] ||= argv[0]
36
+ # option[:where] ||= argv[1]
37
+ option[:table_name] ||= "tbl"
38
+ if option[:output_dlm] == 'tab'
39
+ option[:output_dlm] = "\t"
40
+ end
41
+ option[:output_dlm] ||= "|"
42
+
43
+ if option[:completion]
44
+ puts opt.compsys('csvql')
45
+ exit 0
46
+ end
47
+ option
48
+ end
49
+
50
+ def run(argv)
51
+ option = option_parse(argv)
52
+ if option[:console] && option[:source] == nil
53
+ puts "Can not open console with pipe input, read a file instead"
54
+ exit 1
55
+ end
56
+ if option[:sql] && (option[:select] || option[:where])
57
+ puts "Can not use --sql option and --select|--where option at the same time."
58
+ exit 1
59
+ end
60
+
61
+ csvfile = option[:source] ? File.open(option[:source]) : $stdin
62
+ first_line = csvfile.readline
63
+
64
+ schema = option[:schema]
65
+ if schema
66
+ file = File.expand_path(schema)
67
+ if File.exist?(file)
68
+ schema = File.open(file).read
69
+ end
70
+ else
71
+ cols = first_line.parse_csv
72
+ col_name = if option[:header]
73
+ cols
74
+ else
75
+ cols.size.times.map {|i| "c#{i}" }
76
+ end
77
+ schema = col_name.map {|c| "#{c} NONE" }.join(",")
78
+ end
79
+ csvfile.rewind unless option[:header]
80
+
81
+ tbl = TableHandler.new(option[:save_to], option[:console])
82
+ tbl.drop_table(option[:table_name]) unless option[:append]
83
+ tbl.create_table(schema, option[:table_name])
84
+ tbl.exec("PRAGMA synchronous=OFF")
85
+ tbl.exec("BEGIN TRANSACTION")
86
+ csvfile.each.with_index(1) do |line,i|
87
+ line = NKF.nkf('-w', line).strip
88
+ next if line.size == 0
89
+ next if option[:skip_comment] && line.start_with?("#")
90
+ row = line.parse_csv
91
+ tbl.insert(row, i)
92
+ end
93
+ tbl.exec("COMMIT TRANSACTION")
94
+
95
+ if option[:sql]
96
+ sql = option[:sql]
97
+ elsif option[:select] || option[:where]
98
+ option[:select] ||= "*"
99
+ sql = "select #{option[:select]} from #{option[:table_name]}"
100
+ if option[:where]
101
+ sql += " where (#{option[:where]})"
102
+ end
103
+ end
104
+
105
+ tbl.exec(sql).each {|row| puts row.join(option[:output_dlm]) } if sql
106
+ tbl.open_console if option[:console]
107
+ end
108
+ end
6
109
  end
data/spec/csvql_spec.rb CHANGED
@@ -1,11 +1,56 @@
1
1
  require 'spec_helper'
2
2
 
3
+ csvfile = File.join(File.expand_path(File.dirname("__FILE__")), "spec/sample.csv")
4
+
3
5
  describe Csvql do
4
6
  it 'has a version number' do
5
7
  expect(Csvql::VERSION).not_to be nil
6
8
  end
7
9
 
8
- it 'does something useful' do
9
- expect(false).to eq(true)
10
+ it 'select name' do
11
+ expect(capture {
12
+ Csvql.run([csvfile, "--select", "name"])
13
+ }).to eq(<<EOL)
14
+ Anne
15
+ Bob
16
+ Charry
17
+ Daniel
18
+ Edward
19
+ EOL
20
+ end
21
+
22
+ it 'where age > 40' do
23
+ expect(capture {
24
+ Csvql.run([csvfile, "--where", "age > 40"])
25
+ }).to eq(<<EOL)
26
+ 3|Charry|48
27
+ 5|Edward|52
28
+ EOL
29
+ end
30
+
31
+ it 'sql option' do
32
+ expect(capture {
33
+ Csvql.run([csvfile, "--sql", "select name,age from tbl where age between 20 and 40"])
34
+ }).to eq(<<EOL)
35
+ Anne|33
36
+ Bob|25
37
+ EOL
38
+ end
39
+
40
+ it 'change output delimiter' do
41
+ expect(capture {
42
+ Csvql.run([csvfile, "--where", "id = 3", "--output-dlm", ","])
43
+ }).to eq(<<EOL)
44
+ 3,Charry,48
45
+ EOL
46
+ end
47
+
48
+ it 'change table name' do
49
+ expect(capture {
50
+ Csvql.run([csvfile, "--sql", "select id,name from user_info where id >= 4", "--table-name", "user_info"])
51
+ }).to eq(<<EOL)
52
+ 4|Daniel
53
+ 5|Edward
54
+ EOL
10
55
  end
11
56
  end
data/spec/sample.csv ADDED
@@ -0,0 +1,6 @@
1
+ id,name,age
2
+ 1,Anne,33
3
+ 2,Bob,25
4
+ 3,Charry,48
5
+ 4,Daniel,16
6
+ 5,Edward,52
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,13 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
2
  require 'csvql'
3
+
4
+ def capture
5
+ begin
6
+ $stdout = StringIO.new
7
+ yield
8
+ result = $stdout.string
9
+ ensure
10
+ $stdout = STDOUT
11
+ end
12
+ result
13
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csvql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - YANO Satoru
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-10 00:00:00.000000000 Z
11
+ date: 2014-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sqlite3
@@ -45,6 +45,7 @@ files:
45
45
  - lib/csvql/csvql.rb
46
46
  - lib/csvql/version.rb
47
47
  - spec/csvql_spec.rb
48
+ - spec/sample.csv
48
49
  - spec/spec_helper.rb
49
50
  homepage: ''
50
51
  licenses:
@@ -66,10 +67,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
66
67
  version: '0'
67
68
  requirements: []
68
69
  rubyforge_project:
69
- rubygems_version: 2.2.2
70
+ rubygems_version: 2.3.0
70
71
  signing_key:
71
72
  specification_version: 4
72
73
  summary: csvql
73
74
  test_files:
74
75
  - spec/csvql_spec.rb
76
+ - spec/sample.csv
75
77
  - spec/spec_helper.rb