torque-postgresql 0.2.16 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.rdoc +76 -3
- data/lib/torque-postgresql.rb +1 -0
- data/lib/torque/postgresql.rb +6 -0
- data/lib/torque/postgresql/adapter.rb +2 -4
- data/lib/torque/postgresql/adapter/database_statements.rb +23 -9
- data/lib/torque/postgresql/adapter/oid.rb +12 -1
- data/lib/torque/postgresql/adapter/oid/box.rb +28 -0
- data/lib/torque/postgresql/adapter/oid/circle.rb +37 -0
- data/lib/torque/postgresql/adapter/oid/enum.rb +9 -5
- data/lib/torque/postgresql/adapter/oid/enum_set.rb +44 -0
- data/lib/torque/postgresql/adapter/oid/line.rb +59 -0
- data/lib/torque/postgresql/adapter/oid/range.rb +52 -0
- data/lib/torque/postgresql/adapter/oid/segment.rb +73 -0
- data/lib/torque/postgresql/adapter/quoting.rb +21 -0
- data/lib/torque/postgresql/adapter/schema_definitions.rb +7 -0
- data/lib/torque/postgresql/adapter/schema_dumper.rb +10 -1
- data/lib/torque/postgresql/arel.rb +3 -0
- data/lib/torque/postgresql/arel/infix_operation.rb +42 -0
- data/lib/torque/postgresql/arel/nodes.rb +32 -0
- data/lib/torque/postgresql/arel/operations.rb +18 -0
- data/lib/torque/postgresql/arel/visitors.rb +28 -2
- data/lib/torque/postgresql/associations.rb +8 -0
- data/lib/torque/postgresql/associations/association.rb +30 -0
- data/lib/torque/postgresql/associations/association_scope.rb +116 -0
- data/lib/torque/postgresql/associations/belongs_to_many_association.rb +117 -0
- data/lib/torque/postgresql/associations/builder.rb +2 -0
- data/lib/torque/postgresql/associations/builder/belongs_to_many.rb +121 -0
- data/lib/torque/postgresql/associations/builder/has_many.rb +15 -0
- data/lib/torque/postgresql/associations/join_dependency/join_association.rb +15 -0
- data/lib/torque/postgresql/associations/preloader.rb +25 -0
- data/lib/torque/postgresql/associations/preloader/association.rb +64 -0
- data/lib/torque/postgresql/attributes.rb +2 -0
- data/lib/torque/postgresql/attributes/builder.rb +1 -0
- data/lib/torque/postgresql/attributes/builder/enum.rb +23 -15
- data/lib/torque/postgresql/attributes/builder/period.rb +452 -0
- data/lib/torque/postgresql/attributes/enum.rb +11 -8
- data/lib/torque/postgresql/attributes/enum_set.rb +256 -0
- data/lib/torque/postgresql/attributes/lazy.rb +1 -1
- data/lib/torque/postgresql/attributes/period.rb +31 -0
- data/lib/torque/postgresql/attributes/type_map.rb +3 -5
- data/lib/torque/postgresql/autosave_association.rb +40 -0
- data/lib/torque/postgresql/auxiliary_statement.rb +201 -198
- data/lib/torque/postgresql/auxiliary_statement/settings.rb +20 -12
- data/lib/torque/postgresql/base.rb +161 -2
- data/lib/torque/postgresql/config.rb +91 -9
- data/lib/torque/postgresql/geometry_builder.rb +92 -0
- data/lib/torque/postgresql/i18n.rb +1 -1
- data/lib/torque/postgresql/railtie.rb +18 -5
- data/lib/torque/postgresql/reflection.rb +21 -0
- data/lib/torque/postgresql/reflection/abstract_reflection.rb +109 -0
- data/lib/torque/postgresql/reflection/association_reflection.rb +30 -0
- data/lib/torque/postgresql/reflection/belongs_to_many_reflection.rb +44 -0
- data/lib/torque/postgresql/reflection/has_many_reflection.rb +13 -0
- data/lib/torque/postgresql/reflection/runtime_reflection.rb +12 -0
- data/lib/torque/postgresql/reflection/through_reflection.rb +11 -0
- data/lib/torque/postgresql/relation.rb +11 -10
- data/lib/torque/postgresql/relation/auxiliary_statement.rb +11 -18
- data/lib/torque/postgresql/relation/inheritance.rb +2 -2
- data/lib/torque/postgresql/relation/merger.rb +11 -7
- data/lib/torque/postgresql/schema_cache.rb +1 -1
- data/lib/torque/postgresql/version.rb +1 -1
- data/lib/torque/range.rb +40 -0
- metadata +41 -9
@@ -0,0 +1,52 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Adapter
|
4
|
+
module OID
|
5
|
+
class Range < ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Range
|
6
|
+
HASH_PICK = %i[from start end to].freeze
|
7
|
+
|
8
|
+
module Comparasion
|
9
|
+
def <=>(other)
|
10
|
+
return super unless other.acts_like?(:date) || other.acts_like?(:time)
|
11
|
+
other = other.to_time if other.acts_like?(:date)
|
12
|
+
super other.to_i
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def cast_value(value)
|
17
|
+
case value
|
18
|
+
when Array
|
19
|
+
cast_custom(value[0], value[1])
|
20
|
+
when Hash
|
21
|
+
pieces = value.with_indifferent_access.values_at(*HASH_PICK)
|
22
|
+
cast_custom(pieces[0] || pieces[1], pieces[2] || pieces[3])
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def cast_custom(from, to)
|
31
|
+
from = custom_cast_single(from, true)
|
32
|
+
to = custom_cast_single(to)
|
33
|
+
::Range.new(from, to)
|
34
|
+
end
|
35
|
+
|
36
|
+
def custom_cast_single(value, negative = false)
|
37
|
+
value.blank? ? custom_infinity(negative) : subtype.deserialize(value)
|
38
|
+
end
|
39
|
+
|
40
|
+
def custom_infinity(negative)
|
41
|
+
negative ? -::Float::INFINITY : ::Float::INFINITY
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
::ActiveRecord::ConnectionAdapters::PostgreSQL::OID.send(:remove_const, :Range)
|
46
|
+
::ActiveRecord::ConnectionAdapters::PostgreSQL::OID.const_set(:Range, Range)
|
47
|
+
|
48
|
+
::Float.prepend(Range::Comparasion)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
class Segment < Struct.new(:point0, :point1)
|
4
|
+
def x1=(value)
|
5
|
+
self.point0 = new_point(value, y1)
|
6
|
+
end
|
7
|
+
|
8
|
+
def x1
|
9
|
+
point0.x
|
10
|
+
end
|
11
|
+
|
12
|
+
def y1=(value)
|
13
|
+
self.point0 = new_point(x1, value)
|
14
|
+
end
|
15
|
+
|
16
|
+
def y1
|
17
|
+
point0.y
|
18
|
+
end
|
19
|
+
|
20
|
+
def x2=(value)
|
21
|
+
self.point1 = new_point(value, y2)
|
22
|
+
end
|
23
|
+
|
24
|
+
def x2
|
25
|
+
point1.x
|
26
|
+
end
|
27
|
+
|
28
|
+
def y2=(value)
|
29
|
+
self.point1 = new_point(x2, value)
|
30
|
+
end
|
31
|
+
|
32
|
+
def y2
|
33
|
+
point1.y
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def new_point(x, y)
|
39
|
+
Torque::PostgreSQL.config.geometry.point_class.new(x, y)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
config.geometry.segment_class ||= ::ActiveRecord.const_set('Segment', Class.new(Segment))
|
44
|
+
|
45
|
+
module Adapter
|
46
|
+
module OID
|
47
|
+
class Segment < Torque::PostgreSQL::GeometryBuilder
|
48
|
+
|
49
|
+
PIECES = %i[x1 y1 x2 y2].freeze
|
50
|
+
FORMATION = '((%s,%s),(%s,%s))'.freeze
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def point_class
|
55
|
+
Torque::PostgreSQL.config.geometry.point_class
|
56
|
+
end
|
57
|
+
|
58
|
+
def build_klass(*args)
|
59
|
+
return nil if args.empty?
|
60
|
+
check_invalid_format!(args)
|
61
|
+
|
62
|
+
x1, y1, x2, y2 = args.try(:first, pieces.size)&.map(&:to_f)
|
63
|
+
config_class.new(
|
64
|
+
point_class.new(x1, y1),
|
65
|
+
point_class.new(x2, y2),
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -17,6 +17,27 @@ module Torque
|
|
17
17
|
Name.new(schema, table).quoted
|
18
18
|
end
|
19
19
|
|
20
|
+
def quote_default_expression(value, column)
|
21
|
+
if value.is_a?(::Enumerable)
|
22
|
+
quote(value) + '::' + column.sql_type
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def _quote(value)
|
31
|
+
return super unless value.is_a?(Array)
|
32
|
+
|
33
|
+
values = value.map(&method(:quote))
|
34
|
+
"ARRAY[#{values.join(','.freeze)}]"
|
35
|
+
end
|
36
|
+
|
37
|
+
def _type_cast(value)
|
38
|
+
return super unless value.is_a?(Array)
|
39
|
+
value.map(&method(:quote)).join(','.freeze)
|
40
|
+
end
|
20
41
|
end
|
21
42
|
end
|
22
43
|
end
|
@@ -20,6 +20,13 @@ module Torque
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
# Creates a column with an enum array type, needing to specify the
|
24
|
+
# subtype, which is basically the name of the type defined prior
|
25
|
+
# creating the column
|
26
|
+
def enum_set(*args, **options)
|
27
|
+
super(*args, **options.merge(array: true))
|
28
|
+
end
|
29
|
+
|
23
30
|
end
|
24
31
|
|
25
32
|
module TableDefinition
|
@@ -10,6 +10,15 @@ module Torque
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
# Translate +:enum_set+ into +:enum+
|
14
|
+
def schema_type(column)
|
15
|
+
if column.type == :enum_set
|
16
|
+
:enum
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
13
22
|
# Adds +:subtype+ option to the default set
|
14
23
|
def prepare_column_options(column)
|
15
24
|
spec = super
|
@@ -24,7 +33,7 @@ module Torque
|
|
24
33
|
private
|
25
34
|
|
26
35
|
def schema_subtype(column)
|
27
|
-
column.sql_type.to_sym.inspect if column.type == :enum
|
36
|
+
column.sql_type.to_sym.inspect if column.type == :enum || column.type == :enum_set
|
28
37
|
end
|
29
38
|
|
30
39
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Arel
|
4
|
+
nodes = ::Arel::Nodes
|
5
|
+
inflix = nodes::InfixOperation
|
6
|
+
visitors = ::Arel::Visitors::PostgreSQL
|
7
|
+
default_alias = :visit_Arel_Nodes_InfixOperation
|
8
|
+
|
9
|
+
Math = Module.new
|
10
|
+
INFLIX_OPERATION = {
|
11
|
+
'Overlaps' => :'&&',
|
12
|
+
'Contains' => :'@>',
|
13
|
+
'ContainedBy' => :'<@',
|
14
|
+
'HasKey' => :'?',
|
15
|
+
'HasAllKeys' => :'?&',
|
16
|
+
'HasAnyKeys' => :'?|',
|
17
|
+
'StrictlyLeft' => :'<<',
|
18
|
+
'StrictlyRight' => :'>>',
|
19
|
+
'DoesntRightExtend' => :'&<',
|
20
|
+
'DoesntLeftExtend' => :'&>',
|
21
|
+
'AdjacentTo' => :'-|-',
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
INFLIX_OPERATION.each do |operator_name, operator|
|
25
|
+
klass = Class.new(inflix)
|
26
|
+
klass.send(:define_method, :initialize) { |*args| super(operator, *args) }
|
27
|
+
|
28
|
+
nodes.const_set(operator_name, klass)
|
29
|
+
visitors.send(:alias_method, :"visit_Arel_Nodes_#{operator_name}", default_alias)
|
30
|
+
|
31
|
+
# Don't worry about quoting here, if the right side is something that
|
32
|
+
# doesn't need quoting, it will leave it as it is
|
33
|
+
Math.send(:define_method, operator_name.underscore) do |other|
|
34
|
+
klass.new(self, nodes.build_quoted(other, self))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
::Arel::Nodes::Node.include(Math)
|
39
|
+
::Arel::Attribute.include(Math)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Arel
|
4
|
+
module Nodes
|
5
|
+
|
6
|
+
class Cast < ::Arel::Nodes::Binary
|
7
|
+
include ::Arel::Expressions
|
8
|
+
include ::Arel::Predications
|
9
|
+
include ::Arel::AliasPredication
|
10
|
+
include ::Arel::OrderPredications
|
11
|
+
include ::Arel::Math
|
12
|
+
|
13
|
+
def initialize(left, right, array = false)
|
14
|
+
right = right.to_s
|
15
|
+
right << '[]' if array
|
16
|
+
super left, right
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
::Arel.define_singleton_method(:array) do |*values, cast: nil|
|
23
|
+
values = values.first if values.size.eql?(1) && values.first.is_a?(::Enumerable)
|
24
|
+
result = ::Arel::Nodes.build_quoted(values)
|
25
|
+
result = result.cast(cast, true) if cast.present?
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
::Arel::Nodes::Function.include(::Arel::Math)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Arel
|
4
|
+
module Operations
|
5
|
+
|
6
|
+
# Create a cast operation
|
7
|
+
def cast(type, array = false)
|
8
|
+
Nodes::Cast.new(self, type, array)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
::Arel::Attributes::Attribute.include(Operations)
|
14
|
+
::Arel::Nodes::SqlLiteral.include(Operations)
|
15
|
+
::Arel::Nodes::Node.include(Operations)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -2,7 +2,6 @@ module Torque
|
|
2
2
|
module PostgreSQL
|
3
3
|
module Arel
|
4
4
|
module Visitors
|
5
|
-
|
6
5
|
# Enclose select manager with parenthesis
|
7
6
|
# :TODO: Remove when checking the new version of Arel
|
8
7
|
def visit_Arel_SelectManager o, collector
|
@@ -16,9 +15,36 @@ module Torque
|
|
16
15
|
super
|
17
16
|
end
|
18
17
|
|
18
|
+
# Allow quoted arrays to get here
|
19
|
+
def visit_Arel_Nodes_Quoted(o, collector)
|
20
|
+
return super unless o.expr.is_a?(::Enumerable)
|
21
|
+
quote_array(o.expr, collector)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Allow quoted arrays to get here
|
25
|
+
def visit_Arel_Nodes_Casted(o, collector)
|
26
|
+
return super unless o.val.is_a?(::Enumerable)
|
27
|
+
quote_array(o.val, collector)
|
28
|
+
end
|
29
|
+
|
30
|
+
## TORQUE VISITORS
|
31
|
+
# Allow casting any node
|
32
|
+
def visit_Torque_PostgreSQL_Arel_Nodes_Cast(o, collector)
|
33
|
+
visit(o.left, collector) << '::' << o.right
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def quote_array(value, collector)
|
39
|
+
value = value.map(&::Arel::Nodes.method(:build_quoted))
|
40
|
+
|
41
|
+
collector << 'ARRAY['
|
42
|
+
visit_Array(value, collector)
|
43
|
+
collector << ']'
|
44
|
+
end
|
19
45
|
end
|
20
46
|
|
21
|
-
::Arel::Visitors::PostgreSQL.
|
47
|
+
::Arel::Visitors::PostgreSQL.prepend(Visitors)
|
22
48
|
end
|
23
49
|
end
|
24
50
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require_relative 'associations/association'
|
2
|
+
require_relative 'associations/association_scope'
|
3
|
+
require_relative 'associations/belongs_to_many_association'
|
4
|
+
require_relative 'associations/builder'
|
5
|
+
require_relative 'associations/preloader'
|
6
|
+
|
7
|
+
require_relative 'associations/join_dependency/join_association' \
|
8
|
+
unless Torque::PostgreSQL::AR521
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Associations
|
4
|
+
module Association
|
5
|
+
|
6
|
+
def inversed_from(record)
|
7
|
+
return super unless reflection.connected_through_array?
|
8
|
+
|
9
|
+
self.target ||= []
|
10
|
+
self.target.push(record) unless self.target.include?(record)
|
11
|
+
@inversed = self.target.present?
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def set_owner_attributes(record)
|
17
|
+
return super unless reflection.connected_through_array?
|
18
|
+
|
19
|
+
add_id = owner[reflection.active_record_primary_key]
|
20
|
+
record_fk = reflection.foreign_key
|
21
|
+
|
22
|
+
record[record_fk].push(add_id) unless (record[record_fk] ||= []).include?(add_id)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
::ActiveRecord::Associations::Association.prepend(Association)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
module Associations
|
4
|
+
module AssociationScope
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def get_bind_values(*)
|
8
|
+
super.flatten
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# When the relation is connected through an array, intercept the
|
15
|
+
# condition builder and uses an overlap condition building it on
|
16
|
+
# +build_id_constraint+
|
17
|
+
def last_chain_scope(scope, *args)
|
18
|
+
# 5.0 table, reflection, owner, association_klass
|
19
|
+
# 5.1 table, reflection, owner
|
20
|
+
# 5.2 reflection, owner
|
21
|
+
|
22
|
+
reflection = args.size.eql?(2) ? args[0] : args[1]
|
23
|
+
return super unless reflection.connected_through_array?
|
24
|
+
|
25
|
+
table = args[0] if args.size > 2
|
26
|
+
keys = args.size.eql?(4) ? reflection.join_keys(args[3]) : reflection.join_keys
|
27
|
+
owner = args.size.eql?(2) ? args[1] : args[2]
|
28
|
+
|
29
|
+
value = transform_value(owner[keys.foreign_key])
|
30
|
+
constraint, binds = build_id_constraint(reflection, keys, value, table, true)
|
31
|
+
|
32
|
+
if Torque::PostgreSQL::AR521
|
33
|
+
scope.where!(constraint)
|
34
|
+
else
|
35
|
+
klass = ::ActiveRecord::Relation::WhereClause
|
36
|
+
scope.where_clause += klass.new([constraint], binds)
|
37
|
+
scope
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# When the relation is connected through an array, intercept the
|
42
|
+
# condition builder and uses an overlap condition building it on
|
43
|
+
# +build_id_constraint+
|
44
|
+
def next_chain_scope(scope, *args)
|
45
|
+
# 5.0 table, reflection, association_klass, foreign_table, next_reflection
|
46
|
+
# 5.1 table, reflection, foreign_table, next_reflection
|
47
|
+
# 5.2 reflection, next_reflection
|
48
|
+
|
49
|
+
reflection = args.size.eql?(2) ? args[0] : args[1]
|
50
|
+
return super unless reflection.connected_through_array?
|
51
|
+
|
52
|
+
table = args[0] if args.size > 2
|
53
|
+
next_reflection = args[-1]
|
54
|
+
|
55
|
+
foreign_table = args[-2] if args.size.eql?(5)
|
56
|
+
foreign_table ||= next_reflection.aliased_table
|
57
|
+
|
58
|
+
keys = args.size.eql?(5) ? reflection.join_keys(args[2]) : reflection.join_keys
|
59
|
+
|
60
|
+
value = foreign_table[keys.foreign_key]
|
61
|
+
constraint, *_ = build_id_constraint(reflection, keys, value, table)
|
62
|
+
|
63
|
+
scope.joins!(join(foreign_table, constraint))
|
64
|
+
end
|
65
|
+
|
66
|
+
# Trigger the same method on the relation which will build the
|
67
|
+
# constraint condition using array logics
|
68
|
+
def build_id_constraint(reflection, keys, value, table = nil, bind_param = false)
|
69
|
+
table ||= reflection.aliased_table
|
70
|
+
value, binds = build_binds_for_constraint(reflection, value, keys.foreign_key) \
|
71
|
+
if bind_param
|
72
|
+
|
73
|
+
[reflection.build_id_constraint(table[keys.key], value), binds]
|
74
|
+
end
|
75
|
+
|
76
|
+
# For array-like values, it needs to call the method as many times as
|
77
|
+
# the array size
|
78
|
+
def transform_value(value)
|
79
|
+
if value.is_a?(::Enumerable)
|
80
|
+
value.map { |v| value_transformation.call(v) }
|
81
|
+
else
|
82
|
+
value_transformation.call(value)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# When binds are necessary for a constraint, instantiate them
|
87
|
+
if Torque::PostgreSQL::AR521
|
88
|
+
def build_binds_for_constraint(reflection, values, foreign_key)
|
89
|
+
result = Array.wrap(values).map do |value|
|
90
|
+
::Arel::Nodes::BindParam.new(::ActiveRecord::Relation::QueryAttribute.new(
|
91
|
+
foreign_key, value, reflection.klass.attribute_types[foreign_key],
|
92
|
+
))
|
93
|
+
end
|
94
|
+
|
95
|
+
[result, nil]
|
96
|
+
end
|
97
|
+
else
|
98
|
+
def build_binds_for_constraint(reflection, values, foreign_key)
|
99
|
+
type = reflection.klass.attribute_types[foreign_key]
|
100
|
+
parts = Array.wrap(values).map do |value|
|
101
|
+
bind = ::Arel::Nodes::BindParam.new
|
102
|
+
value = ::ActiveRecord::Relation::QueryAttribute.new(foreign_key, value, type)
|
103
|
+
[bind, value]
|
104
|
+
end.to_h
|
105
|
+
|
106
|
+
[parts.keys, parts.values]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
::ActiveRecord::Associations::AssociationScope.singleton_class.prepend(AssociationScope::ClassMethods)
|
113
|
+
::ActiveRecord::Associations::AssociationScope.prepend(AssociationScope)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|