torque-postgresql 0.2.16 → 1.0.0
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/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
|