slyce 0.9.2 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/bin/slyce +18 -10
  3. data/bin/slyce3 +127 -0
  4. metadata +3 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73484428602b9a69afae319a88b9b0045cb13b3d17e3f24a9532b73a35c53a28
4
- data.tar.gz: 243242d2a638ad262b6e34c0b7c5d3541eac62048ed24a81d9c1d93a6d91b55c
3
+ metadata.gz: 380c2147a52bd30761850468c1a06b6f041523d66ed513912a0756a51d80d7d5
4
+ data.tar.gz: 1f306e010169260bc76a5bfb7200d2c9c0ca87ca76fc27b143b9e61e6310ef14
5
5
  SHA512:
6
- metadata.gz: 1f636b19580ca0797aa86325d5b0d24e23caa9c6e92d3a35716882a1d0c69b9708fbb5554c982d8f1f096801248e2ce9f79562b11b46eac50b76fd93747fdd69
7
- data.tar.gz: eb0ffa3c6b948a0d0d6c0bb05b16881f4c628eebbf9de63c5bc052df80e0b661a91cb195a1ff1449afcf004a006b19e76e43a0ee279e4993615fd45d2d48bae3
6
+ metadata.gz: 33369805c3929785f1709b567484d35ceaeb2d0502c5db8db8c1a26ea50e31f43dd39d48f6ac605e4cf294e8ea727fa3f9c5977091c3c48e25c68a4080c6e444
7
+ data.tar.gz: ef9ca1f35c4f6c172f231b9609fc72968e393ffbf45005973a4918e293af59ca53d82dbd8d7788f829a783213c70a020b88640939c64fbc1db5395659272507e
data/bin/slyce CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- STDOUT.sync = true
3
+ VERSION="0.9.7"
4
4
 
5
- VERSION="0.9.2"
5
+ STDOUT.sync = true
6
6
 
7
7
  require "mysql2"
8
8
  require "optparse"
@@ -27,19 +27,23 @@ OptionParser.new.instance_eval do
27
27
  end.parse!(into: opts={}) rescue abort($!.message)
28
28
 
29
29
  abcd = opts[:alpha]
30
+ filt = opts[:where] and filt = "where\n #{filt}"
30
31
  show = opts[:show]
31
32
  want = opts[:extract].to_s.downcase.split(",")
32
- filt = opts[:where] and filt = "where\n #{filt}"
33
33
 
34
- dbas ||= ARGV.shift or Kernel.abort "no database given"
35
- tabl ||= ARGV.shift or Kernel.abort "no table given"
34
+ dbas ||= ARGV.shift or abort "no database given"
35
+ tabl ||= ARGV.shift or abort "no table given"
36
36
 
37
37
  # ==[ Helpers ]==
38
38
 
39
39
  class Mysql2::Client
40
- def query!(stmt, *args, **, &)
40
+ def sql(...)
41
+ query(...)
42
+ end
43
+
44
+ def sql!(stmt, *args, **, &)
41
45
  puts "\n==[ SQL statement ]==\n\n", stmt.strip, ";"
42
- query(stmt, *args, **, &)
46
+ sql(stmt, *args, **, &)
43
47
  end
44
48
  end
45
49
 
@@ -69,10 +73,14 @@ if opts[:columns]
69
73
  exit
70
74
  end
71
75
 
76
+ if want.empty?
77
+ abort "no columns are selected"
78
+ end
79
+
72
80
  want.each do |name|
73
81
  sort = abcd ? "" : "cnt desc,"
74
82
  stmt = show ? "limit #{show}" : ""
75
- data = conn.query(<<~"" + stmt).to_a
83
+ data = conn.sql(<<~"" + stmt).to_a
76
84
  select
77
85
  count(*) as cnt,
78
86
  `#{name}` as val
@@ -87,14 +95,14 @@ want.each do |name|
87
95
  -if(regexp_like(`#{name}`, '^\\\\d'), regexp_instr(`#{name}`, '[^\\\\d]'), null) desc,
88
96
  `#{name}` is null, `#{name}`
89
97
 
90
- uniq = conn.query(<<~"").to_a[0][0]
98
+ uniq = conn.sql(<<~"").to_a[0][0]
91
99
  select
92
100
  count(distinct(ifnull(`#{name}`,0)))
93
101
  from
94
102
  `#{tabl}`
95
103
  #{filt}
96
104
 
97
- tots = conn.query(<<~"").to_a[0][0]
105
+ tots = conn.sql(<<~"").to_a[0][0]
98
106
  select
99
107
  count(ifnull(`#{name}`,0))
100
108
  from
