hoardable 0.2.0 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c960d95a373942d9183464cc50b7c4213c25c7563fa9d920c81d2c325ea71705
4
- data.tar.gz: e7e0f289e60acd720538edc15584209ed3d30e08b21758d06884a5486f198ee0
3
+ metadata.gz: 50086ef99aac41454b28ab8bff2e8abf94d7870b371da0c706c477e0b296ffc3
4
+ data.tar.gz: 6e6d4ab40470bbfb93e23e96fdbb2d8b086878d24e55d499ac368523125e5397
5
5
  SHA512:
6
- metadata.gz: a83966223151922d24bb009ac50465723388ba91825e27cf933bb5e00370c270a0518ec828358f1109a040e2a9202cee7b37d7ea98e0387b30dc07a74f7eb851
7
- data.tar.gz: 6bc246f6664b61c5000ffa71b24c8ddd30c409eda87e790b0ea1bd9d47f46c4e85e0b5eb89736939a75018e272cdd5ac2ce1217c7c7e9272ddc4f96cc8cc33f4
6
+ metadata.gz: 747ac52845c950eb655cb7b0af22794dda49ed08e2b0f1aee472595fd2c63b1f886d4f516e686807607efe4946ca588792913ea92ec1c3152a44c23f8cd84487
7
+ data.tar.gz: 3460ccd66ebe6eed7cdb129bca6150696b82ad9f8613965e80b08fb458ac6e2b8b644e662036533f73f95f52b97a10bf50f2782f76d3fd6671f23f9c2b58df08
data/README.md CHANGED
@@ -69,7 +69,7 @@ Rails 7.
69
69
  ### Overview
70
70
 
71
71
  Once you include `Hoardable::Model` into a model, it will dynamically generate a "Version" subclass
72
- of that model. As we continue our example above, :
72
+ of that model. As we continue our example above:
73
73
 
74
74
  ```
75
75
  $ irb
@@ -146,7 +146,10 @@ choosing.
146
146
  One convenient way to assign contextual data to these is by defining a proc in an initializer, i.e.:
147
147
 
148
148
  ```ruby
149
+ # config/initiailzers/hoardable.rb
149
150
  Hoardable.whodunit = -> { Current.user&.id }
151
+
152
+ # somewhere in your app code
150
153
  Current.user = User.find(123)
151
154
  post.update!(status: 'live')
152
155
  post.versions.last.hoardable_whodunit # => 123
@@ -230,6 +233,7 @@ There are three configurable options currently:
230
233
  Hoardable.enabled # => default true
231
234
  Hoardable.version_updates # => default true
232
235
  Hoardable.save_trash # => default true
236
+ Hoardable.return_everything # => default false
233
237
  ```
234
238
 
235
239
  `Hoardable.enabled` controls whether versions will be ever be created.
@@ -239,6 +243,10 @@ Hoardable.save_trash # => default true
239
243
  `Hoardable.save_trash` controls whether to create versions upon record deletion. When this is set to
240
244
  `false`, all versions of a record will be deleted when the record is destroyed.
241
245
 
246
+ `Hoardable.return_everything` controls whether to include versions when doing queries for source
247
+ models. This is typically only useful to set around a block, as explained below in
248
+ [Relationships](#relationships).
249
+
242
250
  If you would like to temporarily set a config setting, you can use `Hoardable.with`:
243
251
 
244
252
  ```ruby
@@ -247,17 +255,26 @@ Hoardable.with(enabled: false) do
247
255
  end
248
256
  ```
249
257
 
250
- You can also configure these variables per `ActiveRecord` class as well using `hoardable_options`:
258
+ You can also configure these variables per `ActiveRecord` class as well using `hoardable_config`:
251
259
 
252
260
  ```ruby
253
261
  class Comment < ActiveRecord::Base
254
262
  include Hoardable::Model
255
- hoardable_options version_updates: false
263
+ hoardable_config version_updates: false
256
264
  end
257
265
  ```
258
266
 
259
- If either the model-level option or global option for a configuration variable is set to `false`,
260
- that behavior will be disabled.
267
+ If you want to temporarily set the `hoardable_config` for a specific model, you can use
268
+ `with_hoardable_config`:
269
+
270
+ ```ruby
271
+ Comment.with_hoardable_config(version_updates: true) do
272
+ comment.update!(text: "Edited")
273
+ end
274
+ ```
275
+
276
+ If a model-level option exists, it will use that. Otherwise, it will fall back to the global
277
+ `Hoardable` config.
261
278
 
262
279
  ### Relationships
263
280
 
@@ -267,17 +284,20 @@ features in this area, but here are a couple pointers.
267
284
  Sometimes you’ll have a record that belongs to a record that you’ll trash. Now the child record’s
268
285
  foreign key will point to the non-existent trashed version of the parent. If you would like this
269
286
  `belongs_to` relationship to always resolve to the parent as if it was not trashed, you can include
270
- the scope on the relationship definition:
287
+ the `include_versions` scope on the relationship definition:
271
288
 
272
289
  ```ruby
