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.
Files changed (303) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -1
  3. data/CHANGELOG.md +186 -20
  4. data/README.md +25 -15
  5. data/db/migrations/10_setup_pg_cron.rb +1 -23
  6. data/db/migrations/15_create_streams_global_index.sql +17 -0
  7. data/db/migrations/16_populate_streams_global_index.rb +150 -0
  8. data/db/migrations/17_create_events_global_index.sql +62 -0
  9. data/db/migrations/18_populate_events_global_index.rb +124 -0
  10. data/db/migrations/19_populate_events_global_index_p2.rb +25 -0
  11. data/db/migrations/20_migrate_subscriptions_current_position.sql +19 -0
  12. data/db/migrations/21_create_partitions_stats.sql +2 -0
  13. data/db/migrations/22_drop_streams_sql_view.sql +2 -0
  14. data/db/migrations/23_adjust_partitions_indexes.sql +5 -0
  15. data/db/migrations/24_drop_legacy_events_indexes.sql +3 -0
  16. data/db/migrations/25_add_parent_partitions_info_to_partitions.sql +16 -0
  17. data/db/migrations/26_change_events_stream_revision_type.rb +35 -0
  18. data/db/migrations/27_drop_events_horizon.sql +3 -0
  19. data/db/migrations/28_create_maintenance_tasks.sql +8 -0
  20. data/db/migrations/29_create_event_markers.sql +35 -0
  21. data/db/migrations/30_improve_partitions_search_in_admin_ui.rb +24 -0
  22. data/db/migrations/31_drop_events_id_default_value.sql +1 -0
  23. data/db/migrations/32_create_parittions_triggers.sql +101 -0
  24. data/docs/AGENTS.fragment.md +696 -0
  25. data/docs/admin_ui.md +3 -1
  26. data/docs/appending_events.md +110 -49
  27. data/docs/configuration.md +69 -36
  28. data/docs/event_tracing.md +55 -0
  29. data/docs/events_and_streams.md +54 -30
  30. data/docs/how_it_works.md +57 -16
  31. data/docs/linking_events.md +2 -1
  32. data/docs/maintenance.md +14 -5
  33. data/docs/multiple_commands.md +17 -8
  34. data/docs/reading_events.md +208 -43
  35. data/docs/reading_streams.md +50 -0
  36. data/docs/replication.md +99 -0
  37. data/docs/subscriptions.md +165 -35
  38. data/docs/writing_middleware.md +25 -8
  39. data/ext/pg_eventstore_ext/extconf.rb +5 -0
  40. data/ext/pg_eventstore_ext/pg_eventstore_ext.c +74 -0
  41. data/lib/pg_eventstore/async_runner.rb +63 -0
  42. data/lib/pg_eventstore/basic_config.rb +15 -0
  43. data/lib/pg_eventstore/chunks/chunk.rb +31 -0
  44. data/lib/pg_eventstore/chunks/read_api_events_index_chunk.rb +83 -0
  45. data/lib/pg_eventstore/chunks/replica_events_index_chunk.rb +35 -0
  46. data/lib/pg_eventstore/chunks/repository.rb +73 -0
  47. data/lib/pg_eventstore/chunks/subscription_checkpoint_chunk.rb +48 -0
  48. data/lib/pg_eventstore/chunks/subscription_events_index_chunk.rb +99 -0
  49. data/lib/pg_eventstore/chunks.rb +14 -0
  50. data/lib/pg_eventstore/client.rb +163 -50
  51. data/lib/pg_eventstore/commands/append.rb +62 -43
  52. data/lib/pg_eventstore/commands/delete_event.rb +7 -8
  53. data/lib/pg_eventstore/commands/delete_stream.rb +3 -3
  54. data/lib/pg_eventstore/commands/event_modifiers/prepare_link_event.rb +9 -7
  55. data/lib/pg_eventstore/commands/event_modifiers/prepare_regular_event.rb +12 -7
  56. data/lib/pg_eventstore/commands/link_to.rb +5 -5
  57. data/lib/pg_eventstore/commands/read.rb +23 -5
  58. data/lib/pg_eventstore/commands/read_grouped.rb +46 -0
  59. data/lib/pg_eventstore/commands/read_streams.rb +18 -0
  60. data/lib/pg_eventstore/commands/read_streams_paginated.rb +56 -0
  61. data/lib/pg_eventstore/commands/regular_stream_read_paginated.rb +4 -4
  62. data/lib/pg_eventstore/commands/revision_check/current_revision.rb +51 -0
  63. data/lib/pg_eventstore/commands/revision_check/event_type_revisions_comparison.rb +46 -0
  64. data/lib/pg_eventstore/commands/revision_check/expected_revision.rb +135 -0
  65. data/lib/pg_eventstore/commands/revision_check/stream_revision_check.rb +98 -0
  66. data/lib/pg_eventstore/commands/revision_check/stream_revision_comparison.rb +36 -0
  67. data/lib/pg_eventstore/commands/stream_revision.rb +14 -0
  68. data/lib/pg_eventstore/commands/system_stream_read_paginated.rb +4 -4
  69. data/lib/pg_eventstore/commands.rb +4 -2
  70. data/lib/pg_eventstore/config.rb +30 -9
  71. data/lib/pg_eventstore/connection.rb +21 -2
  72. data/lib/pg_eventstore/errors.rb +136 -10
  73. data/lib/pg_eventstore/event.rb +34 -2
  74. data/lib/pg_eventstore/event_deserializer.rb +5 -4
  75. data/lib/pg_eventstore/event_global_index.rb +118 -0
  76. data/lib/pg_eventstore/event_marker.rb +16 -0
  77. data/lib/pg_eventstore/event_marker_index.rb +25 -0
  78. data/lib/pg_eventstore/event_serializer.rb +6 -0
  79. data/lib/pg_eventstore/extensions/acts_as_configurable.rb +88 -0
  80. data/lib/pg_eventstore/extensions/options_defaults.rb +25 -0
  81. data/lib/pg_eventstore/extensions/options_extension.rb +2 -2
  82. data/lib/pg_eventstore/feature_marker.rb +18 -0
  83. data/lib/pg_eventstore/maintenance.rb +11 -6
  84. data/lib/pg_eventstore/middleware/event_tracing.rb +53 -0
  85. data/lib/pg_eventstore/partition.rb +6 -0
  86. data/lib/pg_eventstore/pg_connection.rb +70 -14
  87. data/lib/pg_eventstore/queries/event_marker_queries.rb +74 -0
  88. data/lib/pg_eventstore/queries/event_queries.rb +7 -93
  89. data/lib/pg_eventstore/queries/events_global_index_queries.rb +131 -0
  90. data/lib/pg_eventstore/queries/index_filtering_queries.rb +179 -0
  91. data/lib/pg_eventstore/queries/links_resolver.rb +4 -4
  92. data/lib/pg_eventstore/queries/maintenance_queries.rb +159 -42
  93. data/lib/pg_eventstore/queries/partition_queries.rb +45 -103
  94. data/lib/pg_eventstore/queries/replica_queries.rb +110 -0
  95. data/lib/pg_eventstore/queries/streams_global_index_queries.rb +163 -0
  96. data/lib/pg_eventstore/queries/transaction_queries.rb +52 -10
  97. data/lib/pg_eventstore/queries.rb +29 -1
  98. data/lib/pg_eventstore/query_builders/basic_filtering.rb +38 -5
  99. data/lib/pg_eventstore/query_builders/event_markers_filtering.rb +47 -0
  100. data/lib/pg_eventstore/query_builders/event_markers_index_filtering.rb +275 -0
  101. data/lib/pg_eventstore/query_builders/event_subscription_positions_filtering.rb +37 -0
  102. data/lib/pg_eventstore/query_builders/events_filtering.rb +15 -164
  103. data/lib/pg_eventstore/query_builders/events_global_index_filtering.rb +227 -0
  104. data/lib/pg_eventstore/query_builders/filters/collection.rb +324 -0
  105. data/lib/pg_eventstore/query_builders/filters/event_type_filter.rb +37 -0
  106. data/lib/pg_eventstore/query_builders/filters/filter_row.rb +54 -0
  107. data/lib/pg_eventstore/query_builders/filters/marker_filter.rb +20 -0
  108. data/lib/pg_eventstore/query_builders/filters/marker_filter_row.rb +49 -0
  109. data/lib/pg_eventstore/query_builders/filters/stream_filter.rb +48 -0
  110. data/lib/pg_eventstore/query_builders/index_based_events_filtering.rb +260 -0
  111. data/lib/pg_eventstore/query_builders/partitions_filtering.rb +175 -51
  112. data/lib/pg_eventstore/query_builders/read_cursor/stream_cursor.rb +122 -0
  113. data/lib/pg_eventstore/query_builders/streams_global_index_filtering.rb +83 -0
  114. data/lib/pg_eventstore/query_builders/subscription_events_filtering.rb +79 -0
  115. data/lib/pg_eventstore/query_strategy/async.rb +64 -0
  116. data/lib/pg_eventstore/query_strategy/foreground.rb +25 -0
  117. data/lib/pg_eventstore/query_strategy.rb +19 -0
  118. data/lib/pg_eventstore/raw_event.rb +46 -0
  119. data/lib/pg_eventstore/rspec/test_helpers.rb +21 -8
  120. data/lib/pg_eventstore/sql_builder.rb +87 -8
  121. data/lib/pg_eventstore/stream.rb +13 -16
  122. data/lib/pg_eventstore/stream_global_index.rb +28 -0
  123. data/lib/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rb +5 -17
  124. data/lib/pg_eventstore/subscriptions/callback_handlers/events_subscription_position_worker_handlers.rb +36 -0
  125. data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rb +12 -0
  126. data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rb +21 -7
  127. data/lib/pg_eventstore/subscriptions/events_processor.rb +20 -18
  128. data/lib/pg_eventstore/subscriptions/events_processor_consumer/multiple.rb +63 -0
  129. data/lib/pg_eventstore/subscriptions/events_processor_consumer/replica.rb +68 -0
  130. data/lib/pg_eventstore/subscriptions/events_processor_consumer/single.rb +62 -0
  131. data/lib/pg_eventstore/subscriptions/events_processor_consumer.rb +44 -0
  132. data/lib/pg_eventstore/subscriptions/events_subscription_position_worker.rb +68 -0
  133. data/lib/pg_eventstore/subscriptions/queries/event_subscription_position_queries.rb +177 -0
  134. data/lib/pg_eventstore/subscriptions/queries/subscription_queries.rb +78 -54
  135. data/lib/pg_eventstore/subscriptions/replica_subscription_handler.rb +140 -0
  136. data/lib/pg_eventstore/subscriptions/replica_subscription_runner.rb +9 -0
  137. data/lib/pg_eventstore/subscriptions/subscription.rb +2 -1
  138. data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/collection.rb +36 -0
  139. data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/index_read_strategy.rb +82 -0
  140. data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/replication_strategy.rb +75 -0
  141. data/lib/pg_eventstore/subscriptions/subscription_feed_strategy.rb +31 -0
  142. data/lib/pg_eventstore/subscriptions/subscription_feeder.rb +24 -0
  143. data/lib/pg_eventstore/subscriptions/subscription_handler_performance.rb +4 -2
  144. data/lib/pg_eventstore/subscriptions/subscription_runner.rb +20 -9
  145. data/lib/pg_eventstore/subscriptions/subscription_runner_commands/reset_position.rb +1 -1
  146. data/lib/pg_eventstore/subscriptions/subscription_runners_feeder.rb +9 -18
  147. data/lib/pg_eventstore/subscriptions/subscriptions_lifecycle.rb +0 -12
  148. data/lib/pg_eventstore/subscriptions/subscriptions_manager.rb +74 -14
  149. data/lib/pg_eventstore/{subscriptions/synchronized_array.rb → synchronized_array.rb} +15 -0
  150. data/lib/pg_eventstore/tasks/setup.rake +2 -2
  151. data/lib/pg_eventstore/utils.rb +31 -0
  152. data/lib/pg_eventstore/version.rb +1 -1
  153. data/lib/pg_eventstore/web/application.rb +100 -16
  154. data/lib/pg_eventstore/web/paginator/base_collection.rb +5 -1
  155. data/lib/pg_eventstore/web/paginator/event_types_collection.rb +14 -4
  156. data/lib/pg_eventstore/web/paginator/events_collection.rb +29 -33
  157. data/lib/pg_eventstore/web/paginator/helpers.rb +16 -9
  158. data/lib/pg_eventstore/web/paginator/markers_collection.rb +48 -0
  159. data/lib/pg_eventstore/web/paginator/stream_contexts_collection.rb +13 -2
  160. data/lib/pg_eventstore/web/paginator/stream_ids_collection.rb +21 -11
  161. data/lib/pg_eventstore/web/paginator/stream_names_collection.rb +18 -4
  162. data/lib/pg_eventstore/web/paginator/streams_collection.rb +95 -0
  163. data/lib/pg_eventstore/web/public/javascripts/pg_eventstore.js +49 -22
  164. data/lib/pg_eventstore/web/subscriptions/set_collection.rb +1 -1
  165. data/lib/pg_eventstore/web/subscriptions/subscriptions.rb +1 -1
  166. data/lib/pg_eventstore/web/subscriptions/with_state/set_collection.rb +1 -1
  167. data/lib/pg_eventstore/web/subscriptions/with_state/subscriptions.rb +1 -1
  168. data/lib/pg_eventstore/web/views/home/dashboard.erb +11 -9
  169. data/lib/pg_eventstore/web/views/home/partials/event_filter.erb +18 -5
  170. data/lib/pg_eventstore/web/views/home/partials/events.erb +38 -1
  171. data/lib/pg_eventstore/web/views/home/partials/markers_filter.erb +18 -0
  172. data/lib/pg_eventstore/web/views/layouts/application.erb +6 -0
  173. data/lib/pg_eventstore/web/views/streams/index.erb +110 -0
  174. data/lib/pg_eventstore/web/views/streams/partials/streams.erb +11 -0
  175. data/lib/pg_eventstore/web/views/subscriptions/index.erb +4 -1
  176. data/lib/pg_eventstore/web.rb +2 -0
  177. data/lib/pg_eventstore.rb +23 -60
  178. data/pg_eventstore.gemspec +6 -4
  179. data/sig/interfaces/_raw_events_handler.rbs +3 -0
  180. data/sig/interfaces/subscription_handler.rbs +1 -1
  181. data/sig/pg/result.rbs +9 -0
  182. data/sig/pg_eventstore/async_runner.rbs +13 -0
  183. data/sig/pg_eventstore/basic_config.rbs +9 -0
  184. data/sig/pg_eventstore/chunks/chunk.rbs +13 -0
  185. data/sig/pg_eventstore/chunks/read_api_events_index_chunk.rbs +30 -0
  186. data/sig/pg_eventstore/chunks/replica_events_index_chunk.rbs +11 -0
  187. data/sig/pg_eventstore/chunks/repository.rbs +22 -0
  188. data/sig/pg_eventstore/chunks/subscription_checkpoint_chunk.rbs +18 -0
  189. data/sig/pg_eventstore/chunks/subscription_events_index_chunk.rbs +37 -0
  190. data/sig/pg_eventstore/client.rbs +40 -42
  191. data/sig/pg_eventstore/commands/append.rbs +11 -25
  192. data/sig/pg_eventstore/commands/event_modifiers/prepare_link_event.rbs +9 -12
  193. data/sig/pg_eventstore/commands/event_modifiers/prepare_regular_event.rbs +5 -4
  194. data/sig/pg_eventstore/commands/link_to.rbs +6 -11
  195. data/sig/pg_eventstore/commands/read.rbs +2 -5
  196. data/sig/pg_eventstore/commands/read_grouped.rbs +7 -0
  197. data/sig/pg_eventstore/commands/read_streams.rbs +7 -0
  198. data/sig/pg_eventstore/commands/read_streams_paginated.rbs +16 -0
  199. data/sig/pg_eventstore/commands/regular_stream_read_paginated.rbs +9 -17
  200. data/sig/pg_eventstore/commands/revision_check/current_revision.rbs +25 -0
  201. data/sig/pg_eventstore/commands/revision_check/event_type_revisions_comparison.rbs +14 -0
  202. data/sig/pg_eventstore/commands/revision_check/expected_revision.rbs +67 -0
  203. data/sig/pg_eventstore/commands/revision_check/stream_revision_check.rbs +20 -0
  204. data/sig/pg_eventstore/commands/revision_check/stream_revision_comparison.rbs +9 -0
  205. data/sig/pg_eventstore/commands/stream_revision.rbs +7 -0
  206. data/sig/pg_eventstore/commands/system_stream_read_paginated.rbs +9 -14
  207. data/sig/pg_eventstore/config.rbs +15 -6
  208. data/sig/pg_eventstore/connection.rbs +11 -18
  209. data/sig/pg_eventstore/errors.rbs +64 -34
  210. data/sig/pg_eventstore/event.rbs +16 -2
  211. data/sig/pg_eventstore/event_deserializer.rbs +5 -10
  212. data/sig/pg_eventstore/event_global_index.rbs +60 -0
  213. data/sig/pg_eventstore/event_marker.rbs +9 -0
  214. data/sig/pg_eventstore/event_marker_index.rbs +12 -0
  215. data/sig/pg_eventstore/extensions/acts_as_configurable.rbs +29 -0
  216. data/sig/pg_eventstore/extensions/options_defaults.rbs +7 -0
  217. data/sig/pg_eventstore/feature_marker.rbs +10 -0
  218. data/sig/pg_eventstore/maintenance.rbs +12 -8
  219. data/sig/pg_eventstore/middleware/event_trace.rbs +14 -0
  220. data/sig/pg_eventstore/partition.rbs +2 -4
  221. data/sig/pg_eventstore/pg_connection.rbs +8 -0
  222. data/sig/pg_eventstore/queries/event_marker_queries.rbs +21 -0
  223. data/sig/pg_eventstore/queries/event_queries.rbs +4 -36
  224. data/sig/pg_eventstore/queries/events_global_index_queries.rbs +37 -0
  225. data/sig/pg_eventstore/queries/index_filtering_queries.rbs +50 -0
  226. data/sig/pg_eventstore/queries/links_resolver.rbs +5 -9
  227. data/sig/pg_eventstore/queries/maintenance_queries.rbs +12 -9
  228. data/sig/pg_eventstore/queries/partition_queries.rbs +32 -67
  229. data/sig/pg_eventstore/queries/replica_queries.rbs +31 -0
  230. data/sig/pg_eventstore/queries/streams_global_index_queries.rbs +39 -0
  231. data/sig/pg_eventstore/queries/transaction_queries.rbs +2 -0
  232. data/sig/pg_eventstore/queries.rbs +11 -21
  233. data/sig/pg_eventstore/query_builders/basic_filtering.rbs +10 -3
  234. data/sig/pg_eventstore/query_builders/event_markers_filtering.rbs +17 -0
  235. data/sig/pg_eventstore/query_builders/event_markers_index_filtering.rbs +69 -0
  236. data/sig/pg_eventstore/query_builders/event_subscription_positions_filtering.rbs +15 -0
  237. data/sig/pg_eventstore/query_builders/events_filtering_query.rbs +9 -51
  238. data/sig/pg_eventstore/query_builders/events_global_index_filtering.rbs +68 -0
  239. data/sig/pg_eventstore/query_builders/filters/collection.rbs +84 -0
  240. data/sig/pg_eventstore/query_builders/filters/event_type_filter.rbs +19 -0
  241. data/sig/pg_eventstore/query_builders/filters/filter_row.rbs +21 -0
  242. data/sig/pg_eventstore/query_builders/filters/marker_filter.rbs +13 -0
  243. data/sig/pg_eventstore/query_builders/filters/marker_filter_row.rbs +19 -0
  244. data/sig/pg_eventstore/query_builders/filters/stream_filter.rbs +24 -0
  245. data/sig/pg_eventstore/query_builders/index_based_events_filtering.rbs +60 -0
  246. data/sig/pg_eventstore/query_builders/partitions_filtering.rbs +29 -10
  247. data/sig/pg_eventstore/query_builders/read_cursor/stream_cursor.rbs +47 -0
  248. data/sig/pg_eventstore/query_builders/streams_global_index_filtering.rbs +27 -0
  249. data/sig/pg_eventstore/query_builders/subscription_events_filtering.rbs +26 -0
  250. data/sig/pg_eventstore/query_strategy/async.rbs +17 -0
  251. data/sig/pg_eventstore/query_strategy/foreground.rbs +11 -0
  252. data/sig/pg_eventstore/query_strategy.rbs +7 -0
  253. data/sig/pg_eventstore/raw_event.rbs +20 -0
  254. data/sig/pg_eventstore/sql_builder.rbs +32 -10
  255. data/sig/pg_eventstore/stream.rbs +10 -18
  256. data/sig/pg_eventstore/stream_global_index.rbs +14 -0
  257. data/sig/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rbs +5 -4
  258. data/sig/pg_eventstore/subscriptions/callback_handlers/events_subscription_position_worker_handlers.rbs +9 -0
  259. data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rbs +17 -12
  260. data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rbs +17 -6
  261. data/sig/pg_eventstore/subscriptions/event_subscription_position_queries.rbs +30 -0
  262. data/sig/pg_eventstore/subscriptions/events_processor.rbs +12 -5
  263. data/sig/pg_eventstore/subscriptions/events_processor_consumer/multiple.rbs +17 -0
  264. data/sig/pg_eventstore/subscriptions/events_processor_consumer/replica.rbs +17 -0
  265. data/sig/pg_eventstore/subscriptions/events_processor_consumer/single.rbs +17 -0
  266. data/sig/pg_eventstore/subscriptions/events_processor_consumer.rbs +14 -0
  267. data/sig/pg_eventstore/subscriptions/events_subscription_position_worker.rbs +28 -0
  268. data/sig/pg_eventstore/subscriptions/queries/subscription_queries.rbs +7 -39
  269. data/sig/pg_eventstore/subscriptions/replica_subscription_handler.rbs +33 -0
  270. data/sig/pg_eventstore/subscriptions/replica_subscription_runner.rbs +4 -0
  271. data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/collection.rbs +14 -0
  272. data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/index_read_strategy.rbs +23 -0
  273. data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/replication_strategy.rbs +23 -0
  274. data/sig/pg_eventstore/subscriptions/subscription_feed_strategy.rbs +11 -0
  275. data/sig/pg_eventstore/subscriptions/subscription_feeder.rbs +13 -10
  276. data/sig/pg_eventstore/subscriptions/subscription_handler_performance.rbs +1 -1
  277. data/sig/pg_eventstore/subscriptions/subscription_runner.rbs +13 -2
  278. data/sig/pg_eventstore/subscriptions/subscription_runners_feeder.rbs +1 -8
  279. data/sig/pg_eventstore/subscriptions/subscriptions_lifecycle.rbs +4 -6
  280. data/sig/pg_eventstore/subscriptions/subscriptions_manager.rbs +29 -43
  281. data/sig/pg_eventstore/synchronized_array.rbs +4 -0
  282. data/sig/pg_eventstore/utils.rbs +10 -11
  283. data/sig/pg_eventstore/web/application.rbs +13 -3
  284. data/sig/pg_eventstore/web/paginator/base_collection.rbs +2 -0
  285. data/sig/pg_eventstore/web/paginator/event_types_collection.rbs +4 -0
  286. data/sig/pg_eventstore/web/paginator/events_collection.rbs +11 -11
  287. data/sig/pg_eventstore/web/paginator/helpers.rbs +6 -15
  288. data/sig/pg_eventstore/web/paginator/markers_collection.rbs +13 -0
  289. data/sig/pg_eventstore/web/paginator/stream_contexts_collection.rbs +4 -0
  290. data/sig/pg_eventstore/web/paginator/stream_names_collection.rbs +4 -0
  291. data/sig/pg_eventstore/web/paginator/streams_collection.rbs +30 -0
  292. data/sig/pg_eventstore.rbs +8 -26
  293. metadata +175 -20
  294. data/Dockerfile +0 -3
  295. data/lib/pg_eventstore/commands/all_stream_read_grouped.rb +0 -69
  296. data/lib/pg_eventstore/commands/regular_stream_read_grouped.rb +0 -31
  297. data/lib/pg_eventstore/subscriptions/queries/subscription_service_queries.rb +0 -78
  298. data/lib/pg_eventstore/web/views/home/partials/system_stream_filter.erb +0 -15
  299. data/sig/pg_eventstore/commands/all_stream_read_grouped.rbs +0 -16
  300. data/sig/pg_eventstore/commands/regular_stream_read_grouped.rbs +0 -8
  301. data/sig/pg_eventstore/subscriptions/queries/subscription_service_queries.rbs +0 -19
  302. data/sig/pg_eventstore/subscriptions/synchronized_array.rbs +0 -4
  303. /data/sig/interfaces/{_raw_event_handler.rbs → raw_event_handler.rbs} +0 -0
