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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7278f7eac12f1013fe34eb2b1e84e75b7114d71d0f646c275a374c6615e56a82
4
- data.tar.gz: a3c052ba9ced08c46d895b1197a63cfc65132df7e5f8ac6f64b5a16c3c0fa64b
3
+ metadata.gz: fd2c4945a82772005af76b00f2c441471d2a4812b3956e7a5067feca800bccfb
4
+ data.tar.gz: 21465b906c268333878acf0f316450f4059ae03d9bebc25f2ce4617bd0864087
5
5
  SHA512:
6
- metadata.gz: 36ef6a95c554444c3e7d18e2027da7050b3e58390b9a3a707461d17abbdbe480195f8594eb49c71d1c1ad8b5ce51d6f6f54911480a94acb0971227c12f26ad3e
7
- data.tar.gz: 87bcb39c6ab1e19e1ff38342a42ddb0d48311d922bee2439de15ab9b95af5f58e1a90ad7472d97f4b85c2fd1cbabbd4e417c07f17d74e0059e2f250c19f198e0
6
+ metadata.gz: ee6edba69e2e20b7f1ae999e949c500c3bfd911aca0e7b5368081858843a73baea086551280dd25d1b4acfc1461263f5d3f2b38de218ddd0db646dd853908974
7
+ data.tar.gz: ccf5d3b63d88e31b4537bf1e2b4caf8205080bba51d2cd9bd079d24b2bfca2ce4cc6fe62fc2246ac02df4f5a56ccd18c2eb34b7b50c35a5660dd369803aef5a3
data/.babelrc CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "presets": [
3
3
  "@babel/preset-env",
4
- "@babel/preset-react"
4
+ "@babel/preset-react",
5
+ "@babel/preset-typescript"
5
6
  ],
6
7
  "env": {
7
8
  "test": {
@@ -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
@@ -0,0 +1,11 @@
1
+ pull_request_rules:
2
+ - name: Automatically merge dependencies
3
+ conditions:
4
+ - base=master
5
+ - label=dependencies
6
+ - status-success=CI Ruby
7
+ - status-success=CI TypeScript
8
+ actions:
9
+ merge:
10
+ strict: true
11
+ delete_head_branch: {}
@@ -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
@@ -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.2.1...HEAD
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
@@ -1,56 +1,58 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rack-queries (0.2.1)
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.3)
12
- json (2.2.0)
13
- minitest (5.11.3)
14
- parallel (1.17.0)
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.0.7)
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 (12.3.3)
22
- rubocop (0.74.0)
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.6)
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, < 1.7)
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.17.0)
34
+ simplecov (0.18.5)
33
35
  docile (~> 1.1)
34
- json (>= 1.8, < 3)
35
- simplecov-html (~> 0.10.0)
36
- simplecov-html (0.10.2)
37
- sqlite3 (1.4.1)
38
- unicode-display_width (1.6.0)
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 (~> 12.0)
50
- rubocop (~> 0.72)
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.0.1
58
+ 2.1.4
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Rack::Queries
2
2
 
3
- [![Build Status](https://travis-ci.com/CultureHQ/rack-queries.svg?branch=master)](https://travis-ci.com/CultureHQ/rack-queries)
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:
@@ -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
 
@@ -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, MethodLength
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, MethodLength
31
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
32
+ # rubocop:enable Metrics/MethodLength
31
33
 
32
34
  private
33
35
 
@@ -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
- def self.name(name = :get)
8
- if name == :get
9
- @name
10
- else
11
- @name = name
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
- def self.desc(desc = :get)
16
- if desc == :get
17
- @desc
18
- else
19
- @desc = desc
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
- def self.opt(name, &block)
24
- define_method(name, &block)
25
- end
36
+ def opts
37
+ @opts ||= {}
38
+ end
26
39
 
27
- def self.run(&block)
28
- define_method(:run, &block)
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
- return unless query
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 = query.public_instance_methods(false) - %i[run]
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-active {
78
+ .query[aria-current='true'] {
79
79
  background-color: #8b3333;
80
80
  color: #fff;
81
81
  }
82
82
 
83
- .query-active p {
83
+ .query[aria-current='true'] p {
84
84
  color: #fff;
85
85
  }
86
86
 
87
- .query-active:before {
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-active:hover {
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;