data/bin/slyce3 ADDED
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # NOTE: Requires the 'regexp' sqlite3 extension from https://github.com/nalgeon/sqlean
4
+ #
5
+ # Downloads from https://github.com/nalgeon/sqlean/releases/latest
6
+ #
7
+ # For example, on Apple Silicon with macOS with an M1 you can use:
8
+ #
9
+ # wget https://github.com/nalgeon/sqlean/releases/download/0.19.3/sqlean-macos-arm64.zip
10
+ # unzip sqlean-macos-arm64.zip regexp.dylib
11
+
12
+ VERSION="0.9.7"
13
+
14
+ STDOUT.sync = true
15
+
16
+ require "extralite"
17
+ require "optparse"
18
+
19
+ trap("INT" ) { abort "\n" }
20
+
21
+ dbas = nil
22
+ tabl = nil
23
+
24
+ OptionParser.new.instance_eval do
25
+ @banner = "usage: #{program_name} [options] <database> <table>"
26
+
27
+ on "-a", "--alpha" , "Sort alphabetically, not numerically"
28
+ on "-c", "--columns" , "Display column names and quit"
29
+ on "-h", "--help" , "Show help and command usage" do Kernel.abort to_s; end
30
+ on "-r", "--regexp <path>" , "Path to the sqlean/regexp extension"
31
+ on "-s", "--show <count>" , "Show this many values", Integer
32
+ on "-v", "--version" , "Show version number" do Kernel.abort "#{program_name} #{VERSION}"; end
33
+ on "-w", "--where <cond>" , "Filter rows (eg - 'age=33,Name=/[BW]ill/i,color=\"\"'"
34
+ on "-x", "--extract <col1,col2,...>", "Comma separated list of columns to extract"
35
+
36
+ self
37
+ end.parse!(into: opts={}) rescue abort($!.message)
38
+
39
+ abcd = opts[:alpha]
40
+ filt = opts[:where] and filt = "where\n #{filt}"
41
+ regx = opts[:regexp] || Dir["{,sqlean}/regexp.{dll,dylib,so}"].first
42
+ show = opts[:show]
43
+ want = opts[:extract].to_s.downcase.split(",")
44
+
45
+ dbas ||= ARGV.shift or abort "no database given"
46
+ tabl ||= ARGV.shift or abort "no table given"
47
+
48
+ regx && File.exist?(regx) or abort "no regexp extension found#{regx ? " at '#{regx}'" : ''}"
49
+
50
+ # ==[ Helpers ]==
51
+
52
+ class Extralite::Database
53
+ def sql(...)
54
+ query_ary(...)
55
+ end
56
+
57
+ def sql!(stmt, *args, **, &)
58
+ puts "\n==[ SQL statement ]==\n\n", stmt.strip, ";"
59
+ sql(stmt, *args, **, &)
60
+ end
61
+ end
62
+
63
+ def display(name, data, show, uniq, tots)
64
+ seen = data.inject(0) {|seen, coun| seen += coun[0] }
65
+ rows = [data.size, seen].min
66
+ wide = tots.to_s.size
67
+ fill = " " * wide
68
+ line = "=" * name.size
69
+
70
+ puts "\n#{fill} #{name}\n#{fill} #{line}\n"
71
+ data.each {|cnt, val| puts "%*d %s" % [wide, cnt, val || "NULL"] }
72
+ puts "#{fill} -----\n"
73
+ puts "%*d shown (top %d)" % [wide, rows, rows] if show
74
+ puts "%*d total (all %d)" % [wide, tots, uniq]
75
+ end
76
+
77
+ # ==[ Let 'er rip! ]==
78
+
79
+ conn = Extralite::Database.new(dbas)
80
+ resu = conn.load_extension(regx) rescue abort("unable to load regexp extension '#{regx}'")
81
+ cols = conn.columns("select * from `#{tabl}` limit 0").map(&:to_s)
82
+ want = want.empty? ? cols : want & cols
83
+
84
+ if opts[:columns]
85
+ puts cols
86
+ exit
87
+ end
88
+
89
+ if want.empty?
90
+ abort "no columns are selected"
91
+ end
92
+
93
+ want.each do |name|
94
+ sort = abcd ? "" : "cnt desc,"
95
+ stmt = show ? "limit #{show}" : ""
96
+ data = conn.sql(<<~"" + stmt).to_a
97
+ select
98
+ count(*) as cnt,
99
+ `#{name}` as val
100
+ from
101
+ `#{tabl}`
102
+ #{filt}
103
+ group by
104
+ val
105
+ order by #{sort}
106
+ -iif(regexp_like(`#{name}`, '^[-+]?((0|([1-9]\\d*)(\\.\\d*)?)|((0|([1-9]\\d*))\\.\\d+))$'), `#{name}` + 0, null) desc,
107
+ -iif(regexp_like(`#{name}`, '^0\\d+$'), length(`#{name}`), null) desc,
108
+ -iif(regexp_like(`#{name}`, '^\\d'), length(regexp_substr(`#{name}`, '^\\d+')), null) desc,
109
+ `#{name}` is null, `#{name}`
110
+ collate nocase
111
+
112
+ uniq = conn.sql(<<~"").to_a[0][0]
113
+ select
114
+ count(distinct(ifnull(`#{name}`,0)))
115
+ from
116
+ `#{tabl}`
117
+ #{filt}
118
+
119
+ tots = conn.sql(<<~"").to_a[0][0]
120
+ select
121
+ count(ifnull(`#{name}`,0))
122
+ from
123
+ `#{tabl}`
124
+ #{filt}
125
+
126
+ display(name, data, show, uniq, tots)
127
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slyce
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.9.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Shreeve
@@ -28,6 +28,7 @@ description: Ruby utility to show data statistics for MySQL databases
28
28
  email: steve.shreeve@gmail.com
29
29
  executables:
30
30
  - slyce
31
+ - slyce3
31
32
  extensions: []
32
33
  extra_rdoc_files: []
33
34
  files:
@@ -35,6 +36,7 @@ files:
35
36
  - LICENSE
36
37
  - README.md
37
38
  - bin/slyce
39
+ - bin/slyce3
38
40
  - slyce.gemspec
39
41
  homepage: https://github.com/shreeve/slyce
40
42
  licenses: