metka 0.1.2 → 2.0.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: dd6f202972d558afed083a0095530a47e1e2f35028beb4a457c1b13741614b0d
4
- data.tar.gz: e11832ae26b49cdb99aa7b6fd5dddb9f559b862b8460c19b492c05467ea04331
3
+ metadata.gz: 9add2168156651d369dc1cbb040481d55d2e83fdeee318e065153063746036eb
4
+ data.tar.gz: 055e9db64b595b512440a58db7c971d3d7ecd4ba87e52fbb05563133aec3774d
5
5
  SHA512:
6
- metadata.gz: ea2f237f88c8a661931db07532243ddd6c7af85741f77422cc6f6fafd3460fbfaacad205064eeecb438a29a25c3aff11157ddf6309ff6bb559d317674bbdc019
7
- data.tar.gz: b9e9f74757a541c6bf8fb123ba27cf619ebafeb7b92b61ea0a71b0482b5e3a3def87bae4c5292cd159e4bc6beeeb9274811e77e7dd461736d16bb15529ec7673
6
+ metadata.gz: ac957fdb84eecbbf711c9ac03f068a15e7b8e40e99e9f255a5ba6fa1ef438681d8c1cab877513174921a7f0a514233fa513e2c2fd5bdd0893ebf628e26105d3a
7
+ data.tar.gz: d3fc6a6474c316249c38b8a5eb5344fe27beb425b8979368402c6bfbe015e8aeed1083d16348d312fdbef12cae70259a087eeb2d4804e6e12439f69f4d6d6a73
data/.gitignore CHANGED
@@ -10,3 +10,7 @@
10
10
 
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
+ spec/debug.log
14
+
15
+ spec/dummy/log/test.log
16
+ spec/dummy/log/development.log
@@ -8,17 +8,28 @@ sudo: false
8
8
  notifications:
9
9
  email: false
10
10
 
11
+ services:
12
+ - postgresql
11
13
  addons:
12
- postgresql: '9.6'
13
-
14
- env:
15
- global:
16
- - METKA_DB_USER=postgres
17
- - METKA_DB_NAME=metka
14
+ postgresql: "11.2"
18
15
 
19
16
  before_install:
20
17
  - gem install -v 2.0.2 bundler
18
+ - sudo apt-get update
19
+ - sudo apt-get --yes remove postgresql\*
20
+ - sudo apt-get install -y postgresql-11 postgresql-client-11
21
+ - sudo cp /etc/postgresql/{9.6,11}/main/pg_hba.conf
22
+ - sudo service postgresql restart 11
21
23
 
22
24
  before_script:
23
- - gem update --system
24
- - RAILS_ENV=test bundle exec rake dummy:db:create dummy:db:schema:load
25
+ - psql -c 'CREATE ROLE travis SUPERUSER LOGIN CREATEDB;' -U postgres
26
+ - ./bin/setup
27
+
28
+ matrix:
29
+ include:
30
+ - rvm: 2.5.1
31
+ gemfile: gemfiles/rails5.gemfile
32
+ - rvm: 2.5.5
33
+ gemfile: gemfiles/rails52.gemfile
34
+ - rvm: 2.6.2
35
+ gemfile: gemfiles/rails6.gemfile
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- metka (0.1.1)
5
- dry-configurable
6
- rails (>= 4.2)
4
+ metka (1.0.2)
5
+ dry-configurable (>= 0.8)
6
+ rails (>= 5.1)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
@@ -52,27 +52,31 @@ GEM
52
52
  arel (8.0.0)
53
53
  ast (2.4.0)
54
54
  builder (3.2.3)
55
- concurrent-ruby (1.1.5)
56
- crass (1.0.4)
55
+ coderay (1.1.2)
56
+ concurrent-ruby (1.1.6)
57
+ crass (1.0.5)
58
+ database_cleaner (1.7.0)
57
59
  diff-lcs (1.3)
58
- dry-configurable (0.8.3)
60
+ dry-configurable (0.11.5)
59
61
  concurrent-ruby (~> 1.0)
60
62
  dry-core (~> 0.4, >= 0.4.7)
63
+ dry-equalizer (~> 0.2)
61
64
  dry-core (0.4.9)
62
65
  concurrent-ruby (~> 1.0)
63
- erubi (1.8.0)
64
- faker (2.3.0)
65
- i18n (~> 1.6.0)
66
+ dry-equalizer (0.3.0)
67
+ erubi (1.9.0)
68
+ faker (2.8.0)
69
+ i18n (>= 1.6, < 1.8)
66
70
  globalid (0.4.2)
67
71
  activesupport (>= 4.2.0)
