metka 1.0.3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3c0565e7e049ea911c9039ef193104c7bf7e7213a12bbd3ca804fa0f3a3ce9f
4
- data.tar.gz: 11e33a74f78aca7fa1942702fd2dd550c232dde0bdab414ec2cbe3ddec8ffaa0
3
+ metadata.gz: 1ea5e1ca3ea95cdb4f0beb2704afc1d92986b0a7c38aa49a70e794b2653c5764
4
+ data.tar.gz: e9994da8c7db21d1d079c5464d2ffae2bf06ee742f2a664df505f144b1d995be
5
5
  SHA512:
6
- metadata.gz: 76749d9965518aaacc8e592a569c9a4a57885647b99b6df4aecd7574536658c5d8e2259a9b344bb2bfe44cdd506eff95a73530f775778151253d92e3e081d531
7
- data.tar.gz: e29dea73313396cf64d120b5cbdde93b42902442962243925ae25c541b9b7fab361d4be7b81ccc83e946d03f34c7995475d37d6c869ad54d50b2981b6544f322
6
+ metadata.gz: 5c8da36cf3bec90c63888d24ac7d09dbec00219ca547df88289b3f858c25eb7f6a0ca729ee46021bfe47f7086a0cb7209a309ae95d8a88bb1b696acd0e772901
7
+ data.tar.gz: 4f7791a9be469c60ed1505d9f037653eccb0e81c1dcb18954c90daca440264eb9c0ca57067770c4d7222a86b2fca1c6a0ae1ad977becaad7d92ecda5ebf4513a
@@ -19,7 +19,7 @@ Style/TrailingCommaInArrayLiteral:
19
19
  Style/TrailingCommaInHashLiteral:
20
20
  EnforcedStyleForMultiline: no_comma
21
21
 
22
- Layout/AlignParameters:
22
+ Layout/ParameterAlignment:
23
23
  EnforcedStyle: with_first_parameter
24
24
 
25
25
  # See https://github.com/rubocop-hq/rubocop/issues/4222
@@ -0,0 +1 @@
1
+ 2.7.2
@@ -22,7 +22,6 @@ before_install:
22
22
  - sudo service postgresql restart 11
23
23
 
24
24
  before_script:
25
- # - gem update --system
26
25
  - psql -c 'CREATE ROLE travis SUPERUSER LOGIN CREATEDB;' -U postgres
27
26
  - ./bin/setup
28
27
 
@@ -34,3 +33,5 @@ matrix:
34
33
  gemfile: gemfiles/rails52.gemfile
35
34
  - rvm: 2.6.2
36
35
  gemfile: gemfiles/rails6.gemfile
36
+ - rvm: 2.7.2
37
+ gemfile: gemfiles/rails61.gemfile
data/Gemfile CHANGED
@@ -8,5 +8,5 @@ local_gemfile = "#{File.dirname(__FILE__)}/Gemfile.local"
8
8
  if File.exist?(local_gemfile)
9
9
  eval(File.read(local_gemfile)) # rubocop:disable Lint/Eval
10
10
  else
11
- gem 'activerecord', '~> 5.1.1'
11
+ gem 'activerecord', '>= 5.2.4', '< 6.2'
12
12
  end
@@ -1,46 +1,50 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- metka (1.0.3)
4
+ metka (2.0.3)
5
5
  dry-configurable (>= 0.8)
6
6
  rails (>= 5.1)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- actioncable (5.1.7)
12
- actionpack (= 5.1.7)
11
+ actioncable (5.2.4.4)
12
+ actionpack (= 5.2.4.4)
13
13
  nio4r (~> 2.0)
14
- websocket-driver (~> 0.6.1)
15
- actionmailer (5.1.7)
16
- actionpack (= 5.1.7)
17
- actionview (= 5.1.7)
18
- activejob (= 5.1.7)
14
+ websocket-driver (>= 0.6.1)
15
+ actionmailer (5.2.4.4)
16
+ actionpack (= 5.2.4.4)
17
+ actionview (= 5.2.4.4)
18
+ activejob (= 5.2.4.4)
19
19
  mail (~> 2.5, >= 2.5.4)
