waldit 0.0.5 → 0.0.6

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: 8b76edf8a202620aff6e09391009e6c00ae0f26a404d1b81741c5cd3e339db66
4
- data.tar.gz: f0c7582d6af476ecf536aa4e96846eea620b8c3bd5c215c240d9e68056ade643
3
+ metadata.gz: e8e8ecb8b8fc2c3c4b855fb06b204d858b7cfbf24f12dc016b4c3f5ca10849a2
4
+ data.tar.gz: b72218c4df4b396e497f1aa9d96fd159305fabb7faf0d481392044536da5141a
5
5
  SHA512:
6
- metadata.gz: 5aee8ef8ff8c9f0b6fc636b866a9fe72a08c1ba98e507df1b7d3771339130808c04c9fb32345a07a12416967d386be92bdfe3bfd1f3215dc723f337baf06278b
7
- data.tar.gz: e5f139662394131f2bfbe1af5ac3df85fa7b6202756ec67c02f0e679d11c78e2a62ecdb3a5bb188fa20a25ddee23699824266831f86b09e3284c0ad2584e9d6b
6
+ metadata.gz: 5471e11fa41cb7c3576dba2e0c1095ee3b2a7b7fd4eda88cd46e10523cf54ecdcda5a2d3470fdb9e97f3aebc066ce84bba7aa63be8507a0f0e37927b6604520f
7
+ data.tar.gz: 11dd782e95115cb77e8df0bed87f4dd8422454f5ef6ce84c35b9fe39af931c9855b37b07685cb3833ace964757c7d81b3d64a55a23330b52177ada7b60dd7ea8
data/lib/waldit/record.rb CHANGED
@@ -2,8 +2,22 @@
2
2
 
3
3
  module Waldit
4
4
  module Record
5
+ def new
6
+ return self[:new] if self[:new]
7
+
8
+ (self[:diff] || {}).transform_values { |_old, new| new }
9
+ end
10
+
11
+ def old
12
+ return self[:old] if self[:old]
13
+
14
+ (self[:diff] || {}).transform_values { |old, _new| old }
15
+ end
16
+
5
17
  def diff
6
- (old.keys | new.keys).reduce({}.with_indifferent_access) do |diff, key|
18
+ return self[:diff] if self[:diff]
19
+
20
+ (old.keys | new.keys).reduce({}) do |diff, key|
7
21
  old[key] != new[key] ? diff.merge(key => [old[key], new[key]]) : diff
8
22
  end
9
23
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Waldit
4
- VERSION = "0.0.5"
4
+ VERSION = "0.0.6"
5
5
  end
@@ -34,6 +34,7 @@ module Waldit
34
34
  def on_transaction_events(events)
35
35
  record.transaction do
36
36
  @connection = record.connection.raw_connection
37
+ tables = Set.new
37
38
  insert_prepared = false
38
39
  update_prepared = false
39
40
  delete_prepared = false
@@ -43,7 +44,29 @@ module Waldit
43
44
  when CommitTransactionEvent
44
45
  record.where(transaction_id: event.transaction_id).update_all(commited_at: event.timestamp)
45
46
 