@@ -20,20 +20,34 @@ module PgEventstore
20
20
  # @param stream [PgEventstore::Stream]
21
21
  # @param events_or_event [PgEventstore::Event, Array<PgEventstore::Event>]
22
22
  # @param options [Hash]
23
- # @option options [Integer] :expected_revision provide your own revision number
23
+ # @option options [Integer] :expected_revision expected stream revision
24
24
  # @option options [Symbol] :expected_revision provide one of next values: :any, :no_stream or :stream_exists
25
- # @param middlewares [Array, nil] provide a list of middleware names to override a config's middlewares
25
+ # @option options [Hash<String, Integer>, Hash<String, Symbol>] :expected_revision
26
+ # <even type>-to-<expected stream revision> map. Allows to define expected stream revision at the given event
27
+ # type. Useful when implementing Dynamic Consistency Boundaries
28
+ # @option options [Hash<String, Hash>] :expected_revision <even type>-to-<markers> map. Allows to define expected
29
+ # stream revision at the given event type, scoped to the specific marker(s). Useful when implementing
30
+ # Dynamic Consistency Boundaries
31
+ # @param middlewares [Array<Symbol>, nil] provide a list of middleware names to override a config's middlewares
26
32
  # @return [PgEventstore::Event, Array<PgEventstore::Event>] persisted event(s)