20
20
  rails-dom-testing (~> 2.0)
21
- actionpack (5.1.7)
22
- actionview (= 5.1.7)
23
- activesupport (= 5.1.7)
24
- rack (~> 2.0)
21
+ actionpack (5.2.4.4)
22
+ actionview (= 5.2.4.4)
23
+ activesupport (= 5.2.4.4)
24
+ rack (~> 2.0, >= 2.0.8)
25
25
  rack-test (>= 0.6.3)
26
26
  rails-dom-testing (~> 2.0)
27
27
  rails-html-sanitizer (~> 1.0, >= 1.0.2)
28
- actionview (5.1.7)
29
- activesupport (= 5.1.7)
28
+ actionview (5.2.4.4)
29
+ activesupport (= 5.2.4.4)
30
30
  builder (~> 3.1)
31
31
  erubi (~> 1.4)
32
32
  rails-dom-testing (~> 2.0)
33
33
  rails-html-sanitizer (~> 1.0, >= 1.0.3)
34
- activejob (5.1.7)
35
- activesupport (= 5.1.7)
34
+ activejob (5.2.4.4)
35
+ activesupport (= 5.2.4.4)
36
36
  globalid (>= 0.3.6)
37
- activemodel (5.1.7)
38
- activesupport (= 5.1.7)
39
- activerecord (5.1.7)
40
- activemodel (= 5.1.7)
41
- activesupport (= 5.1.7)
42
- arel (~> 8.0)
43
- activesupport (5.1.7)
37
+ activemodel (5.2.4.4)
38
+ activesupport (= 5.2.4.4)
39
+ activerecord (5.2.4.4)
40
+ activemodel (= 5.2.4.4)
41
+ activesupport (= 5.2.4.4)
42
+ arel (>= 9.0)
43
+ activestorage (5.2.4.4)
44
+ actionpack (= 5.2.4.4)
45
+ activerecord (= 5.2.4.4)
46
+ marcel (~> 0.3.1)
47
+ activesupport (5.2.4.4)
44
48
  concurrent-ruby (~> 1.0, >= 1.0.2)
45
49
  i18n (>= 0.7, < 2)
46
50
  minitest (~> 5.1)
@@ -49,141 +53,152 @@ GEM
49
53
  activesupport (>= 3.0)
50
54
  railties (>= 3.0)
51
55
  rspec-rails (>= 2.2)
52
- arel (8.0.0)
53
- ast (2.4.0)
54
- builder (3.2.3)
55
- coderay (1.1.2)
56
- concurrent-ruby (1.1.5)
57
- crass (1.0.5)
58
- database_cleaner (1.7.0)
59
- diff-lcs (1.3)
60
- dry-configurable (0.11.3)
56
+ arel (9.0.0)
57
+ ast (2.4.1)
58
+ builder (3.2.4)
59
+ coderay (1.1.3)
60
+ concurrent-ruby (1.1.7)
61
+ crass (1.0.6)
62
+ database_cleaner (1.8.5)
63
+ diff-lcs (1.4.4)
64
+ dry-configurable (0.11.6)
61
65
  concurrent-ruby (~> 1.0)
62
66
  dry-core (~> 0.4, >= 0.4.7)
63
67
  dry-equalizer (~> 0.2)
64
- dry-core (0.4.9)
68
+ dry-core (0.5.0)
65
69
  concurrent-ruby (~> 1.0)
66
70
  dry-equalizer (0.3.0)
67
- erubi (1.9.0)
68
- faker (2.8.0)
69
- i18n (>= 1.6, < 1.8)
71
+ erubi (1.10.0)
72
+ faker (2.15.1)
73
+ i18n (>= 1.6, < 2)
70
74
  globalid (0.4.2)
71
75
  activesupport (>= 4.2.0)
72
- i18n (1.7.0)
76
+ i18n (1.8.5)
73
77
  concurrent-ruby (~> 1.0)
74
- jaro_winkler (1.5.4)
75
- jetrockets-standard (1.0.4)
76
- rubocop-rails (~> 2.3.2)
77
- rubocop-rspec (~> 1.35.0)
78
- standard (~> 0.1.4)
79
- loofah (2.4.0)
78
+ jetrockets-standard (1.0.7)
79
+ rubocop-rails (~> 2.8.1)
80
+ rubocop-rspec (~> 1.43.2)
81
+ standard (~> 0.6.1)
82
+ loofah (2.8.0)
80
83
  crass (~> 1.0.2)
81
84
  nokogiri (>= 1.5.9)
82
85
  mail (2.7.1)
83
86
  mini_mime (>= 0.1.1)
84
- method_source (0.9.2)
87
+ marcel (0.3.3)
88
+ mimemagic (~> 0.3.2)
89
+ method_source (1.0.0)
90
+ mimemagic (0.3.5)
85
91
  mini_mime (1.0.2)
86
92
  mini_portile2 (2.4.0)
87
- minitest (5.13.0)
88
- nio4r (2.5.2)
89
- nokogiri (1.10.8)
93
+ minitest (5.14.2)
94
+ nio4r (2.5.4)
95
+ nokogiri (1.10.10)
90
96
  mini_portile2 (~> 2.4.0)
91
- parallel (1.19.1)
92
- parser (2.6.5.0)
93
- ast (~> 2.4.0)
94
- pg (1.1.4)
95
- pry (0.12.2)
96
- coderay (~> 1.1.0)
97
- method_source (~> 0.9.0)
98
- rack (2.0.8)
97
+ parallel (1.20.1)
98
+ parser (2.7.2.0)
99
+ ast (~> 2.4.1)
100
+ pg (1.2.3)
101
+ pry (0.13.1)
102
+ coderay (~> 1.1)
103
+ method_source (~> 1.0)
104
+ rack (2.2.3)
99
105
  rack-test (1.1.0)
100
106
  rack (>= 1.0, < 3)
101
- rails (5.1.7)
102
- actioncable (= 5.1.7)
103
- actionmailer (= 5.1.7)
104
- actionpack (= 5.1.7)
105
- actionview (= 5.1.7)
106
- activejob (= 5.1.7)
107
- activemodel (= 5.1.7)
108
- activerecord (= 5.1.7)
109
- activesupport (= 5.1.7)
107
+ rails (5.2.4.4)
108
+ actioncable (= 5.2.4.4)
109
+ actionmailer (= 5.2.4.4)
110
+ actionpack (= 5.2.4.4)
111
+ actionview (= 5.2.4.4)
112
+ activejob (= 5.2.4.4)
113
+ activemodel (= 5.2.4.4)
114
+ activerecord (= 5.2.4.4)
115
+ activestorage (= 5.2.4.4)
116
+ activesupport (= 5.2.4.4)
110
117
  bundler (>= 1.3.0)
111
- railties (= 5.1.7)
118
+ railties (= 5.2.4.4)
112
119
  sprockets-rails (>= 2.0.0)
113
120
  rails-dom-testing (2.0.3)
114
121
  activesupport (>= 4.2.0)
115
122
  nokogiri (>= 1.6)
116
123
  rails-html-sanitizer (1.3.0)
117
124
  loofah (~> 2.3)
118
- railties (5.1.7)
119
- actionpack (= 5.1.7)
120
- activesupport (= 5.1.7)
125
+ railties (5.2.4.4)
126
+ actionpack (= 5.2.4.4)
127
+ activesupport (= 5.2.4.4)
121
128
  method_source
122
129
  rake (>= 0.8.7)
123
- thor (>= 0.18.1, < 2.0)
130
+ thor (>= 0.19.0, < 2.0)
124
131
  rainbow (3.0.0)
125
- rake (13.0.1)
126
- rspec (3.9.0)
127
- rspec-core (~> 3.9.0)
128
- rspec-expectations (~> 3.9.0)
129
- rspec-mocks (~> 3.9.0)
130
- rspec-core (3.9.0)
131
- rspec-support (~> 3.9.0)
132
- rspec-expectations (3.9.0)
132
+ rake (13.0.3)
133
+ regexp_parser (2.0.1)
134
+ rexml (3.2.4)
135
+ rspec (3.10.0)
136
+ rspec-core (~> 3.10.0)
137
+ rspec-expectations (~> 3.10.0)
138
+ rspec-mocks (~> 3.10.0)
139
+ rspec-core (3.10.0)
140
+ rspec-support (~> 3.10.0)
141
+ rspec-expectations (3.10.0)
133
142
  diff-lcs (>= 1.2.0, < 2.0)
