Skip to content

Commit c497b5d

Browse files
committed
ActiveRecord::Writer no Context allocs
1 parent 15271e6 commit c497b5d

File tree

1 file changed

+90
-2
lines changed
  • lib/panko/impl/attributes_writer/active_record

1 file changed

+90
-2
lines changed

lib/panko/impl/attributes_writer/active_record/writer.rb

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,16 @@
55

66
module Panko::Impl::AttributesWriter::ActiveRecord
77
class Writer
8+
def initialize
9+
@attributes_hash = EMPTY_HASH
10+
@attributes_hash_size = 0
11+
@indexed_row_column_indexes = nil
12+
@is_indexed_row = false
13+
@indexed_row_row = nil
14+
end
15+
816
def write_attributes(object, descriptor, writer)
9-
attributes_ctx = Context.new(object)
17+
set_from_record(object)
1018
object_class = object.class
1119

1220
length = descriptor.attributes.length
@@ -16,12 +24,92 @@ def write_attributes(object, descriptor, writer)
1624

1725
attribute.invalidate!(object_class)
1826

19-
value = attributes_ctx.read_attribute(attribute)
27+
value = read_attribute(attribute)
2028

2129
ValuesWriter.write(writer, attribute, value)
2230

2331
i += 1
2432
end
2533
end
34+
35+
private
36+
37+
def set_from_record(record)
38+
attributes_set = record._panko_attributes
39+
40+
attributes_hash = attributes_set._panko_attributes_hash
41+
if attributes_hash&.empty?
42+
@attributes_hash = EMPTY_HASH
43+
@attributes_hash_size = 0
44+
else
45+
@attributes_hash = attributes_hash
46+
@attributes_hash_size = attributes_hash.size
47+
end
48+
49+
@types = attributes_set._panko_types
50+
@additional_types = attributes_set._panko_additional_types
51+
@try_to_read_from_additional_types = !@additional_types.nil? && !@additional_types.empty?
52+
53+
@values = attributes_set._panko_values
54+
55+
# Check if the values are of type ActiveRecord::Result::IndexedRow
56+
if PANKO_INDEX_ROW_DEFINED && @values.is_a?(ActiveRecord::Result::IndexedRow)
57+
@indexed_row_column_indexes = @values._panko_column_indexes
58+
@indexed_row_row = @values._panko_row
59+
@is_indexed_row = true
60+
else
61+
@indexed_row_column_indexes = nil
62+
@is_indexed_row = false
63+
@indexed_row_row = nil
64+
end
65+
end
66+
67+
# Reads a value from the indexed row
68+
def read_value_from_indexed_row(member)
69+
return nil if @indexed_row_column_indexes.nil? || @indexed_row_row.nil?
70+
71+
column_index = @indexed_row_column_indexes[member]
72+
return nil if column_index.nil?
73+
74+
row = @indexed_row_row
75+
return nil if row.nil?
76+
77+
row[column_index]
78+
end
79+
80+
# Reads the attribute value
81+
def read_attribute(attribute)
82+
member = attribute.name
83+
value = nil
84+
85+
# If we have a populated attributes_hash
86+
if @attributes_hash_size > 0 && !@attributes_hash.nil?
87+
attribute_metadata = @attributes_hash[member]
88+
unless attribute_metadata.nil?
89+
value = attribute_metadata.instance_variable_get(:@value_before_type_cast)
90+
attribute.type ||= attribute_metadata.instance_variable_get(:@type)
91+
end
92+
end
93+
94+
# Fallback to reading from values or indexed row
95+
if value.nil? && !@values.nil?
96+
value = if @is_indexed_row
97+
read_value_from_indexed_row(member)
98+
else
99+
@values[member]
100+
end
101+
end
102+
103+
# Fetch the type if not yet set
104+
if attribute.type.nil? && !value.nil?
105+
if @try_to_read_from_additional_types
106+
attribute.type = @additional_types[member]
107+
end
108+
109+
attribute.type ||= @types[member]
110+
end
111+
112+
value
113+
end
26114
end
27115
end

0 commit comments

Comments
 (0)