27
33
  # @raise [PgEventstore::WrongExpectedRevisionError]
28
34
  def append_to_stream(stream, events_or_event, options: {}, middlewares: nil)
29
- result =
30
- Commands::Append.new(
31
- Queries.new(
32
- partitions: partition_queries,
33
- events: event_queries(middlewares(middlewares)),
34
- transactions: transaction_queries
35
- )
36
- ).call(stream, *events_or_event, options:)
35
+ Utils.assert_node_role!(config, Config::NodeRole.writable)
36
+ middlewares = self.middlewares(middlewares)
37
+ event_modifier = Commands::EventModifiers::PrepareRegularEvent.new(EventSerializer.new(middlewares))
38
+ queries = Queries.new(
39
+ partitions: partition_queries,
40
+ events: event_queries,
41
+ transactions: transaction_queries,
42
+ events_global_index: events_global_index_queries,
43
+ streams_global_index: streams_global_index_queries,
44
+ event_subscription_positions: event_subscription_position_queries,
45
+ event_markers: event_marker_queries,
46
+ index_filtering: index_filtering_queries
47
+ )
48
+ result = Commands::Append.new(queries).call(
49
+ stream, *events_or_event, event_modifier:, deserializer: event_deserializer(middlewares), options:
50
+ )
37
51
  events_or_event.is_a?(Array) ? result : result.first
