render_sql 0.0.1
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 +7 -0
- data/README.md +125 -0
- data/Rakefile +3 -0
- data/lib/render_sql/engine.rb +20 -0
- data/lib/render_sql/query.rb +39 -0
- data/lib/render_sql/template_handler.rb +73 -0
- data/lib/render_sql/version.rb +5 -0
- data/lib/render_sql.rb +9 -0
- metadata +104 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 79e1fd7e1a9c5b7dff2b66880e5ee967c22a82014c7f6b8a8cc2672c6e99ecfd
|
|
4
|
+
data.tar.gz: 732d844fbf23393b21b9a77b263b467d38d3cb9524b7790b926f2dff2eb43400
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 94e7ffc62d42432319817b8a3409a68ad38a3e4fcbd54fc3c6f3247fb86a968e3f76fc796c45461b4b7e3b697cc5ebd6582d8c9d6154740036b0337e92e6cae6
|
|
7
|
+
data.tar.gz: d28a482b7d9241894a817c4f86a046075df5bb87cc59cf809453385e522a50b20531410a083e2d59ed2b83f1a8967716d10327a7b6963db815b96f8ff9adbb04
|
data/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# RenderSQL
|
|
2
|
+
|
|
3
|
+
Rails Engine to treat SQL files as user-facing views.
|
|
4
|
+
|
|
5
|
+
Often times —usually in an "admin" context— one needs to display data to users.
|
|
6
|
+
SQL is a quick way to retrieve the data but _your users_ need (semi)pretty HTML displays.
|
|
7
|
+
This means you have to create a view file, maybe convert it to an ActiveRecord query or paste it
|
|
8
|
+
into a `.find_by_sql` call etc... Sometimes in lieu of writing an HTML view you'll
|
|
9
|
+
"compromise" and export to CSV.
|
|
10
|
+
|
|
11
|
+
With RenderSQL just create an SQL file. The result will be automatically displayed in an HTML table.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
In your `Gemfile`:
|
|
16
|
+
|
|
17
|
+
```rb
|
|
18
|
+
gem "render_sql"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Define an action and route in a controller:
|
|
22
|
+
|
|
23
|
+
```rb
|
|
24
|
+
class UsersController
|
|
25
|
+
def must_upgrade
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Create an SQL file named `must_upgrade.sql` with a query:
|
|
31
|
+
|
|
32
|
+
```sql
|
|
33
|
+
select id, name, monthly_payment from users where monthly_payment < 5 order by created_at desc
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Now when you visit the `#must_upgrade` action the query will be executed and its result placed in an HTML table
|
|
37
|
+
using the current controller's layout.
|
|
38
|
+
|
|
39
|
+
The selected column names will be used for the HTML table's headers. If you need something pretty create column aliases:
|
|
40
|
+
|
|
41
|
+
```sql
|
|
42
|
+
select id, name 'Full Name', monthly_payment 'Monthly Payment' from users where monthly_payment < 5 order by created_at desc
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If you want to use a single action for multiple SQL files:
|
|
46
|
+
|
|
47
|
+
```rb
|
|
48
|
+
class UsersController
|
|
49
|
+
KNOWN_REPORTS = %w[monthly weekly yearly].freeze
|
|
50
|
+
|
|
51
|
+
# Don't forget to define the route
|
|
52
|
+
def reports
|
|
53
|
+
if KNOWN_REPORTS.include?(params[:report])
|
|
54
|
+
render params[:report]
|
|
55
|
+
else
|
|
56
|
+
render :plain => "Unknown report", :status => 400
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Then create 3 SQL files `monthly.sql`, `weekly.sql`, `yearly.sql` containing the respective queries.
|
|
63
|
+
|
|
64
|
+
The page's heading will be the SQL file's basename, titleized.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
### Query Placeholders
|
|
68
|
+
|
|
69
|
+
Supported only for where clauses. For example:
|
|
70
|
+
|
|
71
|
+
```sql
|
|
72
|
+
select id, name from users where created_at < :created_at limit 50
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Now when the associated controller action is accessed one must provide a value for the `created_at` parameter.
|
|
76
|
+
|
|
77
|
+
If a required placeholder is missing a `RenderSQL::MissingParameter` error will be raised.
|
|
78
|
+
|
|
79
|
+
### View Customization
|
|
80
|
+
|
|
81
|
+
You can override some things in your app's `application.rb` file:
|
|
82
|
+
|
|
83
|
+
```rb
|
|
84
|
+
module YourApp
|
|
85
|
+
class Application < Rails::Application
|
|
86
|
+
config.render_sql.css_classes[:table] = "table"
|
|
87
|
+
config.render_sql.css_classes[:container] = "container py-4"
|
|
88
|
+
config.render_sql.css_classes[:heading] = "mb-2"
|
|
89
|
+
config.render_sql.partial = "your-partial"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The partial will be provided with a `result` variable:
|
|
95
|
+
|
|
96
|
+
```erb
|
|
97
|
+
<table>
|
|
98
|
+
<tr>
|
|
99
|
+
<% result.headers.each do |header| %>
|
|
100
|
+
<th><%= h(header) %></th>
|
|
101
|
+
<% end %>
|
|
102
|
+
</tr>
|
|
103
|
+
<% result.each do |row| %>
|
|
104
|
+
<tr>
|
|
105
|
+
<% row.each do |cell| %>
|
|
106
|
+
<td><%= h(cell) %></td>
|
|
107
|
+
<% end %>
|
|
108
|
+
</tr>
|
|
109
|
+
<% end %>
|
|
110
|
+
</table>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Limitations
|
|
114
|
+
|
|
115
|
+
- No pagination
|
|
116
|
+
- Placeholders only for where criteria
|
|
117
|
+
- Rails >= 6.1
|
|
118
|
+
|
|
119
|
+
## Author
|
|
120
|
+
|
|
121
|
+
Skye Shaw [skye.shaw -AT- gmail.com]
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
Released under the MIT License: http://www.opensource.org/licenses/MIT
|
data/Rakefile
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RenderSQL
|
|
4
|
+
class Engine < ::Rails::Engine
|
|
5
|
+
isolate_namespace RenderSQL
|
|
6
|
+
|
|
7
|
+
config.render_sql = ActiveSupport::OrderedOptions.new.tap do |c|
|
|
8
|
+
c.partial = nil
|
|
9
|
+
c.css_classes = {
|
|
10
|
+
:heading => "render-sql-heading",
|
|
11
|
+
:table => "render-sql-results",
|
|
12
|
+
:container => "render-sql-container"
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
initializer "render_sql.register_template_handler" do
|
|
17
|
+
ActionView::Template.register_template_handler(:sql, RenderSQL::TemplateHandler)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RenderSQL
|
|
4
|
+
class Query # :nodoc:
|
|
5
|
+
Result = Struct.new(:headers, :rows) do
|
|
6
|
+
include Enumerable
|
|
7
|
+
|
|
8
|
+
def each(&block)
|
|
9
|
+
return rows.to_enum(:each) unless block_given?
|
|
10
|
+
|
|
11
|
+
rows.each(&block)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
def execute(sql, params)
|
|
17
|
+
result = ActiveRecord::Base.connection.select_all(sanitize(sql, params))
|
|
18
|
+
Result.new(result.columns, result.rows)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def sanitize(sql, params)
|
|
24
|
+
values = []
|
|
25
|
+
|
|
26
|
+
query = sql.gsub(/:(\w+)/) do
|
|
27
|
+
name = $1.to_sym
|
|
28
|
+
raise RenderSQL::MissingParameter, "Missing required query parameter: #{name}" unless params[name]
|
|
29
|
+
|
|
30
|
+
values << params[name]
|
|
31
|
+
|
|
32
|
+
"?"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
ActiveRecord::Base.sanitize_sql_array([query, *values])
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "render_sql/query"
|
|
4
|
+
|
|
5
|
+
module RenderSQL
|
|
6
|
+
class TemplateHandler
|
|
7
|
+
DEFAULT_CSS = <<-CSS
|
|
8
|
+
<style>
|
|
9
|
+
table.render-sql-results {
|
|
10
|
+
border-collapse: collapse;
|
|
11
|
+
width: 100%;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
table.render-sql-results th, table.render-sql-results td {
|
|
15
|
+
border: 1px solid #ccc;
|
|
16
|
+
padding: 8px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
table.render-sql-results th {
|
|
20
|
+
text-align: left;
|
|
21
|
+
background-color: #f2f2f2;
|
|
22
|
+
}
|
|
23
|
+
</style>
|
|
24
|
+
CSS
|
|
25
|
+
|
|
26
|
+
DEFAULT_TEMPLATE = <<-ERB
|
|
27
|
+
<div class="<%= css[:container] %>">
|
|
28
|
+
<h1 class="<%= css[:heading] %>"><%= heading %></h1>
|
|
29
|
+
<table class="<%= css[:table] %>">
|
|
30
|
+
<thead>
|
|
31
|
+
<tr>
|
|
32
|
+
<% result.headers.each do |header| %>
|
|
33
|
+
<th><%= h(header) %></th>
|
|
34
|
+
<% end %>
|
|
35
|
+
</tr>
|
|
36
|
+
</thead>
|
|
37
|
+
<tbody>
|
|
38
|
+
<% result.each do |row| %>
|
|
39
|
+
<tr>
|
|
40
|
+
<% row.each do |cell| %>
|
|
41
|
+
<td><%= h(cell) %></td>
|
|
42
|
+
<% end %>
|
|
43
|
+
</tr>
|
|
44
|
+
<% end %>
|
|
45
|
+
</tbody>
|
|
46
|
+
</table>
|
|
47
|
+
</div>
|
|
48
|
+
ERB
|
|
49
|
+
|
|
50
|
+
class << self
|
|
51
|
+
def call(template, source = nil)
|
|
52
|
+
sql = source || template.source
|
|
53
|
+
|
|
54
|
+
<<-TEMPLATE
|
|
55
|
+
begin
|
|
56
|
+
config = Rails.application.config.render_sql
|
|
57
|
+
heading = File.basename(#{template.short_identifier.inspect}, ".sql").titleize
|
|
58
|
+
result = RenderSQL::Query.execute(#{sql.inspect}, params)
|
|
59
|
+
|
|
60
|
+
if config.partial
|
|
61
|
+
render :partial => config.partial, :locals => { :css => config.css_classes, :result => result }
|
|
62
|
+
else
|
|
63
|
+
css = config.css_classes
|
|
64
|
+
ERB.new(#{DEFAULT_CSS.inspect + DEFAULT_TEMPLATE.inspect}).result(binding)
|
|
65
|
+
end
|
|
66
|
+
rescue ActiveRecord::StatementInvalid => e
|
|
67
|
+
"<p style='color: red'>SQL Error: \#{h(e.message)}</p>"
|
|
68
|
+
end
|
|
69
|
+
TEMPLATE
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/render_sql.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: render_sql
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Skye Shaw
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-01-10 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rails
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '6.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '6.1'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: sqlite3
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: bundler
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rake
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
email:
|
|
69
|
+
- skye.shaw@gmail.com
|
|
70
|
+
executables: []
|
|
71
|
+
extensions: []
|
|
72
|
+
extra_rdoc_files: []
|
|
73
|
+
files:
|
|
74
|
+
- README.md
|
|
75
|
+
- Rakefile
|
|
76
|
+
- lib/render_sql.rb
|
|
77
|
+
- lib/render_sql/engine.rb
|
|
78
|
+
- lib/render_sql/query.rb
|
|
79
|
+
- lib/render_sql/template_handler.rb
|
|
80
|
+
- lib/render_sql/version.rb
|
|
81
|
+
homepage: https://github.com/sshaw/render_sql
|
|
82
|
+
licenses:
|
|
83
|
+
- MIT
|
|
84
|
+
metadata:
|
|
85
|
+
homepage_uri: https://github.com/sshaw/render_sql
|
|
86
|
+
source_code_uri: https://github.com/sshaw/render_sql
|
|
87
|
+
rdoc_options: []
|
|
88
|
+
require_paths:
|
|
89
|
+
- lib
|
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - ">="
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '0'
|
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - ">="
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '0'
|
|
100
|
+
requirements: []
|
|
101
|
+
rubygems_version: 3.6.2
|
|
102
|
+
specification_version: 4
|
|
103
|
+
summary: Rails engine for rendering SQL files as user-facing views
|
|
104
|
+
test_files: []
|