paginated 1.0.4 → 1.0.4.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/lib/paginated/search.rb +74 -76
- data/lib/paginated/serialization.rb +50 -52
- data/lib/paginated.rb +11 -5
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60256c0f7c8df7e2fd347f31b5b713b6a878aa4554017a2aa074e05ffc9b5900
|
4
|
+
data.tar.gz: 3daaacf9ba025b0ce2b47d0990aa72b29e45037dde4c8461fb913bc21aa28f94
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3a615e433b61937db50ccacea1c96857b263e7cf680cfe29c9e0feb4f678cd988a2ac34cfb24dc693884f525406262dd7bfbe60e0859ee8e6e93ae50b23f24a
|
7
|
+
data.tar.gz: 3ffafc39efb627cdfbf2bbff6f9c273421694fcc8abe6984260453cca1893ed8a65cd190740fcec7fcba0d459b4af1a0a2f7eb4374273e651f9ce4c9cb580215
|
data/lib/paginated/search.rb
CHANGED
@@ -4,98 +4,96 @@ module Search
|
|
4
4
|
|
5
5
|
private
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
@objects = list.send(scope_name, value)
|
25
|
-
@objects_count = @objects.count
|
26
|
-
next
|
27
|
-
end
|
28
|
-
|
29
|
-
# форматирование кавычек
|
30
|
-
if operator != 'IN' && !@model.defined_enums.key?(field)
|
31
|
-
value = quotations_formatting(value)
|
32
|
-
end
|
33
|
-
|
34
|
-
if field.include?('.')
|
35
|
-
# нужно приджойнить таблицу
|
36
|
-
join_assoc, field = field.split('.')
|
37
|
-
table = join_assoc.tableize
|
38
|
-
list = list.joins(join_assoc.to_sym)
|
39
|
-
else
|
40
|
-
table = @model.table_name
|
41
|
-
field = field.split('|')[0]
|
42
|
-
end
|
43
|
-
|
44
|
-
query = where_query(table, field, operator, value)
|
45
|
-
@objects = list.where(query)
|
7
|
+
def search
|
8
|
+
@search_fields&.each do |field|
|
9
|
+
# коллекция записей для дальнейшей фильтрации
|
10
|
+
list = @objects || @model.unscoped.merge(@scopes)
|
11
|
+
|
12
|
+
# оператор и значение для поиска
|
13
|
+
operator, value = search_operands(field)
|
14
|
+
|
15
|
+
# пропускаем, если параметр для поиска не передан
|
16
|
+
next if value.blank? || value == 'null'
|
17
|
+
|
18
|
+
# кастомный поиск
|
19
|
+
if operator.include?('custom_search') && value.present?
|
20
|
+
# название скоупа из модели, который нужно применить
|
21
|
+
scope_name = operator.split('.')[1]
|
22
|
+
# применение скоупа
|
23
|
+
@objects = list.send(scope_name, value)
|
46
24
|
@objects_count = @objects.count
|
25
|
+
next
|
47
26
|
end
|
48
|
-
end
|
49
27
|
|
50
|
-
|
51
|
-
|
28
|
+
# форматирование кавычек
|
29
|
+
if operator != 'IN' && !@model.defined_enums.key?(field)
|
30
|
+
value = quotations_formatting(value)
|
31
|
+
end
|
52
32
|
|
53
|
-
|
54
|
-
|
33
|
+
if field.include?('.')
|
34
|
+
# нужно приджойнить таблицу
|
35
|
+
join_assoc, field = field.split('.')
|
36
|
+
table = join_assoc.tableize
|
37
|
+
list = list.joins(join_assoc.to_sym)
|
38
|
+
else
|
39
|
+
table = @model.table_name
|
40
|
+
field = field.split('|')[0]
|
41
|
+
end
|
55
42
|
|
56
|
-
|
57
|
-
|
43
|
+
query = where_query(table, field, operator, value)
|
44
|
+
@objects = list.where(query)
|
45
|
+
@objects_count = @objects.count
|
46
|
+
end
|
47
|
+
end
|
58
48
|
|
59
|
-
|
60
|
-
|
61
|
-
operator = 'IN'
|
62
|
-
value = "(#{value.join(', ')})"
|
63
|
-
end
|
49
|
+
def search_operands(field)
|
50
|
+
value = default_param_value(field)
|
64
51
|
|
65
|
-
|
66
|
-
|
67
|
-
range_field = field.split('.').last.split(':')[0].try { |i| i.split('|')[0] }
|
68
|
-
value = @params["#{range_field}_#{operator}"]
|
69
|
-
operator = operator == 'min' ? '>=' : '<='
|
70
|
-
end
|
52
|
+
# WHERE query operator
|
53
|
+
operator = field.split('|').size > 1 ? field.split('|').last : '='
|
71
54
|
|
72
|
-
|
73
|
-
|
74
|
-
operator = '='
|
75
|
-
value = "{#{value}}"
|
76
|
-
end
|
55
|
+
# условие для поиска ILIKE
|
56
|
+
value = "%#{value}%" if operator == 'ilike' && value.present?
|
77
57
|
|
78
|
-
|
58
|
+
# проверка мульти-поиска по параметру с массивом
|
59
|
+
if operator == 'multi' && !value.blank?
|
60
|
+
operator = 'IN'
|
61
|
+
value = "(#{value.join(', ')})"
|
79
62
|
end
|
80
63
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
64
|
+
# проверка диапазона (MIN/MAX)
|
65
|
+
if %w[min max].include?(operator)
|
66
|
+
range_field = field.split('.').last.split(':')[0].try { |i| i.split('|')[0] }
|
67
|
+
value = @params["#{range_field}_#{operator}"]
|
68
|
+
operator = operator == 'min' ? '>=' : '<='
|
86
69
|
end
|
87
70
|
|
88
|
-
|
89
|
-
|
71
|
+
# check array operator
|
72
|
+
if operator == 'array' && value.present?
|
73
|
+
operator = '='
|
74
|
+
value = "{#{value}}"
|
90
75
|
end
|
91
76
|
|
92
|
-
|
93
|
-
|
94
|
-
value = string.to_s.gsub(/'/, '')
|
77
|
+
[operator, value]
|
78
|
+
end
|
95
79
|
|
96
|
-
|
97
|
-
|
98
|
-
|
80
|
+
def default_param_value(field)
|
81
|
+
# название ключа-поля без оператора (напр. ilike)
|
82
|
+
key = field.split('|')[0]
|
83
|
+
|
84
|
+
@params[key]
|
85
|
+
end
|
86
|
+
|
87
|
+
def where_query(table, field, operator, value)
|
88
|
+
"#{table}.#{field} #{operator} #{value}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def quotations_formatting(string)
|
92
|
+
# удаление одинарных кавычек (напр. внутри строки)
|
93
|
+
value = string.to_s.gsub(/'/, '')
|
94
|
+
|
95
|
+
# добавление одинарных кавычек вокруг строки
|
96
|
+
"'#{value}'"
|
99
97
|
end
|
100
98
|
|
101
99
|
end
|
@@ -4,72 +4,70 @@ module Serialization
|
|
4
4
|
|
5
5
|
private
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
serialize_with_entity
|
20
|
-
end
|
7
|
+
def serialize
|
8
|
+
# коллекция записей / сущность для применения аггрегирования
|
9
|
+
list = @objects || @model.unscoped.merge(@scopes)
|
10
|
+
|
11
|
+
# применение сортировки и пагинации к коллекции записей
|
12
|
+
@objects = list.offset(@offset).merge(sort_proc).limit(@limit)
|
13
|
+
|
14
|
+
# сериализация с помощью переданных полей или сериалайзера
|
15
|
+
if @fields
|
16
|
+
serialize_with_fields
|
17
|
+
elsif @grape_entity
|
18
|
+
serialize_with_entity
|
21
19
|
end
|
20
|
+
end
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
def serialize_with_fields
|
23
|
+
# добавление ID в список полей по умолчанию
|
24
|
+
@fields.push(:id)
|
26
25
|
|
27
|
-
|
28
|
-
|
26
|
+
# список массивов значений
|
27
|
+
@objects = @objects.map { |i| obtain_fields_values(i) }
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
# трансформация массивов значений в объекты (ключ-значение)
|
30
|
+
@objects = @objects.map { |i| @fields.zip(i).to_h }
|
31
|
+
end
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
def serialize_with_entity
|
34
|
+
@objects = @objects.map { |i| @grape_entity.represent(i, current_user: @current_user).as_json }
|
35
|
+
end
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
37
|
+
def sort_proc
|
38
|
+
# сортировка не задана явно, не передан параметр
|
39
|
+
# или значение переданного параметра не совпадает с ожидаемым
|
40
|
+
if @sort.blank? || @sort.map { |i| i.split('|')[0] }.exclude?(@params[:sort])
|
41
|
+
field = @order
|
42
|
+
return proc { order("#{field} DESC") }
|
43
|
+
end
|
45
44
|
|
46
|
-
|
47
|
-
|
45
|
+
@sort.each do |sort_option|
|
46
|
+
sort, field = sort_option.split('|')
|
48
47
|
|
49
|
-
|
50
|
-
|
48
|
+
# пропускаем, если поле для сортировки не совпадает с переданным параметром
|
49
|
+
next if @params[:sort] != sort
|
51
50
|
|
52
|
-
|
53
|
-
|
51
|
+
# если поле для сортировки совпадает с ключом переданного параметра
|
52
|
+
field = sort if field.blank?
|
54
53
|
|
55
|
-
|
54
|
+
sort_order = "#{@params[:sort_order]} NULLS LAST"
|
56
55
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
56
|
+
order_proc =
|
57
|
+
if field.split('.').count > 1
|
58
|
+
# сортировка по связанной таблице
|
59
|
+
relation, column = field.split('.')
|
60
|
+
proc { eager_load(relation).order("#{relation.tableize}.#{column} #{sort_order}") }
|
61
|
+
else
|
62
|
+
proc { order("#{field} #{sort_order}") }
|
63
|
+
end
|
65
64
|
|
66
|
-
|
67
|
-
end
|
65
|
+
return order_proc
|
68
66
|
end
|
67
|
+
end
|
69
68
|
|
70
|
-
|
71
|
-
|
72
|
-
end
|
69
|
+
def obtain_fields_values(record)
|
70
|
+
@fields.map { |i| record.send(i) }
|
73
71
|
end
|
74
72
|
|
75
73
|
end
|
data/lib/paginated.rb
CHANGED
@@ -6,13 +6,16 @@ class Paginated
|
|
6
6
|
include Search
|
7
7
|
include Serialization
|
8
8
|
|
9
|
-
def
|
9
|
+
def initialize(**args)
|
10
10
|
# обработка переданных аргументов
|
11
11
|
handle_args(**args)
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
def self.collection(**args)
|
15
|
+
new(**args).collection
|
16
|
+
end
|
15
17
|
|
18
|
+
def collection
|
16
19
|
if @objects_count > 0
|
17
20
|
search
|
18
21
|
serialize
|
@@ -24,7 +27,7 @@ class Paginated
|
|
24
27
|
{ count: @objects_count, objects: @objects }
|
25
28
|
end
|
26
29
|
|
27
|
-
def
|
30
|
+
def handle_args(**args)
|
28
31
|
# обрабатываемая Rails модель
|
29
32
|
@model = args[:model]
|
30
33
|
|
@@ -50,9 +53,12 @@ class Paginated
|
|
50
53
|
# сортировка
|
51
54
|
@order = args[:order] || :id
|
52
55
|
@sort = args[:sort]
|
56
|
+
|
57
|
+
# подсчет кол-ва записей
|
58
|
+
@objects_count = records_count
|
53
59
|
end
|
54
60
|
|
55
|
-
def
|
61
|
+
def records_count
|
56
62
|
# получение кол-ва записей из кеша
|
57
63
|
cache_key = "#{@model}_records_count"
|
58
64
|
cached = Rails.cache.read(cache_key)
|