hoardable 0.17.0 → 0.18.2

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: 888659d9c6655e69c72fd8cf5b10b3697d5a81f432a44c8fa39984a05f4b23d9
4
- data.tar.gz: ba850c1bf2363dd965a6e7780435d4feaf2ad417f2712f5f4635398ad5e9913d
3
+ metadata.gz: fa8fcbadc193fbfcbdb4efa5f1030c2ff5a6be1da19b672136ca0ce5a4bfd846
4
+ data.tar.gz: 57b7f6fcbe331e181be56a4e8d284bed7ba322c9cb42280917a684e99ae53c0f
5
5
  SHA512:
6
- metadata.gz: 851d039e113df11834b18bb69edf786ba1d91598e408a45fab6ae7bb65efbc37264e4b803b8c8335f6839784f964f20d29c4c94b02aa6b994a21f3fd346ec162
7
- data.tar.gz: 022a7ada38d996f8116a7ab8ed3d671e29055a8c75cc4155789ea3be135d87f24625ab67311c22f3b89b172320a973cbf203586407c6788750443bec90b461be
6
+ metadata.gz: f4adc32f25af165fc80a53b0982b392dc4878ff3b6afcf1f9f892d75acac859c3b8bf1d9a292e9578da25926b349e380e92dd2d06e8bcb683239e0a7b4ddb95e
7
+ data.tar.gz: a076911d80e94a764992716188f35dfe5893662e908d40d7f2b7c48305d3188554a494f5c0fd6d598161a16b52abd53a392cf85e29d927535624d25de3ae3b2a
data/README.md CHANGED
@@ -41,7 +41,6 @@ Include `Hoardable::Model` into an ActiveRecord model you would like to hoard ve
41
41
  ```ruby
42
42
  class Post < ActiveRecord::Base
43
43
  include Hoardable::Model
44
- ...
45
44
  end
46
45
  ```
47
46
 
@@ -328,6 +327,14 @@ end
328
327
 
329
328
  Model-level configuration overrides global configuration.
330
329
 
330
+ ### Single Table Inheritance
331
+
332
+ Hoardable works for [Single Table
333
+ Inheritance](https://guides.rubyonrails.org/association_basics.html#single-table-inheritance-sti). You
334
+ will need to include `Hoardable::Model` in each child model you'd like to version, as that is what
335
+ generates the model's version class. The migration generator only needs to be run for the parent
336
+ model, as the versions will similarly be stored in a single table.
337
+
331
338
  ## Relationships
332
339
 
333
340
  ### `belongs_to`
@@ -45,21 +45,24 @@ module Hoardable
45
45
  "hoardable_set_hoardable_id_from_#{primary_key}"
46
46
  end
47
47
 
48
+ def klass
49
+ @klass ||= class_name.singularize.constantize
50
+ end
51
+
48
52
  def table_name
49
- class_name.singularize.constantize.table_name
53
+ klass.table_name
50
54
  rescue StandardError
51
55
  super
52
56
  end
53
57
 
54
58
  def foreign_key_type
55
- options[:foreign_key_type] ||
56
- class_name.singularize.constantize.columns.find { |col| col.name == primary_key }.sql_type
59
+ options[:foreign_key_type] || klass.columns.find { |col| col.name == primary_key }.sql_type
57
60
  rescue StandardError
58
61
  "bigint"
59
62
  end
60
63
 
61
64
  def primary_key
62
- options[:primary_key] || class_name.singularize.constantize.primary_key
65
+ options[:primary_key] || klass.primary_key
63
66
  rescue StandardError
64
67
  "id"
65
68
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Create<%= class_name.singularize.delete(':') %>Versions < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
3
+ class Create<%= singularized_table_name.classify %>Versions < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
4
4
  def change
5
5
  add_column :<%= table_name %>, :hoardable_id, :<%= foreign_key_type %>
6
6
  add_index :<%= table_name %>, :hoardable_id
@@ -0,0 +1,17 @@
1
+ module Hoardable
2
+ # Monkey-patches an internal Arel method to ensure that bulk UPDATE's always operate
3
+ # directly on the root table by injecting the ONLY keyword.
4
+ module ArelCrud
5
+ def compile_update(*args)
6
+ um = super(*args)
7
+
8
+ if source.left.instance_variable_get(:@klass).in?(Hoardable::REGISTRY)
9
+ return um.table(Arel.sql("ONLY #{source.left.name}"))
10
+ end
11
+
12
+ um
13
+ end
14
+ end
15
+ end
16
+
17
+ Arel::SelectManager.prepend Hoardable::ArelCrud
@@ -26,16 +26,21 @@ module Hoardable
26
26
  class_methods do
27
27
  def has_many(*args, &block)
28
28
  options = args.extract_options!
29
- options[:extend] = Array(options[:extend]).push(HasManyExtension) if options.delete(
30
- :hoardable
31
- )
29
+ hoardable_option = options.delete(:hoardable)
30
+ options[:extend] = Array(options[:extend]).push(HasManyExtension) if hoardable_option
31
+
32
32
  super(*args, **options, &block)
33
+ return unless hoardable_option
33
34
 
34
35
  # This hack is needed to force Rails to not use any existing method cache so that the
35
- # {HasManyExtension} scope is always used.
36
+ # {HasManyExtension} scope is always used when using {Hoardable.at}.
36
37
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
37
38
  def #{args.first}
38
- super.extending
39
+ if Hoardable.instance_variable_get("@at")
40
+ super.extending
41
+ else
42
+ super
43
+ end
39
44
  end
40
45
  RUBY
41
46
  end
@@ -50,12 +50,14 @@ module Hoardable
50
50
  define_model_callbacks :versioned, only: :after
51
51
  define_model_callbacks :reverted, only: :after
52
52
  define_model_callbacks :untrashed, only: :after
53
+ end
53
54
 
55
+ def self.included(base)
54
56
  TracePoint
55
57
  .new(:end) do |trace|
56
- next unless self == trace.self
58
+ next unless base == trace.self
57
59
 
58
- full_version_class_name = "#{name}#{VERSION_CLASS_SUFFIX}"
60
+ full_version_class_name = "#{base.name}#{VERSION_CLASS_SUFFIX}"
59
61
  if (namespace_match = full_version_class_name.match(/(.*)::(.*)/))
60
62
  object_namespace = namespace_match[1].constantize
61
63
  version_class_name = namespace_match[2]
@@ -64,10 +66,10 @@ module Hoardable
64
66
  version_class_name = full_version_class_name
65
67
  end
66
68
  unless Object.const_defined?(full_version_class_name)
67
- object_namespace.const_set(version_class_name, Class.new(self) { include VersionModel })
69
+ object_namespace.const_set(version_class_name, Class.new(base) { include VersionModel })
68
70
  end
69
- include SourceModel
70
- REGISTRY.add(self)
71
+ base.class_eval { include SourceModel }
72
+ REGISTRY.add(base)
71
73
 
72
74
  trace.disable
73
75
  end
@@ -9,13 +9,20 @@ module Hoardable
9
9
  included do
10
10
  # By default {Hoardable} only returns instances of the parent table, and not the +versions+ in
11
11
  # the inherited table. This can be bypassed by using the {.include_versions} scope or wrapping
12
- # the code in a `Hoardable.at(datetime)` block.
12
+ # the code in a `Hoardable.at(datetime)` block. When this is a version class that is an STI
13
+ # model, also scope to them.
13
14
  default_scope do
14
- if (hoardable_at = Hoardable.instance_variable_get("@at"))
15
- at(hoardable_at)
16
- else
17
- exclude_versions
18
- end
15
+ scope =
16
+ (
17
+ if (hoardable_at = Hoardable.instance_variable_get("@at"))
18
+ at(hoardable_at)
19
+ else
20
+ exclude_versions
21
+ end
22
+ )
23
+ next scope unless klass == version_class && "type".in?(column_names)
24
+
25
+ scope.where(type: superclass.sti_name)
19
26
  end
20
27
 
21
28
  # @!scope class
@@ -40,20 +40,24 @@ module Hoardable
40
40
  end
41
41
 
42
42
  before_destroy(if: HOARDABLE_CALLBACKS_ENABLED, unless: HOARDABLE_SAVE_TRASH) do
43
- versions.delete_all
43
+ versions.extending.delete_all
44
44
  end
45
45
 
46
46
  after_commit { hoardable_client.unset_hoardable_version_and_event_uuid }
47
+ end
47
48
 
48
- # Returns all +versions+ in ascending order of their temporal timeframes.
49
- has_many(
50
- :versions,
51
- -> { order("UPPER(_during) ASC") },
52
- dependent: nil,
53
- class_name: version_class.to_s,
54
- inverse_of: :hoardable_source,
55
- foreign_key: :hoardable_id
56
- )
49
+ def self.included(base)
50
+ base.class_eval do
51
+ # Returns all +versions+ in ascending order of their temporal timeframes.
52
+ has_many(
53
+ :versions,
54
+ -> { order("UPPER(_during) ASC") },
55
+ dependent: nil,
56
+ class_name: version_class.to_s,
57
+ inverse_of: :hoardable_source,
58
+ foreign_key: :hoardable_id
59
+ )
60
+ end
57
61
  end
58
62
 
59
63
  # Returns a boolean of whether the record is actually a trashed +version+ cast as an instance of the
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hoardable
4
- VERSION = "0.17.0"
4
+ VERSION = "0.18.2"
5
5
  end
@@ -24,6 +24,9 @@ module Hoardable
24
24
  class_name: superclass.model_name
25
25
  )
