52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
# File 'lib/ar_virtual_field.rb', line 52
def virtual_field(name, scope: nil, select:, get:, default: nil)
@ar_virtual_fields ||= FieldsData.new
name = name.to_s
current_class = self
if default
default = HelperMethods.wrap_to_lambda(default)
end
select = HelperMethods.wrap_to_lambda(select)
if scope
field_name = Arel.sql(HelperMethods.table_with_column(name))
select_lambda =
if default
-> { Arel::Nodes::NamedFunction.new('COALESCE', [field_name, default.()]) }
else
-> { field_name }
end
scope_name = :"_scope_#{name}"
scope(scope_name, scope)
scope(:"with_#{name}", -> do
scope_query = current_class
.send(scope_name)
.select(select.().as(name), "#{table_name}.id")
HelperMethods.select_append(joins(<<~SQL.squish), select_lambda.().as(name))
LEFT JOIN (#{scope_query.to_sql}) #{HelperMethods.table_name(name)}
ON #{
Array(primary_key).map do |pk|
"#{HelperMethods.table_name(name)}.#{pk} = #{table_name}.#{pk}"
end.join(' AND')
}
SQL
end)
else
select_lambda =
if default
-> { Arel::Nodes::NamedFunction.new('COALESCE', [select.(), default.()]) }
else
select
end
scope(:"with_#{name}", -> do
HelperMethods.select_append(self, select_lambda.().as(name))
end)
end
@ar_virtual_fields[name.to_sym] = select_lambda
method_name = :"ar_virtual_field_#{name}"
define_method(method_name, &get)
define_method(name) do
if ActiveRecord::Base.connection.query_cache_enabled
attributes.key?(name) ? self[name] : send(method_name)
else
send(method_name)
end
end
end
|