pgrel 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|