querylet-rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []