Class: PaperTrailDiff::TimelineRange

Inherits:
Object
  • Object
show all
Defined in:
lib/paper_trail_diff/timeline_range.rb,
sig/generated/paper_trail_diff/timeline_range.rbs

Overview

Chooses explicit-version or wall-clock selection for one timeline request.

Constant Summary collapse

BOUNDARY_SYMBOLS =

Returns:

  • (Object)
%i[first last].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(record, from:, to:, within:, versions: nil, version_scope: nil, plan: nil, live_endpoint: nil) ⇒ TimelineRange

: (untyped, from: untyped, to: untyped, within: untyped, ?versions: Array?, ?version_scope: untyped, ?plan: RootVersionPlan?, ?live_endpoint: untyped) -> void

Parameters:

  • (Object)
  • from: (Object)
  • to: (Object)
  • within: (Object)
  • versions: (Array[untyped], nil) (defaults to: nil)
  • version_scope: (Object) (defaults to: nil)
  • plan: (RootVersionPlan, nil) (defaults to: nil)
  • live_endpoint: (Object) (defaults to: nil)


14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/paper_trail_diff/timeline_range.rb', line 14

def initialize(record, from:, to:, within:, versions: nil, version_scope: nil, plan: nil, live_endpoint: nil) # rubocop:disable Metrics/ParameterLists, Layout/LineLength
  @record = record
  @plan = plan
  @live_endpoint = live_endpoint
  @versions = (plan ? plan.versions : versions)&.freeze
  @version_scope = version_scope
  @requested_from = from
  @requested_to = to
  @time_range = build_time_range(within)
  validate_mode!
  @from = resolve(from)
  @to = resolve(to)
  freeze
end

Instance Attribute Details

#fromObject (readonly)

Signature:

  • untyped

Returns:

  • (Object)


9
10
11
# File 'lib/paper_trail_diff/timeline_range.rb', line 9

def from
  @from
end

#time_rangeTimeRange? (readonly)

Signature:

  • TimeRange?

Returns:



11
12
13
# File 'lib/paper_trail_diff/timeline_range.rb', line 11

def time_range
  @time_range
end

#toObject (readonly)

Signature:

  • untyped

Returns:

  • (Object)


10
11
12
# File 'lib/paper_trail_diff/timeline_range.rb', line 10

def to
  @to
end

Instance Method Details

#begin_timeTime?

: () -> Time?

Returns:

  • (Time, nil)


81
82
83
# File 'lib/paper_trail_diff/timeline_range.rb', line 81

def begin_time
  time_range&.begin_time
end

#build_time_range(within) ⇒ TimeRange?

: (untyped) -> TimeRange?

Parameters:

  • (Object)

Returns:



143
144
145
# File 'lib/paper_trail_diff/timeline_range.rb', line 143

def build_time_range(within)
  TimeRange.new(within) unless within.nil?
end

#empty_versionsArray[untyped]

: () -> Array

Returns:

  • (Array[untyped])


104
105
106
107
# File 'lib/paper_trail_diff/timeline_range.rb', line 104

def empty_versions
  versions = [] #: Array[untyped]
  versions.freeze
end

#include?(version) ⇒ Boolean

: (untyped) -> bool

Parameters:

  • (Object)

Returns:

  • (Boolean)


86
87
88
89
# File 'lib/paper_trail_diff/timeline_range.rb', line 86

def include?(version)
  range = time_range
  !range || range.include?(version.created_at)
end

#ordered_versionsObject

: () -> untyped

Returns:

  • (Object)


130
131
132
# File 'lib/paper_trail_diff/timeline_range.rb', line 130

def ordered_versions
  versions_relation.reorder(created_at: :asc, id: :asc)
end

#resolve(boundary) ⇒ Object

Resolving :first and :last here keeps callers from depending on the order PaperTrail happens to give its versions association, which a caller is also free to reorder. : (untyped) -> untyped

