wal 0.0.20 → 0.0.21
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/LICENSE.txt +24 -17
- data/lib/wal/record_watcher.rb +11 -9
- data/lib/wal/replicator.rb +18 -5
- data/lib/wal/version.rb +1 -1
- data/lib/wal.rb +17 -3
- data/rbi/wal.rbi +14 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 302e387a9951a4120fea323ca2f3eee13e8608963defa796c8ce0193ac1f2310
|
4
|
+
data.tar.gz: 7adfed0108d9e3671eb83f3750babe622acb1470cc85447a74ab8519c9e41122
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06d389b77e47f82dbcf6c3397c0e5c9b7d9b9fba124273e58d2a336d45c341317cb17ce0810e84c5cebf10ce51b12a0b26102a1600fa84e79f09fc42cb9fd89e
|
7
|
+
data.tar.gz: '09ccf267a08bf2007aeb799ca521445fe25fbaa55ddabf1618577ef70f91b0baaff1bf0f622800d7dd9e2d210c8eaf2f401fa8dc847f72f45c950a4d74d974ab'
|
data/LICENSE.txt
CHANGED
@@ -1,21 +1,28 @@
|
|
1
|
-
|
1
|
+
BSD 3-Clause License
|
2
2
|
|
3
|
-
Copyright (c) 2025 Rodrigo Navarro
|
3
|
+
Copyright (c) 2025-present, Rodrigo Navarro. All rights reserved.
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
11
7
|
|
12
|
-
|
13
|
-
|
8
|
+
* Redistributions of source code must retain the above copyright notice, this
|
9
|
+
list of conditions and the following disclaimer.
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
13
|
+
and/or other materials provided with the distribution.
|
14
|
+
|
15
|
+
* Neither the name of wsrv.nl and images.weserv.nl nor the names of its
|
16
|
+
contributors may be used to endorse or promote products derived from
|
17
|
+
this software without specific prior written permission.
|
18
|
+
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/lib/wal/record_watcher.rb
CHANGED
@@ -76,12 +76,12 @@ module Wal
|
|
76
76
|
def on_record_changed(event)
|
77
77
|
case event
|
78
78
|
when InsertEvent
|
79
|
-
@@change_callbacks[event.
|
79
|
+
@@change_callbacks[event.full_table_name]
|
80
80
|
.filter { |callback| callback[:only].include? :create }
|
81
81
|
.each { |callback| instance_exec(event, &callback[:block]) }
|
82
82
|
|
83
83
|
when UpdateEvent
|
84
|
-
@@change_callbacks[event.
|
84
|
+
@@change_callbacks[event.full_table_name]
|
85
85
|
.filter { |callback| callback[:only].include? :update }
|
86
86
|
.each do |callback|
|
87
87
|
if (attributes = callback[:changed])
|
@@ -92,7 +92,7 @@ module Wal
|
|
92
92
|
end
|
93
93
|
|
94
94
|
when DeleteEvent
|
95
|
-
@@delete_callbacks[event.
|
95
|
+
@@delete_callbacks[event.full_table_name].each do |callback|
|
96
96
|
instance_exec(event, &callback[:block])
|
97
97
|
end
|
98
98
|
end
|
@@ -184,7 +184,7 @@ module Wal
|
|
184
184
|
def on_update(event)
|
185
185
|
if (id = event.primary_key)
|
186
186
|
@records ||= {}
|
187
|
-
@records[[event.
|
187
|
+
@records[[event.full_table_name, id]] = case (existing_event = @records[[event.full_table_name, id]])
|
188
188
|
when InsertEvent
|
189
189
|
# A record inserted on this transaction is being updated, which means it should still reflect as a insert
|
190
190
|
# event, we just change the information to reflect the most current data that was just updated.
|
@@ -204,7 +204,7 @@ module Wal
|
|
204
204
|
def on_delete(event)
|
205
205
|
if (id = event.primary_key)
|
206
206
|
@records ||= {}
|
207
|
-
@records[[event.
|
207
|
+
@records[[event.full_table_name, id]] = case (existing_event = @records[[event.full_table_name, id]])
|
208
208
|
when InsertEvent
|
209
209
|
# We are removing a record that was inserted on this transaction, we should not even report this change, as
|
210
210
|
# this record never existed outside this transaction anyways.
|
@@ -304,9 +304,9 @@ module Wal
|
|
304
304
|
end
|
305
305
|
|
306
306
|
def on_delete(event)
|
307
|
-
case @table.where(table_name: event.
|
307
|
+
case @table.where(table_name: event.full_table_name, primary_key: event.primary_key).pluck(:action, :old).first
|
308
308
|
in ["insert", _]
|
309
|
-
@table.where(table_name: event.
|
309
|
+
@table.where(table_name: event.full_table_name, primary_key: event.primary_key).delete_all
|
310
310
|
in ["update", old]
|
311
311
|
@table.upsert(serialize(event).merge(old:))
|
312
312
|
in ["delete", _]
|
@@ -326,7 +326,7 @@ module Wal
|
|
326
326
|
serialized = {
|
327
327
|
transaction_id: event.transaction_id,
|
328
328
|
lsn: event.lsn,
|
329
|
-
table_name: event.
|
329
|
+
table_name: event.full_table_name,
|
330
330
|
primary_key: event.primary_key,
|
331
331
|
context: event.context,
|
332
332
|
}
|
@@ -343,10 +343,12 @@ module Wal
|
|
343
343
|
end
|
344
344
|
|
345
345
|
def deserialize(persisted_event)
|
346
|
+
table, schema = persisted_event.table_name.split(".", 2)
|
346
347
|
deserialized = {
|
347
348
|
transaction_id: persisted_event.transaction_id,
|
348
349
|
lsn: persisted_event.lsn,
|
349
|
-
|
350
|
+
schema: schema || "public",
|
351
|
+
table: table,
|
350
352
|
primary_key: persisted_event.primary_key,
|
351
353
|
context: persisted_event.context,
|
352
354
|
}
|
data/lib/wal/replicator.rb
CHANGED
@@ -47,10 +47,11 @@ module Wal
|
|
47
47
|
|
48
48
|
watch_conn.start_pgoutput_replication_slot(@replication_slot, publications, messages: true).filter_map do |msg|
|
49
49
|
case msg
|
50
|
-
in XLogData(data: PG::Replication::PGOutput::Relation(oid:, name:, columns:))
|
50
|
+
in XLogData(data: PG::Replication::PGOutput::Relation(oid:, name:, columns:, namespace:))
|
51
51
|
tables[oid] = Table.new(
|
52
52
|
# TODO: for now we are forcing an id column here, but that is not really correct
|
53
53
|
primary_key_colums: columns.any? { |col| col.name == "id" } ? ["id"] : [],
|
54
|
+
schema: namespace,
|
54
55
|
name:,
|
55
56
|
columns: columns.map do |col|
|
56
57
|
Column.new(
|
@@ -100,7 +101,7 @@ module Wal
|
|
100
101
|
|
101
102
|
in XLogData(lsn:, data: PG::Replication::PGOutput::Insert(oid:, new:))
|
102
103
|
table = tables[oid]
|
103
|
-
next unless watcher.should_watch_table? table.
|
104
|
+
next unless watcher.should_watch_table? table.full_table_name
|
104
105
|
new_data = table.decode_row(new)
|
105
106
|
record_id = table.primary_key(new_data)
|
106
107
|
next unless record_id
|
@@ -109,6 +110,7 @@ module Wal
|
|
109
110
|
transaction_id:,
|
110
111
|
lsn:,
|
111
112
|
context:,
|
113
|
+
schema: table.schema,
|
112
114
|
table: table.name,
|
113
115
|
primary_key: record_id,
|
114
116
|
new: new_data,
|
@@ -116,7 +118,7 @@ module Wal
|
|
116
118
|
|
117
119
|
in XLogData(lsn:, data: PG::Replication::PGOutput::Update(oid:, new:, old:))
|
118
120
|
table = tables[oid]
|
119
|
-
next unless watcher.should_watch_table? table.
|
121
|
+
next unless watcher.should_watch_table? table.full_table_name
|
120
122
|
old_data = table.decode_row(old)
|
121
123
|
new_data = table.decode_row(new)
|
122
124
|
record_id = table.primary_key(new_data)
|
@@ -126,6 +128,7 @@ module Wal
|
|
126
128
|
transaction_id:,
|
127
129
|
lsn:,
|
128
130
|
context:,
|
131
|
+
schema: table.schema,
|
129
132
|
table: table.name,
|
130
133
|
primary_key: record_id,
|
131
134
|
old: old_data,
|
@@ -134,7 +137,7 @@ module Wal
|
|
134
137
|
|
135
138
|
in XLogData(lsn:, data: PG::Replication::PGOutput::Delete(oid:, old:, key:))
|
136
139
|
table = tables[oid]
|
137
|
-
next unless watcher.should_watch_table? table.
|
140
|
+
next unless watcher.should_watch_table? table.full_table_name
|
138
141
|
old_data = table.decode_row(old.presence || key)
|
139
142
|
record_id = table.primary_key(old_data)
|
140
143
|
next unless record_id
|
@@ -143,6 +146,7 @@ module Wal
|
|
143
146
|
transaction_id:,
|
144
147
|
lsn:,
|
145
148
|
context:,
|
149
|
+
schema: table.schema,
|
146
150
|
table: table.name,
|
147
151
|
primary_key: record_id,
|
148
152
|
old: old_data,
|
@@ -160,7 +164,16 @@ module Wal
|
|
160
164
|
end
|
161
165
|
end
|
162
166
|
|
163
|
-
class Table < Data.define(:name, :primary_key_colums, :columns)
|
167
|
+
class Table < Data.define(:schema, :name, :primary_key_colums, :columns)
|
168
|
+
def full_table_name
|
169
|
+
case schema
|
170
|
+
in "public"
|
171
|
+
name
|
172
|
+
else
|
173
|
+
"#{schema}.#{name}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
164
177
|
def primary_key(decoded_row)
|
165
178
|
case primary_key_colums
|
166
179
|
in [key]
|
data/lib/wal/version.rb
CHANGED
data/lib/wal.rb
CHANGED
@@ -29,6 +29,17 @@ module Wal
|
|
29
29
|
class CommitTransactionEvent < Data.define(:transaction_id, :lsn, :context, :timestamp)
|
30
30
|
end
|
31
31
|
|
32
|
+
module TableName
|
33
|
+
def full_table_name
|
34
|
+
case schema
|
35
|
+
in "public"
|
36
|
+
table
|
37
|
+
else
|
38
|
+
"#{schema}.#{table}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
32
43
|
module ChangeEvent
|
33
44
|
def diff
|
34
45
|
{}
|
@@ -55,7 +66,8 @@ module Wal
|
|
55
66
|
end
|
56
67
|
end
|
57
68
|
|
58
|
-
class InsertEvent < Data.define(:transaction_id, :lsn, :context, :table, :primary_key, :new)
|
69
|
+
class InsertEvent < Data.define(:transaction_id, :lsn, :context, :schema, :table, :primary_key, :new)
|
70
|
+
include ::Wal::TableName
|
59
71
|
include ::Wal::ChangeEvent
|
60
72
|
|
61
73
|
def diff
|
@@ -63,7 +75,8 @@ module Wal
|
|
63
75
|
end
|
64
76
|
end
|
65
77
|
|
66
|
-
class UpdateEvent < Data.define(:transaction_id, :lsn, :context, :table, :primary_key, :old, :new)
|
78
|
+
class UpdateEvent < Data.define(:transaction_id, :lsn, :context, :schema, :table, :primary_key, :old, :new)
|
79
|
+
include ::Wal::TableName
|
67
80
|
include ::Wal::ChangeEvent
|
68
81
|
|
69
82
|
def diff
|
@@ -73,7 +86,8 @@ module Wal
|
|
73
86
|
end
|
74
87
|
end
|
75
88
|
|
76
|
-
class DeleteEvent < Data.define(:transaction_id, :lsn, :context, :table, :primary_key, :old)
|
89
|
+
class DeleteEvent < Data.define(:transaction_id, :lsn, :context, :schema, :table, :primary_key, :old)
|
90
|
+
include ::Wal::TableName
|
77
91
|
include ::Wal::ChangeEvent
|
78
92
|
|
79
93
|
def diff
|
data/rbi/wal.rbi
CHANGED
@@ -7,7 +7,7 @@ module Wal
|
|
7
7
|
UpdateEvent,
|
8
8
|
DeleteEvent,
|
9
9
|
) }
|
10
|
-
VERSION = "0.0.
|
10
|
+
VERSION = "0.0.21"
|
11
11
|
|
12
12
|
class << self
|
13
13
|
sig { returns(T.class_of(Logger)) }
|
@@ -37,6 +37,13 @@ module Wal
|
|
37
37
|
|
38
38
|
end
|
39
39
|
|
40
|
+
module TableName
|
41
|
+
extend T::Sig
|
42
|
+
|
43
|
+
sig { returns(String) }
|
44
|
+
def full_table_name; end
|
45
|
+
end
|
46
|
+
|
40
47
|
module ChangeEvent
|
41
48
|
extend T::Sig
|
42
49
|
|
@@ -60,10 +67,12 @@ module Wal
|
|
60
67
|
prop :transaction_id, Integer, immutable: true
|
61
68
|
prop :lsn, Integer, immutable: true
|
62
69
|
prop :context, T::Hash[String, T.untyped], immutable: true
|
70
|
+
prop :schema, String, immutable: true
|
63
71
|
prop :table, String, immutable: true
|
64
72
|
prop :primary_key, T.untyped, immutable: true
|
65
73
|
prop :new, T::Hash[String, T.untyped], immutable: true
|
66
74
|
|
75
|
+
include ::Wal::TableName
|
67
76
|
include ::Wal::ChangeEvent
|
68
77
|
extend T::Sig
|
69
78
|
|
@@ -75,11 +84,13 @@ module Wal
|
|
75
84
|
prop :transaction_id, Integer, immutable: true
|
76
85
|
prop :lsn, Integer, immutable: true
|
77
86
|
prop :context, T::Hash[String, T.untyped], immutable: true
|
87
|
+
prop :schema, String, immutable: true
|
78
88
|
prop :table, String, immutable: true
|
79
89
|
prop :primary_key, T.untyped, immutable: true
|
80
90
|
prop :old, T::Hash[String, T.untyped], immutable: true
|
81
91
|
prop :new, T::Hash[String, T.untyped], immutable: true
|
82
92
|
|
93
|
+
include ::Wal::TableName
|
83
94
|
include ::Wal::ChangeEvent
|
84
95
|
extend T::Sig
|
85
96
|
|
@@ -91,10 +102,12 @@ module Wal
|
|
91
102
|
prop :transaction_id, Integer, immutable: true
|
92
103
|
prop :lsn, Integer, immutable: true
|
93
104
|
prop :context, T::Hash[String, T.untyped], immutable: true
|
105
|
+
prop :schema, String, immutable: true
|
94
106
|
prop :table, String, immutable: true
|
95
107
|
prop :primary_key, T.untyped, immutable: true
|
96
108
|
prop :old, T::Hash[String, T.untyped], immutable: true
|
97
109
|
|
110
|
+
include ::Wal::TableName
|
98
111
|
include ::Wal::ChangeEvent
|
99
112
|
extend T::Sig
|
100
113
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rodrigo Navarro
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-09
|
10
|
+
date: 2025-10-09 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: pg
|
@@ -105,7 +105,7 @@ files:
|
|
105
105
|
- lib/wal/watcher.rb
|
106
106
|
- rbi/wal.rbi
|
107
107
|
licenses:
|
108
|
-
-
|
108
|
+
- BSD-3-Clause
|
109
109
|
metadata:
|
110
110
|
homepage_uri: https://github.com/reu/wal
|
111
111
|
source_code_uri: https://github.com/reu/wal
|