querylet-rails 1.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 66c6879ef73a6a30386db584b9237cfbcc1fe3eb6c75b0807ab91a43f5272714
4
+ data.tar.gz: c2bf111d8e123d42557a69f422dc97c90950c55393df92235c6dc971e18914c1
5
+ SHA512:
6
+ metadata.gz: 817d3712b2f5b175a974389ece5dadec2e84b286288cf91d9ff5e06100189c5d39b925a208a203463a69f5de5854b991a25ae47bb8982e402dcea3a04a80173d
7
+ data.tar.gz: 52499b2461bf2090b7b9e03c6ad98101d6806fb6e1526bd64a884deca3043eb3413fbb22a29eafa548d71080acb61705b80ee1727c7745c5c953dd0b8bcda263
@@ -0,0 +1,101 @@
1
+ # Querylet Rails
2
+
3
+ ## What is Querylet?
4
+
5
+ [Querylet](https://github.com/teacherseat/querylet) is a query template
6
+ langauge for Postgres to ease working with complex queries eg.
7
+
8
+ Similar to handlebars but a much simpler langague and specfically
9
+ designed for postgre queries.
10
+
11
+ ```
12
+ {{#if count}}
13
+ {{> include 'admin.shared.paginate_select'}}
14
+ {{/else}}
15
+ {{> include 'admin.users.select'}}
16
+ {{/if}}
17
+ FROM users
18
+ WHERE true
19
+ AND 'customer' != ANY(users.role)
20
+ {{#if search}}
21
+ AND (
22
+ (coalesce(users.first_name, '') || ' ' || coalesce(users.last_name, '') ILIKE {{wild search}})
23
+ OR users.email ILIKE {{wild search}}
24
+ )
25
+ {{/if}}
26
+ {{#unless count}}
27
+ {{#if sort}}
28
+ ORDER BY {{sort}}
29
+ {{/else}}
30
+ ORDER BY users.id ASC
31
+ {{/if}}
32
+ {{> include 'admin.shared.paginate_offset'}}
33
+ {{/unless}}
34
+ ```
35
+
36
+ ## What is Querylet Rails?
37
+
38
+ Querylet Rails helps configure querylet for use in a Rails application.
39
+
40
+ It contains two files:
41
+
42
+ - querylet_rails/controller/queryable.rb (QueryletRails::Controller::Queryable)
43
+ - querylet_rails/model/queryable.rb (QueryletRails::Model::Queryable)
44
+
45
+
46
+ ## QueryletRails::Controller::Queryable
47
+
48
+ This module is a Rails Controller Concerns to include your ApplicationController
49
+
50
+ It defines the following controller methods:
51
+
52
+ - set_pagination_headers
53
+ - render_paginated
54
+ - render_paginated_json
55
+ - index_params
56
+
57
+ ## QueryletRails::Model::Queryable
58
+
59
+ This module is a Rails Model Concerns to include your ApplicationRecord
60
+
61
+ It defines the following model methods:
62
+
63
+ - select_value and self.select_value
64
+ - select_values and self.select_values
65
+ - select_object and self.select_object
66
+ - select_array and self.select_array
67
+ - select_all and self.select_all
68
+ - select_paginate and self.select_paginate
69
+ - self.query_root
70
+ - self.query
71
+ - self.query_compile_template
72
+ - self.query_wrap_object
73
+ - self.query_wrap_array
74
+
75
+ ## How to Install
76
+
77
+ Create a queries directory eg.
78
+
79
+ Create a directory to contain your queries
80
+
81
+ ```
82
+ mkdir app/queries
83
+ ```
84
+
85
+ Include `QueryletRails::Controller::Queryable` in your ApplicationController
86
+
87
+ ```rb
88
+ require 'querylet_rails/controller/queryable'
89
+ class ApplicationController < ActionController::Base
90
+ include QueryletRails::Controller::Queryable
91
+ end
92
+ ```
93
+
94
+ Include `QueryletRails::Model::Queryablek` in your ApplicationRecord
95
+
96
+ ```rb
97
+ require 'querylet_rails/model/queryable'
98
+ class ApplicationRecord < ActiveRecord::Base
99
+ include QueryletRails::Model::Queryable
100
+ end
101
+ ```
@@ -0,0 +1,61 @@
1
+ module QueryletRails
2
+ module Controller
3
+ module Queryable
4
+ extend ActiveSupport::Concern
5
+
6
+ def set_pagination_headers count_json
7
+ json = JSON.parse(count_json)
8
+ json = json.first if json.is_a?(Array)
9
+ page = json['page']
10
+ total = json['total_entries']
11
+ per_page = json['per_page'] || 20
12
+ pages = (total.to_f / per_page).ceil
13
+ end_entry = page * per_page
14
+ end_entry = total if end_entry > total
15
+ headers["X-Pagination"] = {
16
+ page: page,
17
+ total: total,
18
+ total_pages: pages,
19
+ first_page: page == 1,
20
+ last_page: page >= pages,
21
+ previous_page: page - 1,
22
+ next_page: page + 1,
23
+ out_of_bounds: page < 1 || page > pages,
24
+ first_entry: (page - 1) * per_page + 1,
25
+ end_entry: end_entry
26
+ }.to_json
27
+ end
28
+
29
+ # AB - We should phase out {{sort}} in favour
30
+ # of {{order}} {{by}} for more finetune control
31
+ def render_paginated target, method, attrs
32
+ if attrs.key?(:sort)
33
+ name,dir = attrs[:sort].split ','
34
+ v = [name]
35
+ v.push dir.upcase if dir
36
+ v = v.join ' '
37
+ attrs[:sort] = v
38
+ attrs[:order] = name
39
+ attrs[:by] = (dir || 'ASC').upcase
40
+ end
41
+
42
+ # Use the same query but to count all the records
43
+ attrs[:count] = true
44
+ count_json = target.send method, attrs
45
+ set_pagination_headers count_json
46
+ attrs.delete(:count)
47
+
48
+ target.send method, attrs
49
+ end
50
+
51
+ def render_paginated_json target, method, attrs
52
+ json = render_paginated target, method, attrs
53
+ render json: json
54
+ end
55
+
56
+ def index_params
57
+ params.permit :page, :search, :sort
58
+ end
59
+ end # Queryable
60
+ end # Controller
61
+ end # QueryletRails
@@ -0,0 +1,119 @@
1
+ require 'querylet'
2
+
3
+ module QueryletRails
4
+ module Model
5
+ module Queryable
6
+ extend ActiveSupport::Concern
7
+ # override this function
8
+
9
+ def select_value relative_path, data={}
10
+ self.class.select_value relative_path, data
11
+ end
12
+
13
+ def select_values relative_path, data={}
14
+ self.class.select_values relative_path, data
15
+ end
16
+
17
+ def select_object relative_path, data={}
18
+ self.class.select_object relative_path, data
19
+ end
20
+
21
+ def select_array relative_path, data={}
22
+ self.class.select_array relative_path, data
23
+ end
24
+
25
+ def select_all relative_path, data={}
26
+ self.class.select_all relative_path, data
27
+ end
28
+
29
+ def select_paginate query, attrs, count
30
+ self.class.select_paginate query, attrs, count
31
+ end
32
+
33
+ module ClassMethods
34
+ def query_root
35
+ Rails.root
36
+ end
37
+
38
+ def query relative_path, data={}
39
+ file_path = self.query_root.join('app','queries',relative_path + '.sql')
40
+ template = File.read file_path
41
+ query_compile_template template, data
42
+ end
43
+
44
+ def query_compile_template template, data={}
45
+ querylet = Querylet::Querylet.new path: self.query_root.join('app','queries').to_s
46
+ begin
47
+ querylet.compile(template).call(data)
48
+ rescue => e
49
+ puts ""
50
+ puts "===== Querylet Compile Error Occured ====="
51
+ template_annotated = ''
52
+ template.split("\n").each_with_index do |line,i|
53
+ template_annotated << "#{(i+1).to_s.rjust(3, " ")} | #{line}\n"
54
+ end
55
+ puts template_annotated
56
+ raise e
57
+ end
58
+ end
59
+
60
+ def select_value relative_path, data={}
61
+ sql = self.query relative_path, data
62
+ self.connection.select_value sql
63
+ end
64
+
65
+ def select_values relative_path, data={}
66
+ sql = self.query relative_path, data
67
+ self.connection.select_values sql
68
+ end
69
+
70
+ def select_array relative_path, data={}
71
+ template = self.query relative_path, data
72
+ sql = query_wrap_array template
73
+ self.connection.select_value sql
74
+ end
75
+
76
+ def select_object relative_path, data={}
77
+ template = self.query relative_path, data
78
+ sql = query_wrap_object template
79
+ self.connection.select_value sql
80
+ end
81
+
82
+ def select_all relative_path, data={}
83
+ sql = self.query relative_path, data
84
+ self.connection.select_all sql
85
+ end
86
+
87
+ def query_wrap_object template
88
+ <<-HEREDOC.chomp
89
+ (SELECT COALESCE(row_to_json(object_row),'{}'::json) FROM (
90
+ #{template.to_s.chomp}
91
+ ) object_row)
92
+ HEREDOC
93
+ end
94
+
95
+ def query_wrap_array template
96
+ <<-HEREDOC.chomp
97
+ (SELECT COALESCE(array_to_json(array_agg(row_to_json(array_row))),'[]'::json) FROM (
98
+ #{template.to_s.chomp}
99
+ ) array_row)
100
+ HEREDOC
101
+ end
102
+
103
+ def select_paginate relative_path, data, count
104
+ file_path = self.query_root.join('app','queries',relative_path + '.sql')
105
+ template = File.read file_path
106
+ if count
107
+ sql = self.query_wrap_object template
108
+ sql = self.query_compile_template sql, data
109
+ self.connection.select_value sql
110
+ else
111
+ sql = self.query_wrap_array template
112
+ sql = self.query_compile_template sql, data
113
+ self.connection.select_value sql
114
+ end
115
+ end
116
+ end
117
+ end # Queryable
118
+ end # Model
119
+ end # QueryletRails
@@ -0,0 +1,3 @@
1
+ module QueryletRails
2
+ VERSION = "1.0.0"
3
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: querylet-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - TeacherSeat
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-12-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: querylet
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Querylet Rails
56
+ email:
57
+ - andrew@teacherseat.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - Readme.md
63
+ - lib/querylet_rails/controller/queryable.rb
64
+ - lib/querylet_rails/model/queryable.rb
65
+ - lib/querylet_rails/version.rb
66
+ homepage: https://teacherseat.com
67
+ licenses:
68
+ - MIT
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubygems_version: 3.1.2
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: Querylet Rails
89
+ test_files: []