38
52
  end
39
53
 
@@ -61,16 +75,22 @@ module PgEventstore
61
75
  # :asc, :desc
62
76
  # @option options [Integer] :from_revision a starting revision number. **Use this option when stream name is a
63
77
  # normal stream name**
78
+ # @option options [Integer] :to_revision ending revision number. **Use this option when stream name is a
79
+ # normal stream name**
64
80
  # @option options [Integer] :from_position a starting global position number. **Use this option when reading
65
81
  # from "all" stream**
82
+ # @option options [Integer] :to_position ending global position number. **Use this option when reading from
83
+ # "all" stream**
66
84
  # @option options [Integer] :max_count max number of events to return in one response. Defaults to config.max_count
67
85
  # @option options [Boolean] :resolve_link_tos When using projections to create new events you
68
86
  # can set whether the generated events are pointers to existing events. Setting this option to true tells
69
87
  # PgEventstore to return the original event instead a link event.
70
- # @option options [Hash] :filter provide it to filter events. You can filter by: stream and by event type. Filtering
71
- # by stream is only available when reading from "all" stream.
72
- # Examples:
73
- # # Filtering by stream's context. This will return all events which #context is 'User
88
+ # @option options [Hash] :filter provide it to filter events. You can filter by: stream, event type and event
89
+ # markers. Filtering by stream is only available when reading from "all" stream.
90
+ # Basically, you can mix almost all combinations of stream attributes, event types and markers. That are some
91
+ # limitations, though. Please refer to docs/reading_events.md for details.
92
+ # Here are some examples:
93
+ # # Filtering by stream's context. This will return all events which #context is 'User'
74
94
  # PgEventstore.client.read(
75
95
  # PgEventstore::Stream.all_stream,
76
96
  # options: { filter: { streams: [{ context: 'User' }] } }
@@ -105,42 +125,92 @@ module PgEventstore
105
125
  #
106
126
  # # Filtering by specific event when reading from the specific stream
107
127
  # PgEventstore.client.read(stream, options: { filter: { event_types: ['MyAwesomeEvent'] } })
108
- # @param middlewares [Array, nil] provide a list of middleware names to override a config's middlewares
128
+ #
129
+ # # Filtering a specific stream by event markers
130
+ # PgEventstore.client.read(stream, options: { filter: { event_types: [{ markers: ['foo'] }] } })
131
+ #
132
+ # # Filtering a specific stream by event type with markers and event types
133
+ # PgEventstore.client.read(
134
+ # stream, options: { filter: { event_types: [{ type: 'Foo', markers: ['foo'] }, 'Bar'] } }
135
+ # )
136
+ #
137
+ # # Filtering all events by markers
138
+ # PgEventstore.client.read(
139
+ # PgEventstore::Stream.all_stream, options: { filter: { event_types: [{ markers: ['foo'] }] } }
140
+ # )
141
+ # @param middlewares [Array<Symbol>, nil] provide a list of middleware names to override a config's middlewares
109
142
  # @return [Array<PgEventstore::Event>]
110
143
  # @raise [PgEventstore::StreamNotFoundError]
111
144
  def read(stream, options: {}, middlewares: nil)
112
- Commands::Read.
113
- new(Queries.new(partitions: partition_queries, events: event_queries(middlewares(middlewares)))).
114
- call(stream, options: { max_count: config.max_count }.merge(options))
145
+ queries = Queries.new(
146
+ index_filtering: index_filtering_queries,
147
+ streams_global_index: streams_global_index_queries
148
+ )
149
+ Commands::Read.new(queries).call(
150
+ stream,
151
+ deserializer: event_deserializer(middlewares(middlewares)),
152
+ options: { max_count: config.max_count }.merge(options)
153
+ )
115
154
  end
116
155
 
117
156
  # @see {#read} for the detailed docs
118
157
  # @param stream [PgEventstore::Stream]
119
158
  # @param options [Hash] request options
120
- # @param middlewares [Array, nil]
121
- # @return [Enumerator] enumerator will yield PgEventstore::Event
159
+ # @param middlewares [Array<Symbol>, nil]
160
+ # @return [Enumerator] enumerator will yield Array<PgEventstore::Event>
122
161
  def read_paginated(stream, options: {}, middlewares: nil)
123
162
  cmd_class = stream.system? ? Commands::SystemStreamReadPaginated : Commands::RegularStreamReadPaginated
124
- cmd_class.
125
- new(Queries.new(partitions: partition_queries, events: event_queries(middlewares(middlewares)))).
126
- call(stream, options: { max_count: config.max_count }.merge(options))
163
+ queries = Queries.new(
164
+ index_filtering: index_filtering_queries,
165
+ streams_global_index: streams_global_index_queries
166
+ )
167
+ cmd_class.new(queries).call(
168
+ stream,
169
+ deserializer: event_deserializer(middlewares(middlewares)),
170
+ options: { max_count: config.max_count }.merge(options)
171
+ )
127
172
  end
128
173
 
129
- # Takes a stream, determines a list of even types in it and returns most recent(or very first - depending on
130
- # :direction option) events, one of each type. If :event_types filter is provided - uses it instead of automatic
131
- # event types lookup logic. The result size is almost always less than or equal to event types list size, so passing
132
- # :max_count option does not make any effect. In case if event of same type appears in different context/stream
133
- # name - it will be counted as a different event, thus, may appear several times in the result.
174
+ # Takes a stream, event types filter and returns most recent(or very first - depending on :direction option) events,
175
+ # one of each given type. The result size is almost always less than or equal to event types list size, so passing
176
+ # :max_count option does not take any effect. In case if event of same type appears in different context/stream
177
+ # name - it will be counted as a different event, thus, may appear several times in the result, scoped to each
178
+ # context and stream name in the result. Useful when implementing Dynamic Consistency Boundaries.
134
179
  # @see {#read} for the detailed docs
135
180
  # @param stream [PgEventstore::Stream]
136
181
  # @param options [Hash] request options
137
- # @param middlewares [Array, nil]
182
+ # @param middlewares [Array<Symbol>, nil]
138
183
  # @return [Array<PgEventstore::Event>]
139
184
  def read_grouped(stream, options: {}, middlewares: nil)
140
- cmd_class = stream.all_stream? ? Commands::AllStreamReadGrouped : Commands::RegularStreamReadGrouped
141
- cmd_class.
142
- new(Queries.new(partitions: partition_queries, events: event_queries(middlewares(middlewares)))).
143
- call(stream, options:)
185
+ queries = Queries.new(
186
+ index_filtering: index_filtering_queries,
187
+ streams_global_index: streams_global_index_queries
188
+ )
189
+ Commands::ReadGrouped.new(queries).call(
190
+ stream, deserializer: event_deserializer(middlewares(middlewares)), options:
191
+ )
192
+ end
193
+
194
+ # @param options [Hash] request options
195
+ # @option options [String] :direction read direction. Allowed values are "Forwards", "Backwards", "asc", "desc",
196
+ # :asc, :desc
197
+ # @option options [Integer] :from_position a starting global position number
198
+ # @option options [Integer] :max_count max number of streams to return in one response. Defaults to config.max_count
199
+ # @return [Array<PgEventstore::Stream>]
200
+ def read_streams(options: {})
201
+ queries = Queries.new(streams_global_index: streams_global_index_queries)
202
+ Commands::ReadStreams.new(queries).call(options: { max_count: config.max_count }.merge(options))
203
+ end
204
+
205
+ # @param options [Hash] request options
206
+ # @option options [String] :direction read direction. Allowed values are "Forwards", "Backwards", "asc", "desc",
207
+ # :asc, :desc
208
+ # @option options [Integer] :from_position a starting global position number
209
+ # @option options [Integer] :max_count max number of streams to yield. Defaults to config.max_count
210
+ # @return [Enumerator] yields Array<PgEventstore::Stream>
211
+ def read_streams_paginated(options: {})
212
+ queries = Queries.new(streams_global_index: streams_global_index_queries)
213
+ Commands::ReadStreamsPaginated.new(queries).call(options: { max_count: config.max_count }.merge(options))
144
214
  end
145
215
 
146
216
  # Links event from one stream into another stream. You can later access it by providing :resolve_link_tos option
@@ -150,25 +220,42 @@ module PgEventstore
150
220
  # @param options [Hash]
151
221
  # @option options [Integer] :expected_revision provide your own revision number
152
222
  # @option options [Symbol] :expected_revision provide one of next values: :any, :no_stream or :stream_exists
