piko-smart-pkg 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/paper_trail-17.0.0/LICENSE +20 -0
  3. data/paper_trail-17.0.0/lib/generators/paper_trail/install/USAGE +31 -0
  4. data/paper_trail-17.0.0/lib/generators/paper_trail/install/install_generator.rb +249 -0
  5. data/paper_trail-17.0.0/lib/generators/paper_trail/install/templates/add_object_changes_to_versions.rb.erb +12 -0
  6. data/paper_trail-17.0.0/lib/generators/paper_trail/install/templates/create_versions.rb.erb +41 -0
  7. data/paper_trail-17.0.0/lib/generators/paper_trail/migration_generator.rb +65 -0
  8. data/paper_trail-17.0.0/lib/generators/paper_trail/update_item_subtype/USAGE +4 -0
  9. data/paper_trail-17.0.0/lib/generators/paper_trail/update_item_subtype/templates/update_versions_for_item_subtype.rb.erb +86 -0
  10. data/paper_trail-17.0.0/lib/generators/paper_trail/update_item_subtype/update_item_subtype_generator.rb +40 -0
  11. data/paper_trail-17.0.0/lib/paper_trail/attribute_serializers/README.md +10 -0
  12. data/paper_trail-17.0.0/lib/paper_trail/attribute_serializers/attribute_serializer_factory.rb +41 -0
  13. data/paper_trail-17.0.0/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +51 -0
  14. data/paper_trail-17.0.0/lib/paper_trail/attribute_serializers/object_attribute.rb +48 -0
  15. data/paper_trail-17.0.0/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +51 -0
  16. data/paper_trail-17.0.0/lib/paper_trail/cleaner.rb +60 -0
  17. data/paper_trail-17.0.0/lib/paper_trail/compatibility.rb +51 -0
  18. data/paper_trail-17.0.0/lib/paper_trail/config.rb +41 -0
  19. data/paper_trail-17.0.0/lib/paper_trail/errors.rb +33 -0
  20. data/paper_trail-17.0.0/lib/paper_trail/events/base.rb +343 -0
  21. data/paper_trail-17.0.0/lib/paper_trail/events/create.rb +32 -0
  22. data/paper_trail-17.0.0/lib/paper_trail/events/destroy.rb +42 -0
  23. data/paper_trail-17.0.0/lib/paper_trail/events/update.rb +76 -0
  24. data/paper_trail-17.0.0/lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb +16 -0
  25. data/paper_trail-17.0.0/lib/paper_trail/frameworks/active_record.rb +12 -0
  26. data/paper_trail-17.0.0/lib/paper_trail/frameworks/cucumber.rb +33 -0
  27. data/paper_trail-17.0.0/lib/paper_trail/frameworks/rails/controller.rb +103 -0
  28. data/paper_trail-17.0.0/lib/paper_trail/frameworks/rails/railtie.rb +34 -0
  29. data/paper_trail-17.0.0/lib/paper_trail/frameworks/rails.rb +3 -0
  30. data/paper_trail-17.0.0/lib/paper_trail/frameworks/rspec/helpers.rb +29 -0
  31. data/paper_trail-17.0.0/lib/paper_trail/frameworks/rspec.rb +42 -0
  32. data/paper_trail-17.0.0/lib/paper_trail/has_paper_trail.rb +92 -0
  33. data/paper_trail-17.0.0/lib/paper_trail/model_config.rb +257 -0
  34. data/paper_trail-17.0.0/lib/paper_trail/queries/versions/where_attribute_changes.rb +50 -0
  35. data/paper_trail-17.0.0/lib/paper_trail/queries/versions/where_object.rb +65 -0
  36. data/paper_trail-17.0.0/lib/paper_trail/queries/versions/where_object_changes.rb +70 -0
  37. data/paper_trail-17.0.0/lib/paper_trail/queries/versions/where_object_changes_from.rb +57 -0
  38. data/paper_trail-17.0.0/lib/paper_trail/queries/versions/where_object_changes_to.rb +57 -0
  39. data/paper_trail-17.0.0/lib/paper_trail/record_history.rb +51 -0
  40. data/paper_trail-17.0.0/lib/paper_trail/record_trail.rb +342 -0
  41. data/paper_trail-17.0.0/lib/paper_trail/reifier.rb +147 -0
  42. data/paper_trail-17.0.0/lib/paper_trail/request.rb +163 -0
  43. data/paper_trail-17.0.0/lib/paper_trail/serializers/json.rb +36 -0
  44. data/paper_trail-17.0.0/lib/paper_trail/serializers/yaml.rb +68 -0
  45. data/paper_trail-17.0.0/lib/paper_trail/type_serializers/postgres_array_serializer.rb +35 -0
  46. data/paper_trail-17.0.0/lib/paper_trail/version_concern.rb +406 -0
  47. data/paper_trail-17.0.0/lib/paper_trail/version_number.rb +23 -0
  48. data/paper_trail-17.0.0/lib/paper_trail.rb +138 -0
  49. data/piko-smart-pkg.gemspec +12 -0
  50. metadata +89 -0
