pg_eventstore 1.13.4 → 3.0.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/.rubocop.yml +11 -2
- data/CHANGELOG.md +195 -16
- data/README.md +33 -10
- data/db/migrations/10_setup_pg_cron.rb +1 -0
- data/db/migrations/11_add_events_link_global_position.sql +1 -0
- data/db/migrations/12_migrate_legacy_links.rb +83 -0
- data/db/migrations/13_remove_events_link_id.sql +6 -0
- data/db/migrations/14_remove_ids_events_id_index.sql +1 -0
- data/db/migrations/15_create_streams_global_index.sql +17 -0
- data/db/migrations/16_populate_streams_global_index.rb +150 -0
- data/db/migrations/17_create_events_global_index.sql +62 -0
- data/db/migrations/18_populate_events_global_index.rb +124 -0
- data/db/migrations/19_populate_events_global_index_p2.rb +25 -0
- data/db/migrations/20_migrate_subscriptions_current_position.sql +19 -0
- data/db/migrations/21_create_partitions_stats.sql +2 -0
- data/db/migrations/22_drop_streams_sql_view.sql +2 -0
- data/db/migrations/23_adjust_partitions_indexes.sql +5 -0
- data/db/migrations/24_drop_legacy_events_indexes.sql +3 -0
- data/db/migrations/25_add_parent_partitions_info_to_partitions.sql +16 -0
- data/db/migrations/26_change_events_stream_revision_type.rb +35 -0
- data/db/migrations/27_drop_events_horizon.sql +3 -0
- data/db/migrations/28_create_maintenance_tasks.sql +8 -0
- data/db/migrations/29_create_event_markers.sql +35 -0
- data/db/migrations/30_improve_partitions_search_in_admin_ui.rb +24 -0
- data/db/migrations/31_drop_events_id_default_value.sql +1 -0
- data/db/migrations/32_create_parittions_triggers.sql +101 -0
- data/db/migrations/9_create_events_horizon.sql +21 -0
- data/docs/AGENTS.fragment.md +696 -0
- data/docs/admin_ui.md +3 -1
- data/docs/appending_events.md +110 -49
- data/docs/configuration.md +69 -36
- data/docs/event_tracing.md +55 -0
- data/docs/events_and_streams.md +54 -30
- data/docs/how_it_works.md +57 -16
- data/docs/linking_events.md +2 -1
- data/docs/maintenance.md +14 -5
- data/docs/multiple_commands.md +30 -6
- data/docs/reading_events.md +208 -43
- data/docs/reading_streams.md +50 -0
- data/docs/replication.md +99 -0
- data/docs/subscriptions.md +165 -35
- data/docs/writing_middleware.md +25 -8
- data/ext/pg_eventstore_ext/extconf.rb +5 -0
- data/ext/pg_eventstore_ext/pg_eventstore_ext.c +74 -0
- data/lib/pg_eventstore/async_runner.rb +63 -0
- data/lib/pg_eventstore/basic_config.rb +15 -0
- data/lib/pg_eventstore/callbacks.rb +7 -5
- data/lib/pg_eventstore/chunks/chunk.rb +31 -0
- data/lib/pg_eventstore/chunks/read_api_events_index_chunk.rb +83 -0
- data/lib/pg_eventstore/chunks/replica_events_index_chunk.rb +35 -0
- data/lib/pg_eventstore/chunks/repository.rb +73 -0
- data/lib/pg_eventstore/chunks/subscription_checkpoint_chunk.rb +48 -0
- data/lib/pg_eventstore/chunks/subscription_events_index_chunk.rb +99 -0
- data/lib/pg_eventstore/chunks.rb +14 -0
- data/lib/pg_eventstore/cli/try_to_delete_subscriptions_set.rb +2 -2
- data/lib/pg_eventstore/client.rb +167 -52
- data/lib/pg_eventstore/commands/append.rb +62 -43
- data/lib/pg_eventstore/commands/delete_event.rb +7 -8
- data/lib/pg_eventstore/commands/delete_stream.rb +3 -3
- data/lib/pg_eventstore/commands/event_modifiers/prepare_link_event.rb +11 -6
- data/lib/pg_eventstore/commands/event_modifiers/prepare_regular_event.rb +12 -7
- data/lib/pg_eventstore/commands/link_to.rb +9 -9
- data/lib/pg_eventstore/commands/multiple.rb +2 -2
- data/lib/pg_eventstore/commands/read.rb +23 -5
- data/lib/pg_eventstore/commands/read_grouped.rb +46 -0
- data/lib/pg_eventstore/commands/read_streams.rb +18 -0
- data/lib/pg_eventstore/commands/read_streams_paginated.rb +56 -0
- data/lib/pg_eventstore/commands/regular_stream_read_paginated.rb +4 -4
- data/lib/pg_eventstore/commands/revision_check/current_revision.rb +51 -0
- data/lib/pg_eventstore/commands/revision_check/event_type_revisions_comparison.rb +46 -0
- data/lib/pg_eventstore/commands/revision_check/expected_revision.rb +135 -0
- data/lib/pg_eventstore/commands/revision_check/stream_revision_check.rb +98 -0
- data/lib/pg_eventstore/commands/revision_check/stream_revision_comparison.rb +36 -0
- data/lib/pg_eventstore/commands/stream_revision.rb +14 -0
- data/lib/pg_eventstore/commands/system_stream_read_paginated.rb +4 -4
- data/lib/pg_eventstore/commands.rb +4 -2
- data/lib/pg_eventstore/config.rb +30 -9
- data/lib/pg_eventstore/connection.rb +22 -37
- data/lib/pg_eventstore/errors.rb +137 -11
- data/lib/pg_eventstore/event.rb +39 -7
- data/lib/pg_eventstore/event_deserializer.rb +5 -4
- data/lib/pg_eventstore/event_global_index.rb +118 -0
- data/lib/pg_eventstore/event_marker.rb +16 -0
- data/lib/pg_eventstore/event_marker_index.rb +25 -0
- data/lib/pg_eventstore/event_serializer.rb +6 -0
- data/lib/pg_eventstore/extensions/acts_as_configurable.rb +88 -0
- data/lib/pg_eventstore/extensions/options_defaults.rb +25 -0
- data/lib/pg_eventstore/extensions/options_extension.rb +42 -13
- data/lib/pg_eventstore/feature_marker.rb +18 -0
- data/lib/pg_eventstore/maintenance.rb +11 -6
- data/lib/pg_eventstore/middleware/event_tracing.rb +53 -0
- data/lib/pg_eventstore/partition.rb +6 -0
- data/lib/pg_eventstore/pg_connection.rb +70 -14
- data/lib/pg_eventstore/queries/event_marker_queries.rb +74 -0
- data/lib/pg_eventstore/queries/event_queries.rb +9 -95
- data/lib/pg_eventstore/queries/events_global_index_queries.rb +131 -0
- data/lib/pg_eventstore/queries/index_filtering_queries.rb +179 -0
- data/lib/pg_eventstore/queries/links_resolver.rb +10 -7
- data/lib/pg_eventstore/queries/maintenance_queries.rb +159 -42
- data/lib/pg_eventstore/queries/partition_queries.rb +46 -104
- data/lib/pg_eventstore/queries/replica_queries.rb +110 -0
- data/lib/pg_eventstore/queries/streams_global_index_queries.rb +163 -0
- data/lib/pg_eventstore/queries/transaction_queries.rb +58 -10
- data/lib/pg_eventstore/queries.rb +29 -1
- data/lib/pg_eventstore/query_builders/basic_filtering.rb +38 -5
- data/lib/pg_eventstore/query_builders/event_markers_filtering.rb +47 -0
- data/lib/pg_eventstore/query_builders/event_markers_index_filtering.rb +275 -0
- data/lib/pg_eventstore/query_builders/event_subscription_positions_filtering.rb +37 -0
- data/lib/pg_eventstore/query_builders/events_filtering.rb +15 -164
- data/lib/pg_eventstore/query_builders/events_global_index_filtering.rb +227 -0
- data/lib/pg_eventstore/query_builders/filters/collection.rb +324 -0
- data/lib/pg_eventstore/query_builders/filters/event_type_filter.rb +37 -0
- data/lib/pg_eventstore/query_builders/filters/filter_row.rb +54 -0
- data/lib/pg_eventstore/query_builders/filters/marker_filter.rb +20 -0
- data/lib/pg_eventstore/query_builders/filters/marker_filter_row.rb +49 -0
- data/lib/pg_eventstore/query_builders/filters/stream_filter.rb +48 -0
- data/lib/pg_eventstore/query_builders/index_based_events_filtering.rb +260 -0
- data/lib/pg_eventstore/query_builders/partitions_filtering.rb +175 -51
- data/lib/pg_eventstore/query_builders/read_cursor/stream_cursor.rb +122 -0
- data/lib/pg_eventstore/query_builders/streams_global_index_filtering.rb +83 -0
- data/lib/pg_eventstore/query_builders/subscription_events_filtering.rb +79 -0
- data/lib/pg_eventstore/query_strategy/async.rb +64 -0
- data/lib/pg_eventstore/query_strategy/foreground.rb +25 -0
- data/lib/pg_eventstore/query_strategy.rb +19 -0
- data/lib/pg_eventstore/raw_event.rb +46 -0
- data/lib/pg_eventstore/rspec/test_helpers.rb +21 -8
- data/lib/pg_eventstore/sql_builder.rb +87 -8
- data/lib/pg_eventstore/stream.rb +14 -17
- data/lib/pg_eventstore/stream_global_index.rb +28 -0
- data/lib/pg_eventstore/subscriptions/basic_runner.rb +4 -4
- data/lib/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rb +5 -17
- data/lib/pg_eventstore/subscriptions/callback_handlers/events_subscription_position_worker_handlers.rb +36 -0
- data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rb +13 -1
- data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rb +19 -14
- data/lib/pg_eventstore/subscriptions/events_processor.rb +21 -19
- data/lib/pg_eventstore/subscriptions/events_processor_consumer/multiple.rb +63 -0
- data/lib/pg_eventstore/subscriptions/events_processor_consumer/replica.rb +68 -0
- data/lib/pg_eventstore/subscriptions/events_processor_consumer/single.rb +62 -0
- data/lib/pg_eventstore/subscriptions/events_processor_consumer.rb +44 -0
- data/lib/pg_eventstore/subscriptions/events_subscription_position_worker.rb +68 -0
- data/lib/pg_eventstore/subscriptions/queries/event_subscription_position_queries.rb +177 -0
- data/lib/pg_eventstore/subscriptions/queries/subscription_command_queries.rb +5 -5
- data/lib/pg_eventstore/subscriptions/queries/subscription_queries.rb +80 -56
- data/lib/pg_eventstore/subscriptions/queries/subscriptions_set_command_queries.rb +2 -2
- data/lib/pg_eventstore/subscriptions/queries/subscriptions_set_queries.rb +1 -1
- data/lib/pg_eventstore/subscriptions/replica_subscription_handler.rb +140 -0
- data/lib/pg_eventstore/subscriptions/replica_subscription_runner.rb +9 -0
- data/lib/pg_eventstore/subscriptions/subscription.rb +9 -7
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/collection.rb +36 -0
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/index_read_strategy.rb +82 -0
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/replication_strategy.rb +75 -0
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategy.rb +31 -0
- data/lib/pg_eventstore/subscriptions/subscription_feeder.rb +26 -2
- data/lib/pg_eventstore/subscriptions/subscription_handler_performance.rb +5 -5
- data/lib/pg_eventstore/subscriptions/subscription_runner.rb +20 -22
- data/lib/pg_eventstore/subscriptions/subscription_runner_commands/reset_position.rb +1 -1
- data/lib/pg_eventstore/subscriptions/subscription_runners_feeder.rb +10 -11
- data/lib/pg_eventstore/subscriptions/subscriptions_lifecycle.rb +0 -12
- data/lib/pg_eventstore/subscriptions/subscriptions_manager.rb +84 -29
- data/lib/pg_eventstore/{subscriptions/synchronized_array.rb → synchronized_array.rb} +15 -0
- data/lib/pg_eventstore/tasks/setup.rake +32 -33
- data/lib/pg_eventstore/utils.rb +39 -0
- data/lib/pg_eventstore/version.rb +1 -1
- data/lib/pg_eventstore/web/application.rb +104 -20
- data/lib/pg_eventstore/web/paginator/base_collection.rb +5 -1
- data/lib/pg_eventstore/web/paginator/event_types_collection.rb +14 -4
- data/lib/pg_eventstore/web/paginator/events_collection.rb +29 -33
- data/lib/pg_eventstore/web/paginator/helpers.rb +19 -12
- data/lib/pg_eventstore/web/paginator/markers_collection.rb +48 -0
- data/lib/pg_eventstore/web/paginator/stream_contexts_collection.rb +13 -2
- data/lib/pg_eventstore/web/paginator/stream_ids_collection.rb +21 -11
- data/lib/pg_eventstore/web/paginator/stream_names_collection.rb +18 -4
- data/lib/pg_eventstore/web/paginator/streams_collection.rb +95 -0
- data/lib/pg_eventstore/web/public/javascripts/pg_eventstore.js +49 -22
- data/lib/pg_eventstore/web/subscriptions/helpers.rb +2 -2
- data/lib/pg_eventstore/web/subscriptions/set_collection.rb +1 -1
- data/lib/pg_eventstore/web/subscriptions/subscriptions.rb +1 -1
- data/lib/pg_eventstore/web/subscriptions/with_state/set_collection.rb +1 -1
- data/lib/pg_eventstore/web/subscriptions/with_state/subscriptions.rb +1 -1
- data/lib/pg_eventstore/web/views/home/dashboard.erb +11 -9
- data/lib/pg_eventstore/web/views/home/partials/event_filter.erb +18 -5
- data/lib/pg_eventstore/web/views/home/partials/events.erb +38 -1
- data/lib/pg_eventstore/web/views/home/partials/markers_filter.erb +18 -0
- data/lib/pg_eventstore/web/views/layouts/application.erb +6 -0
- data/lib/pg_eventstore/web/views/streams/index.erb +110 -0
- data/lib/pg_eventstore/web/views/streams/partials/streams.erb +11 -0
- data/lib/pg_eventstore/web/views/subscriptions/index.erb +4 -1
- data/lib/pg_eventstore/web.rb +2 -0
- data/lib/pg_eventstore.rb +26 -63
- data/pg_eventstore.gemspec +6 -4
- data/sig/interfaces/_raw_events_handler.rbs +3 -0
- data/sig/interfaces/subscription_handler.rbs +1 -1
- data/sig/pg/result.rbs +9 -0
- data/sig/pg_eventstore/async_runner.rbs +13 -0
- data/sig/pg_eventstore/basic_config.rbs +9 -0
- data/sig/pg_eventstore/chunks/chunk.rbs +13 -0
- data/sig/pg_eventstore/chunks/read_api_events_index_chunk.rbs +30 -0
- data/sig/pg_eventstore/chunks/replica_events_index_chunk.rbs +11 -0
- data/sig/pg_eventstore/chunks/repository.rbs +22 -0
- data/sig/pg_eventstore/chunks/subscription_checkpoint_chunk.rbs +18 -0
- data/sig/pg_eventstore/chunks/subscription_events_index_chunk.rbs +37 -0
- data/sig/pg_eventstore/client.rbs +41 -43
- data/sig/pg_eventstore/commands/append.rbs +11 -25
- data/sig/pg_eventstore/commands/event_modifiers/prepare_link_event.rbs +9 -12
- data/sig/pg_eventstore/commands/event_modifiers/prepare_regular_event.rbs +5 -4
- data/sig/pg_eventstore/commands/link_to.rbs +6 -11
- data/sig/pg_eventstore/commands/multiple.rbs +1 -1
- data/sig/pg_eventstore/commands/read.rbs +2 -5
- data/sig/pg_eventstore/commands/read_grouped.rbs +7 -0
- data/sig/pg_eventstore/commands/read_streams.rbs +7 -0
- data/sig/pg_eventstore/commands/read_streams_paginated.rbs +16 -0
- data/sig/pg_eventstore/commands/regular_stream_read_paginated.rbs +9 -17
- data/sig/pg_eventstore/commands/revision_check/current_revision.rbs +25 -0
- data/sig/pg_eventstore/commands/revision_check/event_type_revisions_comparison.rbs +14 -0
- data/sig/pg_eventstore/commands/revision_check/expected_revision.rbs +67 -0
- data/sig/pg_eventstore/commands/revision_check/stream_revision_check.rbs +20 -0
- data/sig/pg_eventstore/commands/revision_check/stream_revision_comparison.rbs +9 -0
- data/sig/pg_eventstore/commands/stream_revision.rbs +7 -0
- data/sig/pg_eventstore/commands/system_stream_read_paginated.rbs +9 -14
- data/sig/pg_eventstore/config.rbs +15 -6
- data/sig/pg_eventstore/connection.rbs +11 -18
- data/sig/pg_eventstore/errors.rbs +64 -34
- data/sig/pg_eventstore/event.rbs +20 -6
- data/sig/pg_eventstore/event_deserializer.rbs +5 -10
- data/sig/pg_eventstore/event_global_index.rbs +60 -0
- data/sig/pg_eventstore/event_marker.rbs +9 -0
- data/sig/pg_eventstore/event_marker_index.rbs +12 -0
- data/sig/pg_eventstore/extensions/acts_as_configurable.rbs +29 -0
- data/sig/pg_eventstore/extensions/options_defaults.rbs +7 -0
- data/sig/pg_eventstore/extensions/options_extension.rbs +9 -1
- data/sig/pg_eventstore/feature_marker.rbs +10 -0
- data/sig/pg_eventstore/maintenance.rbs +12 -8
- data/sig/pg_eventstore/middleware/event_trace.rbs +14 -0
- data/sig/pg_eventstore/partition.rbs +2 -4
- data/sig/pg_eventstore/pg_connection.rbs +8 -0
- data/sig/pg_eventstore/queries/event_marker_queries.rbs +21 -0
- data/sig/pg_eventstore/queries/event_queries.rbs +6 -38
- data/sig/pg_eventstore/queries/events_global_index_queries.rbs +37 -0
- data/sig/pg_eventstore/queries/index_filtering_queries.rbs +50 -0
- data/sig/pg_eventstore/queries/links_resolver.rbs +7 -11
- data/sig/pg_eventstore/queries/maintenance_queries.rbs +12 -9
- data/sig/pg_eventstore/queries/partition_queries.rbs +32 -67
- data/sig/pg_eventstore/queries/replica_queries.rbs +31 -0
- data/sig/pg_eventstore/queries/streams_global_index_queries.rbs +39 -0
- data/sig/pg_eventstore/queries/transaction_queries.rbs +4 -2
- data/sig/pg_eventstore/queries.rbs +11 -21
- data/sig/pg_eventstore/query_builders/basic_filtering.rbs +10 -3
- data/sig/pg_eventstore/query_builders/event_markers_filtering.rbs +17 -0
- data/sig/pg_eventstore/query_builders/event_markers_index_filtering.rbs +69 -0
- data/sig/pg_eventstore/query_builders/event_subscription_positions_filtering.rbs +15 -0
- data/sig/pg_eventstore/query_builders/events_filtering_query.rbs +9 -51
- data/sig/pg_eventstore/query_builders/events_global_index_filtering.rbs +68 -0
- data/sig/pg_eventstore/query_builders/filters/collection.rbs +84 -0
- data/sig/pg_eventstore/query_builders/filters/event_type_filter.rbs +19 -0
- data/sig/pg_eventstore/query_builders/filters/filter_row.rbs +21 -0
- data/sig/pg_eventstore/query_builders/filters/marker_filter.rbs +13 -0
- data/sig/pg_eventstore/query_builders/filters/marker_filter_row.rbs +19 -0
- data/sig/pg_eventstore/query_builders/filters/stream_filter.rbs +24 -0
- data/sig/pg_eventstore/query_builders/index_based_events_filtering.rbs +60 -0
- data/sig/pg_eventstore/query_builders/partitions_filtering.rbs +29 -10
- data/sig/pg_eventstore/query_builders/read_cursor/stream_cursor.rbs +47 -0
- data/sig/pg_eventstore/query_builders/streams_global_index_filtering.rbs +27 -0
- data/sig/pg_eventstore/query_builders/subscription_events_filtering.rbs +26 -0
- data/sig/pg_eventstore/query_strategy/async.rbs +17 -0
- data/sig/pg_eventstore/query_strategy/foreground.rbs +11 -0
- data/sig/pg_eventstore/query_strategy.rbs +7 -0
- data/sig/pg_eventstore/raw_event.rbs +20 -0
- data/sig/pg_eventstore/sql_builder.rbs +32 -10
- data/sig/pg_eventstore/stream.rbs +10 -18
- data/sig/pg_eventstore/stream_global_index.rbs +14 -0
- data/sig/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rbs +5 -4
- data/sig/pg_eventstore/subscriptions/callback_handlers/events_subscription_position_worker_handlers.rbs +9 -0
- data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rbs +17 -12
- data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rbs +16 -8
- data/sig/pg_eventstore/subscriptions/event_subscription_position_queries.rbs +30 -0
- data/sig/pg_eventstore/subscriptions/events_processor.rbs +12 -5
- data/sig/pg_eventstore/subscriptions/events_processor_consumer/multiple.rbs +17 -0
- data/sig/pg_eventstore/subscriptions/events_processor_consumer/replica.rbs +17 -0
- data/sig/pg_eventstore/subscriptions/events_processor_consumer/single.rbs +17 -0
- data/sig/pg_eventstore/subscriptions/events_processor_consumer.rbs +14 -0
- data/sig/pg_eventstore/subscriptions/events_subscription_position_worker.rbs +28 -0
- data/sig/pg_eventstore/subscriptions/queries/subscription_queries.rbs +18 -50
- data/sig/pg_eventstore/subscriptions/replica_subscription_handler.rbs +33 -0
- data/sig/pg_eventstore/subscriptions/replica_subscription_runner.rbs +4 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/collection.rbs +14 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/index_read_strategy.rbs +23 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/replication_strategy.rbs +23 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy.rbs +11 -0
- data/sig/pg_eventstore/subscriptions/subscription_feeder.rbs +13 -10
- data/sig/pg_eventstore/subscriptions/subscription_handler_performance.rbs +1 -1
- data/sig/pg_eventstore/subscriptions/subscription_runner.rbs +13 -5
- data/sig/pg_eventstore/subscriptions/subscription_runners_feeder.rbs +5 -5
- data/sig/pg_eventstore/subscriptions/subscriptions_lifecycle.rbs +4 -6
- data/sig/pg_eventstore/subscriptions/subscriptions_manager.rbs +29 -43
- data/sig/pg_eventstore/synchronized_array.rbs +4 -0
- data/sig/pg_eventstore/utils.rbs +18 -11
- data/sig/pg_eventstore/web/application.rbs +13 -3
- data/sig/pg_eventstore/web/paginator/base_collection.rbs +2 -0
- data/sig/pg_eventstore/web/paginator/event_types_collection.rbs +4 -0
- data/sig/pg_eventstore/web/paginator/events_collection.rbs +11 -11
- data/sig/pg_eventstore/web/paginator/helpers.rbs +6 -15
- data/sig/pg_eventstore/web/paginator/markers_collection.rbs +13 -0
- data/sig/pg_eventstore/web/paginator/stream_contexts_collection.rbs +4 -0
- data/sig/pg_eventstore/web/paginator/stream_names_collection.rbs +4 -0
- data/sig/pg_eventstore/web/paginator/streams_collection.rbs +30 -0
- data/sig/pg_eventstore.rbs +8 -26
- metadata +181 -21
- data/lib/pg_eventstore/commands/all_stream_read_grouped.rb +0 -69
- data/lib/pg_eventstore/commands/regular_stream_read_grouped.rb +0 -31
- data/lib/pg_eventstore/subscriptions/queries/service_queries.rb +0 -73
- data/lib/pg_eventstore/subscriptions/subscription_position_evaluation.rb +0 -195
- data/lib/pg_eventstore/web/views/home/partials/system_stream_filter.erb +0 -15
- data/sig/pg_eventstore/commands/all_stream_read_grouped.rbs +0 -16
- data/sig/pg_eventstore/commands/regular_stream_read_grouped.rbs +0 -8
- data/sig/pg_eventstore/subscriptions/queries/service_queries.rbs +0 -15
- data/sig/pg_eventstore/subscriptions/subscription_position_evaluation.rbs +0 -53
- data/sig/pg_eventstore/subscriptions/synchronized_array.rbs +0 -4
- /data/sig/interfaces/{_raw_event_handler.rbs → raw_event_handler.rbs} +0 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
# @!visibility private
|
|
5
|
+
class EventsGlobalIndexQueries
|
|
6
|
+
# @!attribute connection
|
|
7
|
+
# @return [PgEventstore::Connection]
|
|
8
|
+
attr_reader :connection
|
|
9
|
+
private :connection
|
|
10
|
+
|
|
11
|
+
# @param connection [PgEventstore::Connection]
|
|
12
|
+
# @param query_strategy [PgEventstore::QueryStrategy]
|
|
13
|
+
def initialize(connection, query_strategy)
|
|
14
|
+
@connection = connection
|
|
15
|
+
@query_strategy = query_strategy
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @param raw_events [Array<Hash>]
|
|
19
|
+
# @param affected_partitions [Array<PgEventstore::Partition>]
|
|
20
|
+
# @param stream_index_id [Integer]
|
|
21
|
+
# @return [Array<PgEventstore::EventGlobalIndex::WriteApiRepr>]
|
|
22
|
+
def index_events(raw_events, affected_partitions, stream_index_id)
|
|
23
|
+
partitions = affected_partitions.to_h { [_1.event_type, _1] }
|
|
24
|
+
values = raw_events.map do |event_attrs|
|
|
25
|
+
values = [
|
|
26
|
+
event_attrs['global_position'],
|
|
27
|
+
event_attrs['stream_revision'],
|
|
28
|
+
partitions[event_attrs['type']].parent_context_partition_id,
|
|
29
|
+
partitions[event_attrs['type']].parent_stream_name_partition_id,
|
|
30
|
+
partitions[event_attrs['type']].id,
|
|
31
|
+
stream_index_id,
|
|
32
|
+
]
|
|
33
|
+
"(#{values.join(', ')})"
|
|
34
|
+
end
|
|
35
|
+
values = values.join(',')
|
|
36
|
+
|
|
37
|
+
result = @query_strategy.exec(<<~SQL)
|
|
38
|
+
INSERT INTO events_global_index
|
|
39
|
+
("global_position", "stream_revision", "context_partition_id", "stream_name_partition_id",
|
|
40
|
+
"event_type_partition_id", "streams_global_index_id")
|
|
41
|
+
VALUES #{values}
|
|
42
|
+
RETURNING global_position, stream_revision, event_type_partition_id
|
|
43
|
+
SQL
|
|
44
|
+
# "returning" statement has no guarantees about the order in which rows are returned. Thus, sort them explicitly
|
|
45
|
+
deserialize(result, repr: EventGlobalIndex::ReprType::WRITE_API).sort_by(&:stream_revision)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @param grouped_opts [Hash]
|
|
49
|
+
# @return [Hash<Integer, Array<PgEventstore::SubscriptionRepr>>]
|
|
50
|
+
def fetch_indexes_for_subscriptions(grouped_opts)
|
|
51
|
+
builders = grouped_opts.map do |subscription_id, opts|
|
|
52
|
+
filter = QueryBuilders::SubscriptionEventsFiltering.build(subscription_id, opts)
|
|
53
|
+
filter.to_sql_builder.select("#{subscription_id} as subscription_id")
|
|
54
|
+
end
|
|
55
|
+
final_builder = SQLBuilder.union_builders(builders)
|
|
56
|
+
res = @query_strategy.exec_params(*final_builder.to_exec_params)
|
|
57
|
+
res = res.group_by { _1['subscription_id'] }
|
|
58
|
+
res.to_h do |sid, indexes|
|
|
59
|
+
[
|
|
60
|
+
sid,
|
|
61
|
+
indexes.map do |attrs|
|
|
62
|
+
EventGlobalIndex::SubscriptionRepr.new(**attrs.except('subscription_id').transform_keys(&:to_sym))
|
|
63
|
+
end,
|
|
64
|
+
]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @param indexes [Array<EventGlobalIndex::ReadApiRepr>, Array<EventGlobalIndex::SubscriptionRepr>]
|
|
69
|
+
# @param resolve_link_tos [Boolean]
|
|
70
|
+
# @param direction [String, Symbol, nil]
|
|
71
|
+
# @return [Array<Hash>]
|
|
72
|
+
def resolve_indexes(indexes, resolve_link_tos:, direction: nil)
|
|
73
|
+
indexes = indexes.group_by(&:event_type_partition_id)
|
|
74
|
+
partitions = partition_queries.find_by_ids(indexes.keys).to_h { [_1['id'], _1] }
|
|
75
|
+
builders = indexes.map do |partition_id, idxs|
|
|
76
|
+
partition = partitions[partition_id]
|
|
77
|
+
events_filtering = QueryBuilders::EventsFiltering.new
|
|
78
|
+
events_filtering.add_stream_attrs(context: partition['context'], stream_name: partition['stream_name'])
|
|
79
|
+
events_filtering.add_event_types([partition['event_type']])
|
|
80
|
+
builder = events_filtering.to_sql_builder
|
|
81
|
+
builder.where('global_position = ANY(?)', idxs.map(&:global_position))
|
|
82
|
+
end
|
|
83
|
+
main_builder = SQLBuilder.union_builders(builders)
|
|
84
|
+
with_sorted_events = SQLBuilder.new.select('*').from(main_builder)
|
|
85
|
+
if direction
|
|
86
|
+
with_sorted_events.order("global_position #{QueryBuilders::BasicFiltering::SQL_DIRECTIONS[direction]}")
|
|
87
|
+
end
|
|
88
|
+
raw_events = @query_strategy.exec_params(*with_sorted_events.to_exec_params).to_a
|
|
89
|
+
resolve_link_tos ? links_resolver.resolve(raw_events) : raw_events
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @return [Integer, nil]
|
|
93
|
+
def max_global_position
|
|
94
|
+
builder = SQLBuilder.new.from(QueryBuilders::EventsGlobalIndexFiltering::PRIMARY_TABLE_NAME)
|
|
95
|
+
builder.select('max(global_position) as max_global_position')
|
|
96
|
+
@query_strategy.exec_params(*builder.to_exec_params).first['max_global_position']
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Takes an array of potentially persisted events and loads their ids from db. Those ids can be later used to check
|
|
100
|
+
# whether events are actually existing events.
|
|
101
|
+
# @param events [Array<PgEventstore::Event>]
|
|
102
|
+
# @return [Array<Integer>]
|
|
103
|
+
def global_positions_from_db(events)
|
|
104
|
+
builder = SQLBuilder.new.from(QueryBuilders::EventsGlobalIndexFiltering::PRIMARY_TABLE_NAME)
|
|
105
|
+
builder.where('global_position = ANY(?::bigint[])', events.map(&:global_position))
|
|
106
|
+
@query_strategy.exec_params(*builder.to_exec_params).map { _1['global_position'] }
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
# @return [PgEventstore::PartitionQueries]
|
|
112
|
+
def partition_queries
|
|
113
|
+
PartitionQueries.new(connection)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @return [PgEventstore::LinksResolver]
|
|
117
|
+
def links_resolver
|
|
118
|
+
LinksResolver.new(connection, @query_strategy)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# @param repr [Symbol, nil]
|
|
122
|
+
# @return [Array<PgEventstore::EventGlobalIndex>, Array<PgEventstore::EventGlobalIndex::SubscriptionRepr>,
|
|
123
|
+
# Array<PgEventstore::EventGlobalIndex::ReadApiRepr>, Array<PgEventstore::EventGlobalIndex::WriteApiRepr>,
|
|
124
|
+
# Array<PgEventstore::EventGlobalIndex::RevisionCheckRepr>]
|
|
125
|
+
def deserialize(pg_result, repr: nil)
|
|
126
|
+
pg_result.map do |attrs|
|
|
127
|
+
EventGlobalIndex.create_representation(attrs.transform_keys(&:to_sym), repr:)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
class IndexFilteringQueries
|
|
5
|
+
# @!attribute connection
|
|
6
|
+
# @return [PgEventstore::Connection]
|
|
7
|
+
attr_reader :connection
|
|
8
|
+
private :connection
|
|
9
|
+
|
|
10
|
+
# @param connection [PgEventstore::Connection]
|
|
11
|
+
# @param query_strategy [PgEventstore::QueryStrategy]
|
|
12
|
+
def initialize(connection, query_strategy)
|
|
13
|
+
@connection = connection
|
|
14
|
+
@query_strategy = query_strategy
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @param stream [PgEventstore::Stream]
|
|
18
|
+
# @param expected_revisions [Array<PgEventstore::Commands::RevisionCheck::ExpectedRevision::EventTypeRevision,
|
|
19
|
+
# PgEventstore::Commands::RevisionCheck::ExpectedRevision::EventTypeRevisionWithMarkers,
|
|
20
|
+
# PgEventstore::Commands::RevisionCheck::ExpectedRevision::MarkersRevision>]
|
|
21
|
+
# @return [Array<PgEventstore::EventGlobalIndex::RevisionCheckRepr>]
|
|
22
|
+
def fetch_indexes_for_revision_validation(stream, expected_revisions)
|
|
23
|
+
builders = expected_revisions.map do |expected_revision|
|
|
24
|
+
case expected_revision
|
|
25
|
+
when Commands::RevisionCheck::ExpectedRevision::EventTypeRevision
|
|
26
|
+
QueryBuilders::IndexBasedEventsFiltering.sql_builder_for_event_type_revision_validation(
|
|
27
|
+
stream, expected_revision
|
|
28
|
+
)
|
|
29
|
+
when Commands::RevisionCheck::ExpectedRevision::EventTypeRevisionWithMarkers
|
|
30
|
+
QueryBuilders::IndexBasedEventsFiltering.sql_builder_for_event_type_with_markers_revision_validation(
|
|
31
|
+
stream, expected_revision
|
|
32
|
+
)
|
|
33
|
+
when Commands::RevisionCheck::ExpectedRevision::MarkersRevision
|
|
34
|
+
QueryBuilders::IndexBasedEventsFiltering.sql_builder_for_markers_revision_validation(
|
|
35
|
+
stream, expected_revision
|
|
36
|
+
)
|
|
37
|
+
else
|
|
38
|
+
Utils.missing_implementation!(expected_revision)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
final = SQLBuilder.union_builders(builders)
|
|
42
|
+
deserialize(@query_strategy.exec_params(*final.to_exec_params), repr: EventGlobalIndex::ReprType::REVISION_CHECK)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @param filters_collection [PgEventstore::QueryBuilders::Filters::Collection]
|
|
46
|
+
# @param cursor [PgEventstore::QueryBuilders::ReadCursor::StreamCursor]
|
|
47
|
+
# @return [Array<PgEventstore::EventGlobalIndex::ReadApiRepr>]
|
|
48
|
+
def fetch_indexes_for_read_api(filters_collection, cursor)
|
|
49
|
+
filter_rows =
|
|
50
|
+
if filters_collection.collection.any?(&:ambiguous_event_type?)
|
|
51
|
+
expand_event_types(filters_collection)
|
|
52
|
+
else
|
|
53
|
+
filters_collection.collection
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
sql_builder = QueryBuilders::IndexBasedEventsFiltering.sql_builder_for_read_common(filter_rows, cursor)
|
|
57
|
+
deserialize(@query_strategy.exec_params(*sql_builder.to_exec_params), repr: EventGlobalIndex::ReprType::READ_API)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @param filters_collection [PgEventstore::QueryBuilders::Filters::Collection]
|
|
61
|
+
# @param cursor [PgEventstore::QueryBuilders::ReadCursor::StreamCursor]
|
|
62
|
+
# @return [Array<PgEventstore::EventGlobalIndex::ReadApiRepr>]
|
|
63
|
+
def fetch_grouped_indexes_for_read_api(filters_collection, cursor)
|
|
64
|
+
filter_rows =
|
|
65
|
+
if filters_collection.collection.any?(&:ambiguous_event_type?)
|
|
66
|
+
expand_event_types(filters_collection)
|
|
67
|
+
else
|
|
68
|
+
filters_collection.collection
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
sql_builder = QueryBuilders::IndexBasedEventsFiltering.sql_builder_for_read_grouped(filter_rows, cursor)
|
|
72
|
+
deserialize(@query_strategy.exec_params(*sql_builder.to_exec_params), repr: EventGlobalIndex::ReprType::READ_API)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @param indexes [Array<PgEventstore::EventGlobalIndex::ReadApiRepr>]
|
|
76
|
+
# @param resolve_link_tos [Boolean]
|
|
77
|
+
# @return [PgEventstore::Chunks::Repository]
|
|
78
|
+
def compute_read_api_chunks_repo(indexes, resolve_link_tos)
|
|
79
|
+
repo = Chunks::Repository.new
|
|
80
|
+
repo.add_chunk(Chunks::ReadApiEventsIndexChunk.new(indexes, connection, @query_strategy, resolve_link_tos))
|
|
81
|
+
repo
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
# @return [PgEventstore::PartitionQueries]
|
|
87
|
+
def partition_queries
|
|
88
|
+
PartitionQueries.new(connection)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @param filters_collection [PgEventstore::QueryBuilders::Filters::Collection]
|
|
92
|
+
# @return [Array<PgEventstore::QueryBuilders::Filters::FilterRow>]
|
|
93
|
+
def expand_event_types(filters_collection)
|
|
94
|
+
filter_rows = filters_collection.collection
|
|
95
|
+
to_expand = filter_rows.select(&:ambiguous_event_type?)
|
|
96
|
+
rest_filter_rows = filter_rows - to_expand
|
|
97
|
+
partition_builders = to_expand.map do |filter_row|
|
|
98
|
+
partitions_filtering = QueryBuilders::PartitionsFiltering.new
|
|
99
|
+
partitions_filtering.with_event_types
|
|
100
|
+
filter_row = filter_row.to_filter_row if filter_row.is_a?(QueryBuilders::Filters::MarkerFilterRow)
|
|
101
|
+
partitions_filtering.add_filter_row(filter_row)
|
|
102
|
+
partitions_filtering.to_sql_builder.unselect.select('context, stream_name, event_type')
|
|
103
|
+
end
|
|
104
|
+
final_partition_builder = SQLBuilder.union_builders(partition_builders)
|
|
105
|
+
expanded_partitions_list = @query_strategy.exec_params(*final_partition_builder.to_exec_params)
|
|
106
|
+
expanded_partitions_list = expanded_partitions_list.group_by { _1['event_type'] }
|
|
107
|
+
expanded_filter_rows =
|
|
108
|
+
to_expand.flat_map do |filter_row|
|
|
109
|
+
case filter_row
|
|
110
|
+
when QueryBuilders::Filters::FilterRow
|
|
111
|
+
filter_row.event_type_filters.flat_map do |event_type_filter|
|
|
112
|
+
related_partitions =
|
|
113
|
+
if event_type_filter.prefix?
|
|
114
|
+
expanded_partitions_list.select do |event_type, _|
|
|
115
|
+
event_type.start_with?(event_type_filter.event_type)
|
|
116
|
+
end.values.flatten
|
|
117
|
+
else
|
|
118
|
+
expanded_partitions_list[event_type_filter.event_type]
|
|
119
|
+
end
|
|
120
|
+
next [] unless related_partitions
|
|
121
|
+
|
|
122
|
+
if filter_row.stream_filter
|
|
123
|
+
related_partitions = related_partitions.select do |attrs|
|
|
124
|
+
if filter_row.stream_filter.context?
|
|
125
|
+
attrs['context'] == filter_row.stream_filter.context
|
|
126
|
+
else
|
|
127
|
+
attrs['context'] == filter_row.stream_filter.context &&
|
|
128
|
+
attrs['stream_name'] == filter_row.stream_filter.stream_name
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
related_partitions.map do |partition_attrs|
|
|
133
|
+
stream_filter = QueryBuilders::Filters::StreamFilter.new(
|
|
134
|
+
context: partition_attrs['context'],
|
|
135
|
+
stream_name: partition_attrs['stream_name']
|
|
136
|
+
)
|
|
137
|
+
event_type_filter = QueryBuilders::Filters::EventTypeFilter.new(
|
|
138
|
+
event_type: partition_attrs['event_type'], prefix: false
|
|
139
|
+
)
|
|
140
|
+
QueryBuilders::Filters::FilterRow.new(stream_filter:, event_type_filters: [event_type_filter])
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
when QueryBuilders::Filters::MarkerFilterRow
|
|
144
|
+
related_partitions = expanded_partitions_list[filter_row.marker_filter.event_type]
|
|
145
|
+
next [] unless related_partitions
|
|
146
|
+
|
|
147
|
+
if filter_row.stream_filter
|
|
148
|
+
related_partitions = related_partitions.select do |attrs|
|
|
149
|
+
attrs['context'] == filter_row.stream_filter.context
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
related_partitions.map do |partition_attrs|
|
|
153
|
+
stream_filter = QueryBuilders::Filters::StreamFilter.new(
|
|
154
|
+
context: partition_attrs['context'],
|
|
155
|
+
stream_name: partition_attrs['stream_name']
|
|
156
|
+
)
|
|
157
|
+
QueryBuilders::Filters::MarkerFilterRow.new(stream_filter:, marker_filter: filter_row.marker_filter.dup)
|
|
158
|
+
end
|
|
159
|
+
else
|
|
160
|
+
Utils.missing_implementation!(filter_row)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
adjusted_rows = expanded_filter_rows + rest_filter_rows
|
|
164
|
+
return [QueryBuilders::Filters::FilterRow.null_filter_row] if adjusted_rows.empty?
|
|
165
|
+
|
|
166
|
+
adjusted_rows
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# @param repr [Symbol, nil]
|
|
170
|
+
# @return [Array<PgEventstore::EventGlobalIndex>, Array<PgEventstore::EventGlobalIndex::SubscriptionRepr>,
|
|
171
|
+
# Array<PgEventstore::EventGlobalIndex::ReadApiRepr>, Array<PgEventstore::EventGlobalIndex::WriteApiRepr>,
|
|
172
|
+
# Array<PgEventstore::EventGlobalIndex::RevisionCheckRepr>]
|
|
173
|
+
def deserialize(pg_result, repr: nil)
|
|
174
|
+
pg_result.map do |attrs|
|
|
175
|
+
EventGlobalIndex.create_representation(attrs.transform_keys(&:to_sym), repr:)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -9,8 +9,10 @@ module PgEventstore
|
|
|
9
9
|
private :connection
|
|
10
10
|
|
|
11
11
|
# @param connection [PgEventstore::Connection]
|
|
12
|
-
|
|
12
|
+
# @param query_strategy [PgEventstore::QueryStrategy]
|
|
13
|
+
def initialize(connection, query_strategy)
|
|
13
14
|
@connection = connection
|
|
15
|
+
@query_strategy = query_strategy
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
# Takes an array of events, look for link events in there and replaces link events with original events
|
|
@@ -20,9 +22,9 @@ module PgEventstore
|
|
|
20
22
|
link_events = raw_events.select { _1['link_partition_id'] }.group_by { _1['link_partition_id'] }
|
|
21
23
|
return raw_events if link_events.empty?
|
|
22
24
|
|
|
23
|
-
original_events = load_original_events(link_events).to_h { |attrs| [attrs['
|
|
25
|
+
original_events = load_original_events(link_events).to_h { |attrs| [attrs['global_position'], attrs] }
|
|
24
26
|
raw_events.map do |attrs|
|
|
25
|
-
original_event = original_events[attrs['
|
|
27
|
+
original_event = original_events[attrs['link_global_position']]
|
|
26
28
|
next attrs unless original_event
|
|
27
29
|
|
|
28
30
|
original_event.merge('link' => attrs).merge(attrs.except(*original_event.keys))
|
|
@@ -37,15 +39,16 @@ module PgEventstore
|
|
|
37
39
|
partitions = partition_queries.find_by_ids(link_events.keys)
|
|
38
40
|
sql_builders = partitions.map do |partition|
|
|
39
41
|
sql_builder = SQLBuilder.new.select('*').from(partition['table_name'])
|
|
40
|
-
sql_builder.where(
|
|
42
|
+
sql_builder.where(
|
|
43
|
+
'global_position = ANY(?::bigint[])',
|
|
44
|
+
link_events[partition['id']].map { _1['link_global_position'] }
|
|
45
|
+
)
|
|
41
46
|
end
|
|
42
47
|
sql_builder = sql_builders[1..].each_with_object(sql_builders.first) do |builder, top_builder|
|
|
43
48
|
top_builder.union(builder)
|
|
44
49
|
end
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
conn.exec_params(*sql_builder.to_exec_params)
|
|
48
|
-
end.to_a
|
|
51
|
+
@query_strategy.exec_params(*sql_builder.to_exec_params).to_a
|
|
49
52
|
end
|
|
50
53
|
|
|
51
54
|
# @return [PgEventstore::PartitionQueries]
|
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
module PgEventstore
|
|
4
4
|
# @!visibility private
|
|
5
5
|
class MaintenanceQueries
|
|
6
|
+
# @return [Integer]
|
|
7
|
+
EVENT_INDEXES_TO_REMOVE_PER_QUERY = 10_000
|
|
8
|
+
# @return [Integer]
|
|
9
|
+
EVENT_INDEXES_TO_UPDATE_PER_QUERY = 10_000
|
|
10
|
+
|
|
6
11
|
# @!attribute connection
|
|
7
12
|
# @return [PgEventstore::Connection]
|
|
8
13
|
attr_reader :connection
|
|
@@ -13,36 +18,155 @@ module PgEventstore
|
|
|
13
18
|
@connection = connection
|
|
14
19
|
end
|
|
15
20
|
|
|
21
|
+
# TODO: refactor me. Reason: fatty
|
|
16
22
|
# @param stream [PgEventstore::Stream]
|
|
17
23
|
# @return [Integer] number of deleted events of the given stream
|
|
18
24
|
def delete_stream(stream)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
total_removed = 0
|
|
26
|
+
transaction_queries.transaction(:read_committed) do
|
|
27
|
+
stream_global_idx = streams_global_index_queries.find_by!(stream)
|
|
28
|
+
streams_global_index_queries.delete(stream_global_idx.id)
|
|
29
|
+
global_position = 1
|
|
30
|
+
loop do
|
|
31
|
+
deleted_events_global_index = connection.with do |conn|
|
|
32
|
+
conn.exec_params(<<~SQL, [stream_global_idx.id, global_position, EVENT_INDEXES_TO_REMOVE_PER_QUERY]).to_a
|
|
33
|
+
delete from events_global_index
|
|
34
|
+
where global_position in (
|
|
35
|
+
select global_position from events_global_index
|
|
36
|
+
where streams_global_index_id = $1 and global_position >= $2
|
|
37
|
+
order by global_position asc
|
|
38
|
+
limit $3
|
|
39
|
+
)
|
|
40
|
+
returning event_type_partition_id, global_position
|
|
41
|
+
SQL
|
|
42
|
+
end
|
|
43
|
+
break if deleted_events_global_index.empty?
|
|
44
|
+
|
|
45
|
+
global_position = deleted_events_global_index.last['global_position'] + 1
|
|
46
|
+
total_removed += deleted_events_global_index.size
|
|
47
|
+
deleted_events_global_index = deleted_events_global_index.group_by { _1['event_type_partition_id'] }
|
|
48
|
+
partitions = partition_queries.find_by_ids(deleted_events_global_index.keys).to_h { [_1['id'], _1] }
|
|
49
|
+
queries = deleted_events_global_index.map do |partition_id, idxs|
|
|
50
|
+
partition = partitions[partition_id]
|
|
51
|
+
positions = idxs.map { _1['global_position'] }.join(', ')
|
|
52
|
+
context = PG::Connection.escape(partition['context'])
|
|
53
|
+
stream_name = PG::Connection.escape(partition['stream_name'])
|
|
54
|
+
event_type = PG::Connection.escape(partition['event_type'])
|
|
55
|
+
<<~SQL
|
|
56
|
+
delete from events
|
|
57
|
+
where context = '#{context}' and stream_name = '#{stream_name}' and type = '#{event_type}'
|
|
58
|
+
and global_position in (#{positions});
|
|
59
|
+
delete from event_subscription_positions where global_position in (#{positions});
|
|
60
|
+
delete from event_subscription_positions_unprocessed where global_position in (#{positions});
|
|
61
|
+
delete from event_markers_index where global_position in (#{positions});
|
|
62
|
+
SQL
|
|
63
|
+
end
|
|
64
|
+
connection.with do |conn|
|
|
65
|
+
conn.exec(queries.join("\n"))
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
total_removed
|
|
24
70
|
end
|
|
25
71
|
|
|
72
|
+
# TODO: refactor me. Reason: fatty
|
|
26
73
|
# @param event [PgEventstore::Event]
|
|
27
|
-
# @return [
|
|
74
|
+
# @return [void]
|
|
28
75
|
def delete_event(event)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
76
|
+
stream = event.stream
|
|
77
|
+
transaction_queries.transaction(:read_commited) do
|
|
78
|
+
stream_global_idx = streams_global_index_queries.find_by!(stream)
|
|
79
|
+
current_stream_revision = connection.with do |conn|
|
|
80
|
+
conn.exec_params(
|
|
81
|
+
'select stream_revision from streams_global_index where id = $1 for update', [stream_global_idx.id]
|
|
82
|
+
)
|
|
83
|
+
end.to_a.first['stream_revision']
|
|
84
|
+
exists =
|
|
85
|
+
connection.with do |conn|
|
|
86
|
+
conn.exec_params(<<~SQL, [event.global_position]).first&.[]('one') == 1
|
|
87
|
+
select 1 as one from events_global_index where global_position = $1
|
|
88
|
+
SQL
|
|
89
|
+
end
|
|
90
|
+
raise RecordNotFound.new('events_global_index', event.global_position) unless exists
|
|
91
|
+
# We are deleting the only event. Thus, we should delete the whole stream
|
|
92
|
+
return delete_stream(stream) if current_stream_revision == 0
|
|
35
93
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
94
|
+
deleted_event = connection.with do |conn|
|
|
95
|
+
conn.exec_params(<<~SQL, [stream_global_idx.id, event.global_position]).to_a.first
|
|
96
|
+
delete from events_global_index where streams_global_index_id = $1 and global_position = $2
|
|
97
|
+
returning global_position, event_type_partition_id, stream_revision
|
|
98
|
+
SQL
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
affected_partition = partition_queries.find_by_ids([deleted_event['event_type_partition_id']]).first
|
|
102
|
+
connection.with do |conn|
|
|
103
|
+
delete_args = [
|
|
104
|
+
affected_partition['context'],
|
|
105
|
+
affected_partition['stream_name'],
|
|
106
|
+
affected_partition['event_type'],
|
|
107
|
+
deleted_event['global_position'],
|
|
108
|
+
]
|
|
109
|
+
conn.exec_params(<<~SQL, delete_args)
|
|
110
|
+
with _1 as (delete from events where context = $1 and stream_name = $2 and type = $3 and global_position = $4),
|
|
111
|
+
_2 as (delete from event_subscription_positions where global_position = $4),
|
|
112
|
+
_3 as (delete from event_subscription_positions_unprocessed where global_position = $4),
|
|
113
|
+
_4 as (delete from event_markers_index where global_position = $4)
|
|
114
|
+
select 1;
|
|
115
|
+
SQL
|
|
116
|
+
end
|
|
117
|
+
first_updated_event = nil
|
|
118
|
+
stream_revision = deleted_event['stream_revision']
|
|
119
|
+
loop do
|
|
120
|
+
updated_events = connection.with do |conn|
|
|
121
|
+
conn.exec_params(<<~SQL, [stream_global_idx.id, stream_revision, EVENT_INDEXES_TO_UPDATE_PER_QUERY]).to_a
|
|
122
|
+
update event_markers_index set stream_revision = stream_revision - 1
|
|
123
|
+
where global_position in (
|
|
124
|
+
select global_position from events_global_index
|
|
125
|
+
where streams_global_index_id = $1 and stream_revision > $2
|
|
126
|
+
order by stream_revision asc
|
|
127
|
+
limit $3
|
|
128
|
+
)
|
|
129
|
+
SQL
|
|
130
|
+
conn.exec_params(<<~SQL, [stream_global_idx.id, stream_revision, EVENT_INDEXES_TO_UPDATE_PER_QUERY]).to_a
|
|
131
|
+
update events_global_index set stream_revision = stream_revision - 1
|
|
132
|
+
where global_position in (
|
|
133
|
+
select global_position from events_global_index
|
|
134
|
+
where streams_global_index_id = $1 and stream_revision > $2
|
|
135
|
+
order by stream_revision asc
|
|
136
|
+
limit $3
|
|
137
|
+
)
|
|
138
|
+
returning event_type_partition_id, global_position, stream_revision
|
|
139
|
+
SQL
|
|
140
|
+
end
|
|
141
|
+
first_updated_event ||= updated_events.min_by { _1['stream_revision'] }
|
|
142
|
+
break if updated_events.empty?
|
|
143
|
+
|
|
144
|
+
stream_revision += updated_events.size
|
|
145
|
+
updated_events = updated_events.group_by { _1['event_type_partition_id'] }
|
|
146
|
+
partitions = partition_queries.find_by_ids(updated_events.keys).to_h { [_1['id'], _1] }
|
|
147
|
+
queries = updated_events.flat_map do |partition_id, idxs|
|
|
148
|
+
partition = partitions[partition_id]
|
|
149
|
+
context = PG::Connection.escape(partition['context'])
|
|
150
|
+
stream_name = PG::Connection.escape(partition['stream_name'])
|
|
151
|
+
event_type = PG::Connection.escape(partition['event_type'])
|
|
152
|
+
idxs.map do |idx|
|
|
153
|
+
<<~SQL
|
|
154
|
+
update events set stream_revision = #{idx['stream_revision']}
|
|
155
|
+
where context = '#{context}' and stream_name = '#{stream_name}' and type = '#{event_type}' and
|
|
156
|
+
global_position = #{idx['global_position']};
|
|
157
|
+
SQL
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
connection.with do |conn|
|
|
161
|
+
conn.exec(queries.join("\n"))
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
stream_idx_attrs_to_update = { stream_revision: current_stream_revision - 1 }
|
|
165
|
+
# Adjust starting_position in case zero revision event was deleted
|
|
166
|
+
if deleted_event['stream_revision'] == 0
|
|
167
|
+
stream_idx_attrs_to_update[:starting_position] = first_updated_event['global_position']
|
|
168
|
+
end
|
|
169
|
+
streams_global_index_queries.update(stream_global_idx.id, **stream_idx_attrs_to_update)
|
|
46
170
|
end
|
|
47
171
|
end
|
|
48
172
|
|
|
@@ -50,32 +174,25 @@ module PgEventstore
|
|
|
50
174
|
# @param after_revision [Integer]
|
|
51
175
|
# @return [Integer]
|
|
52
176
|
def events_to_lock_count(stream, after_revision)
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
177
|
+
stream_index = streams_global_index_queries.find_by!(stream)
|
|
178
|
+
stream_index.stream_revision - after_revision
|
|
59
179
|
end
|
|
60
180
|
|
|
61
|
-
|
|
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
|
|
181
|
+
private
|
|
70
182
|
|
|
71
|
-
|
|
183
|
+
# @return [PgEventstore::StreamsGlobalIndexQueries]
|
|
184
|
+
def streams_global_index_queries
|
|
185
|
+
StreamsGlobalIndexQueries.new(connection, QueryStrategy::Foreground.new(connection))
|
|
72
186
|
end
|
|
73
187
|
|
|
74
|
-
|
|
188
|
+
# @return [PgEventstore::TransactionQueries]
|
|
189
|
+
def transaction_queries
|
|
190
|
+
TransactionQueries.new(connection)
|
|
191
|
+
end
|
|
75
192
|
|
|
76
|
-
# @return [PgEventstore::
|
|
77
|
-
def
|
|
78
|
-
|
|
193
|
+
# @return [PgEventstore::PartitionQueries]
|
|
194
|
+
def partition_queries
|
|
195
|
+
PartitionQueries.new(connection)
|
|
79
196
|
end
|
|
80
197
|
end
|
|
81
198
|
end
|