hoardable 0.19.0 → 0.19.3
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 +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile +5 -0
- data/lib/hoardable/database_client.rb +5 -6
- data/lib/hoardable/engine.rb +34 -16
- data/lib/hoardable/error.rb +18 -9
- data/lib/hoardable/model.rb +13 -10
- data/lib/hoardable/schema_dumper.rb +1 -0
- data/lib/hoardable/scopes.rb +2 -2
- data/lib/hoardable/version.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 27747103c387757c5faf3cf3771651d221d67b8367d5b6f6623a34c43b3afe9d
|
|
4
|
+
data.tar.gz: 4abd9206358508019a69273c33fe9d772ad28b9ea4f76f85f499315b17bd99c2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a771a19b506f170a17fd672219a4899dcbfebc55e9ab2422a2d22198d0efd6c13667e5fbb2c69e1da724222bb9f9923fc4263f7b3ae14b3e260c62cc22eb42fd
|
|
7
|
+
data.tar.gz: c8eab3064758767b33f46943f0e09544e096545ad3f436c3b43e237d5be6e11589bc7840241561ddd04f860a1371656285badcd3a890cc003244829d6abf4010
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## 0.19.3
|
|
2
|
+
|
|
3
|
+
- Support providing `event_uuid` in `with`.
|
|
4
|
+
|
|
5
|
+
## 0.19.2
|
|
6
|
+
|
|
7
|
+
- Consult `inheritance_column` when constructing default scope
|
|
8
|
+
|
|
9
|
+
## 0.19.1
|
|
10
|
+
|
|
11
|
+
- Thread-safety support added for `with_hoardable_config`.
|
|
12
|
+
|
|
1
13
|
## 0.19.0
|
|
2
14
|
|
|
3
15
|
- Ensure that stateful Hoardable class methods `with`, `travel_to` and `at` are thread-safe.
|
data/Gemfile
CHANGED
|
@@ -19,7 +19,7 @@ module Hoardable
|
|
|
19
19
|
returning: source_primary_key.to_sym
|
|
20
20
|
)
|
|
21
21
|
version_id = version[0][source_primary_key]
|
|
22
|
-
source_record.instance_variable_set(
|
|
22
|
+
source_record.instance_variable_set(:@hoardable_version, version_class.find(version_id))
|
|
23
23
|
source_record.run_callbacks(:versioned, &block)
|
|
24
24
|
end
|
|
25
25
|
|
|
@@ -28,9 +28,8 @@ module Hoardable
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def find_or_initialize_hoardable_event_uuid
|
|
31
|
-
Thread.current[:hoardable_event_uuid] ||=
|
|
32
|
-
|
|
33
|
-
)
|
|
31
|
+
Thread.current[:hoardable_event_uuid] ||= Thread.current[:contextual_event_uuid] ||
|
|
32
|
+
SecureRandom.uuid
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
def initialize_version_attributes(operation)
|
|
@@ -94,7 +93,7 @@ module Hoardable
|
|
|
94
93
|
|
|
95
94
|
def initialize_temporal_range
|
|
96
95
|
upper_bound = Thread.current[:hoardable_travel_to] || Time.now.utc
|
|
97
|
-
lower_bound =
|
|
96
|
+
lower_bound = previous_temporal_tsrange_end || hoardable_source_epoch
|
|
98
97
|
|
|
99
98
|
if upper_bound < lower_bound
|
|
100
99
|
raise InvalidTemporalUpperBoundError.new(upper_bound, lower_bound)
|
|
@@ -114,7 +113,7 @@ module Hoardable
|
|
|
114
113
|
end
|
|
115
114
|
|
|
116
115
|
def unset_hoardable_version_and_event_uuid
|
|
117
|
-
source_record.instance_variable_set(
|
|
116
|
+
source_record.instance_variable_set(:@hoardable_version, nil)
|
|
118
117
|
return if source_record.class.connection.transaction_open?
|
|
119
118
|
|
|
120
119
|
Thread.current[:hoardable_event_uuid] = nil
|
data/lib/hoardable/engine.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Hoardable
|
|
|
6
6
|
|
|
7
7
|
# Symbols for use with setting contextual data, when creating versions. See
|
|
8
8
|
# {file:README.md#tracking-contextual-data README} for more.
|
|
9
|
-
DATA_KEYS = %i[meta whodunit
|
|
9
|
+
DATA_KEYS = %i[meta whodunit].freeze
|
|
10
10
|
|
|
11
11
|
# Symbols for use with setting {Hoardable} configuration. See {file:README.md#configuration
|
|
12
12
|
# README} for more.
|
|
@@ -44,21 +44,15 @@ module Hoardable
|
|
|
44
44
|
|
|
45
45
|
class << self
|
|
46
46
|
CONFIG_KEYS.each do |key|
|
|
47
|
-
define_method(key)
|
|
48
|
-
local_config = Thread.current[:hoardable_config] || @config
|
|
49
|
-
local_config[key]
|
|
50
|
-
end
|
|
47
|
+
define_method(key) { hoardable_config[key] }
|
|
51
48
|
|
|
52
|
-
define_method("#{key}=") { |value| @config[key] = value }
|
|
49
|
+
define_method(:"#{key}=") { |value| @config[key] = value }
|
|
53
50
|
end
|
|
54
51
|
|
|
55
52
|
DATA_KEYS.each do |key|
|
|
56
|
-
define_method(key)
|
|
57
|
-
local_context = Thread.current[:hoardable_context] || @context
|
|
58
|
-
local_context[key]
|
|
59
|
-
end
|
|
53
|
+
define_method(key) { hoardable_context[key] }
|
|
60
54
|
|
|
61
|
-
define_method("#{key}=") { |value| @context[key] = value }
|
|
55
|
+
define_method(:"#{key}=") { |value| @context[key] = value }
|
|
62
56
|
end
|
|
63
57
|
|
|
64
58
|
# This is a general use method for setting {file:README.md#tracking-contextual-data Contextual
|
|
@@ -67,12 +61,36 @@ module Hoardable
|
|
|
67
61
|
# @param hash [Hash] config and contextual data to set within a block
|
|
68
62
|
def with(hash)
|
|
69
63
|
thread = Thread.current
|
|
70
|
-
thread[:hoardable_config]
|
|
71
|
-
thread[:hoardable_context]
|
|
64
|
+
current_thread_config = thread[:hoardable_config]
|
|
65
|
+
current_thread_context = thread[:hoardable_context]
|
|
66
|
+
|
|
67
|
+
if hash.include?(:event_uuid)
|
|
68
|
+
contextual_event_uuid = hash[:event_uuid]
|
|
69
|
+
unless valid_event_uuid?(contextual_event_uuid)
|
|
70
|
+
raise InvalidEventUUID, contextual_event_uuid
|
|
71
|
+
end
|
|
72
|
+
thread[:contextual_event_uuid] = contextual_event_uuid
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
thread[:hoardable_config] = hoardable_config.merge(hash.slice(*CONFIG_KEYS))
|
|
76
|
+
thread[:hoardable_context] = hoardable_context.merge(hash.slice(*DATA_KEYS))
|
|
72
77
|
yield
|
|
73
78
|
ensure
|
|
74
|
-
thread[:hoardable_config] =
|
|
75
|
-
thread[:hoardable_context] =
|
|
79
|
+
thread[:hoardable_config] = current_thread_config
|
|
80
|
+
thread[:hoardable_context] = current_thread_context
|
|
81
|
+
thread[:contextual_event_uuid] = nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private def hoardable_config
|
|
85
|
+
@config.merge(Thread.current[:hoardable_config] ||= {})
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private def valid_event_uuid?(value)
|
|
89
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.match?(value.to_s.downcase)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private def hoardable_context
|
|
93
|
+
@context.merge(Thread.current[:hoardable_context] ||= {})
|
|
76
94
|
end
|
|
77
95
|
|
|
78
96
|
# Allows performing a query for record states at a certain time. Returned {SourceModel}
|
|
@@ -118,7 +136,7 @@ module Hoardable
|
|
|
118
136
|
initializer "hoardable.schema_statements" do
|
|
119
137
|
ActiveSupport.on_load(:active_record_postgresqladapter) do
|
|
120
138
|
# We need to control the table dumping order of tables, so revert these to just +super+
|
|
121
|
-
Fx::SchemaDumper.module_eval("def tables(streams); super; end")
|
|
139
|
+
Fx::SchemaDumper.module_eval("def tables(streams); super; end", __FILE__, __LINE__)
|
|
122
140
|
|
|
123
141
|
ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaDumper.prepend(SchemaDumper)
|
|
124
142
|
ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements.prepend(SchemaStatements)
|
data/lib/hoardable/error.rb
CHANGED
|
@@ -9,9 +9,9 @@ module Hoardable
|
|
|
9
9
|
class CreatedAtColumnMissingError < Error
|
|
10
10
|
def initialize(source_table_name)
|
|
11
11
|
super(<<~LOG)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
'#{source_table_name}' does not have a 'created_at' column, so the start of the first
|
|
13
|
+
version’s temporal period cannot be known. Add a 'created_at' column to '#{source_table_name}'.
|
|
14
|
+
LOG
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -19,9 +19,9 @@ module Hoardable
|
|
|
19
19
|
class UpdatedAtColumnMissingError < Error
|
|
20
20
|
def initialize(source_table_name)
|
|
21
21
|
super(<<~LOG)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
'#{source_table_name}' does not have an 'updated_at' column, so Hoardable cannot look up
|
|
23
|
+
associated record versions with it. Add an 'updated_at' column to '#{source_table_name}'.
|
|
24
|
+
LOG
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -29,9 +29,18 @@ module Hoardable
|
|
|
29
29
|
class InvalidTemporalUpperBoundError < Error
|
|
30
30
|
def initialize(upper, lower)
|
|
31
31
|
super(<<~LOG)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
'The supplied value to `Hoardable.travel_to` (#{upper}) is before the calculated lower bound (#{lower}).
|
|
33
|
+
You must provide a datetime > the lower bound.
|
|
34
|
+
LOG
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# An error to be raised when an invalid (non-UUID) value is provided as an event_uuid
|
|
39
|
+
class InvalidEventUUID < Error
|
|
40
|
+
def initialize(value)
|
|
41
|
+
super(<<~LOG)
|
|
42
|
+
'The supplied 'event_uuid' value must be a valid UUID'
|
|
43
|
+
LOG
|
|
35
44
|
end
|
|
36
45
|
end
|
|
37
46
|
end
|
data/lib/hoardable/model.rb
CHANGED
|
@@ -9,9 +9,6 @@ module Hoardable
|
|
|
9
9
|
extend ActiveSupport::Concern
|
|
10
10
|
|
|
11
11
|
class_methods do
|
|
12
|
-
# @!visibility private
|
|
13
|
-
attr_reader :_hoardable_config
|
|
14
|
-
|
|
15
12
|
# If called with a hash, this will set the model-level +Hoardable+ configuration variables. If
|
|
16
13
|
# called without an argument it will return the computed +Hoardable+ configuration considering
|
|
17
14
|
# both model-level and global values.
|
|
@@ -23,10 +20,7 @@ module Hoardable
|
|
|
23
20
|
if hash
|
|
24
21
|
@_hoardable_config = hash.slice(*CONFIG_KEYS)
|
|
25
22
|
else
|
|
26
|
-
|
|
27
|
-
CONFIG_KEYS.to_h do |key|
|
|
28
|
-
[key, @_hoardable_config.key?(key) ? @_hoardable_config[key] : Hoardable.send(key)]
|
|
29
|
-
end
|
|
23
|
+
CONFIG_KEYS.to_h { |key| [key, _hoardable_config.fetch(key) { Hoardable.send(key) }] }
|
|
30
24
|
end
|
|
31
25
|
end
|
|
32
26
|
|
|
@@ -36,11 +30,20 @@ module Hoardable
|
|
|
36
30
|
# @param hash [Hash] The +Hoardable+ configuration for the model. Keys must be present in
|
|
37
31
|
# {CONFIG_KEYS}
|
|
38
32
|
def with_hoardable_config(hash)
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
thread = Thread.current
|
|
34
|
+
current_thread_config = thread[hoardable_current_config_key]
|
|
35
|
+
thread[hoardable_current_config_key] = _hoardable_config.merge(hash.slice(*CONFIG_KEYS))
|
|
41
36
|
yield
|
|
42
37
|
ensure
|
|
43
|
-
|
|
38
|
+
thread[hoardable_current_config_key] = current_thread_config
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private def _hoardable_config
|
|
42
|
+
(@_hoardable_config ||= {}).merge(Thread.current[hoardable_current_config_key] ||= {})
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private def hoardable_current_config_key
|
|
46
|
+
"hoardable_#{name}_config".to_sym
|
|
44
47
|
end
|
|
45
48
|
end
|
|
46
49
|
|
data/lib/hoardable/scopes.rb
CHANGED
|
@@ -20,9 +20,9 @@ module Hoardable
|
|
|
20
20
|
exclude_versions
|
|
21
21
|
end
|
|
22
22
|
)
|
|
23
|
-
next scope unless klass == version_class &&
|
|
23
|
+
next scope unless klass == version_class && superclass.inheritance_column.in?(column_names)
|
|
24
24
|
|
|
25
|
-
scope.where(
|
|
25
|
+
scope.where(superclass.inheritance_column => superclass.sti_name)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
# @!scope class
|
data/lib/hoardable/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hoardable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.19.
|
|
4
|
+
version: 0.19.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- justin talbott
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
10
|
+
date: 2025-11-10 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activerecord
|
|
@@ -162,7 +161,6 @@ metadata:
|
|
|
162
161
|
homepage_uri: https://github.com/waymondo/hoardable
|
|
163
162
|
source_code_uri: https://github.com/waymondo/hoardable
|
|
164
163
|
rubygems_mfa_required: 'true'
|
|
165
|
-
post_install_message:
|
|
166
164
|
rdoc_options: []
|
|
167
165
|
require_paths:
|
|
168
166
|
- lib
|
|
@@ -177,8 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
177
175
|
- !ruby/object:Gem::Version
|
|
178
176
|
version: '0'
|
|
179
177
|
requirements: []
|
|
180
|
-
rubygems_version: 3.
|
|
181
|
-
signing_key:
|
|
178
|
+
rubygems_version: 3.6.2
|
|
182
179
|
specification_version: 4
|
|
183
180
|
summary: An ActiveRecord extension for versioning and soft-deletion of records in
|
|
184
181
|
Postgres
|