metka 2.3.4 → 3.0.1
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 +273 -236
- data/lib/generators/metka/sql_identifier.rb +25 -0
- data/lib/generators/metka/strategies/index/index_generator.rb +84 -0
- data/lib/generators/metka/strategies/index/templates/migration.rb.erb +89 -0
- data/lib/generators/metka/strategies/table/table_generator.rb +91 -0
- data/lib/generators/metka/strategies/table/templates/migration.rb.erb +128 -0
- data/lib/generators/metka/strategies/table/templates/migration.sqlite.rb.erb +93 -0
- data/lib/metka/generic_parser.rb +28 -14
- data/lib/metka/model.rb +130 -51
- data/lib/metka/query_builder.rb +45 -49
- data/lib/metka/tag_list.rb +16 -8
- data/lib/metka/tags_query.rb +93 -0
- data/lib/metka/version.rb +1 -1
- data/lib/metka.rb +24 -10
- metadata +35 -154
- data/.github/ISSUE_TEMPLATE.md +0 -15
- data/.github/workflows/lint_code.yml +0 -21
- data/.github/workflows/lint_docs.yml +0 -57
- data/.github/workflows/specs.yml +0 -86
- data/.gitignore +0 -18
- data/.mdlrc +0 -1
- data/.rspec +0 -2
- data/.rubocop-md.yml +0 -20
- data/.rubocop.yml +0 -27
- data/.ruby-version +0 -1
- data/Gemfile +0 -12
- data/Gemfile.lock +0 -239
- data/Rakefile +0 -13
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/forspell.dict +0 -7
- data/gemfiles/rails52.gemfile +0 -6
- data/gemfiles/rails6.gemfile +0 -6
- data/gemfiles/rails61.gemfile +0 -6
- data/gemfiles/railsmain.gemfile +0 -5
- data/gemfiles/rubocop.gemfile +0 -4
- data/lib/generators/metka/strategies/materialized_view/materialized_view_generator.rb +0 -73
- data/lib/generators/metka/strategies/materialized_view/templates/migration.rb.erb +0 -54
- data/lib/generators/metka/strategies/view/templates/migration.rb.erb +0 -26
- data/lib/generators/metka/strategies/view/view_generator.rb +0 -70
- data/lib/metka/query_builder/all_tags_query.rb +0 -11
- data/lib/metka/query_builder/any_tags_query.rb +0 -11
- data/lib/metka/query_builder/base_query.rb +0 -48
- data/metka.gemspec +0 -42
data/Gemfile.lock
DELETED
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: .
|
|
3
|
-
specs:
|
|
4
|
-
metka (2.3.3)
|
|
5
|
-
dry-configurable (>= 0.8)
|
|
6
|
-
rails (>= 5.2)
|
|
7
|
-
|
|
8
|
-
GEM
|
|
9
|
-
remote: https://rubygems.org/
|
|
10
|
-
specs:
|
|
11
|
-
actioncable (6.1.4.1)
|
|
12
|
-
actionpack (= 6.1.4.1)
|
|
13
|
-
activesupport (= 6.1.4.1)
|
|
14
|
-
nio4r (~> 2.0)
|
|
15
|
-
websocket-driver (>= 0.6.1)
|
|
16
|
-
actionmailbox (6.1.4.1)
|
|
17
|
-
actionpack (= 6.1.4.1)
|
|
18
|
-
activejob (= 6.1.4.1)
|
|
19
|
-
activerecord (= 6.1.4.1)
|
|
20
|
-
activestorage (= 6.1.4.1)
|
|
21
|
-
activesupport (= 6.1.4.1)
|
|
22
|
-
mail (>= 2.7.1)
|
|
23
|
-
actionmailer (6.1.4.1)
|
|
24
|
-
actionpack (= 6.1.4.1)
|
|
25
|
-
actionview (= 6.1.4.1)
|
|
26
|
-
activejob (= 6.1.4.1)
|
|
27
|
-
activesupport (= 6.1.4.1)
|
|
28
|
-
mail (~> 2.5, >= 2.5.4)
|
|
29
|
-
rails-dom-testing (~> 2.0)
|
|
30
|
-
actionpack (6.1.4.1)
|
|
31
|
-
actionview (= 6.1.4.1)
|
|
32
|
-
activesupport (= 6.1.4.1)
|
|
33
|
-
rack (~> 2.0, >= 2.0.9)
|
|
34
|
-
rack-test (>= 0.6.3)
|
|
35
|
-
rails-dom-testing (~> 2.0)
|
|
36
|
-
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
37
|
-
actiontext (6.1.4.1)
|
|
38
|
-
actionpack (= 6.1.4.1)
|
|
39
|
-
activerecord (= 6.1.4.1)
|
|
40
|
-
activestorage (= 6.1.4.1)
|
|
41
|
-
activesupport (= 6.1.4.1)
|
|
42
|
-
nokogiri (>= 1.8.5)
|
|
43
|
-
actionview (6.1.4.1)
|
|
44
|
-
activesupport (= 6.1.4.1)
|
|
45
|
-
builder (~> 3.1)
|
|
46
|
-
erubi (~> 1.4)
|
|
47
|
-
rails-dom-testing (~> 2.0)
|
|
48
|
-
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
49
|
-
activejob (6.1.4.1)
|
|
50
|
-
activesupport (= 6.1.4.1)
|
|
51
|
-
globalid (>= 0.3.6)
|
|
52
|
-
activemodel (6.1.4.1)
|
|
53
|
-
activesupport (= 6.1.4.1)
|
|
54
|
-
activerecord (6.1.4.1)
|
|
55
|
-
activemodel (= 6.1.4.1)
|
|
56
|
-
activesupport (= 6.1.4.1)
|
|
57
|
-
activestorage (6.1.4.1)
|
|
58
|
-
actionpack (= 6.1.4.1)
|
|
59
|
-
activejob (= 6.1.4.1)
|
|
60
|
-
activerecord (= 6.1.4.1)
|
|
61
|
-
activesupport (= 6.1.4.1)
|
|
62
|
-
marcel (~> 1.0.0)
|
|
63
|
-
mini_mime (>= 1.1.0)
|
|
64
|
-
activesupport (6.1.4.1)
|
|
65
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
66
|
-
i18n (>= 1.6, < 2)
|
|
67
|
-
minitest (>= 5.1)
|
|
68
|
-
tzinfo (~> 2.0)
|
|
69
|
-
zeitwerk (~> 2.3)
|
|
70
|
-
ammeter (1.1.5)
|
|
71
|
-
activesupport (>= 3.0)
|
|
72
|
-
railties (>= 3.0)
|
|
73
|
-
rspec-rails (>= 2.2)
|
|
74
|
-
ast (2.4.2)
|
|
75
|
-
builder (3.2.4)
|
|
76
|
-
coderay (1.1.3)
|
|
77
|
-
concurrent-ruby (1.1.9)
|
|
78
|
-
crass (1.0.6)
|
|
79
|
-
database_cleaner (2.0.1)
|
|
80
|
-
database_cleaner-active_record (~> 2.0.0)
|
|
81
|
-
database_cleaner-active_record (2.0.0)
|
|
82
|
-
activerecord (>= 5.a)
|
|
83
|
-
database_cleaner-core (~> 2.0.0)
|
|
84
|
-
database_cleaner-core (2.0.1)
|
|
85
|
-
diff-lcs (1.4.4)
|
|
86
|
-
dry-configurable (0.13.0)
|
|
87
|
-
concurrent-ruby (~> 1.0)
|
|
88
|
-
dry-core (~> 0.6)
|
|
89
|
-
dry-core (0.7.1)
|
|
90
|
-
concurrent-ruby (~> 1.0)
|
|
91
|
-
erubi (1.10.0)
|
|
92
|
-
faker (2.17.0)
|
|
93
|
-
i18n (>= 1.6, < 2)
|
|
94
|
-
globalid (1.0.0)
|
|
95
|
-
activesupport (>= 5.0)
|
|
96
|
-
i18n (1.8.10)
|
|
97
|
-
concurrent-ruby (~> 1.0)
|
|
98
|
-
jetrockets-standard (1.2.0)
|
|
99
|
-
rubocop-rails
|
|
100
|
-
rubocop-rspec
|
|
101
|
-
standard (~> 1.1.1)
|
|
102
|
-
loofah (2.12.0)
|
|
103
|
-
crass (~> 1.0.2)
|
|
104
|
-
nokogiri (>= 1.5.9)
|
|
105
|
-
mail (2.7.1)
|
|
106
|
-
mini_mime (>= 0.1.1)
|
|
107
|
-
marcel (1.0.2)
|
|
108
|
-
method_source (1.0.0)
|
|
109
|
-
mini_mime (1.1.2)
|
|
110
|
-
mini_portile2 (2.6.1)
|
|
111
|
-
minitest (5.14.4)
|
|
112
|
-
nio4r (2.5.8)
|
|
113
|
-
nokogiri (1.12.5)
|
|
114
|
-
mini_portile2 (~> 2.6.1)
|
|
115
|
-
racc (~> 1.4)
|
|
116
|
-
parallel (1.21.0)
|
|
117
|
-
parser (3.1.0.0)
|
|
118
|
-
ast (~> 2.4.1)
|
|
119
|
-
pg (1.2.3)
|
|
120
|
-
pry (0.14.0)
|
|
121
|
-
coderay (~> 1.1)
|
|
122
|
-
method_source (~> 1.0)
|
|
123
|
-
racc (1.5.2)
|
|
124
|
-
rack (2.2.3)
|
|
125
|
-
rack-test (1.1.0)
|
|
126
|
-
rack (>= 1.0, < 3)
|
|
127
|
-
rails (6.1.4.1)
|
|
128
|
-
actioncable (= 6.1.4.1)
|
|
129
|
-
actionmailbox (= 6.1.4.1)
|
|
130
|
-
actionmailer (= 6.1.4.1)
|
|
131
|
-
actionpack (= 6.1.4.1)
|
|
132
|
-
actiontext (= 6.1.4.1)
|
|
133
|
-
actionview (= 6.1.4.1)
|
|
134
|
-
activejob (= 6.1.4.1)
|
|
135
|
-
activemodel (= 6.1.4.1)
|
|
136
|
-
activerecord (= 6.1.4.1)
|
|
137
|
-
activestorage (= 6.1.4.1)
|
|
138
|
-
activesupport (= 6.1.4.1)
|
|
139
|
-
bundler (>= 1.15.0)
|
|
140
|
-
railties (= 6.1.4.1)
|
|
141
|
-
sprockets-rails (>= 2.0.0)
|
|
142
|
-
rails-dom-testing (2.0.3)
|
|
143
|
-
activesupport (>= 4.2.0)
|
|
144
|
-
nokogiri (>= 1.6)
|
|
145
|
-
rails-html-sanitizer (1.4.2)
|
|
146
|
-
loofah (~> 2.3)
|
|
147
|
-
railties (6.1.4.1)
|
|
148
|
-
actionpack (= 6.1.4.1)
|
|
149
|
-
activesupport (= 6.1.4.1)
|
|
150
|
-
method_source
|
|
151
|
-
rake (>= 0.13)
|
|
152
|
-
thor (~> 1.0)
|
|
153
|
-
rainbow (3.0.0)
|
|
154
|
-
rake (13.0.6)
|
|
155
|
-
regexp_parser (2.2.0)
|
|
156
|
-
rexml (3.2.5)
|
|
157
|
-
rspec (3.10.0)
|
|
158
|
-
rspec-core (~> 3.10.0)
|
|
159
|
-
rspec-expectations (~> 3.10.0)
|
|
160
|
-
rspec-mocks (~> 3.10.0)
|
|
161
|
-
rspec-core (3.10.1)
|
|
162
|
-
rspec-support (~> 3.10.0)
|
|
163
|
-
rspec-expectations (3.10.1)
|
|
164
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
165
|
-
rspec-support (~> 3.10.0)
|
|
166
|
-
rspec-mocks (3.10.2)
|
|
167
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
168
|
-
rspec-support (~> 3.10.0)
|
|
169
|
-
rspec-rails (5.0.1)
|
|
170
|
-
actionpack (>= 5.2)
|
|
171
|
-
activesupport (>= 5.2)
|
|
172
|
-
railties (>= 5.2)
|
|
173
|
-
rspec-core (~> 3.10)
|
|
174
|
-
rspec-expectations (~> 3.10)
|
|
175
|
-
rspec-mocks (~> 3.10)
|
|
176
|
-
rspec-support (~> 3.10)
|
|
177
|
-
rspec-support (3.10.2)
|
|
178
|
-
rubocop (1.18.4)
|
|
179
|
-
parallel (~> 1.10)
|
|
180
|
-
parser (>= 3.0.0.0)
|
|
181
|
-
rainbow (>= 2.2.2, < 4.0)
|
|
182
|
-
regexp_parser (>= 1.8, < 3.0)
|
|
183
|
-
rexml
|
|
184
|
-
rubocop-ast (>= 1.8.0, < 2.0)
|
|
185
|
-
ruby-progressbar (~> 1.7)
|
|
186
|
-
unicode-display_width (>= 1.4.0, < 3.0)
|
|
187
|
-
rubocop-ast (1.15.1)
|
|
188
|
-
parser (>= 3.0.1.1)
|
|
189
|
-
rubocop-performance (1.11.4)
|
|
190
|
-
rubocop (>= 1.7.0, < 2.0)
|
|
191
|
-
rubocop-ast (>= 0.4.0)
|
|
192
|
-
rubocop-rails (2.13.0)
|
|
193
|
-
activesupport (>= 4.2.0)
|
|
194
|
-
rack (>= 1.1)
|
|
195
|
-
rubocop (>= 1.7.0, < 2.0)
|
|
196
|
-
rubocop-rspec (2.4.0)
|
|
197
|
-
rubocop (~> 1.0)
|
|
198
|
-
rubocop-ast (>= 1.1.0)
|
|
199
|
-
ruby-progressbar (1.11.0)
|
|
200
|
-
sprockets (4.0.2)
|
|
201
|
-
concurrent-ruby (~> 1.0)
|
|
202
|
-
rack (> 1, < 3)
|
|
203
|
-
sprockets-rails (3.4.2)
|
|
204
|
-
actionpack (>= 5.2)
|
|
205
|
-
activesupport (>= 5.2)
|
|
206
|
-
sprockets (>= 3.0.0)
|
|
207
|
-
standard (1.1.7)
|
|
208
|
-
rubocop (= 1.18.4)
|
|
209
|
-
rubocop-performance (= 1.11.4)
|
|
210
|
-
thor (1.1.0)
|
|
211
|
-
timecop (0.9.4)
|
|
212
|
-
tzinfo (2.0.4)
|
|
213
|
-
concurrent-ruby (~> 1.0)
|
|
214
|
-
unicode-display_width (2.1.0)
|
|
215
|
-
websocket-driver (0.7.5)
|
|
216
|
-
websocket-extensions (>= 0.1.0)
|
|
217
|
-
websocket-extensions (0.1.5)
|
|
218
|
-
zeitwerk (2.4.2)
|
|
219
|
-
|
|
220
|
-
PLATFORMS
|
|
221
|
-
ruby
|
|
222
|
-
|
|
223
|
-
DEPENDENCIES
|
|
224
|
-
activerecord (>= 5.2.4, < 6.2)
|
|
225
|
-
ammeter (>= 1.1)
|
|
226
|
-
bundler (>= 1.3)
|
|
227
|
-
database_cleaner (>= 1.7)
|
|
228
|
-
faker (>= 2.8)
|
|
229
|
-
jetrockets-standard (>= 1.1)
|
|
230
|
-
metka!
|
|
231
|
-
pg (>= 1.1)
|
|
232
|
-
pry (>= 0.12.2)
|
|
233
|
-
rake (>= 0.8.7)
|
|
234
|
-
rspec (>= 3.9)
|
|
235
|
-
rspec-rails (>= 3.9)
|
|
236
|
-
timecop (>= 0.9)
|
|
237
|
-
|
|
238
|
-
BUNDLED WITH
|
|
239
|
-
2.1.4
|
data/Rakefile
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'bundler/gem_tasks'
|
|
4
|
-
require 'rspec/core/rake_task'
|
|
5
|
-
|
|
6
|
-
RSpec::Core::RakeTask.new(:spec)
|
|
7
|
-
|
|
8
|
-
namespace :dummy do
|
|
9
|
-
require_relative 'spec/dummy/config/application'
|
|
10
|
-
Dummy::Application.load_tasks
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
task default: :spec
|
data/bin/console
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require "bundler/setup"
|
|
4
|
-
require "metka"
|
|
5
|
-
|
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
-
|
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
-
# require "pry"
|
|
11
|
-
# Pry.start
|
|
12
|
-
|
|
13
|
-
require "irb"
|
|
14
|
-
IRB.start(__FILE__)
|
data/bin/setup
DELETED
data/forspell.dict
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
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
DELETED
data/gemfiles/rails6.gemfile
DELETED
data/gemfiles/rails61.gemfile
DELETED
data/gemfiles/railsmain.gemfile
DELETED
data/gemfiles/rubocop.gemfile
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rails/generators'
|
|
4
|
-
require 'rails/generators/active_record'
|
|
5
|
-
|
|
6
|
-
module Metka
|
|
7
|
-
module Generators
|
|
8
|
-
module Strategies
|
|
9
|
-
class MaterializedViewGenerator < ::Rails::Generators::Base # :nodoc:
|
|
10
|
-
include Rails::Generators::Migration
|
|
11
|
-
|
|
12
|
-
DEFAULT_SOURCE_COLUMNS = ['tags'].freeze
|
|
13
|
-
|
|
14
|
-
desc <<~LONGDESC
|
|
15
|
-
Generates migration to implement view strategy for Metka
|
|
16
|
-
|
|
17
|
-
> $ rails g metka:strategies:materialized_view \
|
|
18
|
-
--source-table-name=NAME_OF_TABLE_WITH_TAGS \
|
|
19
|
-
--source-columns=NAME_OF_TAGGED_COLUMN_1 NAME_OF_TAGGED_COLUMN_2 \
|
|
20
|
-
--view-name=NAME_OF_VIEW
|
|
21
|
-
LONGDESC
|
|
22
|
-
|
|
23
|
-
source_root File.expand_path('templates', __dir__)
|
|
24
|
-
|
|
25
|
-
class_option :source_table_name, type: :string, required: true,
|
|
26
|
-
desc: 'Name of the table that has a column with tags'
|
|
27
|
-
|
|
28
|
-
class_option :source_columns, type: :array, default: DEFAULT_SOURCE_COLUMNS,
|
|
29
|
-
desc: 'List of the tagged columns names'
|
|
30
|
-
|
|
31
|
-
class_option :view_name, type: :string,
|
|
32
|
-
desc: 'Custom name for the resulting view'
|
|
33
|
-
|
|
34
|
-
def generate_migration
|
|
35
|
-
migration_template 'migration.rb.erb', "db/migrate/#{migration_name}.rb"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
no_tasks do
|
|
39
|
-
def source_table_name
|
|
40
|
-
options[:source_table_name]
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def source_columns
|
|
44
|
-
options[:source_columns]
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def source_columns_names
|
|
48
|
-
source_columns.join('_and_')
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def view_name
|
|
52
|
-
return options[:view_name] if options[:view_name]
|
|
53
|
-
|
|
54
|
-
columns_sequence = source_columns == DEFAULT_SOURCE_COLUMNS ? nil : "_with_#{source_columns_names}"
|
|
55
|
-
"tagged#{columns_sequence}_#{source_table_name}"
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def migration_name
|
|
59
|
-
"create_#{view_name}_materialized_view"
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def migration_class_name
|
|
63
|
-
migration_name.classify
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def self.next_migration_number(dir)
|
|
68
|
-
::ActiveRecord::Generators::Base.next_migration_number(dir)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class <%= @migration_class_name %> < ActiveRecord::Migration<%= ActiveRecord::VERSION::MAJOR < 5 ? '' : '[5.0]' %>
|
|
4
|
-
def up
|
|
5
|
-
execute <<-SQL
|
|
6
|
-
CREATE OR REPLACE FUNCTION metka_refresh_<%= view_name %>_materialized_view() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
7
|
-
BEGIN
|
|
8
|
-
IF TG_OP = 'INSERT' AND
|
|
9
|
-
(<%= source_columns.map { |column| "NEW.#{column} IS NOT NULL" }.join(' OR ') %>) THEN
|
|
10
|
-
REFRESH MATERIALIZED VIEW CONCURRENTLY <%= view_name %>;
|
|
11
|
-
END IF;
|
|
12
|
-
|
|
13
|
-
IF TG_OP = 'UPDATE' AND
|
|
14
|
-
(<%= source_columns.map { |column| "OLD.#{column} IS DISTINCT FROM NEW.#{column}" }.join(' OR ') %>) THEN
|
|
15
|
-
REFRESH MATERIALIZED VIEW CONCURRENTLY <%= view_name %>;
|
|
16
|
-
END IF;
|
|
17
|
-
|
|
18
|
-
IF TG_OP = 'DELETE' AND
|
|
19
|
-
(<%= source_columns.map { |column| "OLD.#{column} IS NOT NULL" }.join(' OR ') %>) THEN
|
|
20
|
-
REFRESH MATERIALIZED VIEW CONCURRENTLY <%= view_name %>;
|
|
21
|
-
END IF;
|
|
22
|
-
RETURN NEW;
|
|
23
|
-
END $$;
|
|
24
|
-
|
|
25
|
-
DROP MATERIALIZED VIEW IF EXISTS <%= view_name %>;
|
|
26
|
-
CREATE MATERIALIZED VIEW <%= view_name %> AS
|
|
27
|
-
SELECT
|
|
28
|
-
tag_name,
|
|
29
|
-
COUNT(*) AS taggings_count
|
|
30
|
-
FROM (
|
|
31
|
-
SELECT UNNEST
|
|
32
|
-
(<%= source_columns.join(' || ') %>) AS tag_name
|
|
33
|
-
FROM
|
|
34
|
-
<%= source_table_name %>
|
|
35
|
-
) subquery
|
|
36
|
-
GROUP BY
|
|
37
|
-
tag_name;
|
|
38
|
-
|
|
39
|
-
CREATE UNIQUE INDEX idx_<%= source_table_name %>_<%= source_columns_names %> ON <%= view_name %>(tag_name);
|
|
40
|
-
|
|
41
|
-
CREATE TRIGGER metka_on_<%= source_table_name %>_<%= source_columns_names %>
|
|
42
|
-
AFTER UPDATE OR INSERT OR DELETE ON <%= source_table_name %> FOR EACH ROW
|
|
43
|
-
EXECUTE PROCEDURE metka_refresh_<%= view_name %>_materialized_view();
|
|
44
|
-
SQL
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def down
|
|
48
|
-
execute <<-SQL
|
|
49
|
-
DROP TRIGGER IF EXISTS metka_on_<%= source_table_name %>_<%= source_columns_names %> ON <%= source_table_name %>;
|
|
50
|
-
DROP FUNCTION IF EXISTS metka_refresh_<%= view_name %>_materialized_view;
|
|
51
|
-
DROP MATERIALIZED VIEW IF EXISTS <%= view_name %>;
|
|
52
|
-
SQL
|
|
53
|
-
end
|
|
54
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class <%= @migration_class_name %> < ActiveRecord::Migration<%= ActiveRecord::VERSION::MAJOR < 5 ? '' : '[5.0]' %>
|
|
4
|
-
def up
|
|
5
|
-
execute <<-SQL
|
|
6
|
-
CREATE OR REPLACE VIEW <%= view_name %> AS
|
|
7
|
-
SELECT
|
|
8
|
-
tag_name,
|
|
9
|
-
COUNT(*) AS taggings_count
|
|
10
|
-
FROM (
|
|
11
|
-
SELECT UNNEST
|
|
12
|
-
(<%= source_columns.join(' || ') %>) AS tag_name
|
|
13
|
-
FROM
|
|
14
|
-
<%= source_table_name %>
|
|
15
|
-
) subquery
|
|
16
|
-
GROUP BY
|
|
17
|
-
tag_name;
|
|
18
|
-
SQL
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def down
|
|
22
|
-
execute <<-SQL
|
|
23
|
-
DROP VIEW <%= view_name %>;
|
|
24
|
-
SQL
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rails/generators'
|
|
4
|
-
require 'rails/generators/active_record'
|
|
5
|
-
|
|
6
|
-
module Metka
|
|
7
|
-
module Generators
|
|
8
|
-
module Strategies
|
|
9
|
-
class ViewGenerator < ::Rails::Generators::Base # :nodoc:
|
|
10
|
-
include Rails::Generators::Migration
|
|
11
|
-
|
|
12
|
-
DEFAULT_SOURCE_COLUMNS = ['tags'].freeze
|
|
13
|
-
|
|
14
|
-
desc <<~LONGDESC
|
|
15
|
-
Generates migration to implement view strategy for Metka
|
|
16
|
-
|
|
17
|
-
> $ rails g metka:strategies:view --source-table-name=NAME_OF_TABLE_WITH_TAGS
|
|
18
|
-
LONGDESC
|
|
19
|
-
|
|
20
|
-
source_root File.expand_path('templates', __dir__)
|
|
21
|
-
|
|
22
|
-
class_option :source_table_name, type: :string, required: true,
|
|
23
|
-
desc: 'Name of the table that has a column with tags'
|
|
24
|
-
|
|
25
|
-
class_option :source_columns, type: :array, default: DEFAULT_SOURCE_COLUMNS,
|
|
26
|
-
desc: 'List of the tagged columns names'
|
|
27
|
-
|
|
28
|
-
class_option :view_name, type: :string,
|
|
29
|
-
desc: 'Custom name for the resulting view'
|
|
30
|
-
|
|
31
|
-
def generate_migration
|
|
32
|
-
migration_template 'migration.rb.erb', "db/migrate/#{migration_name}.rb"
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
no_tasks do
|
|
36
|
-
def source_table_name
|
|
37
|
-
options[:source_table_name]
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def source_columns
|
|
41
|
-
options[:source_columns]
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def source_columns_names
|
|
45
|
-
source_columns.join('_and_')
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def view_name
|
|
49
|
-
return options[:view_name] if options[:view_name]
|
|
50
|
-
|
|
51
|
-
columns_sequence = source_columns == DEFAULT_SOURCE_COLUMNS ? nil : "_with_#{source_columns_names}"
|
|
52
|
-
"tagged#{columns_sequence}_#{source_table_name}"
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def migration_name
|
|
56
|
-
"create_#{view_name}_view"
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def migration_class_name
|
|
60
|
-
migration_name.classify
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def self.next_migration_number(dir)
|
|
65
|
-
::ActiveRecord::Generators::Base.next_migration_number(dir)
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'singleton'
|
|
4
|
-
|
|
5
|
-
module Metka
|
|
6
|
-
class BaseQuery
|
|
7
|
-
include Singleton
|
|
8
|
-
|
|
9
|
-
def call(model, column_name, tag_list)
|
|
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)
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
data/metka.gemspec
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
lib = File.expand_path('../lib', __FILE__)
|
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
-
require 'metka/version'
|
|
6
|
-
|
|
7
|
-
Gem::Specification.new do |spec|
|
|
8
|
-
spec.name = 'metka'
|
|
9
|
-
spec.version = Metka::VERSION
|
|
10
|
-
spec.authors = ['Igor Alexandrov', 'Andrey Morozov']
|
|
11
|
-
spec.email = ['igor.alexandrov@gmail.com', 'andrey.morozov@jetrockets.ru']
|
|
12
|
-
|
|
13
|
-
spec.summary = 'Rails tagging system based on PostgreSQL arrays'
|
|
14
|
-
spec.description = 'Rails tagging system based on PostgreSQL arrays'
|
|
15
|
-
spec.homepage = 'https://github.com/jetrockets/metka'
|
|
16
|
-
spec.license = 'MIT'
|
|
17
|
-
|
|
18
|
-
# Specify which files should be added to the gem when it is released.
|
|
19
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
20
|
-
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
21
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
22
|
-
end
|
|
23
|
-
spec.bindir = 'exe'
|
|
24
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
25
|
-
spec.require_paths = ['lib']
|
|
26
|
-
|
|
27
|
-
spec.add_dependency 'dry-configurable', '>= 0.8'
|
|
28
|
-
spec.add_dependency 'rails', '>= 5.2'
|
|
29
|
-
|
|
30
|
-
spec.add_development_dependency 'ammeter', '>= 1.1'
|
|
31
|
-
spec.add_development_dependency 'pry', '>= 0.12.2'
|
|
32
|
-
spec.add_development_dependency 'bundler', '>= 1.3'
|
|
33
|
-
spec.add_development_dependency 'faker', '>= 2.8'
|
|
34
|
-
spec.add_development_dependency 'pg', '>= 1.1'
|
|
35
|
-
spec.add_development_dependency 'rake', '>= 0.8.7'
|
|
36
|
-
spec.add_development_dependency 'rspec', '>= 3.9'
|
|
37
|
-
spec.add_development_dependency 'rspec-rails', '>= 3.9'
|
|
38
|
-
spec.add_development_dependency 'timecop', '>= 0.9'
|
|
39
|
-
spec.add_development_dependency 'database_cleaner', '>= 1.7'
|
|
40
|
-
spec.add_development_dependency 'jetrockets-standard', '>= 1.1'
|
|
41
|
-
spec.required_ruby_version = '>= 2.5'
|
|
42
|
-
end
|