Module: TemporalTables::RelationExtensions

Defined in:
lib/temporal_tables/relation_extensions.rb

Overview

Stores the time from the “at” field into each of the resulting objects so that it can be carried forward in subsequent queries.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



5
6
7
8
9
# File 'lib/temporal_tables/relation_extensions.rb', line 5

def self.included(base)
	base.class_eval do
		ActiveRecord::Relation::SINGLE_VALUE_METHODS << :at
	end
end

Instance Method Details

#at(*args) ⇒ Object



19
20
21
# File 'lib/temporal_tables/relation_extensions.rb', line 19

def at(*args)
    spawn.at!(*args)
end

#at!(value) ⇒ Object



23
24
25
26
# File 'lib/temporal_tables/relation_extensions.rb', line 23

def at!(value)
	self.at_value = value
	self
end

#at_valueObject



11
12
13
# File 'lib/temporal_tables/relation_extensions.rb', line 11

def at_value
  get_value(:at) || Thread.current[:at_time]
end

#at_value=(value) ⇒ Object



15
16
17
# File 'lib/temporal_tables/relation_extensions.rb', line 15

def at_value=(value)
  set_value(:at, value)
end

#exec_queriesObject



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/temporal_tables/relation_extensions.rb', line 67

def exec_queries
	# Note that record preloading, like when you specify
	#  MyClass.includes(:associations)
	# happens within this exec_queries call.  That's why we needed to
	# store the at_time in the thread above.
	threadify_at do
		super
	end

	if historical?
		# Store the at value on each record returned
		# TODO: traverse preloaded associations too
		@records.each do |r|
			r.at_value = at_value
		end
	end
	@records
end

#historical?Boolean

Returns:

  • (Boolean)


86
87
88
# File 'lib/temporal_tables/relation_extensions.rb', line 86

def historical?
	table_name =~ /_h$/i && at_value
end

#limited_ids_for(*args) ⇒ Object



61
62
63
64
65
# File 'lib/temporal_tables/relation_extensions.rb', line 61

def limited_ids_for(*args)
	threadify_at do
		super *args
	end
end

#threadify_atObject



50
51
52
53
54
55
56
57
58
59
# File 'lib/temporal_tables/relation_extensions.rb', line 50

def threadify_at
	if at_value && !Thread.current[:at_time]
		Thread.current[:at_time] = at_value
		result = yield
		Thread.current[:at_time] = nil
	else
		result = yield
	end
	result
end

#to_sql(*args) ⇒ Object



44
45
46
47
48
# File 'lib/temporal_tables/relation_extensions.rb', line 44

def to_sql(*args)
	threadify_at do
		super *args
	end
end

#where_clauseObject



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/temporal_tables/relation_extensions.rb', line 28

def where_clause
	s = super

	at_clauses = []
	if historical?
		at_clauses << where_clause_factory.build(
			arel_table[:eff_to].gteq(at_value).and(
				arel_table[:eff_from].lteq(at_value)
			),
			[]
		)
	end

	[s, *at_clauses.compact].sum
end