134
- rspec-support (~> 3.9.0)
135
- rspec-mocks (3.9.0)
143
+ rspec-support (~> 3.10.0)
144
+ rspec-mocks (3.10.0)
136
145
  diff-lcs (>= 1.2.0, < 2.0)
137
- rspec-support (~> 3.9.0)
138
- rspec-rails (3.9.0)
139
- actionpack (>= 3.0)
140
- activesupport (>= 3.0)
141
- railties (>= 3.0)
142
- rspec-core (~> 3.9.0)
143
- rspec-expectations (~> 3.9.0)
144
- rspec-mocks (~> 3.9.0)
145
- rspec-support (~> 3.9.0)
146
- rspec-support (3.9.0)
147
- rubocop (0.75.1)
148
- jaro_winkler (~> 1.5.1)
146
+ rspec-support (~> 3.10.0)
147
+ rspec-rails (4.0.1)
148
+ actionpack (>= 4.2)
149
+ activesupport (>= 4.2)
150
+ railties (>= 4.2)
151
+ rspec-core (~> 3.9)
152
+ rspec-expectations (~> 3.9)
153
+ rspec-mocks (~> 3.9)
154
+ rspec-support (~> 3.9)
155
+ rspec-support (3.10.0)
156
+ rubocop (0.91.1)
149
157
  parallel (~> 1.10)
150
- parser (>= 2.6)
158
+ parser (>= 2.7.1.1)
151
159
  rainbow (>= 2.2.2, < 4.0)
160
+ regexp_parser (>= 1.7)
161
+ rexml
162
+ rubocop-ast (>= 0.4.0, < 1.0)
152
163
  ruby-progressbar (~> 1.7)
153
- unicode-display_width (>= 1.4.0, < 1.7)
154
- rubocop-performance (1.5.1)
155
- rubocop (>= 0.71.0)
156
- rubocop-rails (2.3.2)
164
+ unicode-display_width (>= 1.4.0, < 2.0)
165
+ rubocop-ast (0.8.0)
166
+ parser (>= 2.7.1.5)
167
+ rubocop-performance (1.8.1)
168
+ rubocop (>= 0.87.0)
169
+ rubocop-ast (>= 0.4.0)
170
+ rubocop-rails (2.8.1)
171
+ activesupport (>= 4.2.0)
157
172
  rack (>= 1.1)
158
- rubocop (>= 0.72.0)
159
- rubocop-rspec (1.35.0)
160
- rubocop (>= 0.60.0)
173
+ rubocop (>= 0.87.0)
174
+ rubocop-rspec (1.43.2)
175
+ rubocop (~> 0.87)
161
176
  ruby-progressbar (1.10.1)
162
- sprockets (4.0.0)
177
+ sprockets (4.0.2)
163
178
  concurrent-ruby (~> 1.0)
164
179
  rack (> 1, < 3)
165
- sprockets-rails (3.2.1)
180
+ sprockets-rails (3.2.2)
166
181
  actionpack (>= 4.0)
167
182
  activesupport (>= 4.0)
168
183
  sprockets (>= 3.0.0)
169
- standard (0.1.6)
170
- rubocop (~> 0.75.0)
171
- rubocop-performance (~> 1.5.0)
172
- thor (0.20.3)
184
+ standard (0.6.2)
185
+ rubocop (= 0.91.1)
186
+ rubocop-performance (= 1.8.1)
187
+ thor (1.0.1)
173
188
  thread_safe (0.3.6)
174
- timecop (0.9.1)
175
- tzinfo (1.2.5)
189
+ timecop (0.9.2)
190
+ tzinfo (1.2.9)
176
191
  thread_safe (~> 0.1)
177
- unicode-display_width (1.6.0)
178
- websocket-driver (0.6.5)
192
+ unicode-display_width (1.7.0)
193
+ websocket-driver (0.7.3)
179
194
  websocket-extensions (>= 0.1.0)
