pgrel 0.1.1 → 0.3.1
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 +5 -5
- data/CHANGELOG.md +31 -0
- data/{MIT-LICENSE → LICENSE.txt} +1 -1
- data/README.md +56 -13
- data/lib/pgrel.rb +4 -2
- data/lib/pgrel/active_record.rb +9 -2
- data/lib/pgrel/active_record/query_methods.rb +7 -5
- data/lib/pgrel/active_record/querying.rb +7 -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 +108 -36
- data/lib/pgrel/active_record/store_chain/array_chain.rb +3 -1
- data/lib/pgrel/active_record/store_chain/hstore_chain.rb +18 -23
- data/lib/pgrel/active_record/store_chain/jsonb_chain.rb +47 -32
- data/lib/pgrel/version.rb +3 -1
- metadata +19 -60
- data/.gitignore +0 -36
- data/.rubocop.yml +0 -41
- data/.travis.yml +0 -21
- data/Gemfile +0 -11
- data/Rakefile +0 -6
- data/gemfiles/rails40.gemfile +0 -5
- data/gemfiles/rails41.gemfile +0 -5
- data/gemfiles/rails42.gemfile +0 -5
- data/gemfiles/rails5.gemfile +0 -6
- data/pgrel.gemspec +0 -27
- data/spec/pgrel/array_spec.rb +0 -71
- data/spec/pgrel/hstore_spec.rb +0 -130
- data/spec/pgrel/jsonb_spec.rb +0 -137
- data/spec/spec_helper.rb +0 -35
- data/spec/support/array_store.rb +0 -2
- data/spec/support/hstore.rb +0 -2
- data/spec/support/jsonb.rb +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 686f59a1c868b3ee3268ab06137c35dcd2f8e9fed9136bbbec2a27622401d301
|
4
|
+
data.tar.gz: a381b46c2a07d0193a5764d099e25f731ac90c17f2f9bef11ca600ac08f10c1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92b7300c636eb9f985a7a9b5b9467d1480b92ca38997d73cce0105915f1f2d50f7df5724b5b9e0c5c36e32dd5ea3999803145caa0b51a0561ba40d17603606f8
|
7
|
+
data.tar.gz: 7b7153c935e88f6084463e58639e9c297fb44dcc1d8c538a8e17e5cb3f6f836837ca7a8dbefd479dbf22ac5f4fd8e9a3400d47985a9c35b30f65238821cd0bc8
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Change log
|
2
|
+
|
3
|
+
## master
|
4
|
+
|
5
|
+
## 0.3.1 (2020-12-18)
|
6
|
+
|
7
|
+
- Update internal query building for Rails 6.1 compatibility. ([@zokioki][])
|
8
|
+
|
9
|
+
## 0.3.0 (2019-28-01)
|
10
|
+
|
11
|
+
- Rename `#value` method to `#overlap_values`.
|
12
|
+
- Rename `#values` method to `#contains_values`.
|
13
|
+
- Improve `#contains_values` method:
|
14
|
+
eliminate multiple `avals` calls for Hstore and multiple `array_agg` calls for Jsonb.
|
15
|
+
|
16
|
+
See https://github.com/palkan/pgrel/pull/9. ([@StanisLove][])
|
17
|
+
|
18
|
+
- Quote store name in queries. ([@palkan][])
|
19
|
+
|
20
|
+
Previously, we didn't quote store name in queries which could led
|
21
|
+
to ambiguity conflicts when joining tables.
|
22
|
+
Now it fixed.
|
23
|
+
|
24
|
+
## 0.2.0 (2018-06-15)
|
25
|
+
|
26
|
+
- Add `#update_store` methods. ([@StanisLove][])
|
27
|
+
|
28
|
+
See https://github.com/palkan/pgrel/pull/5.
|
29
|
+
|
30
|
+
[@palkan]: https://github.com/palkan
|
31
|
+
[@StanisLove]: https://github.com/StanisLove
|
data/{MIT-LICENSE → LICENSE.txt}
RENAMED
data/README.md
CHANGED
@@ -1,34 +1,41 @@
|
|
1
|
-
[](https://rubygems.org/gems/pgrel)
|
2
|
+

|
2
3
|
|
3
4
|
## Pgrel
|
4
5
|
|
5
6
|
ActiveRecord extension for querying hstore, array and jsonb.
|
6
7
|
|
7
|
-
Compatible with **Rails** >= 4.
|
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).
|
8
|
+
Compatible with **Rails** >= 4.2 (including **Rails 6**).
|
13
9
|
|
14
10
|
#### Install
|
15
11
|
|
16
12
|
In your Gemfile:
|
17
13
|
|
18
14
|
```ruby
|
19
|
-
gem "pgrel", "~>0.
|
15
|
+
gem "pgrel", "~> 0.3"
|
20
16
|
```
|
21
17
|
|
22
18
|
### HStore
|
23
19
|
|
20
|
+
#### Querying
|
21
|
+
|
22
|
+
The functionality is based on ActiveRecord `WhereChain`.
|
23
|
+
To start querying call `where(:store_name)` and chain it with store-specific call (see below).
|
24
|
+
|
24
25
|
Query by key value:
|
25
26
|
|
26
27
|
```ruby
|
27
28
|
Hstore.where.store(:tags, a: 1, b: 2)
|
28
|
-
#=> select * from hstores where tags
|
29
|
+
#=> select * from hstores where tags @> '"a"=>"1","b"=>"2"'
|
29
30
|
|
30
31
|
Hstore.where.store(:tags, a: [1, 2])
|
31
|
-
#=> select * from hstores where tags
|
32
|
+
#=> select * from hstores where (tags @> '"a"=>"1"' or tags @> '"a"=>"2"')
|
33
|
+
|
34
|
+
Hstore.where.store(:tags, :a)
|
35
|
+
#=> select * from hstores where (tags @> '"a"=>NULL')
|
36
|
+
|
37
|
+
Hstore.where.store(:tags, { a: 1 }, { b: 2 })
|
38
|
+
#=> select * from hstores where (tags @> '"a"=>"1" or tags @> "b"=>"2"')
|
32
39
|
```
|
33
40
|
|
34
41
|
Keys existence:
|
@@ -47,6 +54,18 @@ Hstore.where.store(:tags).any('a', 'b')
|
|
47
54
|
#=> select * from hstores where tags ?| array['a', 'b']
|
48
55
|
```
|
49
56
|
|
57
|
+
Values existence:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# Retrieve items that have value '1' OR '2'
|
61
|
+
Hstore.where.store(:tags).overlap_values(1, 2)
|
62
|
+
#=> select * from hstores where (avals(tags) && ARRAY['1', '2'])
|
63
|
+
|
64
|
+
# Retrieve items that have values '1' AND '2'
|
65
|
+
Hstore.where.store(:tags).contains_values(1, 2)
|
66
|
+
#=> select * from hstores where (avals(tags) @> ARRAY['1', '2'])
|
67
|
+
```
|
68
|
+
|
50
69
|
Containment:
|
51
70
|
|
52
71
|
```ruby
|
@@ -57,18 +76,42 @@ Hstore.where.store(:tags).contained(a: 1, b: 2)
|
|
57
76
|
#=> select * from hstores where tags <@ '\"a\"=>\"1\", \"b\"=>\"2\"'
|
58
77
|
```
|
59
78
|
|
79
|
+
#### Update
|
80
|
+
|
81
|
+
Is implemented through `ActiveRecord::Store::FlexibleHstore` and `ActiveRecord::Store::FlexibleJsonb`
|
82
|
+
objects. You can get them by sending `update_store(store_name)` to relation or class.
|
83
|
+
|
84
|
+
Add key, value pairs:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
Hstore.update_store(:tags).merge(new_key: 1, one_more: 2)
|
88
|
+
Hstore.update_store(:tags).merge([[:new_key, 1], [:one_more, 2]])
|
89
|
+
```
|
90
|
+
|
91
|
+
Delete keys:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
Hstore.update_store(:tags).delete_keys(:a, :b)
|
95
|
+
```
|
96
|
+
|
97
|
+
Delete key, value pairs:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
Hstore.update_store(:tags).delete_pairs(a: 1, b: 2)
|
101
|
+
```
|
102
|
+
|
60
103
|
### JSONB
|
61
104
|
|
62
|
-
All queries for Hstore also available for JSONB.
|
105
|
+
All queries and updates for Hstore also available for JSONB.
|
63
106
|
|
64
|
-
**NOTE**. Querying by array value always resolves to `
|
107
|
+
**NOTE**. Querying by array value always resolves to `(... or ...)` statement.
|
65
108
|
Thus it's impossible to query json array value, e.g.:
|
66
109
|
|
67
110
|
```ruby
|
68
111
|
Model.create!(tags: {main: ['a', 'b']})
|
69
112
|
|
70
113
|
Model.where.store(:tags, main: ['a', 'b']).empty? == true
|
71
|
-
#=> select * from models where tags
|
114
|
+
#=> select * from models where (tags @> '{\"main\":\"a\"}' or tags @> '{\"main\":\"b\"}')
|
72
115
|
```
|
73
116
|
|
74
117
|
Path query:
|
data/lib/pgrel.rb
CHANGED
data/lib/pgrel/active_record.rb
CHANGED
@@ -1,2 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
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"
|
9
|
+
require "pgrel/active_record/query_methods"
|
@@ -1,8 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/relation"
|
4
|
+
require "pgrel/active_record/store_chain"
|
5
|
+
require "pgrel/active_record/store_chain/array_chain"
|
6
|
+
require "pgrel/active_record/store_chain/hstore_chain"
|
7
|
+
require "pgrel/active_record/store_chain/jsonb_chain"
|
6
8
|
|
7
9
|
module ActiveRecord
|
8
10
|
module QueryMethods
|
@@ -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 = +"#{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
|
@@ -1,5 +1,4 @@
|
|
1
|
-
#
|
2
|
-
RAILS_5 = ActiveRecord.version.release >= Gem::Version.new("5")
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module ActiveRecord
|
5
4
|
module QueryMethods
|
@@ -7,10 +6,13 @@ module ActiveRecord
|
|
7
6
|
# Provides _containment_ queries methods.
|
8
7
|
# Provides basic methods.
|
9
8
|
class StoreChain
|
9
|
+
attr_reader :store_name, :quoted_store_name
|
10
|
+
|
10
11
|
def initialize(scope, store_name)
|
11
12
|
@scope = scope
|
12
13
|
@store_name = store_name
|
13
14
|
@inverted = false
|
15
|
+
@quoted_store_name = "#{@scope.klass.quoted_table_name}.#{@scope.klass.connection.quote_column_name(store_name)}"
|
14
16
|
end
|
15
17
|
|
16
18
|
# Whether the store contains provided store
|
@@ -22,7 +24,7 @@ module ActiveRecord
|
|
22
24
|
# data = {a: 1}
|
23
25
|
# Model.store(:store).contains(data).all #=> [Model(name: 'first', ...)]
|
24
26
|
def contains(opts)
|
25
|
-
update_scope
|
27
|
+
update_scope contains_clause(opts)
|
26
28
|
end
|
27
29
|
|
28
30
|
# Whether the store is contained within provided store
|
@@ -34,7 +36,7 @@ module ActiveRecord
|
|
34
36
|
# data = {b: 1, c: 2}
|
35
37
|
# Model.store(:store).contains(data).all #=> [Model(name: 'first', ...)]
|
36
38
|
def contained(opts)
|
37
|
-
update_scope "#{
|
39
|
+
update_scope "#{quoted_store_name} <@ #{type_cast(opts)}"
|
38
40
|
end
|
39
41
|
|
40
42
|
# Add negation to condition.
|
@@ -52,37 +54,56 @@ module ActiveRecord
|
|
52
54
|
self
|
53
55
|
end
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
+
# Query by store values.
|
58
|
+
# Supports array values.
|
59
|
+
#
|
60
|
+
# NOTE: This method uses "@>" (contains) operator with logic (AND/OR)
|
61
|
+
# and not uses "->" (value-by-key). The use of "contains" operator allows us to
|
62
|
+
# use GIN index effectively.
|
63
|
+
#
|
64
|
+
# Example
|
65
|
+
# Model.create!(name: 'first', store: {b: 1, c: 2})
|
66
|
+
# Model.create!(name: 'second', store: {b: 2, c: 3})
|
67
|
+
#
|
68
|
+
# Model.store(:store, c: 2).all #=> [Model(name: 'first', ...)]
|
69
|
+
# #=> (SQL) select * from ... where store @> '"c"=>"2"'::hstore
|
70
|
+
#
|
71
|
+
# Model.store(:store, b: [1, 2]).size #=> 2
|
72
|
+
# #=> (SQL) select * from ... where (store @> '"c"=>"1"'::hstore) or
|
73
|
+
# (store @> '"c"=>"2"'::hstore)
|
74
|
+
def where(*opts)
|
75
|
+
opts.map! { |opt| opt.is_a?(Hash) ? opt : [opt] }
|
76
|
+
|
77
|
+
update_scope(
|
78
|
+
opts.map do |opt|
|
79
|
+
opt.map do |k, v|
|
80
|
+
case v
|
81
|
+
when Array
|
82
|
+
"(#{build_or_contains(k, v)})"
|
83
|
+
else
|
84
|
+
contains_clause(k => v)
|
85
|
+
end
|
86
|
+
end.join(" and ")
|
87
|
+
end.join(" or ")
|
88
|
+
)
|
89
|
+
@scope
|
90
|
+
end
|
91
|
+
|
92
|
+
protected
|
57
93
|
|
94
|
+
if ActiveRecord.version.release >= Gem::Version.new("5")
|
58
95
|
def update_scope(*opts)
|
59
|
-
where_clause =
|
96
|
+
where_clause = build_where_clause(opts)
|
60
97
|
@scope.where_clause += @inverted ? where_clause.invert : where_clause
|
61
98
|
@scope
|
62
99
|
end
|
63
100
|
|
64
101
|
def type_cast(value)
|
65
102
|
ActiveRecord::Base.connection.quote(
|
66
|
-
@scope.
|
103
|
+
@scope.klass.type_caster.type_cast_for_database(@store_name, value)
|
67
104
|
)
|
68
105
|
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
106
|
else
|
84
|
-
protected
|
85
|
-
|
86
107
|
def update_scope(*opts)
|
87
108
|
where_clause = @scope.send(:build_where, opts).map do |rel|
|
88
109
|
@inverted ? invert_arel(rel) : rel
|
@@ -98,15 +119,6 @@ module ActiveRecord
|
|
98
119
|
)
|
99
120
|
end
|
100
121
|
|
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
122
|
def invert_arel(rel)
|
111
123
|
case rel
|
112
124
|
when Arel::Nodes::In
|
@@ -120,6 +132,24 @@ module ActiveRecord
|
|
120
132
|
end
|
121
133
|
end
|
122
134
|
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def contains_clause(opts)
|
139
|
+
"#{quoted_store_name} @> #{type_cast(opts)}"
|
140
|
+
end
|
141
|
+
|
142
|
+
def build_or_contains(k, vals)
|
143
|
+
vals.map { |v| contains_clause(k => v) }.join(" or ")
|
144
|
+
end
|
145
|
+
|
146
|
+
def build_where_clause(opts)
|
147
|
+
if ActiveRecord.version.release >= Gem::Version.new("6.1.0")
|
148
|
+
@scope.send(:build_where_clause, opts)
|
149
|
+
else
|
150
|
+
@scope.send(:where_clause_factory).build(opts, [])
|
151
|
+
end
|
152
|
+
end
|
123
153
|
end
|
124
154
|
|
125
155
|
# Base class for key-value types of stores (hstore, jsonb)
|
@@ -133,7 +163,7 @@ module ActiveRecord
|
|
133
163
|
# # Get all records which have key 'a' in store 'store'
|
134
164
|
# Model.store(:store).key('a').all #=> [Model(name: 'first', ...)]
|
135
165
|
def key(key)
|
136
|
-
update_scope "#{
|
166
|
+
update_scope "#{quoted_store_name} ? :key", key: key.to_s
|
137
167
|
end
|
138
168
|
|
139
169
|
# Several keys existence
|
@@ -145,7 +175,7 @@ module ActiveRecord
|
|
145
175
|
# Model.store(:store).keys('a','b').all #=> [Model(name: 'first', ...)]
|
146
176
|
def keys(*keys)
|
147
177
|
update_scope(
|
148
|
-
"#{
|
178
|
+
"#{quoted_store_name} ?& ARRAY[:keys]",
|
149
179
|
keys: keys.flatten.map(&:to_s)
|
150
180
|
)
|
151
181
|
end
|
@@ -159,7 +189,7 @@ module ActiveRecord
|
|
159
189
|
# Model.store(:store).keys('a','b').count #=> 2
|
160
190
|
def any(*keys)
|
161
191
|
update_scope(
|
162
|
-
"#{
|
192
|
+
"#{quoted_store_name} ?| ARRAY[:keys]",
|
163
193
|
keys: keys.flatten.map(&:to_s)
|
164
194
|
)
|
165
195
|
end
|
@@ -171,6 +201,48 @@ module ActiveRecord
|
|
171
201
|
"#{prefix}'#{node.name}'"
|
172
202
|
)
|
173
203
|
end
|
204
|
+
|
205
|
+
if ActiveRecord.version.release >= Gem::Version.new("5")
|
206
|
+
def where_with_prefix(prefix, opts)
|
207
|
+
where_clause = build_where_clause(opts)
|
208
|
+
where_clause_ast = where_clause.ast
|
209
|
+
|
210
|
+
# Converting `HomogenousIn` node to `In` type allows us to set its `left`
|
211
|
+
# to sql literal as with other node types (`HomogenousIn` does not support this).
|
212
|
+
if defined?(Arel::Nodes::HomogeneousIn) && where_clause_ast.is_a?(Arel::Nodes::HomogeneousIn)
|
213
|
+
where_clause_ast = Arel::Nodes::In.new(where_clause_ast.left, where_clause_ast.right)
|
214
|
+
end
|
215
|
+
|
216
|
+
predicates = if where_clause_ast.is_a?(Arel::Nodes::And)
|
217
|
+
where_clause.ast.children.map do |rel|
|
218
|
+
rel.left = to_sql_literal(prefix, rel.left)
|
219
|
+
rel
|
220
|
+
end
|
221
|
+
else
|
222
|
+
where_clause_ast.left = to_sql_literal(prefix, where_clause_ast.left)
|
223
|
+
[where_clause_ast]
|
224
|
+
end
|
225
|
+
|
226
|
+
params = if ActiveRecord.version.release >= Gem::Version.new("5.2.0")
|
227
|
+
[predicates]
|
228
|
+
else
|
229
|
+
[predicates, where_clause.binds]
|
230
|
+
end
|
231
|
+
|
232
|
+
where_clause = ActiveRecord::Relation::WhereClause.new(*params)
|
233
|
+
@scope.where_clause += @inverted ? where_clause.invert : where_clause
|
234
|
+
@scope
|
235
|
+
end
|
236
|
+
else
|
237
|
+
def where_with_prefix(prefix, opts)
|
238
|
+
where_value = @scope.send(:build_where, opts).map do |rel|
|
239
|
+
rel.left = to_sql_literal(prefix, rel.left)
|
240
|
+
@inverted ? invert_arel(rel) : rel
|
241
|
+
end
|
242
|
+
@scope.where_values += where_value
|
243
|
+
@scope
|
244
|
+
end
|
245
|
+
end
|
174
246
|
end
|
175
247
|
end
|
176
248
|
end
|