Module: ActiveVersion::Revisions::HasRevisions::RevisionQueries

Extended by:
ActiveSupport::Concern
Included in:
ActiveVersion::Revisions::HasRevisions
Defined in:
lib/active_version/revisions/has_revisions/revision_queries.rb

Overview

Methods for querying revisions

Instance Method Summary collapse

Instance Method Details

#at(time: nil, version: nil) ⇒ Object

Return a copy of record at specified time (read-only)



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
# File 'lib/active_version/revisions/has_revisions/revision_queries.rb', line 31

def at(time: nil, version: nil)
  if version
    return self if !revisions_scope.exists? && ActiveVersion.config.return_self_if_no_revisions
    return at_version(version)
  end

  time = ActiveVersion.parse_time(time)

  # Validate future time
  if time.future?
    unless ActiveVersion.config.return_self_if_no_revisions
      raise ActiveVersion::FutureTimeError, "Future state cannot be known"
    end
    return self
  end

  # Check if revisions exist
  unless revisions_scope.exists?
    return ActiveVersion.config.return_self_if_no_revisions ? self : nil
  end

  return nil unless exists_at_time?(time)
  return self if current_at_time?(time)

  revision_entry = find_revision_by_time(time)
  build_revision_dup(revision_entry, time) if revision_entry
end

#at!(time: nil, version: nil) ⇒ Object

Return a copy of record at specified time (read-only) or raise error

Raises:

  • (ActiveRecord::RecordNotFound)


60
61
62
63
64
# File 'lib/active_version/revisions/has_revisions/revision_queries.rb', line 60

def at!(time: nil, version: nil)
  result = at(time: time, version: version)
  raise ActiveRecord::RecordNotFound, "No revision found at #{time || version}" unless result
  result
end

#at_version(version) ⇒ Object

Get revision at specific version



82
83
84
85
86
87
88
89
# File 'lib/active_version/revisions/has_revisions/revision_queries.rb', line 82

def at_version(version)
  return nil unless version
  version_column = revision_version_column
  revision_entry = revisions_scope.find_by(version_column => version)
  return nil unless revision_entry

  build_revision_dup(revision_entry)
end

#at_version!(version) ⇒ Object

Get revision at specific version (read-only)

Raises:

  • (ActiveRecord::RecordNotFound)


67
68
69
70
71
# File 'lib/active_version/revisions/has_revisions/revision_queries.rb', line 67

def at_version!(version)
  result = at_version(version)
  raise ActiveRecord::RecordNotFound, "No revision found at version #{version}" unless result
  result
end

#current_versionObject

Get current version number (or version we’re at after switch_to!/undo!)



74
75
76
77
78
79
# File 'lib/active_version/revisions/has_revisions/revision_queries.rb', line 74

def current_version
  ptr = instance_variable_get(:@active_version_pointer)
  return ptr if ptr
  version_column = revision_version_column
  revisions_scope.maximum(version_column) || 0
end

#revision(version: nil) ⇒ Object

Get revision at specific version Returns a reconstructed instance of the model at that version



10
11
12
13
14
# File 'lib/active_version/revisions/has_revisions/revision_queries.rb', line 10

def revision(version: nil)
  return nil unless version

  at_version(version)
end

#revision_at(time: nil) ⇒ Object

Get revision at specific time



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/active_version/revisions/has_revisions/revision_queries.rb', line 17

def revision_at(time: nil)
  return nil unless time

  time_obj = ActiveVersion.parse_time_to_time(time)
  raise ActiveVersion::FutureTimeError, "Future state cannot be known" if time_obj.future?

  version_column = revision_version_column
  revision_entry = revisions_scope.where("created_at <= ?", time_obj).order(version_column => :desc).first
  # If requested time is before the first revision, return the earliest revision if present.
  revision_entry ||= revisions_scope.order(version_column => :asc).first
  revision_entry
end

#versions(reverse: false, include_self: false) ⇒ Object

Enumerate all versions (lazy enumerator returning revision instances)



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
118
119
# File 'lib/active_version/revisions/has_revisions/revision_queries.rb', line 92

def versions(reverse: false, include_self: false)
  version_column = revision_version_column
  ordered_rows = revisions_scope.order(version_column => (reverse ? :desc : :asc)).to_a
  entries_by_version = ordered_rows.index_by { |row| row.public_send(version_column) }
  version_list = ordered_rows.map { |row| row.public_send(version_column) }

  # If include_self, prepare current state as a revision instance
  current_self = nil
  if include_self
    current_self = dup
    current_self.instance_variable_set(:@new_record, false)
    current_self.instance_variable_set(:@persisted, true)
    current_self.readonly!
  end

  Enumerator.new do |yielder|
    version_list.each do |v|
      revision_entry = entries_by_version[v]
      next unless revision_entry

      revision = build_revision_dup(revision_entry)
      yielder << revision if revision
    end
    if include_self
      yielder << current_self if current_self
    end
  end
end