180
- websocket-extensions (0.1.4)
195
+ websocket-extensions (0.1.5)
181
196
 
182
197
  PLATFORMS
183
198
  ruby
184
199
 
185
200
  DEPENDENCIES
186
- activerecord (~> 5.1.1)
201
+ activerecord (>= 5.2.4, < 6.2)
187
202
  ammeter (>= 1.1)
188
203
  bundler (>= 1.3)
189
204
  database_cleaner (>= 1.7)
@@ -198,4 +213,4 @@ DEPENDENCIES
198
213
  timecop (>= 0.9)
199
214
 
200
215
  BUNDLED WITH
201
- 2.0.2
216
+ 2.1.4
data/README.md CHANGED
@@ -43,8 +43,7 @@ end
43
43
 
44
44
  ```ruby
45
45
  class Song < ActiveRecord::Base
46
- include Metka::Model(column: 'tags')
47
- include Metka::Model(column: 'genres')
46
+ include Metka::Model(columns: %w[genres tags])
48
47
  end
49
48
 
50
49
  @song = Song.new(title: 'Migrate tags in Rails to PostgreSQL')
@@ -93,7 +92,7 @@ Song.without_all_tags('top, 1990')
93
92
  => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
94
93
 
95
94
  Song.without_all_tags('')
96
- => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
95
+ => []
97
96
 
98
97
  Song.without_all_genres('rock, pop')
99
98
  => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
@@ -114,17 +113,65 @@ Song.without_any_genres('rock, pop')
114
113
  => []
115
114
 
116
115
  Song.without_any_genres('')
116
+ => []
117
+ ```
118
+
119
+ ### .tagged_with
120
+ ```ruby
121
+ Song.tagged_with('top')
122
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
123
+
124
+ Song.tagged_with('top, 1990')
125
+ => []
126
+
127
+ Song.tagged_with('')
128
+ => []
129
+
130
+ Song.tagged_with('rock')
131
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
132
+
133
+ Song.tagged_with('rock', join_operator: Metka::And)
134
+ => []
135
+
136
+ Song.tagged_with('chill', any: true)
137
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
138
+
139
+ Song.tagged_with('chill, 1980', any: true)
140
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
141
+
142
+ Song.tagged_with('', any: true)
143
+ => []
144
+
145
+ Song.tagged_with('rock, rap', any: true, on: ['genres'])
117
146
  => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
147
+
148
+ Song.without_all_tags('top')
149
+ => []
150
+
151
+ Song.tagged_with('top, 1990', exclude: true)
152
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
153
+
154
+ Song.tagged_with('', exclude: true)
155
+ => []
156
+
157
+ Song.tagged_with('top, 1990', any: true, exclude: true)
158
+ => []
159
+
160
+ Song.tagged_with('1990, 1980', any: true, exclude: true)
161
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
162
+
163
+ Song.without_any_genres('rock, pop')
164
+ => []
118
165
  ```
119
166
 
120
167
  ## Custom delimiter
121
168
  By default, a comma is used as a delimiter to create tags from a string.
122
169
  You can make your own custom separator:
123
170
  ```ruby
124
- Metka.config.delimiter = [',', ' ', '\|']
171
+ Metka.config.delimiter = '|'
125
172
  parsed_data = Metka::GenericParser.instance.call('cool, data|I have')
126
173
  parsed_data.to_a
127
- =>['cool', 'data', 'I', 'have']
174
+ =>['cool, data', 'I have']
128
175
  ```
129
176
 
130
177
  ## Tags with quote
@@ -136,11 +183,10 @@ parsed_data.to_a
136
183
 
137
184
  ## Custom parser
138
185
  By default we use [generic_parser](lib/metka/generic_parser.rb "generic_parser")
139
- If you want use your custom parser you can do:
186
+ If you want to use your custom parser you can do:
140
187
  ```ruby
141
188
  class Song < ActiveRecord::Base
142
- include Metka::Model(column: 'tags', parser: Your::Custom::Parser.instance)
143
- include Metka::Model(column: 'genres')
189
+ include Metka::Model(columns: %w[genres tags], parser: Your::Custom::Parser.instance)
144
190
  end
145
191
  ```
