pgrel 0.1.1 → 0.1.2
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/README.md +5 -5
- data/gemfiles/rails5.gemfile +1 -0
- data/lib/pgrel/active_record/store_chain.rb +67 -24
- data/lib/pgrel/active_record/store_chain/hstore_chain.rb +0 -29
- data/lib/pgrel/active_record/store_chain/jsonb_chain.rb +1 -29
- data/lib/pgrel/version.rb +1 -1
- data/spec/pgrel/hstore_spec.rb +2 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a4870c7384f1433c46da0d1515243c3753e928d
|
4
|
+
data.tar.gz: 446c7ccfd60abe33f7422cd2252dfa8d9bb47281
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39575efbbe02500b4a3534e4a188b845305911e96fbd33f01a68a7eaad0fa4185261727da4a7e9bf498f506af5ee63de9a147024f5b16b283a91776ee568346c
|
7
|
+
data.tar.gz: 63c370d875d0442c14a680d846cf34c7ccdb2f03ca25d061fbe6eae2772cf5bc5b2b9dcf16febb0543ffee61ec3c00c8cfd076c0e7dcea861925d2217790a05c
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[](https://travis-ci.org/palkan/pgrel)
|
1
|
+
[](https://rubygems.org/gems/pgrel) [](https://travis-ci.org/palkan/pgrel)
|
2
2
|
|
3
3
|
## Pgrel
|
4
4
|
|
@@ -25,10 +25,10 @@ Query by key value:
|
|
25
25
|
|
26
26
|
```ruby
|
27
27
|
Hstore.where.store(:tags, a: 1, b: 2)
|
28
|
-
#=> select * from hstores where tags
|
28
|
+
#=> select * from hstores where tags @> '"a"=>"1","b"=>"2"'
|
29
29
|
|
30
30
|
Hstore.where.store(:tags, a: [1, 2])
|
31
|
-
#=> select * from hstores where tags
|
31
|
+
#=> select * from hstores where (tags @> '"a"=>"1"' or tags @> '"a"=>"2"')
|
32
32
|
```
|
33
33
|
|
34
34
|
Keys existence:
|
@@ -61,14 +61,14 @@ Hstore.where.store(:tags).contained(a: 1, b: 2)
|
|
61
61
|
|
62
62
|
All queries for Hstore also available for JSONB.
|
63
63
|
|
64
|
-
**NOTE**. Querying by array value always resolves to `
|
64
|
+
**NOTE**. Querying by array value always resolves to `(... or ...)` statement.
|
65
65
|
Thus it's impossible to query json array value, e.g.:
|
66
66
|
|
67
67
|
```ruby
|
68
68
|
Model.create!(tags: {main: ['a', 'b']})
|
69
69
|
|
70
70
|
Model.where.store(:tags, main: ['a', 'b']).empty? == true
|
71
|
-
#=> select * from models where tags
|
71
|
+
#=> select * from models where (tags @> '{\"main\":\"a\"}' or tags @> '{\"main\":\"b\"}')
|
72
72
|
```
|
73
73
|
|
74
74
|
Path query:
|
data/gemfiles/rails5.gemfile
CHANGED
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
22
22
|
# data = {a: 1}
|
23
23
|
# Model.store(:store).contains(data).all #=> [Model(name: 'first', ...)]
|
24
24
|
def contains(opts)
|
25
|
-
update_scope
|
25
|
+
update_scope contains_clause(opts)
|
26
26
|
end
|
27
27
|
|
28
28
|
# Whether the store is contained within provided store
|
@@ -52,6 +52,37 @@ module ActiveRecord
|
|
52
52
|
self
|
53
53
|
end
|
54
54
|
|
55
|
+
# Query by store values.
|
56
|
+
# Supports array values.
|
57
|
+
#
|
58
|
+
# NOTE: This method uses "@>" (contains) operator with logic (AND/OR)
|
59
|
+
# and not uses "->" (value-by-key). The use of "contains" operator allows us to
|
60
|
+
# use GIN index effectively.
|
61
|
+
#
|
62
|
+
# Example
|
63
|
+
# Model.create!(name: 'first', store: {b: 1, c: 2})
|
64
|
+
# Model.create!(name: 'second', store: {b: 2, c: 3})
|
65
|
+
#
|
66
|
+
# Model.store(:store, c: 2).all #=> [Model(name: 'first', ...)]
|
67
|
+
# #=> (SQL) select * from ... where store @> '"c"=>"2"'::hstore
|
68
|
+
#
|
69
|
+
# Model.store(:store, b: [1, 2]).size #=> 2
|
70
|
+
# #=> (SQL) select * from ... where (store @> '"c"=>"1"'::hstore) or
|
71
|
+
# (store @> '"c"=>"2"'::hstore)
|
72
|
+
def where(opts)
|
73
|
+
update_scope(
|
74
|
+
opts.map do |k, v|
|
75
|
+
case v
|
76
|
+
when Array
|
77
|
+
"(#{build_or_contains(k, v)})"
|
78
|
+
else
|
79
|
+
contains_clause(k => v)
|
80
|
+
end
|
81
|
+
end.join(' and ')
|
82
|
+
)
|
83
|
+
@scope
|
84
|
+
end
|
85
|
+
|
55
86
|
if RAILS_5
|
56
87
|
protected
|
57
88
|
|
@@ -66,20 +97,6 @@ module ActiveRecord
|
|
66
97
|
@scope.table.type_cast_for_database(@store_name, value)
|
67
98
|
)
|
68
99
|
end
|
69
|
-
|
70
|
-
def where_with_prefix(prefix, opts)
|
71
|
-
where_clause = @scope.send(:where_clause_factory).build(opts, {})
|
72
|
-
predicates = where_clause.ast.children.map do |rel|
|
73
|
-
rel.left = to_sql_literal(prefix, rel.left)
|
74
|
-
rel
|
75
|
-
end
|
76
|
-
where_clause = ActiveRecord::Relation::WhereClause.new(
|
77
|
-
predicates,
|
78
|
-
where_clause.binds
|
79
|
-
)
|
80
|
-
@scope.where_clause += @inverted ? where_clause.invert : where_clause
|
81
|
-
@scope
|
82
|
-
end
|
83
100
|
else
|
84
101
|
protected
|
85
102
|
|
@@ -98,15 +115,6 @@ module ActiveRecord
|
|
98
115
|
)
|
99
116
|
end
|
100
117
|
|
101
|
-
def where_with_prefix(prefix, opts)
|
102
|
-
where_value = @scope.send(:build_where, opts).map do |rel|
|
103
|
-
rel.left = to_sql_literal(prefix, rel.left)
|
104
|
-
@inverted ? invert_arel(rel) : rel
|
105
|
-
end
|
106
|
-
@scope.where_values += where_value
|
107
|
-
@scope
|
108
|
-
end
|
109
|
-
|
110
118
|
def invert_arel(rel)
|
111
119
|
case rel
|
112
120
|
when Arel::Nodes::In
|
@@ -120,6 +128,16 @@ module ActiveRecord
|
|
120
128
|
end
|
121
129
|
end
|
122
130
|
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def contains_clause(opts)
|
135
|
+
"#{@store_name} @> #{type_cast(opts)}"
|
136
|
+
end
|
137
|
+
|
138
|
+
def build_or_contains(k, vals)
|
139
|
+
vals.map { |v| contains_clause(k => v) }.join(' or ')
|
140
|
+
end
|
123
141
|
end
|
124
142
|
|
125
143
|
# Base class for key-value types of stores (hstore, jsonb)
|
@@ -171,6 +189,31 @@ module ActiveRecord
|
|
171
189
|
"#{prefix}'#{node.name}'"
|
172
190
|
)
|
173
191
|
end
|
192
|
+
|
193
|
+
if RAILS_5
|
194
|
+
def where_with_prefix(prefix, opts)
|
195
|
+
where_clause = @scope.send(:where_clause_factory).build(opts, {})
|
196
|
+
predicates = where_clause.ast.children.map do |rel|
|
197
|
+
rel.left = to_sql_literal(prefix, rel.left)
|
198
|
+
rel
|
199
|
+
end
|
200
|
+
where_clause = ActiveRecord::Relation::WhereClause.new(
|
201
|
+
predicates,
|
202
|
+
where_clause.binds
|
203
|
+
)
|
204
|
+
@scope.where_clause += @inverted ? where_clause.invert : where_clause
|
205
|
+
@scope
|
206
|
+
end
|
207
|
+
else
|
208
|
+
def where_with_prefix(prefix, opts)
|
209
|
+
where_value = @scope.send(:build_where, opts).map do |rel|
|
210
|
+
rel.left = to_sql_literal(prefix, rel.left)
|
211
|
+
@inverted ? invert_arel(rel) : rel
|
212
|
+
end
|
213
|
+
@scope.where_values += where_value
|
214
|
+
@scope
|
215
|
+
end
|
216
|
+
end
|
174
217
|
end
|
175
218
|
end
|
176
219
|
end
|
@@ -2,35 +2,6 @@ module ActiveRecord
|
|
2
2
|
module QueryMethods
|
3
3
|
# Store chain for hstore columns.
|
4
4
|
class HstoreChain < KeyStoreChain
|
5
|
-
# Query by store values.
|
6
|
-
#
|
7
|
-
# Supports array values.
|
8
|
-
#
|
9
|
-
# Example
|
10
|
-
# Model.create!(name: 'first', store: {b: 1, c: 2})
|
11
|
-
# Model.create!(name: 'second', store: {b: 2, c: 3})
|
12
|
-
#
|
13
|
-
# Model.store(:store, c: 2).all #=> [Model(name: 'first', ...)]
|
14
|
-
# Model.store(:store, b: [1, 2]).size #=> 2
|
15
|
-
def where(opts)
|
16
|
-
opts = stringify(opts)
|
17
|
-
where_with_prefix "#{@store_name}->", opts
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def stringify(val)
|
23
|
-
case val
|
24
|
-
when String
|
25
|
-
val
|
26
|
-
when Array
|
27
|
-
val.map { |v| stringify(v) }
|
28
|
-
when Hash
|
29
|
-
Hash[val.map { |k, v| [stringify(k), stringify(v)] }]
|
30
|
-
else
|
31
|
-
val.to_s
|
32
|
-
end
|
33
|
-
end
|
34
5
|
end
|
35
6
|
end
|
36
7
|
end
|
@@ -2,23 +2,7 @@ module ActiveRecord
|
|
2
2
|
module QueryMethods
|
3
3
|
# Store chain for jsonb columns.
|
4
4
|
class JsonbChain < KeyStoreChain
|
5
|
-
# Query by
|
6
|
-
# Supports array values (convert to IN statement).
|
7
|
-
#
|
8
|
-
# Example
|
9
|
-
# Model.create!(name: 'first', store: {b: 1, c: 2})
|
10
|
-
# Model.create!(name: 'second', store: {b: 2, c: 3})
|
11
|
-
#
|
12
|
-
# Model.store(:store, c: 2).all #=> [Model(name: 'first', ...)]
|
13
|
-
# Model.store(:store, b: [1, 2]).size #=> 2
|
14
|
-
def where(opts)
|
15
|
-
opts = flatten_json(opts)
|
16
|
-
where_with_prefix "#{@store_name}->", opts
|
17
|
-
end
|
18
|
-
|
19
|
-
# Query by quality in path.
|
20
|
-
#
|
21
|
-
# Path can be set as object or as args.
|
5
|
+
# Query by value in path.
|
22
6
|
#
|
23
7
|
# Example:
|
24
8
|
# Model.create!(name: 'first', store: {b: 1, c: { d: 3 } })
|
@@ -49,18 +33,6 @@ module ActiveRecord
|
|
49
33
|
|
50
34
|
private
|
51
35
|
|
52
|
-
def flatten_json(val)
|
53
|
-
Hash[
|
54
|
-
val.map do |k, v|
|
55
|
-
if v.is_a?(Array)
|
56
|
-
[k, v.map { |i| ::ActiveSupport::JSON.encode(i) }]
|
57
|
-
else
|
58
|
-
[k, ::ActiveSupport::JSON.encode(v)]
|
59
|
-
end
|
60
|
-
end
|
61
|
-
]
|
62
|
-
end
|
63
|
-
|
64
36
|
def flatten_hash(hash)
|
65
37
|
case hash
|
66
38
|
when Hash
|
data/lib/pgrel/version.rb
CHANGED
data/spec/pgrel/hstore_spec.rb
CHANGED
@@ -116,7 +116,8 @@ describe Hstore do
|
|
116
116
|
|
117
117
|
context '#not' do
|
118
118
|
it '#where' do
|
119
|
-
expect(Hstore.where.store(:tags).not(a:
|
119
|
+
expect(Hstore.where.store(:tags).not(a: 2).size).to eq 4
|
120
|
+
expect(Hstore.where.store(:tags).not(a: 1, g: 'c').size).to eq 6
|
120
121
|
end
|
121
122
|
|
122
123
|
it '#any' do
|
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.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -148,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
148
|
version: '0'
|
149
149
|
requirements: []
|
150
150
|
rubyforge_project:
|
151
|
-
rubygems_version: 2.
|
151
|
+
rubygems_version: 2.4.5
|
152
152
|
signing_key:
|
153
153
|
specification_version: 4
|
154
154
|
summary: ActiveRecord extension for querying hstore and jsonb.
|