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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9b99f0c11a5e624145d178ed3bdb97dd9345ccad
4
- data.tar.gz: 7db4f0a1086111e10ded6e6f9af923179ddc2012
3
+ metadata.gz: 5a4870c7384f1433c46da0d1515243c3753e928d
4
+ data.tar.gz: 446c7ccfd60abe33f7422cd2252dfa8d9bb47281
5
5
  SHA512:
6
- metadata.gz: 4ef4b9230787c49c3ccb1b24d68113cf90b57c0ae8281e6814eb6d01c01925fc04031ee3f02e1cc09abf60386b2d3c12f6b2f46674f6b75ccc27cd34d3a08619
7
- data.tar.gz: 8aaeaab12dd78aac0ad21a49b68af1a5efb83aeb261e0cfd431f24662b5f8b0dc88dcc4b93c8115b3a0d4999ddf3ca842c32d75f92270ebab7113eac31b71acf
6
+ metadata.gz: 39575efbbe02500b4a3534e4a188b845305911e96fbd33f01a68a7eaad0fa4185261727da4a7e9bf498f506af5ee63de9a147024f5b16b283a91776ee568346c
7
+ data.tar.gz: 63c370d875d0442c14a680d846cf34c7ccdb2f03ca25d061fbe6eae2772cf5bc5b2b9dcf16febb0543ffee61ec3c00c8cfd076c0e7dcea861925d2217790a05c
@@ -11,7 +11,7 @@ before_script:
11
11
 
12
12
  matrix:
13
13
  include:
14
- - rvm: 2.2.1
14
+ - rvm: 2.2.3
15
15
  gemfile: gemfiles/rails5.gemfile
16
16
  - rvm: 2.2.1
17
17
  gemfile: gemfiles/rails42.gemfile
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->'a' = '1' and tags->'b' = '2'
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->'a' in ('1', '2')
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 `IN (...)` statement.
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->'main' in ('a', 'b')
71
+ #=> select * from models where (tags @> '{\"main\":\"a\"}' or tags @> '{\"main\":\"b\"}')
72
72
  ```
73
73
 
74
74
  Path query:
@@ -1,5 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem 'rack', github: "rack/rack"
3
4
  gem 'arel', github: 'rails/arel'
4
5
  gem 'rails', github: 'rails/rails'
5
6
 
@@ -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 "#{@store_name} @> #{type_cast(opts)}"
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 store values.
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
@@ -1,3 +1,3 @@
1
1
  module Pgrel # :nodoc:
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -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: 1, g: 'c').size).to eq 1
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.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-04-30 00:00:00.000000000 Z
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.2.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.