26
26
 
27
+ # disable STI on versions tables
28
+ self.inheritance_column = :_
29
+
27
30
  self.table_name = "#{table_name.singularize}#{VERSION_TABLE_SUFFIX}"
28
31
 
29
32
  alias_method :readonly?, :persisted?
data/lib/hoardable.rb CHANGED
@@ -4,6 +4,7 @@ require "active_record"
4
4
  require "fx"
5
5
  require_relative "hoardable/version"
6
6
  require_relative "hoardable/arel_visitors"
7
+ require_relative "hoardable/arel_crud"
7
8
  require_relative "hoardable/schema_statements"
8
9
  require_relative "hoardable/schema_dumper"
9
10
  require_relative "hoardable/engine"
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.17.0
4
+ version: 0.18.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - justin talbott
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-19 00:00:00.000000000 Z
11
+ date: 2025-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '7'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '9'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,6 +27,9 @@ dependencies:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: '7'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '9'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: activesupport
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -31,6 +37,9 @@ dependencies:
31
37
  - - ">="
32
38
  - !ruby/object:Gem::Version
33
39
  version: '7'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '9'
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -38,6 +47,9 @@ dependencies:
38
47
  - - ">="
39
48
  - !ruby/object:Gem::Version
40
49
  version: '7'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '9'
41
53
  - !ruby/object:Gem::Dependency
42
54
  name: railties
43
55
  requirement: !ruby/object:Gem::Requirement
@@ -45,6 +57,9 @@ dependencies:
45
57
  - - ">="
46
58
  - !ruby/object:Gem::Version
47
59
  version: '7'
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: '9'
48
63
  type: :runtime
49
64
  prerelease: false
50
65
  version_requirements: !ruby/object:Gem::Requirement
@@ -52,6 +67,9 @@ dependencies:
52
67
  - - ">="
53
68
  - !ruby/object:Gem::Version
54
69
  version: '7'
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: '9'
55
73
  - !ruby/object:Gem::Dependency
56
74
  name: fx
57
75
  requirement: !ruby/object:Gem::Requirement
@@ -100,7 +118,6 @@ extensions: []
100
118
  extra_rdoc_files: []
101
119
  files:
102
120
  - ".streerc"
103
- - ".tool-versions"
104
121
  - CHANGELOG.md
105
122
  - Gemfile
106
123
  - LICENSE.txt
@@ -117,6 +134,7 @@ files:
117
134
  - lib/generators/hoardable/triggers/set_hoardable_id.sql
118
135
  - lib/generators/hoardable/triggers/versions_prevent_update.sql
119
136
  - lib/hoardable.rb
137
+ - lib/hoardable/arel_crud.rb
120
138
  - lib/hoardable/arel_visitors.rb
121
139
  - lib/hoardable/associations.rb
122
140
  - lib/hoardable/belongs_to.rb
@@ -159,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
177
  - !ruby/object:Gem::Version
160
178
  version: '0'
161
179
  requirements: []
162
- rubygems_version: 3.5.6
180
+ rubygems_version: 3.5.16
163
181
  signing_key:
164
182
  specification_version: 4
165
183
  summary: An ActiveRecord extension for versioning and soft-deletion of records in
data/.tool-versions DELETED
@@ -1,2 +0,0 @@
1
- ruby 3.3.0
2
- postgres 16.1