pgrel 0.1.1 → 0.1.2
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/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
|
-
[![Build Status](https://travis-ci.org/palkan/pgrel.svg?branch=master)](https://travis-ci.org/palkan/pgrel)
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/pgrel.svg)](https://rubygems.org/gems/pgrel) [![Build Status](https://travis-ci.org/palkan/pgrel.svg?branch=master)](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.
|