hsql 0.3.8 → 0.4.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 +4 -4
- data/README.md +147 -36
- data/bin/hsql +1 -1
- data/examples/simple.sql +1 -1
- data/lib/hsql/file.rb +21 -20
- data/lib/hsql/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f0f814ecf9e392ba9fdaf7b9ca4189cf5d938ce
|
4
|
+
data.tar.gz: 03b44002a2c25d8ae9aad92662e942af90f30d4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f403e66309574a45a882bfb52150273a83d15ed2868b382bc89520943128459d7888b36f4fdfcbed03f8ca39be6adb6b1ff19845baf82035f2c7da388e7843b4
|
7
|
+
data.tar.gz: d789ce8019449d9b7cf20d61ee84cca6f4584dba60750074d1d9a1b288c6109e706b0e93c4eb2a4e9834a78b798078a0ad54685f95754632d82588c68b5f92f7
|
data/README.md
CHANGED
@@ -11,13 +11,13 @@ the program executing the SQL can use.
|
|
11
11
|
|
12
12
|
Rather than specifying variables and metadata for a set of database
|
13
13
|
queries in a `.rb`,`.py` or other programming language source file the queries
|
14
|
-
should be written
|
14
|
+
should be written into a .sql file directly.
|
15
15
|
|
16
16
|
```sql
|
17
17
|
# filename: daily_summary.sql
|
18
18
|
owner: jackdanger
|
19
19
|
schedule: hourly
|
20
|
-
|
20
|
+
environments:
|
21
21
|
production:
|
22
22
|
output_table: summaries
|
23
23
|
update_condition:
|
@@ -29,57 +29,168 @@ INSERT INTO {{{output_table}}} SELECT * FROM interesting_information;
|
|
29
29
|
UPDATE summaries_performed SET complete = 1 {{{update_condition}}};
|
30
30
|
```
|
31
31
|
|
32
|
-
The above is a
|
32
|
+
The above is a `.sql` file and any text editor will allow analysts to use
|
33
33
|
code completion and syntax highlighting for their queries.
|
34
34
|
|
35
35
|
The `data` hash in the YAML front matter lists a set of variables, by
|
36
36
|
environment, that can be interpolated into the SQL queries. To render
|
37
|
-
the queries an environment must be provided.
|
37
|
+
the queries an environment must be provided. The templating system used
|
38
|
+
for interpolating data is [Mustache](https://mustache.github.io/)
|
39
|
+
(though theoretically we could use any templating system).
|
38
40
|
|
41
|
+
### Rendering SQL on the command line
|
39
42
|
```bash
|
40
|
-
$ hsql daily_summary.sql development
|
43
|
+
$ hsql daily_summary.sql -env development
|
41
44
|
USE some_database;
|
42
45
|
INSERT INTO jackdanger_summaries SELECT * FROM interesting_information;
|
43
46
|
UPDATE summaries_performed SET complete = 1 WHERE 1 <> 1;
|
44
47
|
```
|
45
48
|
|
46
|
-
The `hsql` command-line utility
|
47
|
-
|
48
|
-
|
49
|
+
The `hsql` command-line utility outputs valid Postgres SQL with any
|
50
|
+
template variables filled in from the YAML data.
|
51
|
+
To access the metadata directly use the `--yaml` or `--json` flag
|
49
52
|
|
50
|
-
|
53
|
+
```bash
|
54
|
+
$ hsql daily_summary.sql -env development --json
|
55
|
+
{"owner":"jackdanger","schedule":"hourly","output_table":"jackdanger_summaries","update_condition":"WHERE 1 <> 1"}
|
56
|
+
$ hsql daily_summary.sql -env development --yaml
|
57
|
+
---
|
58
|
+
owner: jackdanger
|
59
|
+
schedule: hourly
|
60
|
+
output_table: jackdanger_summaries
|
61
|
+
update_condition: WHERE 1 <> 1
|
62
|
+
```
|
51
63
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
64
|
+
### Working with times and dates
|
65
|
+
By default when you run the `hsql` command it will set the template
|
66
|
+
variable `{{{ now }}}` to the current moment (as per the local
|
67
|
+
machine's clock). You can modify this by setting a `--timestamp`
|
68
|
+
command line flag to any Ruby-parseable time or date string and that
|
69
|
+
will be used to establish the value of `{{{ now }}}`.
|
70
|
+
|
71
|
+
To avoid having to do date math in SQL all of the following are also
|
72
|
+
available in every template, relative to the value of `{{{ now }}}`:
|
73
|
+
|
74
|
+
```
|
75
|
+
"now" => "'2015-10-06 12:34:55 -0700'",
|
76
|
+
"beginning_of_hour" => "'2015-10-06 12:00:00 -0700'",
|
77
|
+
"beginning_of_day" => "'2015-10-06 00:00:00 -0700'",
|
78
|
+
"beginning_of_week" => "'2015-10-05 00:00:00 -0700'",
|
79
|
+
"beginning_of_month" => "'2015-10-01 00:00:00 -0700'",
|
80
|
+
"beginning_of_quarter" => "'2015-10-01 00:00:00 -0700'",
|
81
|
+
"beginning_of_year" => "'2015-01-01 00:00:00 -0800'",
|
82
|
+
"end_of_hour" => "'2015-10-06 12:59:59 -0700'",
|
83
|
+
"end_of_day" => "'2015-10-06 23:59:59 -0700'",
|
84
|
+
"end_of_week" => "'2015-10-11 23:59:59 -0700'",
|
85
|
+
"end_of_month" => "'2015-10-31 23:59:59 -0700'",
|
86
|
+
"end_of_quarter" => "'2015-12-31 23:59:59 -0800'",
|
87
|
+
"end_of_year" => "'2015-12-31 23:59:59 -0800'",
|
88
|
+
"beginning_of_previous_hour" => "'2015-10-06 11:00:00 -0700'",
|
89
|
+
"end_of_previous_hour" => "'2015-10-06 11:59:59 -0700'",
|
90
|
+
"beginning_of_previous_day" => "'2015-10-05 00:00:00 -0700'",
|
91
|
+
"end_of_previous_day" => "'2015-10-05 23:59:59 -0700'",
|
92
|
+
"beginning_of_previous_week" => "'2015-09-28 00:00:00 -0700'",
|
93
|
+
"end_of_previous_week" => "'2015-10-04 23:59:59 -0700'",
|
94
|
+
"beginning_of_previous_month" => "'2015-09-01 00:00:00 -0700'",
|
95
|
+
"end_of_previous_month" => "'2015-09-30 23:59:59 -0700'",
|
96
|
+
"beginning_of_previous_quarter" => "'2015-07-01 00:00:00 -0700'",
|
97
|
+
"end_of_previous_quarter" => "'2015-09-30 23:59:59 -0700'",
|
98
|
+
"beginning_of_previous_year" => "'2014-01-01 00:00:00 -0800'",
|
99
|
+
"end_of_previous_year" => "'2014-12-31 23:59:59 -0800'"
|
60
100
|
```
|
61
101
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
to
|
66
|
-
|
102
|
+
### Programmatic Ruby API
|
103
|
+
|
104
|
+
If you'd like to manipulate the queries in some advanced way
|
105
|
+
(e.g. to modify the AST of a parsed query) you can use the gem as a
|
106
|
+
dependency.
|
67
107
|
|
68
108
|
```ruby
|
69
|
-
>>
|
70
|
-
>> file.
|
109
|
+
>> require 'hsql'
|
110
|
+
>> file = HSQL::File.parse_file('./simple.sql', 'development')
|
111
|
+
>> query = file.queries.first;
|
112
|
+
>> query.to_s
|
113
|
+
=> "INSERT INTO jackdanger_summaries SELECT count(*) FROM interesting_information"
|
114
|
+
>> query.ast
|
71
115
|
=> {
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
116
|
+
"INSERT INTO" => {
|
117
|
+
"relation" => {
|
118
|
+
"RANGEVAR" => {
|
119
|
+
"schemaname" => nil,
|
120
|
+
"relname" => "jackdanger_summaries",
|
121
|
+
"inhOpt" => 2,
|
122
|
+
"relpersistence" => "p",
|
123
|
+
"alias" => nil,
|
124
|
+
"location" => 13
|
125
|
+
}
|
126
|
+
},
|
127
|
+
"cols" => nil,
|
128
|
+
"selectStmt" => {
|
129
|
+
"SELECT" => {
|
130
|
+
"distinctClause" => nil,
|
131
|
+
"intoClause" => nil,
|
132
|
+
"targetList" => [
|
133
|
+
[0] {
|
134
|
+
"RESTARGET" => {
|
135
|
+
"name" => nil,
|
136
|
+
"indirection" => nil,
|
137
|
+
"val" => {
|
138
|
+
"FUNCCALL" => {
|
139
|
+
"funcname" => [
|
140
|
+
[0] "count"
|
141
|
+
],
|
142
|
+
"args" => nil,
|
143
|
+
"agg_order" => nil,
|
144
|
+
"agg_filter" => nil,
|
145
|
+
"agg_within_group" => false,
|
146
|
+
"agg_star" => true,
|
147
|
+
"agg_distinct" => false,
|
148
|
+
"func_variadic" => false,
|
149
|
+
"over" => nil,
|
150
|
+
"location" => 79
|
151
|
+
}
|
152
|
+
},
|
153
|
+
"location" => 79
|
154
|
+
}
|
155
|
+
}
|
156
|
+
],
|
157
|
+
"fromClause" => [
|
158
|
+
[0] {
|
159
|
+
"RANGEVAR" => {
|
160
|
+
"schemaname" => nil,
|
161
|
+
"relname" => "interesting_information",
|
162
|
+
"inhOpt" => 2,
|
163
|
+
"relpersistence" => "p",
|
164
|
+
"alias" => nil,
|
165
|
+
"location" => 95
|
166
|
+
}
|
167
|
+
}
|
168
|
+
],
|
169
|
+
"whereClause" => nil,
|
170
|
+
"groupClause" => nil,
|
171
|
+
"havingClause" => nil,
|
172
|
+
"windowClause" => nil,
|
173
|
+
"valuesLists" => nil,
|
174
|
+
"sortClause" => nil,
|
175
|
+
"limitOffset" => nil,
|
176
|
+
"limitCount" => nil,
|
177
|
+
"lockingClause" => nil,
|
178
|
+
"withClause" => nil,
|
179
|
+
"op" => 0,
|
180
|
+
"all" => false,
|
181
|
+
"larg" => nil,
|
182
|
+
"rarg" => nil
|
183
|
+
}
|
184
|
+
},
|
185
|
+
"returningList" => nil,
|
186
|
+
"withClause" => nil
|
187
|
+
}
|
84
188
|
}
|
189
|
+
>> query.ast['INSERT INTO']['relation']['RANGEVAR']['relname'] = 'othertable'
|
190
|
+
=> "othertable"
|
191
|
+
>> query.to_s
|
192
|
+
=> "INSERT INTO othertable SELECT count(*) FROM interesting_information"
|
85
193
|
```
|
194
|
+
|
195
|
+
Please don't hesitate to open a PR or issue for any reason. New
|
196
|
+
contributors and bug fixes are welcome. Forks of this project will be celebrated.
|
data/bin/hsql
CHANGED
data/examples/simple.sql
CHANGED
data/lib/hsql/file.rb
CHANGED
@@ -17,15 +17,15 @@ module HSQL
|
|
17
17
|
@verbose = options[:verbose]
|
18
18
|
end
|
19
19
|
|
20
|
-
# Given
|
21
|
-
# example) this will return a HSQL::File object providing access to
|
22
|
-
# of that file.
|
23
|
-
def self.
|
24
|
-
|
20
|
+
# Given a SQL file with YAML front matter (see README for an
|
21
|
+
# example) this will return a HSQL::File object providing access to
|
22
|
+
# the parts of that file.
|
23
|
+
def self.parse_file(filename, options)
|
24
|
+
parse(::File.read(filename), options)
|
25
25
|
end
|
26
26
|
|
27
|
-
def self.
|
28
|
-
|
27
|
+
def self.parse(source, options)
|
28
|
+
new(source, options).parse!
|
29
29
|
end
|
30
30
|
|
31
31
|
def to_yaml
|
@@ -37,7 +37,11 @@ module HSQL
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def metadata
|
40
|
-
@metadata ||=
|
40
|
+
@metadata ||= begin
|
41
|
+
hash = @front_matter ? ::YAML.load(@front_matter) : {}
|
42
|
+
environments = hash.delete('environments') || {}
|
43
|
+
hash.merge(environments[environment] || {})
|
44
|
+
end
|
41
45
|
end
|
42
46
|
|
43
47
|
def queries
|
@@ -46,12 +50,18 @@ module HSQL
|
|
46
50
|
|
47
51
|
def parse!
|
48
52
|
split!
|
49
|
-
|
53
|
+
interpolate_metadata!
|
50
54
|
self
|
51
55
|
end
|
52
56
|
|
53
57
|
private
|
54
58
|
|
59
|
+
# Insert the `environments:` data for the given environment into our
|
60
|
+
# SQL queries.
|
61
|
+
def template_data
|
62
|
+
@data ||= metadata.merge(Data.for_machines(timestamp))
|
63
|
+
end
|
64
|
+
|
55
65
|
def split!
|
56
66
|
@split ||= begin
|
57
67
|
top_half, divider, rest = string.partition(/^---$/)
|
@@ -65,17 +75,8 @@ module HSQL
|
|
65
75
|
end
|
66
76
|
end
|
67
77
|
|
68
|
-
def
|
69
|
-
@
|
70
|
-
hash = metadata['data'] || {}
|
71
|
-
hash = hash.merge(hash[environment] || {})
|
72
|
-
hash.merge(Data.for_machines(timestamp))
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def interpolate_data!
|
77
|
-
# Insert the `data:` section of YAML for the given environment into our SQL queries.
|
78
|
-
@rendered_sql = Template.new(@sql, @verbose).render(data)
|
78
|
+
def interpolate_metadata!
|
79
|
+
@rendered_sql = Template.new(@sql, @verbose).render(template_data)
|
79
80
|
end
|
80
81
|
end
|
81
82
|
end
|
data/lib/hsql/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hsql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jack Danger Canty
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mustache
|