273
- belongs_to :parent, -> { include_versions }
290
+ class Comment
291
+ include Hoardable::Model
292
+ belongs_to :post, -> { include_versions } # `Post` also includes `Hoardable::Model`
293
+ end
274
294
  ```
275
295
 
276
296
  Sometimes you’ll trash something that `has_many :children, dependent: :destroy` and both the parent
277
297
  and child model classes include `Hoardable::Model`. Whenever a hoardable version is created in a
278
298
  database transaction, it will create or re-use a unique event UUID for that transaction and tag all
279
- versions created with it. That way, when you `untrash!` a parent object, you can find and `untrash!`
280
- the children like so:
299
+ versions created with it. That way, when you `untrash!` a record, you can find and `untrash!`
300
+ records that were trashed with it:
281
301
 
282
302
  ```ruby
283
303
  class Post < ActiveRecord::Base
@@ -295,20 +315,35 @@ class Post < ActiveRecord::Base
295
315
  end
296
316
  ```
297
317
 
318
+ If there are models that might be related to versions that are trashed or otherwise, and/or might
319
+ trashed themselves, you can bypass the inherited tables query handling altogether by using the
320
+ `return_everything` configuration variable in `Hoardable.with`:
321
+
322
+ ```ruby
323
+ post.destroy!
324
+
325
+ Hoardable.with(return_everything: true) do
326
+ post = Post.find(post.id) # returns the trashed post as if it was not
327
+ post.comments # returns the trashed comments as well
328
+ end
329
+
330
+ post.reload # raises ActiveRecord::RecordNotFound
331
+ ```
332
+
298
333
  ## Gem Comparison
299
334
 
300
- ### [`paper_trail`](https://github.com/paper-trail-gem/paper_trail)
335
+ ### [`paper_trail`](https://github.com/paper-trail-gem/paper_trail)
301
336
 
302
337
  `paper_trail` is maybe the most popular and fully featured gem in this space. It works for other
303
- database types than PostgeSQL and (by default) stores all versions of all versioned models in a
304
- single `versions` table. It stores changes in a `text`, `json`, or `jsonb` column. In order to
305
- efficiently query the `versions` table, a `jsonb` column should be used, which takes up a lot of
306
- space to index. Unless you customize your configuration, all `versions` for all models types are
307
- in the same table which is inefficient if you are only interested in querying versions of a single
308
- model. By contrast, `hoardable` stores versions in smaller, isolated and inherited tables with the
309
- same database columns as their parents, which are more efficient for querying as well as auditing
310
- for truncating and dropping. The concept of a `temporal` time-frame does not exist for a single
311
- version since there is only a `created_at` timestamp.
338
+ database types than PostgeSQL and (by default) stores all versions of all versioned models in a
339
+ single `versions` table. It stores changes in a `text`, `json`, or `jsonb` column. In order to
340
+ efficiently query the `versions` table, a `jsonb` column should be used, which takes up a lot of
341
+ space to index. Unless you customize your configuration, all `versions` for all models types are
342
+ in the same table which is inefficient if you are only interested in querying versions of a single
343
+ model. By contrast, `hoardable` stores versions in smaller, isolated and inherited tables with the
344
+ same database columns as their parents, which are more efficient for querying as well as auditing
345
+ for truncating and dropping. The concept of a `temporal` time-frame does not exist for a single
346
+ version since there is only a `created_at` timestamp.
312
347
 
313
348
  ### [`audited`](https://github.com/collectiveidea/audited)
314
349
 
@@ -7,7 +7,7 @@ module Hoardable
7
7
  DATA_KEYS = %i[meta whodunit note event_uuid].freeze
8
8
  # Symbols for use with setting {Hoardable} configuration. See {file:README.md#configuration
9
9
  # README} for more.
10
- CONFIG_KEYS = %i[enabled version_updates save_trash].freeze
10
+ CONFIG_KEYS = %i[enabled version_updates save_trash return_everything].freeze
11
11
 
12
12
  # @!visibility private
13
13
  VERSION_CLASS_SUFFIX = 'Version'
@@ -20,7 +20,7 @@ module Hoardable
20
20
 
21
21
  @context = {}
22
22
  @config = CONFIG_KEYS.to_h do |key|
23
- [key, true]
23
+ [key, key != :return_everything]
24
24
  end
25
25
 
26
26
  class << self
@@ -46,7 +46,7 @@ module Hoardable
46
46
 
47
47
  # This is a general use method for setting {DATA_KEYS} or {CONFIG_KEYS} around a scoped block.
48
48
  #
49
- # @param hash [Hash] Options and contextual data to set within a block
49
+ # @param hash [Hash] config and contextual data to set within a block
50
50
  def with(hash)
51
51
  current_config = @config
52
52
  current_context = @context
@@ -10,7 +10,7 @@ module Hoardable
10
10
 
11
11
  class_methods do
12
12
  # @!visibility private
13
- attr_reader :_hoardable_options
13
+ attr_reader :_hoardable_config
14
14
 
15
15
  # If called with a hash, this will set the model-level +Hoardable+ configuration variables. If
16
16
  # called without an argument it will return the computed +Hoardable+ configuration considering
@@ -19,16 +19,29 @@ module Hoardable
19
19
  # @param hash [Hash] The +Hoardable+ configuration for the model. Keys must be present in
20
20
  # {CONFIG_KEYS}
21
21
  # @return [Hash]
22
- def hoardable_options(hash = nil)
22
+ def hoardable_config(hash = nil)
23
23
  if hash
24
- @_hoardable_options = hash.slice(*Hoardable::CONFIG_KEYS)
24
+ @_hoardable_config = hash.slice(*Hoardable::CONFIG_KEYS)
25
25
  else
26
- @_hoardable_options ||= {}
26
+ @_hoardable_config ||= {}
27
27
  Hoardable::CONFIG_KEYS.to_h do |key|
28
- [key, Hoardable.send(key) != false && @_hoardable_options[key] != false]
28
+ [key, @_hoardable_config.key?(key) ? @_hoardable_config[key] : Hoardable.send(key)]
29
29
  end
30
30
  end
31
31
  end
32
+
33
+ # Set the model-level +Hoardable+ configuration variables around a block. The configuration
34
+ # will be reset to it’s previous value afterwards.
35
+ #
36
+ # @param hash [Hash] The +Hoardable+ configuration for the model. Keys must be present in
37
+ # {CONFIG_KEYS}
38
+ def with_hoardable_config(hash)
39
+ current_config = @_hoardable_config
40
+ @_hoardable_config = hash.slice(*Hoardable::CONFIG_KEYS)
41
+ yield
42
+ ensure
43
+ @_hoardable_config = current_config
44
+ end
32
45
  end
33
46
 
34
47
  included do
@@ -45,7 +45,7 @@ module Hoardable
45
45
  #
46
46
  # @return [Boolean]
47
47
  def trashed?
48
- versions.trashed.limit(1).order(_during: :desc).first&.send(:hoardable_source_attributes) == attributes
48
+ versions.trashed.limit(1).order(_during: :desc).first&.id == id
49
49
  end
50
50
 
51
51
  # Returns the +version+ at the supplied +datetime+ or +time+. It will return +self+ if there is
@@ -71,15 +71,15 @@ module Hoardable
71
71
  private
72
72
 
73
73
  def hoardable_callbacks_enabled
74
- self.class.hoardable_options[:enabled] && !self.class.name.end_with?(VERSION_CLASS_SUFFIX)
74
+ self.class.hoardable_config[:enabled] && !self.class.name.end_with?(VERSION_CLASS_SUFFIX)
75
75
  end
76
76
 
77
77
  def hoardable_save_trash
78
- self.class.hoardable_options[:save_trash]
78
+ self.class.hoardable_config[:save_trash]
79
79
  end
80
80
 
81
81
  def hoardable_version_updates
82
- self.class.hoardable_options[:version_updates]
82
+ self.class.hoardable_config[:version_updates]
83
83
  end
84
84
 
85
85
  def insert_hoardable_version_on_update(&block)
@@ -17,9 +17,16 @@ module Hoardable
17
17
  # @!visibility private
18
18
  attr_writer :tableoid
19
19
 
20
- # By default, {Hoardable} only returns instances of the parent table, and not the +versions+
21
- # in the inherited table.
22
- default_scope { where(TABLEOID_AREL_CONDITIONS.call(arel_table, :eq)) }
20
+ # By default {Hoardable} only returns instances of the parent table, and not the +versions+ in
21
+ # the inherited table. This can be bypassed by using the {.include_versions} scope or wrapping
22
+ # the code in a `Hoardable.with(return_everything: true)` block.
23
+ default_scope do
24
+ if hoardable_config[:return_everything]
25
+ where(nil)
26
+ else
27
+ where(TABLEOID_AREL_CONDITIONS.call(arel_table, :eq))
28
+ end
29
+ end
23
30
 
24
31
  # @!scope class
25
32
  # @!method include_versions
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hoardable
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
data/sig/hoardable.rbs CHANGED
@@ -1,7 +1,7 @@
1
1
  module Hoardable
2
2
  VERSION: String
3
3
  DATA_KEYS: [:meta, :whodunit, :note, :event_uuid]
4
- CONFIG_KEYS: [:enabled, :version_updates, :save_trash]
4
+ CONFIG_KEYS: [:enabled, :version_updates, :save_trash, :return_everything]
5
5
  VERSION_CLASS_SUFFIX: String
6
6
  VERSION_TABLE_SUFFIX: String
7
7
  DURING_QUERY: String
@@ -71,8 +71,8 @@ module Hoardable
71
71
  include VersionModel
72
72
  include SourceModel
73
73
 
74
- attr_reader _hoardable_options: Hash[untyped, untyped]
75
- def hoardable_options: (?nil hash) -> untyped
74
+ def hoardable_config: (?nil hash) -> untyped
75
+ def with_hoardable_config: (untyped hash) -> untyped
76
76
  end
77
77
 
78
78
  class MigrationGenerator
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hoardable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - justin talbott
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-08 00:00:00.000000000 Z
11
+ date: 2022-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord