checkpoint before breaking things

This commit is contained in:
Dylan Knutson
2025-07-15 03:50:34 +00:00
parent 9f73c0d364
commit 5f358abae6
5 changed files with 324 additions and 60 deletions

View File

@@ -5,24 +5,13 @@ module HasAuxTable
module QueryExtensions
extend T::Sig
# Get all aux column names for this model
def get_aux_column_names(aux_table_name)
config = @aux_table_configs[aux_table_name]
return [] unless config&.model_class
config.model_class.column_names.reject do |col|
%w[base_table_id created_at updated_at].include?(col)
end
end
# Split conditions into main table and aux table conditions
def split_conditions(conditions, association_name)
aux_columns = self.get_aux_column_names(association_name)
def split_conditions(conditions, aux_config)
main_conditions = {}
aux_conditions = {}
conditions.each do |key, value|
if aux_columns.include?(key.to_s)
if aux_config.is_aux_column?(key)
aux_conditions[key] = value
else
main_conditions[key] = value
@@ -41,6 +30,7 @@ module HasAuxTable
end
def setup_query_extensions!(on, aux_config, with_bind_attribute: true)
association_name = aux_config.aux_association_name
on.define_singleton_method(:where) do |*args|
if args.first.is_a?(Hash)
relation = self.eager_load(association_name)
@@ -52,6 +42,11 @@ module HasAuxTable
end
end
all_method = on.method(:all)
on.define_singleton_method(:all) do
all_method.call.eager_load(association_name)
end
unscoped_method = on.method(:unscoped)
on.define_singleton_method(:unscoped) do
relation = unscoped_method.call
@@ -62,16 +57,8 @@ module HasAuxTable
if with_bind_attribute
bind_attribute_method = on.method(:bind_attribute)
on.define_singleton_method(:bind_attribute) do |name, value, &block|
aux_column_names = self.get_aux_column_names(association_name)
if aux_column_names.include?(name.to_s)
attr = aux_config.model_class.arel_table[name]
bind =
aux_config.model_class.predicate_builder.build_bind_attribute(
attr.name,
value
)
block.call(attr, bind)
if aux_config.is_aux_column?(name)
aux_config.aux_bind_attribute(name, value, &block)
else
bind_attribute_method.call(name, value, &block)
end
@@ -87,7 +74,7 @@ module HasAuxTable
on.define_singleton_method(:apply_split_conditions!) do |relation, args|
conditions = args.first
main_conditions, aux_conditions =
self.split_conditions(conditions, association_name)
self.split_conditions(conditions, aux_config)
relation.where!(main_conditions) if main_conditions.any?
if aux_conditions.any?
relation.where!(association_name => aux_conditions)
@@ -101,7 +88,7 @@ module HasAuxTable
on.define_singleton_method(:exists?) do |*args|
conditions = args.first || {}
main_conditions, aux_conditions =
self.split_conditions(conditions, association_name)
self.split_conditions(conditions, aux_config)
puts "checking with conditions: #{main_conditions} / #{aux_conditions}"
relation = self.select("1").joins(association_name)

View File

@@ -39,6 +39,21 @@ module HasAuxTable
aux_association.target ||= aux_association.build
end
sig do
params(name: Symbol, value: T.untyped, block: T.proc.void).returns(
Arel::Nodes::Node
)
end
def aux_bind_attribute(name, value, &block)
arel_attr = model_class.arel_table[name]
aux_bind =
model_class.predicate_builder.build_bind_attribute(
arel_attr.name,
value
)
block.call(arel_attr, aux_bind)
end
sig do
params(
main_class: T.class_of(ActiveRecord::Base),
@@ -63,6 +78,27 @@ module HasAuxTable
aux_model = self.ensure_aux_target(main_model)
aux_model.assign_attributes(aux_args)
end
sig { returns(T::Array[Symbol]) }
def aux_column_names
@aux_column_names ||=
model_class
.column_names
.reject do |col|
[
self.foreign_key,
:base_table_id,
:created_at,
:updated_at
].flatten.include?(col.to_sym)
end
.map(&:to_sym)
end
sig { params(name: T.any(Symbol, String)).returns(T::Boolean) }
def is_aux_column?(name)
aux_column_names.include?(name.to_sym)
end
end
module ClassMethods
@@ -173,15 +209,14 @@ module HasAuxTable
end
end
%i[_read_attribute read_attribute].each do |method_name|
# override _read_attribute to delegate auxiliary columns to the auxiliary table
%i[_read_attribute read_attribute write_attribute].each do |method_name|
read_attribute_method = self.instance_method(method_name)
self.define_method(method_name) do |name|
if aux_columns_hash.include?(name.to_s)
self.define_method(method_name) do |name, *args, **kwargs|
if aux_config.is_aux_column?(name)
target = aux_config.ensure_aux_target(self)
target.send(method_name, name)
target.send(method_name, name, *args, **kwargs)
else
read_attribute_method.bind(self).call(name)
read_attribute_method.bind(self).call(name, *args, **kwargs)
end
end
end
@@ -189,8 +224,7 @@ module HasAuxTable
initialize_method = self.instance_method(:initialize)
self.define_method(:initialize) do |args|
aux_args, main_args =
args.partition { |k, _| aux_columns_hash.key?(k.to_s) }.map(&:to_h)
args.partition { |k, _| aux_config.is_aux_column?(k) }.map(&:to_h)
initialize_method.bind(self).call(main_args)
aux_config.assign_aux_attributes(self, aux_args)
end
@@ -208,13 +242,6 @@ module HasAuxTable
.target
.instance_variable_get(:@attributes)
)
# ActiveRecord::Base.transaction do
# aux_model = aux_config.ensure_aux_target(self)
# result = reload_method.bind(self).call(*args)
# self.send(:"#{aux_config.aux_association_name}=", aux_model)
# end
# fresh_model =
# result
self
end
@@ -293,7 +320,8 @@ module HasAuxTable
class_name: aux_class_name,
foreign_key:,
primary_key:,
inverse_of: main_association_name
inverse_of: main_association_name,
dependent: :destroy
# autosave: true
)