rad_core_rails 0.5.0 → 0.5.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 +4 -4
- data/.gitignore +16 -15
- data/Gemfile +13 -6
- data/lib/rad_core_rails.rb +15 -14
- data/lib/rad_core_rails/query_generator.rb +167 -167
- data/lib/rad_core_rails/version.rb +5 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ceead2841d732a837cd792358174211cd357da39c2f72b1435fdd47a68cc354
|
4
|
+
data.tar.gz: f3fc5c87d4e9a9769b13354b3b1f6594936f54d97221c56910e1d9a4c677eb07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 343d979caca6c5ef32a443720983111ef7c4b1f9d1f5bfe58517929ddba0d0c3dcafaa9f8d87b62f1a307259f3af2be829e78e9e9bbf942975bc8544cdfbe7e8
|
7
|
+
data.tar.gz: 9b0205167f8736b088c68ab4eefba1aae2997480bd1fd4eb427924287985bbc0bbb7b4eb84e4633b1a596634d758674e779574b9a1e7a63b8484a4d667fb9665
|
data/.gitignore
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
-
/.idea/
|
2
|
-
/.bundle/
|
3
|
-
/.yardoc
|
4
|
-
/_yardoc/
|
5
|
-
/coverage/
|
6
|
-
/doc/
|
7
|
-
/pkg/
|
8
|
-
/spec/reports/
|
9
|
-
/tmp/
|
10
|
-
Gemfile.lock
|
11
|
-
bin
|
12
|
-
*.gem
|
13
|
-
.rspec_status
|
14
|
-
.ruby-gemset
|
15
|
-
.ruby-version
|
1
|
+
/.idea/
|
2
|
+
/.bundle/
|
3
|
+
/.yardoc
|
4
|
+
/_yardoc/
|
5
|
+
/coverage/
|
6
|
+
/doc/
|
7
|
+
/pkg/
|
8
|
+
/spec/reports/
|
9
|
+
/tmp/
|
10
|
+
Gemfile.lock
|
11
|
+
bin
|
12
|
+
*.gem
|
13
|
+
.rspec_status
|
14
|
+
.ruby-gemset
|
15
|
+
.ruby-version
|
16
|
+
/.byebug_history
|
data/Gemfile
CHANGED
@@ -1,6 +1,13 @@
|
|
1
|
-
source "https://rubygems.org"
|
2
|
-
|
3
|
-
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
|
-
|
5
|
-
# Specify your gem's dependencies in new_gem.gemspec
|
6
|
-
gemspec
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in new_gem.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
group :test do
|
9
|
+
gem 'byebug'
|
10
|
+
gem 'pg'
|
11
|
+
gem 'database_cleaner-active_record'
|
12
|
+
gem "factory_bot_rails"
|
13
|
+
end
|
data/lib/rad_core_rails.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
|
-
require "rad_core_rails/version"
|
2
|
-
require "active_support/concern"
|
3
|
-
require "
|
4
|
-
require
|
5
|
-
require 'rad_core_rails/
|
6
|
-
require 'rad_core_rails/
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
1
|
+
require "rad_core_rails/version"
|
2
|
+
require "active_support/concern"
|
3
|
+
require "active_support/core_ext"
|
4
|
+
require "active_record"
|
5
|
+
require 'rad_core_rails/query_generator'
|
6
|
+
require 'rad_core_rails/search_terms'
|
7
|
+
require 'rad_core_rails/sortable'
|
8
|
+
|
9
|
+
module RadCoreRails
|
10
|
+
def self.included(receiver)
|
11
|
+
receiver.send :include, Sortable, SearchTerms, QueryGenerator
|
12
|
+
end
|
13
|
+
|
14
|
+
class Error < StandardError; end
|
15
|
+
end
|
@@ -1,167 +1,167 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RadCoreRails
|
4
|
-
module QueryGenerator
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
class_methods do
|
8
|
-
attr_reader :searchable_columns
|
9
|
-
|
10
|
-
def searchable(columns = [])
|
11
|
-
@searchable_columns = handle_columns(columns)
|
12
|
-
end
|
13
|
-
|
14
|
-
def joins_clause
|
15
|
-
<<-SQL
|
16
|
-
SQL
|
17
|
-
end
|
18
|
-
|
19
|
-
def filter_manifest
|
20
|
-
{}.with_indifferent_access
|
21
|
-
end
|
22
|
-
|
23
|
-
def create_filters(search, filters)
|
24
|
-
query = []
|
25
|
-
args = []
|
26
|
-
clause, arguments = generate_search_clause(search)
|
27
|
-
query << clause
|
28
|
-
arguments.each do |arg|
|
29
|
-
args << arg
|
30
|
-
end
|
31
|
-
filters.map do |filter|
|
32
|
-
clause, arguments = filter_manifest[filter[:key]].call(filter)
|
33
|
-
query << clause
|
34
|
-
arguments.each do |arg|
|
35
|
-
args << arg
|
36
|
-
end
|
37
|
-
end
|
38
|
-
[query.reject(&:blank?).join(' AND '), args]
|
39
|
-
end
|
40
|
-
|
41
|
-
def generate_search_clause(search)
|
42
|
-
args = []
|
43
|
-
if search.present? && searchable_columns.is_a?(Array)
|
44
|
-
clause = []
|
45
|
-
search.split(' ').each do |term|
|
46
|
-
columns = []
|
47
|
-
searchable_columns.each do |col|
|
48
|
-
columns.push("(LOWER(#{col}) ILIKE ?)")
|
49
|
-
args.push '%' + term.downcase.strip + '%'
|
50
|
-
end
|
51
|
-
clause.push '(' + columns.join(' OR ') + ')'
|
52
|
-
end
|
53
|
-
['(' + clause.join(' AND ') + ')', args]
|
54
|
-
else
|
55
|
-
['', []]
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# Generate Boolean clause
|
60
|
-
def generate_boolean_clause(column_name, filter)
|
61
|
-
str = "#{column_name} = ?"
|
62
|
-
args = []
|
63
|
-
args << filter[:values][0]
|
64
|
-
|
65
|
-
[str, args]
|
66
|
-
end
|
67
|
-
|
68
|
-
def generate_model_clause(column_name, filter)
|
69
|
-
str = "(#{column_name} = ANY(ARRAY[?]))"
|
70
|
-
args = [filter[:values]]
|
71
|
-
|
72
|
-
[str, args]
|
73
|
-
end
|
74
|
-
|
75
|
-
def generate_array_clause(column_name, filter)
|
76
|
-
str = "(#{column_name} && ARRAY[?])"
|
77
|
-
args = [filter[:values]]
|
78
|
-
|
79
|
-
[str, args]
|
80
|
-
end
|
81
|
-
|
82
|
-
def generate_reference_link_clause(link_out_type, filter)
|
83
|
-
str = "(reference_links.link_out_type = '#{link_out_type}' AND reference_links.link_out_id = ANY(?))"
|
84
|
-
args = [filter[:values]]
|
85
|
-
|
86
|
-
[str, args]
|
87
|
-
end
|
88
|
-
|
89
|
-
def generate_jsonb_array_clause(unique_filter_key, column_name, filter)
|
90
|
-
str = "(#{column_name} ?| ARRAY[:#{unique_filter_key}])"
|
91
|
-
args = [{ "#{unique_filter_key}": filter[:values] }]
|
92
|
-
|
93
|
-
[str, args]
|
94
|
-
end
|
95
|
-
|
96
|
-
def generate_number_clause(column_name, filter)
|
97
|
-
option = filter[:option]
|
98
|
-
values = filter[:values]
|
99
|
-
str = ''
|
100
|
-
args = []
|
101
|
-
|
102
|
-
case option
|
103
|
-
when '='
|
104
|
-
str = "#{column_name} = ?"
|
105
|
-
args << values[0]
|
106
|
-
when '>'
|
107
|
-
str = "#{column_name} > ?"
|
108
|
-
args << values[0]
|
109
|
-
when '<'
|
110
|
-
str = "#{column_name} < ?"
|
111
|
-
args << values[0]
|
112
|
-
when '..'
|
113
|
-
str = "(#{column_name} BETWEEN ? AND ?)"
|
114
|
-
args << values[0]
|
115
|
-
args << values[1]
|
116
|
-
end
|
117
|
-
[str, args]
|
118
|
-
end
|
119
|
-
|
120
|
-
def generate_date_clause(column_name, filter)
|
121
|
-
option = filter[:option]
|
122
|
-
values = filter[:values]
|
123
|
-
str = ''
|
124
|
-
args = []
|
125
|
-
|
126
|
-
case option
|
127
|
-
when '='
|
128
|
-
str = "#{column_name}::date = ?::date"
|
129
|
-
args << values[0]
|
130
|
-
when '>'
|
131
|
-
str = "#{column_name}::date > ?::date"
|
132
|
-
args << values[0]
|
133
|
-
when '<'
|
134
|
-
str = "#{column_name}::date < ?::date"
|
135
|
-
args << values[0]
|
136
|
-
when '..'
|
137
|
-
str = "(#{column_name}::date BETWEEN ?::date AND ?::date)"
|
138
|
-
args << values[0]
|
139
|
-
args << values[1]
|
140
|
-
end
|
141
|
-
[str, args]
|
142
|
-
end
|
143
|
-
|
144
|
-
def sort_direction(direction)
|
145
|
-
direction == 'asc' ? 'ASC' : 'DESC'
|
146
|
-
end
|
147
|
-
|
148
|
-
private
|
149
|
-
|
150
|
-
def handle_columns(columns)
|
151
|
-
if columns.empty?
|
152
|
-
return self.columns.select { |c| c.type == :string }.map { |c| "#{table_name}.#{c.name}" }
|
153
|
-
end
|
154
|
-
|
155
|
-
columns.map do |c|
|
156
|
-
splitted_c = c.split('.')
|
157
|
-
|
158
|
-
if splitted_c.size == 1 && splitted_c.first != table_name
|
159
|
-
"#{table_name}.#{c}"
|
160
|
-
else
|
161
|
-
c
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RadCoreRails
|
4
|
+
module QueryGenerator
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
class_methods do
|
8
|
+
attr_reader :searchable_columns
|
9
|
+
|
10
|
+
def searchable(columns = [])
|
11
|
+
@searchable_columns = handle_columns(columns)
|
12
|
+
end
|
13
|
+
|
14
|
+
def joins_clause
|
15
|
+
<<-SQL
|
16
|
+
SQL
|
17
|
+
end
|
18
|
+
|
19
|
+
def filter_manifest
|
20
|
+
{}.with_indifferent_access
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_filters(search, filters)
|
24
|
+
query = []
|
25
|
+
args = []
|
26
|
+
clause, arguments = generate_search_clause(search)
|
27
|
+
query << clause
|
28
|
+
arguments.each do |arg|
|
29
|
+
args << arg
|
30
|
+
end
|
31
|
+
filters.map do |filter|
|
32
|
+
clause, arguments = filter_manifest[filter[:key]].call(filter)
|
33
|
+
query << clause
|
34
|
+
arguments.each do |arg|
|
35
|
+
args << arg
|
36
|
+
end
|
37
|
+
end
|
38
|
+
[query.reject(&:blank?).join(' AND '), args]
|
39
|
+
end
|
40
|
+
|
41
|
+
def generate_search_clause(search)
|
42
|
+
args = []
|
43
|
+
if search.present? && searchable_columns.is_a?(Array)
|
44
|
+
clause = []
|
45
|
+
search.split(' ').each do |term|
|
46
|
+
columns = []
|
47
|
+
searchable_columns.each do |col|
|
48
|
+
columns.push("(LOWER(#{col}) ILIKE ?)")
|
49
|
+
args.push '%' + term.downcase.strip + '%'
|
50
|
+
end
|
51
|
+
clause.push '(' + columns.join(' OR ') + ')'
|
52
|
+
end
|
53
|
+
['(' + clause.join(' AND ') + ')', args]
|
54
|
+
else
|
55
|
+
['', []]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Generate Boolean clause
|
60
|
+
def generate_boolean_clause(column_name, filter)
|
61
|
+
str = "#{column_name} = ?"
|
62
|
+
args = []
|
63
|
+
args << filter[:values][0]
|
64
|
+
|
65
|
+
[str, args]
|
66
|
+
end
|
67
|
+
|
68
|
+
def generate_model_clause(column_name, filter)
|
69
|
+
str = "(#{column_name} = ANY(ARRAY[?]))"
|
70
|
+
args = [filter[:values]]
|
71
|
+
|
72
|
+
[str, args]
|
73
|
+
end
|
74
|
+
|
75
|
+
def generate_array_clause(column_name, filter)
|
76
|
+
str = "(#{column_name} && ARRAY[?])"
|
77
|
+
args = [filter[:values]]
|
78
|
+
|
79
|
+
[str, args]
|
80
|
+
end
|
81
|
+
|
82
|
+
def generate_reference_link_clause(link_out_type, filter)
|
83
|
+
str = "(reference_links.link_out_type = '#{link_out_type}' AND reference_links.link_out_id = ANY(?))"
|
84
|
+
args = [filter[:values]]
|
85
|
+
|
86
|
+
[str, args]
|
87
|
+
end
|
88
|
+
|
89
|
+
def generate_jsonb_array_clause(unique_filter_key, column_name, filter)
|
90
|
+
str = "(#{column_name} ?| ARRAY[:#{unique_filter_key}])"
|
91
|
+
args = [{ "#{unique_filter_key}": filter[:values] }]
|
92
|
+
|
93
|
+
[str, args]
|
94
|
+
end
|
95
|
+
|
96
|
+
def generate_number_clause(column_name, filter)
|
97
|
+
option = filter[:option]
|
98
|
+
values = filter[:values]
|
99
|
+
str = ''
|
100
|
+
args = []
|
101
|
+
|
102
|
+
case option
|
103
|
+
when '='
|
104
|
+
str = "#{column_name} = ?"
|
105
|
+
args << values[0]
|
106
|
+
when '>'
|
107
|
+
str = "#{column_name} > ?"
|
108
|
+
args << values[0]
|
109
|
+
when '<'
|
110
|
+
str = "#{column_name} < ?"
|
111
|
+
args << values[0]
|
112
|
+
when '..'
|
113
|
+
str = "(#{column_name} BETWEEN ? AND ?)"
|
114
|
+
args << values[0]
|
115
|
+
args << values[1]
|
116
|
+
end
|
117
|
+
[str, args]
|
118
|
+
end
|
119
|
+
|
120
|
+
def generate_date_clause(column_name, filter)
|
121
|
+
option = filter[:option]
|
122
|
+
values = filter[:values]
|
123
|
+
str = ''
|
124
|
+
args = []
|
125
|
+
|
126
|
+
case option
|
127
|
+
when '='
|
128
|
+
str = "#{column_name}::date = ?::date"
|
129
|
+
args << values[0]
|
130
|
+
when '>'
|
131
|
+
str = "#{column_name}::date > ?::date"
|
132
|
+
args << values[0]
|
133
|
+
when '<'
|
134
|
+
str = "#{column_name}::date < ?::date"
|
135
|
+
args << values[0]
|
136
|
+
when '..'
|
137
|
+
str = "(#{column_name}::date BETWEEN ?::date AND ?::date)"
|
138
|
+
args << values[0]
|
139
|
+
args << values[1]
|
140
|
+
end
|
141
|
+
[str, args]
|
142
|
+
end
|
143
|
+
|
144
|
+
def sort_direction(direction)
|
145
|
+
direction == 'asc' ? 'ASC' : 'DESC'
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def handle_columns(columns)
|
151
|
+
if columns.empty?
|
152
|
+
return self.columns.select { |c| c.type == :string }.map { |c| "#{table_name}.#{c.name}" }
|
153
|
+
end
|
154
|
+
|
155
|
+
columns.map do |c|
|
156
|
+
splitted_c = c.split('.')
|
157
|
+
|
158
|
+
if splitted_c.size == 1 && splitted_c.first != table_name
|
159
|
+
"#{table_name}.#{c}"
|
160
|
+
else
|
161
|
+
c
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RadCoreRails
|
4
|
-
VERSION = '0.5.
|
5
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RadCoreRails
|
4
|
+
VERSION = '0.5.1'
|
5
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rad_core_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oleksandr Poltavets, James Marrs
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|