hoardable 0.16.0 → 0.17.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: 8c41a6c69f62f7e2a99fefe00229a7244f5cd0dcb9ed3b0d243db9adf9cabd98
4
- data.tar.gz: 30dc9d7a551c29331a7736f7b825c0b5f9db83bf5c5cd537d5d2910908f683ff
3
+ metadata.gz: 888659d9c6655e69c72fd8cf5b10b3697d5a81f432a44c8fa39984a05f4b23d9
4
+ data.tar.gz: ba850c1bf2363dd965a6e7780435d4feaf2ad417f2712f5f4635398ad5e9913d
5
5
  SHA512:
6
- metadata.gz: ad46ae05e3241052089aaf432016b906f648051fae6405e2ce4a90c7f247942a09a011d2fc35e6558695814949ef37a0398d36baaa71500f2c31d33436a7eac7
7
- data.tar.gz: b3307392cdff1b14a37192cd1a004099c5d99d7dd0ce3d0f8fe230c1dac4b59697c4708f5859cb7b2b831f45f1a3a6489cdce2eaf464fef2d9e135bd902e4f26
6
+ metadata.gz: 851d039e113df11834b18bb69edf786ba1d91598e408a45fab6ae7bb65efbc37264e4b803b8c8335f6839784f964f20d29c4c94b02aa6b994a21f3fd346ec162
7
+ data.tar.gz: 022a7ada38d996f8116a7ab8ed3d671e29055a8c75cc4155789ea3be135d87f24625ab67311c22f3b89b172320a973cbf203586407c6788750443bec90b461be
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.17.0
2
+
3
+ - Much improved performance of setting `hoardable_id` for versions.
4
+
1
5
  ## 0.16.0
2
6
 
3
7
  - Rails 8 support introduced
data/README.md CHANGED
@@ -235,6 +235,21 @@ version.changes # => { "title"=> ["Title", "New Title"] }
235
235
  version.hoardable_operation # => "update"
