pg_eventstore 1.8.0 → 1.9.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +1 -0
- data/docs/configuration.md +3 -0
- data/docs/maintenance.md +51 -0
- data/lib/pg_eventstore/client.rb +0 -2
- data/lib/pg_eventstore/commands/delete_event.rb +38 -0
- data/lib/pg_eventstore/commands/delete_stream.rb +18 -0
- data/lib/pg_eventstore/commands.rb +2 -0
- data/lib/pg_eventstore/errors.rb +19 -1
- data/lib/pg_eventstore/maintenance.rb +48 -0
- data/lib/pg_eventstore/queries/maintenance_queries.rb +81 -0
- data/lib/pg_eventstore/queries.rb +5 -0
- data/lib/pg_eventstore/version.rb +1 -1
- data/lib/pg_eventstore/web/application.rb +49 -0
- data/lib/pg_eventstore/web/public/javascripts/pg_eventstore.js +66 -0
- data/lib/pg_eventstore/web/public/javascripts/vendor/js.cookie.min.js +2 -0
- data/lib/pg_eventstore/web/subscriptions/helpers.rb +12 -0
- data/lib/pg_eventstore/web/views/home/dashboard.erb +32 -0
- data/lib/pg_eventstore/web/views/home/partials/event_filter.erb +1 -1
- data/lib/pg_eventstore/web/views/home/partials/events.erb +8 -2
- data/lib/pg_eventstore/web/views/home/partials/stream_filter.erb +11 -6
- data/lib/pg_eventstore/web/views/home/partials/system_stream_filter.erb +1 -1
- data/lib/pg_eventstore/web/views/layouts/application.erb +12 -0
- data/lib/pg_eventstore.rb +9 -0
- data/sig/pg_eventstore/commands/delete_event.rbs +13 -0
- data/sig/pg_eventstore/commands/delete_stream.rbs +7 -0
- data/sig/pg_eventstore/errors.rbs +10 -0
- data/sig/pg_eventstore/maintenance.rbs +19 -0
- data/sig/pg_eventstore/queries/maintenance_queries.rbs +21 -0
- data/sig/pg_eventstore/queries.rbs +8 -6
- data/sig/pg_eventstore/web/application.rbs +3 -0
- data/sig/pg_eventstore/web/subscriptions/helpers.rbs +4 -0
- data/sig/pg_eventstore.rbs +2 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c0936a5580f6340a43f65d5b1b3362855b30e78fb25bdd498bf21c759458fcb
|
4
|
+
data.tar.gz: d18a05c7c6917e66c83de05013afcf6b9f25aaf7027e32fb1345553f5398a120
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b11fcbc08f2853a69c288dcd08498a5e40277cdeaf32ccba71ade48eac03cf3fd0c157abe0058daedb27aca945406afa8f3078f149e045ff63d89a47ca12da36
|
7
|
+
data.tar.gz: c021e192cfd8f61364235fa7ccdd2d97a37c39fe304f9167fe7cda508acd7c65b84bc2d168687a1cec185cf07870183b70fc849508a434ea13935398687cbea4
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [1.9.0]
|
4
|
+
|
5
|
+
- Implement an ability to delete a stream
|
6
|
+
- Implement an ability to delete an event
|
7
|
+
- Add "Delete event" and "Delete stream" buttons into admin UI
|
8
|
+
|
3
9
|
## [1.8.0]
|
4
10
|
- Introduce default config for admin web UI. Now if you define `:admin_web_ui` config - it will be preferred over default config
|
5
11
|
- Fix pagination of events in admin UI
|
data/README.md
CHANGED
@@ -45,6 +45,7 @@ Documentation chapters:
|
|
45
45
|
- [Linking events](docs/linking_events.md)
|
46
46
|
- [Reading events](docs/reading_events.md)
|
47
47
|
- [Subscriptions](docs/subscriptions.md)
|
48
|
+
- [Maintenance functions](docs/maintenance.md)
|
48
49
|
- [Writing middlewares](docs/writing_middleware.md)
|
49
50
|
- [How to make multiple commands atomic](docs/multiple_commands.md)
|
50
51
|
- [Admin UI](docs/admin_ui.md)
|
data/docs/configuration.md
CHANGED
@@ -45,6 +45,9 @@ Tell `PgEventstore` which config you want to use:
|
|
45
45
|
PgEventstore.client(:pg_db_1).read(PgEventstore::Stream.all_stream)
|
46
46
|
# Read from "all" stream using :pg_db_2 config
|
47
47
|
PgEventstore.client(:pg_db_2).read(PgEventstore::Stream.all_stream)
|
48
|
+
# Delete a stream using :pg_db_1 config
|
49
|
+
stream = PgEventstore::Stream.new(context: 'FooCtx', stream_name: 'MyStream', stream_id: '1')
|
50
|
+
PgEventstore.maintenance.delete_stream(stream)
|
48
51
|
```
|
49
52
|
|
50
53
|
### Default config
|
data/docs/maintenance.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Maintenance
|
2
|
+
|
3
|
+
`pg_eventstore` provides maintenance functional which can be used to clean up various objects in your database.
|
4
|
+
|
5
|
+
## Delete a stream
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
stream = PgEventstore::Stream.new(context: 'FooCtx', stream_name: 'MyStream', stream_id: '1')
|
9
|
+
PgEventstore.client.append_to_stream(stream, PgEventstore::Event.new)
|
10
|
+
PgEventstore.maintenance.delete_stream(stream) # => true
|
11
|
+
```
|
12
|
+
deletes all events in the given stream. If the given stream does not exist - `false` is returned:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
stream = PgEventstore::Stream.new(context: 'NonExistingCtx', stream_name: 'NonExistingStream', stream_id: '1')
|
16
|
+
PgEventstore.maintenance.delete_stream(stream) # => false
|
17
|
+
```
|
18
|
+
|
19
|
+
**Please note that this operation does not automatically delete links to deleted events - you have to do delete them separately.**
|
20
|
+
|
21
|
+
## Delete an event
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
stream = PgEventstore::Stream.new(context: 'FooCtx', stream_name: 'MyStream', stream_id: '1')
|
25
|
+
PgEventstore.client.append_to_stream(stream, PgEventstore::Event.new)
|
26
|
+
# Grab the first event for further deletion
|
27
|
+
event = PgEventstore.client.read(stream, options: { max_count: 1 }).first
|
28
|
+
PgEventstore.maintenance.delete_event(event) # => true
|
29
|
+
```
|
30
|
+
deletes the given event. If the given event does not exist - `false` is returned:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
stream = PgEventstore::Stream.new(context: 'FooCtx', stream_name: 'MyStream', stream_id: '1')
|
34
|
+
PgEventstore.client.append_to_stream(stream, PgEventstore::Event.new)
|
35
|
+
# Grab the first event for further deletion
|
36
|
+
event = PgEventstore.client.read(stream, options: { max_count: 1 }).first
|
37
|
+
PgEventstore.maintenance.delete_event(event) # => true
|
38
|
+
PgEventstore.maintenance.delete_event(event) # => false
|
39
|
+
```
|
40
|
+
|
41
|
+
**Please note that this operation does not automatically delete links to the deleted event - you have to do delete them separately.**
|
42
|
+
|
43
|
+
### Deleting an event in a large stream
|
44
|
+
|
45
|
+
There can be a situation when you would like to delete an event in a large stream. If an event is in the position where there are 1000+ events after it in a stream - a `PgEventstore::TooManyRecordsToLockError` error will be raised. This is because in addition to removing the event, we need to adjust the rest of the stream by updating the `#stream_revision` of all events that come after this event. To overcome this limitation - you can provide `force: true` flag:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
PgEventstore.maintenance.delete_event(event, force: true)
|
49
|
+
```
|
50
|
+
|
51
|
+
Because the update operation can lock thousands of events - `#delete_event` can be slow and can slow down other processes which insert events in the same stream at the same moment. **Thus, it is recommended to avoid using `#delete_event` in your business logic.**
|
data/lib/pg_eventstore/client.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgEventstore
|
4
|
+
module Commands
|
5
|
+
# @!visibility private
|
6
|
+
class DeleteEvent < AbstractCommand
|
7
|
+
# Determines max allowed number of records to lock during an update. If the threshold is reached - an error is
|
8
|
+
# raised.
|
9
|
+
# @return [Integer]
|
10
|
+
MAX_RECORDS_TO_LOCK = 1_000
|
11
|
+
|
12
|
+
# @param event [PgEventstore::Event]
|
13
|
+
# @param force [Boolean]
|
14
|
+
# @return [Boolean]
|
15
|
+
def call(event, force:)
|
16
|
+
queries.transactions.transaction do
|
17
|
+
event = queries.maintenance.reload_event(event)
|
18
|
+
next false unless event
|
19
|
+
|
20
|
+
check_records_number_to_lock(event) unless force
|
21
|
+
queries.maintenance.delete_event(event)
|
22
|
+
queries.maintenance.adjust_stream_revisions(event.stream, event.stream_revision)
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# @param event [PgEventstore::Event]
|
30
|
+
# @return [void]
|
31
|
+
# @raise [PgEventstore::TooManyRecordsToLockError]
|
32
|
+
def check_records_number_to_lock(event)
|
33
|
+
records_to_lock = queries.maintenance.events_to_lock_count(event.stream, event.stream_revision)
|
34
|
+
raise TooManyRecordsToLockError.new(event.stream, records_to_lock) if records_to_lock > MAX_RECORDS_TO_LOCK
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgEventstore
|
4
|
+
module Commands
|
5
|
+
# @!visibility private
|
6
|
+
class DeleteStream < AbstractCommand
|
7
|
+
# @param stream [PgEventstore::Stream]
|
8
|
+
# @return [Boolean]
|
9
|
+
def call(stream)
|
10
|
+
raise SystemStreamError, stream if stream.system?
|
11
|
+
|
12
|
+
queries.transactions.transaction do
|
13
|
+
queries.maintenance.delete_stream(stream) > 0
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -9,3 +9,5 @@ require_relative 'commands/regular_stream_read_paginated'
|
|
9
9
|
require_relative 'commands/system_stream_read_paginated'
|
10
10
|
require_relative 'commands/multiple'
|
11
11
|
require_relative 'commands/link_to'
|
12
|
+
require_relative 'commands/delete_stream'
|
13
|
+
require_relative 'commands/delete_event'
|
data/lib/pg_eventstore/errors.rb
CHANGED
@@ -41,7 +41,7 @@ module PgEventstore
|
|
41
41
|
# @param stream [PgEventstore::Stream]
|
42
42
|
def initialize(stream)
|
43
43
|
@stream = stream
|
44
|
-
super("
|
44
|
+
super("Can't perform this action with #{stream.inspect} system stream.")
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -225,4 +225,22 @@ module PgEventstore
|
|
225
225
|
|
226
226
|
class EmptyChunkFedError < Error
|
227
227
|
end
|
228
|
+
|
229
|
+
class TooManyRecordsToLockError < Error
|
230
|
+
attr_reader :stream
|
231
|
+
attr_reader :number_of_records
|
232
|
+
|
233
|
+
# @param stream [PgEventstore::Stream]
|
234
|
+
# @param number_of_records [Integer]
|
235
|
+
def initialize(stream, number_of_records)
|
236
|
+
@stream = stream
|
237
|
+
@number_of_records = number_of_records
|
238
|
+
super(user_friendly_message)
|
239
|
+
end
|
240
|
+
|
241
|
+
# @return [String]
|
242
|
+
def user_friendly_message
|
243
|
+
"Too many records of #{stream.to_hash.inspect} stream to lock: #{number_of_records}"
|
244
|
+
end
|
245
|
+
end
|
228
246
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgEventstore
|
4
|
+
class Maintenance
|
5
|
+
# @!attribute config
|
6
|
+
# @return [PgEventstore::Config]
|
7
|
+
attr_reader :config
|
8
|
+
private :config
|
9
|
+
|
10
|
+
# @param config [PgEventstore::Config]
|
11
|
+
def initialize(config)
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param stream [PgEventstore::Stream]
|
16
|
+
# @return [Boolean] whether a stream was deleted successfully
|
17
|
+
def delete_stream(stream)
|
18
|
+
Commands::DeleteStream.new(
|
19
|
+
Queries.new(transactions: transaction_queries, maintenance: maintenance_queries)
|
20
|
+
).call(stream)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param event [PgEventstore::Event] persisted event
|
24
|
+
# @return [Boolean] whether an event was deleted successfully
|
25
|
+
def delete_event(event, force: false)
|
26
|
+
Commands::DeleteEvent.new(
|
27
|
+
Queries.new(transactions: transaction_queries, maintenance: maintenance_queries)
|
28
|
+
).call(event, force: force)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# @return [PgEventstore::MaintenanceQueries]
|
34
|
+
def maintenance_queries
|
35
|
+
MaintenanceQueries.new(connection)
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return [PgEventstore::TransactionQueries]
|
39
|
+
def transaction_queries
|
40
|
+
TransactionQueries.new(connection)
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [PgEventstore::Connection]
|
44
|
+
def connection
|
45
|
+
PgEventstore.connection(config.name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgEventstore
|
4
|
+
# @!visibility private
|
5
|
+
class MaintenanceQueries
|
6
|
+
# @!attribute connection
|
7
|
+
# @return [PgEventstore::Connection]
|
8
|
+
attr_reader :connection
|
9
|
+
private :connection
|
10
|
+
|
11
|
+
# @param connection [PgEventstore::Connection]
|
12
|
+
def initialize(connection)
|
13
|
+
@connection = connection
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param stream [PgEventstore::Stream]
|
17
|
+
# @return [Integer] number of deleted events of the given stream
|
18
|
+
def delete_stream(stream)
|
19
|
+
connection.with do |conn|
|
20
|
+
conn.exec_params(<<~SQL, stream.deconstruct)
|
21
|
+
DELETE FROM events WHERE context = $1 AND stream_name = $2 AND stream_id = $3
|
22
|
+
SQL
|
23
|
+
end.cmd_tuples
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param event [PgEventstore::Event]
|
27
|
+
# @return [Integer] number of deleted events
|
28
|
+
def delete_event(event)
|
29
|
+
connection.with do |conn|
|
30
|
+
conn.exec_params(<<~SQL, [event.stream.context, event.stream.stream_name, event.type, event.global_position])
|
31
|
+
DELETE FROM events WHERE context = $1 AND stream_name = $2 AND type = $3 AND global_position = $4
|
32
|
+
SQL
|
33
|
+
end.cmd_tuples
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param stream [PgEventstore::Stream]
|
37
|
+
# @param after_revision [Integer]
|
38
|
+
# @return [void]
|
39
|
+
def adjust_stream_revisions(stream, after_revision)
|
40
|
+
connection.with do |conn|
|
41
|
+
conn.exec_params(<<~SQL, [stream.context, stream.stream_name, stream.stream_id, after_revision])
|
42
|
+
UPDATE events SET stream_revision = stream_revision - 1
|
43
|
+
WHERE context = $1 AND stream_name = $2
|
44
|
+
AND stream_id = $3 AND stream_revision > $4
|
45
|
+
SQL
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param stream [PgEventstore::Stream]
|
50
|
+
# @param after_revision [Integer]
|
51
|
+
# @return [Integer]
|
52
|
+
def events_to_lock_count(stream, after_revision)
|
53
|
+
connection.with do |conn|
|
54
|
+
conn.exec_params(<<~SQL, [*stream.deconstruct, after_revision])
|
55
|
+
EXPLAIN SELECT * FROM events
|
56
|
+
WHERE context = $1 AND stream_name = $2 AND stream_id = $3 AND stream_revision > $4
|
57
|
+
SQL
|
58
|
+
end.to_a.first['QUERY PLAN'].match(/rows=(\d+)/)[1].to_i
|
59
|
+
end
|
60
|
+
|
61
|
+
# @param event [PgEventstore::Event]
|
62
|
+
# @return [PgEventstore::Event]
|
63
|
+
def reload_event(event)
|
64
|
+
event_attrs = connection.with do |conn|
|
65
|
+
conn.exec_params(<<~SQL, [event.stream&.context, event.stream&.stream_name, event.type, event.global_position])
|
66
|
+
SELECT * FROM events WHERE context = $1 AND stream_name = $2 AND type = $3 AND global_position = $4 LIMIT 1
|
67
|
+
SQL
|
68
|
+
end.to_a.first
|
69
|
+
return unless event_attrs
|
70
|
+
|
71
|
+
basic_deserializer.deserialize(event_attrs)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# @return [PgEventstore::EventDeserializer]
|
77
|
+
def basic_deserializer
|
78
|
+
EventDeserializer.new([], ->(_event_type) { Event })
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -6,6 +6,7 @@ require_relative 'queries/transaction_queries'
|
|
6
6
|
require_relative 'queries/event_queries'
|
7
7
|
require_relative 'queries/partition_queries'
|
8
8
|
require_relative 'queries/links_resolver'
|
9
|
+
require_relative 'queries/maintenance_queries'
|
9
10
|
|
10
11
|
module PgEventstore
|
11
12
|
# @!visibility private
|
@@ -21,5 +22,9 @@ module PgEventstore
|
|
21
22
|
# @!attribute transactions
|
22
23
|
# @return [PgEventstore::TransactionQueries, nil]
|
23
24
|
attribute(:transactions)
|
25
|
+
|
26
|
+
# @!attribute maintenance
|
27
|
+
# @return [PgEventstore::MaintenanceQueries, nil]
|
28
|
+
attribute(:maintenance)
|
24
29
|
end
|
25
30
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'securerandom'
|
4
|
+
require 'base64'
|
4
5
|
|
5
6
|
module PgEventstore
|
6
7
|
module Web
|
@@ -9,6 +10,8 @@ module PgEventstore
|
|
9
10
|
DEFAULT_ADMIN_UI_CONFIG = :admin_web_ui
|
10
11
|
# @return [String]
|
11
12
|
COOKIES_CONFIG_KEY = 'current_config'
|
13
|
+
# @return [String]
|
14
|
+
COOKIES_FLASH_MESSAGE_KEY = 'flash_message'
|
12
15
|
|
13
16
|
set :static_cache_control, [:private, max_age: 86400]
|
14
17
|
set :environment, -> { (ENV['RACK_ENV'] || ENV['RAILS_ENV'] || ENV['APP_ENV'])&.to_sym || :development }
|
@@ -97,6 +100,14 @@ module PgEventstore
|
|
97
100
|
def resolve_link_tos?
|
98
101
|
params.key?(:resolve_link_tos) ? params[:resolve_link_tos] == 'true' : true
|
99
102
|
end
|
103
|
+
|
104
|
+
# @param val [Hash]
|
105
|
+
def flash_message=(val)
|
106
|
+
val = Base64.urlsafe_encode64(val.to_json)
|
107
|
+
response.set_cookie(
|
108
|
+
COOKIES_FLASH_MESSAGE_KEY, { value: val, http_only: false, same_site: :lax, path: '/' }
|
109
|
+
)
|
110
|
+
end
|
100
111
|
end
|
101
112
|
|
102
113
|
get '/' do
|
@@ -243,6 +254,44 @@ module PgEventstore
|
|
243
254
|
|
244
255
|
redirect redirect_back_url(fallback_url: url('/subscriptions'))
|
245
256
|
end
|
257
|
+
|
258
|
+
post '/delete_event/:global_position' do
|
259
|
+
params in { data: { force: String => force } }
|
260
|
+
global_position = params[:global_position].to_i
|
261
|
+
force = force == 'true'
|
262
|
+
event = PgEventstore.client(current_config).read(
|
263
|
+
PgEventstore::Stream.all_stream, options: { max_count: 1, from_position: global_position }
|
264
|
+
).first
|
265
|
+
if event&.global_position == global_position
|
266
|
+
begin
|
267
|
+
PgEventstore.maintenance(current_config).delete_event(event, force: force)
|
268
|
+
self.flash_message = {
|
269
|
+
message: "An event at global position #{event.global_position} has been deleted successfully.",
|
270
|
+
kind: 'success'
|
271
|
+
}
|
272
|
+
rescue TooManyRecordsToLockError => e
|
273
|
+
text = <<~TEXT
|
274
|
+
Could not delete an event at global position #{event.global_position} - too many \
|
275
|
+
records(~#{e.number_of_records}) to lock.
|
276
|
+
TEXT
|
277
|
+
self.flash_message = { message: text, kind: 'error' }
|
278
|
+
end
|
279
|
+
else
|
280
|
+
self.flash_message = { message: 'Failed to delete an event - event does not exist.', kind: 'warning' }
|
281
|
+
end
|
282
|
+
redirect(redirect_back_url(fallback_url: '/'))
|
283
|
+
end
|
284
|
+
|
285
|
+
post '/delete_stream/:context/:stream_name/:stream_id' do
|
286
|
+
attrs = Hash[params.slice(:context, :stream_name, :stream_id)].transform_keys(&:to_sym)
|
287
|
+
stream = PgEventstore::Stream.new(**attrs)
|
288
|
+
PgEventstore.maintenance(current_config).delete_stream(stream)
|
289
|
+
self.flash_message = {
|
290
|
+
message: "Stream #{stream.to_hash} has been successfully deleted.",
|
291
|
+
kind: 'success'
|
292
|
+
}
|
293
|
+
redirect(redirect_back_url(fallback_url: '/'))
|
294
|
+
end
|
246
295
|
end
|
247
296
|
end
|
248
297
|
end
|
@@ -5,6 +5,11 @@ $(function(){
|
|
5
5
|
let $contextSelect = $filter.find('select[name*="context"]');
|
6
6
|
let $streamNameSelect = $filter.find('select[name*="stream_name"]');
|
7
7
|
let $streamIdSelect = $filter.find('select[name*="stream_id"]');
|
8
|
+
|
9
|
+
let removeDeleteBtn = function(){
|
10
|
+
$filter.find('.delete-stream').remove();
|
11
|
+
}
|
12
|
+
|
8
13
|
$contextSelect.select2({
|
9
14
|
ajax: {
|
10
15
|
url: $contextSelect.data('url'),
|
@@ -58,6 +63,9 @@ $(function(){
|
|
58
63
|
},
|
59
64
|
allowClear: true
|
60
65
|
});
|
66
|
+
$contextSelect.on('change.select2', removeDeleteBtn);
|
67
|
+
$streamNameSelect.on('change.select2', removeDeleteBtn);
|
68
|
+
$streamIdSelect.on('change.select2', removeDeleteBtn);
|
61
69
|
}
|
62
70
|
|
63
71
|
let initSystemStreamFilterAutocomplete = function($filter){
|
@@ -257,3 +265,61 @@ $(function(){
|
|
257
265
|
window.location.href = $selected.data('url');
|
258
266
|
});
|
259
267
|
});
|
268
|
+
|
269
|
+
// Event deletion handling
|
270
|
+
$(function(){
|
271
|
+
"use strict";
|
272
|
+
|
273
|
+
let $deleteEventModal = $('#delete-event-modal');
|
274
|
+
|
275
|
+
$deleteEventModal.on('hide.bs.modal', function(){
|
276
|
+
$(this).find('.global-position-text').html('');
|
277
|
+
$(this).find('form').removeAttr('action');
|
278
|
+
});
|
279
|
+
|
280
|
+
$deleteEventModal.on('show.bs.modal', function(e){
|
281
|
+
let $clickedLink = $(e.relatedTarget);
|
282
|
+
$(this).find('.global-position-text').html($clickedLink.data('global-position'));
|
283
|
+
$(this).find('form').attr('action', $clickedLink.data('url'));
|
284
|
+
});
|
285
|
+
});
|
286
|
+
|
287
|
+
// Flash messages
|
288
|
+
$(function () {
|
289
|
+
"use strict";
|
290
|
+
|
291
|
+
let message = Cookies.get(window.flashMessageCookie);
|
292
|
+
if (!message)
|
293
|
+
return;
|
294
|
+
|
295
|
+
try {
|
296
|
+
message = Uint8Array.fromBase64(message, { alphabet: "base64url" });
|
297
|
+
message = new TextDecoder().decode(message);
|
298
|
+
message = JSON.parse(message);
|
299
|
+
} catch (e) {
|
300
|
+
console.debug(message);
|
301
|
+
console.debug(e);
|
302
|
+
Cookies.remove(window.flashMessageCookie);
|
303
|
+
return;
|
304
|
+
}
|
305
|
+
|
306
|
+
let $flashMessage = $('#flash-message');
|
307
|
+
let alertClass;
|
308
|
+
switch(message.kind) {
|
309
|
+
case "error":
|
310
|
+
alertClass = "alert-danger";
|
311
|
+
break;
|
312
|
+
case "warning":
|
313
|
+
alertClass = "alert-warning";
|
314
|
+
break;
|
315
|
+
case "success":
|
316
|
+
alertClass = "alert-success";
|
317
|
+
break;
|
318
|
+
default:
|
319
|
+
alertClass = "alert-light";
|
320
|
+
}
|
321
|
+
|
322
|
+
$flashMessage.find('.message').text(message.message);
|
323
|
+
$flashMessage.addClass(alertClass).removeClass('d-none');
|
324
|
+
Cookies.remove(window.flashMessageCookie);
|
325
|
+
});
|
@@ -0,0 +1,2 @@
|
|
1
|
+
/*! js-cookie v3.0.5 | MIT */
|
2
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self,function(){var n=e.Cookies,o=e.Cookies=t();o.noConflict=function(){return e.Cookies=n,o}}())}(this,(function(){"use strict";function e(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)e[o]=n[o]}return e}var t=function t(n,o){function r(t,r,i){if("undefined"!=typeof document){"number"==typeof(i=e({},o,i)).expires&&(i.expires=new Date(Date.now()+864e5*i.expires)),i.expires&&(i.expires=i.expires.toUTCString()),t=encodeURIComponent(t).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var c="";for(var u in i)i[u]&&(c+="; "+u,!0!==i[u]&&(c+="="+i[u].split(";")[0]));return document.cookie=t+"="+n.write(r,t)+c}}return Object.create({set:r,get:function(e){if("undefined"!=typeof document&&(!arguments.length||e)){for(var t=document.cookie?document.cookie.split("; "):[],o={},r=0;r<t.length;r++){var i=t[r].split("="),c=i.slice(1).join("=");try{var u=decodeURIComponent(i[0]);if(o[u]=n.read(c,u),e===u)break}catch(e){}}return e?o[e]:o}},remove:function(t,n){r(t,"",e({},n,{expires:-1}))},withAttributes:function(n){return t(this.converter,e({},this.attributes,n))},withConverter:function(n){return t(e({},this.converter,n),this.attributes)}},{attributes:{value:Object.freeze(o)},converter:{value:Object.freeze(n)}})}({read:function(e){return'"'===e[0]&&(e=e.slice(1,-1)),e.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent)},write:function(e){return encodeURIComponent(e).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,decodeURIComponent)}},{path:"/"});return t}));
|
@@ -107,6 +107,18 @@ module PgEventstore
|
|
107
107
|
encoded_params = Rack::Utils.build_nested_query(ids: ids)
|
108
108
|
url("/delete_all_subscriptions?#{encoded_params}")
|
109
109
|
end
|
110
|
+
|
111
|
+
# @param global_position [Integer]
|
112
|
+
# @return [String]
|
113
|
+
def delete_event_url(global_position)
|
114
|
+
url("/delete_event/#{global_position}")
|
115
|
+
end
|
116
|
+
|
117
|
+
# @param stream_attrs [Hash]
|
118
|
+
# @return [String]
|
119
|
+
def delete_stream_url(stream_attrs)
|
120
|
+
url("/delete_stream/#{stream_attrs[:context]}/#{stream_attrs[:stream_name]}/#{stream_attrs[:stream_id]}")
|
121
|
+
end
|
110
122
|
end
|
111
123
|
end
|
112
124
|
end
|
@@ -165,3 +165,35 @@
|
|
165
165
|
</div>
|
166
166
|
</div>
|
167
167
|
</div>
|
168
|
+
|
169
|
+
<div class="modal fade" id="delete-event-modal" tabindex="-1" role="dialog" aria-labelledby="delete-event-modal" aria-hidden="true">
|
170
|
+
<div class="modal-dialog modal-dialog-centered" role="document">
|
171
|
+
<div class="modal-content">
|
172
|
+
<div class="modal-header">
|
173
|
+
<h5 class="modal-title">Delete Event</h5>
|
174
|
+
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
175
|
+
<span aria-hidden="true">×</span>
|
176
|
+
</button>
|
177
|
+
</div>
|
178
|
+
<div class="modal-body font-weight-bold text-break">
|
179
|
+
<h5>
|
180
|
+
You are about to delete Event on global position <span class="global-position-text"></span>. This action is irreversible. Continue?
|
181
|
+
</h5>
|
182
|
+
|
183
|
+
<form id="delete-event-form" data-parsley-validate="" class="form-horizontal form-label-left" novalidate="" method="POST">
|
184
|
+
<input type="hidden" name="data[force]" value="false">
|
185
|
+
<div class="checkbox">
|
186
|
+
<label>
|
187
|
+
<input type="checkbox" id="force-delete" name="data[force]" autocomplete="off" value="true">
|
188
|
+
Ignore limitations(see <a class="text-info" href="https://github.com/yousty/pg_eventstore/blob/main/docs/maintenance.md#deleting-an-event-in-a-large-stream" target="_blank" rel="noreferrer,nofollow">docs</a>).
|
189
|
+
</label>
|
190
|
+
</div>
|
191
|
+
</form>
|
192
|
+
</div>
|
193
|
+
<div class="modal-footer">
|
194
|
+
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
195
|
+
<button type="submit" class="btn btn-danger" form="delete-event-form">Delete</button>
|
196
|
+
</div>
|
197
|
+
</div>
|
198
|
+
</div>
|
199
|
+
</div>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<div class="form-row align-items-center">
|
2
2
|
<div class="col-11">
|
3
|
-
<select name="filter[events][]" class="form-control mb-2" data-placeholder="Event type" data-url="<%= url('/event_types_filtering') %>">
|
3
|
+
<select name="filter[events][]" class="form-control mb-2" data-placeholder="Event type" data-url="<%= url('/event_types_filtering') %>" autocomplete="off">
|
4
4
|
<option></option>
|
5
5
|
<% if event_type %>
|
6
6
|
<option value="<%= h event_type %>" selected><%= h event_type %></option>
|
@@ -16,8 +16,14 @@
|
|
16
16
|
</td>
|
17
17
|
<td><%= event.created_at.strftime('%F %T') %></td>
|
18
18
|
<td><%= event.id %></td>
|
19
|
-
<td
|
20
|
-
class="
|
19
|
+
<td>
|
20
|
+
<a href="javascript: void(0);" class="d-inline-block text-nowrap toggle-event-data">
|
21
|
+
JSON <i class="fa fa-eye"></i>
|
22
|
+
</a>
|
23
|
+
<a href="javascript: void(0);" class="ml-2 btn btn-danger btn-small delete-event-btn" data-global-position="<%= event.global_position %>" data-url="<%= delete_event_url(event.global_position) %>" data-toggle="modal" data-target="#delete-event-modal">
|
24
|
+
Delete
|
25
|
+
</a>
|
26
|
+
</td>
|
21
27
|
</tr>
|
22
28
|
<tr class="event-payload d-none">
|
23
29
|
<td colspan="8">
|
@@ -1,31 +1,36 @@
|
|
1
1
|
<div class="form-row align-items-center">
|
2
2
|
<div class="col-3">
|
3
|
-
<select name="filter[streams][][context]" class="form-control mb-2" data-placeholder="Context" data-url="<%= url('/stream_contexts_filtering') %>">
|
3
|
+
<select name="filter[streams][][context]" class="form-control mb-2" data-placeholder="Context" data-url="<%= url('/stream_contexts_filtering') %>" autocomplete="off">
|
4
4
|
<option></option>
|
5
5
|
<% if stream[:context] %>
|
6
6
|
<option value="<%= h stream[:context] %>" selected><%= h stream[:context] %></option>
|
7
7
|
<% end %>
|
8
8
|
</select>
|
9
9
|
</div>
|
10
|
-
<div class="col-
|
11
|
-
<select name="filter[streams][][stream_name]" class="form-control mb-2" data-placeholder="Stream name" data-url="<%= url('/stream_names_filtering') %>">
|
10
|
+
<div class="col-3">
|
11
|
+
<select name="filter[streams][][stream_name]" class="form-control mb-2" data-placeholder="Stream name" data-url="<%= url('/stream_names_filtering') %>" autocomplete="off">
|
12
12
|
<option></option>
|
13
13
|
<% if stream[:stream_name] %>
|
14
14
|
<option value="<%= h stream[:stream_name] %>" selected><%= h stream[:stream_name] %></option>
|
15
15
|
<% end %>
|
16
16
|
</select>
|
17
17
|
</div>
|
18
|
-
<div class="col-
|
19
|
-
<select name="filter[streams][][stream_id]" class="form-control mb-2" data-placeholder="Stream ID" data-url="<%= url('/stream_ids_filtering') %>">
|
18
|
+
<div class="col-3">
|
19
|
+
<select name="filter[streams][][stream_id]" class="form-control mb-2" data-placeholder="Stream ID" data-url="<%= url('/stream_ids_filtering') %>" autocomplete="off">
|
20
20
|
<option></option>
|
21
21
|
<% if stream[:stream_id] %>
|
22
22
|
<option value="<%= h stream[:stream_id] %>" selected><%= h stream[:stream_id] %></option>
|
23
23
|
<% end %>
|
24
24
|
</select>
|
25
25
|
</div>
|
26
|
-
<div class="col-
|
26
|
+
<div class="col-3">
|
27
27
|
<a class="btn btn-default remove-filter" href="javascript: void(0);">
|
28
28
|
<i class="fa fa-minus-circle"></i>
|
29
29
|
</a>
|
30
|
+
<% if stream[:context] && stream[:stream_name] && stream[:stream_id] %>
|
31
|
+
<a class="btn btn-danger btn-small delete-stream" data-confirm="You are about to delete all events in <%= h stream.inspect %> stream. This action is irreversible Continue?" data-confirm-title="Delete Stream" data-method="post" href="<%= delete_stream_url(stream) %>">
|
32
|
+
Delete stream
|
33
|
+
</a>
|
34
|
+
<% end %>
|
30
35
|
</div>
|
31
36
|
</div>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<div class="form-row align-items-center">
|
2
2
|
<div class="col-3">
|
3
|
-
<select name="filter[system_stream]" class="form-control mb-2" data-placeholder="Select system stream">
|
3
|
+
<select name="filter[system_stream]" class="form-control mb-2" data-placeholder="Select system stream" autocomplete="off">
|
4
4
|
<option></option>
|
5
5
|
<% PgEventstore::Stream::KNOWN_SYSTEM_STREAMS.each do |stream_name| %>
|
6
6
|
<option value="<%= stream_name %>" <% if stream == stream_name %> selected <% end %>><%= stream_name %></option>
|
@@ -95,6 +95,12 @@
|
|
95
95
|
</li>
|
96
96
|
</ul>
|
97
97
|
</nav>
|
98
|
+
<div class="alert alert-success alert-dismissible fade show text-center d-none" id="flash-message" role="alert">
|
99
|
+
<h5 class="text-dark message"></h5>
|
100
|
+
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
101
|
+
<span aria-hidden="true">×</span>
|
102
|
+
</button>
|
103
|
+
</div>
|
98
104
|
</div>
|
99
105
|
</div>
|
100
106
|
<!-- /top navigation -->
|
@@ -133,12 +139,18 @@
|
|
133
139
|
</div>
|
134
140
|
</div>
|
135
141
|
|
142
|
+
<script type="text/javascript">
|
143
|
+
window.flashMessageCookie = "<%= PgEventstore::Web::Application::COOKIES_FLASH_MESSAGE_KEY %>";
|
144
|
+
</script>
|
145
|
+
|
136
146
|
<!-- jQuery -->
|
137
147
|
<script src="<%= asset_url("javascripts/vendor/jquery.min.js") %>"></script>
|
138
148
|
<!-- Bootstrap -->
|
139
149
|
<script src="<%= asset_url("javascripts/vendor/bootstrap.bundle.min.js") %>"></script>
|
140
150
|
<script src="<%= asset_url("javascripts/vendor/select2.full.min.js") %>"></script>
|
141
151
|
|
152
|
+
<script src="<%= asset_url("javascripts/vendor/js.cookie.min.js") %>"></script>
|
153
|
+
|
142
154
|
<!-- Custom Theme Scripts -->
|
143
155
|
<script src="<%= asset_url("javascripts/gentelella.js") %>"></script>
|
144
156
|
<script src="<%= asset_url("javascripts/pg_eventstore.js") %>"></script>
|
data/lib/pg_eventstore.rb
CHANGED
@@ -11,7 +11,10 @@ require_relative 'pg_eventstore/event_class_resolver'
|
|
11
11
|
require_relative 'pg_eventstore/config'
|
12
12
|
require_relative 'pg_eventstore/event'
|
13
13
|
require_relative 'pg_eventstore/stream'
|
14
|
+
require_relative 'pg_eventstore/commands'
|
15
|
+
require_relative 'pg_eventstore/queries'
|
14
16
|
require_relative 'pg_eventstore/client'
|
17
|
+
require_relative 'pg_eventstore/maintenance'
|
15
18
|
require_relative 'pg_eventstore/connection'
|
16
19
|
require_relative 'pg_eventstore/errors'
|
17
20
|
require_relative 'pg_eventstore/middleware'
|
@@ -96,6 +99,12 @@ module PgEventstore
|
|
96
99
|
Client.new(config(name))
|
97
100
|
end
|
98
101
|
|
102
|
+
# @param name [Symbol]
|
103
|
+
# @return [PgEventstore::Maintenance]
|
104
|
+
def maintenance(name = DEFAULT_CONFIG)
|
105
|
+
Maintenance.new(config(name))
|
106
|
+
end
|
107
|
+
|
99
108
|
# @return [Logger, nil]
|
100
109
|
def logger
|
101
110
|
@logger
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module PgEventstore
|
2
|
+
module Commands
|
3
|
+
class DeleteEvent
|
4
|
+
MAX_RECORDS_TO_LOCK: Integer
|
5
|
+
|
6
|
+
def call: (PgEventstore::Event event, force: bool)-> bool
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def check_records_number_to_lock: (PgEventstore::Event event)-> void
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -113,4 +113,14 @@ module PgEventstore
|
|
113
113
|
|
114
114
|
attr_accessor event_types: ::Array[String]
|
115
115
|
end
|
116
|
+
|
117
|
+
class TooManyRecordsToLockError < PgEventstore::Error
|
118
|
+
def initialize: (PgEventstore::Stream stream, Integer number_of_records) -> void
|
119
|
+
|
120
|
+
attr_accessor stream: PgEventstore::Stream
|
121
|
+
|
122
|
+
attr_accessor number_of_records: Integer
|
123
|
+
|
124
|
+
def user_friendly_message: -> String
|
125
|
+
end
|
116
126
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module PgEventstore
|
2
|
+
class Maintenance
|
3
|
+
@config: PgEventstore::Config
|
4
|
+
|
5
|
+
attr_reader config: PgEventstore::Config
|
6
|
+
|
7
|
+
def initialize: (PgEventstore::Config config) -> void
|
8
|
+
|
9
|
+
def connection: () -> PgEventstore::Connection
|
10
|
+
|
11
|
+
def delete_event: (PgEventstore::Event event, ?force: bool)-> bool
|
12
|
+
|
13
|
+
def delete_stream: (PgEventstore::Stream stream)-> bool
|
14
|
+
|
15
|
+
def maintenance_queries: () -> PgEventstore::MaintenanceQueries
|
16
|
+
|
17
|
+
def transaction_queries: () -> PgEventstore::TransactionQueries
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module PgEventstore
|
2
|
+
class MaintenanceQueries
|
3
|
+
attr_reader connection: PgEventstore::Connection
|
4
|
+
|
5
|
+
def initialize: (PgEventstore::Connection connection)-> untyped
|
6
|
+
|
7
|
+
def adjust_stream_revisions: (PgEventstore::Stream stream, Integer after_revision)-> void
|
8
|
+
|
9
|
+
def delete_event: (PgEventstore::Event event)-> Integer
|
10
|
+
|
11
|
+
def delete_stream: (PgEventstore::Stream stream)-> Integer
|
12
|
+
|
13
|
+
def events_to_lock_count: (PgEventstore::Stream stream, Integer after_revision)-> Integer
|
14
|
+
|
15
|
+
def reload_event: (PgEventstore::Event event)-> PgEventstore::Event?
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def basic_deserializer: -> PgEventstore::EventDeserializer
|
20
|
+
end
|
21
|
+
end
|
@@ -2,6 +2,14 @@ module PgEventstore
|
|
2
2
|
class Queries
|
3
3
|
include PgEventstore::Extensions::OptionsExtension
|
4
4
|
|
5
|
+
attr_accessor events: PgEventstore::EventQueries?
|
6
|
+
|
7
|
+
attr_accessor partitions: PgEventstore::PartitionQueries?
|
8
|
+
|
9
|
+
attr_accessor transactions: PgEventstore::TransactionQueries?
|
10
|
+
|
11
|
+
attr_accessor maintenance: PgEventstore::MaintenanceQueries?
|
12
|
+
|
5
13
|
def initialize: (**untyped options) -> void
|
6
14
|
|
7
15
|
def options_hash: () -> ::Hash[untyped, untyped]
|
@@ -13,11 +21,5 @@ module PgEventstore
|
|
13
21
|
def readonly_error: (Symbol opt_name) -> void
|
14
22
|
|
15
23
|
def init_default_values: (::Hash[untyped, untyped] options) -> void
|
16
|
-
|
17
|
-
attr_accessor events: PgEventstore::EventQueries?
|
18
|
-
|
19
|
-
attr_accessor partitions: PgEventstore::PartitionQueries?
|
20
|
-
|
21
|
-
attr_accessor transactions: PgEventstore::TransactionQueries?
|
22
24
|
end
|
23
25
|
end
|
@@ -2,6 +2,7 @@ module PgEventstore
|
|
2
2
|
module Web
|
3
3
|
class Application
|
4
4
|
COOKIES_CONFIG_KEY: String
|
5
|
+
COOKIES_FLASH_MESSAGE_KEY: String
|
5
6
|
DEFAULT_ADMIN_UI_CONFIG: Symbol
|
6
7
|
|
7
8
|
def asset_url: (String path) -> String
|
@@ -14,6 +15,8 @@ module PgEventstore
|
|
14
15
|
|
15
16
|
def events_filter: -> Array[String]?
|
16
17
|
|
18
|
+
def flash_message=: (({ message: String, kind: String }) val)-> String
|
19
|
+
|
17
20
|
def h: (String text) -> String
|
18
21
|
|
19
22
|
def paginated_json_response: (PgEventstore::Web::Paginator::BaseCollection collection) -> void
|
@@ -2,6 +2,10 @@ module PgEventstore
|
|
2
2
|
module Web
|
3
3
|
module Subscriptions
|
4
4
|
module Helpers
|
5
|
+
def delete_event_url: (Integer global_position)-> String
|
6
|
+
|
7
|
+
def delete_stream_url: (({ context: String, stream_name: String, stream_id: String }) stream_attrs)-> String
|
8
|
+
|
5
9
|
# _@param_ `set_name`
|
6
10
|
def subscriptions_url: (?set_name: String?) -> String
|
7
11
|
|
data/sig/pg_eventstore.rbs
CHANGED
@@ -14,6 +14,8 @@ module PgEventstore
|
|
14
14
|
# _@param_ `name`
|
15
15
|
def self.connection: (?Symbol name) -> PgEventstore::Connection
|
16
16
|
|
17
|
+
def self.maintenance: (?Symbol name) -> PgEventstore::Maintenance
|
18
|
+
|
17
19
|
def self.subscriptions_manager: (
|
18
20
|
?Symbol config_name,
|
19
21
|
subscription_set: String,
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_eventstore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Dzyzenko
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-03-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- docs/events_and_streams.md
|
86
86
|
- docs/how_it_works.md
|
87
87
|
- docs/linking_events.md
|
88
|
+
- docs/maintenance.md
|
88
89
|
- docs/multiple_commands.md
|
89
90
|
- docs/reading_events.md
|
90
91
|
- docs/subscriptions.md
|
@@ -116,6 +117,8 @@ files:
|
|
116
117
|
- lib/pg_eventstore/client.rb
|
117
118
|
- lib/pg_eventstore/commands.rb
|
118
119
|
- lib/pg_eventstore/commands/append.rb
|
120
|
+
- lib/pg_eventstore/commands/delete_event.rb
|
121
|
+
- lib/pg_eventstore/commands/delete_stream.rb
|
119
122
|
- lib/pg_eventstore/commands/event_modifiers/prepare_link_event.rb
|
120
123
|
- lib/pg_eventstore/commands/event_modifiers/prepare_regular_event.rb
|
121
124
|
- lib/pg_eventstore/commands/link_to.rb
|
@@ -134,11 +137,13 @@ files:
|
|
134
137
|
- lib/pg_eventstore/extensions/callbacks_extension.rb
|
135
138
|
- lib/pg_eventstore/extensions/options_extension.rb
|
136
139
|
- lib/pg_eventstore/extensions/using_connection_extension.rb
|
140
|
+
- lib/pg_eventstore/maintenance.rb
|
137
141
|
- lib/pg_eventstore/middleware.rb
|
138
142
|
- lib/pg_eventstore/pg_connection.rb
|
139
143
|
- lib/pg_eventstore/queries.rb
|
140
144
|
- lib/pg_eventstore/queries/event_queries.rb
|
141
145
|
- lib/pg_eventstore/queries/links_resolver.rb
|
146
|
+
- lib/pg_eventstore/queries/maintenance_queries.rb
|
142
147
|
- lib/pg_eventstore/queries/partition_queries.rb
|
143
148
|
- lib/pg_eventstore/queries/transaction_queries.rb
|
144
149
|
- lib/pg_eventstore/query_builders/events_filtering.rb
|
@@ -208,6 +213,7 @@ files:
|
|
208
213
|
- lib/pg_eventstore/web/public/javascripts/vendor/bootstrap.bundle.min.js
|
209
214
|
- lib/pg_eventstore/web/public/javascripts/vendor/jquery.autocomplete.min.js
|
210
215
|
- lib/pg_eventstore/web/public/javascripts/vendor/jquery.min.js
|
216
|
+
- lib/pg_eventstore/web/public/javascripts/vendor/js.cookie.min.js
|
211
217
|
- lib/pg_eventstore/web/public/javascripts/vendor/select2.full.min.js
|
212
218
|
- lib/pg_eventstore/web/public/stylesheets/pg_eventstore.css
|
213
219
|
- lib/pg_eventstore/web/public/stylesheets/vendor/bootstrap.min.css
|
@@ -266,6 +272,8 @@ files:
|
|
266
272
|
- sig/pg_eventstore/cli/wait_for_subscriptions_set_shutdown.rbs
|
267
273
|
- sig/pg_eventstore/client.rbs
|
268
274
|
- sig/pg_eventstore/commands/append.rbs
|
275
|
+
- sig/pg_eventstore/commands/delete_event.rbs
|
276
|
+
- sig/pg_eventstore/commands/delete_stream.rbs
|
269
277
|
- sig/pg_eventstore/commands/event_modifiers/prepare_link_event.rbs
|
270
278
|
- sig/pg_eventstore/commands/event_modifiers/prepare_regular_event.rbs
|
271
279
|
- sig/pg_eventstore/commands/link_to.rbs
|
@@ -284,11 +292,13 @@ files:
|
|
284
292
|
- sig/pg_eventstore/extensions/callbacks_extension.rbs
|
285
293
|
- sig/pg_eventstore/extensions/options_extension.rbs
|
286
294
|
- sig/pg_eventstore/extensions/using_connection_extension.rbs
|
295
|
+
- sig/pg_eventstore/maintenance.rbs
|
287
296
|
- sig/pg_eventstore/middleware.rbs
|
288
297
|
- sig/pg_eventstore/pg_connection.rbs
|
289
298
|
- sig/pg_eventstore/queries.rbs
|
290
299
|
- sig/pg_eventstore/queries/event_queries.rbs
|
291
300
|
- sig/pg_eventstore/queries/links_resolver.rbs
|
301
|
+
- sig/pg_eventstore/queries/maintenance_queries.rbs
|
292
302
|
- sig/pg_eventstore/queries/partition_queries.rbs
|
293
303
|
- sig/pg_eventstore/queries/transaction_queries.rbs
|
294
304
|
- sig/pg_eventstore/query_builders/events_filtering_query.rbs
|