Class: PaperTrailDiff::HistoryDiagnostics
- Inherits:
-
Object
- Object
- PaperTrailDiff::HistoryDiagnostics
- Defined in:
- lib/paper_trail_diff/diagnostics.rb,
sig/generated/paper_trail_diff/diagnostics.rbs
Overview
Performs read-only checks for known PaperTrail/PT-AT reconstruction hazards.
Instance Method Summary collapse
-
#add_error(code, message, path = nil, version_id = nil) ⇒ void
: (Symbol, String, ?String?, ?untyped) -> void.
-
#add_issue(severity, code, message, path, version_id) ⇒ void
: (Symbol, Symbol, String, String?, untyped) -> void.
-
#add_warning(code, message, path = nil) ⇒ void
: (Symbol, String, ?String?) -> void.
-
#association_tracking_available? ⇒ Boolean
: () -> bool.
-
#call ⇒ DiagnosticReport
: () -> DiagnosticReport.
-
#initialize(from_version, to_version, associations:) ⇒ HistoryDiagnostics
constructor
: (untyped, untyped, associations: Array[String | Symbol]) -> void.
-
#inspect_checkpoint_timestamp(model_class) ⇒ void
: (untyped) -> void.
-
#inspect_habtm(selected) ⇒ void
: (Array[Array[untyped]]) -> void.
-
#inspect_targets(selected) ⇒ void
: (Array[Array[untyped]]) -> void.
-
#inspect_through_model(reflection, path) ⇒ void
: (untyped, String) -> void.
-
#inspect_transaction_metadata(paths) ⇒ void
: (Array) -> void.
-
#inspect_version_order ⇒ void
Ordering falls back to the id when timestamps tie, which only recovers the real sequence for ids that increase with insertion.
-
#inspect_versioned_model(model_class, path) ⇒ void
: (untyped, String) -> void.
-
#model_versioned?(model_class) ⇒ Boolean
: (untyped) -> bool.
-
#ordered_range_versions ⇒ Array[untyped]
: () -> Array.
-
#synchronized_timestamp_disabled?(model_class) ⇒ Boolean
: (untyped) -> bool.
-
#tracking_unavailable_message ⇒ String
: () -> String.
-
#validated_model_class ⇒ Object
: () -> untyped.
-
#version_identity(version) ⇒ Array[String]
: (untyped) -> Array.
-
#version_type(version) ⇒ String
: (untyped) -> String.
Constructor Details
#initialize(from_version, to_version, associations:) ⇒ HistoryDiagnostics
: (untyped, untyped, associations: Array[String | Symbol]) -> void
69 70 71 72 73 74 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 69 def initialize(from_version, to_version, associations:) @from_version = from_version @to_version = to_version @tree = AssociationTree.build(associations) @issues = [] #: Array[DiagnosticIssue] end |
Instance Method Details
#add_error(code, message, path = nil, version_id = nil) ⇒ void
This method returns an undefined value.
: (Symbol, String, ?String?, ?untyped) -> void
251 252 253 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 251 def add_error(code, , path = nil, version_id = nil) add_issue(:error, code, , path, version_id) end |
#add_issue(severity, code, message, path, version_id) ⇒ void
This method returns an undefined value.
: (Symbol, Symbol, String, String?, untyped) -> void
261 262 263 264 265 266 267 268 269 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 261 def add_issue(severity, code, , path, version_id) @issues << DiagnosticIssue.new( severity: severity, code: code, message: , path: path, version_id: version_id ) end |
#add_warning(code, message, path = nil) ⇒ void
This method returns an undefined value.
: (Symbol, String, ?String?) -> void
256 257 258 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 256 def add_warning(code, , path = nil) add_issue(:warning, code, , path, nil) end |
#association_tracking_available? ⇒ Boolean
: () -> bool
227 228 229 230 231 232 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 227 def association_tracking_available? paper_trail = Object.const_get(:PaperTrail) #: untyped config = paper_trail.config #: untyped !!(defined?(::PaperTrailAssociationTracking) && config.respond_to?(:track_associations?) && config.track_associations?) end |
#call ⇒ DiagnosticReport
: () -> DiagnosticReport
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 77 def call model_class = validated_model_class # Runs whether or not associations are selected: unorderable versions # corrupt a scalar timeline just as surely, and a report that inspected # nothing has no business answering `ok?`. inspect_version_order return DiagnosticReport.new(issues: @issues) if @tree.empty? unless association_tracking_available? add_error(:association_tracking_unavailable, ) return DiagnosticReport.new(issues: @issues) end traversal = AssociationTraversal.new(@tree) selected = traversal.selected_reflections(model_class) inspect_targets(selected) (model_class) inspect_habtm(selected) DiagnosticReport.new(issues: @issues) end |
#inspect_checkpoint_timestamp(model_class) ⇒ void
This method returns an undefined value.
: (untyped) -> void
165 166 167 168 169 170 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 165 def (model_class) return if (model_class) = 'manual checkpoints should set synchronize_version_creation_timestamp: false' add_warning(:synchronized_version_timestamp, ) end |
#inspect_habtm(selected) ⇒ void
This method returns an undefined value.
: (Array[Array[untyped]]) -> void
130 131 132 133 134 135 136 137 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 130 def inspect_habtm(selected) paths = selected.filter_map do |path, reflection| path if reflection.macro == :has_and_belongs_to_many end return if paths.empty? (paths) end |
#inspect_targets(selected) ⇒ void
This method returns an undefined value.
: (Array[Array[untyped]]) -> void
117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 117 def inspect_targets(selected) selected.each do |path, reflection| if reflection.polymorphic? add_warning(:polymorphic_target_unverified, 'polymorphic target cannot be verified', path) next end inspect_versioned_model(reflection.klass, path) inspect_through_model(reflection, path) if reflection.[:through] end end |
#inspect_through_model(reflection, path) ⇒ void
This method returns an undefined value.
: (untyped, String) -> void
202 203 204 205 206 207 208 209 210 211 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 202 def inspect_through_model(reflection, path) model_class = reflection.through_reflection.klass return if model_versioned?(model_class) add_warning( :unversioned_through_model, "#{model_class.name} does not appear to have PaperTrail enabled", path ) end |
#inspect_transaction_metadata(paths) ⇒ void
This method returns an undefined value.
: (Array) -> void
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 173 def (paths) [@from_version, @to_version].each do |version| if !version.respond_to?(:transaction_id) add_error(:transaction_id_column_missing, 'version has no transaction_id column') elsif version.transaction_id.nil? paths.each do |path| add_error( :transaction_id_missing, 'HABTM endpoint has no transaction-backed association snapshot', path, version.id ) end end end end |
#inspect_version_order ⇒ void
This method returns an undefined value.
Ordering falls back to the id when timestamps tie, which only recovers the real sequence for ids that increase with insertion. Reported before a run rather than after a wrong answer. : () -> void
143 144 145 146 147 148 149 150 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 143 def inspect_version_order pair = Support.ambiguous_pair(ordered_range_versions) return unless pair add_error(:ambiguous_version_order, Support.(pair), nil, pair.first.id) rescue StandardError nil end |
#inspect_versioned_model(model_class, path) ⇒ void
This method returns an undefined value.
: (untyped, String) -> void
191 192 193 194 195 196 197 198 199 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 191 def inspect_versioned_model(model_class, path) return if model_versioned?(model_class) add_warning( :unversioned_association_target, "#{model_class.name} does not appear to have PaperTrail enabled", path ) end |
#model_versioned?(model_class) ⇒ Boolean
: (untyped) -> bool
214 215 216 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 214 def model_versioned?(model_class) model_class.respond_to?(:paper_trail_options) && !model_class..nil? end |
#ordered_range_versions ⇒ Array[untyped]
: () -> Array
153 154 155 156 157 158 159 160 161 162 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 153 def ordered_range_versions bounds = [@from_version.created_at, @to_version.created_at].compact.sort return [] unless bounds.length == 2 @from_version.class .where(item_type: @from_version.item_type, item_id: @from_version.item_id) .where(created_at: bounds.first..bounds.last) .to_a .sort_by { |version| Support.chronological_version_key(version) } end |
#synchronized_timestamp_disabled?(model_class) ⇒ Boolean
: (untyped) -> bool
219 220 221 222 223 224 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 219 def (model_class) = model_class. [:synchronize_version_creation_timestamp] == false rescue NoMethodError false end |
#tracking_unavailable_message ⇒ String
: () -> String
246 247 248 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 246 def 'association tracking must be loaded and enabled to diagnose associations' end |
#validated_model_class ⇒ Object
: () -> untyped
106 107 108 109 110 111 112 113 114 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 106 def validated_model_class unless version_identity(@from_version) == version_identity(@to_version) raise VersionMismatchError, 'versions must belong to the same PaperTrail item' end Object.const_get(version_type(@from_version)) rescue NoMethodError => e raise VersionMismatchError, 'expected PaperTrail version endpoints', cause: e end |
#version_identity(version) ⇒ Array[String]
: (untyped) -> Array
235 236 237 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 235 def version_identity(version) [version.item_type.to_s, version.item_id.to_s] end |
#version_type(version) ⇒ String
: (untyped) -> String
240 241 242 243 |
# File 'lib/paper_trail_diff/diagnostics.rb', line 240 def version_type(version) subtype = version.item_subtype if version.respond_to?(:item_subtype) subtype.to_s.empty? ? version.item_type.to_s : subtype.to_s end |