153
- # @param middlewares [Array] provide a list of middleware names to use. Defaults to empty array, meaning no
223
+ # @param middlewares [Array<Symbol>] provide a list of middleware names to use. Defaults to empty array, meaning no
154
224
  # middlewares will be applied to the "link" event
155
225
  # @return [PgEventstore::Event, Array<PgEventstore::Event>] persisted event(s)
156
226
  # @raise [PgEventstore::WrongExpectedRevisionError]
157
227
  def link_to(stream, events_or_event, options: {}, middlewares: [])
158
- result =
159
- Commands::LinkTo.new(
160
- Queries.new(
161
- partitions: partition_queries,
162
- events: event_queries(middlewares(middlewares)),
163
- transactions: transaction_queries
164
- )
165
- ).call(stream, *events_or_event, options:)
228
+ Utils.assert_node_role!(config, Config::NodeRole.writable)
229
+ middlewares = self.middlewares(middlewares)
230
+ event_modifier = Commands::EventModifiers::PrepareLinkEvent.new(
231
+ partition_queries, EventSerializer.new(middlewares)
232
+ )
233
+ queries = Queries.new(
234
+ partitions: partition_queries,
235
+ events: event_queries,
236
+ transactions: transaction_queries,
237
+ events_global_index: events_global_index_queries,
238
+ streams_global_index: streams_global_index_queries,
239
+ event_subscription_positions: event_subscription_position_queries,
240
+ event_markers: event_marker_queries,
241
+ index_filtering: index_filtering_queries
242
+ )
243
+ result = Commands::LinkTo.new(queries).call(
244
+ stream, *events_or_event, event_modifier:, deserializer: event_deserializer(middlewares), options:
245
+ )
166
246
  events_or_event.is_a?(Array) ? result : result.first
167
247
  end
168
248
 
249
+ # @param stream [PgEventstore::Stream]
250
+ # @return [Integer]
251
+ def stream_revision(stream)
252
+ queries = Queries.new(streams_global_index: streams_global_index_queries)
253
+ Commands::StreamRevision.new(queries).call(stream)
254
+ end
255
+
169
256
  private
170
257
 
171
- # @param middlewares [Array, nil]
258
+ # @param middlewares [Array<Symbol>, nil]
172
259
  # @return [Array<PgEventstore::Middleware>]
173
260
  def middlewares(middlewares = nil)
174
261
  return config.middlewares.values unless middlewares
@@ -191,14 +278,40 @@ module PgEventstore
191
278
  TransactionQueries.new(connection)
192
279
  end
193
280
 
194
- # @param middlewares [Array<Object<#serialize, #deserialize>>]
195
281
  # @return [PgEventstore::EventQueries]
196
- def event_queries(middlewares)
197
- EventQueries.new(
198
- connection,
199
- EventSerializer.new(middlewares),
200
- EventDeserializer.new(middlewares, config.event_class_resolver)
201
- )
282
+ def event_queries
283
+ EventQueries.new(connection)
284
+ end
285
+
286
+ # @param middlewares [Array<Middleware>]
287
+ # @return [PgEventstore::EventDeserializer]
288
+ def event_deserializer(middlewares)
289
+ EventDeserializer.new(middlewares, config.event_class_resolver)
290
+ end
291
+
292
+ # @return [PgEventstore::EventsGlobalIndexQueries]
293
+ def events_global_index_queries
294
+ EventsGlobalIndexQueries.new(connection, QueryStrategy::Foreground.new(connection))
295
+ end
296
+
297
+ # @return [PgEventstore::StreamsGlobalIndexQueries]
298
+ def streams_global_index_queries
299
+ StreamsGlobalIndexQueries.new(connection, QueryStrategy::Foreground.new(connection))
300
+ end
301
+
302
+ # @return [PgEventstore::EventSubscriptionPositionQueries]
303
+ def event_subscription_position_queries
304
+ EventSubscriptionPositionQueries.new(connection)
305
+ end
306
+
307
+ # @return [PgEventstore::EventMarkerQueries]
308
+ def event_marker_queries
309
+ EventMarkerQueries.new(connection, QueryStrategy::Foreground.new(connection))
310
+ end
311
+
312
+ # @return [PgEventstore::IndexFilteringQueries]
313
+ def index_filtering_queries
314
+ IndexFilteringQueries.new(connection, QueryStrategy::Foreground.new(connection))
202
315
  end
203
316
  end
204
317
  end
@@ -1,71 +1,90 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'revision_check/stream_revision_check'
4
+
3
5
  module PgEventstore
4
6
  module Commands
5
7
  # @!visibility private
6
8
  class Append < AbstractCommand
7
9
  # @param stream [PgEventstore::Stream]
8
10
  # @param events [Array<PgEventstore::Event>]
11
+ # @param event_modifier [#call]
12
+ # @param deserializer [PgEventstore::EventDeserializer]
9
13
  # @param options [Hash]
10
14
  # @option options [Integer] :expected_revision provide your own revision number
11
15
  # @option options [Symbol] :expected_revision provide one of next values: :any, :no_stream or :stream_exists
12
- # @param event_modifier [#call]
13
16
  # @return [Array<PgEventstore::Event>] persisted events
14
17
  # @raise [PgEventstore::WrongExpectedRevisionError]
15
- def call(stream, *events, options: {}, event_modifier: EventModifiers::PrepareRegularEvent.new)
18
+ def call(stream, *events, event_modifier:, deserializer:, options: {})
16
19
  raise SystemStreamError, stream if stream.system?
20
+ raise ArgumentError, 'No events to append.' if events.empty?
17
21
 
18
- queries.transactions.transaction do
19
- revision = queries.events.stream_revision(stream) || Stream::NON_EXISTING_STREAM_REVISION
20
- assert_expected_revision!(revision, options[:expected_revision], stream) if options[:expected_revision]
21
- formatted_events = events.map.with_index(1) do |event, index|
22
- event_modifier.call(event, revision + index)
22
+ events = events.map(&event_modifier.method(:call))
23
+ markers = events.flat_map { _1.markers + feature_markers(_1) }.uniq
24
+ raw_events = queries.transactions.transaction(:repeatable_read) do
25
+ revision_to_marker_ids_map = {}
26
+ partitions = prepare_partitions(stream, events)
27
+ markers_map = queries.event_markers.find_or_create_by(markers).to_h { [_1.name, _1.id] } if markers.any?
28
+ stream_index = queries.streams_global_index.find_or_create_by(stream)
29
+ revision = stream_index.stream_revision
30
+ expected_revision = RevisionCheck::ExpectedRevision.build(options[:expected_revision])
31
+ current_revision = RevisionCheck::CurrentRevision.build(
32
+ stream, revision, expected_revision, queries.index_filtering
33
+ )
34
+ RevisionCheck::StreamRevisionCheck.assert_eq!(current_revision, expected_revision, stream)
35
+ events.each.with_index(1) do |event, index|
36
+ event.stream_revision = revision + index
37
+ event.markers.each do |event_marker|
38
+ revision_to_marker_ids_map[revision + index] ||= Set.new
39
+ revision_to_marker_ids_map[revision + index].add(markers_map[event_marker])
40
+ end
41
+ event.feature_markers.each do |feature_marker|
42
+ revision_to_marker_ids_map[revision + index] ||= Set.new
43
+ revision_to_marker_ids_map[revision + index].add(markers_map[feature_marker.marker])
44
+ end
45
+ end
46
+ revision += events.size
47
+ queries.events.insert(stream, events).tap do |created_events|
48
+ stream_idx_attrs_to_update = { stream_revision: revision }
49
+ if stream_index.starting_position == StreamGlobalIndex::INITIAL_STARTING_POSITION
50
+ stream_idx_attrs_to_update[:starting_position] = created_events.first['global_position']
51
+ end
52
+ queries.streams_global_index.update(stream_index.id, **stream_idx_attrs_to_update)
53
+ write_api_events_idx = queries.events_global_index.index_events(created_events, partitions, stream_index.id)
54
+ queries.event_subscription_positions.create_unprocessed_positions(created_events)
55
+ if markers.any?
56
+ queries.event_markers.create_indexes(
57
+ stream_index.id, write_api_events_idx, revision_to_marker_ids_map
58
+ )
59
+ end
23
60
  end