68
- i18n (1.6.0)
72
+ i18n (1.7.0)
69
73
  concurrent-ruby (~> 1.0)
70
- jaro_winkler (1.5.3)
71
- jetrockets-standard (1.0.1)
74
+ jaro_winkler (1.5.4)
75
+ jetrockets-standard (1.0.4)
72
76
  rubocop-rails (~> 2.3.2)
73
77
  rubocop-rspec (~> 1.35.0)
74
78
  standard (~> 0.1.4)
75
- loofah (2.2.3)
79
+ loofah (2.4.0)
76
80
  crass (~> 1.0.2)
77
81
  nokogiri (>= 1.5.9)
78
82
  mail (2.7.1)
@@ -80,15 +84,18 @@ GEM
80
84
  method_source (0.9.2)
81
85
  mini_mime (1.0.2)
82
86
  mini_portile2 (2.4.0)
83
- minitest (5.11.3)
84
- nio4r (2.5.1)
85
- nokogiri (1.10.4)
87
+ minitest (5.13.0)
88
+ nio4r (2.5.2)
89
+ nokogiri (1.10.8)
86
90
  mini_portile2 (~> 2.4.0)
87
- parallel (1.17.0)
88
- parser (2.6.4.1)
91
+ parallel (1.19.1)
92
+ parser (2.6.5.0)
89
93
  ast (~> 2.4.0)
90
94
  pg (1.1.4)
91
- rack (2.0.7)
95
+ pry (0.12.2)
96
+ coderay (~> 1.1.0)
97
+ method_source (~> 0.9.0)
98
+ rack (2.0.8)
92
99
  rack-test (1.1.0)
93
100
  rack (>= 1.0, < 3)
94
101
  rails (5.1.7)
@@ -106,8 +113,8 @@ GEM
106
113
  rails-dom-testing (2.0.3)
107
114
  activesupport (>= 4.2.0)
108
115
  nokogiri (>= 1.6)
109
- rails-html-sanitizer (1.2.0)
110
- loofah (~> 2.2, >= 2.2.2)
116
+ rails-html-sanitizer (1.3.0)
117
+ loofah (~> 2.3)
111
118
  railties (5.1.7)
112
119
  actionpack (= 5.1.7)
113
120
  activesupport (= 5.1.7)
@@ -115,36 +122,36 @@ GEM
115
122
  rake (>= 0.8.7)
116
123
  thor (>= 0.18.1, < 2.0)
117
124
  rainbow (3.0.0)
118
- rake (12.3.3)
119
- rspec (3.8.0)
120
- rspec-core (~> 3.8.0)
121
- rspec-expectations (~> 3.8.0)
122
- rspec-mocks (~> 3.8.0)
123
- rspec-core (3.8.2)
124
- rspec-support (~> 3.8.0)
125
- rspec-expectations (3.8.4)
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)
126
133
  diff-lcs (>= 1.2.0, < 2.0)
127
- rspec-support (~> 3.8.0)
128
- rspec-mocks (3.8.1)
134
+ rspec-support (~> 3.9.0)
135
+ rspec-mocks (3.9.0)
129
136
  diff-lcs (>= 1.2.0, < 2.0)
130
- rspec-support (~> 3.8.0)
131
- rspec-rails (3.8.2)
137
+ rspec-support (~> 3.9.0)
138
+ rspec-rails (3.9.0)
132
139
  actionpack (>= 3.0)
133
140
  activesupport (>= 3.0)
134
141
  railties (>= 3.0)
135
- rspec-core (~> 3.8.0)
136
- rspec-expectations (~> 3.8.0)
137
- rspec-mocks (~> 3.8.0)
138
- rspec-support (~> 3.8.0)
139
- rspec-support (3.8.2)
140
- rubocop (0.72.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)
141
148
  jaro_winkler (~> 1.5.1)
142
149
  parallel (~> 1.10)
143
150
  parser (>= 2.6)
144
151
  rainbow (>= 2.2.2, < 4.0)
145
152
  ruby-progressbar (~> 1.7)
146
153
  unicode-display_width (>= 1.4.0, < 1.7)
147
- rubocop-performance (1.4.1)
154
+ rubocop-performance (1.5.1)
148
155
  rubocop (>= 0.71.0)
149
156
  rubocop-rails (2.3.2)
150
157
  rack (>= 1.1)
@@ -152,16 +159,16 @@ GEM
152
159
  rubocop-rspec (1.35.0)
153
160
  rubocop (>= 0.60.0)
154
161
  ruby-progressbar (1.10.1)
155
- sprockets (3.7.2)
162
+ sprockets (4.0.0)
156
163
  concurrent-ruby (~> 1.0)
157
164
  rack (> 1, < 3)
158
165
  sprockets-rails (3.2.1)
159
166
  actionpack (>= 4.0)
160
167
  activesupport (>= 4.0)
161
168
  sprockets (>= 3.0.0)
162
- standard (0.1.4)
163
- rubocop (~> 0.72.0)
164
- rubocop-performance (~> 1.4.0)
169
+ standard (0.1.6)
170
+ rubocop (~> 0.75.0)
171
+ rubocop-performance (~> 1.5.0)
165
172
  thor (0.20.3)
166
173
  thread_safe (0.3.6)
167
174
  timecop (0.9.1)
@@ -177,16 +184,18 @@ PLATFORMS
177
184
 
178
185
  DEPENDENCIES
179
186
  activerecord (~> 5.1.1)
180
- ammeter
181
- bundler
182
- faker
187
+ ammeter (>= 1.1)
188
+ bundler (>= 1.3)
189
+ database_cleaner (>= 1.7)
190
+ faker (>= 2.8)
183
191
  jetrockets-standard (~> 1.0.1)
184
192
  metka!
185
- pg
186
- rake
187
- rspec
188
- rspec-rails
189
- timecop
193
+ pg (>= 1.1)
194
+ pry (>= 0.12.2)
195
+ rake (>= 0.8.7)
196
+ rspec (>= 3.9)
197
+ rspec-rails (>= 3.9)
198
+ timecop (>= 0.9)
190
199
 
191
200
  BUNDLED WITH
