pg_taggable 0.1.0 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +97 -11
- data/lib/pg_taggable/predicate_handler.rb +1 -1
- data/lib/pg_taggable/taggable.rb +10 -4
- data/lib/pg_taggable/version.rb +1 -1
- 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: d69f3ca42c6a0521d3c78f45b02aabd4ac22a2d2fc24a7292bff7cfffc55f954
|
4
|
+
data.tar.gz: 138eb372bdba0b11dd34d284c3c2d86afc81821140fb894c9b5787e5038f948d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e7f136c064d12711f2bc8432881976df03332e3882e57dd548f107c7ebcecf97adac266569c17aada7c3c4d3fc3118fc68036d95869745ff16d6f7cf5e9d162
|
7
|
+
data.tar.gz: a49d82d021946a137e0b3ed82a644c346804f042df6c9b921a41d49dcf7c5040b2f266d28e189654cc41a99433cf48d8316bb1b88ad83e0c361d11be05feb1d7
|
data/README.md
CHANGED
@@ -87,12 +87,6 @@ Find records that have exact same tags as the list, order is not important
|
|
87
87
|
Post.where(tags_eq: ['food', 'travel'])
|
88
88
|
```
|
89
89
|
|
90
|
-
#### #{tag_name}
|
91
|
-
Find records that have exact same tags as the list, order is important. This is the default behavior.
|
92
|
-
```Ruby
|
93
|
-
Post.where(tags: ['food', 'travel'])
|
94
|
-
```
|
95
|
-
|
96
90
|
Assume a post has tags: 'A', 'B'
|
97
91
|
|Method|Query|Matched|
|
98
92
|
|-|-|-|
|
@@ -112,10 +106,6 @@ Assume a post has tags: 'A', 'B'
|
|
112
106
|
|tags_eq|A, B|True|
|
113
107
|
|tags_eq|B, A|True|
|
114
108
|
|tags_eq|A, B, C|False|
|
115
|
-
|tags|A|False|
|
116
|
-
|tags|A, B|True|
|
117
|
-
|tags|B, A|False|
|
118
|
-
|tags|A, B, C|False|
|
119
109
|
|
120
110
|
### Class Methods
|
121
111
|
#### taggable(name, unique: true)
|
@@ -145,7 +135,7 @@ Post.tags
|
|
145
135
|
Post.tags.size
|
146
136
|
# => 4
|
147
137
|
|
148
|
-
Post.tags.distinct.size
|
138
|
+
Post.tags.select(:tag).distinct.size
|
149
139
|
# => 3
|
150
140
|
|
151
141
|
Post.tags.distinct.pluck(:tag)
|
@@ -155,6 +145,16 @@ Post.tags.group(:tag).count
|
|
155
145
|
# => {"food"=>1, "travel"=>2, "technology"=>1}
|
156
146
|
```
|
157
147
|
|
148
|
+
#### distinct_#{tag_name}
|
149
|
+
Return an array of distinct tag records. It can be used for paging, count or other query.
|
150
|
+
```Ruby
|
151
|
+
Post.distinct_tags
|
152
|
+
# => #<ActiveRecord::Relation [#<Post tag: "food", id: nil>, #<Post tag: "travel", id: nil>, #<Post tag: "technology", id: nil>]>
|
153
|
+
|
154
|
+
# equal to
|
155
|
+
Post.tags.select(:tag).distinct
|
156
|
+
```
|
157
|
+
|
158
158
|
#### uniq_#{tag_name}
|
159
159
|
Return an array of unique tag strings.
|
160
160
|
```Ruby
|
@@ -175,6 +175,77 @@ Post.count_tags
|
|
175
175
|
Post.tags.group(:tag).count
|
176
176
|
```
|
177
177
|
|
178
|
+
#### any_#{tag_name}(value, delimiter = ',')
|
179
|
+
It will create some scopes, this is useful for using ransack
|
180
|
+
```Ruby
|
181
|
+
Post.any_tags(['food', 'travel'])
|
182
|
+
|
183
|
+
# equal to
|
184
|
+
Post.where(any_tags: ['food', 'travel'])
|
185
|
+
```
|
186
|
+
|
187
|
+
Scope support string input
|
188
|
+
```Ruby
|
189
|
+
Post.any_tags('food,travel')
|
190
|
+
Post.any_tags('food|travel', '|')
|
191
|
+
```
|
192
|
+
|
193
|
+
#### all_#{tag_name}(value, delimiter = ',')
|
194
|
+
```Ruby
|
195
|
+
Post.all_tags(['food', 'travel'])
|
196
|
+
|
197
|
+
# equal to
|
198
|
+
Post.where(all_tags: ['food', 'travel'])
|
199
|
+
```
|
200
|
+
|
201
|
+
#### #{tag_name}_in(value, delimiter = ',')
|
202
|
+
```Ruby
|
203
|
+
Post.tags_in(['food', 'travel'])
|
204
|
+
|
205
|
+
# equal to
|
206
|
+
Post.where(tags_in: ['food', 'travel'])
|
207
|
+
```
|
208
|
+
|
209
|
+
#### #{tag_name}_eq(value, delimiter = ',')
|
210
|
+
```Ruby
|
211
|
+
Post.tags_eq(['food', 'travel'])
|
212
|
+
|
213
|
+
# equal to
|
214
|
+
Post.where(tags_eq: ['food', 'travel'])
|
215
|
+
```
|
216
|
+
|
217
|
+
#### not_any_#{tag_name}(value, delimiter = ',')
|
218
|
+
```Ruby
|
219
|
+
Post.not_any_tags(['food', 'travel'])
|
220
|
+
|
221
|
+
# equal to
|
222
|
+
Post.where.not(any_tags: ['food', 'travel'])
|
223
|
+
```
|
224
|
+
|
225
|
+
#### not_all_#{tag_name}(value, delimiter = ',')
|
226
|
+
```Ruby
|
227
|
+
Post.not_all_tags(['food', 'travel'])
|
228
|
+
|
229
|
+
# equal to
|
230
|
+
Post.where.not(all_tags: ['food', 'travel'])
|
231
|
+
```
|
232
|
+
|
233
|
+
#### not_#{tag_name}_in(value, delimiter = ',')
|
234
|
+
```Ruby
|
235
|
+
Post.not_tags_in(['food', 'travel'])
|
236
|
+
|
237
|
+
# equal to
|
238
|
+
Post.where.not(tags_in: ['food', 'travel'])
|
239
|
+
```
|
240
|
+
|
241
|
+
#### not_#{tag_name}_eq(value, delimiter = ',')
|
242
|
+
```Ruby
|
243
|
+
Post.not_tags_eq(['food', 'travel'])
|
244
|
+
|
245
|
+
# equal to
|
246
|
+
Post.where.not(tags_eq: ['food', 'travel'])
|
247
|
+
```
|
248
|
+
|
178
249
|
### Case Insensitive
|
179
250
|
If you use `string` type, it is case sensitive.
|
180
251
|
```Ruby
|
@@ -209,6 +280,21 @@ post.tags
|
|
209
280
|
# => ['food', 'travel']
|
210
281
|
```
|
211
282
|
|
283
|
+
### Ransack
|
284
|
+
You can use with ransack
|
285
|
+
```Ruby
|
286
|
+
class Post < ActiveRecord::Base
|
287
|
+
def self.ransackable_scopes(_auth_object = nil)
|
288
|
+
%i[all_tags]
|
289
|
+
end
|
290
|
+
end
|
291
|
+
```
|
292
|
+
|
293
|
+
And you can search
|
294
|
+
```Ruby
|
295
|
+
Post.ransack(all_tags: 'foold,travel')
|
296
|
+
```
|
297
|
+
|
212
298
|
## License
|
213
299
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
214
300
|
|
@@ -15,7 +15,7 @@ module PgTaggable
|
|
15
15
|
bind_param = Arel::Nodes::BindParam.new(query_attribute)
|
16
16
|
if operator == '='
|
17
17
|
operator = '@>'
|
18
|
-
Arel::Nodes::NamedFunction.new('ARRAY_LENGTH', [attribute, 1]).eq(query.size).and(
|
18
|
+
Arel::Nodes::NamedFunction.new('ARRAY_LENGTH', [ attribute, 1 ]).eq(query.size).and(
|
19
19
|
Arel::Nodes::InfixOperation.new(operator, attribute, bind_param)
|
20
20
|
)
|
21
21
|
else
|
data/lib/pg_taggable/taggable.rb
CHANGED
@@ -16,13 +16,14 @@ module PgTaggable
|
|
16
16
|
|
17
17
|
def taggable(name, unique: true)
|
18
18
|
type = type_for_attribute(name)
|
19
|
-
|
20
|
-
@@taggable_attributes = @@taggable_attributes.merge(
|
19
|
+
taggable_attributes = {
|
21
20
|
"any_#{name}" => [ name, type, '&&' ],
|
22
21
|
"all_#{name}" => [ name, type, '@>' ],
|
23
22
|
"#{name}_in" => [ name, type, '<@' ],
|
24
23
|
"#{name}_eq" => [ name, type, '=' ]
|
25
|
-
|
24
|
+
}
|
25
|
+
@@taggable_attributes ||= {}
|
26
|
+
@@taggable_attributes = @@taggable_attributes.merge(taggable_attributes)
|
26
27
|
|
27
28
|
if unique
|
28
29
|
if type.type == :citext
|
@@ -33,8 +34,13 @@ module PgTaggable
|
|
33
34
|
end
|
34
35
|
|
35
36
|
scope name, -> { unscope(:where).from(select("UNNEST(#{table_name}.#{name}) AS tag"), table_name) }
|
36
|
-
scope "
|
37
|
+
scope "distinct_#{name}", -> { public_send(name).select(:tag).distinct }
|
38
|
+
scope "uniq_#{name}", -> { public_send("distinct_#{name}").pluck(:tag) }
|
37
39
|
scope "count_#{name}", -> { public_send(name).group(:tag).count }
|
40
|
+
taggable_attributes.keys.each do |key|
|
41
|
+
scope key, ->(value, delimiter = ',') { where(key => value.is_a?(Array) ? value : value.split(delimiter)) }
|
42
|
+
scope "not_#{key}", ->(value, delimiter = ',') { where.not(key => value.is_a?(Array) ? value : value.split(delimiter)) }
|
43
|
+
end
|
38
44
|
end
|
39
45
|
end
|
40
46
|
end
|
data/lib/pg_taggable/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_taggable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yi-Cyuan Chen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-07-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|