Module: ChronoModel::TimeMachine::Timeline
- Defined in:
- lib/chrono_model/time_machine/timeline.rb
Instance Method Summary collapse
- #has_timeline(options) ⇒ Object
- #quoted_history_fields ⇒ Object
-
#timeline(record = nil, options = {}) ⇒ Object
Returns an Array of unique UTC timestamps for which at least an history record exists.
- #timeline_associations ⇒ Object
- #timeline_associations_from(names) ⇒ Object
Instance Method Details
#has_timeline(options) ⇒ Object
62 63 64 65 66 67 68 |
# File 'lib/chrono_model/time_machine/timeline.rb', line 62 def has_timeline() .assert_valid_keys(:with) timeline_associations_from([:with]).tap do |assocs| timeline_associations.concat assocs end end |
#quoted_history_fields ⇒ Object
81 82 83 84 85 86 87 88 89 90 |
# File 'lib/chrono_model/time_machine/timeline.rb', line 81 def quoted_history_fields @quoted_history_fields ||= begin validity = [connection.quote_table_name(table_name), connection.quote_column_name('validity') ].join('.') [:lower, :upper].map! {|func| "#{func}(#{validity})"} end end |
#timeline(record = nil, options = {}) ⇒ Object
Returns an Array of unique UTC timestamps for which at least an history record exists. Takes temporal associations into account.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/chrono_model/time_machine/timeline.rb', line 8 def timeline(record = nil, = {}) rid = record.respond_to?(:rid) ? record.rid : record.id if record assocs = .key?(:with) ? timeline_associations_from([:with]) : timeline_associations models = [] models.push self if self.chrono? models.concat(assocs.map {|a| a.klass.history}) return [] if models.empty? fields = models.inject([]) {|a,m| a.concat m.quoted_history_fields} relation = self.except(:order). select("DISTINCT UNNEST(ARRAY[#{fields.join(',')}]) AS ts") if assocs.present? relation = relation.joins(*assocs.map(&:name)) end relation = relation. order('ts ' << ([:reverse] ? 'DESC' : 'ASC')) relation = relation.from(%["public".#{quoted_table_name}]) unless self.chrono? relation = relation.where(id: rid) if rid sql = "SELECT ts FROM ( #{relation.to_sql} ) foo WHERE ts IS NOT NULL" if .key?(:before) sql << " AND ts < '#{Conversions.time_to_utc_string(options[:before])}'" end if .key?(:after) sql << " AND ts > '#{Conversions.time_to_utc_string(options[:after ])}'" end if rid && ![:with] sql << (self.chrono? ? %{ AND ts <@ ( SELECT tsrange(min(lower(validity)), max(upper(validity)), '[]') FROM #{quoted_table_name} WHERE id = #{rid} ) } : %[ AND ts < NOW() ]) end sql << " LIMIT #{options[:limit].to_i}" if .key?(:limit) sql.gsub! 'INNER JOIN', 'LEFT OUTER JOIN' connection.on_schema(Adapter::HISTORY_SCHEMA) do connection.select_values(sql, "#{self.name} periods").map! do |ts| Conversions.string_to_utc_time ts end end end |
#timeline_associations ⇒ Object
70 71 72 |
# File 'lib/chrono_model/time_machine/timeline.rb', line 70 def timeline_associations @timeline_associations ||= [] end |
#timeline_associations_from(names) ⇒ Object
74 75 76 77 78 79 |
# File 'lib/chrono_model/time_machine/timeline.rb', line 74 def timeline_associations_from(names) Array.wrap(names).map do |name| reflect_on_association(name) or raise ArgumentError, "No association found for name `#{name}'" end end |