@@ -0,0 +1,257 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PaperTrail
4
+ # Configures an ActiveRecord model, mostly at application boot time, but also
5
+ # sometimes mid-request, with methods like enable/disable.
6
+ class ModelConfig
7
+ E_CANNOT_RECORD_AFTER_DESTROY = <<~STR
8
+ paper_trail.on_destroy(:after) is incompatible with ActiveRecord's
9
+ belongs_to_required_by_default. Use on_destroy(:before)
10
+ or disable belongs_to_required_by_default.
11
+ STR
12
+ E_HPT_ABSTRACT_CLASS = <<~STR.squish.freeze
13
+ An application model (%s) has been configured to use PaperTrail (via
14
+ `has_paper_trail`), but the version model it has been told to use (%s) is
15
+ an `abstract_class`. This could happen when an advanced feature called
16
+ Custom Version Classes (http://bit.ly/2G4ch0G) is misconfigured. When all
17
+ version classes are custom, PaperTrail::Version is configured to be an
18
+ `abstract_class`. This is fine, but all application models must be
19
+ configured to use concrete (not abstract) version models.
20
+ STR
21
+ DPR_PASSING_ASSOC_NAME_DIRECTLY_TO_VERSIONS_OPTION = <<~STR.squish
22
+ Passing versions association name as `has_paper_trail versions: %{versions_name}`
23
+ is deprecated. Use `has_paper_trail versions: {name: %{versions_name}}` instead.
24
+ The hash you pass to `versions:` is now passed directly to `has_many`.
25
+ STR
26
+ DPR_CLASS_NAME_OPTION = <<~STR.squish
27
+ Passing Version class name as `has_paper_trail class_name: %{class_name}`
28
+ is deprecated. Use `has_paper_trail versions: {class_name: %{class_name}}`
29
+ instead. The hash you pass to `versions:` is now passed directly to `has_many`.
30
+ STR
31
+
32
+ def initialize(model_class)
33
+ @model_class = model_class
34
+ end
35
+
36
+ # Adds a callback that records a version after a "create" event.
37
+ #
38
+ # @api public
39
+ def on_create
40
+ @model_class.after_create { |r|
41
+ r.paper_trail.record_create if r.paper_trail.save_version?
42
+ }
43
+ append_option_uniquely(:on, :create)
44
+ end
45
+
46
+ # Adds a callback that records a version before or after a "destroy" event.
47
+ #
48
+ # @api public
49
+ def on_destroy(recording_order = "before")
50
+ assert_valid_recording_order_for_on_destroy(recording_order)
51
+ @model_class.send(
52
+ :"#{recording_order}_destroy",
53
+ lambda do |r|
54
+ return unless r.paper_trail.save_version?
55
+ r.paper_trail.record_destroy(recording_order)
56
+ end
57
+ )
58
+ append_option_uniquely(:on, :destroy)
59
+ end
60
+
61
+ # Adds a callback that records a version after an "update" event.
62
+ #
63
+ # @api public
64
+ def on_update
65
+ @model_class.before_save { |r|
66
+ r.paper_trail.reset_timestamp_attrs_for_update_if_needed
67
+ }
68
+ @model_class.after_update { |r|
69
+ if r.paper_trail.save_version?
70
+ r.paper_trail.record_update(
71
+ force: false,
72
+ in_after_callback: true,
73
+ is_touch: false
74
+ )
75
+ end
76
+ }
77
+ @model_class.after_update { |r|
78
+ r.paper_trail.clear_version_instance
79
+ }
80
+ append_option_uniquely(:on, :update)
81
+ end
82
+
83
+ # Adds a callback that records a version after a "touch" event.
84
+ #
85
+ # Rails < 6.0 (no longer supported by PT) had a bug where dirty-tracking
86
+ # did not occur during a `touch`.
87
+ # (https://github.com/rails/rails/issues/33429) See also:
88
+ # https://github.com/paper-trail-gem/paper_trail/issues/1121
89
+ # https://github.com/paper-trail-gem/paper_trail/issues/1161
90
+ # https://github.com/paper-trail-gem/paper_trail/pull/1285
91
+ #
92
+ # @api public
93
+ def on_touch
94
+ @model_class.after_touch { |r|
95
+ if r.paper_trail.save_version?
96
+ r.paper_trail.record_update(
97
+ force: false,
98
+ in_after_callback: true,
99
+ is_touch: true
100
+ )
101
+ end
102
+ }
103
+ end
104
+
105
+ # Set up `@model_class` for PaperTrail. Installs callbacks, associations,
106
+ # "class attributes", instance methods, and more.
107
+ # @api private
108
+ def setup(options = {})
109
+ options[:on] ||= %i[create update destroy touch]
110
+ options[:on] = Array(options[:on]) # Support single symbol
111
+ @model_class.send :include, ::PaperTrail::Model::InstanceMethods
112
+ setup_options(options)
113
+ setup_associations(options)
114
+ @model_class.after_rollback { paper_trail.clear_rolled_back_versions }
115
+ setup_callbacks_from_options options[:on]
116
+ end
117
+
118
+ # @api private
119
+ def version_class
120
+ @version_class ||= @model_class.version_class_name.constantize
121
+ end
122
+
123
+ private
124
+
125
+ # @api private
126
+ def append_option_uniquely(option, value)
127
+ collection = @model_class.paper_trail_options.fetch(option)
128
+ return if collection.include?(value)
129
+ collection << value
130
+ end
131
+
132
+ # Raises an error if the provided class is an `abstract_class`.
133
+ # @api private
134
+ def assert_concrete_activerecord_class(class_name)
135
+ if class_name.constantize.abstract_class?
136
+ raise Error, format(E_HPT_ABSTRACT_CLASS, @model_class, class_name)
137
+ end
138
+ end
139
+
140
+ # @api private
141
+ def assert_valid_recording_order_for_on_destroy(recording_order)
142
+ unless %w[after before].include?(recording_order.to_s)
143
+ raise ArgumentError, 'recording order can only be "after" or "before"'
144
+ end
145
+
146
+ if recording_order.to_s == "after" && cannot_record_after_destroy?
147
+ raise Error, E_CANNOT_RECORD_AFTER_DESTROY
148
+ end
149
+ end
150
+
151
+ def cannot_record_after_destroy?
152
+ ::ActiveRecord::Base.belongs_to_required_by_default
153
+ end
154
+
155
+ def check_version_class_name(options)
156
+ # @api private - `version_class_name`
157
+ @model_class.class_attribute :version_class_name
158
+ if options[:class_name]
159
+ PaperTrail.deprecator.warn(
160
+ format(
161
+ DPR_CLASS_NAME_OPTION,
162
+ class_name: options[:class_name].inspect
163
+ ),
164
+ caller(1)
165
+ )
166
+ options[:versions][:class_name] = options[:class_name]
167
+ end
168
+ @model_class.version_class_name = options[:versions][:class_name] || "PaperTrail::Version"
169
+ assert_concrete_activerecord_class(@model_class.version_class_name)
170
+ end
171
+
172
+ def check_versions_association_name(options)
173
+ # @api private - versions_association_name
174
+ @model_class.class_attribute :versions_association_name
175
+ @model_class.versions_association_name = options[:versions][:name] || :versions
176
+ end
177
+
178
+ def define_has_many_versions(options)
179
+ options = ensure_versions_option_is_hash(options)
180
+ check_version_class_name(options)
181
+ check_versions_association_name(options)
182
+ scope = get_versions_scope(options)
183
+ @model_class.has_many(
184
+ @model_class.versions_association_name,
185
+ scope,
186
+ class_name: @model_class.version_class_name,
187
+ as: :item,
188
+ **options[:versions].except(:name, :scope)
189
+ )
190
+ end
191
+
192
+ def ensure_versions_option_is_hash(options)
193
+ unless options[:versions].is_a?(Hash)
194
+ if options[:versions]
195
+ PaperTrail.deprecator.warn(
196
+ format(
197
+ DPR_PASSING_ASSOC_NAME_DIRECTLY_TO_VERSIONS_OPTION,
198
+ versions_name: options[:versions].inspect
199
+ ),
200
+ caller(1)
201
+ )
202
+ end
203
+ options[:versions] = {
204
+ name: options[:versions]
205
+ }
206
+ end
207
+ options
208
+ end
209
+
210
+ # Process an `ignore`, `skip`, or `only` option.
211
+ def event_attribute_option(option_name)
212
+ [@model_class.paper_trail_options[option_name]].
213
+ flatten.
214
+ compact.
215
+ map { |attr| attr.is_a?(Hash) ? attr.stringify_keys : attr.to_s }
216
+ end
217
+
218
+ def get_versions_scope(options)
219
+ options[:versions][:scope] || -> { order(model.timestamp_sort_order) }
220
+ end
221
+
222
+ def setup_associations(options)
223
+ # @api private - version_association_name
224
+ @model_class.class_attribute :version_association_name
225
+ @model_class.version_association_name = options[:version] || :version
226
+
227
+ # The version this instance was reified from.
228
+ # @api public
229
+ @model_class.send :attr_accessor, @model_class.version_association_name
230
+
231
+ # @api public - paper_trail_event
232
+ @model_class.send :attr_accessor, :paper_trail_event
233
+
234
+ define_has_many_versions(options)
235
+ end
236
+
237
+ def setup_callbacks_from_options(options_on = [])
238
+ options_on.each do |event|
239
+ public_send(:"on_#{event}")
240
+ end
241
+ end
242
+
243
+ def setup_options(options)
244
+ # @api public - paper_trail_options - Let's encourage plugins to use eg.
245
+ # `paper_trail_options[:versions][:class_name]` rather than
246
+ # `version_class_name` because the former is documented and the latter is
247
+ # not.
248
+ @model_class.class_attribute :paper_trail_options
249
+ @model_class.paper_trail_options = options.dup
250
+
251
+ %i[ignore skip only].each do |k|
252
+ @model_class.paper_trail_options[k] = event_attribute_option(k)
253
+ end
254
+ @model_class.paper_trail_options[:meta] ||= {}
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PaperTrail
4
+ module Queries
5
+ module Versions
6
+ # For public API documentation, see `where_attribute_changes` in
7
+ # `paper_trail/version_concern.rb`.
8
+ # @api private
9
+ class WhereAttributeChanges
10
+ # - version_model_class - The class that VersionConcern was mixed into.
11
+ # - attribute - An attribute that changed. See the public API
12
+ # documentation for details.
13
+ # @api private
14
+ def initialize(version_model_class, attribute)
15
+ @version_model_class = version_model_class
16
+ @attribute = attribute
17
+ end
18
+
19
+ # @api private
20
+ def execute
21
+ if PaperTrail.config.object_changes_adapter.respond_to?(:where_attribute_changes)
22
+ return PaperTrail.config.object_changes_adapter.where_attribute_changes(
23
+ @version_model_class, @attribute
24
+ )
25
+ end
26
+ column_type = @version_model_class.columns_hash["object_changes"].type
27
+ case column_type
28
+ when :jsonb, :json
29
+ json
30
+ else
31
+ raise UnsupportedColumnType.new(
32
+ method: "where_attribute_changes",
33
+ expected: "json or jsonb",
34
+ actual: column_type
35
+ )
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ # @api private
42
+ def json
43
+ sql = "object_changes -> ? IS NOT NULL"
44
+
45
+ @version_model_class.where(sql, @attribute)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PaperTrail
4
+ module Queries
5
+ module Versions
6
+ # For public API documentation, see `where_object` in
7
+ # `paper_trail/version_concern.rb`.
8
+ # @api private
9
+ class WhereObject
10
+ # - version_model_class - The class that VersionConcern was mixed into.
11
+ # - attributes - A `Hash` of attributes and values. See the public API
12
+ # documentation for details.
13
+ # @api private
14
+ def initialize(version_model_class, attributes)
15
+ @version_model_class = version_model_class
16
+ @attributes = attributes
17
+ end
18
+
19
+ # @api private
20
+ def execute
21
+ column = @version_model_class.columns_hash["object"]
22
+ raise Error, "where_object requires an object column" unless column
23
+
24
+ case column.type
25
+ when :jsonb
26
+ jsonb
27
+ when :json
28
+ json
29
+ else
30
+ text
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ # @api private
37
+ def json
38
+ predicates = []
39
+ values = []
40
+ @attributes.each do |field, value|
41
+ predicates.push "object->>? = ?"
42
+ values.push(field, value.to_s)
43
+ end
44
+ sql = predicates.join(" and ")
45
+ @version_model_class.where(sql, *values)
46
+ end
47
+
48
+ # @api private
49
+ def jsonb
50
+ @version_model_class.where("object @> ?", @attributes.to_json)
51
+ end
52
+
53
+ # @api private
54
+ def text
55
+ arel_field = @version_model_class.arel_table[:object]
56
+ where_conditions = @attributes.map { |field, value|
57
+ ::PaperTrail.serializer.where_object_condition(arel_field, field, value)
58
+ }
59
+ where_conditions = where_conditions.reduce { |a, e| a.and(e) }
60
+ @version_model_class.where(where_conditions)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PaperTrail
4
+ module Queries
5
+ module Versions
6
+ # For public API documentation, see `where_object_changes` in
7
+ # `paper_trail/version_concern.rb`.
8
+ # @api private
9
+ class WhereObjectChanges
10
+ # - version_model_class - The class that VersionConcern was mixed into.
11
+ # - attributes - A `Hash` of attributes and values. See the public API
12
+ # documentation for details.
13
+ # @api private
14
+ def initialize(version_model_class, attributes)
15
+ @version_model_class = version_model_class
16
+
17
+ # Currently, this `deep_dup` is necessary because the `jsonb` branch
18
+ # modifies `@attributes`, and that would be a nasty surprise for
19
+ # consumers of this class.
20
+ # TODO: Stop modifying `@attributes`, then remove `deep_dup`.
21
+ @attributes = attributes.deep_dup
22
+ end
23
+
24
+ # @api private
25
+ def execute
26
+ if PaperTrail.config.object_changes_adapter.respond_to?(:where_object_changes)
27
+ return PaperTrail.config.object_changes_adapter.where_object_changes(
28
+ @version_model_class, @attributes
29
+ )
30
+ end
31
+ column_type = @version_model_class.columns_hash["object_changes"].type
32
+ case column_type
33
+ when :jsonb
34
+ jsonb
35
+ when :json
36
+ json
37
+ else
38
+ raise UnsupportedColumnType.new(
39
+ method: "where_object_changes",
40
+ expected: "json or jsonb",
41
+ actual: column_type
42
+ )
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ # @api private
49
+ def json
50
+ predicates = []
51
+ values = []
52
+ @attributes.each do |field, value|
53
+ predicates.push(
54
+ "((object_changes->>? ILIKE ?) OR (object_changes->>? ILIKE ?))"
55
+ )
56
+ values.push(field, "[#{value.to_json},%", field, "[%,#{value.to_json}]%")
57
+ end
58
+ sql = predicates.join(" and ")
59
+ @version_model_class.where(sql, *values)
60
+ end
61
+
62
+ # @api private
63
+ def jsonb
64
+ @attributes.each { |field, value| @attributes[field] = [value] }
65
+ @version_model_class.where("object_changes @> ?", @attributes.to_json)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PaperTrail
4
+ module Queries
5
+ module Versions
6
+ # For public API documentation, see `where_object_changes_from` in
7
+ # `paper_trail/version_concern.rb`.
8
+ # @api private
9
+ class WhereObjectChangesFrom
10
+ # - version_model_class - The class that VersionConcern was mixed into.
11
+ # - attributes - A `Hash` of attributes and values. See the public API
12
+ # documentation for details.
13
+ # @api private
14
+ def initialize(version_model_class, attributes)
15
+ @version_model_class = version_model_class
16
+ @attributes = attributes
17
+ end
18
+
19
+ # @api private
20
+ def execute
21
+ if PaperTrail.config.object_changes_adapter.respond_to?(:where_object_changes_from)
22
+ return PaperTrail.config.object_changes_adapter.where_object_changes_from(
23
+ @version_model_class, @attributes
24
+ )
25
+ end
26
+ column_type = @version_model_class.columns_hash["object_changes"].type
27
+ case column_type
28
+ when :jsonb, :json
29
+ json
30
+ else
31
+ raise UnsupportedColumnType.new(
32
+ method: "where_object_changes_from",
33
+ expected: "json or jsonb",
34
+ actual: column_type
35
+ )
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ # @api private
42
+ def json
43
+ predicates = []
44
+ values = []
45
+ @attributes.each do |field, value|
46
+ predicates.push(
47
+ "(object_changes->>? ILIKE ?)"
48
+ )
49
+ values.push(field, "[#{value.to_json},%")
50
+ end
51
+ sql = predicates.join(" and ")
52
+ @version_model_class.where(sql, *values)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PaperTrail
4
+ module Queries
5
+ module Versions
6
+ # For public API documentation, see `where_object_changes_to` in
7
+ # `paper_trail/version_concern.rb`.
8
+ # @api private
9
+ class WhereObjectChangesTo
10
+ # - version_model_class - The class that VersionConcern was mixed into.
11
+ # - attributes - A `Hash` of attributes and values. See the public API
12
+ # documentation for details.
13
+ # @api private
14
+ def initialize(version_model_class, attributes)
15
+ @version_model_class = version_model_class
16
+ @attributes = attributes
17
+ end
18
+
19
+ # @api private
20
+ def execute
21
+ if PaperTrail.config.object_changes_adapter.respond_to?(:where_object_changes_to)
22
+ return PaperTrail.config.object_changes_adapter.where_object_changes_to(
23
+ @version_model_class, @attributes
24
+ )
25
+ end
26
+ column_type = @version_model_class.columns_hash["object_changes"].type
27
+ case column_type
28
+ when :jsonb, :json
29
+ json
30
+ else
31
+ raise UnsupportedColumnType.new(
32
+ method: "where_object_changes_to",
33
+ expected: "json or jsonb",
34
+ actual: column_type
35
+ )
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ # @api private
42
+ def json
43
+ predicates = []
44
+ values = []
45
+ @attributes.each do |field, value|
46
+ predicates.push(
47
+ "(object_changes->>? ILIKE ?)"
48
+ )
49
+ values.push(field, "[%#{value.to_json}]")
50
+ end
51
+ sql = predicates.join(" and ")
52
+ @version_model_class.where(sql, *values)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PaperTrail
4
+ # Represents the history of a single record.
5
+ # @api private
6
+ class RecordHistory
7
+ # @param versions - ActiveRecord::Relation - All versions of the record.
8
+ # @param version_class - Class - Usually PaperTrail::Version,
9
+ # but it could also be a custom version class.
10
+ # @api private
11
+ def initialize(versions, version_class)
12
+ @versions = versions
13
+ @version_class = version_class
14
+ end
15
+
16
+ # Returns ordinal position of `version` in `sequence`.
17
+ # @api private
18
+ def index(version)
19
+ sequence.to_a.index(version)
20
+ end
21
+
22
+ private
23
+
24
+ # Returns `@versions` in chronological order.
25
+ # @api private
26
+ def sequence
27
+ if @version_class.primary_key_is_int?
28
+ @versions.select(primary_key).order(primary_key.asc)
29
+ else
30
+ @versions.
31
+ select([table[:created_at], primary_key]).
32
+ order(@version_class.timestamp_sort_order)
33
+ end
34
+ end
35
+
36
+ # @return - Arel::Attribute - Attribute representing the primary key
37
+ # of the version table. The column's data type is usually a serial
38
+ # integer (the rails convention) but not always.
39
+ # @api private
40
+ def primary_key
41
+ table[@version_class.primary_key]
42
+ end
43
+
44
+ # @return - Arel::Table - The version table, usually named `versions`, but
45
+ # not always.
46
+ # @api private
47
+ def table
48
+ @version_class.arel_table
49
+ end
50
+ end
51
+ end