pg_tags_on 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -2
- data/LICENSE.txt +1 -1
- data/README.md +30 -22
- data/lib/pg_tags_on/active_record/base.rb +1 -1
- data/lib/pg_tags_on/repositories/array_jsonb_repository.rb +47 -24
- data/lib/pg_tags_on/repositories/array_repository.rb +31 -18
- data/lib/pg_tags_on/repositories/base_repository.rb +39 -4
- data/lib/pg_tags_on/validations/validator.rb +4 -4
- data/lib/pg_tags_on/version.rb +1 -1
- metadata +21 -137
- data/.gitignore +0 -11
- data/.rspec +0 -3
- data/.rubocop.yml +0 -9
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -6
- data/Gemfile.lock +0 -91
- data/Rakefile +0 -16
- data/bin/console +0 -16
- data/bin/setup +0 -8
- data/pg_tags_on.gemspec +0 -38
- data/spec/array_integers/records_spec.rb +0 -47
- data/spec/array_integers/tag_ops_spec.rb +0 -65
- data/spec/array_integers/taggings_spec.rb +0 -27
- data/spec/array_integers/tags_spec.rb +0 -53
- data/spec/array_jsonb/records_spec.rb +0 -89
- data/spec/array_jsonb/tag_ops_spec.rb +0 -115
- data/spec/array_jsonb/taggings_spec.rb +0 -27
- data/spec/array_jsonb/tags_spec.rb +0 -41
- data/spec/array_strings/records_spec.rb +0 -61
- data/spec/array_strings/tag_ops_spec.rb +0 -65
- data/spec/array_strings/taggings_spec.rb +0 -27
- data/spec/array_strings/tags_spec.rb +0 -54
- data/spec/config/database.yml +0 -6
- data/spec/configuration_spec.rb +0 -48
- data/spec/helpers/database_helpers.rb +0 -46
- data/spec/spec_helper.rb +0 -39
- data/spec/support/factory.rb +0 -47
- data/spec/tags_query_spec.rb +0 -31
- data/spec/validator_spec.rb +0 -40
- data/tasks/benchmark.rake +0 -58
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe 'ArrayJsonb::Taggings' do
|
4
|
-
before(:all) do
|
5
|
-
@column = :tags_jsonb
|
6
|
-
Entity.pg_tags_on @column, key: :name
|
7
|
-
truncate && Factory.array_jsonb
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:column) { @column }
|
11
|
-
let(:ref) { %("#{Entity.table_name}"."#{column}") }
|
12
|
-
let(:relation) { Entity.send(column) }
|
13
|
-
|
14
|
-
it 'find all taggings' do
|
15
|
-
taggings = relation.taggings.order('name')
|
16
|
-
|
17
|
-
expect(taggings.size).to be_eql(6)
|
18
|
-
expect(taggings.map(&:name)).to be_eql(%w[a b b c c d])
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'find all taggings for filtered records' do
|
22
|
-
taggings = Entity.where(attr: 'test2').send(column).taggings.order('name')
|
23
|
-
|
24
|
-
expect(taggings.size).to be_eql(2)
|
25
|
-
expect(taggings.map(&:name)).to be_eql(%w[b c])
|
26
|
-
end
|
27
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe 'ArrayJsonb::Tags' do
|
4
|
-
before(:all) do
|
5
|
-
@column = :tags_jsonb
|
6
|
-
Entity.pg_tags_on @column, key: :name
|
7
|
-
truncate && Factory.array_jsonb
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:column) { @column }
|
11
|
-
let(:ref) { %("#{Entity.table_name}"."#{column}") }
|
12
|
-
let(:relation) { Entity.send(column) }
|
13
|
-
|
14
|
-
it 'find all tags' do
|
15
|
-
tags = relation.all.order('name')
|
16
|
-
|
17
|
-
expect(tags.size).to be_eql(4)
|
18
|
-
expect(tags.map(&:name)).to be_eql(%w[a b c d])
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'find all tags for filtered records' do
|
22
|
-
tags = Entity.where(attr: 'test2').send(column).all
|
23
|
-
|
24
|
-
expect(tags.size).to be_eql(2)
|
25
|
-
expect(tags.map(&:name)).to be_eql(%w[b c])
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'find all tags with counts' do
|
29
|
-
tag = relation.all_with_counts.first
|
30
|
-
|
31
|
-
expect(tag.count).to be_eql(1)
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'count tags' do
|
35
|
-
expect(relation.count).to be_eql(4)
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'count tags for filtered records' do
|
39
|
-
expect(Entity.where(attr: 'test2').send(column).count).to be_eql(2)
|
40
|
-
end
|
41
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe 'ArrayStrings::Records' do
|
4
|
-
before(:all) do
|
5
|
-
@column = :tags_str # defined as instance var as it is used in before_all callback
|
6
|
-
Entity.pg_tags_on @column
|
7
|
-
truncate && Factory.array_strings
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:column) { @column }
|
11
|
-
let(:ref) { %("#{Entity.table_name}"."#{column}") }
|
12
|
-
let(:relation) { Entity.send(column) }
|
13
|
-
|
14
|
-
it 'find records by tag' do
|
15
|
-
rel = Entity.where(column => Tags.one('b'))
|
16
|
-
|
17
|
-
expect(rel.to_sql).to include(%(#{ref} @> '{b}'))
|
18
|
-
expect(rel.count).to be_eql(2)
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'find records without tag' do
|
22
|
-
rel = Entity.where.not(column => Tags.one('b'))
|
23
|
-
|
24
|
-
expect(rel.to_sql).to include(%(NOT (#{ref} @> '{b}')))
|
25
|
-
expect(rel.count).to be_eql(1)
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'find records with exact same tags' do
|
29
|
-
rel = Entity.where(column => Tags.eq(%w[c b]))
|
30
|
-
|
31
|
-
expect(rel.count).to be_eql(1)
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'find records with all tags' do
|
35
|
-
rel = Entity.where(column => Tags.all(%w[a b c]))
|
36
|
-
|
37
|
-
expect(rel.to_sql).to include(%(#{ref} @> '{a,b,c}'))
|
38
|
-
expect(rel.count).to be_eql(1)
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'find records without tags' do
|
42
|
-
rel = Entity.where.not(column => Tags.all(%w[a b]))
|
43
|
-
|
44
|
-
expect(rel.to_sql).to include(%(NOT (#{ref} @> '{a,b}')))
|
45
|
-
expect(rel.count).to be_eql(2)
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'find records with any tag' do
|
49
|
-
rel = Entity.where(column => Tags.any(%w[a b c]))
|
50
|
-
|
51
|
-
expect(rel.to_sql).to include(%(#{ref} && '{a,b,c}'))
|
52
|
-
expect(rel.count).to be_eql(2)
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'find records with tags included in tag list' do
|
56
|
-
rel = Entity.where(column => Tags.in(%w[a b c]))
|
57
|
-
|
58
|
-
expect(rel.to_sql).to include(%(#{ref} <@ '{a,b,c}'))
|
59
|
-
expect(rel.count).to be_eql(2)
|
60
|
-
end
|
61
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe 'ArrayStrings::TagOps' do
|
4
|
-
before(:all) do
|
5
|
-
@column = :tags_str # defined as instance var as it is used in before_all callback
|
6
|
-
Entity.pg_tags_on @column
|
7
|
-
end
|
8
|
-
|
9
|
-
before do
|
10
|
-
truncate && Factory.array_strings
|
11
|
-
end
|
12
|
-
|
13
|
-
let(:column) { @column }
|
14
|
-
let(:ref) { %("#{Entity.table_name}"."#{column}") }
|
15
|
-
let(:relation) { Entity.send(column) }
|
16
|
-
|
17
|
-
context 'create' do
|
18
|
-
it 'create tag' do
|
19
|
-
relation.create('new-tag1')
|
20
|
-
|
21
|
-
Entity.all.each do |entity|
|
22
|
-
expect(entity.send(column)).to include('new-tag1')
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'create tag for filtered records' do
|
27
|
-
Entity.where(attr: 'test2').send(column).create('new-tag2')
|
28
|
-
|
29
|
-
expect(Entity.find_by_attr('test1').send(column)).not_to include('new-tag2')
|
30
|
-
expect(Entity.find_by_attr('test2').send(column)).to include('new-tag2')
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
context 'update' do
|
35
|
-
it 'update tag' do
|
36
|
-
relation.update('b', 'updated-b')
|
37
|
-
|
38
|
-
count = Entity.where(column => Tags.all('updated-b')).count
|
39
|
-
expect(count).to be_eql(2)
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'update tag for filtered records' do
|
43
|
-
Entity.where(attr: 'test2').send(column).update('c', 'updated-c')
|
44
|
-
|
45
|
-
count = Entity.where(column => Tags.all('updated-c')).count
|
46
|
-
expect(count).to be_eql(1)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context 'delete' do
|
51
|
-
it 'delete tag' do
|
52
|
-
relation.delete('b')
|
53
|
-
|
54
|
-
tags = relation.all.pluck(:name)
|
55
|
-
expect(tags).not_to include('b')
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'delete tag for filtered records' do
|
59
|
-
Entity.where(attr: 'test2').send(column).delete('c')
|
60
|
-
|
61
|
-
expect(Entity.find_by_attr('test1').send(column)).to include('c')
|
62
|
-
expect(Entity.find_by_attr('test2').send(column)).not_to include('c')
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe 'ArrayStrings::Taggings' do
|
4
|
-
before(:all) do
|
5
|
-
@column = :tags_str # defined as instance var as it is used in before_all callback
|
6
|
-
Entity.pg_tags_on @column
|
7
|
-
truncate && Factory.array_strings
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:column) { @column }
|
11
|
-
let(:ref) { %("#{Entity.table_name}"."#{column}") }
|
12
|
-
let(:relation) { Entity.send(column) }
|
13
|
-
|
14
|
-
it 'find all taggings' do
|
15
|
-
taggings = relation.taggings.order('name')
|
16
|
-
|
17
|
-
expect(taggings.size).to be_eql(6)
|
18
|
-
expect(taggings.map(&:name)).to be_eql(%w[a b b c c d])
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'find all taggings for filtered records' do
|
22
|
-
taggings = Entity.where(attr: 'test2').send(column).taggings.order('name')
|
23
|
-
|
24
|
-
expect(taggings.size).to be_eql(2)
|
25
|
-
expect(taggings.map(&:name)).to be_eql(%w[b c])
|
26
|
-
end
|
27
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe 'ArrayStrings::Tags' do
|
4
|
-
before(:all) do
|
5
|
-
@column = :tags_str # defined as instance var as it is used in before_all callback
|
6
|
-
Entity.pg_tags_on @column
|
7
|
-
truncate && Factory.array_strings
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:column) { @column }
|
11
|
-
let(:ref) { %("#{Entity.table_name}"."#{column}") }
|
12
|
-
let(:relation) { Entity.send(column) }
|
13
|
-
|
14
|
-
it 'find all tags' do
|
15
|
-
tags = relation.all.order('name')
|
16
|
-
|
17
|
-
expect(tags.size).to be_eql(4)
|
18
|
-
expect(tags.map(&:name)).to be_eql(%w[a b c d])
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'find all tags for filtered records' do
|
22
|
-
tags = Entity.where(attr: 'test2').send(column).all
|
23
|
-
|
24
|
-
expect(tags.size).to be_eql(2)
|
25
|
-
expect(tags.map(&:name)).to be_eql(%w[b c])
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'find all tags with counts' do
|
29
|
-
tag = relation.all_with_counts.first
|
30
|
-
|
31
|
-
expect(tag.count).to be_eql(1)
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'count tags' do
|
35
|
-
expect(relation.count).to be_eql(4)
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'count tags for filtered records' do
|
39
|
-
expect(Entity.where(attr: 'test2').send(column).count).to be_eql(2)
|
40
|
-
end
|
41
|
-
|
42
|
-
context 'cast integers to strings' do
|
43
|
-
before do
|
44
|
-
Entity.create(attr: 'int1', column => [1])
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'find tags in numeric format' do
|
48
|
-
tags = relation.all.where(name: 1)
|
49
|
-
|
50
|
-
expect(tags.size).to be_eql(1)
|
51
|
-
expect(tags.map(&:name)).to be_eql(['1'])
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
data/spec/config/database.yml
DELETED
@@ -1,6 +0,0 @@
|
|
1
|
-
adapter: postgresql
|
2
|
-
host: <%= ENV.fetch("PG_HOST") { "localhost" } %>
|
3
|
-
port: <%= ENV.fetch("PG_PORT") { 5432 } %>
|
4
|
-
username: <%= ENV.fetch("PG_USER") { raise "PG_USER env. not set" } %>
|
5
|
-
password: <%= ENV.fetch("PG_PSWD") { raise "PG_PSWD env. not set" } %>
|
6
|
-
database: <%= ENV.fetch("PG_TAGS_ON_DB") { raise "PG_TAGS_ON_DB env. not set" } %>
|
data/spec/configuration_spec.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe 'configuration' do
|
4
|
-
before do
|
5
|
-
Entity.pg_tags_on_reset
|
6
|
-
end
|
7
|
-
|
8
|
-
it 'should set query class' do
|
9
|
-
PgTagsOn.configure do |c|
|
10
|
-
c.query_class = 'Tagz'
|
11
|
-
end
|
12
|
-
Entity.pg_tags_on :tags_int
|
13
|
-
|
14
|
-
expect(Kernel.const_defined?('Tagz')).to be_truthy
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'should set columns for multiple models' do
|
18
|
-
class Entity1 < ActiveRecord::Base
|
19
|
-
self.table_name = 'entities'
|
20
|
-
pg_tags_on :tags_int
|
21
|
-
end
|
22
|
-
|
23
|
-
class Entity2 < ActiveRecord::Base
|
24
|
-
self.table_name = 'entities'
|
25
|
-
pg_tags_on :tags_str
|
26
|
-
end
|
27
|
-
|
28
|
-
expect(Entity1.pg_tags_on_settings).to be_eql('tags_int' => {})
|
29
|
-
expect(Entity2.pg_tags_on_settings).to be_eql('tags_str' => {})
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'should set multiple columns for the same model' do
|
33
|
-
Entity.pg_tags_on :tags_int
|
34
|
-
Entity.pg_tags_on :tags_str
|
35
|
-
|
36
|
-
expect(Entity.pg_tags_on_settings).to be_eql('tags_int' => {}, 'tags_str' => {})
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'should raise error if column does not exists' do
|
40
|
-
expect { Entity.pg_tags_on(:dummy) }.to raise_error(PgTagsOn::ColumnNotFoundError)
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'should create named scopes' do
|
44
|
-
Entity.pg_tags_on :tags_int
|
45
|
-
|
46
|
-
expect(Entity).to respond_to(:tags_int)
|
47
|
-
end
|
48
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DatabaseHelpers
|
4
|
-
def establish_connection
|
5
|
-
ActiveRecord::Base.establish_connection(config)
|
6
|
-
end
|
7
|
-
|
8
|
-
def config
|
9
|
-
@config ||= begin
|
10
|
-
file = File.expand_path('../config/database.yml', File.dirname(__FILE__))
|
11
|
-
YAML.safe_load(ERB.new(File.read(file)).result)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def load_schema
|
16
|
-
@connection = ActiveRecord::Base.connection
|
17
|
-
@connection.drop_table :entities
|
18
|
-
@connection.transaction do
|
19
|
-
@connection.create_table :entities, force: true do |t|
|
20
|
-
t.integer :tags_int, array: true
|
21
|
-
t.string :tags_str, array: true
|
22
|
-
t.text :tags_text, array: true
|
23
|
-
t.jsonb :tags_jsonb, array: true
|
24
|
-
t.string :attr
|
25
|
-
end
|
26
|
-
@connection.add_index :entities, :tags_str, using: 'gin'
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def truncate
|
31
|
-
ActiveRecord::Base.connection.truncate(Entity.table_name)
|
32
|
-
end
|
33
|
-
|
34
|
-
def encode_json(json)
|
35
|
-
case json
|
36
|
-
when String
|
37
|
-
ActiveSupport::JSON.encode(json)
|
38
|
-
when Hash
|
39
|
-
ActiveSupport::JSON.encode(json.to_json)
|
40
|
-
when Array
|
41
|
-
"'{" + json.map { |item| encode_json(item) }.join(',') + "}'"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
module_function :config, :establish_connection, :load_schema, :truncate
|
46
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
WITH_COVERAGE = ENV['COVERAGE']
|
4
|
-
|
5
|
-
if WITH_COVERAGE
|
6
|
-
require 'simplecov'
|
7
|
-
SimpleCov.start do
|
8
|
-
add_filter %r{/benchmark/}
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
require 'pg'
|
13
|
-
require 'active_record'
|
14
|
-
require 'bundler/setup'
|
15
|
-
require 'pg_tags_on'
|
16
|
-
require 'helpers/database_helpers'
|
17
|
-
require 'support/factory'
|
18
|
-
require 'pry'
|
19
|
-
|
20
|
-
RSpec.configure do |config|
|
21
|
-
# Enable flags like --only-failures and --next-failure
|
22
|
-
config.example_status_persistence_file_path = '.rspec_status'
|
23
|
-
|
24
|
-
# Disable RSpec exposing methods globally on `Module` and `main`
|
25
|
-
config.disable_monkey_patching!
|
26
|
-
|
27
|
-
config.expect_with :rspec do |c|
|
28
|
-
c.syntax = :expect
|
29
|
-
end
|
30
|
-
|
31
|
-
config.include DatabaseHelpers
|
32
|
-
|
33
|
-
config.before(:all) do
|
34
|
-
DatabaseHelpers.establish_connection
|
35
|
-
DatabaseHelpers.load_schema
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
Entity = Class.new(::ActiveRecord::Base)
|
data/spec/support/factory.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Factory
|
4
|
-
def self.array_strings
|
5
|
-
Entity.insert_all([
|
6
|
-
{ tags_str: %w[a b c], attr: 'test1' },
|
7
|
-
{ tags_str: %w[b c], attr: 'test2' },
|
8
|
-
{ tags_str: ['d'], attr: 'test3' }
|
9
|
-
])
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.array_integers
|
13
|
-
Entity.insert_all([
|
14
|
-
{ tags_int: [1, 2, 3], attr: 'test1' },
|
15
|
-
{ tags_int: [2, 3], attr: 'test2' },
|
16
|
-
{ tags_int: [4], attr: 'test3' }
|
17
|
-
])
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.array_jsonb
|
21
|
-
Entity.insert_all([
|
22
|
-
{ tags_jsonb: [{ name: 'a' },
|
23
|
-
{ name: 'b' },
|
24
|
-
{ name: 'c' }],
|
25
|
-
attr: 'test1' },
|
26
|
-
{ tags_jsonb: [{ name: 'b' },
|
27
|
-
{ name: 'c' }],
|
28
|
-
attr: 'test2' },
|
29
|
-
{ tags_jsonb: [{ name: 'd' }],
|
30
|
-
attr: 'test3' }
|
31
|
-
])
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.array_jsonb_with_attrs
|
35
|
-
Entity.insert_all([
|
36
|
-
{ tags_jsonb: [{ name: 'a', meta: 'a' },
|
37
|
-
{ name: 'b', meta: 'b' },
|
38
|
-
{ name: 'c', meta: 'c' }],
|
39
|
-
attr: 'test1' },
|
40
|
-
{ tags_jsonb: [{ name: 'b', meta: 'b' },
|
41
|
-
{ name: 'c', meta: 'c' }],
|
42
|
-
attr: 'test2' },
|
43
|
-
{ tags_jsonb: [{ name: 'd', meta: 'd' }],
|
44
|
-
attr: 'test3' }
|
45
|
-
])
|
46
|
-
end
|
47
|
-
end
|