rack-queries 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.babelrc +2 -1
- data/.github/workflows/main.yml +47 -0
- data/.mergify.yml +11 -0
- data/.rubocop.yml +20 -2
- data/CHANGELOG.md +12 -1
- data/Gemfile.lock +25 -23
- data/README.md +22 -1
- data/bin/example +19 -1
- data/lib/rack/queries/app.rb +4 -2
- data/lib/rack/queries/cache.rb +57 -22
- data/lib/rack/queries/static/app.css +9 -4
- data/lib/rack/queries/static/app.js +8 -8
- data/lib/rack/queries/version.rb +1 -1
- data/package.json +25 -13
- data/rack-queries.gemspec +3 -3
- data/tsconfig.json +14 -0
- data/webpack.config.babel.js +17 -0
- data/yarn.lock +3246 -2948
- metadata +25 -23
- data/.travis.yml +0 -18
- data/webpack.config.js +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd2c4945a82772005af76b00f2c441471d2a4812b3956e7a5067feca800bccfb
|
4
|
+
data.tar.gz: 21465b906c268333878acf0f316450f4059ae03d9bebc25f2ce4617bd0864087
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee6edba69e2e20b7f1ae999e949c500c3bfd911aca0e7b5368081858843a73baea086551280dd25d1b4acfc1461263f5d3f2b38de218ddd0db646dd853908974
|
7
|
+
data.tar.gz: ccf5d3b63d88e31b4537bf1e2b4caf8205080bba51d2cd9bd079d24b2bfca2ce4cc6fe62fc2246ac02df4f5a56ccd18c2eb34b7b50c35a5660dd369803aef5a3
|
data/.babelrc
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
name: Main
|
2
|
+
on: push
|
3
|
+
jobs:
|
4
|
+
ci-ruby:
|
5
|
+
name: CI Ruby
|
6
|
+
runs-on: ubuntu-latest
|
7
|
+
steps:
|
8
|
+
- run: sudo apt-get update
|
9
|
+
- run: sudo apt-get install libsqlite3-dev
|
10
|
+
- uses: actions/checkout@master
|
11
|
+
- uses: ruby/setup-ruby@v1
|
12
|
+
with:
|
13
|
+
ruby-version: 2.7
|
14
|
+
- uses: actions/cache@v1
|
15
|
+
with:
|
16
|
+
path: vendor/bundle
|
17
|
+
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
|
18
|
+
restore-keys: |
|
19
|
+
${{ runner.os }}-gems-
|
20
|
+
- run: bundle config path vendor/bundle
|
21
|
+
- run: bundle install --jobs 4 --retry 3
|
22
|
+
- run: bundle exec bundle audit --update
|
23
|
+
- run: bundle exec rubocop --parallel
|
24
|
+
- run: bundle exec rake test
|
25
|
+
env:
|
26
|
+
CI: true
|
27
|
+
ci-ts:
|
28
|
+
name: CI TypeScript
|
29
|
+
runs-on: ubuntu-latest
|
30
|
+
steps:
|
31
|
+
- uses: actions/checkout@master
|
32
|
+
- uses: actions/setup-node@v1
|
33
|
+
with:
|
34
|
+
node-version: 11.x
|
35
|
+
- id: yarn-cache
|
36
|
+
run: echo "::set-output name=directory::$(yarn cache dir)"
|
37
|
+
- uses: actions/cache@v1
|
38
|
+
with:
|
39
|
+
path: ${{ steps.yarn-cache.outputs.directory }}
|
40
|
+
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
41
|
+
restore-keys: |
|
42
|
+
${{ runner.os }}-yarn-
|
43
|
+
- run: yarn install --frozen-lockfile
|
44
|
+
- run: yarn lint
|
45
|
+
- run: yarn test
|
46
|
+
env:
|
47
|
+
CI: true
|
data/.mergify.yml
ADDED
data/.rubocop.yml
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require: rubocop-performance
|
2
|
-
|
3
1
|
AllCops:
|
4
2
|
DisplayCopNames: true
|
5
3
|
DisplayStyleGuide: true
|
@@ -13,3 +11,23 @@ Style/Documentation:
|
|
13
11
|
|
14
12
|
Style/PerlBackrefs:
|
15
13
|
Enabled: false
|
14
|
+
|
15
|
+
Style/StructInheritance:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
##############################
|
19
|
+
|
20
|
+
Lint/RaiseException:
|
21
|
+
Enabled: true
|
22
|
+
|
23
|
+
Lint/StructNewOverride:
|
24
|
+
Enabled: true
|
25
|
+
|
26
|
+
Style/HashEachMethods:
|
27
|
+
Enabled: true
|
28
|
+
|
29
|
+
Style/HashTransformKeys:
|
30
|
+
Enabled: true
|
31
|
+
|
32
|
+
Style/HashTransformValues:
|
33
|
+
Enabled: true
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [0.3.0] - 2020-04-13
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- The ability to specify client-side provided options of type `string` and type `text`.
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
|
17
|
+
- Switch the frontend over to TypeScript.
|
18
|
+
|
9
19
|
## [0.2.1] - 2019-08-09
|
10
20
|
|
11
21
|
### Changed
|
@@ -48,7 +58,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
48
58
|
|
49
59
|
- Initial release 🎉
|
50
60
|
|
51
|
-
[unreleased]: https://github.com/CultureHQ/rack-queries/compare/v0.
|
61
|
+
[unreleased]: https://github.com/CultureHQ/rack-queries/compare/v0.3.0...HEAD
|
62
|
+
[0.3.0]: https://github.com/CultureHQ/rack-queries/compare/v0.2.1...v0.3.0
|
52
63
|
[0.2.1]: https://github.com/CultureHQ/rack-queries/compare/v0.2.0...v0.2.1
|
53
64
|
[0.2.0]: https://github.com/CultureHQ/rack-queries/compare/v0.1.3...v0.2.0
|
54
65
|
[0.1.3]: https://github.com/CultureHQ/rack-queries/compare/v0.1.2...v0.1.3
|
data/Gemfile.lock
CHANGED
@@ -1,56 +1,58 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rack-queries (0.
|
4
|
+
rack-queries (0.3.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
ast (2.4.0)
|
10
|
+
bundler-audit (0.6.1)
|
11
|
+
bundler (>= 1.2.0, < 3)
|
12
|
+
thor (~> 0.18)
|
10
13
|
docile (1.3.2)
|
11
|
-
jaro_winkler (1.5.
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
parser (2.6.3.0)
|
14
|
+
jaro_winkler (1.5.4)
|
15
|
+
minitest (5.14.0)
|
16
|
+
parallel (1.19.1)
|
17
|
+
parser (2.7.0.5)
|
16
18
|
ast (~> 2.4.0)
|
17
|
-
rack (2.
|
19
|
+
rack (2.2.2)
|
18
20
|
rack-test (1.1.0)
|
19
21
|
rack (>= 1.0, < 3)
|
20
22
|
rainbow (3.0.0)
|
21
|
-
rake (
|
22
|
-
|
23
|
+
rake (13.0.1)
|
24
|
+
rexml (3.2.4)
|
25
|
+
rubocop (0.81.0)
|
23
26
|
jaro_winkler (~> 1.5.1)
|
24
27
|
parallel (~> 1.10)
|
25
|
-
parser (>= 2.
|
28
|
+
parser (>= 2.7.0.1)
|
26
29
|
rainbow (>= 2.2.2, < 4.0)
|
30
|
+
rexml
|
27
31
|
ruby-progressbar (~> 1.7)
|
28
|
-
unicode-display_width (>= 1.4.0, <
|
29
|
-
rubocop-performance (1.4.1)
|
30
|
-
rubocop (>= 0.71.0)
|
32
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
31
33
|
ruby-progressbar (1.10.1)
|
32
|
-
simplecov (0.
|
34
|
+
simplecov (0.18.5)
|
33
35
|
docile (~> 1.1)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
unicode-display_width (1.
|
36
|
+
simplecov-html (~> 0.11)
|
37
|
+
simplecov-html (0.12.1)
|
38
|
+
sqlite3 (1.4.2)
|
39
|
+
thor (0.20.3)
|
40
|
+
unicode-display_width (1.7.0)
|
39
41
|
|
40
42
|
PLATFORMS
|
41
43
|
ruby
|
42
44
|
|
43
45
|
DEPENDENCIES
|
44
46
|
bundler (~> 2.0)
|
47
|
+
bundler-audit (~> 0.6)
|
45
48
|
minitest (~> 5.0)
|
46
49
|
rack (~> 2.0)
|
47
50
|
rack-queries!
|
48
51
|
rack-test (~> 1.1)
|
49
|
-
rake (~>
|
50
|
-
rubocop (~> 0.
|
51
|
-
rubocop-performance (~> 1.3)
|
52
|
+
rake (~> 13.0)
|
53
|
+
rubocop (~> 0.78)
|
52
54
|
simplecov (~> 0.16)
|
53
55
|
sqlite3 (~> 1.4)
|
54
56
|
|
55
57
|
BUNDLED WITH
|
56
|
-
2.
|
58
|
+
2.1.4
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Rack::Queries
|
2
2
|
|
3
|
-
[![Build Status](https://
|
3
|
+
[![Build Status](https://github.com/CultureHQ/rack-queries/workflows/Main/badge.svg)](https://github.com/CultureHQ/rack-queries/actions)
|
4
4
|
[![Gem Version](https://img.shields.io/gem/v/rack-queries.svg)](https://github.com/CultureHQ/rack-queries)
|
5
5
|
|
6
6
|
This gem provides a page in your rack-based (e.g., `Rails`, `Sinatra`) application that allows quick execution of pre-built queries. The goal is to allow quick insights into the state of your application without needing to update the main UI. Consider it a backdoor admin page that you can use before you decide to truly expose query results.
|
@@ -79,6 +79,27 @@ Rack::Queries.create do
|
|
79
79
|
end
|
80
80
|
```
|
81
81
|
|
82
|
+
With the DSL, you can additionally provide a `type` for your options that allows them to be specified on the client side. By default, the type is `select`, which will perform a query to the server to get the list of options. However, if you specify one of the other types (`string` or `text`), it will instead allow the user to provide input. For example, to allow a text area field, you would:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
Rack::Queries.create do
|
86
|
+
name 'Some CSV parsing'
|
87
|
+
desc 'Parse some CSV input!'
|
88
|
+
|
89
|
+
opt :csv, type: :text
|
90
|
+
|
91
|
+
run do |opts|
|
92
|
+
require 'csv'
|
93
|
+
|
94
|
+
CSV.foreach(opts['csv']) do
|
95
|
+
...
|
96
|
+
end
|
97
|
+
|
98
|
+
...
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
82
103
|
### Middleware
|
83
104
|
|
84
105
|
Since `Rack::Queries` is a rack application, you can add whatever middleware you like into its stack before the request hits the application. For instance, to integrate HTTP basic auth around it to protect the query results, you can use the `Rack::Queries::App::use` method as in:
|
data/bin/example
CHANGED
@@ -44,7 +44,7 @@ class Database
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def rows_from(query, binds = [])
|
47
|
-
execute(query, binds)
|
47
|
+
execute(query, binds).to_a
|
48
48
|
end
|
49
49
|
|
50
50
|
class << self
|
@@ -124,6 +124,24 @@ module Rack
|
|
124
124
|
Database.value_from(query, opts)
|
125
125
|
end
|
126
126
|
end
|
127
|
+
|
128
|
+
create do
|
129
|
+
name 'Name search'
|
130
|
+
desc 'Search for a user by name'
|
131
|
+
|
132
|
+
opt(:org_name) { Database.values_from('SELECT name FROM orgs') }
|
133
|
+
opt(:user_name, type: :text)
|
134
|
+
|
135
|
+
run do |opts|
|
136
|
+
query = <<~SQL
|
137
|
+
SELECT id, org_id, active, name FROM users
|
138
|
+
WHERE org_id = (SELECT id FROM orgs WHERE name = :org_name)
|
139
|
+
AND name LIKE :user_name || '%'
|
140
|
+
SQL
|
141
|
+
|
142
|
+
[%w[id org_id active name]] + Database.rows_from(query, opts)
|
143
|
+
end
|
144
|
+
end
|
127
145
|
end
|
128
146
|
end
|
129
147
|
|
data/lib/rack/queries/app.rb
CHANGED
@@ -7,7 +7,8 @@ module Rack
|
|
7
7
|
# Thought about refactoring this to split it out into multiple objects,
|
8
8
|
# but then thought better of it. If we end up adding more API endpoints
|
9
9
|
# then we can do something smart about it, but for now it's fine.
|
10
|
-
# rubocop:disable AbcSize, CyclomaticComplexity
|
10
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
11
|
+
# rubocop:disable Metrics/MethodLength
|
11
12
|
def call(env)
|
12
13
|
return not_found unless env[REQUEST_METHOD]
|
13
14
|
|
@@ -27,7 +28,8 @@ module Rack
|
|
27
28
|
not_found
|
28
29
|
end
|
29
30
|
end
|
30
|
-
# rubocop:enable AbcSize, CyclomaticComplexity
|
31
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
32
|
+
# rubocop:enable Metrics/MethodLength
|
31
33
|
|
32
34
|
private
|
33
35
|
|
data/lib/rack/queries/cache.rb
CHANGED
@@ -3,29 +3,56 @@
|
|
3
3
|
module Rack
|
4
4
|
module Queries
|
5
5
|
class Cache
|
6
|
+
class Option < Struct.new(:name, :type)
|
7
|
+
def as_json
|
8
|
+
{ name: name, type: type }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class SelectOption < Struct.new(:name)
|
13
|
+
def as_json
|
14
|
+
{ name: name, type: 'select' }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
6
18
|
class CreateQuery
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
19
|
+
class << self
|
20
|
+
def name(name = :get)
|
21
|
+
if name == :get
|
22
|
+
@name
|
23
|
+
else
|
24
|
+
@name = name
|
25
|
+
end
|
12
26
|
end
|
13
|
-
end
|
14
27
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
28
|
+
def desc(desc = :get)
|
29
|
+
if desc == :get
|
30
|
+
@desc
|
31
|
+
else
|
32
|
+
@desc = desc
|
33
|
+
end
|
20
34
|
end
|
21
|
-
end
|
22
35
|
|
23
|
-
|
24
|
-
|
25
|
-
|
36
|
+
def opts
|
37
|
+
@opts ||= {}
|
38
|
+
end
|
26
39
|
|
27
|
-
|
28
|
-
|
40
|
+
def opt(name, type: :select, &block)
|
41
|
+
if type != :select && block
|
42
|
+
raise ArgumentError, 'Can only specify a block if it is a select'
|
43
|
+
end
|
44
|
+
|
45
|
+
if type == :select
|
46
|
+
define_method(name, &block)
|
47
|
+
opts[name.to_s] = SelectOption.new(name)
|
48
|
+
else
|
49
|
+
opts[name.to_s] = Option.new(name, type)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def run(&block)
|
54
|
+
define_method(:run, &block)
|
55
|
+
end
|
29
56
|
end
|
30
57
|
end
|
31
58
|
|
@@ -36,6 +63,16 @@ module Rack
|
|
36
63
|
end
|
37
64
|
|
38
65
|
def add(*queries)
|
66
|
+
queries.each do |query|
|
67
|
+
opts = {}
|
68
|
+
|
69
|
+
(query.public_instance_methods(false) - %i[run]).each do |name|
|
70
|
+
opts[name] = SelectOption.new(name)
|
71
|
+
end
|
72
|
+
|
73
|
+
query.define_singleton_method(:opts) { opts }
|
74
|
+
end
|
75
|
+
|
39
76
|
@cache = (cache + queries).sort_by(&:name)
|
40
77
|
end
|
41
78
|
|
@@ -46,16 +83,14 @@ module Rack
|
|
46
83
|
|
47
84
|
def opts_for(name, opt)
|
48
85
|
query = query_for(name)
|
49
|
-
|
50
|
-
|
51
|
-
instance = query.new
|
52
|
-
instance.public_send(opt) if instance.respond_to?(opt)
|
86
|
+
query.new.public_send(opt) if query
|
53
87
|
end
|
54
88
|
|
55
89
|
def queries
|
56
90
|
cache.map do |query|
|
57
91
|
desc = query.respond_to?(:desc) ? query.desc : ''
|
58
|
-
opts =
|
92
|
+
opts =
|
93
|
+
query.respond_to?(:opts) ? query.opts.values.map(&:as_json) : []
|
59
94
|
|
60
95
|
{ name: query.name, desc: desc, opts: opts }
|
61
96
|
end
|
@@ -75,16 +75,16 @@ nav {
|
|
75
75
|
z-index: 1
|
76
76
|
}
|
77
77
|
|
78
|
-
.query-
|
78
|
+
.query[aria-current='true'] {
|
79
79
|
background-color: #8b3333;
|
80
80
|
color: #fff;
|
81
81
|
}
|
82
82
|
|
83
|
-
.query-
|
83
|
+
.query[aria-current='true'] p {
|
84
84
|
color: #fff;
|
85
85
|
}
|
86
86
|
|
87
|
-
.query-
|
87
|
+
.query[aria-current='true']:before {
|
88
88
|
border-bottom: 12px solid transparent;
|
89
89
|
border-right: 12px solid #8b3333;
|
90
90
|
border-top: 12px solid transparent;
|
@@ -93,7 +93,7 @@ nav {
|
|
93
93
|
position: absolute;
|
94
94
|
}
|
95
95
|
|
96
|
-
.query-
|
96
|
+
.query[aria-current='true']:hover {
|
97
97
|
background-color: #8b3333;
|
98
98
|
}
|
99
99
|
|
@@ -108,6 +108,11 @@ nav {
|
|
108
108
|
vertical-align: middle;
|
109
109
|
}
|
110
110
|
|
111
|
+
.opt textarea {
|
112
|
+
height: 20em;
|
113
|
+
width: 50em;
|
114
|
+
}
|
115
|
+
|
111
116
|
.run {
|
112
117
|
border-radius: 4px;
|
113
118
|
background: #8b3333;
|