Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 1 addition & 24 deletions lib/activerecord-bitemporal/bitemporal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ def reload(options = nil)
@previously_force_updated = false
self
end
elsif Gem::Version.new("6.1.0") <= ActiveRecord.version
else
def reload(options = nil)
return active_record_bitemporal_original_reload(options) unless self.class.bi_temporal_model?

Expand All @@ -447,29 +447,6 @@ def reload(options = nil)
@previously_force_updated = false
self
end
else
def reload(options = nil)
return active_record_bitemporal_original_reload(options) unless self.class.bi_temporal_model?

self.class.connection.clear_query_cache

fresh_object =
ActiveRecord::Bitemporal.with_bitemporal_option(**bitemporal_option) {
if options && options[:lock]
self.class.unscoped { self.class.lock(options[:lock]).bitemporal_default_scope.find(id) }
else
self.class.unscoped { self.class.bitemporal_default_scope.find(id) }
end
}

@attributes = fresh_object.instance_variable_get("@attributes")
@new_record = false
# NOTE: Hook to copying swapped_id
@_swapped_id_previously_was = nil
@_swapped_id = fresh_object.swapped_id
@previously_force_updated = false
self
end
end
end

Expand Down
218 changes: 65 additions & 153 deletions lib/activerecord-bitemporal/scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,53 +47,28 @@ def operator; nil ; end
end
}

def each_operatable_node_6_0(nodes = predicates, &block)
def each_operatable_node(nodes = predicates, &block)
if block
each_operatable_node(nodes).each(&block)
else
Enumerator.new { |y|
Array(nodes).each { |node|
case node
when Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
y << node if node && node.left.respond_to?(:relation)
when Arel::Nodes::Grouping
each_operatable_node(node.expr) { |node| y << node }
end
}
}
end
end

def each_operatable_node_6_1(nodes = predicates, &block)
if block
each_operatable_node_6_1(nodes).each(&block)
else
Enumerator.new { |y|
Array(nodes).each { |node|
case node
when Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
y << node if node && node.left.respond_to?(:relation)
when Arel::Nodes::And
each_operatable_node_6_1(node.children) { |node| y << node }
each_operatable_node(node.children) { |node| y << node }
when Arel::Nodes::Binary
each_operatable_node_6_1(node.left) { |node| y << node }
each_operatable_node_6_1(node.right) { |node| y << node }
each_operatable_node(node.left) { |node| y << node }
each_operatable_node(node.right) { |node| y << node }
when Arel::Nodes::Unary
each_operatable_node_6_1(node.expr) { |node| y << node }
each_operatable_node(node.expr) { |node| y << node }
end
}
}
end
end

def each_operatable_node(nodes = predicates, &block)
if Gem::Version.new("6.1.0") <= ActiveRecord.version
each_operatable_node_6_1(nodes, &block)
else
each_operatable_node_6_0(nodes, &block)
end
end

def bitemporal_query_hash(*names)
each_operatable_node
.select { |node| names.include? node.left.name.to_s }
Expand Down Expand Up @@ -126,31 +101,6 @@ def bitemporal_clause(table_name = klass.table_name)
end
}

if ActiveRecord.version < Gem::Version.new("6.1.0")
class WhereClauseWithCheckTable < ActiveRecord::Relation::WhereClause
using NodeBitemporalInclude

def bitemporal_include?(column)
!!predicates.grep(::Arel::Nodes::Node).find do |node|
node.bitemporal_include?(column)
end
end

private

def except_predicates(columns)
columns = Array(columns)
predicates.reject do |node|
::Arel::Nodes::Node === node && node.bitemporal_include?(*columns)
end
end
end

def where_clause
WhereClauseWithCheckTable.new(super.send(:predicates))
end
end

module MergeWithExceptBitemporalDefaultScope
using BitemporalChecker
def merge(other)
Expand Down Expand Up @@ -243,118 +193,80 @@ def ignore_transaction_datetime?
end
}

