torque-postgresql 2.0.2 → 2.1.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/lib/torque/postgresql.rb +1 -0
- data/lib/torque/postgresql/adapter.rb +23 -0
- data/lib/torque/postgresql/adapter/database_statements.rb +2 -0
- data/lib/torque/postgresql/adapter/oid.rb +3 -1
- data/lib/torque/postgresql/adapter/oid/box.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/circle.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/enum.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/enum_set.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/interval.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/line.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/range.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/segment.rb +2 -0
- data/lib/torque/postgresql/adapter/quoting.rb +2 -0
- data/lib/torque/postgresql/adapter/schema_creation.rb +8 -1
- data/lib/torque/postgresql/adapter/schema_definitions.rb +2 -0
- data/lib/torque/postgresql/adapter/schema_dumper.rb +7 -1
- data/lib/torque/postgresql/adapter/schema_statements.rb +2 -0
- data/lib/torque/postgresql/arel/infix_operation.rb +5 -1
- data/lib/torque/postgresql/arel/join_source.rb +2 -0
- data/lib/torque/postgresql/arel/nodes.rb +2 -0
- data/lib/torque/postgresql/arel/operations.rb +2 -0
- data/lib/torque/postgresql/arel/select_manager.rb +2 -0
- data/lib/torque/postgresql/arel/visitors.rb +6 -3
- data/lib/torque/postgresql/associations/association.rb +14 -3
- data/lib/torque/postgresql/associations/association_scope.rb +2 -0
- data/lib/torque/postgresql/associations/belongs_to_many_association.rb +169 -47
- data/lib/torque/postgresql/associations/builder/belongs_to_many.rb +8 -5
- data/lib/torque/postgresql/associations/builder/has_many.rb +2 -0
- data/lib/torque/postgresql/associations/preloader/association.rb +30 -1
- data/lib/torque/postgresql/attributes/builder.rb +3 -1
- data/lib/torque/postgresql/attributes/builder/enum.rb +5 -3
- data/lib/torque/postgresql/attributes/builder/period.rb +6 -4
- data/lib/torque/postgresql/attributes/enum.rb +5 -10
- data/lib/torque/postgresql/attributes/enum_set.rb +2 -0
- data/lib/torque/postgresql/attributes/lazy.rb +3 -1
- data/lib/torque/postgresql/attributes/period.rb +2 -0
- data/lib/torque/postgresql/autosave_association.rb +19 -16
- data/lib/torque/postgresql/auxiliary_statement.rb +2 -0
- data/lib/torque/postgresql/auxiliary_statement/settings.rb +2 -0
- data/lib/torque/postgresql/base.rb +11 -2
- data/lib/torque/postgresql/coder.rb +5 -3
- data/lib/torque/postgresql/collector.rb +2 -0
- data/lib/torque/postgresql/config.rb +5 -0
- data/lib/torque/postgresql/geometry_builder.rb +2 -0
- data/lib/torque/postgresql/i18n.rb +2 -0
- data/lib/torque/postgresql/inheritance.rb +2 -0
- data/lib/torque/postgresql/insert_all.rb +26 -0
- data/lib/torque/postgresql/migration/command_recorder.rb +2 -0
- data/lib/torque/postgresql/railtie.rb +2 -0
- data/lib/torque/postgresql/reflection.rb +2 -0
- data/lib/torque/postgresql/reflection/abstract_reflection.rb +13 -28
- data/lib/torque/postgresql/reflection/association_reflection.rb +24 -0
- data/lib/torque/postgresql/reflection/belongs_to_many_reflection.rb +18 -4
- data/lib/torque/postgresql/reflection/has_many_reflection.rb +2 -0
- data/lib/torque/postgresql/reflection/runtime_reflection.rb +2 -0
- data/lib/torque/postgresql/reflection/through_reflection.rb +2 -0
- data/lib/torque/postgresql/relation.rb +15 -11
- data/lib/torque/postgresql/relation/auxiliary_statement.rb +6 -1
- data/lib/torque/postgresql/relation/distinct_on.rb +2 -0
- data/lib/torque/postgresql/relation/inheritance.rb +2 -0
- data/lib/torque/postgresql/relation/merger.rb +2 -0
- data/lib/torque/postgresql/schema_cache.rb +2 -0
- data/lib/torque/postgresql/version.rb +3 -1
- data/spec/schema.rb +3 -2
- data/spec/tests/arel_spec.rb +3 -1
- data/spec/tests/belongs_to_many_spec.rb +134 -13
- data/spec/tests/enum_set_spec.rb +1 -1
- data/spec/tests/has_many_spec.rb +25 -1
- data/spec/tests/insert_all_spec.rb +89 -0
- data/spec/tests/table_inheritance_spec.rb +1 -1
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd2096d27cb0b11fd4cd2048627bf0b12dcd905d4240ea0251366f580a0afcf2
|
4
|
+
data.tar.gz: c6d948dd77768feff3d85284bc838b8fb03c91233cc33ecdc8b3c22e463038c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f61ba4bf68f2519090bb23b259cf9d8fa2c59f5a9935c867fe0dd2629eeeddd21e7a9f68a0e168550f696564d9613a4617ed6619ac4fe1f3d7660bf3fd1fc9c
|
7
|
+
data.tar.gz: dbb298a6df589aa9368fb70f933b5ece9984bfc3661d667c7e42b989e2bdda6159aafbf78a303f9926f3b17dbc762473454f4646e91e976a21a0fd439a57c9f9
|
data/lib/torque/postgresql.rb
CHANGED
@@ -22,6 +22,7 @@ require 'torque/postgresql/autosave_association'
|
|
22
22
|
require 'torque/postgresql/auxiliary_statement'
|
23
23
|
require 'torque/postgresql/base'
|
24
24
|
require 'torque/postgresql/inheritance'
|
25
|
+
require 'torque/postgresql/insert_all'
|
25
26
|
require 'torque/postgresql/coder'
|
26
27
|
require 'torque/postgresql/migration'
|
27
28
|
require 'torque/postgresql/relation'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'adapter/database_statements'
|
2
4
|
require_relative 'adapter/oid'
|
3
5
|
require_relative 'adapter/quoting'
|
@@ -13,12 +15,33 @@ module Torque
|
|
13
15
|
include DatabaseStatements
|
14
16
|
include SchemaStatements
|
15
17
|
|
18
|
+
INJECT_WHERE_REGEX = /(DO UPDATE SET.*excluded\.[^ ]+) RETURNING/.freeze
|
19
|
+
|
16
20
|
# Get the current PostgreSQL version as a Gem Version.
|
17
21
|
def version
|
18
22
|
@version ||= Gem::Version.new(
|
19
23
|
select_value('SELECT version()').match(/#{Adapter::ADAPTER_NAME} ([\d\.]+)/)[1]
|
20
24
|
)
|
21
25
|
end
|
26
|
+
|
27
|
+
# Add `inherits` to the list of extracted table options
|
28
|
+
def extract_table_options!(options)
|
29
|
+
super.merge(options.extract!(:inherits))
|
30
|
+
end
|
31
|
+
|
32
|
+
# Allow filtered bulk insert by adding the where clause. This method is only used by
|
33
|
+
# +InsertAll+, so it somewhat safe to override it
|
34
|
+
def build_insert_sql(insert)
|
35
|
+
super.tap do |sql|
|
36
|
+
if insert.update_duplicates? && insert.where_condition?
|
37
|
+
if insert.returning
|
38
|
+
sql.gsub!(INJECT_WHERE_REGEX, "\\1 WHERE #{insert.where} RETURNING")
|
39
|
+
else
|
40
|
+
sql << " WHERE #{insert.where}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
22
45
|
end
|
23
46
|
|
24
47
|
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend Adapter
|
@@ -17,9 +17,11 @@ module Torque
|
|
17
17
|
ActiveRecord::Type.register(:circle, OID::Circle, adapter: :postgresql)
|
18
18
|
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
|
19
19
|
ActiveRecord::Type.register(:enum_set, OID::EnumSet, adapter: :postgresql)
|
20
|
-
ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql)
|
21
20
|
ActiveRecord::Type.register(:line, OID::Line, adapter: :postgresql)
|
22
21
|
ActiveRecord::Type.register(:segment, OID::Segment, adapter: :postgresql)
|
22
|
+
|
23
|
+
ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql) \
|
24
|
+
unless PostgreSQL::AR610
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
@@ -24,10 +24,17 @@ module Torque
|
|
24
24
|
end)
|
25
25
|
end
|
26
26
|
|
27
|
+
if respond_to?(:supports_check_constraints?) && supports_check_constraints?
|
28
|
+
statements.concat(o.check_constraints.map do |expression, options|
|
29
|
+
check_constraint_in_create(o.name, expression, options)
|
30
|
+
end)
|
31
|
+
end
|
32
|
+
|
27
33
|
create_sql << "(#{statements.join(', ')})" \
|
28
34
|
if statements.present? || o.inherits.present?
|
29
35
|
|
30
|
-
|
36
|
+
options = PostgreSQL::AR610 ? o : table_options(o)
|
37
|
+
add_table_options!(create_sql, options)
|
31
38
|
|
32
39
|
if o.inherits.present?
|
33
40
|
tables = o.inherits.map(&method(:quote_table_name))
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Adapter
|
@@ -39,7 +41,7 @@ module Torque
|
|
39
41
|
|
40
42
|
def tables(stream) # :nodoc:
|
41
43
|
inherited_tables = @connection.inherited_tables
|
42
|
-
sorted_tables = @connection.
|
44
|
+
sorted_tables = @connection.tables.sort - @connection.views
|
43
45
|
|
44
46
|
stream.puts " # These are the common tables managed"
|
45
47
|
(sorted_tables - inherited_tables.keys).each do |table_name|
|
@@ -76,6 +78,10 @@ module Torque
|
|
76
78
|
|
77
79
|
# Scenic integration
|
78
80
|
views(stream) if defined?(::Scenic)
|
81
|
+
|
82
|
+
# FX integration
|
83
|
+
functions(stream) if defined?(::Fx::SchemaDumper::Function)
|
84
|
+
triggers(stream) if defined?(::Fx::SchemaDumper::Trigger)
|
79
85
|
end
|
80
86
|
|
81
87
|
# Dump user defined types like enum
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Arel
|
@@ -22,6 +24,8 @@ module Torque
|
|
22
24
|
}.freeze
|
23
25
|
|
24
26
|
INFLIX_OPERATION.each do |operator_name, operator|
|
27
|
+
next if nodes.const_defined?(operator_name)
|
28
|
+
|
25
29
|
klass = Class.new(inflix)
|
26
30
|
klass.send(:define_method, :initialize) { |*args| super(operator, *args) }
|
27
31
|
|
@@ -31,7 +35,7 @@ module Torque
|
|
31
35
|
# Don't worry about quoting here, if the right side is something that
|
32
36
|
# doesn't need quoting, it will leave it as it is
|
33
37
|
Math.send(:define_method, operator_name.underscore) do |other|
|
34
|
-
klass.new(self,
|
38
|
+
klass.new(self, other)
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Arel
|
4
6
|
module Visitors
|
5
7
|
# Enclose select manager with parenthesis
|
6
8
|
# :TODO: Remove when checking the new version of Arel
|
7
|
-
def visit_Arel_SelectManager
|
9
|
+
def visit_Arel_SelectManager(o, collector)
|
8
10
|
collector << '('
|
9
11
|
visit(o.ast, collector) << ')'
|
10
12
|
end
|
@@ -23,8 +25,9 @@ module Torque
|
|
23
25
|
|
24
26
|
# Allow quoted arrays to get here
|
25
27
|
def visit_Arel_Nodes_Casted(o, collector)
|
26
|
-
|
27
|
-
|
28
|
+
value = o.respond_to?(:val) ? o.val : o.value
|
29
|
+
return super unless value.is_a?(::Enumerable)
|
30
|
+
quote_array(value, collector)
|
28
31
|
end
|
29
32
|
|
30
33
|
## TORQUE VISITORS
|
@@ -1,8 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Associations
|
4
6
|
module Association
|
5
7
|
|
8
|
+
# There is no problem of adding temporary items on target because
|
9
|
+
# CollectionProxy will handle memory and persisted relationship
|
6
10
|
def inversed_from(record)
|
7
11
|
return super unless reflection.connected_through_array?
|
8
12
|
|
@@ -11,20 +15,27 @@ module Torque
|
|
11
15
|
@inversed = self.target.present?
|
12
16
|
end
|
13
17
|
|
18
|
+
# The binds and the cache are getting mixed and caching the wrong query
|
19
|
+
def skip_statement_cache?(*)
|
20
|
+
super || reflection.connected_through_array?
|
21
|
+
end
|
22
|
+
|
14
23
|
private
|
15
24
|
|
25
|
+
# This is mainly for the has many when connect through an array to add
|
26
|
+
# its id to the list of the inverse belongs to many association
|
16
27
|
def set_owner_attributes(record)
|
17
28
|
return super unless reflection.connected_through_array?
|
18
29
|
|
19
30
|
add_id = owner[reflection.active_record_primary_key]
|
20
|
-
|
21
|
-
|
22
|
-
record[record_fk].push(add_id) unless (record[record_fk] ||= []).include?(add_id)
|
31
|
+
list = record[reflection.foreign_key] ||= []
|
32
|
+
list.push(add_id) unless list.include?(add_id)
|
23
33
|
end
|
24
34
|
|
25
35
|
end
|
26
36
|
|
27
37
|
::ActiveRecord::Associations::Association.prepend(Association)
|
38
|
+
::ActiveRecord::Associations::HasManyAssociation.prepend(Association)
|
28
39
|
end
|
29
40
|
end
|
30
41
|
end
|
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_record/associations/collection_association'
|
4
|
+
|
2
5
|
# FIXME: build, create
|
3
6
|
module Torque
|
4
7
|
module PostgreSQL
|
@@ -6,10 +9,69 @@ module Torque
|
|
6
9
|
class BelongsToManyAssociation < ::ActiveRecord::Associations::CollectionAssociation
|
7
10
|
include ::ActiveRecord::Associations::ForeignAssociation
|
8
11
|
|
12
|
+
## CUSTOM
|
13
|
+
def ids_reader
|
14
|
+
if loaded?
|
15
|
+
target.pluck(reflection.association_primary_key)
|
16
|
+
elsif !target.empty?
|
17
|
+
load_target.pluck(reflection.association_primary_key)
|
18
|
+
else
|
19
|
+
stale_state || column_default_value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def ids_writer(ids)
|
24
|
+
ids = ids.presence || column_default_value
|
25
|
+
owner.write_attribute(source_attr, ids)
|
26
|
+
return unless owner.persisted? && owner.attribute_changed?(source_attr)
|
27
|
+
|
28
|
+
owner.update_attribute(source_attr, ids)
|
29
|
+
end
|
30
|
+
|
31
|
+
def size
|
32
|
+
if loaded?
|
33
|
+
target.size
|
34
|
+
elsif !target.empty?
|
35
|
+
unsaved_records = target.select(&:new_record?)
|
36
|
+
unsaved_records.size + stale_state.size
|
37
|
+
else
|
38
|
+
stale_state&.size || 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def empty?
|
43
|
+
size.zero?
|
44
|
+
end
|
45
|
+
|
46
|
+
def include?(record)
|
47
|
+
return false unless record.is_a?(reflection.klass)
|
48
|
+
return include_in_memory?(record) if record.new_record?
|
49
|
+
|
50
|
+
(!target.empty? && target.include?(record)) ||
|
51
|
+
stale_state&.include?(record.read_attribute(klass_attr))
|
52
|
+
end
|
53
|
+
|
54
|
+
def load_target
|
55
|
+
if stale_target? || find_target?
|
56
|
+
@target = merge_target_lists(find_target, target)
|
57
|
+
end
|
58
|
+
|
59
|
+
loaded!
|
60
|
+
target
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_changes
|
64
|
+
@_building_changes = true
|
65
|
+
yield.tap { ids_writer(ids_reader) }
|
66
|
+
ensure
|
67
|
+
@_building_changes = nil
|
68
|
+
end
|
69
|
+
|
70
|
+
## HAS MANY
|
9
71
|
def handle_dependency
|
10
72
|
case options[:dependent]
|
11
73
|
when :restrict_with_exception
|
12
|
-
raise
|
74
|
+
raise ActiveRecord::DeleteRestrictionError.new(reflection.name) unless empty?
|
13
75
|
|
14
76
|
when :restrict_with_error
|
15
77
|
unless empty?
|
@@ -19,88 +81,126 @@ module Torque
|
|
19
81
|
end
|
20
82
|
|
21
83
|
when :destroy
|
22
|
-
# No point in executing the counter update since we're going to destroy the parent anyway
|
23
84
|
load_target.each { |t| t.destroyed_by_association = reflection }
|
24
85
|
destroy_all
|
86
|
+
when :destroy_async
|
87
|
+
load_target.each do |t|
|
88
|
+
t.destroyed_by_association = reflection
|
89
|
+
end
|
90
|
+
|
91
|
+
unless target.empty?
|
92
|
+
association_class = target.first.class
|
93
|
+
primary_key_column = association_class.primary_key.to_sym
|
94
|
+
|
95
|
+
ids = target.collect do |assoc|
|
96
|
+
assoc.public_send(primary_key_column)
|
97
|
+
end
|
98
|
+
|
99
|
+
enqueue_destroy_association(
|
100
|
+
owner_model_name: owner.class.to_s,
|
101
|
+
owner_id: owner.id,
|
102
|
+
association_class: association_class.to_s,
|
103
|
+
association_ids: ids,
|
104
|
+
association_primary_key_column: primary_key_column,
|
105
|
+
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
|
106
|
+
)
|
107
|
+
end
|
25
108
|
else
|
26
109
|
delete_all
|
27
110
|
end
|
28
111
|
end
|
29
112
|
|
30
|
-
def ids_reader
|
31
|
-
owner[reflection.active_record_primary_key]
|
32
|
-
end
|
33
|
-
|
34
|
-
def ids_writer(new_ids)
|
35
|
-
column = reflection.active_record_primary_key
|
36
|
-
command = owner.persisted? ? :update_column : :write_attribute
|
37
|
-
owner.public_send(command, column, new_ids.presence)
|
38
|
-
@association_scope = nil
|
39
|
-
end
|
40
|
-
|
41
113
|
def insert_record(record, *)
|
42
|
-
super
|
43
|
-
|
44
|
-
|
45
|
-
attribute.push(record[klass_fk])
|
46
|
-
record
|
47
|
-
end
|
48
|
-
|
49
|
-
def empty?
|
50
|
-
size.zero?
|
114
|
+
super.tap do |saved|
|
115
|
+
ids_rewriter(record.read_attribute(klass_attr), :<<) if saved
|
116
|
+
end
|
51
117
|
end
|
52
118
|
|
53
|
-
|
54
|
-
|
55
|
-
|
119
|
+
## BELONGS TO
|
120
|
+
def default(&block)
|
121
|
+
writer(owner.instance_exec(&block)) if reader.nil?
|
56
122
|
end
|
57
123
|
|
58
124
|
private
|
59
125
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
126
|
+
## CUSTOM
|
127
|
+
def _create_record(attributes, raises = false, &block)
|
128
|
+
if attributes.is_a?(Array)
|
129
|
+
attributes.collect { |attr| _create_record(attr, raises, &block) }
|
130
|
+
else
|
131
|
+
build_record(attributes, &block).tap do |record|
|
132
|
+
transaction do
|
133
|
+
result = nil
|
134
|
+
add_to_target(record) do
|
135
|
+
result = insert_record(record, true, raises) { @_was_loaded = loaded? }
|
136
|
+
end
|
137
|
+
raise ActiveRecord::Rollback unless result
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
64
141
|
end
|
65
142
|
|
66
|
-
# When the idea is to
|
143
|
+
# When the idea is to nullify the association, then just set the owner
|
67
144
|
# +primary_key+ as empty
|
68
|
-
def delete_count(method, scope, ids
|
69
|
-
|
70
|
-
|
71
|
-
remove_stash_records(ids)
|
145
|
+
def delete_count(method, scope, ids)
|
146
|
+
size_cache = scope.delete_all if method == :delete_all
|
147
|
+
(size_cache || ids.size).tap { ids_rewriter(ids, :-) }
|
72
148
|
end
|
73
149
|
|
74
150
|
def delete_or_nullify_all_records(method)
|
75
|
-
delete_count(method, scope)
|
151
|
+
delete_count(method, scope, ids_reader)
|
76
152
|
end
|
77
153
|
|
78
154
|
# Deletes the records according to the <tt>:dependent</tt> option.
|
79
155
|
def delete_records(records, method)
|
80
|
-
ids =
|
156
|
+
ids = read_records_ids(records)
|
81
157
|
|
82
158
|
if method == :destroy
|
83
159
|
records.each(&:destroy!)
|
84
|
-
|
160
|
+
ids_rewriter(ids, :-)
|
85
161
|
else
|
86
|
-
scope = self.scope.where(
|
162
|
+
scope = self.scope.where(klass_attr => records)
|
87
163
|
delete_count(method, scope, ids)
|
88
164
|
end
|
89
165
|
end
|
90
166
|
|
91
|
-
def
|
92
|
-
|
93
|
-
ids_writer(ids_reader)
|
94
|
-
result
|
167
|
+
def source_attr
|
168
|
+
reflection.foreign_key
|
95
169
|
end
|
96
170
|
|
97
|
-
def
|
98
|
-
|
99
|
-
ids_writer(ids_reader - Array.wrap(ids))
|
171
|
+
def klass_attr
|
172
|
+
reflection.active_record_primary_key
|
100
173
|
end
|
101
174
|
|
102
|
-
def
|
103
|
-
|
175
|
+
def read_records_ids(records)
|
176
|
+
return unless records.present?
|
177
|
+
Array.wrap(records).each_with_object(klass_attr).map(&:read_attribute).presence
|
178
|
+
end
|
179
|
+
|
180
|
+
def ids_rewriter(ids, operator)
|
181
|
+
list = owner[source_attr] ||= []
|
182
|
+
list = list.public_send(operator, ids)
|
183
|
+
owner[source_attr] = list.uniq.compact.presence || column_default_value
|
184
|
+
|
185
|
+
return if @_building_changes || !owner.persisted?
|
186
|
+
owner.update_attribute(source_attr, list)
|
187
|
+
end
|
188
|
+
|
189
|
+
def column_default_value
|
190
|
+
owner.class.columns_hash[source_attr].default
|
191
|
+
end
|
192
|
+
|
193
|
+
## HAS MANY
|
194
|
+
def replace_records(*)
|
195
|
+
build_changes { super }
|
196
|
+
end
|
197
|
+
|
198
|
+
def concat_records(*)
|
199
|
+
build_changes { super }
|
200
|
+
end
|
201
|
+
|
202
|
+
def delete_or_destroy(*)
|
203
|
+
build_changes { super }
|
104
204
|
end
|
105
205
|
|
106
206
|
def difference(a, b)
|
@@ -110,6 +210,28 @@ module Torque
|
|
110
210
|
def intersection(a, b)
|
111
211
|
a & b
|
112
212
|
end
|
213
|
+
|
214
|
+
## BELONGS TO
|
215
|
+
def scope_for_create
|
216
|
+
super.except!(klass.primary_key)
|
217
|
+
end
|
218
|
+
|
219
|
+
def find_target?
|
220
|
+
!loaded? && foreign_key_present? && klass
|
221
|
+
end
|
222
|
+
|
223
|
+
def foreign_key_present?
|
224
|
+
stale_state.present?
|
225
|
+
end
|
226
|
+
|
227
|
+
def invertible_for?(record)
|
228
|
+
inverse = inverse_reflection_for(record)
|
229
|
+
inverse && (inverse.has_many? && inverse.connected_through_array?)
|
230
|
+
end
|
231
|
+
|
232
|
+
def stale_state
|
233
|
+
owner.read_attribute(source_attr)
|
234
|
+
end
|
113
235
|
end
|
114
236
|
|
115
237
|
::ActiveRecord::Associations.const_set(:BelongsToManyAssociation, BelongsToManyAssociation)
|