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 +4 -4
- data/lib/waldit/record.rb +15 -1
- data/lib/waldit/version.rb +1 -1
- data/lib/waldit/watcher.rb +27 -2
- data/lib/waldit.rb +17 -0
- data/rbi/waldit.rbi +7 -1
- metadata +2 -3
- data/sig/waldit.rbs +0 -73
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8e8ecb8b8fc2c3c4b855fb06b204d858b7cfbf24f12dc016b4c3f5ca10849a2
|
4
|
+
data.tar.gz: b72218c4df4b396e497f1aa9d96fd159305fabb7faf0d481392044536da5141a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
data/lib/waldit/version.rb
CHANGED
data/lib/waldit/watcher.rb
CHANGED
@@ -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
|
115
|
-
VALUES ($1, $2, $3, $4, 'delete'::waldit_action, $5, $6
|
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.
|
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.
|
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-
|
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
|