192
- 2.0.2
201
+ 2.1.4
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ [![Gem Version](https://badge.fury.io/rb/metka.svg)](https://badge.fury.io/rb/metka)
1
2
  [![Build Status](https://travis-ci.org/jetrockets/metka.svg?branch=master)](https://travis-ci.org/jetrockets/metka)
2
3
  [![Open Source Helpers](https://www.codetriage.com/jetrockets/metka/badges/users.svg)](https://www.codetriage.com/jetrockets/metka)
3
4
 
@@ -23,47 +24,206 @@ Or install it yourself as:
23
24
 
24
25
  ## Tag objects
25
26
 
27
+ ```bash
28
+ rails g migration CreateSongs
29
+ ```
30
+
26
31
  ```ruby
27
- class Post < ActiveRecord::Base
28
- include Metka::Model
32
+ class CreateSongs < ActiveRecord::Migration[5.0]
33
+ def change
34
+ create_table :songs do |t|
35
+ t.string :title
36
+ t.string :tags, array: true
37
+ t.string :genres, array: true
38
+ t.timestamps
39
+ end
40
+ end
41
+ end
42
+ ```
29
43
 
44
+ ```ruby
45
+ class Song < ActiveRecord::Base
46
+ include Metka::Model(columns: %w[genres tags])
30
47
  end
31
48
 
32
- @post = Post.new(title: 'Migrate tags in Rails to PostgreSQL')
33
- @post.tags = ['ruby', 'postgres', 'rails']
34
- @post.save
49
+ @song = Song.new(title: 'Migrate tags in Rails to PostgreSQL')
50
+ @song.tag_list = 'top, chill'
51
+ @song.genre_list = 'rock, jazz, pop'
52
+ @song.save
35
53
  ```
36
54
 
37
55
  ## Find tagged objects
38
56
 
57
+ ### .with_all_#{column_name}
58
+ ```ruby
59
+ Song.with_all_tags('top')
60
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
61
+
62
+ Song.with_all_tags('top, 1990')
63
+ => []
64
+
65
+ Song.with_all_tags('')
66
+ => []
67
+
68
+ Song.with_all_genres('rock')
69
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
70
+ ```
71
+
72
+ ### .with_any_#{column_name}
73
+ ```ruby
74
+ Song.with_any_tags('chill')
75
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
76
+
77
+ Song.with_any_tags('chill, 1980')
78
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
79
+
80
+ Song.with_any_tags('')
81
+ => []
82
+
83
+ Song.with_any_genres('rock, rap')
84
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
85
+ ```
86
+ ### .without_all_#{column_name}
39
87
  ```ruby
40
- Post.tagged_with('ruby')
41
- => [#<Post id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['ruby', 'postgres', 'rails']
88
+ Song.without_all_tags('top')
89
+ => []
90
+
91
+ Song.without_all_tags('top, 1990')
92
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
93
+
94
+ Song.without_all_tags('')
95
+ => []
42
96
 
43
- Post.tagged_with('ruby, crystal')
44
- => nil
97
+ Song.without_all_genres('rock, pop')
98
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
99
+
100
+ Song.without_all_genres('rock')
101
+ => []
45
102
  ```
46
103
 
47
- In example above you will get records that are tagged with `ruby` and `crystal`. To get records that are tagged with any of these tags use `any` option.
104
+ ### .without_any_#{column_name}
105
+ ```ruby
106
+ Song.without_any_tags('top, 1990')
107
+ => []
108
+
109
+ Song.without_any_tags('1990, 1980')
110
+ => [#<Song id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]
111
+
112
+ Song.without_any_genres('rock, pop')
113
+ => []
114
+
115
+ Song.without_any_genres('')
116
+ => []
117
+ ```
48
118
 
119
+ ### .tagged_with
49
120
  ```ruby
50
- Post.tagged_with('ruby, crystal', any: true)
51
- => [#<Post id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['ruby', 'postgres', 'rails']
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'])
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
+ => []
52
165
  ```
53
166
 
167
+ ## Custom delimiter
168
+ By default, a comma is used as a delimiter to create tags from a string.
169
+ You can make your own custom separator:
170
+ ```ruby
171
+ Metka.config.delimiter = '|'
172
+ parsed_data = Metka::GenericParser.instance.call('cool, data|I have')
173
+ parsed_data.to_a
174
+ =>['cool, data', 'I have']
175
+ ```
176
+
177
+ ## Tags with quote
178
+ ```ruby
179
+ parsed_data = Metka::GenericParser.instance.call("'cool, data', code")
180
+ parsed_data.to_a
181
+ => ['cool, data', 'code']
182
+ ```
183
+
184
+ ## Custom parser
185
+ By default we use [generic_parser](lib/metka/generic_parser.rb "generic_parser")
186
+ If you want to use your custom parser you can do:
187
+ ```ruby
188
+ class Song < ActiveRecord::Base
189
+ include Metka::Model(columns: %w[genres tags], parser: Your::Custom::Parser.instance)
190
+ end
191
+ ```
192
+ Custom parser must be a singleton class that has a `.call` method that accepts the tag string
193
+
54
194
  ## Tag Cloud Strategies
55
195
 
56
196
  There are several strategies to get tag statistics
57
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
+
58
216
  ### View Strategy
59
217
 
60
- 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.
61
219
 
62
220
  ```bash
63
- 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]
64
222
  ```
65
223
 
66
- 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.
67
227
 
68
228
  Lets take a look at real example. We have a `notes` table with `tags` column.
69
229
 
@@ -87,15 +247,18 @@ The result would be:
87
247
  class CreateTaggedNotesView < ActiveRecord::Migration[5.0]
88
248
  def up
89
249
  execute <<-SQL
90
- CREATE OR REPLACE VIEW tagged_notes AS
91
-
92
- SELECT UNNEST
93
- ( tags ) AS tag_name,
94
- COUNT ( * ) AS taggings_count
95
- FROM
96
- notes
97
- GROUP BY
98
- 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;
99
262
  SQL
100
263
  end
101
264
 
@@ -121,9 +284,27 @@ Now you can create `TaggedNote` model and work with the view like you usually do
121
284
 
122
285
  ### Materialized View Strategy
123
286
 
124
- 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.
125
288
 
126
- TBD
289
+ ```bash
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
291
+ ```
292
+
293
+ All of the options for that stategy's generation command are the same as for the View Strategy.
294
+
295
+ The migration template can be seen [here](spec/dummy/db/migrate/06_create_tagged_materialized_view_posts_materialized_view.rb "here")
296
+
297
+ With the same `notes` table with `tags` column the resulting view would have the same two columns
298
+
299
+ | tag_name | taggings_count |
300
+ |----------|----------------|
301
+ | Ruby | 124056 |
302
+ | React | 30632 |
303
+ | Rails | 28696 |
304
+ | Crystal | 6566 |
305
+ | Elixir | 3475 |
306
+
307
+ And you can also create `TaggedNote` model to work with the view as with a Rails model.
127
308
 
128
309
  ### Table Strategy with Triggers
129
310
 
@@ -131,6 +312,133 @@ TBD
131
312
 
132
313
  TBD
133
314
 
315
+ ## Inspired by
316
+ 1. [ActsAsTaggableOn](https://github.com/mbleigh/acts-as-taggable-on)
317
+ 2. [ActsAsTaggableArrayOn](https://github.com/tmiyamon/acts-as-taggable-array-on)
318
+ 3. [TagColumns](https://github.com/hopsoft/tag_columns)
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
+
134
442
  ## Development
135
443
 
136
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.
@@ -141,6 +449,10 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
141
449
 
142
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.
143
451
 
452
+ ## Credits
453
+ ![JetRockets](https://jetrockets.pro/jetrockets-icons-black.png)
454
+ Metka is maintained by [JetRockets](http://www.jetrockets.ru).
455
+
144
456
  ## License
145
457
 
146
458
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).