Parameters:

  • (Object)

Returns:

  • (Object)


118
119
120
121
122
123
124
125
126
127
# File 'lib/paper_trail_diff/timeline_range.rb', line 118

def resolve(boundary)
  return boundary unless symbolic?(boundary)

  unless BOUNDARY_SYMBOLS.include?(boundary)
    raise InvalidTimelineRangeError,
          "unsupported boundary: #{boundary.inspect}; use :first, :last, a version, or a record"
  end

  boundary == :first ? ordered_versions.first : ordered_versions.last
end

#select(context_required: false) ⇒ Array[untyped]

: (?context_required: bool) -> Array

Parameters:

  • context_required: (Boolean) (defaults to: false)

Returns:

  • (Array[untyped])


60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/paper_trail_diff/timeline_range.rb', line 60

def select(context_required: false)
  preselected = @versions
  return preselected if preselected

  range = time_range
  if range
    return TimeVersionRange.new(
      @record, time_range: range, version_scope: @version_scope
    ).select(context_required: context_required)
  end
  return empty_versions if unresolved?

  VersionRange.new(@record, from: @from, to: @to, version_scope: @version_scope).select
end

#select_plan(context_required: false) ⇒ RootVersionPlan

A batch may have selected these versions already, in which case reselecting them per record would undo the batching. The plan says which pairs of versions become steps, which a filter can make different from adjacent pairs of the selected versions. : (?context_required: bool) -> RootVersionPlan

Parameters:

  • context_required: (Boolean) (defaults to: false)

Returns:



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/paper_trail_diff/timeline_range.rb', line 41

def select_plan(context_required: false)
  preselected = @plan
  return preselected if preselected

  range = time_range
  if range
    return TimeVersionRange.new(
      @record, time_range: range, version_scope: @version_scope,
               live_endpoint: @live_endpoint
    ).select_plan(context_required: context_required)
  end
  return RootVersionPlan.empty if unresolved?

  VersionRange.new(
    @record, from: @from, to: @to, version_scope: @version_scope
  ).select_plan_for_range
end

#symbolic?(boundary) ⇒ Boolean

: (untyped) -> bool

Parameters:

  • (Object)

Returns:

  • (Boolean)


110
111
112
# File 'lib/paper_trail_diff/timeline_range.rb', line 110

def symbolic?(boundary)
  boundary.is_a?(Symbol)
end

#time?Boolean

: () -> bool

Returns:

  • (Boolean)


76
77
78
# File 'lib/paper_trail_diff/timeline_range.rb', line 76

def time?
  !time_range.nil?
end

#unresolved?Boolean

A record with no versions has no first or last boundary to resolve, which is an empty history rather than a bad request. : () -> bool

Returns:

  • (Boolean)


32
33
34
# File 'lib/paper_trail_diff/timeline_range.rb', line 32

def unresolved?
  (symbolic?(@requested_from) && @from.nil?) || (symbolic?(@requested_to) && @to.nil?)
end

#validate_mode!void

This method returns an undefined value.

: () -> void



148
149
150
151
152
153
154
155
156
157
# File 'lib/paper_trail_diff/timeline_range.rb', line 148

def validate_mode!
  if time?
    return if @requested_from.nil? && @requested_to.nil?

    raise InvalidTimelineRangeError, '`within` cannot be combined with `from` or `to`'
  end
  return unless @requested_from.nil? || @requested_to.nil?

  raise InvalidTimelineRangeError, 'provide both `from` and `to`, or provide `within`'
end

#versions_relationObject

: () -> untyped

Returns:

  • (Object)


135
136
137
138
139
140
# File 'lib/paper_trail_diff/timeline_range.rb', line 135

def versions_relation
  @record.public_send(@record.class.versions_association_name)
rescue NoMethodError => e
  message = 'record does not expose a PaperTrail version history'
  raise InvalidTimelineRangeError, message, cause: e
end