csvql 0.1.7 → 0.2.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
  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