24
- create_partitions(stream, formatted_events)
25
- queries.events.insert(stream, formatted_events)
26
61
  end
62
+ # It is important to return events in the form they were persisted into the database instead passing them
63
+ # through the configured middlewares
64
+ deserializer.deserialize_many(raw_events)
27
65
  end
28
66
 
29
67
  private
30
68
 
31
- # @param stream [PgEventstore::Stream]
32
- # @param events [Array<PgEventstore::Event>]
33
- # @return [void]
34
- def create_partitions(stream, events)
35
- missing_event_types = events.map(&:type).map(&:to_s).uniq.select do |event_type|
36
- queries.partitions.partition_required?(stream, event_type)
37
- end
38
- raise MissingPartitions.new(stream, missing_event_types) if missing_event_types.any?
69
+ # @param event [PgEventstore::Event]
70
+ # @return [Array<String>]
71
+ def feature_markers(event)
72
+ event.feature_markers.map(&:marker)
39
73
  end
40
74
 
41
- # @param revision [Integer]
42
- # @param expected_revision [Symbol, Integer]
43
75
  # @param stream [PgEventstore::Stream]
44
- # @raise [PgEventstore::WrongExpectedRevisionError] in case if revision does not satisfy expected revision
45
- # @return [void]
46
- def assert_expected_revision!(revision, expected_revision, stream)
47
- return if expected_revision == :any
48
-
49
- case [revision, expected_revision]
50
- in [Integer, Integer]
51
- unless revision == expected_revision
52
- raise WrongExpectedRevisionError.new(
53
- revision:, expected_revision:, stream:
54
- )
55
- end
76
+ # @param events [Array<PgEventstore::Event>]
77
+ # @return [Array<PgEventstore::Partition>]
78
+ def prepare_partitions(stream, events)
79
+ event_types = events.map { _1.type.to_s }.uniq
80
+ filter_collection = QueryBuilders::Filters::Collection.from_options(
81
+ { filter: { streams: [{ context: stream.context, stream_name: stream.stream_name }], event_types: } }
82
+ )
83
+ existing_partitions = queries.partitions.partitions(filter_collection)
84
+ missing_event_types = event_types - existing_partitions.map(&:event_type)
85
+ raise MissingPartitions.new(stream, missing_event_types) if missing_event_types.any?
56
86
 
57
- in [Integer, Symbol]
58
- if revision == Stream::NON_EXISTING_STREAM_REVISION && expected_revision == :stream_exists
59
- raise WrongExpectedRevisionError.new(
60
- revision:, expected_revision:, stream:
61
- )
62
- end
63
- if revision > Stream::NON_EXISTING_STREAM_REVISION && expected_revision == :no_stream
64
- raise WrongExpectedRevisionError.new(
65
- revision:, expected_revision:, stream:
66
- )
67
- end
68
- end
87
+ existing_partitions
69
88
  end
70
89
  end
71
90
  end
@@ -13,15 +13,14 @@ module PgEventstore
13
13
  # @param force [Boolean]
14
14
  # @return [Boolean]
15
15
  def call(event, force:)
16
- queries.transactions.transaction do
17
- event = queries.maintenance.reload_event(event)
18
- next false unless event
16
+ raise ArgumentError, "Event#stream is nil: #{event.inspect}" unless event.stream
17
+ return false if queries.events_global_index.global_positions_from_db([event]).empty?
19
18
 
20
- check_records_number_to_lock(event) unless force
21
- queries.maintenance.delete_event(event)
22
- queries.maintenance.adjust_stream_revisions(event.stream, event.stream_revision)
23
- true
24
- end
19
+ check_records_number_to_lock(event) unless force
20
+ queries.maintenance.delete_event(event)
21
+ true
22
+ rescue RecordNotFound
23
+ false
25
24
  end
26
25
 
27
26
  private
@@ -9,9 +9,9 @@ module PgEventstore
9
9
  def call(stream)
10
10
  raise SystemStreamError, stream if stream.system?
11
11
 
12
- queries.transactions.transaction do
13
- queries.maintenance.delete_stream(stream) > 0
14
- end
12
+ queries.maintenance.delete_stream(stream) > 0
13
+ rescue RecordNotFound
14
+ false
15
15
  end
16
16
  end
17
17
  end
@@ -9,23 +9,25 @@ module PgEventstore
9
9
  attr_reader :partition_queries, :partitions
10
10
 
11
11
  # @param partition_queries [PgEventstore::PartitionQueries]
12
- def initialize(partition_queries)
12
+ # @param serializer [PgEventstore::EventSerializer]
13
+ def initialize(partition_queries, serializer)
13
14
  @partitions = {}
14
15
  @partition_queries = partition_queries
16
+ @serializer = serializer
15
17
  end
16
18
 
17
19
  # @param event [PgEventstore::Event]
18
- # @param revision [Integer]
19
20
  # @return [PgEventstore::Event]