146
192
  Custom parser must be a singleton class that has a `.call` method that accepts the tag string
@@ -149,15 +195,35 @@ Custom parser must be a singleton class that has a `.call` method that accepts t
149
195
 
150
196
  There are several strategies to get tag statistics
151
197
 
198
+ ### ActiveRecord Strategy (Default)
199
+
200
+ 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
+
202
+ ```ruby
203
+ class Book < ActiveRecord::Base
204
+ include Metka::Model(column: 'authors')
205
+ include Metka::Model(column: 'co_authors')
206
+ end
207
+
208
+ tag_cloud = Book.author_cloud
209
+ => [["L.N. Tolstoy", 3], ["F.M. Dostoevsky", 6]]
210
+ genre_cloud = Book.co_author_cloud
211
+ => [["A.P. Chekhov", 5], ["N.V. Gogol", 8], ["L.N. Tolstoy", 2]]
212
+ summary_cloud = Book.metka_cloud('authors', 'co_authors')
213
+ => [["L.N. Tolstoy", 5], ["F.M. Dostoevsky", 6], ["A.P. Chekhov", 5], ["N.V. Gogol", 8]]
214
+ ```
215
+
152
216
  ### View Strategy
153
217
 
154
- Data about taggings will be agregated in SQL View. The easiest way to implement but the most slow on SELECT.
218
+ Data about taggings will be agregated 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.
155
219
 
156
220
  ```bash
157
- rails g metka:strategies:view --source-table-name=NAME_OF_TABLE_WITH_TAGS
221
+ 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]
158
222
  ```
159
223
 
160
- The code above will generate a migration that creates view to store aggregated data about tag in `NAME_OF_TABLE_WITH_TAGS` table.
224
+ 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 occurences across all stated tagged columns.
226
+ `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.
161
227
 
162
228
  Lets take a look at real example. We have a `notes` table with `tags` column.
163
229
 
@@ -181,15 +247,18 @@ The result would be:
181
247
  class CreateTaggedNotesView < ActiveRecord::Migration[5.0]
182
248
  def up
183
249
  execute <<-SQL
184
- CREATE OR REPLACE VIEW tagged_notes AS
185
-
186
- SELECT UNNEST
187
- ( tags ) AS tag_name,
188
- COUNT ( * ) AS taggings_count
189
- FROM
190
- notes
191
- GROUP BY
192
- name;
250
+ CREATE OR REPLACE VIEW tagged_notes AS
251
+ SELECT
252
+ tag_name,
253
+ COUNT ( * ) AS taggings_count
254
+ FROM (
255
+ SELECT UNNEST
256
+ ( tags ) AS tag_name
257
+ FROM
258
+ view_posts
259
+ ) subquery
260
+ GROUP BY
261
+ tag_name;
193
262
  SQL
194
263
  end
195
264
 
@@ -215,33 +284,27 @@ Now you can create `TaggedNote` model and work with the view like you usually do
215
284
 
216
285
  ### Materialized View Strategy
217
286
 
218
- Similar to the strategy above, but the view will be Materialized and refreshed with the trigger
287
+ Data about taggings will be aggregated in SQL Materialized View, that would be refreshed with the trigger on each change of the tagged column's data. Except for the another type of view being used, that strategy behaves the same way, as a View Strategy above.
219
288
 
220
289
  ```bash
