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 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,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
@@ -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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RenderSQL
4
+ VERSION = "0.0.1"
5
+ end
data/lib/render_sql.rb ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "render_sql/engine"
4
+ require "render_sql/template_handler"
5
+
6
+ module RenderSQL
7
+ Error = Class.new(StandardError)
8
+ MissingParameter = Class.new(Error)
9
+ end
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: []