slyce 0.9.2 → 0.9.7

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.
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: