pgrel 0.1.3 → 0.2.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/.travis.yml +1 -1
- data/CHANGELOG.md +12 -0
- data/README.md +49 -7
- data/lib/pgrel/active_record.rb +5 -0
- data/lib/pgrel/active_record/querying.rb +5 -0
- data/lib/pgrel/active_record/relation.rb +19 -0
- data/lib/pgrel/active_record/store/flexible_hstore.rb +24 -0
- data/lib/pgrel/active_record/store/flexible_jsonb.rb +25 -0
- data/lib/pgrel/active_record/store/flexible_store.rb +13 -0
- data/lib/pgrel/active_record/store_chain.rb +21 -13
- data/lib/pgrel/active_record/store_chain/hstore_chain.rb +27 -0
- data/lib/pgrel/active_record/store_chain/jsonb_chain.rb +49 -0
- data/lib/pgrel/version.rb +1 -1
- data/spec/pgrel/hstore_spec.rb +81 -4
- data/spec/pgrel/jsonb_spec.rb +67 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43d4c6d3c7078b0823c3da86d1749db92e7b86f9759fb17326b3065780290649
|
4
|
+
data.tar.gz: ebf600d3ccb22d4bed4dc4f6a479c7f3c1aa65e300edebbcaaded0da9e8698cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7a7c10c700279fbc1943d44e478ddbc096fe35af24d1733b4cc95bf564322580c177abbc56c3e76f2ffcd69053229badab34b5e9cc53b496e1d8a638118f662
|
7
|
+
data.tar.gz: b8381c2b638a70e58c9159b3a8ab2a3ecd2261a305d376fa2346f91dc7130ff163caafbe237bfe4f0c3c503f51c28be15dbb95e7e20421478187f4bc29c4792e
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -6,21 +6,21 @@ ActiveRecord extension for querying hstore, array and jsonb.
|
|
6
6
|
|
7
7
|
Compatible with **Rails** >= 4.2.
|
8
8
|
|
9
|
-
### General
|
10
|
-
|
11
|
-
The functionality is based on ActiveRecord `WhereChain`.
|
12
|
-
To start querying call `where(:store_name)` and chain it with store-specific call (see below).
|
13
|
-
|
14
9
|
#### Install
|
15
10
|
|
16
11
|
In your Gemfile:
|
17
12
|
|
18
13
|
```ruby
|
19
|
-
gem "pgrel", "~>0.
|
14
|
+
gem "pgrel", "~> 0.2"
|
20
15
|
```
|
21
16
|
|
22
17
|
### HStore
|
23
18
|
|
19
|
+
#### Querying
|
20
|
+
|
21
|
+
The functionality is based on ActiveRecord `WhereChain`.
|
22
|
+
To start querying call `where(:store_name)` and chain it with store-specific call (see below).
|
23
|
+
|
24
24
|
Query by key value:
|
25
25
|
|
26
26
|
```ruby
|
@@ -29,6 +29,12 @@ Hstore.where.store(:tags, a: 1, b: 2)
|
|
29
29
|
|
30
30
|
Hstore.where.store(:tags, a: [1, 2])
|
31
31
|
#=> select * from hstores where (tags @> '"a"=>"1"' or tags @> '"a"=>"2"')
|
32
|
+
|
33
|
+
Hstore.where.store(:tags, :a)
|
34
|
+
#=> select * from hstores where (tags @> '"a"=>NULL')
|
35
|
+
|
36
|
+
Hstore.where.store(:tags, { a: 1 }, { b: 2 })
|
37
|
+
#=> select * from hstores where (tags @> '"a"=>"1" or tags @> "b"=>"2"')
|
32
38
|
```
|
33
39
|
|
34
40
|
Keys existence:
|
@@ -47,6 +53,18 @@ Hstore.where.store(:tags).any('a', 'b')
|
|
47
53
|
#=> select * from hstores where tags ?| array['a', 'b']
|
48
54
|
```
|
49
55
|
|
56
|
+
Values existence:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
# Retrieve items that have value '1' OR '2'
|
60
|
+
Hstore.where.store(:tags).value(1, 2)
|
61
|
+
#=> select * from hstores where (avals(tags) @> ARRAY['1'] OR avals(tags) @> ARRAY['2'] )
|
62
|
+
|
63
|
+
# Retrieve items that have values '1' AND '2'
|
64
|
+
Hstore.where.store(:tags).values(1, 2)
|
65
|
+
#=> select * from hstores where (avals(tags) @> ARRAY['1', '2'])
|
66
|
+
```
|
67
|
+
|
50
68
|
Containment:
|
51
69
|
|
52
70
|
```ruby
|
@@ -57,9 +75,33 @@ Hstore.where.store(:tags).contained(a: 1, b: 2)
|
|
57
75
|
#=> select * from hstores where tags <@ '\"a\"=>\"1\", \"b\"=>\"2\"'
|
58
76
|
```
|
59
77
|
|
78
|
+
#### Update
|
79
|
+
|
80
|
+
Is implemented through `ActiveRecord::Store::FlexibleHstore` and `ActiveRecord::Store::FlexibleJsonb`
|
81
|
+
objects. You can get them by sending `update_store(store_name)` to relation or class.
|
82
|
+
|
83
|
+
Add key, value pairs:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
Hstore.update_store(:tags).merge(new_key: 1, one_more: 2)
|
87
|
+
Hstore.update_store(:tags).merge([[:new_key, 1], [:one_more, 2]])
|
88
|
+
```
|
89
|
+
|
90
|
+
Delete keys:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
Hstore.update_store(:tags).delete_keys(:a, :b)
|
94
|
+
```
|
95
|
+
|
96
|
+
Delete key, value pairs:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
Hstore.update_store(:tags).delete_pairs(a: 1, b: 2)
|
100
|
+
```
|
101
|
+
|
60
102
|
### JSONB
|
61
103
|
|
62
|
-
All queries for Hstore also available for JSONB.
|
104
|
+
All queries and updates for Hstore also available for JSONB.
|
63
105
|
|
64
106
|
**NOTE**. Querying by array value always resolves to `(... or ...)` statement.
|
65
107
|
Thus it's impossible to query json array value, e.g.:
|
data/lib/pgrel/active_record.rb
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'active_record'
|
4
|
+
require 'pgrel/active_record/relation'
|
5
|
+
require 'pgrel/active_record/store/flexible_store'
|
6
|
+
require 'pgrel/active_record/store/flexible_hstore'
|
7
|
+
require 'pgrel/active_record/store/flexible_jsonb'
|
8
|
+
require 'pgrel/active_record/querying'
|
4
9
|
require 'pgrel/active_record/query_methods'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class Relation
|
5
|
+
def update_store(store_name)
|
6
|
+
raise ArgumentError, "Empty store name to update" if store_name.blank?
|
7
|
+
type = type_for_attribute(store_name.to_s).type
|
8
|
+
raise TypeConflictError, store_type_error_msg(type) if %i(hstore jsonb).exclude?(type)
|
9
|
+
klass = "ActiveRecord::Store::Flexible#{type.capitalize}".constantize
|
10
|
+
klass.new(self, store_name)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def store_type_error_msg(type)
|
16
|
+
"Column type is not a known store: #{type}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Store
|
5
|
+
class FlexibleHstore < ActiveRecord::Store::FlexibleStore
|
6
|
+
def delete_keys(*keys)
|
7
|
+
keys = keys.flatten.map(&:to_s)
|
8
|
+
relation.update_all(["#{store_name} = delete(#{store_name}, ARRAY[:keys])", keys: keys])
|
9
|
+
end
|
10
|
+
|
11
|
+
def merge(pairs)
|
12
|
+
relation.update_all(["#{store_name} = hstore(#{store_name}) || hstore(ARRAY[:keys])",
|
13
|
+
keys: pairs.to_a.flatten.map(&:to_s)])
|
14
|
+
end
|
15
|
+
|
16
|
+
def delete_pairs(pairs)
|
17
|
+
relation.update_all(
|
18
|
+
["#{store_name} = delete(#{store_name}, hstore(ARRAY[:keys], ARRAY[:values]))",
|
19
|
+
keys: pairs.keys.map(&:to_s), values: pairs.values.map(&:to_s)]
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Store
|
5
|
+
class FlexibleJsonb < ActiveRecord::Store::FlexibleStore
|
6
|
+
def delete_keys(*keys)
|
7
|
+
keys.flatten!
|
8
|
+
query = String.new "#{store_name} = #{store_name}"
|
9
|
+
keys.length.times { query.concat(' - ?') }
|
10
|
+
relation.update_all([query, *keys])
|
11
|
+
end
|
12
|
+
|
13
|
+
def merge(pairs)
|
14
|
+
relation.update_all(["#{store_name} = #{store_name} || ?::jsonb", pairs.to_json])
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete_pairs(pairs)
|
18
|
+
keys = pairs.keys
|
19
|
+
pairs = pairs.map { |k,v| { k => v } }
|
20
|
+
@relation = relation.where.store(store_name, *pairs)
|
21
|
+
delete_keys(keys)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -68,16 +68,20 @@ module ActiveRecord
|
|
68
68
|
# Model.store(:store, b: [1, 2]).size #=> 2
|
69
69
|
# #=> (SQL) select * from ... where (store @> '"c"=>"1"'::hstore) or
|
70
70
|
# (store @> '"c"=>"2"'::hstore)
|
71
|
-
def where(opts)
|
71
|
+
def where(*opts)
|
72
|
+
opts.map! { |opt| opt.is_a?(Hash) ? opt : [opt] }
|
73
|
+
|
72
74
|
update_scope(
|
73
|
-
opts.map do |
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
75
|
+
opts.map do |opt|
|
76
|
+
opt.map do |k, v|
|
77
|
+
case v
|
78
|
+
when Array
|
79
|
+
"(#{build_or_contains(k, v)})"
|
80
|
+
else
|
81
|
+
contains_clause(k => v)
|
82
|
+
end
|
83
|
+
end.join(' and ')
|
84
|
+
end.join(' or ')
|
81
85
|
)
|
82
86
|
@scope
|
83
87
|
end
|
@@ -196,10 +200,14 @@ module ActiveRecord
|
|
196
200
|
rel.left = to_sql_literal(prefix, rel.left)
|
197
201
|
rel
|
198
202
|
end
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
+
|
204
|
+
params = if ActiveRecord.version.release >= Gem::Version.new("5.2.0")
|
205
|
+
[predicates]
|
206
|
+
else
|
207
|
+
[predicates, where_clause.binds]
|
208
|
+
end
|
209
|
+
|
210
|
+
where_clause = ActiveRecord::Relation::WhereClause.new(*params)
|
203
211
|
@scope.where_clause += @inverted ? where_clause.invert : where_clause
|
204
212
|
@scope
|
205
213
|
end
|
@@ -4,6 +4,33 @@ module ActiveRecord
|
|
4
4
|
module QueryMethods
|
5
5
|
# Store chain for hstore columns.
|
6
6
|
class HstoreChain < KeyStoreChain
|
7
|
+
# Value existence
|
8
|
+
#
|
9
|
+
# Example
|
10
|
+
# Model.create!(name: 'first', store: {a: 1, b: 2})
|
11
|
+
# Model.create!(name: 'second', store: {b: 1, c: 3})
|
12
|
+
#
|
13
|
+
# Model.store(:store).value(1, 2).all
|
14
|
+
# #=>[Model(name: 'first', ...), Model(name: 'second')]
|
15
|
+
def value(*values)
|
16
|
+
query = String.new
|
17
|
+
values.length.times do |n|
|
18
|
+
query.concat("avals(#{@store_name}) @> ARRAY[?]")
|
19
|
+
query.concat(' OR ') if n < values.length - 1
|
20
|
+
end
|
21
|
+
update_scope(query, *values.map(&:to_s))
|
22
|
+
end
|
23
|
+
|
24
|
+
# Values existence
|
25
|
+
#
|
26
|
+
# Example
|
27
|
+
# Model.create!(name: 'first', store: {a: 1, b: 2})
|
28
|
+
# Model.create!(name: 'second', store: {b: 1, c: 3})
|
29
|
+
#
|
30
|
+
# Model.store(:store).values(1, 2).all #=> [Model(name: 'first', ...)]
|
31
|
+
def values(*values)
|
32
|
+
update_scope("avals(#{@store_name}) @> ARRAY[?]", values.map(&:to_s))
|
33
|
+
end
|
7
34
|
end
|
8
35
|
end
|
9
36
|
end
|
@@ -33,6 +33,51 @@ module ActiveRecord
|
|
33
33
|
where_with_prefix "#{@store_name}#{op}", path => val
|
34
34
|
end
|
35
35
|
|
36
|
+
# Value existence
|
37
|
+
#
|
38
|
+
# Example
|
39
|
+
# Model.create!(name: 'first', store: {a: 1, b: 2})
|
40
|
+
# Model.create!(name: 'second', store: {b: 1, c: 3})
|
41
|
+
#
|
42
|
+
# Model.store(:store).values(1, 2).all
|
43
|
+
# #=>[Model(name: 'first', ...), Model(name: 'second')]
|
44
|
+
def value(*values)
|
45
|
+
query = String.new
|
46
|
+
values = values.map do |v|
|
47
|
+
case v
|
48
|
+
when Hash, Array, String
|
49
|
+
v.to_json
|
50
|
+
else
|
51
|
+
v.to_s
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
values.length.times do |n|
|
56
|
+
query.concat(value_existence_query)
|
57
|
+
query.concat(' OR ') if n < values.length - 1
|
58
|
+
end
|
59
|
+
update_scope(query, *values)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Values existence
|
63
|
+
#
|
64
|
+
# Example
|
65
|
+
# Model.create!(name: 'first', store: {a: 1, b: 2})
|
66
|
+
# Model.create!(name: 'second', store: {b: 1, c: 3})
|
67
|
+
#
|
68
|
+
# Model.store(:store).values(1, 2).all #=> [Model(name: 'first', ...)]
|
69
|
+
def values(*values)
|
70
|
+
values = values.map do |v|
|
71
|
+
case v
|
72
|
+
when Hash, Array, String
|
73
|
+
v.to_json
|
74
|
+
else
|
75
|
+
v.to_s
|
76
|
+
end
|
77
|
+
end
|
78
|
+
update_scope(value_existence_query, values)
|
79
|
+
end
|
80
|
+
|
36
81
|
private
|
37
82
|
|
38
83
|
def flatten_hash(hash)
|
@@ -45,6 +90,10 @@ module ActiveRecord
|
|
45
90
|
hash
|
46
91
|
end
|
47
92
|
end
|
93
|
+
|
94
|
+
def value_existence_query
|
95
|
+
"(SELECT array_agg(value) FROM jsonb_each(#{@store_name})) @> ARRAY[?]::jsonb[]"
|
96
|
+
end
|
48
97
|
end
|
49
98
|
end
|
50
99
|
end
|
data/lib/pgrel/version.rb
CHANGED
data/spec/pgrel/hstore_spec.rb
CHANGED
@@ -24,7 +24,9 @@ describe Hstore do
|
|
24
24
|
Hstore.create!(name: 'c', tags: { f: true, d: 'b' })
|
25
25
|
Hstore.create!(name: 'd', tags: { f: false })
|
26
26
|
Hstore.create!(name: 'e', tags: { a: 2, c: 'x', d: 'c', g: 'c' })
|
27
|
+
Hstore.create!(name: 'f', tags: { i: [1, 2, { a: 1 }], j: { a: 1, b: [1], f: false } } )
|
27
28
|
Hstore.create!(tags: { 1 => 2 })
|
29
|
+
Hstore.create!(name: 'z', tags: { z: nil })
|
28
30
|
end
|
29
31
|
|
30
32
|
context '#where' do
|
@@ -61,6 +63,21 @@ describe Hstore do
|
|
61
63
|
).size
|
62
64
|
).to eq 2
|
63
65
|
end
|
66
|
+
|
67
|
+
it 'lonely keys' do
|
68
|
+
records = Hstore.where.store(:tags, [:z])
|
69
|
+
expect(records.size).to eq 1
|
70
|
+
expect(records.first.name).to eq 'z'
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'many hashes' do
|
74
|
+
expect(Hstore.where.store(:tags, { a: 2 }, { b: 2 }).size).to eq 3
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'many hashes and lonely keys' do
|
78
|
+
expect(Hstore.where.store(:tags, { a: 1 }, :z).size).to eq 2
|
79
|
+
expect(Hstore.where.store(:tags, { a: 1 }, [:z]).size).to eq 2
|
80
|
+
end
|
64
81
|
end
|
65
82
|
|
66
83
|
it '#key' do
|
@@ -82,6 +99,26 @@ describe Hstore do
|
|
82
99
|
expect(records.first.name).to eq 'e'
|
83
100
|
end
|
84
101
|
|
102
|
+
it '#value' do
|
103
|
+
records = Hstore.where.store(:tags).value(1, false, [1, 2, { a: 1 }])
|
104
|
+
expect(records.size).to eq 3
|
105
|
+
end
|
106
|
+
|
107
|
+
it '#values' do
|
108
|
+
records = Hstore.where.store(:tags).values(1)
|
109
|
+
expect(records.size).to eq 1
|
110
|
+
expect(records.first.name).to eq 'a'
|
111
|
+
|
112
|
+
records = Hstore.where.store(:tags).values('2', 'b')
|
113
|
+
expect(records.size).to eq 2
|
114
|
+
|
115
|
+
records = Hstore.where.store(:tags).values(true)
|
116
|
+
expect(records.size).to eq 2
|
117
|
+
|
118
|
+
records = Hstore.where.store(:tags).values([1, 2, { a: 1 }], { a: 1, b: [1], f: false })
|
119
|
+
expect(records.size).to eq 1
|
120
|
+
end
|
121
|
+
|
85
122
|
it '#any' do
|
86
123
|
records = Hstore.where.store(:tags).any('b', 'f')
|
87
124
|
expect(records.size).to eq 3
|
@@ -116,16 +153,56 @@ describe Hstore do
|
|
116
153
|
|
117
154
|
context '#not' do
|
118
155
|
it '#where' do
|
119
|
-
expect(Hstore.where.store(:tags).not(a: 2).size).to eq
|
120
|
-
expect(Hstore.where.store(:tags).not(a: 1, g: 'c').size).to eq
|
156
|
+
expect(Hstore.where.store(:tags).not(a: 2).size).to eq 6
|
157
|
+
expect(Hstore.where.store(:tags).not(a: 1, g: 'c').size).to eq 8
|
121
158
|
end
|
122
159
|
|
123
160
|
it '#any' do
|
124
|
-
expect(Hstore.where.store(:tags).not.any('a', 'f').size).to eq
|
161
|
+
expect(Hstore.where.store(:tags).not.any('a', 'f').size).to eq 3
|
125
162
|
end
|
126
163
|
|
127
164
|
it '#keys' do
|
128
|
-
expect(Hstore.where.store(:tags).not.keys('a', 'f').size).to eq
|
165
|
+
expect(Hstore.where.store(:tags).not.keys('a', 'f').size).to eq 7
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context "#update_store" do
|
170
|
+
let(:store) { :tags }
|
171
|
+
|
172
|
+
subject { Hstore.update_store(store) }
|
173
|
+
|
174
|
+
it "works on relation" do
|
175
|
+
Hstore.where.store(store).keys(:a).update_store(store).delete_keys(:a)
|
176
|
+
expect(Hstore.where.store(store).keys(:a)).to_not exist
|
177
|
+
end
|
178
|
+
|
179
|
+
it "#delete_keys" do
|
180
|
+
subject.delete_keys(:i)
|
181
|
+
expect(Hstore.where.store(store).keys(:i)).to_not exist
|
182
|
+
|
183
|
+
subject.delete_keys(:a, :b)
|
184
|
+
expect(Hstore.where.store(store).keys(:a)).to_not exist
|
185
|
+
expect(Hstore.where.store(store).keys(:b)).to_not exist
|
186
|
+
|
187
|
+
subject.delete_keys([:c, :d])
|
188
|
+
expect(Hstore.where.store(store).keys(:c)).to_not exist
|
189
|
+
expect(Hstore.where.store(store).keys(:d)).to_not exist
|
190
|
+
end
|
191
|
+
|
192
|
+
it "#merge" do
|
193
|
+
subject.merge(new_key: 1)
|
194
|
+
expect(Hstore.where.store(store).keys(:new_key).count).to be_eql Hstore.count
|
195
|
+
|
196
|
+
subject.merge([['new_key2', 'a'], ['new_key3', 'b']])
|
197
|
+
expect(Hstore.where.store(store).keys(:new_key2, :new_key3).count).to be_eql Hstore.count
|
198
|
+
end
|
199
|
+
|
200
|
+
it "#delete_pairs" do
|
201
|
+
subject.delete_pairs(f: true, a: 1)
|
202
|
+
expect(Hstore.where.store(store, f: true)).to_not exist
|
203
|
+
expect(Hstore.where.store(store, a: 1)).to_not exist
|
204
|
+
expect(Hstore.where.store(store, f: false)).to exist
|
205
|
+
expect(Hstore.where.store(store, a: 2)).to exist
|
129
206
|
end
|
130
207
|
end
|
131
208
|
end
|
data/spec/pgrel/jsonb_spec.rb
CHANGED
@@ -25,6 +25,8 @@ describe Jsonb do
|
|
25
25
|
Jsonb.create!(name: 'd', tags: { a: 1, b: { c: 'd', e: true } })
|
26
26
|
Jsonb.create!(name: 'e', tags: { b: 2, c: 'e' })
|
27
27
|
Jsonb.create!(name: 'f', tags: { d: { e: 1, f: { h: { k: 'a', s: 2 } } } })
|
28
|
+
Jsonb.create!(name: 'g', tags: { f: false, g: { a: 1, b: '1' }, h: [1, '1'] })
|
29
|
+
Jsonb.create!(name: 'z', tags: { z: nil } )
|
28
30
|
end
|
29
31
|
|
30
32
|
context '#where' do
|
@@ -44,6 +46,21 @@ describe Jsonb do
|
|
44
46
|
it 'arrays (as IN)' do
|
45
47
|
expect(Jsonb.where.store(:tags, a: [1, 2, 3]).size).to eq 3
|
46
48
|
end
|
49
|
+
|
50
|
+
it 'lonely keys' do
|
51
|
+
records = Jsonb.where.store(:tags, [:z])
|
52
|
+
expect(records.size).to eq 1
|
53
|
+
expect(records.first.name).to eq 'z'
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'many hashes' do
|
57
|
+
expect(Jsonb.where.store(:tags, { a: 2 }, { b: 2 }).size).to eq 2
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'many hashes and lonely keys' do
|
61
|
+
expect(Jsonb.where.store(:tags, { a: 2 }, :z).size).to eq 2
|
62
|
+
expect(Jsonb.where.store(:tags, { a: 2 }, [:z]).size).to eq 2
|
63
|
+
end
|
47
64
|
end
|
48
65
|
|
49
66
|
context '#path' do
|
@@ -91,6 +108,26 @@ describe Jsonb do
|
|
91
108
|
expect(records.first.name).to eq 'e'
|
92
109
|
end
|
93
110
|
|
111
|
+
it '#value' do
|
112
|
+
records = Jsonb.where.store(:tags).value(1, false, { e: 2 })
|
113
|
+
expect(records.size).to eq 3
|
114
|
+
end
|
115
|
+
|
116
|
+
it '#values' do
|
117
|
+
records = Jsonb.where.store(:tags).values(1)
|
118
|
+
expect(records.size).to eq 2
|
119
|
+
|
120
|
+
records = Jsonb.where.store(:tags).values(2, 'e')
|
121
|
+
expect(records.size).to eq 1
|
122
|
+
expect(records.first.name).to eq 'e'
|
123
|
+
|
124
|
+
records = Jsonb.where.store(:tags).values(e: 1, f: { h: { k: 'a', s: 2 } })
|
125
|
+
expect(records.size).to eq 1
|
126
|
+
|
127
|
+
records = Jsonb.where.store(:tags).values(false, { a: 1, b: '1' }, [1, '1'])
|
128
|
+
expect(records.size).to eq 1
|
129
|
+
end
|
130
|
+
|
94
131
|
it '#any' do
|
95
132
|
records = Jsonb.where.store(:tags).any('a', 'b')
|
96
133
|
expect(records.size).to eq 4
|
@@ -134,4 +171,34 @@ describe Jsonb do
|
|
134
171
|
).to eq 0
|
135
172
|
end
|
136
173
|
end
|
174
|
+
|
175
|
+
context "#update_store" do
|
176
|
+
let(:store) { :tags }
|
177
|
+
|
178
|
+
subject { Jsonb.update_store(store) }
|
179
|
+
|
180
|
+
it "#delete_keys" do
|
181
|
+
subject.delete_keys(:e)
|
182
|
+
expect(Jsonb.where.store(store).keys(:i)).to_not exist
|
183
|
+
|
184
|
+
subject.delete_keys(:a, :b)
|
185
|
+
expect(Jsonb.where.store(store).keys(:a)).to_not exist
|
186
|
+
expect(Jsonb.where.store(store).keys(:b)).to_not exist
|
187
|
+
|
188
|
+
subject.delete_keys([:c, :d])
|
189
|
+
expect(Jsonb.where.store(store).keys(:c)).to_not exist
|
190
|
+
expect(Jsonb.where.store(store).keys(:d)).to_not exist
|
191
|
+
end
|
192
|
+
|
193
|
+
it "#merge" do
|
194
|
+
subject.merge(new_key: 1)
|
195
|
+
expect(Jsonb.where.store(store).keys(:new_key).count).to be_eql Jsonb.count
|
196
|
+
end
|
197
|
+
|
198
|
+
it "#delete_pairs" do
|
199
|
+
subject.delete_pairs(a: 1, d: { e: 2 })
|
200
|
+
expect(Jsonb.where.store(store, a: 1)).to_not exist
|
201
|
+
expect(Jsonb.where.store(store, d: { e: 2 })).to_not exist
|
202
|
+
end
|
203
|
+
end
|
137
204
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pgrel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -104,6 +104,7 @@ files:
|
|
104
104
|
- ".gitignore"
|
105
105
|
- ".rubocop.yml"
|
106
106
|
- ".travis.yml"
|
107
|
+
- CHANGELOG.md
|
107
108
|
- Gemfile
|
108
109
|
- MIT-LICENSE
|
109
110
|
- README.md
|
@@ -113,6 +114,11 @@ files:
|
|
113
114
|
- lib/pgrel.rb
|
114
115
|
- lib/pgrel/active_record.rb
|
115
116
|
- lib/pgrel/active_record/query_methods.rb
|
117
|
+
- lib/pgrel/active_record/querying.rb
|
118
|
+
- lib/pgrel/active_record/relation.rb
|
119
|
+
- lib/pgrel/active_record/store/flexible_hstore.rb
|
120
|
+
- lib/pgrel/active_record/store/flexible_jsonb.rb
|
121
|
+
- lib/pgrel/active_record/store/flexible_store.rb
|
116
122
|
- lib/pgrel/active_record/store_chain.rb
|
117
123
|
- lib/pgrel/active_record/store_chain/array_chain.rb
|
118
124
|
- lib/pgrel/active_record/store_chain/hstore_chain.rb
|
@@ -146,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
152
|
version: '0'
|
147
153
|
requirements: []
|
148
154
|
rubyforge_project:
|
149
|
-
rubygems_version: 2.7.
|
155
|
+
rubygems_version: 2.7.6
|
150
156
|
signing_key:
|
151
157
|
specification_version: 4
|
152
158
|
summary: ActiveRecord extension for querying hstore and jsonb.
|