metka 2.0.1 → 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE.md +15 -0
- data/.github/workflows/docs.yml +57 -0
- data/.github/workflows/rspec.yml +84 -0
- data/.github/workflows/rubocop.yml +21 -0
- data/.gitignore +3 -1
- data/.mdlrc +1 -0
- data/.rubocop-md.yml +20 -0
- data/.rubocop.yml +1 -2
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +3 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +128 -131
- data/README.md +72 -50
- data/forspell.dict +7 -0
- data/gemfiles/rails52.gemfile +2 -2
- data/gemfiles/rails6.gemfile +2 -2
- data/gemfiles/rails61.gemfile +6 -0
- data/gemfiles/{rails5.gemfile → railsmaster.gemfile} +1 -2
- data/gemfiles/rubocop.gemfile +4 -0
- data/lib/metka/generic_parser.rb +2 -2
- data/lib/metka/model.rb +5 -5
- data/lib/metka/query_builder.rb +8 -6
- data/lib/metka/query_builder/base_query.rb +37 -16
- data/lib/metka/version.rb +1 -1
- data/metka.gemspec +1 -2
- metadata +19 -25
- data/.github/workflows/continuous-integration-workflow.yml +0 -11
- data/.travis.yml +0 -35
data/README.md
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
[![Gem Version](https://badge.fury.io/rb/metka.svg)](https://badge.fury.io/rb/metka)
|
2
|
-
[![Build Status](https://
|
2
|
+
[![Build Status](https://github.com/jetrockets/metka/workflows/Build/badge.svg?branch=master)](https://github.com/jetrockets/metka/actions)
|
3
3
|
[![Open Source Helpers](https://www.codetriage.com/jetrockets/metka/badges/users.svg)](https://www.codetriage.com/jetrockets/metka)
|
4
4
|
|
5
5
|
# Metka
|
6
6
|
|
7
7
|
Rails gem to manage tags with PostgreSQL array columns.
|
8
8
|
|
9
|
+
:exclamation: Requirements:
|
10
|
+
|
11
|
+
* Ruby ~> 2.5
|
12
|
+
* Rails >= 5.2 (for Rails 5.1 and 5.0 use version <2.1.0)
|
13
|
+
|
9
14
|
## Installation
|
10
15
|
|
11
16
|
Add this line to your application's Gemfile:
|
@@ -16,11 +21,15 @@ gem 'metka'
|
|
16
21
|
|
17
22
|
And then execute:
|
18
23
|
|
19
|
-
|
24
|
+
```bash
|
25
|
+
bundle
|
26
|
+
```
|
20
27
|
|
21
28
|
Or install it yourself as:
|
22
29
|
|
23
|
-
|
30
|
+
```bash
|
31
|
+
gem install metka
|
32
|
+
```
|
24
33
|
|
25
34
|
## Tag objects
|
26
35
|
|
@@ -32,9 +41,9 @@ rails g migration CreateSongs
|
|
32
41
|
class CreateSongs < ActiveRecord::Migration[5.0]
|
33
42
|
def change
|
34
43
|
create_table :songs do |t|
|
35
|
-
t.string
|
36
|
-
t.string
|
37
|
-
t.string
|
44
|
+
t.string :title
|
45
|
+
t.string :tags, array: true, default: [], index: { using: :gin }
|
46
|
+
t.string :genres, array: true, default: [], index: { using: :gin }
|
38
47
|
t.timestamps
|
39
48
|
end
|
40
49
|
end
|
@@ -55,140 +64,152 @@ end
|
|
55
64
|
## Find tagged objects
|
56
65
|
|
57
66
|
### .with_all_#{column_name}
|
67
|
+
|
58
68
|
```ruby
|
59
69
|
Song.with_all_tags('top')
|
60
|
-
|
70
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
61
71
|
|
62
72
|
Song.with_all_tags('top, 1990')
|
63
|
-
|
73
|
+
#=> []
|
64
74
|
|
65
75
|
Song.with_all_tags('')
|
66
|
-
|
76
|
+
#=> []
|
67
77
|
|
68
78
|
Song.with_all_genres('rock')
|
69
|
-
|
79
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
70
80
|
```
|
71
81
|
|
72
82
|
### .with_any_#{column_name}
|
83
|
+
|
73
84
|
```ruby
|
74
85
|
Song.with_any_tags('chill')
|
75
|
-
|
86
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
76
87
|
|
77
88
|
Song.with_any_tags('chill, 1980')
|
78
|
-
|
89
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
79
90
|
|
80
91
|
Song.with_any_tags('')
|
81
|
-
|
92
|
+
#=> []
|
82
93
|
|
83
94
|
Song.with_any_genres('rock, rap')
|
84
|
-
|
95
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
85
96
|
```
|
97
|
+
|
86
98
|
### .without_all_#{column_name}
|
99
|
+
|
87
100
|
```ruby
|
88
101
|
Song.without_all_tags('top')
|
89
|
-
|
102
|
+
#=> []
|
90
103
|
|
91
104
|
Song.without_all_tags('top, 1990')
|
92
|
-
|
105
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
93
106
|
|
94
107
|
Song.without_all_tags('')
|
95
|
-
|
108
|
+
#=> []
|
96
109
|
|
97
110
|
Song.without_all_genres('rock, pop')
|
98
|
-
|
111
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
99
112
|
|
100
113
|
Song.without_all_genres('rock')
|
101
|
-
|
114
|
+
#=> []
|
102
115
|
```
|
103
116
|
|
104
117
|
### .without_any_#{column_name}
|
118
|
+
|
105
119
|
```ruby
|
106
120
|
Song.without_any_tags('top, 1990')
|
107
|
-
|
121
|
+
#=> []
|
108
122
|
|
109
123
|
Song.without_any_tags('1990, 1980')
|
110
|
-
|
124
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
111
125
|
|
112
126
|
Song.without_any_genres('rock, pop')
|
113
|
-
|
127
|
+
#=> []
|
114
128
|
|
115
129
|
Song.without_any_genres('')
|
116
|
-
|
130
|
+
#=> []
|
117
131
|
```
|
118
132
|
|
119
133
|
### .tagged_with
|
134
|
+
|
120
135
|
```ruby
|
121
136
|
Song.tagged_with('top')
|
122
|
-
|
137
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
123
138
|
|
124
139
|
Song.tagged_with('top, 1990')
|
125
|
-
|
140
|
+
#=> []
|
126
141
|
|
127
142
|
Song.tagged_with('')
|
128
|
-
|
143
|
+
#=> []
|
129
144
|
|
130
145
|
Song.tagged_with('rock')
|
131
|
-
|
146
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
132
147
|
|
133
148
|
Song.tagged_with('rock', join_operator: Metka::And)
|
134
|
-
|
149
|
+
#=> []
|
135
150
|
|
136
151
|
Song.tagged_with('chill', any: true)
|
137
|
-
|
152
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
138
153
|
|
139
154
|
Song.tagged_with('chill, 1980', any: true)
|
140
|
-
|
155
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
141
156
|
|
142
157
|
Song.tagged_with('', any: true)
|
143
|
-
|
158
|
+
#=> []
|
144
159
|
|
145
160
|
Song.tagged_with('rock, rap', any: true, on: ['genres'])
|
146
|
-
|
161
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
147
162
|
|
148
163
|
Song.without_all_tags('top')
|
149
|
-
|
164
|
+
#=> []
|
150
165
|
|
151
166
|
Song.tagged_with('top, 1990', exclude: true)
|
152
|
-
|
167
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
153
168
|
|
154
169
|
Song.tagged_with('', exclude: true)
|
155
|
-
|
170
|
+
#=> []
|
156
171
|
|
157
172
|
Song.tagged_with('top, 1990', any: true, exclude: true)
|
158
|
-
|
173
|
+
#=> []
|
159
174
|
|
160
175
|
Song.tagged_with('1990, 1980', any: true, exclude: true)
|
161
|
-
|
176
|
+
#=> [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
|
162
177
|
|
163
178
|
Song.without_any_genres('rock, pop')
|
164
|
-
|
179
|
+
#=> []
|
165
180
|
```
|
166
181
|
|
167
182
|
## Custom delimiter
|
183
|
+
|
168
184
|
By default, a comma is used as a delimiter to create tags from a string.
|
169
185
|
You can make your own custom separator:
|
186
|
+
|
170
187
|
```ruby
|
171
188
|
Metka.config.delimiter = '|'
|
172
189
|
parsed_data = Metka::GenericParser.instance.call('cool, data|I have')
|
173
190
|
parsed_data.to_a
|
174
|
-
|
191
|
+
#=>['cool, data', 'I have']
|
175
192
|
```
|
176
193
|
|
177
194
|
## Tags with quote
|
195
|
+
|
178
196
|
```ruby
|
179
197
|
parsed_data = Metka::GenericParser.instance.call("'cool, data', code")
|
180
198
|
parsed_data.to_a
|
181
|
-
|
199
|
+
#=> ['cool, data', 'code']
|
182
200
|
```
|
183
201
|
|
184
202
|
## Custom parser
|
203
|
+
|
185
204
|
By default we use [generic_parser](lib/metka/generic_parser.rb "generic_parser")
|
186
205
|
If you want to use your custom parser you can do:
|
206
|
+
|
187
207
|
```ruby
|
188
208
|
class Song < ActiveRecord::Base
|
189
209
|
include Metka::Model(columns: %w[genres tags], parser: Your::Custom::Parser.instance)
|
190
210
|
end
|
191
211
|
```
|
212
|
+
|
192
213
|
Custom parser must be a singleton class that has a `.call` method that accepts the tag string
|
193
214
|
|
194
215
|
## Tag Cloud Strategies
|
@@ -200,29 +221,30 @@ There are several strategies to get tag statistics
|
|
200
221
|
Data about taggings is accessible via class methods of your model with `Metka::Model` attached. You can calculate a cloud for a single tagged column or multiple columns, the latter case would return to you a sum of taggings from multiple tagged columns, that are provided as arguments, for each tag present. ActiveRecord Strategy is an easiest way to implement, since it wouldn't require any additional code, but it's the slowest one on SELECT.
|
201
222
|
|
202
223
|
```ruby
|
224
|
+
|
203
225
|
class Book < ActiveRecord::Base
|
204
226
|
include Metka::Model(column: 'authors')
|
205
227
|
include Metka::Model(column: 'co_authors')
|
206
228
|
end
|
207
229
|
|
208
230
|
tag_cloud = Book.author_cloud
|
209
|
-
|
231
|
+
#=> [["L.N. Tolstoy", 3], ["F.M. Dostoevsky", 6]]
|
210
232
|
genre_cloud = Book.co_author_cloud
|
211
|
-
|
233
|
+
#=> [["A.P. Chekhov", 5], ["N.V. Gogol", 8], ["L.N. Tolstoy", 2]]
|
212
234
|
summary_cloud = Book.metka_cloud('authors', 'co_authors')
|
213
|
-
|
235
|
+
#=> [["L.N. Tolstoy", 5], ["F.M. Dostoevsky", 6], ["A.P. Chekhov", 5], ["N.V. Gogol", 8]]
|
214
236
|
```
|
215
237
|
|
216
238
|
### View Strategy
|
217
239
|
|
218
|
-
Data about taggings will be
|
240
|
+
Data about taggings will be aggregated in SQL View. Performance-wise that strategy has no benefits over ActiveRecord Strategy, but if you need to store tags aggregations in a distinct model, that's an easiest way to achieve it.
|
219
241
|
|
220
242
|
```bash
|
221
243
|
rails g metka:strategies:view --source-table-name=NAME_OF_TABLE_WITH_TAGS [--source-columns=NAME_OF_COLUMN_1 NAME_OF_COLUMN_2] [--view-name=NAME_OF_RESULTING_VIEW]
|
222
244
|
```
|
223
245
|
|
224
246
|
The code above will generate a migration that creates view with specified `NAME_OF_RESULTING_VIEW`, that would aggregate tags data from specified array of tagged columns [`NAME_OF_COLUMN_1`, `NAME_OF_COLUMN_2`, ...], that are present within specified table `NAME_OF_TABLE_WITH_TAGS`.
|
225
|
-
If `source-columns` option is not provided, then `tags` column would be used as defaults. If array of multiple values would be provided to the option, then the aggregation would be made with the tags from multiple tagged columns, so if a single tag would be found within multiple tagged columns, the resulting aggregation inside the view would have a single row for that tag with a sum of it's
|
247
|
+
If `source-columns` option is not provided, then `tags` column would be used as defaults. If array of multiple values would be provided to the option, then the aggregation would be made with the tags from multiple tagged columns, so if a single tag would be found within multiple tagged columns, the resulting aggregation inside the view would have a single row for that tag with a sum of it's occurrences across all stated tagged columns.
|
226
248
|
`view-name` option is also optional, it would just force the resulting view's name to the one of your choice. If it's not provided, then view name would be generated automatically, you could check it within generated migration.
|
227
249
|
|
228
250
|
Lets take a look at real example. We have a `notes` table with `tags` column.
|
@@ -290,7 +312,7 @@ Data about taggings will be aggregated in SQL Materialized View, that would be r
|
|
290
312
|
rails g metka:strategies:materialized_view --source-table-name=NAME_OF_TABLE_WITH_TAGS --source-columns=NAME_OF_COLUMN_1 NAME_OF_COLUMN_2 --view-name=NAME_OF_RESULTING_VIEW
|
291
313
|
```
|
292
314
|
|
293
|
-
All of the options for that
|
315
|
+
All of the options for that strategy's generation command are the same as for the View Strategy.
|
294
316
|
|
295
317
|
The migration template can be seen [here](spec/dummy/db/migrate/06_create_tagged_materialized_view_posts_materialized_view.rb "here")
|
296
318
|
|
@@ -308,11 +330,10 @@ And you can also create `TaggedNote` model to work with the view as with a Rails
|
|
308
330
|
|
309
331
|
### Table Strategy with Triggers
|
310
332
|
|
311
|
-
|
312
|
-
|
313
333
|
TBD
|
314
334
|
|
315
335
|
## Inspired by
|
336
|
+
|
316
337
|
1. [ActsAsTaggableOn](https://github.com/mbleigh/acts-as-taggable-on)
|
317
338
|
2. [ActsAsTaggableArrayOn](https://github.com/tmiyamon/acts-as-taggable-array-on)
|
318
339
|
3. [TagColumns](https://github.com/hopsoft/tag_columns)
|
@@ -447,10 +468,11 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
447
468
|
|
448
469
|
## Contributing
|
449
470
|
|
450
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
471
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/jetrockets/metka](https://github.com/jetrockets/metka). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
451
472
|
|
452
473
|
## Credits
|
453
|
-
|
474
|
+
|
475
|
+
![JetRockets](https://media.jetrockets.pro/jetrockets-white.png)
|
454
476
|
Metka is maintained by [JetRockets](http://www.jetrockets.ru).
|
455
477
|
|
456
478
|
## License
|
data/forspell.dict
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# Format: one word per line. Empty lines and #-comments are supported too.
|
2
|
+
# If you want to add word with its forms, you can write 'word: example' (without quotes) on the line,
|
3
|
+
# where 'example' is existing word with the same possible forms (endings) as your word.
|
4
|
+
# Example: deduplicate: duplicate
|
5
|
+
Metka
|
6
|
+
taggings
|
7
|
+
benchmarked
|
data/gemfiles/rails52.gemfile
CHANGED
data/gemfiles/rails6.gemfile
CHANGED
data/lib/metka/generic_parser.rb
CHANGED
@@ -25,7 +25,7 @@ module Metka
|
|
25
25
|
gsub_quote_pattern!(tag_list, value, double_quote_pattern)
|
26
26
|
gsub_quote_pattern!(tag_list, value, single_quote_pattern)
|
27
27
|
|
28
|
-
tag_list.merge value.split(Regexp.new
|
28
|
+
tag_list.merge value.split(Regexp.new(delimiter)).map(&:strip).reject(&:empty?)
|
29
29
|
when Enumerable
|
30
30
|
tag_list.merge value.reject(&:empty?)
|
31
31
|
end
|
@@ -46,7 +46,7 @@ module Metka
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def single_quote_pattern
|
49
|
-
|
49
|
+
@single_quote_pattern[delimiter] ||= /(\A|#{delimiter})\s*'(.*?)'\s*(?=#{delimiter}\s*|\z)/
|
50
50
|
end
|
51
51
|
|
52
52
|
def double_quote_pattern
|
data/lib/metka/model.rb
CHANGED
@@ -43,10 +43,10 @@ module Metka
|
|
43
43
|
|
44
44
|
base.class_eval do
|
45
45
|
columns.each do |column|
|
46
|
-
scope "with_all_#{column}",
|
47
|
-
scope "with_any_#{column}",
|
48
|
-
scope "without_all_#{column}", ->(tags) { tagged_with(tags, on: [
|
49
|
-
scope "without_any_#{column}", ->(tags) { tagged_with(tags, on: [
|
46
|
+
scope "with_all_#{column}", ->(tags) { tagged_with(tags, on: [column]) }
|
47
|
+
scope "with_any_#{column}", ->(tags) { tagged_with(tags, on: [column], any: true) }
|
48
|
+
scope "without_all_#{column}", ->(tags) { tagged_with(tags, on: [column], exclude: true) }
|
49
|
+
scope "without_any_#{column}", ->(tags) { tagged_with(tags, on: [column], any: true, exclude: true) }
|
50
50
|
end
|
51
51
|
|
52
52
|
unless respond_to?(:tagged_with)
|
@@ -66,7 +66,7 @@ module Metka
|
|
66
66
|
prepared_unnest = columns.map { |column| "#{table_name}.#{column}" }.join(' || ')
|
67
67
|
subquery = all.select("UNNEST(#{prepared_unnest}) AS tag_name")
|
68
68
|
|
69
|
-
unscoped.from(subquery).group(:tag_name).pluck(:tag_name, 'COUNT(*) AS taggings_count')
|
69
|
+
unscoped.from(subquery).group(:tag_name).pluck(:tag_name, Arel.sql('COUNT(*) AS taggings_count'))
|
70
70
|
end
|
71
71
|
|
72
72
|
columns.each do |column|
|
data/lib/metka/query_builder.rb
CHANGED
@@ -10,11 +10,11 @@ module Metka
|
|
10
10
|
def call(model, columns, tags, options)
|
11
11
|
strategy = options_to_strategy(options)
|
12
12
|
|
13
|
-
query = join(options[:join_operator])
|
13
|
+
query = join(options[:join_operator]) {
|
14
14
|
columns.map do |column|
|
15
15
|
build_query(strategy, model, column, tags)
|
16
16
|
end
|
17
|
-
|
17
|
+
}
|
18
18
|
|
19
19
|
if options[:exclude].present?
|
20
20
|
Arel::Nodes::Not.new(query)
|
@@ -25,7 +25,7 @@ module Metka
|
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
-
def options_to_strategy
|
28
|
+
def options_to_strategy(options)
|
29
29
|
if options[:any].present?
|
30
30
|
AnyTagsQuery
|
31
31
|
else
|
@@ -43,11 +43,13 @@ module Metka
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
# @param nodes [Array<Arel::Node>, Arel::Node]
|
47
|
-
# @return [Arel::Node]
|
46
|
+
# @param nodes [Array<Arel::Nodes::Node>, Arel::Nodes::Node]
|
47
|
+
# @return [Arel::Nodes::Node]
|
48
48
|
def join_or(nodes)
|
49
|
+
node_base_klass = defined?(::Arel::Nodes::Node) ? ::Arel::Nodes::Node : ::Arel::Node
|
50
|
+
|
49
51
|
case nodes
|
50
|
-
when
|
52
|
+
when node_base_klass
|
51
53
|
nodes
|
52
54
|
when Array
|
53
55
|
l, *r = nodes
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'singleton'
|
3
4
|
|
4
5
|
module Metka
|
@@ -6,22 +7,42 @@ module Metka
|
|
6
7
|
include Singleton
|
7
8
|
|
8
9
|
def call(model, column_name, tag_list)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
10
|
+
tags = tag_list.to_a
|
11
|
+
|
12
|
+
if tags.one?
|
13
|
+
value = Arel::Nodes::SqlLiteral.new(
|
14
|
+
ActiveRecord::Base.sanitize_sql_for_conditions(['?', tags.first])
|
15
|
+
)
|
16
|
+
|
17
|
+
column_cast = Arel::Nodes::NamedFunction.new(
|
18
|
+
'ANY',
|
19
|
+
[model.arel_table[column_name]]
|
20
|
+
)
|
21
|
+
|
22
|
+
Arel::Nodes::Equality.new(value, column_cast)
|
23
|
+
else
|
24
|
+
value = Arel::Nodes::SqlLiteral.new(
|
25
|
+
ActiveRecord::Base.sanitize_sql_for_conditions(['ARRAY[?]::varchar[]', tags])
|
26
|
+
)
|
27
|
+
|
28
|
+
Arel::Nodes::InfixOperation.new(infix_operator, model.arel_table[column_name], value)
|
29
|
+
end
|
30
|
+
# column_cast = Arel::Nodes::NamedFunction.new(
|
31
|
+
# 'CAST',
|
32
|
+
# [model.arel_table[column_name].as('text[]')]
|
33
|
+
# )
|
34
|
+
|
35
|
+
# value = Arel::Nodes::SqlLiteral.new(
|
36
|
+
# ActiveRecord::Base.sanitize_sql_for_conditions(['ARRAY[?]::varchar[]', tag_list.to_a])
|
37
|
+
# )
|
38
|
+
|
39
|
+
# value_cast = Arel::Nodes::NamedFunction.new(
|
40
|
+
# 'CAST',
|
41
|
+
# [value.as('text[]')]
|
42
|
+
# )
|
43
|
+
|
44
|
+
# # Arel::Nodes::InfixOperation.new(infix_operator, column_cast, value_cast)
|
45
|
+
# Arel::Nodes::InfixOperation.new(infix_operator, model.arel_table[column_name], value)
|
25
46
|
end
|
26
47
|
end
|
27
48
|
end
|