20
- def call(event, revision)
21
- Event.new(
21
+ def call(event)
22
+ event = Event.new(
22
23
  link_global_position: event.global_position,
23
24
  link_partition_id: partition_id(event),
24
- type: Event::LINK_TYPE,
25
- stream_revision: revision
25
+ type: Event::LINK_TYPE
26
26
  ).tap do |e|
27
- %i[link_global_position link_partition_id type stream_revision].each { |attr| e.readonly!(attr) }
27
+ %i[link_global_position link_partition_id type].each { |attr| e.readonly!(attr) }
28
28
  end
29
+ @serializer.serialize(event)
30
+ event
29
31
  end
30
32
 
31
33
  private
@@ -6,15 +6,20 @@ module PgEventstore
6
6
  # Defines how to transform regular event before appending it to the stream
7
7
  # @!visibility private
8
8
  class PrepareRegularEvent
9
+ # @param serializer [PgEventstore::EventSerializer]
10
+ def initialize(serializer)
11
+ @serializer = serializer
12
+ end
13
+
9
14
  # @param event [PgEventstore::Event]
10
- # @param revision [Integer]
11
15
  # @return [PgEventstore::Event]
12
- def call(event, revision)
13
- event.class.new(
14
- id: event.id, data: event.data, metadata: event.metadata, type: event.type, stream_revision: revision
15
- ).tap do |e|
16
- %i[link_global_position link_partition_id stream_revision].each { |attr| e.readonly!(attr) }
17
- end
16
+ def call(event)
17
+ event = event.dup
18
+ event.link_global_position = nil
19
+ event.link_partition_id = nil
20
+ %i[link_global_position link_partition_id].each { |attr| event.readonly!(attr) }
21
+ @serializer.serialize(event)
22
+ event
18
23
  end
19
24
  end
20
25
  end
@@ -6,18 +6,18 @@ module PgEventstore
6
6
  class LinkTo < AbstractCommand
7
7
  # @param stream [PgEventstore::Stream]
8
8
  # @param events [Array<PgEventstore::Event>]
9
+ # @param event_modifier [#call]
10
+ # @param deserializer [PgEventstore::EventDeserializer]
9
11
  # @param options [Hash]
10
12
  # @option options [Integer] :expected_revision provide your own revision number
11
13
  # @option options [Symbol] :expected_revision provide one of next values: :any, :no_stream or :stream_exists
12
14
  # @return [Array<PgEventstore::Event>] persisted events
13
15
  # @raise [PgEventstore::WrongExpectedRevisionError]
14
16
  # @raise [PgEventstore::NotPersistedEventError]
15
- def call(stream, *events, options: {})
17
+ def call(stream, *events, event_modifier:, deserializer:, options: {})
16
18
  check_events_presence(events)
17
19
  append_cmd = Append.new(queries)
18
- append_cmd.call(
19
- stream, *events, options:, event_modifier: EventModifiers::PrepareLinkEvent.new(queries.partitions)
20
- )
20
+ append_cmd.call(stream, *events, event_modifier:, deserializer:, options:)
21
21
  end
22
22
 
23
23
  private
@@ -27,7 +27,7 @@ module PgEventstore
27
27
  # @param events [Array<PgEventstore::Event>]
28
28
  # @return [void]
29
29
  def check_events_presence(events)
30
- global_positions_from_db = queries.events.global_positions_from_db(events)
30
+ global_positions_from_db = queries.events_global_index.global_positions_from_db(events)
31
31
  missing_ids = events.map(&:global_position) - global_positions_from_db
32
32
  return if missing_ids.empty?
33
33
 
@@ -5,19 +5,37 @@ module PgEventstore
5
5
  # @!visibility private
6
6
  class Read < AbstractCommand
7
7
  # @param stream [PgEventstore::Stream]
8
+ # @param deserializer [PgEventstore::EventDeserializer]
8
9
  # @param options [Hash] request options
9
10
  # @option options [String] :direction read direction - 'Forwards' or 'Backwards'
10
- # @option options [Integer, Symbol] :from_revision. **Use this option when stream name is a normal stream name**
11
- # @option options [Integer, Symbol] :from_position. **Use this option when reading from "all" stream**
11
+ # @option options [Integer] :from_revision. **Use this option when stream is a regular stream**
12
+ # @option options [Integer] :from_position. **Use this option when reading from "all" stream**
13
+ # @option options [Integer] :to_revision. **Use this option when stream is a regular stream**
14
+ # @option options [Integer] :to_position. **Use this option when reading from "all" stream**
12
15
  # @option options [Integer] :max_count
13
16
  # @option options [Boolean] :resolve_link_tos
14
17
  # @option options [Hash] :filter provide it to filter events
15
18
  # @return [Array<PgEventstore::Event>]
16
19
  # @raise [PgEventstore::StreamNotFoundError]
17
- def call(stream, options: {})
18
- queries.events.stream_revision(stream) || raise(StreamNotFoundError, stream) unless stream.system?
20
+ def call(stream, deserializer:, options: {})
21
+ queries.streams_global_index.stream_exists?(stream) || raise(StreamNotFoundError, stream) unless stream.system?
19
22
 
20
- queries.events.stream_events(stream, options)
23
+ filter_collection = QueryBuilders::Filters::Collection.from_stream_and_options(stream, options)
24
+ cursor = QueryBuilders::ReadCursor::StreamCursor.from_stream_and_options(stream, options)
25
+ raise NotSupportedError, '#read does not support look up by prefix.' if filter_collection.has_prefix_filter?
26
+
27
+ if filter_collection.has_incomplete_markers_filter? && filter_collection.has_incomplete_stream_filter?
28
+ error_message = <<~TEXT.strip
29
+ #read does not support look up by context/context & stream name and markers filter without specifying \
30
+ event type explicitly. Please add specific event type to your markers filter. \
31
+ Example: { filter: { event_types: [{ type: 'Foo', markers: ['foo', 'bar'] }] } }
32
+ TEXT
33
+ raise NotSupportedError, error_message
34
+ end
35
+
36
+ indexes = queries.index_filtering.fetch_indexes_for_read_api(filter_collection, cursor)
37
+ repo = queries.index_filtering.compute_read_api_chunks_repo(indexes, options[:resolve_link_tos] || false)
38
+ deserializer.deserialize_many(repo.consume_all)
21
39
  end
22
40
  end
23
41
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ module Commands
5
+ # @!visibility private
6
+ class ReadGrouped < AbstractCommand
7
+ # @param stream [PgEventstore::Stream]
8
+ # @param deserializer [PgEventstore::EventDeserializer]
9
+ # @param options [Hash] request options
10
+ # @option options [String] :direction read direction - 'Forwards' or 'Backwards'
11
+ # @option options [Integer, Symbol] :from_revision. **Use this option when stream name is a normal stream name**
12
+ # @option options [Integer, Symbol] :from_position. **Use this option when reading from "all" stream**
13
+ # @option options [Integer] :to_revision. **Use this option when stream is a regular stream**
14
+ # @option options [Integer] :to_position. **Use this option when reading from "all" stream**
15
+ # @option options [Integer] :max_count
16
+ # @option options [Boolean] :resolve_link_tos
17
+ # @option options [Hash] :filter provide it to filter events
18
+ # @return [Array<PgEventstore::Event>]
19
+ # @raise [PgEventstore::StreamNotFoundError]
20
+ def call(stream, deserializer:, options: {})
21
+ filter_collection = QueryBuilders::Filters::Collection.from_stream_and_options(stream, options)
22
+ cursor = QueryBuilders::ReadCursor::StreamCursor.from_stream_and_options(stream, options)
23
+ if filter_collection.has_prefix_filter?
24
+ raise NotSupportedError, '#read_grouped does not support look up by prefix.'
25
+ end
26
+ if !filter_collection.has_event_types? && !filter_collection.has_markers?
27
+ raise ArgumentError, '#read_grouped requires correct :event_types filter.'
28
+ end
29
+
30
+ if filter_collection.has_incomplete_markers_filter? && filter_collection.has_incomplete_stream_filter?
31
+ error_message = <<~TEXT.strip
32
+ #read_paginated does not support look up by context/context & stream name and markers filter without \
33
+ specifying event type explicitly. Please add specific event type to your markers filter. \
34
+ Example: { filter: { event_types: [{ type: 'Foo', markers: ['foo', 'bar'] }] } }
35
+ TEXT
36
+ raise NotSupportedError, error_message
37
+ end
38
+ queries.streams_global_index.stream_exists?(stream) || raise(StreamNotFoundError, stream) unless stream.system?
39
+
40
+ indexes = queries.index_filtering.fetch_grouped_indexes_for_read_api(filter_collection, cursor)
41
+ repo = queries.index_filtering.compute_read_api_chunks_repo(indexes, options[:resolve_link_tos] || false)
42
+ deserializer.deserialize_many(repo.consume_all)
43
+ end
44
+ end
45
+ end
46
+ end