12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
# File 'lib/litetags.rb', line 12
def tag_columns(*column_names)
@tag_columns ||= {}
tag_columns_sanitize_list(column_names).each do |column_name|
@tag_columns[column_name] ||= false
end
@tag_columns.each do |column_name, initialized|
next if initialized
column_name = column_name.to_s
method_name = column_name.downcase
json_each = Arel::Nodes::NamedFunction.new("JSON_EACH", [arel_table[column_name]])
define_singleton_method :"unique_#{method_name}" do |conditions = "true"|
select("value")
.from([arel_table, json_each])
.distinct
.pluck("value")
.sort
end
define_singleton_method :"#{method_name}_cloud" do |conditions = "true"|
select("value")
.from([arel_table, json_each])
.group("value")
.order("value")
.pluck(Arel.sql("value, COUNT(*) AS count"))
.to_h
end
scope :"with_#{method_name}", -> {
where.not(arel_table[column_name].eq(nil))
.where.not(arel_table[column_name].eq([]))
}
scope :"without_#{method_name}", -> {
where(arel_table[column_name].eq(nil))
.or(where(arel_table[column_name].eq([])))
}
scope :"with_any_#{method_name}", ->(*items) {
values = tag_columns_sanitize_list(items)
overlap = Arel::SelectManager.new(json_each)
.project(1)
.where(Arel.sql("value").in(values))
.take(1)
.exists
where overlap
}
scope :"with_all_#{method_name}", ->(*items) {
values = tag_columns_sanitize_list(items)
count = Arel::SelectManager.new(json_each)
.project(Arel.star.count)
.where(Arel.sql("value").in(values))
contains = Arel::Nodes::Equality.new(count, values.size)
where contains
}
scope :"without_any_#{method_name}", ->(*items) {
values = tag_columns_sanitize_list(items)
overlap = Arel::SelectManager.new(json_each)
.project(1)
.where(Arel.sql("value").in(values))
.take(1)
.exists
where.not overlap
}
scope :"without_all_#{method_name}", ->(*items) {
values = tag_columns_sanitize_list(items)
count = Arel::SelectManager.new(json_each)
.project(Arel.star.count)
.where(Arel.sql("value").in(values))
contains = Arel::Nodes::Equality.new(count, values.size)
where.not contains
}
before_validation -> { self[column_name] = self.class.tag_columns_sanitize_list(self[column_name]) }
define_method :"has_any_#{method_name}?" do |*values|
values = self.class.tag_columns_sanitize_list(values)
existing = self.class.tag_columns_sanitize_list(self[column_name])
(values & existing).present?
end
define_method :"has_all_#{method_name}?" do |*values|
values = self.class.tag_columns_sanitize_list(values)
existing = self.class.tag_columns_sanitize_list(self[column_name])
(values & existing).size == values.size
end
alias_method :"has_#{method_name.singularize}?", :"has_all_#{method_name}?"
@tag_columns[column_name] = true
end
end
|