pg_eventstore 2.0.0 → 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 +10 -1
- data/CHANGELOG.md +186 -20
- data/README.md +25 -15
- data/db/migrations/10_setup_pg_cron.rb +1 -23
- 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/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 +17 -8
- 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/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/client.rb +163 -50
- 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 +9 -7
- data/lib/pg_eventstore/commands/event_modifiers/prepare_regular_event.rb +12 -7
- data/lib/pg_eventstore/commands/link_to.rb +5 -5
- 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 +21 -2
- data/lib/pg_eventstore/errors.rb +136 -10
- data/lib/pg_eventstore/event.rb +34 -2
- 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 +2 -2
- 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 +7 -93
- 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 +4 -4
- data/lib/pg_eventstore/queries/maintenance_queries.rb +159 -42
- data/lib/pg_eventstore/queries/partition_queries.rb +45 -103
- 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 +52 -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 +13 -16
- data/lib/pg_eventstore/stream_global_index.rb +28 -0
- 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 +12 -0
- data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rb +21 -7
- data/lib/pg_eventstore/subscriptions/events_processor.rb +20 -18
- 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_queries.rb +78 -54
- 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 +2 -1
- 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 +24 -0
- data/lib/pg_eventstore/subscriptions/subscription_handler_performance.rb +4 -2
- data/lib/pg_eventstore/subscriptions/subscription_runner.rb +20 -9
- data/lib/pg_eventstore/subscriptions/subscription_runner_commands/reset_position.rb +1 -1
- data/lib/pg_eventstore/subscriptions/subscription_runners_feeder.rb +9 -18
- data/lib/pg_eventstore/subscriptions/subscriptions_lifecycle.rb +0 -12
- data/lib/pg_eventstore/subscriptions/subscriptions_manager.rb +74 -14
- data/lib/pg_eventstore/{subscriptions/synchronized_array.rb → synchronized_array.rb} +15 -0
- data/lib/pg_eventstore/tasks/setup.rake +2 -2
- data/lib/pg_eventstore/utils.rb +31 -0
- data/lib/pg_eventstore/version.rb +1 -1
- data/lib/pg_eventstore/web/application.rb +100 -16
- 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 +16 -9
- 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/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 +23 -60
- 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 +40 -42
- 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/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 +16 -2
- 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/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 +4 -36
- 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 +5 -9
- 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 +2 -0
- 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 +17 -6
- 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 +7 -39
- 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 -2
- data/sig/pg_eventstore/subscriptions/subscription_runners_feeder.rbs +1 -8
- 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 +10 -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 +175 -20
- data/Dockerfile +0 -3
- 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/subscription_service_queries.rb +0 -78
- 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/subscription_service_queries.rbs +0 -19
- 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,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
module Middleware
|
|
5
|
+
class EventTracing
|
|
6
|
+
include Middleware
|
|
7
|
+
|
|
8
|
+
# @return [String]
|
|
9
|
+
CAUSATION_ID_KEY = "#{Event::SYSTEM_SYMBOL}CaId".freeze
|
|
10
|
+
# @return [String]
|
|
11
|
+
CORRELATION_ID_KEY = "#{Event::SYSTEM_SYMBOL}CoId".freeze
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
# @param marker [String]
|
|
15
|
+
# @return [PgEventstore::FeatureMarker]
|
|
16
|
+
def causation_marker(marker)
|
|
17
|
+
FeatureMarker.new(marker:, purpose: :causation_id, description: 'Causation ID')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @param marker [String]
|
|
21
|
+
# @return [PgEventstore::FeatureMarker]
|
|
22
|
+
def correlation_marker(marker)
|
|
23
|
+
FeatureMarker.new(marker:, purpose: :correlation_id, description: 'Correlation ID')
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def serialize(event)
|
|
28
|
+
if event.caused_by
|
|
29
|
+
event.causation_id = event.caused_by.id.dup
|
|
30
|
+
event.metadata[CAUSATION_ID_KEY] = event.causation_id
|
|
31
|
+
event.feature_markers.push(self.class.causation_marker(event.causation_id))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
event.correlation_id = event.caused_by&.correlation_id&.dup || SecureRandom.uuid_v7
|
|
35
|
+
event.metadata[CORRELATION_ID_KEY] = event.correlation_id
|
|
36
|
+
event.feature_markers.push(self.class.correlation_marker(event.correlation_id))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# rubocop:disable Style/GuardClause
|
|
40
|
+
def deserialize(event)
|
|
41
|
+
if event.metadata[CAUSATION_ID_KEY]
|
|
42
|
+
event.causation_id = event.metadata[CAUSATION_ID_KEY]
|
|
43
|
+
event.feature_markers.push(self.class.causation_marker(event.causation_id))
|
|
44
|
+
end
|
|
45
|
+
if event.metadata[CORRELATION_ID_KEY]
|
|
46
|
+
event.correlation_id = event.metadata[CORRELATION_ID_KEY]
|
|
47
|
+
event.feature_markers.push(self.class.correlation_marker(event.correlation_id))
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
# rubocop:enable Style/GuardClause
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -19,5 +19,11 @@ module PgEventstore
|
|
|
19
19
|
# @!attribute table_name
|
|
20
20
|
# @return [String]
|
|
21
21
|
option(:table_name)
|
|
22
|
+
# @!attribute parent_context_partition_id
|
|
23
|
+
# @return [Integer, nil]
|
|
24
|
+
option(:parent_context_partition_id)
|
|
25
|
+
# @!attribute parent_stream_name_partition_id
|
|
26
|
+
# @return [Integer, nil]
|
|
27
|
+
option(:parent_stream_name_partition_id)
|
|
22
28
|
end
|
|
23
29
|
end
|
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
module PgEventstore
|
|
4
4
|
# @!visibility private
|
|
5
5
|
class PgConnection < PG::Connection
|
|
6
|
+
PLACEHOLDER_RE = /
|
|
7
|
+
'(?:''|[^'])*' | # string literal
|
|
8
|
+
"(?:""|[^"])*" | # quoted identifier
|
|
9
|
+
--[^\n]* | # line comment
|
|
10
|
+
\/\*.*?\*\/ | # block comment
|
|
11
|
+
\$\$.*?\$\$ | # dollar-quoted string. E.g. $$ $1 $$
|
|
12
|
+
\$(?<__dq_tag>[A-Za-z_][A-Za-z_0-9]*)\$.*?\$\k<__dq_tag>\$ | # named dollar-quoted string. E.g. $foo$ $1 $foo$
|
|
13
|
+
(?<placeholder>\$(?:[1-9]\d*)) # placeholder we are interested in
|
|
14
|
+
/mx
|
|
15
|
+
private_constant :PLACEHOLDER_RE
|
|
16
|
+
|
|
6
17
|
def exec(sql)
|
|
7
18
|
log(sql, [])
|
|
8
19
|
super
|
|
@@ -13,37 +24,82 @@ module PgEventstore
|
|
|
13
24
|
super
|
|
14
25
|
end
|
|
15
26
|
|
|
16
|
-
|
|
27
|
+
def send_query_params(sql, params)
|
|
28
|
+
log(sql, params)
|
|
29
|
+
super
|
|
30
|
+
end
|
|
17
31
|
|
|
18
|
-
def
|
|
19
|
-
|
|
32
|
+
def send_query(sql)
|
|
33
|
+
log(sql, [])
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# This is a partial copy-paste of https://github.com/ged/ruby-pg/pull/726. Because maintainers think it is too risky
|
|
38
|
+
# to accept those changes because of possible sql injections in the long run - I copy-pasted it here and simplified
|
|
39
|
+
# for pg_eventstore use cases.
|
|
40
|
+
# Why is it safe for pg_eventstore? The main concern there is that if new string literal would be introduced in some
|
|
41
|
+
# future PostgreSQL version - the implementation would become vulnerable to sql injections in case that new string
|
|
42
|
+
# literal is used in queries along with #compile. Because pg_eventstore uses only two forms of string literals
|
|
43
|
+
# (those are $$ my string $$ and 'my string') - we are totally safe. Also, there is only one place so far where this
|
|
44
|
+
# method is used(create subscription table function) - all other places use exec/exec_params. To conclude: careful
|
|
45
|
+
# usage + very low risk of future exposure to sql injections makes the usage of this method acceptable for
|
|
46
|
+
# pg_eventstore.
|
|
47
|
+
#
|
|
48
|
+
# Compiles your prepared SQL statement and the given positional arguments into plain SQL string.
|
|
49
|
+
#
|
|
50
|
+
# The resulting SQL string can be used with +conn.exec+ like the prepared SQL statement and parameters with
|
|
51
|
+
# +conn.exec_params+. +conn.exec_params+ is usually preferred because it's faster and safer.
|
|
52
|
+
#
|
|
53
|
+
# Example:
|
|
54
|
+
# res = conn.compile('SELECT $1 AS a, $2 AS b, $3 AS c', [1, 2, nil])
|
|
55
|
+
# # => "SELECT '1' AS a, '2' AS b, NULL AS c"
|
|
56
|
+
# @param sql [String]
|
|
57
|
+
# @param params [Array]
|
|
58
|
+
# @return [String]
|
|
59
|
+
def compile(sql, params)
|
|
60
|
+
return sql if params.empty?
|
|
20
61
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
62
|
+
sql.gsub(PLACEHOLDER_RE).each do |matched|
|
|
63
|
+
placeholder = Regexp.last_match[:placeholder]
|
|
64
|
+
# Do not replace non-positional args string and pass it as is
|
|
65
|
+
next matched unless placeholder
|
|
66
|
+
|
|
67
|
+
prepared_value(params[placeholder[1..].to_i - 1])
|
|
27
68
|
end
|
|
28
|
-
PgEventstore.logger.debug(sql)
|
|
29
69
|
end
|
|
30
70
|
|
|
71
|
+
# Converts the given object into its PostgreSQL representation
|
|
72
|
+
def prepared_value(value)
|
|
73
|
+
value = encode_value(value)
|
|
74
|
+
normalize_value(value)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
31
79
|
def encode_value(value)
|
|
32
80
|
encoder = type_map_for_queries[value.class]
|
|
33
81
|
return type_map_for_queries.send(encoder, value).encode(value) if encoder.is_a?(Symbol)
|
|
82
|
+
# format == 1 stands for binary format
|
|
83
|
+
return value if encoder.nil? || encoder.format == 1
|
|
34
84
|
|
|
35
|
-
|
|
85
|
+
encoder.encode(value)
|
|
36
86
|
end
|
|
37
87
|
|
|
38
88
|
def normalize_value(value)
|
|
39
89
|
case value
|
|
40
|
-
when
|
|
41
|
-
|
|
90
|
+
when TrueClass, FalseClass
|
|
91
|
+
value.to_s
|
|
42
92
|
when NilClass
|
|
43
93
|
'NULL'
|
|
44
94
|
else
|
|
45
|
-
value
|
|
95
|
+
"'#{escape(value.to_s)}'"
|
|
46
96
|
end
|
|
47
97
|
end
|
|
98
|
+
|
|
99
|
+
def log(sql, params)
|
|
100
|
+
return unless PgEventstore.logger&.debug?
|
|
101
|
+
|
|
102
|
+
PgEventstore.logger.debug(compile(sql, params))
|
|
103
|
+
end
|
|
48
104
|
end
|
|
49
105
|
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
# @!visibility private
|
|
5
|
+
class EventMarkerQueries
|
|
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 names [Array<String>]
|
|
19
|
+
# @return [Array<PgEventstore::EventMarker>]
|
|
20
|
+
def find_or_create_by(names)
|
|
21
|
+
builder = QueryBuilders::EventMarkersFiltering.sql_builder_by_names(names)
|
|
22
|
+
existing = @query_strategy.exec_params(*builder.to_exec_params)
|
|
23
|
+
existing = deserialize(existing)
|
|
24
|
+
rest = names - existing.map(&:name)
|
|
25
|
+
return existing if rest.empty?
|
|
26
|
+
|
|
27
|
+
values = rest.map do |name|
|
|
28
|
+
"('#{PG::Connection.escape(name)}')"
|
|
29
|
+
end.join(',')
|
|
30
|
+
table_name = QueryBuilders::EventMarkersFiltering::PRIMARY_TABLE_NAME
|
|
31
|
+
rest = @query_strategy.exec(<<~SQL)
|
|
32
|
+
insert into #{table_name} ("name") values #{values} returning *
|
|
33
|
+
SQL
|
|
34
|
+
existing + deserialize(rest)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @param stream_idx_id [Integer]
|
|
38
|
+
# @param write_api_events_index [Array<PgEventstore::EventGlobalIndex::WriteApiRepr>]
|
|
39
|
+
# @param revision_to_marker_ids_map [Hash<Integer, Set<Integer>>]
|
|
40
|
+
# @return [void]
|
|
41
|
+
def create_indexes(stream_idx_id, write_api_events_index, revision_to_marker_ids_map)
|
|
42
|
+
offset = write_api_events_index.first.stream_revision
|
|
43
|
+
values = revision_to_marker_ids_map.flat_map do |stream_revision, marker_ids|
|
|
44
|
+
event_index = write_api_events_index[stream_revision - offset]
|
|
45
|
+
marker_ids.map do |marker_id|
|
|
46
|
+
values = [
|
|
47
|
+
marker_id,
|
|
48
|
+
stream_idx_id,
|
|
49
|
+
event_index.global_position,
|
|
50
|
+
event_index.stream_revision,
|
|
51
|
+
event_index.event_type_partition_id,
|
|
52
|
+
]
|
|
53
|
+
"(#{values.join(',')})"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
values = values.join(', ')
|
|
57
|
+
table_name = QueryBuilders::EventMarkersIndexFiltering::PRIMARY_TABLE_NAME
|
|
58
|
+
@query_strategy.exec(<<~SQL)
|
|
59
|
+
insert into #{table_name}
|
|
60
|
+
("marker_id", "streams_global_index_id", "global_position", "stream_revision", "event_type_partition_id")
|
|
61
|
+
values
|
|
62
|
+
#{values}
|
|
63
|
+
SQL
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
# @param pg_result [PG::Result]
|
|
69
|
+
# @return [Array<PgEventstore::EventMarker>]
|
|
70
|
+
def deserialize(pg_result)
|
|
71
|
+
pg_result.map { EventMarker.new(**_1.transform_keys(&:to_sym)) }
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -6,82 +6,16 @@ module PgEventstore
|
|
|
6
6
|
# @!attribute connection
|
|
7
7
|
# @return [PgEventstore::Connection]
|
|
8
8
|
attr_reader :connection
|
|
9
|
-
|
|
10
|
-
# @return [PgEventstore::EventSerializer]
|
|
11
|
-
attr_reader :serializer
|
|
12
|
-
# @!attribute deserializer
|
|
13
|
-
# @return [PgEventstore::EventDeserializer]
|
|
14
|
-
attr_reader :deserializer
|
|
15
|
-
private :connection, :serializer, :deserializer
|
|
9
|
+
private :connection
|
|
16
10
|
|
|
17
11
|
# @param connection [PgEventstore::Connection]
|
|
18
|
-
|
|
19
|
-
# @param deserializer [PgEventstore::EventDeserializer]
|
|
20
|
-
def initialize(connection, serializer, deserializer)
|
|
12
|
+
def initialize(connection)
|
|
21
13
|
@connection = connection
|
|
22
|
-
@serializer = serializer
|
|
23
|
-
@deserializer = deserializer
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# @param event [PgEventstore::Event]
|
|
27
|
-
# @return [Boolean]
|
|
28
|
-
def event_exists?(event)
|
|
29
|
-
return false if event.id.nil? || event.stream.nil?
|
|
30
|
-
|
|
31
|
-
sql_builder = SQLBuilder.new.select('1 as exists').from(Event::PRIMARY_TABLE_NAME).where('id = ?', event.id)
|
|
32
|
-
sql_builder.limit(1)
|
|
33
|
-
sql_builder.where(
|
|
34
|
-
'context = ? and stream_name = ? and type = ?', event.stream.context, event.stream.stream_name, event.type
|
|
35
|
-
)
|
|
36
|
-
connection.with do |conn|
|
|
37
|
-
conn.exec_params(*sql_builder.to_exec_params)
|
|
38
|
-
end.to_a.dig(0, 'exists') == 1
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Takes an array of potentially persisted events and loads their ids from db. Those ids can be later used to check
|
|
42
|
-
# whether events are actually existing events.
|
|
43
|
-
# @param events [Array<PgEventstore::Event>]
|
|
44
|
-
# @return [Array<Integer>]
|
|
45
|
-
def global_positions_from_db(events)
|
|
46
|
-
sql_builder = SQLBuilder.new.from(Event::PRIMARY_TABLE_NAME).select('global_position')
|
|
47
|
-
partition_attrs = events.map { |event| [event.stream&.context, event.stream&.stream_name, event.type] }.uniq
|
|
48
|
-
partition_attrs.each do |context, stream_name, event_type|
|
|
49
|
-
sql_builder.where_or('context = ? and stream_name = ? and type = ?', context, stream_name, event_type)
|
|
50
|
-
end
|
|
51
|
-
sql_builder.where('global_position = ANY(?::bigint[])', events.map(&:global_position))
|
|
52
|
-
raw_events = PgEventstore.connection.with do |conn|
|
|
53
|
-
conn.exec_params(*sql_builder.to_exec_params)
|
|
54
|
-
end.to_a
|
|
55
|
-
raw_events.map { |attrs| attrs['global_position'] }
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# @param stream [PgEventstore::Stream]
|
|
59
|
-
# @return [Integer, nil]
|
|
60
|
-
def stream_revision(stream)
|
|
61
|
-
sql_builder = SQLBuilder.new.from(Event::PRIMARY_TABLE_NAME).select('stream_revision')
|
|
62
|
-
sql_builder.where('context = ? and stream_name = ? and stream_id = ?', *stream.to_a)
|
|
63
|
-
sql_builder.order('stream_revision DESC').limit(1)
|
|
64
|
-
connection.with do |conn|
|
|
65
|
-
conn.exec_params(*sql_builder.to_exec_params)
|
|
66
|
-
end.to_a.dig(0, 'stream_revision')
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# @see PgEventstore::Client#read for more info
|
|
70
|
-
# @param stream [PgEventstore::Stream]
|
|
71
|
-
# @param options [Hash]
|
|
72
|
-
# @return [Array<PgEventstore::Event>]
|
|
73
|
-
def stream_events(stream, options)
|
|
74
|
-
exec_params = QueryBuilders::EventsFiltering.events_filtering(stream, options).to_exec_params
|
|
75
|
-
raw_events = connection.with do |conn|
|
|
76
|
-
conn.exec_params(*exec_params)
|
|
77
|
-
end.to_a
|
|
78
|
-
raw_events = links_resolver.resolve(raw_events) if options[:resolve_link_tos]
|
|
79
|
-
deserializer.deserialize_many(raw_events)
|
|
80
14
|
end
|
|
81
15
|
|
|
82
16
|
# @param stream [PgEventstore::Stream]
|
|
83
17
|
# @param events [Array<PgEventstore::Event>]
|
|
84
|
-
# @return [Array<
|
|
18
|
+
# @return [Array<Hash>]
|
|
85
19
|
def insert(stream, events)
|
|
86
20
|
sql_rows_for_insert, values = prepared_statements(stream, events)
|
|
87
21
|
columns = %w[id data metadata stream_revision link_global_position link_partition_id type context stream_name stream_id]
|
|
@@ -92,30 +26,11 @@ module PgEventstore
|
|
|
92
26
|
RETURNING *
|
|
93
27
|
SQL
|
|
94
28
|
|
|
95
|
-
|
|
29
|
+
result = connection.with do |conn|
|
|
96
30
|
conn.exec_params(sql, values)
|
|
97
31
|
end
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# @param stream [PgEventstore::Stream]
|
|
104
|
-
# @param options_by_event_type [Array<Hash>] a set of options per an event type
|
|
105
|
-
# @param options [Hash]
|
|
106
|
-
# @option options [Boolean] :resolve_link_tos
|
|
107
|
-
# @return [Array<PgEventstore::Event>]
|
|
108
|
-
def grouped_events(stream, options_by_event_type, **options)
|
|
109
|
-
builders = options_by_event_type.map do |filter|
|
|
110
|
-
QueryBuilders::EventsFiltering.events_filtering(stream, filter)
|
|
111
|
-
end
|
|
112
|
-
final_builder = SQLBuilder.union_builders(builders.map(&:to_sql_builder))
|
|
113
|
-
|
|
114
|
-
raw_events = connection.with do |conn|
|
|
115
|
-
conn.exec_params(*final_builder.to_exec_params)
|
|
116
|
-
end.to_a
|
|
117
|
-
raw_events = links_resolver.resolve(raw_events) if options[:resolve_link_tos]
|
|
118
|
-
deserializer.deserialize_many(raw_events)
|
|
32
|
+
# "returning" statement has no guarantees about the order in which rows are returned. Thus, sort them explicitly
|
|
33
|
+
result.sort_by { _1['stream_revision'] }
|
|
119
34
|
end
|
|
120
35
|
|
|
121
36
|
private
|
|
@@ -127,7 +42,6 @@ module PgEventstore
|
|
|
127
42
|
positional_counter = 1
|
|
128
43
|
values = []
|
|
129
44
|
sql_rows_for_insert = events.map do |event|
|
|
130
|
-
event = serializer.serialize(event)
|
|
131
45
|
attributes = event.options_hash.slice(
|
|
132
46
|
:id, :data, :metadata, :stream_revision, :link_global_position, :link_partition_id, :type
|
|
133
47
|
)
|
|
@@ -150,7 +64,7 @@ module PgEventstore
|
|
|
150
64
|
|
|
151
65
|
# @return [PgEventstore::LinksResolver]
|
|
152
66
|
def links_resolver
|
|
153
|
-
LinksResolver.new(connection)
|
|
67
|
+
LinksResolver.new(connection, QueryStrategy::Foreground.new(connection))
|
|
154
68
|
end
|
|
155
69
|
end
|
|
156
70
|
end
|
|
@@ -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
|