47
+ log_new = tables.filter { |table| Waldit.store_changes.call(table).include? :new }
48
+ log_old = tables.filter { |table| Waldit.store_changes.call(table).include? :old }
49
+ log_diff = tables.filter { |table| Waldit.store_changes.call(table).include? :diff }
50
+ record.where(transaction_id: event.transaction_id).update_all(<<~SQL)
51
+ new = CASE WHEN table_name = ANY (ARRAY[#{log_new.map { |table| "'#{table}'" }.join(",")}]::varchar[]) THEN new ELSE null END,
52
+ old = CASE WHEN table_name = ANY (ARRAY[#{log_old.map { |table| "'#{table}'" }.join(",")}]::varchar[]) THEN old ELSE null END,
53
+ diff =
54
+ CASE WHEN table_name = ANY (ARRAY[#{log_diff.map { |table| "'#{table}'" }.join(",")}]::varchar[]) THEN (
55
+ SELECT
56
+ jsonb_object_agg(
57
+ coalesce(old_kv.key, new_kv.key),
58
+ jsonb_build_array(old_kv.value, new_kv.value)
59
+ )
60
+ FROM jsonb_each(old) AS old_kv
61
+ FULL OUTER JOIN jsonb_each(new) AS new_kv ON old_kv.key = new_kv.key
62
+ WHERE old_kv.value IS DISTINCT FROM new_kv.value
63
+ )
64
+ ELSE null
65
+ END
66
+ SQL
67
+
46
68
  when InsertEvent
69
+ tables << event.table
47
70
  unless insert_prepared
48
71
  prepare_insert
49
72
  insert_prepared = true
@@ -51,6 +74,7 @@ module Waldit
51
74
  audit_event(event)
52
75
 
53
76
  when UpdateEvent
77
+ tables << event.table
54
78
  unless update_prepared
55
79
  prepare_update
56
80
  update_prepared = true
@@ -58,6 +82,7 @@ module Waldit
58
82
  audit_event(event)
59
83
 
60
84
  when DeleteEvent
85
+ tables << event.table
61
86
  unless delete_prepared
62
87
  prepare_delete
63
88
  prepare_delete_cleanup
@@ -111,8 +136,8 @@ module Waldit
111
136
 
112
137
  def prepare_delete
113
138
  @connection.prepare("waldit_delete", <<~SQL)
114
- INSERT INTO #{record.table_name} (transaction_id, lsn, table_name, primary_key, action, context, old, new)
115
- VALUES ($1, $2, $3, $4, 'delete'::waldit_action, $5, $6, '{}'::jsonb)
139
+ INSERT INTO #{record.table_name} (transaction_id, lsn, table_name, primary_key, action, context, old)
140
+ VALUES ($1, $2, $3, $4, 'delete'::waldit_action, $5, $6)
116
141
  ON CONFLICT (table_name, primary_key, transaction_id)
117
142
  DO UPDATE SET old = #{record.table_name}.old
118
143
  SQL
data/lib/waldit.rb CHANGED
@@ -21,6 +21,21 @@ module Waldit
21
21
  end
22
22
  end
23
23
 
24
+ attr_reader :store_changes
25
+
26
+ def store_changes=(changes)
27
+ case changes
28
+ when Symbol
29
+ changes = [changes].to_set
30
+ @store_changes = -> { changes }
31
+ when Array
32
+ changes = changes.map(&:to_sym).to_set
33
+ @store_changes = -> { changes }
34
+ else
35
+ @store_changes = changes
36
+ end
37
+ end
38
+
24
39
  attr_accessor :ignored_columns
25
40
  attr_accessor :max_transaction_size
26
41
  attr_accessor :model
@@ -36,6 +51,8 @@ module Waldit
36
51
 
37
52
  config.watched_tables = -> table { table != "waldit" }
38
53
 
54
+ config.store_changes = -> table { %i[old new diff] }
55
+
39
56
  config.ignored_columns = -> table { %w[created_at updated_at] }
40
57
 
41
58
  config.max_transaction_size = 10_000
data/rbi/waldit.rbi CHANGED
@@ -2,7 +2,7 @@
2
2
  module Waldit
3
3
  extend T::Sig
4
4
  extend Waldit::Context
5
- VERSION = "0.0.4"
5
+ VERSION = "0.0.6"
6
6
 
7
7
  class << self
8
8
  sig { returns(String) }
@@ -11,6 +11,9 @@ module Waldit
11
11
  sig { returns(T.proc.params(table: String).returns(T::Boolean)) }
12
12
  attr_reader :watched_tables
13
13
 
14
+ sig { returns(T.proc.params(table: String).returns(T::Array[Symbol])) }
15
+ attr_reader :store_changes
16
+
14
17
  sig { returns(T.proc.params(table: String).returns(T::Array[String])) }
15
18
  attr_accessor :ignored_columns
16
19
 
@@ -24,6 +27,9 @@ module Waldit
24
27
  sig { params(tables: T.any(T::Array[String], T.proc.params(table: String).returns(T::Boolean))).void }
25
28
  def self.watched_tables=(tables); end
26
29
 
30
+ sig { params(changes: T.any(Symbol, T::Array[Symbol], T.proc.params(table: String).returns(T::Array[Symbol]))).void }
31
+ def self.store_changes=(changes); end
32
+
27
33
  sig { params(block: T.proc.params(config: T.class_of(Waldit)).void).void }
28
34
  def self.configure(&block); end
29
35
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: waldit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Navarro
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-08-11 00:00:00.000000000 Z
10
+ date: 2025-08-12 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: wal
@@ -71,7 +71,6 @@ files:
71
71
  - lib/waldit/version.rb
72
72
  - lib/waldit/watcher.rb
73
73
  - rbi/waldit.rbi
74
- - sig/waldit.rbs
75
74
  homepage: https://github.com/reu/waldit
76
75
  licenses:
77
76
  - MIT
data/sig/waldit.rbs DELETED
@@ -1,73 +0,0 @@
1
- # typed: strong
2
- module Waldit
3
- extend Waldit::Context
4
-
5
- def self.watched_tables=: () -> String
6
- | () -> ^(String table) -> bool
7
- | () -> ^(String table) -> ::Array[String]
8
- | () -> Integer
9
- | () -> singleton(ActiveRecord::Base)
10
- | (::Array[String] | ^(String table) -> bool tables) -> void
11
-
12
- def self.configure: () { (singleton(Waldit) config) -> void } -> void
13
- end
14
-
15
- Waldit::VERSION: untyped
16
-
17
- module Waldit::Context
18
- def with_context: [U] (Context context) { () -> U } -> U
19
-
20
- def context: () -> Context?
21
-
22
- def add_context: (Context added_context) -> void
23
-
24
- def new_context: (?Context context) -> void
25
- end
26
-
27
- Waldit::Waldit::Context::Context: untyped
28
-
29
- class Waldit::Railtie < Rails::Railtie
30
- end
31
-
32
- module Waldit::Record
33
- extend T::Helpers
34
-
35
- def new: () -> ::Hash[String | Symbol, untyped]
36
-
37
- def old: () -> ::Hash[String | Symbol, untyped]
38
-
39
- def diff: () -> ::Hash[String | Symbol, [ untyped, untyped ]]
40
- end
41
-
42
- module Waldit::Sidekiq
43
- end
44
-
45
- class Waldit::Waldit::Sidekiq::SaveContext
46
- include ::Sidekiq::ClientMiddleware
47
-
48
- def call: (untyped job_class, untyped job, untyped queue, untyped redis) -> untyped
49
- end
50
-
51
- class Waldit::Waldit::Sidekiq::LoadContext
52
- include ::Sidekiq::ServerMiddleware
53
-
54
- def call: (untyped job_instance, untyped job, untyped queue) { () -> untyped } -> untyped
55
-
56
- def deserialize_context: (untyped job) -> untyped
57
- end
58
-
59
- class Waldit::Watcher < Wal::StreamingWatcher
60
- def audit_event: (InsertEvent | UpdateEvent | DeleteEvent event) -> void
61
-
62
- def on_transaction_events: (::Enumerator[Event] events) -> void
63
-
64
- def should_watch_table?: (String table) -> bool
65
-
66
- def valid_context_prefix?: (String prefix) -> bool
67
-
68
- def ignored_columns: (String table) -> ::Array[String]
69
-
70
- def max_transaction_size: () -> Integer
71
-
72
- def record: () -> singleton(ActiveRecord::Base)
73
- end