pg_tags_on 0.1.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +9 -0
- data/CHANGELOG.md +3 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +91 -0
- data/LICENSE.txt +21 -0
- data/README.md +195 -0
- data/Rakefile +16 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/lib/pg_tags_on/active_record/arel.rb +66 -0
- data/lib/pg_tags_on/active_record/base.rb +41 -0
- data/lib/pg_tags_on/benchmark/benchmark.rb +52 -0
- data/lib/pg_tags_on/predicate_handler/array_integer_handler.rb +9 -0
- data/lib/pg_tags_on/predicate_handler/array_jsonb_handler.rb +31 -0
- data/lib/pg_tags_on/predicate_handler/array_jsonb_with_attrs_handler.rb +41 -0
- data/lib/pg_tags_on/predicate_handler/array_string_handler.rb +9 -0
- data/lib/pg_tags_on/predicate_handler/array_text_handler.rb +9 -0
- data/lib/pg_tags_on/predicate_handler/base_handler.rb +89 -0
- data/lib/pg_tags_on/predicate_handler.rb +64 -0
- data/lib/pg_tags_on/repositories/array_jsonb_repository.rb +88 -0
- data/lib/pg_tags_on/repositories/array_repository.rb +103 -0
- data/lib/pg_tags_on/repositories/base_repository.rb +44 -0
- data/lib/pg_tags_on/repository.rb +59 -0
- data/lib/pg_tags_on/tag.rb +31 -0
- data/lib/pg_tags_on/tags_query.rb +27 -0
- data/lib/pg_tags_on/validations/validator.rb +43 -0
- data/lib/pg_tags_on/version.rb +5 -0
- data/lib/pg_tags_on.rb +56 -0
- data/pg_tags_on.gemspec +38 -0
- data/spec/array_integers/records_spec.rb +47 -0
- data/spec/array_integers/tag_ops_spec.rb +65 -0
- data/spec/array_integers/taggings_spec.rb +27 -0
- data/spec/array_integers/tags_spec.rb +53 -0
- data/spec/array_jsonb/records_spec.rb +89 -0
- data/spec/array_jsonb/tag_ops_spec.rb +115 -0
- data/spec/array_jsonb/taggings_spec.rb +27 -0
- data/spec/array_jsonb/tags_spec.rb +41 -0
- data/spec/array_strings/records_spec.rb +61 -0
- data/spec/array_strings/tag_ops_spec.rb +65 -0
- data/spec/array_strings/taggings_spec.rb +27 -0
- data/spec/array_strings/tags_spec.rb +54 -0
- data/spec/config/database.yml +6 -0
- data/spec/configuration_spec.rb +48 -0
- data/spec/helpers/database_helpers.rb +46 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/factory.rb +47 -0
- data/spec/tags_query_spec.rb +31 -0
- data/spec/validator_spec.rb +40 -0
- data/tasks/benchmark.rake +58 -0
- metadata +260 -0
data/pg_tags_on.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'pg_tags_on/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'pg_tags_on'
|
9
|
+
spec.version = PgTagsOn::VERSION
|
10
|
+
spec.authors = ['Catalin Marinescu']
|
11
|
+
spec.email = ['catalin.marinescu@gmail.com']
|
12
|
+
spec.summary = 'Manage tags stored in Postgresql column.'
|
13
|
+
spec.description = 'A gem that makes working with tags stored in a Postgresql column easy.Support for array of string, integer and jsonb values.'
|
14
|
+
spec.homepage = 'http://github.com/cata-m/pg_tags_on'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = 'http://github.com/cata-m/pg_tags_on'
|
18
|
+
spec.metadata['changelog_uri'] = 'http://github.com/cata-m/pg_tags_on/blob/master/CHANGELOG.md'
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = `git ls-files -z`.split("\x0")
|
23
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
24
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
25
|
+
spec.require_paths = ['lib']
|
26
|
+
|
27
|
+
spec.add_dependency 'activerecord', '~> 6.0'
|
28
|
+
spec.add_dependency 'activesupport', '~> 6.0'
|
29
|
+
|
30
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
31
|
+
spec.add_development_dependency 'faker', '~> 2.10'
|
32
|
+
spec.add_development_dependency 'pg', '~> 1.2'
|
33
|
+
spec.add_development_dependency 'pry', '~> 0.12'
|
34
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
35
|
+
spec.add_development_dependency 'rspec', '~> 3.9'
|
36
|
+
spec.add_development_dependency 'rubocop', '~> 0.80'
|
37
|
+
spec.add_development_dependency 'simplecov', '~> 0.18'
|
38
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe 'ArrayIntegers::Records' do
|
4
|
+
before(:all) do
|
5
|
+
@column = :tags_int # defined as instance var as it is used in before_all callback
|
6
|
+
Entity.pg_tags_on @column
|
7
|
+
truncate && Factory.array_integers
|
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(2))
|
16
|
+
|
17
|
+
expect(rel.to_sql).to include(%(#{ref} @> '{2}'))
|
18
|
+
expect(rel.count).to be_eql(2)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'find records with exact same tags' do
|
22
|
+
rel = Entity.where(column => Tags.eq(%w[3 2]))
|
23
|
+
|
24
|
+
expect(rel.count).to be_eql(1)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'find records with all tags' do
|
28
|
+
rel = Entity.where(column => Tags.all([1, 2, 3]))
|
29
|
+
|
30
|
+
expect(rel.to_sql).to include(%(#{ref} @> '{1,2,3}'))
|
31
|
+
expect(rel.count).to be_eql(1)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'find records with any tag' do
|
35
|
+
rel = Entity.where(column => Tags.any([1, 2, 3]))
|
36
|
+
|
37
|
+
expect(rel.to_sql).to include(%(#{ref} && '{1,2,3}'))
|
38
|
+
expect(rel.count).to be_eql(2)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'find records with tags included in tag list' do
|
42
|
+
rel = Entity.where(column => Tags.in([1, 2, 3]))
|
43
|
+
|
44
|
+
expect(rel.to_sql).to include(%(#{ref} <@ '{1,2,3}'))
|
45
|
+
expect(rel.count).to be_eql(2)
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe 'ArrayIntegers::TagOps' do
|
4
|
+
before(:all) do
|
5
|
+
@column = :tags_int # 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_integers
|
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(5)
|
20
|
+
|
21
|
+
Entity.all.each do |entity|
|
22
|
+
expect(entity.send(column)).to include(5)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'create tag for filtered records' do
|
27
|
+
Entity.where(attr: 'test2').send(column).create(6)
|
28
|
+
|
29
|
+
expect(Entity.find_by_attr('test1').send(column)).not_to include(6)
|
30
|
+
expect(Entity.find_by_attr('test2').send(column)).to include(6)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'update' do
|
35
|
+
it 'update tag' do
|
36
|
+
relation.update(2, 22)
|
37
|
+
|
38
|
+
count = Entity.where(column => Tags.all(22)).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(3, 33)
|
44
|
+
|
45
|
+
count = Entity.where(column => Tags.all(33)).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(2)
|
53
|
+
|
54
|
+
tags = relation.all.pluck(:name)
|
55
|
+
expect(tags).not_to include(2)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'delete tag for filtered records' do
|
59
|
+
Entity.where(attr: 'test2').send(column).delete(3)
|
60
|
+
|
61
|
+
expect(Entity.find_by_attr('test1').send(column)).to include(3)
|
62
|
+
expect(Entity.find_by_attr('test2').send(column)).not_to include(3)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe 'ArrayIntegers::Taggings' do
|
4
|
+
before(:all) do
|
5
|
+
@column = :tags_int # defined as instance var as it is used in before_all callback
|
6
|
+
Entity.pg_tags_on @column
|
7
|
+
truncate && Factory.array_integers
|
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([1, 2, 2, 3, 3, 4])
|
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([2, 3])
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe 'ArrayIntegers::Tags' do
|
4
|
+
before(:all) do
|
5
|
+
@column = :tags_int # defined as instance var as it is used in before_all callback
|
6
|
+
Entity.pg_tags_on @column
|
7
|
+
truncate && Factory.array_integers
|
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
|
+
expect(tags.size).to be_eql(4)
|
17
|
+
expect(tags.map(&:name)).to be_eql([1, 2, 3, 4])
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'find all tags for filtered records' do
|
21
|
+
tags = Entity.where(attr: 'test2').send(column).all
|
22
|
+
|
23
|
+
expect(tags.size).to be_eql(2)
|
24
|
+
expect(tags.map(&:name)).to be_eql([2, 3])
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'find all tags with counts' do
|
28
|
+
tag = relation.all_with_counts.first
|
29
|
+
|
30
|
+
expect(tag.count).to be_eql(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'count tags' do
|
34
|
+
expect(relation.count).to be_eql(4)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'count tags for filtered records' do
|
38
|
+
expect(Entity.where(attr: 'test2').send(column).count).to be_eql(2)
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'cast strings to integers' do
|
42
|
+
before do
|
43
|
+
Entity.create(attr: 'int1', column => %w[1])
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'find tags' do
|
47
|
+
tags = relation.all.where(name: '1')
|
48
|
+
|
49
|
+
expect(tags.size).to be_eql(1)
|
50
|
+
expect(tags.map(&:name)).to be_eql([1])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe 'ArrayJsonb::Records' do
|
4
|
+
before(:all) do
|
5
|
+
@column = :tags_jsonb # defined as instance var as it is used in before_all callback
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:column) { @column }
|
9
|
+
let(:ref) { %("#{Entity.table_name}"."#{column}") }
|
10
|
+
let(:relation) { Entity.send(column) }
|
11
|
+
|
12
|
+
context 'objects have only one key' do
|
13
|
+
before(:all) do
|
14
|
+
Entity.pg_tags_on @column, key: :name
|
15
|
+
truncate && Factory.array_jsonb
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'find records by tag' do
|
19
|
+
rel = Entity.where(column => Tags.one('b'))
|
20
|
+
expected_sql = %(#{ref} @> #{encode_json([{ name: 'b' }])})
|
21
|
+
|
22
|
+
expect(rel.to_sql).to include(expected_sql)
|
23
|
+
expect(rel.count).to be_eql(2)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'find records with exact same tags' do
|
27
|
+
rel = Entity.where(column => Tags.eq(%w[b c]))
|
28
|
+
|
29
|
+
expect(rel.count).to be_eql(1)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'find records with all tags' do
|
33
|
+
rel = Entity.where(column => Tags.all(%w[a b c]))
|
34
|
+
expected_sql = %(#{ref} @> #{encode_json([{ name: 'a' }, { name: 'b' }, { name: 'c' }])})
|
35
|
+
|
36
|
+
expect(rel.to_sql).to include(expected_sql)
|
37
|
+
expect(rel.count).to be_eql(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'find records with any tags' do
|
41
|
+
rel = Entity.where(column => Tags.any(%w[a b c]))
|
42
|
+
expected_sql = %(#{ref} && #{encode_json([{ name: 'a' }, { name: 'b' }, { name: 'c' }])})
|
43
|
+
|
44
|
+
expect(rel.to_sql).to include(expected_sql)
|
45
|
+
expect(rel.count).to be_eql(2)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'find records with tags included in tag list' do
|
49
|
+
rel = Entity.where(column => Tags.in(%w[a b c]))
|
50
|
+
expected_sql = %(#{ref} <@ #{encode_json([{ name: 'a' }, { name: 'b' }, { name: 'c' }])})
|
51
|
+
|
52
|
+
expect(rel.to_sql).to include(expected_sql)
|
53
|
+
expect(rel.count).to be_eql(2)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'objects have multiple keys' do
|
58
|
+
before(:all) do
|
59
|
+
Entity.pg_tags_on @column, key: :name, has_attributes: true
|
60
|
+
truncate && Factory.array_jsonb_with_attrs
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'find records by tag' do
|
64
|
+
rel = Entity.where(column => Tags.one('b'))
|
65
|
+
expect(rel.count).to be_eql(2)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'find records with exact same tags' do
|
69
|
+
rel = Entity.where(column => Tags.eq(%w[b c]))
|
70
|
+
|
71
|
+
expect(rel.count).to be_eql(1)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'find records with all tags' do
|
75
|
+
rel = Entity.where(column => Tags.all(%w[a b c]))
|
76
|
+
expect(rel.count).to be_eql(1)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'find records with any tags' do
|
80
|
+
rel = Entity.where(column => Tags.any(%w[a b c]))
|
81
|
+
expect(rel.count).to be_eql(2)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'find records with tags included in tag list' do
|
85
|
+
rel = Entity.where(column => Tags.in(%w[a b c]))
|
86
|
+
expect(rel.count).to be_eql(2)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe 'ArrayJsonb::TagOps' do
|
4
|
+
before(:all) do
|
5
|
+
@column = :tags_jsonb
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:column) { @column }
|
9
|
+
let(:ref) { %("#{Entity.table_name}"."#{column}") }
|
10
|
+
let(:relation) { Entity.send(column) }
|
11
|
+
|
12
|
+
context 'objects has only one key' do
|
13
|
+
before(:all) do
|
14
|
+
Entity.pg_tags_on @column, key: :name
|
15
|
+
truncate && Factory.array_jsonb
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'create' do
|
19
|
+
it 'create tag' do
|
20
|
+
relation.create('new-tag1')
|
21
|
+
|
22
|
+
Entity.all.each do |entity|
|
23
|
+
expect(entity.send(column)).to include({ 'name' => 'new-tag1' })
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'create tag for filtered records' do
|
28
|
+
Entity.where(attr: 'test2').send(column).create('new-tag2')
|
29
|
+
|
30
|
+
expect(Entity.find_by_attr('test1').send(column)).not_to include({ 'name' => 'new-tag2' })
|
31
|
+
expect(Entity.find_by_attr('test2').send(column)).to include({ 'name' => 'new-tag2' })
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'update' do
|
36
|
+
it 'update tag' do
|
37
|
+
relation.update('b', 'updated-b')
|
38
|
+
|
39
|
+
count = Entity.where(column => Tags.all('updated-b')).count
|
40
|
+
expect(count).to be_eql(2)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'update tag for filtered records' do
|
44
|
+
Entity.where(attr: 'test2').send(column).update('c', 'updated-c')
|
45
|
+
|
46
|
+
count = Entity.where(column => Tags.all('updated-c')).count
|
47
|
+
expect(count).to be_eql(1)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'delete' do
|
52
|
+
it 'delete tag' do
|
53
|
+
relation.delete('b')
|
54
|
+
|
55
|
+
tags = relation.all.pluck(:name)
|
56
|
+
expect(tags).not_to include('b')
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'delete tag for filtered records' do
|
60
|
+
Entity.where(attr: 'test2').send(column).delete('c')
|
61
|
+
|
62
|
+
expect(Entity.where(attr: 'test1').send(column).all.pluck(:name)).to include('c')
|
63
|
+
expect(Entity.where(attr: 'test2').send(column).all.pluck(:name)).not_to include('c')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'objects have multiple keys' do
|
69
|
+
before(:all) do
|
70
|
+
Entity.pg_tags_on @column, key: :name, has_attributes: true
|
71
|
+
end
|
72
|
+
|
73
|
+
before(:each) do
|
74
|
+
truncate && Factory.array_jsonb_with_attrs
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'update' do
|
78
|
+
it 'update tag' do
|
79
|
+
relation.update('b', 'updated-b')
|
80
|
+
|
81
|
+
rel = Entity.where(column => Tags.all('updated-b'))
|
82
|
+
expect(rel.count).to be_eql(2)
|
83
|
+
rel.all.each do |record|
|
84
|
+
expect(record.tags_jsonb).to include({ 'meta' => 'b', 'name' => 'updated-b' })
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'update tag for filtered records' do
|
89
|
+
Entity.where(attr: 'test2').send(column).update('c', 'updated-c')
|
90
|
+
|
91
|
+
rel = Entity.where(column => Tags.all('updated-c'))
|
92
|
+
expect(rel.count).to be_eql(1)
|
93
|
+
rel.all.each do |record|
|
94
|
+
expect(record.tags_jsonb).to include({ 'meta' => 'c', 'name' => 'updated-c' })
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'delete' do
|
100
|
+
it 'delete tag' do
|
101
|
+
relation.delete('b')
|
102
|
+
|
103
|
+
tags = relation.all.pluck(:name)
|
104
|
+
expect(tags).not_to include('b')
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'delete tag for filtered records' do
|
108
|
+
Entity.where(attr: 'test2').send(column).delete('c')
|
109
|
+
|
110
|
+
expect(Entity.where(attr: 'test1').send(column).all.pluck(:name)).to include('c')
|
111
|
+
expect(Entity.where(attr: 'test2').send(column).all.pluck(:name)).not_to include('c')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,27 @@
|
|
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
|
@@ -0,0 +1,41 @@
|
|
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
|
@@ -0,0 +1,61 @@
|
|
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
|
@@ -0,0 +1,65 @@
|
|
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
|
@@ -0,0 +1,27 @@
|
|
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
|