sqltorial 0.0.4 → 0.0.5
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 +4 -4
- data/CHANGELOG.md +41 -0
- data/exe/sqltorial +2 -0
- data/lib/sqltorial/assemble_command.rb +8 -2
- data/lib/sqltorial/directives/valid_column_directive.rb +9 -2
- data/lib/sqltorial/metadata.rb +1 -1
- data/lib/sqltorial/query_cache.rb +1 -1
- data/lib/sqltorial/query_to_md.rb +12 -8
- data/lib/sqltorial/sql_to_example.rb +31 -15
- data/sqltorial.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3ca9d5ba9e65f3a01f00225e743efd0a4be9060
|
4
|
+
data.tar.gz: 4e7f40a198a35b4c14d4a71bb1273b5485680eff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bbee4c513b93704a42818553114c40b82fd28945954bf1aa8122c3e626a77de7837cfff17678e62e1f2116298ba04434a124c7523b36933c78ebb0b2827bdf14
|
7
|
+
data.tar.gz: ff37c16257fd820609d68567bb3b80288be467c5551b1b982f8d136a0c2635b8364b7e7c2906cbcc71327ef6fd74aa2c433690b11cc25b98a7a09289cc4c231d
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,47 @@ All notable changes to this project will be documented in this file.
|
|
6
6
|
|
7
7
|
### Added
|
8
8
|
|
9
|
+
- Nothing.
|
10
|
+
|
11
|
+
### Deprecated
|
12
|
+
|
13
|
+
- Nothing.
|
14
|
+
|
15
|
+
### Removed
|
16
|
+
|
17
|
+
- Nothing.
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
|
21
|
+
- Nothing.
|
22
|
+
|
23
|
+
## 0.0.5
|
24
|
+
|
25
|
+
### Added
|
26
|
+
|
27
|
+
- More commas for more types of number columns.
|
28
|
+
- Support for several Impala-oriented commands.
|
29
|
+
- --ignore-cache option
|
30
|
+
- --drop-tables option
|
31
|
+
|
32
|
+
### Deprecated
|
33
|
+
|
34
|
+
- Nothing.
|
35
|
+
|
36
|
+
### Removed
|
37
|
+
|
38
|
+
- Nothing.
|
39
|
+
|
40
|
+
### Fixed
|
41
|
+
|
42
|
+
- ID columns shouldn't end up with commas
|
43
|
+
- Markdown lists should render properly
|
44
|
+
- Handle NULL values in columns
|
45
|
+
|
46
|
+
## 0.0.4
|
47
|
+
|
48
|
+
### Added
|
49
|
+
|
9
50
|
- Watch mode.
|
10
51
|
|
11
52
|
### Deprecated
|
data/exe/sqltorial
CHANGED
@@ -11,6 +11,8 @@ Escort::App.create do |app|
|
|
11
11
|
|
12
12
|
app.options do |opts|
|
13
13
|
opts.opt :no_results, "Don't Include Results", short: '-n', long: '--no-results', type: :boolean, default: false
|
14
|
+
opts.opt :drop_it, "Drop tables before create", short: '-D', long: '--drop-tables', type: :boolean, default: false
|
15
|
+
opts.opt :ignore_cache, "Ignore cache", short: '-C', long: '--ignore-cache', type: :boolean, default: false
|
14
16
|
opts.opt :output, "Output File", short: '-o', long: '--output', type: :string, default: 'output.md'
|
15
17
|
opts.opt :preface, "Preface File", short: '-p', long: '--preface', type: :string, default: 'preface.md'
|
16
18
|
opts.opt :watch, "Watch Mode", short: '-w', long: '--watch', type: :boolean, default: false
|
@@ -2,6 +2,7 @@ require_relative 'sql_to_example'
|
|
2
2
|
require 'sequelizer'
|
3
3
|
require 'facets/pathname/chdir'
|
4
4
|
require 'listen'
|
5
|
+
require "fileutils"
|
5
6
|
|
6
7
|
module SQLtorial
|
7
8
|
class AssembleCommand < ::Escort::ActionCommand::Base
|
@@ -11,7 +12,7 @@ module SQLtorial
|
|
11
12
|
end
|
12
13
|
|
13
14
|
def watch
|
14
|
-
listener = Listen.to(
|
15
|
+
listener = Listen.to(dir) do |modified, added, removed|
|
15
16
|
process
|
16
17
|
end
|
17
18
|
listener.only(/\.sql$/)
|
@@ -20,13 +21,14 @@ module SQLtorial
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def process
|
24
|
+
FileUtils.rm_rf(".sqltorial_cache") if global_options[:ignore_cache]
|
23
25
|
process_dir.chdir do
|
24
26
|
preface = Pathname.new(global_options[:preface]) if global_options[:preface]
|
25
27
|
File.open(global_options[:output], 'w') do |f|
|
26
28
|
f.puts preface.read if preface && preface.exist?
|
27
29
|
examples = files.map.with_index do |file, index|
|
28
30
|
Escort::Logger.output.puts "Examplizing #{file.to_s}"
|
29
|
-
SqlToExample.new(file, db, index + 1).to_str(
|
31
|
+
SqlToExample.new(file, db, index + 1).to_str(global_options)
|
30
32
|
end
|
31
33
|
f.puts(examples.join("\n\n"))
|
32
34
|
end
|
@@ -37,6 +39,10 @@ module SQLtorial
|
|
37
39
|
@process_dir = path.directory? ? path : Pathname.pwd
|
38
40
|
end
|
39
41
|
|
42
|
+
def dir
|
43
|
+
@dir ||= path.directory? ? path : path.dirname
|
44
|
+
end
|
45
|
+
|
40
46
|
def path
|
41
47
|
@path ||= Pathname.new(arguments.first || ".")
|
42
48
|
end
|
@@ -1,6 +1,13 @@
|
|
1
1
|
module SQLtorial
|
2
2
|
class ValidColumnDirective
|
3
|
-
REGEXP =
|
3
|
+
REGEXP = /^\s*DIRECTIVE:\s*(\S+)\s+(\S+)\s+(.+)/
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def regexp
|
7
|
+
REGEXP
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
4
11
|
attr :column, :op, :matcher
|
5
12
|
def initialize(line)
|
6
13
|
_, column, op, matcher = REGEXP.match(line).to_a
|
@@ -18,5 +25,5 @@ module SQLtorial
|
|
18
25
|
[column, op, matcher].join(" ")
|
19
26
|
end
|
20
27
|
end
|
21
|
-
Directive.register(
|
28
|
+
Directive.register(ValidColumnDirective)
|
22
29
|
end
|
data/lib/sqltorial/metadata.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module SQLtorial
|
2
|
-
VERSION = "0.0.
|
2
|
+
VERSION = "0.0.5"
|
3
3
|
SUMMARY = %q{Knitr, but for SQL files, sorta}
|
4
4
|
DESCRIPTION = %q{Ingests a set of commented SQL statements, executes them, and dumps the comments, queries, and results into a markdown file}
|
5
5
|
HOMEPAGE = "http://github.com/outcomesinsights/sqltorial"
|
@@ -24,9 +24,9 @@ module SQLtorial
|
|
24
24
|
def get_md
|
25
25
|
return "**No results found.**" if all.empty?
|
26
26
|
output = []
|
27
|
-
output << "Found #{count} results."
|
27
|
+
output << "Found #{commatize(count)} results."
|
28
28
|
if count > row_limit
|
29
|
-
output.last << " Displaying first #{row_limit}."
|
29
|
+
output.last << " Displaying first #{commatize(row_limit)}."
|
30
30
|
end
|
31
31
|
output << ""
|
32
32
|
output << tableize(all.first.keys + additional_headers)
|
@@ -84,7 +84,7 @@ module SQLtorial
|
|
84
84
|
|
85
85
|
def make_processors
|
86
86
|
output_rows.first.map do |name, column|
|
87
|
-
if name.to_s
|
87
|
+
if name.to_s =~ /_?id(_|$)/
|
88
88
|
Proc.new do |column|
|
89
89
|
column.to_s.chomp
|
90
90
|
end
|
@@ -92,11 +92,11 @@ module SQLtorial
|
|
92
92
|
case column
|
93
93
|
when Float, BigDecimal
|
94
94
|
Proc.new do |column|
|
95
|
-
sprintf("%.02f", column)
|
95
|
+
column ? commatize(sprintf("%.02f", column)) : nil
|
96
96
|
end
|
97
97
|
when Numeric, Fixnum
|
98
98
|
Proc.new do |column|
|
99
|
-
commatize(column.to_s)
|
99
|
+
column ? commatize(column.to_s) : nil
|
100
100
|
end
|
101
101
|
else
|
102
102
|
Proc.new do |column|
|
@@ -130,9 +130,13 @@ module SQLtorial
|
|
130
130
|
widths.map { |width| '-' * width }
|
131
131
|
end
|
132
132
|
|
133
|
-
def commatize(
|
134
|
-
|
135
|
-
str.
|
133
|
+
def commatize(input)
|
134
|
+
str = input.to_s
|
135
|
+
return str unless str =~ /^[\d.]+$/
|
136
|
+
str, dec = str.split('.')
|
137
|
+
commaed = str.reverse.chars.each_slice(3).map(&:join).join(',').reverse
|
138
|
+
commaed << ".#{dec}" if dec and !dec.empty?
|
139
|
+
commaed
|
136
140
|
end
|
137
141
|
|
138
142
|
def cache
|
@@ -48,29 +48,29 @@ module SQLtorial
|
|
48
48
|
lines.shift while lines.first.strip.empty?
|
49
49
|
prose_lines << lines.shift.sub(WHITESPACE_REGEX, ' ').sub(/^\s*$/, "\n\n") while lines.first && (lines.first =~ WHITESPACE_REGEX || lines.first.empty?)
|
50
50
|
directives, prose_lines = prose_lines.partition { |line| Directive.match(line) }
|
51
|
-
[prose_lines.join(
|
51
|
+
[prose_lines.map(&:strip).join("\n"), process_directives(directives), lines.join("\n")]
|
52
52
|
end
|
53
53
|
|
54
54
|
def number
|
55
55
|
@number ||= file.basename.to_s.to_i
|
56
56
|
end
|
57
57
|
|
58
|
-
def to_str(
|
58
|
+
def to_str(options = {})
|
59
|
+
options = options.merge(include_results: true)
|
59
60
|
hash = {}
|
60
61
|
queries.each_with_index do |query, index|
|
61
62
|
prose, directives, sql = make_prose_directives_and_query(query)
|
62
63
|
|
63
64
|
begin
|
64
65
|
if is_create(sql)
|
65
|
-
|
66
|
-
hash[sql] = [prose, create_to_md(include_results, sql, directives)];
|
66
|
+
hash[sql] = [prose, create_to_md(options, sql, directives)];
|
67
67
|
next
|
68
|
-
elsif
|
69
|
-
execute(sql,
|
68
|
+
elsif is_passthru(sql)
|
69
|
+
execute(sql, options)
|
70
70
|
hash[sql] = [prose, nil];
|
71
71
|
next
|
72
72
|
end
|
73
|
-
hash[sql] = [prose, query_to_md(
|
73
|
+
hash[sql] = [prose, query_to_md(options, sql, directives)]
|
74
74
|
rescue
|
75
75
|
puts sql
|
76
76
|
puts $!.message
|
@@ -90,7 +90,7 @@ module SQLtorial
|
|
90
90
|
arr << value.last
|
91
91
|
arr.join("\n\n")
|
92
92
|
end
|
93
|
-
parts.join("\n") + "\n\n"
|
93
|
+
parts.join("\n\n") + "\n\n"
|
94
94
|
end
|
95
95
|
|
96
96
|
private
|
@@ -114,18 +114,34 @@ module SQLtorial
|
|
114
114
|
sql =~ /^\s*drop/i
|
115
115
|
end
|
116
116
|
|
117
|
-
def
|
118
|
-
|
117
|
+
def is_use(sql)
|
118
|
+
sql =~ /^\s*use/i
|
119
119
|
end
|
120
120
|
|
121
|
-
def
|
122
|
-
|
123
|
-
|
121
|
+
def is_compute(sql)
|
122
|
+
sql =~ /^\s*compute\s*stats/i
|
123
|
+
end
|
124
|
+
|
125
|
+
def is_passthru(sql)
|
126
|
+
is_drop(sql) || is_use(sql) || is_compute(sql)
|
127
|
+
end
|
128
|
+
|
129
|
+
def execute(sql, options)
|
130
|
+
db.execute(sql) if options[:include_results]
|
131
|
+
end
|
132
|
+
|
133
|
+
def create_to_md(options, sql, directives)
|
134
|
+
return nil unless options[:include_results]
|
135
|
+
table_name = /create\s*(?:temp)?\s*(?:table|view)(?:\s*if\s*not\s*exists)?\s*(\S+)/i.match(sql)[1]
|
136
|
+
execute("DROP TABLE IF EXISTS #{table_name}", options) if options[:drop_it]
|
137
|
+
execute(sql, options)
|
138
|
+
execute("COMPUTE STATS #{table_name}", options)
|
139
|
+
table_name.gsub!('.', '__')
|
124
140
|
QueryToMD.new(db[table_name.to_sym], directives).to_md
|
125
141
|
end
|
126
142
|
|
127
|
-
def query_to_md(
|
128
|
-
return nil unless include_results
|
143
|
+
def query_to_md(options, sql, directives)
|
144
|
+
return nil unless options[:include_results]
|
129
145
|
return nil if sql.empty?
|
130
146
|
QueryToMD.new(db[sql.sub(';', '')], directives).to_md
|
131
147
|
end
|
data/sqltorial.gemspec
CHANGED
@@ -33,5 +33,5 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_dependency "anbt-sql-formatter", "~> 0.0.3"
|
34
34
|
spec.add_dependency "facets", "~> 3.0"
|
35
35
|
spec.add_dependency "escort", "~> 0.4.0"
|
36
|
-
spec.add_dependency "listen", "~> 3.0
|
36
|
+
spec.add_dependency "listen", "~> 3.0"
|
37
37
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqltorial
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Duryea
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 3.0
|
103
|
+
version: '3.0'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 3.0
|
110
|
+
version: '3.0'
|
111
111
|
description: Ingests a set of commented SQL statements, executes them, and dumps the
|
112
112
|
comments, queries, and results into a markdown file
|
113
113
|
email:
|