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,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
module Extensions
|
|
5
|
+
# @!visibility private
|
|
6
|
+
module OptionsDefaults
|
|
7
|
+
def ==(other)
|
|
8
|
+
return false unless other.is_a?(self.class)
|
|
9
|
+
|
|
10
|
+
attributes_hash == other.attributes_hash
|
|
11
|
+
end
|
|
12
|
+
alias eql? ==
|
|
13
|
+
|
|
14
|
+
# @return [Integer]
|
|
15
|
+
def hash
|
|
16
|
+
attributes_hash.hash
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [self]
|
|
20
|
+
def dup
|
|
21
|
+
self.class.new(**Utils.deep_dup(options_hash))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'set'
|
|
4
|
-
|
|
5
3
|
module PgEventstore
|
|
6
4
|
module Extensions
|
|
7
5
|
# A very simple extension that implements a DSL for adding attr_accessors with default values,
|
|
@@ -72,16 +70,47 @@ module PgEventstore
|
|
|
72
70
|
end
|
|
73
71
|
end
|
|
74
72
|
|
|
75
|
-
class Options
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
class Options
|
|
74
|
+
include Enumerable
|
|
75
|
+
|
|
76
|
+
attr_reader :options
|
|
77
|
+
protected :options
|
|
78
|
+
|
|
79
|
+
# @param options [Array<PgEventstore::Extensions::OptionsExtension::Option>]
|
|
80
|
+
def initialize(options = [])
|
|
81
|
+
@options = options.to_h { [_1, true] }
|
|
79
82
|
end
|
|
80
83
|
|
|
81
|
-
# @param
|
|
84
|
+
# @param option_name [Symbol]
|
|
82
85
|
# @return [PgEventstore::Extensions::OptionsExtension::Option, nil]
|
|
83
|
-
def [](
|
|
84
|
-
|
|
86
|
+
def [](option_name)
|
|
87
|
+
option = Option.new(option_name)
|
|
88
|
+
options.find { |key, _| key == option }&.dig(0)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @param other [PgEventstore::Extensions::OptionsExtension::Options]
|
|
92
|
+
# @return [PgEventstore::Extensions::OptionsExtension::Options]
|
|
93
|
+
def +(other)
|
|
94
|
+
self.class.new(options.keys + other.options.keys)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @param option [PgEventstore::Extensions::OptionsExtension::Option]
|
|
98
|
+
# @return [Boolean]
|
|
99
|
+
def include?(option)
|
|
100
|
+
options.key?(option)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @return [Boolean]
|
|
104
|
+
def dup
|
|
105
|
+
self.class.new(options.keys)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def each(...)
|
|
109
|
+
options.keys.each(...)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def ==(other)
|
|
113
|
+
options.keys == other.options.keys
|
|
85
114
|
end
|
|
86
115
|
end
|
|
87
116
|
|
|
@@ -92,7 +121,7 @@ module PgEventstore
|
|
|
92
121
|
# context of your object to determine the default value of the option
|
|
93
122
|
# @return [Symbol]
|
|
94
123
|
def option(opt_name, metadata: nil, &blk)
|
|
95
|
-
self.options = (options + Options.new([Option.new(opt_name, metadata:
|
|
124
|
+
self.options = (options + Options.new([Option.new(opt_name, metadata:)])).freeze
|
|
96
125
|
warn_already_defined(opt_name)
|
|
97
126
|
warn_already_defined(:"#{opt_name}=")
|
|
98
127
|
define_method "#{opt_name}=" do |value|
|
|
@@ -112,7 +141,7 @@ module PgEventstore
|
|
|
112
141
|
|
|
113
142
|
def inherited(klass)
|
|
114
143
|
super
|
|
115
|
-
klass.options =
|
|
144
|
+
klass.options = options.dup.freeze
|
|
116
145
|
end
|
|
117
146
|
|
|
118
147
|
private
|
|
@@ -144,8 +173,8 @@ module PgEventstore
|
|
|
144
173
|
# value
|
|
145
174
|
# @return [Hash]
|
|
146
175
|
def options_hash
|
|
147
|
-
self.class.options.
|
|
148
|
-
|
|
176
|
+
self.class.options.to_h do |option|
|
|
177
|
+
[option.name, public_send(option.name)]
|
|
149
178
|
end
|
|
150
179
|
end
|
|
151
180
|
alias attributes_hash options_hash
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
class FeatureMarker
|
|
5
|
+
include Extensions::OptionsExtension
|
|
6
|
+
include Extensions::OptionsDefaults
|
|
7
|
+
|
|
8
|
+
# @!attribute marker
|
|
9
|
+
# @return [String]
|
|
10
|
+
attribute(:marker)
|
|
11
|
+
# @!attribute description
|
|
12
|
+
# @return [String, nil] the description of the maker. Can be used as human-friendly explanation of the purpose
|
|
13
|
+
attribute(:description)
|
|
14
|
+
# @!attribute purpose
|
|
15
|
+
# @return [Symbol, nil] the purpose of the maker. Can be used as an identifier in your implementation
|
|
16
|
+
attribute(:purpose)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -15,17 +15,17 @@ module PgEventstore
|
|
|
15
15
|
# @param stream [PgEventstore::Stream]
|
|
16
16
|
# @return [Boolean] whether a stream was deleted successfully
|
|
17
17
|
def delete_stream(stream)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
).call(stream)
|
|
18
|
+
Utils.assert_node_role!(config, Config::NodeRole.maintainable)
|
|
19
|
+
queries = Queries.new(maintenance: maintenance_queries)
|
|
20
|
+
Commands::DeleteStream.new(queries).call(stream)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
# @param event [PgEventstore::Event] persisted event
|
|
24
24
|
# @return [Boolean] whether an event was deleted successfully
|
|
25
25
|
def delete_event(event, force: false)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
).call(event, force:
|
|
26
|
+
Utils.assert_node_role!(config, Config::NodeRole.maintainable)
|
|
27
|
+
queries = Queries.new(maintenance: maintenance_queries, events_global_index: events_global_index_queries)
|
|
28
|
+
Commands::DeleteEvent.new(queries).call(event, force:)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
private
|
|
@@ -44,5 +44,10 @@ module PgEventstore
|
|
|
44
44
|
def connection
|
|
45
45
|
PgEventstore.connection(config.name)
|
|
46
46
|
end
|
|
47
|
+
|
|
48
|
+
# @return [PgEventstore::EventsGlobalIndexQueries]
|
|
49
|
+
def events_global_index_queries
|
|
50
|
+
EventsGlobalIndexQueries.new(connection, QueryStrategy::Foreground.new(connection))
|
|
51
|
+
end
|
|
47
52
|
end
|
|
48
53
|
end
|
|
@@ -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,85 +6,19 @@ 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<String>]
|
|
45
|
-
def ids_from_db(events)
|
|
46
|
-
sql_builder = SQLBuilder.new.from(Event::PRIMARY_TABLE_NAME).select('id')
|
|
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('id = ANY(?::uuid[])', events.map(&:id))
|
|
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['id'] }
|
|
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
|
-
columns = %w[id data metadata stream_revision
|
|
21
|
+
columns = %w[id data metadata stream_revision link_global_position link_partition_id type context stream_name stream_id]
|
|
88
22
|
|
|
89
23
|
sql = <<~SQL
|
|
90
24
|
INSERT INTO events (#{columns.join(', ')})
|
|
@@ -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,9 +42,8 @@ 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
|
-
:id, :data, :metadata, :stream_revision, :
|
|
46
|
+
:id, :data, :metadata, :stream_revision, :link_global_position, :link_partition_id, :type
|
|
133
47
|
)
|
|
134
48
|
|
|
135
49
|
attributes = attributes.merge(stream.to_hash)
|
|
@@ -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
|