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,
sig/active_version/revisions.rbs

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)

Parameters:

  • time: (Object) (defaults to: nil)
  • version: (Integer, nil) (defaults to: nil)

Returns:

  • (Object)


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

Parameters:

  • time: (Object) (defaults to: nil)
  • version: (Integer, nil) (defaults to: nil)

Returns:

  • (Object)

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

Parameters:

  • version (Integer)

Returns:

  • (Object)


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)

Parameters:

  • version (Integer)

Returns:

  • (Object)

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_versionInteger

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

Returns:

  • (Integer)


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

Parameters:

  • version: (Integer, nil) (defaults to: nil)

Returns:

  • (Object)


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

Parameters:

  • time: (Object) (defaults to: nil)

Returns:

  • (Object)

Raises:



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) ⇒ Enumerator[untyped]

Enumerate all versions (lazy enumerator returning revision instances)

Parameters:

  • reverse: (Boolean) (defaults to: false)
  • include_self: (Boolean) (defaults to: false)

Returns:

  • (Enumerator[untyped])


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