236
236
  ```
237
237
 
238
+ ### Overriding the temporal range
239
+
240
+ When calculating the temporal range for a given version, the default upper bound is `Time.now.utc`.
241
+
242
+ You can, however, use the `Hoardable.travel_to` class method to specify a custom upper bound for the time range. This allows
243
+ you to specify the datetime that a particular change should be recorded at by passing a block:
244
+
245
+ ```ruby
246
+ Hoardable.travel_to(2.weeks.ago) do
247
+ post.destroy!
248
+ end
249
+ ```
250
+
251
+ Note: If the provided datetime pre-dates the calculated lower bound then an `InvalidTemporalUpperBoundError` will be raised.
252
+
238
253
  ### Model Callbacks
239
254
 
240
255
  Sometimes you might want to do something with a version after it gets inserted to the database. You
@@ -0,0 +1,7 @@
1
+ CREATE OR REPLACE FUNCTION <%= function_name %>() RETURNS trigger
2
+ LANGUAGE plpgsql AS
3
+ $$
4
+ BEGIN
5
+ NEW.hoardable_id = NEW.<%= primary_key %>;
6
+ RETURN NEW;
7
+ END;$$;
@@ -25,7 +25,7 @@ module Hoardable
25
25
 
26
26
  def create_functions
27
27
  Dir
28
- .glob(File.join(__dir__, "functions", "*.sql"))
28
+ .glob(File.join(__dir__, "install_functions", "*.sql"))
29
29
  .each do |file_path|
30
30
  file_name = file_path.match(%r{([^/]+)\.sql})[1]
31
31
  template file_path, "db/functions/#{file_name}_v01.sql"
@@ -36,7 +36,15 @@ module Hoardable
36
36
  end
37
37
  end
38
38
 
39
+ def create_function
40
+ template("../functions/set_hoardable_id.sql", "db/functions/#{function_name}_v01.sql")
41
+ end
42
+
39
43
  no_tasks do
44
+ def function_name
45
+ "hoardable_set_hoardable_id_from_#{primary_key}"
46
+ end
47
+
40
48
  def table_name
41
49
  class_name.singularize.constantize.table_name
42
50
  rescue StandardError
@@ -4,7 +4,6 @@ class InstallHoardable < ActiveRecord::Migration[<%= ActiveRecord::Migration.cur
4
4
  def change
5
5
  <% if postgres_version < 13 %>enable_extension :pgcrypto
6
6
  <% end %>create_function :hoardable_prevent_update_id
7
- create_function :hoardable_source_set_id
8
7
  create_function :hoardable_version_prevent_update
9
8
  create_enum :hoardable_operation, %w[update delete insert]
10
9
  end
@@ -6,7 +6,7 @@ class Create<%= class_name.singularize.delete(':') %>Versions < ActiveRecord::Mi
6
6
  add_index :<%= table_name %>, :hoardable_id
7
7
  create_table(
8
8
  :<%= singularized_table_name %>_versions,
9
- id: false,
9
+ id: false,
10
10
  options: 'INHERITS (<%= table_name %>)',
11
11
  ) do |t|
12
12
  t.jsonb :_data
@@ -25,6 +25,7 @@ class Create<%= class_name.singularize.delete(':') %>Versions < ActiveRecord::Mi
25
25
  :<%= singularized_table_name %>_versions_prevent_update,
26
26
  on: :<%= singularized_table_name %>_versions
27
27
  )
28
+ create_function :<%= function_name %>
28
29
  create_trigger :<%= table_name %>_set_hoardable_id, on: :<%= table_name %>
29
30
  create_trigger :<%= table_name %>_prevent_update_hoardable_id, on: :<%= table_name %>
30
31
  change_column_null :<%= table_name %>, :hoardable_id, false
@@ -1,3 +1,3 @@
1
1
  CREATE TRIGGER <%= table_name %>_set_hoardable_id
2
2
  BEFORE INSERT ON <%= table_name %> FOR EACH ROW
3
- EXECUTE PROCEDURE hoardable_source_set_id();
3
+ EXECUTE PROCEDURE <%= function_name %>();
@@ -93,7 +93,14 @@ module Hoardable
93
93
  end
94
94
 
95
95
  def initialize_temporal_range
96
- ((previous_temporal_tsrange_end || hoardable_source_epoch)..Time.now.utc)
96
+ upper_bound = Hoardable.instance_variable_get("@travel_to") || Time.now.utc
97
+ lower_bound = (previous_temporal_tsrange_end || hoardable_source_epoch)
98
+
99
+ if upper_bound < lower_bound
100
+ raise InvalidTemporalUpperBoundError.new(upper_bound, lower_bound)
101
+ end
102
+
103
+ (lower_bound..upper_bound)
97
104
  end
98
105
 
99
106
  def initialize_hoardable_data
@@ -81,6 +81,16 @@ module Hoardable
81
81
  @at = nil
82
82
  end
83
83
 
84
+ # Allows calling code to set the upper bound for the temporal range for recorded audits.
85
+ #
86
+ # @param datetime [DateTime] the datetime to temporally record versions at
87
+ def travel_to(datetime)
88
+ @travel_to = datetime
89
+ yield
90
+ ensure
91
+ @travel_to = nil
92
+ end
93
+
84
94
  # @!visibility private
85
95
  def logger
86
96
  @logger ||= ActiveSupport::TaggedLogging.new(Logger.new($stdout))
@@ -101,7 +111,7 @@ module Hoardable
101
111
  initializer "hoardable.schema_statements" do
102
112
  ActiveSupport.on_load(:active_record_postgresqladapter) do
103
113
  # We need to control the table dumping order of tables, so revert these to just +super+
104
- Fx::SchemaDumper::Trigger.module_eval("def tables(streams); super; end")
114
+ Fx::SchemaDumper.module_eval("def tables(streams); super; end")
105
115
 
106
116
  ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaDumper.prepend(SchemaDumper)
107
117
  ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements.prepend(SchemaStatements)
@@ -24,4 +24,14 @@ module Hoardable
24
24
  LOG
25
25
  end
26
26
  end
27
+
28
+ # An error to be raised when the provided temporal upper bound is before the calcualated lower bound.
29
+ class InvalidTemporalUpperBoundError < Error
30
+ def initialize(upper, lower)
31
+ super(<<~LOG)
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
27
37
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hoardable
4
- VERSION = "0.16.0"
4
+ VERSION = "0.17.0"
5
5
  end
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.16.0
4
+ version: 0.17.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: 2024-10-11 00:00:00.000000000 Z
11
+ date: 2024-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -58,7 +58,7 @@ dependencies:
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '0.8'
61
+ version: '0.9'
62
62
  - - "<"
63
63
  - !ruby/object:Gem::Version
64
64
  version: '1'
@@ -68,7 +68,7 @@ dependencies:
68
68
  requirements:
69
69
  - - ">="
70
70
  - !ruby/object:Gem::Version
71
- version: '0.8'
71
+ version: '0.9'
72
72
  - - "<"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '1'
@@ -106,9 +106,9 @@ files:
106
106
  - LICENSE.txt
107
107
  - README.md
108
108
  - Rakefile
109
- - lib/generators/hoardable/functions/hoardable_prevent_update_id.sql
110
- - lib/generators/hoardable/functions/hoardable_source_set_id.sql
111
- - lib/generators/hoardable/functions/hoardable_version_prevent_update.sql
109
+ - lib/generators/hoardable/functions/set_hoardable_id.sql
110
+ - lib/generators/hoardable/install_functions/hoardable_prevent_update_id.sql
111
+ - lib/generators/hoardable/install_functions/hoardable_version_prevent_update.sql
112
112
  - lib/generators/hoardable/install_generator.rb
113
113
  - lib/generators/hoardable/migration_generator.rb
114
114
  - lib/generators/hoardable/templates/install.rb.erb
@@ -1,18 +0,0 @@
1
- CREATE OR REPLACE FUNCTION hoardable_source_set_id() RETURNS trigger
2
- LANGUAGE plpgsql AS
3
- $$
4
- DECLARE
5
- _pk information_schema.constraint_column_usage.column_name%TYPE;
6
- _id _pk%TYPE;
7
- BEGIN
8
- SELECT c.column_name
9
- FROM information_schema.table_constraints t
10
- JOIN information_schema.constraint_column_usage c
11
- ON c.constraint_name = t.constraint_name
12
- WHERE c.table_name = TG_TABLE_NAME AND t.constraint_type = 'PRIMARY KEY'
13
- LIMIT 1
14
- INTO _pk;
15
- EXECUTE format('SELECT $1.%I', _pk) INTO _id USING NEW;
16
- NEW.hoardable_id = _id;
17
- RETURN NEW;
18
- END;$$;