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,227 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
module QueryBuilders
|
|
5
|
+
# @!visibility private
|
|
6
|
+
class EventsGlobalIndexFiltering
|
|
7
|
+
include BasicFiltering
|
|
8
|
+
|
|
9
|
+
# @return [Integer]
|
|
10
|
+
DEFAULT_LIMIT = 1_000
|
|
11
|
+
# @return [String]
|
|
12
|
+
PRIMARY_TABLE_NAME = 'events_global_index'
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
# @param filter_row [PgEventstore::QueryBuilders::Filters::FilterRow]
|
|
16
|
+
# @param cursor [PgEventstore::QueryBuilders::ReadCursor::StreamCursor]
|
|
17
|
+
# @param seq_num [Integer]
|
|
18
|
+
# @return [PgEventstore::SQLBuilder]
|
|
19
|
+
def for_revision_validation_per_type(filter_row, cursor, seq_num)
|
|
20
|
+
builder = filtering_from_filter_row(filter_row, cursor).to_sql_builder
|
|
21
|
+
builder.unselect.select("stream_revision, #{seq_num} as sequence_number")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @param filter_row [PgEventstore::QueryBuilders::Filters::FilterRow]
|
|
25
|
+
# @param cursor [PgEventstore::QueryBuilders::ReadCursor::StreamCursor]
|
|
26
|
+
# @return [PgEventstore::SQLBuilder]
|
|
27
|
+
def for_read_grouped(filter_row, cursor)
|
|
28
|
+
filtering_from_filter_row(filter_row, cursor).to_sql_builder
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @param filter_row [PgEventstore::QueryBuilders::Filters::FilterRow]
|
|
32
|
+
# @param cursor [PgEventstore::QueryBuilders::ReadCursor::StreamCursor]
|
|
33
|
+
# @return [PgEventstore::SQLBuilder]
|
|
34
|
+
def for_read_common(filter_row, cursor)
|
|
35
|
+
filtering_from_filter_row(filter_row, cursor).to_sql_builder
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @param cursor [PgEventstore::QueryBuilders::ReadCursor::StreamCursor]
|
|
39
|
+
# @return [PgEventstore::QueryBuilders::EventsGlobalIndexFiltering]
|
|
40
|
+
def default_filtering(cursor)
|
|
41
|
+
index_filtering = new
|
|
42
|
+
add_direction_and_limit(index_filtering, cursor)
|
|
43
|
+
if cursor.all_stream_cursor?
|
|
44
|
+
index_filtering.from_position(cursor.from, cursor.direction)
|
|
45
|
+
index_filtering.to_position(cursor.to, cursor.direction)
|
|
46
|
+
else
|
|
47
|
+
index_filtering.from_revision(cursor.from, cursor.direction)
|
|
48
|
+
index_filtering.to_revision(cursor.to, cursor.direction)
|
|
49
|
+
end
|
|
50
|
+
index_filtering
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
# @param filter_row [PgEventstore::QueryBuilders::Filters::FilterRow]
|
|
56
|
+
# @param cursor [PgEventstore::QueryBuilders::ReadCursor::StreamCursor]
|
|
57
|
+
# @return [PgEventstore::QueryBuilders::EventsGlobalIndexFiltering]
|
|
58
|
+
def filtering_from_filter_row(filter_row, cursor)
|
|
59
|
+
index_filtering = default_filtering(cursor)
|
|
60
|
+
index_filtering.add_filter_row(filter_row)
|
|
61
|
+
index_filtering
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @param index_filtering [PgEventstore::QueryBuilders::EventsGlobalIndexFiltering]
|
|
65
|
+
# @param cursor [PgEventstore::QueryBuilders::ReadCursor::StreamCursor]
|
|
66
|
+
# @return [void]
|
|
67
|
+
def add_direction_and_limit(index_filtering, cursor)
|
|
68
|
+
if cursor.all_stream_cursor?
|
|
69
|
+
index_filtering.add_global_position_direction(cursor.direction)
|
|
70
|
+
else
|
|
71
|
+
index_filtering.add_stream_revision_direction(cursor.direction)
|
|
72
|
+
end
|
|
73
|
+
index_filtering.add_limit(cursor.max_count)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def initialize
|
|
78
|
+
@sql_builder = SQLBuilder.new
|
|
79
|
+
@sql_builder.select("#{to_table_name}.global_position, #{to_table_name}.event_type_partition_id")
|
|
80
|
+
@sql_builder.from(to_table_name)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def to_sql_builder
|
|
84
|
+
@sql_builder
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @return [String]
|
|
88
|
+
def to_table_name
|
|
89
|
+
PRIMARY_TABLE_NAME
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @param filter_row [PgEventstore::QueryBuilders::Filters::FilterRow]
|
|
93
|
+
# @return [void]
|
|
94
|
+
def add_filter_row(filter_row)
|
|
95
|
+
stream_filter = filter_row.stream_filter
|
|
96
|
+
event_type_filters = filter_row.event_type_filters
|
|
97
|
+
operator, rhs = event_type_comparison(filter_row)
|
|
98
|
+
# Collapse context/stream name & event type filters into event type filters
|
|
99
|
+
if filter_row.collapsable_into_event_types_only?
|
|
100
|
+
affected_partitions = PartitionsFiltering.from_filter_row(filter_row)
|
|
101
|
+
partitions_builder = affected_partitions.select_id_only
|
|
102
|
+
return @sql_builder.where_or(
|
|
103
|
+
"#{to_table_name}.event_type_partition_id #{operator} #{rhs}",
|
|
104
|
+
partitions_builder
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
query_parts = []
|
|
109
|
+
if stream_filter&.stream?
|
|
110
|
+
streams_filter = StreamsGlobalIndexFiltering.new
|
|
111
|
+
streams_filter.add_filter_row(filter_row)
|
|
112
|
+
query_parts << [
|
|
113
|
+
"#{to_table_name}.streams_global_index_id = ?", streams_filter.to_sql_builder.select_id_only
|
|
114
|
+
]
|
|
115
|
+
elsif stream_filter&.context?
|
|
116
|
+
affected_partitions = PartitionsFiltering.from_filter_row(filter_row, scope: :context)
|
|
117
|
+
query_parts << ["#{to_table_name}.context_partition_id = ?", affected_partitions.select_id_only]
|
|
118
|
+
elsif stream_filter&.stream_name?
|
|
119
|
+
affected_partitions = PartitionsFiltering.from_filter_row(filter_row, scope: :stream_name)
|
|
120
|
+
query_parts << ["#{to_table_name}.stream_name_partition_id = ?", affected_partitions.select_id_only]
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
if event_type_filters.any?
|
|
124
|
+
affected_partitions = PartitionsFiltering.from_filter_row(filter_row)
|
|
125
|
+
query_parts << [
|
|
126
|
+
"#{to_table_name}.event_type_partition_id #{operator} #{rhs}",
|
|
127
|
+
affected_partitions.select_id_only,
|
|
128
|
+
]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
attributes_sql, values = query_parts.transpose
|
|
132
|
+
@sql_builder.where_or(attributes_sql.join(' and '), *values)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# @param position [Integer, nil]
|
|
136
|
+
# @param direction [String, Symbol, nil]
|
|
137
|
+
# @return [void]
|
|
138
|
+
def from_position(position, direction)
|
|
139
|
+
return unless position
|
|
140
|
+
|
|
141
|
+
@sql_builder.where("#{to_table_name}.global_position #{direction_operator_from(direction)} ?", position)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @param revision [Integer, nil]
|
|
145
|
+
# @param direction [String, Symbol, nil]
|
|
146
|
+
# @return [void]
|
|
147
|
+
def from_revision(revision, direction)
|
|
148
|
+
return unless revision
|
|
149
|
+
|
|
150
|
+
@sql_builder.where("#{to_table_name}.stream_revision #{direction_operator_from(direction)} ?", revision)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# @param position [Integer, nil]
|
|
154
|
+
# @param direction [String, Symbol, nil]
|
|
155
|
+
# @return [void]
|
|
156
|
+
def to_position(position, direction)
|
|
157
|
+
return unless position
|
|
158
|
+
|
|
159
|
+
@sql_builder.where("#{to_table_name}.global_position #{direction_operator_to(direction)} ?", position)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# @param revision [Integer, nil]
|
|
163
|
+
# @param direction [String, Symbol, nil]
|
|
164
|
+
# @return [void]
|
|
165
|
+
def to_revision(revision, direction)
|
|
166
|
+
return unless revision
|
|
167
|
+
|
|
168
|
+
@sql_builder.where("#{to_table_name}.stream_revision #{direction_operator_to(direction)} ?", revision)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# @param limit [Integer, nil]
|
|
172
|
+
# @return [void]
|
|
173
|
+
def add_limit(limit)
|
|
174
|
+
@sql_builder.limit(limit || DEFAULT_LIMIT)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# @param direction [String, Symbol, nil]
|
|
178
|
+
# @return [void]
|
|
179
|
+
def add_global_position_direction(direction)
|
|
180
|
+
@sql_builder.order("#{to_table_name}.global_position #{SQL_DIRECTIONS[direction]}")
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# @param direction [String, Symbol, nil]
|
|
184
|
+
# @return [void]
|
|
185
|
+
def add_stream_revision_direction(direction)
|
|
186
|
+
@sql_builder.order("#{to_table_name}.stream_revision #{SQL_DIRECTIONS[direction]}")
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# @return [void]
|
|
190
|
+
def for_subscription
|
|
191
|
+
spos_table_name = EventSubscriptionPositionsFiltering::PRIMARY_TABLE_NAME
|
|
192
|
+
@sql_builder.select("#{spos_table_name}.subscription_position")
|
|
193
|
+
@sql_builder.join("join #{spos_table_name} using(global_position)")
|
|
194
|
+
@sql_builder.where("#{spos_table_name}.subscription_position >= from_position")
|
|
195
|
+
@sql_builder.where("#{spos_table_name}.subscription_position <= to_position")
|
|
196
|
+
@sql_builder.where("#{to_table_name}.global_position >= from_gpos")
|
|
197
|
+
@sql_builder.where("#{to_table_name}.global_position <= to_gpos")
|
|
198
|
+
@sql_builder.order("#{spos_table_name}.subscription_position asc")
|
|
199
|
+
@sql_builder.limit('max_count')
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
private
|
|
203
|
+
|
|
204
|
+
# @param direction [String, Symbol, nil]
|
|
205
|
+
# @return [String]
|
|
206
|
+
def direction_operator_from(direction)
|
|
207
|
+
SQL_DIRECTIONS[direction] == 'ASC' ? '>=' : '<='
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# @param direction [String, Symbol, nil]
|
|
211
|
+
# @return [String]
|
|
212
|
+
def direction_operator_to(direction)
|
|
213
|
+
SQL_DIRECTIONS[direction] == 'ASC' ? '<=' : '>='
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# @param filter_row [PgEventstore::QueryBuilders::Filters::FilterRow]
|
|
217
|
+
# @return [Array<String>]
|
|
218
|
+
def event_type_comparison(filter_row)
|
|
219
|
+
if filter_row.event_type_filters.size > 1 || filter_row.ambiguous_event_type?
|
|
220
|
+
['=', 'any(array(?)::bigint[])']
|
|
221
|
+
else
|
|
222
|
+
['=', '?']
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'stream_filter'
|
|
4
|
+
require_relative 'event_type_filter'
|
|
5
|
+
require_relative 'filter_row'
|
|
6
|
+
require_relative 'marker_filter'
|
|
7
|
+
require_relative 'marker_filter_row'
|
|
8
|
+
|
|
9
|
+
module PgEventstore
|
|
10
|
+
module QueryBuilders
|
|
11
|
+
module Filters
|
|
12
|
+
# @!visibility private
|
|
13
|
+
class Collection
|
|
14
|
+
class << self
|
|
15
|
+
# @param stream [PgEventstore::Stream]
|
|
16
|
+
# @param options [Hash]
|
|
17
|
+
# @return [self]
|
|
18
|
+
def from_stream_and_options(stream, options)
|
|
19
|
+
return from_options(options) if stream.all_stream?
|
|
20
|
+
|
|
21
|
+
options in { filter: Hash => current_filter }
|
|
22
|
+
current_filter = (current_filter || {}).except(:streams)
|
|
23
|
+
from_options(options.merge(filter: { **current_filter, streams: [stream.to_hash] }))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @param options [Hash]
|
|
27
|
+
# @return [self]
|
|
28
|
+
def from_options(options)
|
|
29
|
+
instance = new
|
|
30
|
+
case options
|
|
31
|
+
in { filter: { streams: Array => streams, event_types: Array => event_types } }
|
|
32
|
+
extract_streams_filter(instance, streams)
|
|
33
|
+
extract_event_types_filter(instance, event_types)
|
|
34
|
+
in { filter: { streams: Array => streams } }
|
|
35
|
+
extract_streams_filter(instance, streams)
|
|
36
|
+
in { filter: { event_types: Array => event_types } }
|
|
37
|
+
extract_event_types_filter(instance, event_types)
|
|
38
|
+
else
|
|
39
|
+
# empty filters
|
|
40
|
+
end
|
|
41
|
+
instance
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
# @param instance [PgEventstore::QueryBuilders::Filters::Collection]
|
|
47
|
+
# @param event_types [Array<String>]
|
|
48
|
+
# @return [void]
|
|
49
|
+
def extract_event_types_filter(instance, event_types)
|
|
50
|
+
event_types.each do |event_type|
|
|
51
|
+
case event_type
|
|
52
|
+
in String
|
|
53
|
+
instance.add_event_type(EventTypeFilter.new(event_type: event_type, prefix: false))
|
|
54
|
+
in { prefix: String => prefix }
|
|
55
|
+
instance.add_event_type(EventTypeFilter.new(event_type: prefix, prefix: true))
|
|
56
|
+
in { markers: [], type: String => type } # Consider empty markers array as regular event type filter
|
|
57
|
+
instance.add_event_type(EventTypeFilter.new(event_type: type, prefix: false))
|
|
58
|
+
in { markers: Array => markers, **opts }
|
|
59
|
+
str_markers = markers.grep(String)
|
|
60
|
+
if str_markers.empty?
|
|
61
|
+
PgEventstore.logger&.debug("Unsupported #{event_type.inspect} markers filter.")
|
|
62
|
+
next
|
|
63
|
+
end
|
|
64
|
+
opts in { type: String => type }
|
|
65
|
+
instance.add_marker(MarkerFilter.new(event_type: type, markers: str_markers))
|
|
66
|
+
in { type: String => type }
|
|
67
|
+
instance.add_event_type(EventTypeFilter.new(event_type: type, prefix: false))
|
|
68
|
+
else
|
|
69
|
+
PgEventstore.logger&.debug("Unsupported #{event_type.inspect} event type filter.")
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @param instance [PgEventstore::QueryBuilders::Filters::Collection]
|
|
75
|
+
# @param streams [Array<Hash>, nil]
|
|
76
|
+
# @return [void]
|
|
77
|
+
def extract_streams_filter(instance, streams)
|
|
78
|
+
streams&.each do |stream_attrs|
|
|
79
|
+
matches = (stream_attrs in { context: String, stream_name: String, stream_id: String } |
|
|
80
|
+
{ context: String, stream_name: String } |
|
|
81
|
+
{ context: String })
|
|
82
|
+
if matches
|
|
83
|
+
instance.add_stream(StreamFilter.new(**stream_attrs.slice(:context, :stream_name, :stream_id)))
|
|
84
|
+
next
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
unsupported_filter_warning(stream_attrs)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @param stream_attrs
|
|
92
|
+
# @return [void]
|
|
93
|
+
def unsupported_filter_warning(stream_attrs)
|
|
94
|
+
PgEventstore.logger&.debug(<<~TEXT)
|
|
95
|
+
Ignoring unsupported stream filter format for searching #{stream_attrs.inspect}. \
|
|
96
|
+
See docs/reading_events.md docs for supported formats.
|
|
97
|
+
TEXT
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# This class is responsible to index stream filters and compute non-overlapping collection of them. Two stream
|
|
102
|
+
# filters overlap when one stream filter affects on the same or more partitions as another stream filter.
|
|
103
|
+
# Example of overlapping filters:
|
|
104
|
+
# from_options(
|
|
105
|
+
# filter: {
|
|
106
|
+
# streams: [
|
|
107
|
+
# { context: 'FooCtx' },
|
|
108
|
+
# { context: 'FooCtx', stream_name: 'Bar' }
|
|
109
|
+
# ]
|
|
110
|
+
# }
|
|
111
|
+
# )
|
|
112
|
+
# In this particular case first stream filter affects on all partitions of 'FooCtx' context, including those
|
|
113
|
+
# partitions, which are related to 'Foo' stream name partitions from the second stream filter. Thus, was can
|
|
114
|
+
# safely throw away the second filter and keep only the first one.
|
|
115
|
+
# Example of non-overlapping filters:
|
|
116
|
+
# from_options(
|
|
117
|
+
# filter: {
|
|
118
|
+
# streams: [
|
|
119
|
+
# { context: 'FooCtx', stream_name: 'Foo' },
|
|
120
|
+
# { context: 'FooCtx', stream_name: 'Bar' }
|
|
121
|
+
# ]
|
|
122
|
+
# }
|
|
123
|
+
# )
|
|
124
|
+
# This example shows that two filters affect on different set of partitions - ('FooCtx', 'Foo') and
|
|
125
|
+
# ('FooCtx', 'Bar'). Thus, we keep both of them.
|
|
126
|
+
class Index
|
|
127
|
+
attr_reader :path
|
|
128
|
+
attr_accessor :stream_filter
|
|
129
|
+
|
|
130
|
+
def initialize
|
|
131
|
+
@path = {}
|
|
132
|
+
@stream_filter = nil
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# @param stream_filter [PgEventstore::QueryBuilders::Filters::StreamFilter]
|
|
136
|
+
# @return [void]
|
|
137
|
+
def index(stream_filter)
|
|
138
|
+
root = self
|
|
139
|
+
stream_filter.to_h.each_value do |val|
|
|
140
|
+
root.path[val] ||= self.class.new
|
|
141
|
+
root = root.path[val]
|
|
142
|
+
end
|
|
143
|
+
root.stream_filter = stream_filter
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# @return [Boolean]
|
|
147
|
+
def empty?
|
|
148
|
+
path.empty? && stream_filter.nil?
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# @param root [PgEventstore::QueryBuilders::Filters::Collection::Index]
|
|
152
|
+
# @return [Array<PgEventstore::QueryBuilders::Filters::StreamFilter>]
|
|
153
|
+
def find_non_overlapping(root = self)
|
|
154
|
+
return [root.stream_filter] if root.stream_filter
|
|
155
|
+
|
|
156
|
+
root.path.each_value.flat_map do |branch|
|
|
157
|
+
find_non_overlapping(branch)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
private_constant :Index
|
|
162
|
+
|
|
163
|
+
def initialize
|
|
164
|
+
@streams = Index.new
|
|
165
|
+
@event_types = Set.new
|
|
166
|
+
@markers = Set.new
|
|
167
|
+
@prefix_filter = false
|
|
168
|
+
@incomplete_stream_filter = false
|
|
169
|
+
@incomplete_markers_filter = false
|
|
170
|
+
reset
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# @return [Array<PgEventstore::QueryBuilders::Filters::FilterRow>]
|
|
174
|
+
def collection
|
|
175
|
+
compile unless @compiled
|
|
176
|
+
@compiled
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# @param stream_filter [PgEventstore::QueryBuilders::Filters::StreamFilter]
|
|
180
|
+
# @return [void]
|
|
181
|
+
def add_stream(stream_filter)
|
|
182
|
+
reset if @compiled
|
|
183
|
+
@incomplete_stream_filter ||= stream_filter.context? || stream_filter.stream_name?
|
|
184
|
+
@streams.index(stream_filter)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# @param event_type_filter [PgEventstore::QueryBuilders::Filters::EventTypeFilter]
|
|
188
|
+
# @return [void]
|
|
189
|
+
def add_event_type(event_type_filter)
|
|
190
|
+
reset if @compiled
|
|
191
|
+
@prefix_filter ||= event_type_filter.prefix?
|
|
192
|
+
@event_types.add(event_type_filter)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# @param marker_filter [PgEventstore::QueryBuilders::Filters::MarkerFilter]
|
|
196
|
+
# @return [void]
|
|
197
|
+
def add_marker(marker_filter)
|
|
198
|
+
reset if @compiled
|
|
199
|
+
@incomplete_markers_filter ||= marker_filter.event_type.nil?
|
|
200
|
+
@markers.add(marker_filter)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# rubocop:disable Naming/PredicatePrefix
|
|
204
|
+
# @return [Boolean]
|
|
205
|
+
def has_event_types?
|
|
206
|
+
@event_types.any?
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# @return [Boolean]
|
|
210
|
+
def has_markers?
|
|
211
|
+
@markers.any?
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# @return [Boolean]
|
|
215
|
+
def empty?
|
|
216
|
+
@event_types.empty? && @streams.empty? && @markers.empty?
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# @return [Boolean]
|
|
220
|
+
def has_prefix_filter?
|
|
221
|
+
@prefix_filter
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# @return [Boolean]
|
|
225
|
+
def has_incomplete_stream_filter?
|
|
226
|
+
@incomplete_stream_filter
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# @return [Boolean]
|
|
230
|
+
def has_incomplete_markers_filter?
|
|
231
|
+
@incomplete_markers_filter
|
|
232
|
+
end
|
|
233
|
+
# rubocop:enable Naming/PredicatePrefix
|
|
234
|
+
|
|
235
|
+
private
|
|
236
|
+
|
|
237
|
+
# @return [void]
|
|
238
|
+
def reset
|
|
239
|
+
@compiled = nil
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# @return [void]
|
|
243
|
+
def compile
|
|
244
|
+
event_types_with_prefixes, event_types_without_prefixes = non_overlapping_event_types
|
|
245
|
+
markers = non_overlapping_markers(event_types_with_prefixes, event_types_without_prefixes)
|
|
246
|
+
event_types = event_types_with_prefixes + event_types_without_prefixes
|
|
247
|
+
streams = @streams.find_non_overlapping
|
|
248
|
+
@compiled =
|
|
249
|
+
if streams.any?
|
|
250
|
+
streams.flat_map do |stream_filter|
|
|
251
|
+
rows = []
|
|
252
|
+
rows << FilterRow.new(stream_filter:, event_type_filters: event_types) if has_event_types?
|
|
253
|
+
markers.each do |marker_filter|
|
|
254
|
+
rows << MarkerFilterRow.new(stream_filter:, marker_filter:)
|
|
255
|
+
end
|
|
256
|
+
rows = [FilterRow.new(stream_filter:, event_type_filters: [])] if rows.empty?
|
|
257
|
+
rows
|
|
258
|
+
end
|
|
259
|
+
else
|
|
260
|
+
rows = []
|
|
261
|
+
rows << FilterRow.new(event_type_filters: event_types) if has_event_types?
|
|
262
|
+
markers.each do |marker_filter|
|
|
263
|
+
rows << MarkerFilterRow.new(marker_filter:)
|
|
264
|
+
end
|
|
265
|
+
rows
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# @return [Array<Array<PgEventstore::QueryBuilders::Filters::EventTypeFilter>>]
|
|
270
|
+
def non_overlapping_event_types
|
|
271
|
+
with_prefixes = []
|
|
272
|
+
without_prefixes = []
|
|
273
|
+
@event_types.each do |event_type_filter|
|
|
274
|
+
if event_type_filter.prefix?
|
|
275
|
+
with_prefixes.push(event_type_filter)
|
|
276
|
+
else
|
|
277
|
+
without_prefixes.push(event_type_filter)
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
return [[], without_prefixes] if with_prefixes.empty?
|
|
281
|
+
|
|
282
|
+
with_prefixes = with_prefixes.sort_by(&:event_type)
|
|
283
|
+
with_prefixes = with_prefixes.each_with_object([with_prefixes.first]) do |event_type_filter, result|
|
|
284
|
+
result.push(event_type_filter) unless event_type_filter.event_type.start_with?(result.last.event_type)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
without_prefixes = without_prefixes.reject do |event_type_filter|
|
|
288
|
+
with_prefixes.any? { |prefix| event_type_filter.event_type.start_with?(prefix.event_type) }
|
|
289
|
+
end
|
|
290
|
+
[with_prefixes, without_prefixes]
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# @param event_types_with_prefixes [Array<PgEventstore::QueryBuilders::Filters::EventTypeFilter>]
|
|
294
|
+
# @param event_types_without_prefixes [Array<PgEventstore::QueryBuilders::Filters::EventTypeFilter>]
|
|
295
|
+
# @return [Array<PgEventstore::QueryBuilders::Filters::MarkerFilter>]
|
|
296
|
+
def non_overlapping_markers(event_types_with_prefixes, event_types_without_prefixes)
|
|
297
|
+
markers = @markers.group_by(&:event_type).map do |event_type, filters|
|
|
298
|
+
MarkerFilter.new(event_type:, markers: filters.flat_map(&:markers).uniq)
|
|
299
|
+
end
|
|
300
|
+
markers.reject do |marker|
|
|
301
|
+
next false if marker.event_type.nil?
|
|
302
|
+
|
|
303
|
+
marker_filter_overlaps_with_prefix_filter?(marker, event_types_with_prefixes) ||
|
|
304
|
+
marker_filter_overlaps_with_event_type_filter?(marker, event_types_without_prefixes)
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# @param marker_filter [PgEventstore::QueryBuilders::Filters::MarkerFilter]
|
|
309
|
+
# @param prefix_filters [Array<PgEventstore::QueryBuilders::Filters::EventTypeFilter>]
|
|
310
|
+
# @return [Boolean]
|
|
311
|
+
def marker_filter_overlaps_with_prefix_filter?(marker_filter, prefix_filters)
|
|
312
|
+
prefix_filters.any? { marker_filter.event_type.start_with?(_1.event_type) }
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# @param marker_filter [PgEventstore::QueryBuilders::Filters::MarkerFilter]
|
|
316
|
+
# @param event_type_filters [Array<PgEventstore::QueryBuilders::Filters::EventTypeFilter>]
|
|
317
|
+
def marker_filter_overlaps_with_event_type_filter?(marker_filter, event_type_filters)
|
|
318
|
+
event_type_filter = EventTypeFilter.new(event_type: marker_filter.event_type, prefix: false)
|
|
319
|
+
event_type_filters.include?(event_type_filter)
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
module QueryBuilders
|
|
5
|
+
module Filters
|
|
6
|
+
# @!visibility private
|
|
7
|
+
class EventTypeFilter
|
|
8
|
+
include Extensions::OptionsExtension
|
|
9
|
+
include Extensions::OptionsDefaults
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
# @return [PgEventstore::QueryBuilders::Filters::EventTypeFilter]
|
|
13
|
+
def null_filter
|
|
14
|
+
new(event_type: nil, prefix: false)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @!attribute value
|
|
19
|
+
# @return [String, nil]
|
|
20
|
+
attribute(:event_type)
|
|
21
|
+
# @!attribute prefix
|
|
22
|
+
# @return [Boolean]
|
|
23
|
+
attribute(:prefix)
|
|
24
|
+
|
|
25
|
+
# @return [Boolean]
|
|
26
|
+
def prefix?
|
|
27
|
+
prefix
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [String, nil]
|
|
31
|
+
def to_sql_value
|
|
32
|
+
prefix? ? "#{event_type}%" : event_type
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
module QueryBuilders
|
|
5
|
+
module Filters
|
|
6
|
+
# @!visibility private
|
|
7
|
+
class FilterRow
|
|
8
|
+
include Extensions::OptionsExtension
|
|
9
|
+
include Extensions::OptionsDefaults
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
# @return [PgEventstore::QueryBuilders::Filters::FilterRow]
|
|
13
|
+
def null_filter_row
|
|
14
|
+
new(event_type_filters: [EventTypeFilter.null_filter])
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @!attribute stream_filter
|
|
19
|
+
# @return [PgEventstore::QueryBuilders::Filters::StreamFilter, nil]
|
|
20
|
+
attribute(:stream_filter)
|
|
21
|
+
# @!attribute event_type_filters
|
|
22
|
+
# @return [Array<PgEventstore::QueryBuilders::Filters::EventTypeFilter>]
|
|
23
|
+
attribute(:event_type_filters)
|
|
24
|
+
|
|
25
|
+
# @return [Array<PgEventstore::QueryBuilders::Filters::FilterRow>]
|
|
26
|
+
def flatten
|
|
27
|
+
return [dup] if event_type_filters.none?
|
|
28
|
+
|
|
29
|
+
event_type_filters.map do |event_type_filter|
|
|
30
|
+
self.class.new(stream_filter:, event_type_filters: [event_type_filter])
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# When we don't have stream filter or stream filter consists of only context or context and stream name, along
|
|
35
|
+
# with event types filter - we can say that this row can be converted into event type only filter if needed.
|
|
36
|
+
# This means we can craft a query by event_type_partition_id column only without involving other columns such as
|
|
37
|
+
# context_partition_id, stream_name_partition_id or streams_global_index_id
|
|
38
|
+
# @return [Boolean]
|
|
39
|
+
def collapsable_into_event_types_only?
|
|
40
|
+
(stream_filter.nil? || stream_filter.context? || stream_filter.stream_name?) && event_type_filters.any?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Event type is ambiguous in case we can't tell which partition it belongs to. We **can** tell the exact
|
|
44
|
+
# partition of the given event type only when we have context and stream name as well.
|
|
45
|
+
# @return [Boolean]
|
|
46
|
+
def ambiguous_event_type?
|
|
47
|
+
return true if event_type_filters.any?(&:prefix?)
|
|
48
|
+
|
|
49
|
+
(stream_filter.nil? || stream_filter.context?) && event_type_filters.any?
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
module QueryBuilders
|
|
5
|
+
module Filters
|
|
6
|
+
# @!visibility private
|
|
7
|
+
class MarkerFilter
|
|
8
|
+
include Extensions::OptionsExtension
|
|
9
|
+
include Extensions::OptionsDefaults
|
|
10
|
+
|
|
11
|
+
# @!attribute marker
|
|
12
|
+
# @return [Array<String>]
|
|
13
|
+
attribute(:markers)
|
|
14
|
+
# @!attribute event_type
|
|
15
|
+
# @return [String, nil]
|
|
16
|
+
attribute(:event_type)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|