221
- rails g metka:strategies:materialized_view --source-table-name=NAME_OF_TABLE_WITH_TAGS
290
+ 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
222
291
  ```
223
292
 
224
- The code above will generate a migration that creates view to store aggregated data about tag in `NAME_OF_TABLE_WITH_TAGS` table.
225
-
226
- Lets take a look at real example. We have a `notes` table with `tags` column.
227
-
228
- | Column | Type | Default |
229
- |--------|---------------------|-----------------------------------|
230
- | id | integer | nextval('notes_id_seq'::regclass) |
231
- | body | text | |
232
- | tags | character varying[] | '{}'::character varying[] |
233
-
234
- Now lets generate a migration.
293
+ All of the options for that stategy's generation command are the same as for the View Strategy.
235
294
 
236
- ```bash
237
- rails g metka:strategies:materialized_view --source-table-name=notes
238
- ```
295
+ The migration template can be seen [here](spec/dummy/db/migrate/06_create_tagged_materialized_view_posts_materialized_view.rb "here")
239
296
 
240
- The migration code you can see [here](spec/dummy/db/migrate/05_create_tagged_materialized_view_Songs_materialized_view.rb "here")
297
+ With the same `notes` table with `tags` column the resulting view would have the same two columns
241
298
 
242
- Now lets take a look at `tagged_notes` materialized view.
299
+ | tag_name | taggings_count |
300
+ |----------|----------------|
301
+ | Ruby | 124056 |
302
+ | React | 30632 |
303
+ | Rails | 28696 |
304
+ | Crystal | 6566 |
305
+ | Elixir | 3475 |
243
306
 
244
- Now you can create `TaggedNote` model and work with the view like you usually do with Rails models.
307
+ And you can also create `TaggedNote` model to work with the view as with a Rails model.
245
308
 
246
309
  ### Table Strategy with Triggers
247
310
 
@@ -254,6 +317,128 @@ TBD
254
317
  2. [ActsAsTaggableArrayOn](https://github.com/tmiyamon/acts-as-taggable-array-on)
255
318
  3. [TagColumns](https://github.com/hopsoft/tag_columns)
256
319
 
320
+ ## Benchmark Comparison
321
+
322
+ There are some results of benchmarking a performance of write, read and find operations for different gems, that provide solution for tagging. Keep in mind, that those results can't be used as a proof, that some solution is better than the others, since each of the benchmarked gems has their unique features. You could run the benchmarks yourself or check, what exact operations has been used for benchmarking, with [MetkaBench application](https://github.com/jetrockets/metka_bench).
323
+
324
+ ```bash
325
+ $ rake bench:all
326
+ Deleted all MetkaSong
327
+ Deleted all ActsAsTaggableOn::Tagging
328
+ Deleted all ActsAsTaggableOn::Tag
329
+ Deleted all ActsAsTaggableSong
330
+ Deleted all ActsAsTaggableArraySong
331
+ Deleted all TagColumnsSong
332
+ Finished to clean
333
+
334
+ ###################################################################
335
+
336
+ bench:write
337
+
338
+ Time measurements:
339
+
340
+ Rehearsal ----------------------------------------------------------
341
+ Metka: 2.192410 0.161092 2.353502 ( 2.754766)
342
+ ActsAsTaggableOn: 13.769918 0.554951 14.324869 ( 16.990127)
343
+ ActsAsTaggableOnArray: 2.150441 0.154127 2.304568 ( 2.700022)
344
+ TagColumns: 2.202647 0.156162 2.358809 ( 2.753400)
345
+ ------------------------------------------------ total: 21.341748sec
346
+
347
+ user system total real
348
+ Metka: 2.137315 0.154046 2.291361 ( 2.643363)
349
+ ActsAsTaggableOn: 11.302848 0.448674 11.751522 ( 14.019458)
350
+ ActsAsTaggableOnArray: 2.143134 0.128655 2.271789 ( 2.670797)
351
+ TagColumns: 2.133780 0.125749 2.259529 ( 2.653404)
352
+
353
+ Memory measurements:
354
+
355
+ Calculating -------------------------------------
356
+ Metka: 179.064M memsize ( 0.000 retained)
357
+ 1.689M objects ( 0.000 retained)
358
+ 50.000 strings ( 0.000 retained)
359
+ ActsAsTaggableOn: 843.949M memsize ( 0.000 retained)
360
+ 8.550M objects ( 0.000 retained)
361
+ 50.000 strings ( 0.000 retained)
362
+ ActsAsTaggableOnArray: 178.807M memsize ( 0.000 retained)
363
+ 1.684M objects ( 0.000 retained)
364
+ 50.000 strings ( 0.000 retained)
365
+ TagColumns: 180.009M memsize ( 0.000 retained)
366
+ 1.699M objects ( 0.000 retained)
367
+ 50.000 strings ( 0.000 retained)
368
+
369
+ ###################################################################
370
+
371
+ bench:read
372
+
373
+ Time measurements:
374
+
375
+ Rehearsal ----------------------------------------------------------
376
+ Metka: 0.479695 0.044399 0.524094 ( 0.590616)
377
+ ActsAsTaggableOn: 2.436328 0.140581 2.576909 ( 3.096142)
378
+ ActsAsTaggableOnArray: 0.515198 0.042127 0.557325 ( 0.623205)
379
+ TagColumns: 0.518363 0.042661 0.561024 ( 0.626968)
380
+ ------------------------------------------------- total: 4.219352sec
381
+
382
+ user system total real
383
+ Metka: 0.446751 0.041886 0.488637 ( 0.554018)
384
+ ActsAsTaggableOn: 2.395166 0.164500 2.559666 ( 3.069655)
385
+ ActsAsTaggableOnArray: 0.439608 0.041682 0.481290 ( 0.544679)
386
+ TagColumns: 0.435404 0.041623 0.477027 ( 0.540359)
387
+
388
+ Memory measurements:
389
+
390
+ Calculating -------------------------------------
391
+ Metka: 42.291M memsize ( 0.000 retained)
392
+ 388.694k objects ( 0.000 retained)
393
+ 50.000 strings ( 0.000 retained)
394
+ ActsAsTaggableOn: 178.664M memsize ( 0.000 retained)
395
+ 1.812M objects ( 0.000 retained)
396
+ 50.000 strings ( 0.000 retained)
397
+ ActsAsTaggableOnArray: 42.173M memsize ( 0.000 retained)
398
+ 383.003k objects ( 0.000 retained)
399
+ 50.000 strings ( 0.000 retained)
400
+ TagColumns: 41.948M memsize ( 0.000 retained)
401
+ 383.003k objects ( 0.000 retained)
402
+ 50.000 strings ( 0.000 retained)
403
+
404
+ ###################################################################
405
+
406
+ bench:find_by_tag
407
+
408
+ Time measurements:
409
+
410
+ Rehearsal ----------------------------------------------------------
411
+ Metka: 0.029961 0.000059 0.030020 ( 0.030052)
412
+ ActsAsTaggableOn: 0.067095 0.000068 0.067163 ( 0.067205)
413
+ ActsAsTaggableOnArray: 0.043156 0.000133 0.043289 ( 0.043440)
414
+ TagColumns: 0.056475 0.000143 0.056618 ( 0.056697)
415
+ ------------------------------------------------- total: 0.197090sec
416
+
417
+ user system total real
418
+ Metka: 0.028291 0.000019 0.028310 ( 0.028321)
419
+ ActsAsTaggableOn: 0.065925 0.000036 0.065961 ( 0.065989)
420
+ ActsAsTaggableOnArray: 0.043214 0.000079 0.043293 ( 0.043361)
421
+ TagColumns: 0.056390 0.000160 0.056550 ( 0.056666)
422
+
423
+ Memory measurements:
424
+
425
+ Calculating -------------------------------------
426
+ Metka: 4.752M memsize ( 0.000 retained)
427
+ 43.000k objects ( 0.000 retained)
428
+ 1.000 strings ( 0.000 retained)
429
+ ActsAsTaggableOn: 8.967M memsize ( 0.000 retained)
430
+ 81.002k objects ( 0.000 retained)
431
+ 9.000 strings ( 0.000 retained)
432
+ ActsAsTaggableOnArray: 5.211M memsize ( 0.000 retained)
433
+ 57.003k objects ( 0.000 retained)
434
+ 6.000 strings ( 0.000 retained)
435
+ TagColumns: 6.696M memsize ( 0.000 retained)
436
+ 94.003k objects ( 0.000 retained)
437
+ 8.000 strings ( 0.000 retained)
438
+
439
+ Finished all benchmarks
440
+ ```
441
+
257
442
  ## Development
258
443
 
259
444
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -265,7 +450,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
265
450
  Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/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.
266
451
 
267
452
  ## Credits
268
- ![JetRockets](https://jetrockets.pro/jetrockets-icons-black.png)
453
+ ![JetRockets](https://media.jetrockets.pro/jetrockets-white.png)
269
454
  Metka is maintained by [JetRockets](http://www.jetrockets.ru).
270
455
 
271
456
  ## License