if ActiveRecord.version < Gem::Version.new("6.1.0")
module ActiveRecordRelationScope
refine ::ActiveRecord::Relation do
%i(valid_from valid_to transaction_from transaction_to).each { |column|
module_eval <<-STR, __FILE__, __LINE__ + 1
def _ignore_#{column}
unscope(where: "\#{table.name}.#{column}")
.tap { |relation| relation.merge!(bitemporal_value[:through].unscoped._ignore_#{column}) if bitemporal_value[:through] }
end

def _except_#{column}
return self unless where_clause.bitemporal_include?("\#{table.name}.#{column}")
all._ignore_#{column}.tap { |relation|
relation.unscope_values.delete({ where: "\#{table.name}.#{column}" })
}
end
STR

[
:lt, # column < datetime
:lteq, # column <= datetime
:gt, # column > datetime
:gteq # column >= datetime
].each { |op|
module_eval <<-STR, __FILE__, __LINE__ + 1
def _#{column}_#{op}(datetime, without_ignore: false)
target_datetime = datetime&.in_time_zone || Time.current
relation = self.tap { |relation| break relation._ignore_#{column} unless without_ignore }
relation.bitemporal_where_bind!(:#{column}, :#{op}, target_datetime)
.tap { |relation| relation.merge!(bitemporal_value[:through].unscoped._#{column}_#{op}(target_datetime)) if bitemporal_value[:through] }
end
STR
}
}
end
end
else
module ActiveRecordRelationScope
module EqualAttributeName
refine ::Object do
def equal_attribute_name(*)
false
end
module ActiveRecordRelationScope
module EqualAttributeName
refine ::Object do
def equal_attribute_name(*)
false
end
refine ::Hash do
def equal_attribute_name(other)
self[:where].equal_attribute_name(other)
end
end
refine ::Hash do
def equal_attribute_name(other)
self[:where].equal_attribute_name(other)
end
refine ::Array do
def equal_attribute_name(other)
first.equal_attribute_name(other)
end
end
refine ::Array do
def equal_attribute_name(other)
first.equal_attribute_name(other)
end
refine ::String do
def equal_attribute_name(other)
self == other.to_s
end
end
refine ::String do
def equal_attribute_name(other)
self == other.to_s
end
refine ::Symbol do
def equal_attribute_name(other)
self.to_s == other.to_s
end
end
refine ::Symbol do
def equal_attribute_name(other)
self.to_s == other.to_s
end
refine ::Arel::Attributes::Attribute do
def equal_attribute_name(other)
"#{relation.name}.#{name}" == other.to_s
end
end
refine ::Arel::Attributes::Attribute do
def equal_attribute_name(other)
"#{relation.name}.#{name}" == other.to_s
end
end
end

refine ::ActiveRecord::Relation do
using EqualAttributeName
using NodeBitemporalInclude
refine ::ActiveRecord::Relation do
using EqualAttributeName
using NodeBitemporalInclude

def bitemporal_rewhere_bind(attr_name, operator, value, table = self.table)
rewhere(table[attr_name].public_send(operator, predicate_builder.build_bind_attribute(attr_name, value)))
end
def bitemporal_rewhere_bind(attr_name, operator, value, table = self.table)
rewhere(table[attr_name].public_send(operator, predicate_builder.build_bind_attribute(attr_name, value)))
end

%i(valid_from valid_to transaction_from transaction_to).each { |column|
module_eval <<-STR, __FILE__, __LINE__ + 1
def _ignore_#{column}
unscope(where: :"\#{table.name}.#{column}")
.tap { |relation| relation.unscope!(where: bitemporal_value[:through].arel_table["#{column}"]) if bitemporal_value[:through] }
end
%i(valid_from valid_to transaction_from transaction_to).each { |column|
module_eval <<-STR, __FILE__, __LINE__ + 1
def _ignore_#{column}
unscope(where: :"\#{table.name}.#{column}")
.tap { |relation| relation.unscope!(where: bitemporal_value[:through].arel_table["#{column}"]) if bitemporal_value[:through] }
end

def _except_#{column}
return self unless where_clause.send(:predicates).find { |node|
node.bitemporal_include?("\#{table.name}.#{column}")
}
_ignore_#{column}.tap { |relation|
relation.unscope_values.reject! { |query| query.equal_attribute_name("\#{table.name}.#{column}") }
}
def _except_#{column}
return self unless where_clause.send(:predicates).find { |node|
node.bitemporal_include?("\#{table.name}.#{column}")
}
_ignore_#{column}.tap { |relation|
relation.unscope_values.reject! { |query| query.equal_attribute_name("\#{table.name}.#{column}") }
}
end
STR

[
:lt, # column < datetime
:lteq, # column <= datetime
:gt, # column > datetime
:gteq # column >= datetime
].each { |op|
module_eval <<-STR, __FILE__, __LINE__ + 1
def _#{column}_#{op}(datetime,**)
target_datetime = datetime&.in_time_zone || Time.current
bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime)
.tap { |relation| break relation.bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime, bitemporal_value[:through].arel_table) if bitemporal_value[:through] }
end
STR

[
:lt, # column < datetime
:lteq, # column <= datetime
:gt, # column > datetime
:gteq # column >= datetime
].each { |op|
module_eval <<-STR, __FILE__, __LINE__ + 1
def _#{column}_#{op}(datetime,**)
target_datetime = datetime&.in_time_zone || Time.current
bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime)
.tap { |relation| break relation.bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime, bitemporal_value[:through].arel_table) if bitemporal_value[:through] }
end
STR
}
}
end
}
end
end
using ActiveRecordRelationScope
Expand Down