pg_taggable 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec57f99287e3bb16b29e459e42c0f3c5a24d6f967917906d88dadfe491d133e3
4
- data.tar.gz: 525995c96c17957ba46a5025d250c1703efec6da6841277864befd0278072449
3
+ metadata.gz: a1558a67c0063eb3c5dacc16ee3e1420bf01d0c8987891c4da2d4f018721e55f
4
+ data.tar.gz: 7b306fffd714f679925bb9ac870e8f8bcfa3c04e82c8a6bb4e4bb3a215bc430f
5
5
  SHA512:
6
- metadata.gz: caa213bb0b77a0c5f71922337563d9bf3222cf98a17571e90f700b5fabf5b345c1c4494c71c45889e8e081b1c0c44c200fa4c228638408d39d2039d26b5bca73
7
- data.tar.gz: b4760ae519a53f6b414e5578ac6ec241b30b3342acdc82057a9a437599c65ce71bd473ef2be8ccd8c6ee99bff393fc775e647fee75ed5333f519b1ddb8617eda
6
+ metadata.gz: da505e59ecd6b6d24ef848b54c77702c97aab8c874dda0c5cd2953b7ad2206ac3a7f310153c8e02d58b1ee98d00e03ad580bed30c603a006e1fcb974007b45e6
7
+ data.tar.gz: 97b98cbec2d7b32ccaedc4da5fb0500bf67190bfc97dba43134e0811a076922bc05f19c53896bc425404b3d17273b2090e32923110c8589710f20791a6a5e8b4
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)
@@ -175,6 +165,77 @@ Post.count_tags
175
165
  Post.tags.group(:tag).count
176
166
  ```
177
167
 
168
+ #### any_#{tag_name}(value, delimiter = ',')
169
+ It will create some scopes, this is useful for using ransack
170
+ ```Ruby
171
+ Post.any_tags(['food', 'travel'])
172
+
173
+ # equal to
174
+ Post.where(any_tags: ['food', 'travel'])
175
+ ```
176
+
177
+ Scope support string input
178
+ ```Ruby
179
+ Post.any_tags('food,travel')
180
+ Post.any_tags('food|travel', '|')
181
+ ```
182
+
183
+ #### all_#{tag_name}(value, delimiter = ',')
184
+ ```Ruby
185
+ Post.all_tags(['food', 'travel'])
186
+
187
+ # equal to
188
+ Post.where(all_tags: ['food', 'travel'])
189
+ ```
190
+
191
+ #### #{tag_name}_in(value, delimiter = ',')
192
+ ```Ruby
193
+ Post.tags_in(['food', 'travel'])
194
+
195
+ # equal to
196
+ Post.where(tags_in: ['food', 'travel'])
197
+ ```
198
+
199
+ #### #{tag_name}_eq(value, delimiter = ',')
200
+ ```Ruby
201
+ Post.tags_eq(['food', 'travel'])
202
+
203
+ # equal to
204
+ Post.where(tags_eq: ['food', 'travel'])
205
+ ```
206
+
207
+ #### not_any_#{tag_name}(value, delimiter = ',')
208
+ ```Ruby
209
+ Post.not_any_tags(['food', 'travel'])
210
+
211
+ # equal to
212
+ Post.where.not(any_tags: ['food', 'travel'])
213
+ ```
214
+
215
+ #### not_all_#{tag_name}(value, delimiter = ',')
216
+ ```Ruby
217
+ Post.not_all_tags(['food', 'travel'])
218
+
219
+ # equal to
220
+ Post.where.not(all_tags: ['food', 'travel'])
221
+ ```
222
+
223
+ #### not_#{tag_name}_in(value, delimiter = ',')
224
+ ```Ruby
225
+ Post.not_tags_in(['food', 'travel'])
226
+
227
+ # equal to
228
+ Post.where.not(tags_in: ['food', 'travel'])
229
+ ```
230
+
231
+ #### not_#{tag_name}_eq(value, delimiter = ',')
232
+ ```Ruby
233
+ Post.not_tags_eq(['food', 'travel'])
234
+
235
+ # equal to
236
+ Post.where.not(tags_eq: ['food', 'travel'])
237
+ ```
238
+
178
239
  ### Case Insensitive
179
240
  If you use `string` type, it is case sensitive.
180
241
  ```Ruby
@@ -209,6 +270,21 @@ post.tags
209
270
  # => ['food', 'travel']
210
271
  ```
211
272
 
273
+ ### Ransack
274
+ You can use with ransack
275
+ ```Ruby
276
+ class Post < ActiveRecord::Base
277
+ def self.ransackable_scopes(_auth_object = nil)
278
+ %i[all_tags]
279
+ end
280
+ end
281
+ ```
282
+
283
+ And you can search
284
+ ```Ruby
285
+ Post.ransack(all_tags: 'foold,travel')
286
+ ```
287
+
212
288
  ## License
213
289
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
214
290
 
@@ -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
@@ -16,13 +16,14 @@ module PgTaggable
16
16
 
17
17
  def taggable(name, unique: true)
18
18
  type = type_for_attribute(name)
19
- @@taggable_attributes ||= {}
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
@@ -35,6 +36,10 @@ module PgTaggable
35
36
  scope name, -> { unscope(:where).from(select("UNNEST(#{table_name}.#{name}) AS tag"), table_name) }
36
37
  scope "uniq_#{name}", -> { public_send(name).distinct.pluck(:tag) }
37
38
  scope "count_#{name}", -> { public_send(name).group(:tag).count }
39
+ taggable_attributes.keys.each do |key|
40
+ scope key, ->(value, delimiter = ',') { where(key => value.is_a?(Array) ? value : value.split(delimiter)) }
41
+ scope "not_#{key}", ->(value, delimiter = ',') { where.not(key => value.is_a?(Array) ? value : value.split(delimiter)) }
42
+ end
38
43
  end
39
44
  end
40
45
  end
@@ -1,3 +1,3 @@
1
1
  module PgTaggable
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
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.1.0
4
+ version: 0.2.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-04-05 00:00:00.000000000 Z
11
+ date: 2025-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails