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(" LEFT JOIN (\#{scope_query.to_sql}) \#{HelperMethods.table_name(name)}\n ON \#{\n Array(primary_key).map do |pk|\n \"\#{HelperMethods.table_name(name)}.\#{pk} = \#{table_name}.\#{pk}\"\n end.join(' AND')\n }\n SQL\n end)\n else\n select_lambda =\n if default\n -> { Arel::Nodes::NamedFunction.new('COALESCE', [select.(), default.()]) }\n else\n select\n end\n\n scope(:\"with_\#{name}\", -> do\n HelperMethods.select_append(self, select_lambda.().as(name))\n end)\n end\n\n @ar_virtual_fields[name.to_sym] = select_lambda\n\n method_name = :\"ar_virtual_field_\#{name}\"\n\n define_method(method_name, &get)\n define_method(name) do\n if ActiveRecord::Base.connection.query_cache_enabled\n attributes.key?(name) ? self[name] : send(method_name)\n else\n send(method_name)\n end\n end\nend\n".squish), select_lambda.().as(name))
|