pg_eventstore 1.13.4 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +11 -2
  3. data/CHANGELOG.md +195 -16
  4. data/README.md +33 -10
  5. data/db/migrations/10_setup_pg_cron.rb +1 -0
  6. data/db/migrations/11_add_events_link_global_position.sql +1 -0
  7. data/db/migrations/12_migrate_legacy_links.rb +83 -0
  8. data/db/migrations/13_remove_events_link_id.sql +6 -0
  9. data/db/migrations/14_remove_ids_events_id_index.sql +1 -0
  10. data/db/migrations/15_create_streams_global_index.sql +17 -0
  11. data/db/migrations/16_populate_streams_global_index.rb +150 -0
  12. data/db/migrations/17_create_events_global_index.sql +62 -0
  13. data/db/migrations/18_populate_events_global_index.rb +124 -0
  14. data/db/migrations/19_populate_events_global_index_p2.rb +25 -0
  15. data/db/migrations/20_migrate_subscriptions_current_position.sql +19 -0
  16. data/db/migrations/21_create_partitions_stats.sql +2 -0
  17. data/db/migrations/22_drop_streams_sql_view.sql +2 -0
  18. data/db/migrations/23_adjust_partitions_indexes.sql +5 -0
  19. data/db/migrations/24_drop_legacy_events_indexes.sql +3 -0
  20. data/db/migrations/25_add_parent_partitions_info_to_partitions.sql +16 -0
  21. data/db/migrations/26_change_events_stream_revision_type.rb +35 -0
  22. data/db/migrations/27_drop_events_horizon.sql +3 -0
  23. data/db/migrations/28_create_maintenance_tasks.sql +8 -0
  24. data/db/migrations/29_create_event_markers.sql +35 -0
  25. data/db/migrations/30_improve_partitions_search_in_admin_ui.rb +24 -0
  26. data/db/migrations/31_drop_events_id_default_value.sql +1 -0
  27. data/db/migrations/32_create_parittions_triggers.sql +101 -0
  28. data/db/migrations/9_create_events_horizon.sql +21 -0
  29. data/docs/AGENTS.fragment.md +696 -0
  30. data/docs/admin_ui.md +3 -1
  31. data/docs/appending_events.md +110 -49
  32. data/docs/configuration.md +69 -36
  33. data/docs/event_tracing.md +55 -0
  34. data/docs/events_and_streams.md +54 -30
  35. data/docs/how_it_works.md +57 -16
  36. data/docs/linking_events.md +2 -1
  37. data/docs/maintenance.md +14 -5
  38. data/docs/multiple_commands.md +30 -6
  39. data/docs/reading_events.md +208 -43
  40. data/docs/reading_streams.md +50 -0
  41. data/docs/replication.md +99 -0
  42. data/docs/subscriptions.md +165 -35
  43. data/docs/writing_middleware.md +25 -8
  44. data/ext/pg_eventstore_ext/extconf.rb +5 -0
  45. data/ext/pg_eventstore_ext/pg_eventstore_ext.c +74 -0
  46. data/lib/pg_eventstore/async_runner.rb +63 -0
  47. data/lib/pg_eventstore/basic_config.rb +15 -0
  48. data/lib/pg_eventstore/callbacks.rb +7 -5
  49. data/lib/pg_eventstore/chunks/chunk.rb +31 -0
  50. data/lib/pg_eventstore/chunks/read_api_events_index_chunk.rb +83 -0
  51. data/lib/pg_eventstore/chunks/replica_events_index_chunk.rb +35 -0
  52. data/lib/pg_eventstore/chunks/repository.rb +73 -0
  53. data/lib/pg_eventstore/chunks/subscription_checkpoint_chunk.rb +48 -0
  54. data/lib/pg_eventstore/chunks/subscription_events_index_chunk.rb +99 -0
  55. data/lib/pg_eventstore/chunks.rb +14 -0
  56. data/lib/pg_eventstore/cli/try_to_delete_subscriptions_set.rb +2 -2
  57. data/lib/pg_eventstore/client.rb +167 -52
  58. data/lib/pg_eventstore/commands/append.rb +62 -43
  59. data/lib/pg_eventstore/commands/delete_event.rb +7 -8
  60. data/lib/pg_eventstore/commands/delete_stream.rb +3 -3
  61. data/lib/pg_eventstore/commands/event_modifiers/prepare_link_event.rb +11 -6
  62. data/lib/pg_eventstore/commands/event_modifiers/prepare_regular_event.rb +12 -7
  63. data/lib/pg_eventstore/commands/link_to.rb +9 -9
  64. data/lib/pg_eventstore/commands/multiple.rb +2 -2
  65. data/lib/pg_eventstore/commands/read.rb +23 -5
  66. data/lib/pg_eventstore/commands/read_grouped.rb +46 -0
  67. data/lib/pg_eventstore/commands/read_streams.rb +18 -0
  68. data/lib/pg_eventstore/commands/read_streams_paginated.rb +56 -0
  69. data/lib/pg_eventstore/commands/regular_stream_read_paginated.rb +4 -4
  70. data/lib/pg_eventstore/commands/revision_check/current_revision.rb +51 -0
  71. data/lib/pg_eventstore/commands/revision_check/event_type_revisions_comparison.rb +46 -0
  72. data/lib/pg_eventstore/commands/revision_check/expected_revision.rb +135 -0
  73. data/lib/pg_eventstore/commands/revision_check/stream_revision_check.rb +98 -0
  74. data/lib/pg_eventstore/commands/revision_check/stream_revision_comparison.rb +36 -0
  75. data/lib/pg_eventstore/commands/stream_revision.rb +14 -0
  76. data/lib/pg_eventstore/commands/system_stream_read_paginated.rb +4 -4
  77. data/lib/pg_eventstore/commands.rb +4 -2
  78. data/lib/pg_eventstore/config.rb +30 -9
  79. data/lib/pg_eventstore/connection.rb +22 -37
  80. data/lib/pg_eventstore/errors.rb +137 -11
  81. data/lib/pg_eventstore/event.rb +39 -7
  82. data/lib/pg_eventstore/event_deserializer.rb +5 -4
  83. data/lib/pg_eventstore/event_global_index.rb +118 -0
  84. data/lib/pg_eventstore/event_marker.rb +16 -0
  85. data/lib/pg_eventstore/event_marker_index.rb +25 -0
  86. data/lib/pg_eventstore/event_serializer.rb +6 -0
  87. data/lib/pg_eventstore/extensions/acts_as_configurable.rb +88 -0
  88. data/lib/pg_eventstore/extensions/options_defaults.rb +25 -0
  89. data/lib/pg_eventstore/extensions/options_extension.rb +42 -13
  90. data/lib/pg_eventstore/feature_marker.rb +18 -0
  91. data/lib/pg_eventstore/maintenance.rb +11 -6
  92. data/lib/pg_eventstore/middleware/event_tracing.rb +53 -0
  93. data/lib/pg_eventstore/partition.rb +6 -0
  94. data/lib/pg_eventstore/pg_connection.rb +70 -14
  95. data/lib/pg_eventstore/queries/event_marker_queries.rb +74 -0
  96. data/lib/pg_eventstore/queries/event_queries.rb +9 -95
  97. data/lib/pg_eventstore/queries/events_global_index_queries.rb +131 -0
  98. data/lib/pg_eventstore/queries/index_filtering_queries.rb +179 -0
  99. data/lib/pg_eventstore/queries/links_resolver.rb +10 -7
  100. data/lib/pg_eventstore/queries/maintenance_queries.rb +159 -42
  101. data/lib/pg_eventstore/queries/partition_queries.rb +46 -104
  102. data/lib/pg_eventstore/queries/replica_queries.rb +110 -0
  103. data/lib/pg_eventstore/queries/streams_global_index_queries.rb +163 -0
  104. data/lib/pg_eventstore/queries/transaction_queries.rb +58 -10
  105. data/lib/pg_eventstore/queries.rb +29 -1
  106. data/lib/pg_eventstore/query_builders/basic_filtering.rb +38 -5
  107. data/lib/pg_eventstore/query_builders/event_markers_filtering.rb +47 -0
  108. data/lib/pg_eventstore/query_builders/event_markers_index_filtering.rb +275 -0
  109. data/lib/pg_eventstore/query_builders/event_subscription_positions_filtering.rb +37 -0
  110. data/lib/pg_eventstore/query_builders/events_filtering.rb +15 -164
  111. data/lib/pg_eventstore/query_builders/events_global_index_filtering.rb +227 -0
  112. data/lib/pg_eventstore/query_builders/filters/collection.rb +324 -0
  113. data/lib/pg_eventstore/query_builders/filters/event_type_filter.rb +37 -0
  114. data/lib/pg_eventstore/query_builders/filters/filter_row.rb +54 -0
  115. data/lib/pg_eventstore/query_builders/filters/marker_filter.rb +20 -0
  116. data/lib/pg_eventstore/query_builders/filters/marker_filter_row.rb +49 -0
  117. data/lib/pg_eventstore/query_builders/filters/stream_filter.rb +48 -0
  118. data/lib/pg_eventstore/query_builders/index_based_events_filtering.rb +260 -0
  119. data/lib/pg_eventstore/query_builders/partitions_filtering.rb +175 -51
  120. data/lib/pg_eventstore/query_builders/read_cursor/stream_cursor.rb +122 -0
  121. data/lib/pg_eventstore/query_builders/streams_global_index_filtering.rb +83 -0
  122. data/lib/pg_eventstore/query_builders/subscription_events_filtering.rb +79 -0
  123. data/lib/pg_eventstore/query_strategy/async.rb +64 -0
  124. data/lib/pg_eventstore/query_strategy/foreground.rb +25 -0
  125. data/lib/pg_eventstore/query_strategy.rb +19 -0
  126. data/lib/pg_eventstore/raw_event.rb +46 -0
  127. data/lib/pg_eventstore/rspec/test_helpers.rb +21 -8
  128. data/lib/pg_eventstore/sql_builder.rb +87 -8
  129. data/lib/pg_eventstore/stream.rb +14 -17
  130. data/lib/pg_eventstore/stream_global_index.rb +28 -0
  131. data/lib/pg_eventstore/subscriptions/basic_runner.rb +4 -4
  132. data/lib/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rb +5 -17
  133. data/lib/pg_eventstore/subscriptions/callback_handlers/events_subscription_position_worker_handlers.rb +36 -0
  134. data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rb +13 -1
  135. data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rb +19 -14
  136. data/lib/pg_eventstore/subscriptions/events_processor.rb +21 -19
  137. data/lib/pg_eventstore/subscriptions/events_processor_consumer/multiple.rb +63 -0
  138. data/lib/pg_eventstore/subscriptions/events_processor_consumer/replica.rb +68 -0
  139. data/lib/pg_eventstore/subscriptions/events_processor_consumer/single.rb +62 -0
  140. data/lib/pg_eventstore/subscriptions/events_processor_consumer.rb +44 -0
  141. data/lib/pg_eventstore/subscriptions/events_subscription_position_worker.rb +68 -0
  142. data/lib/pg_eventstore/subscriptions/queries/event_subscription_position_queries.rb +177 -0
  143. data/lib/pg_eventstore/subscriptions/queries/subscription_command_queries.rb +5 -5
  144. data/lib/pg_eventstore/subscriptions/queries/subscription_queries.rb +80 -56
  145. data/lib/pg_eventstore/subscriptions/queries/subscriptions_set_command_queries.rb +2 -2
  146. data/lib/pg_eventstore/subscriptions/queries/subscriptions_set_queries.rb +1 -1
  147. data/lib/pg_eventstore/subscriptions/replica_subscription_handler.rb +140 -0
  148. data/lib/pg_eventstore/subscriptions/replica_subscription_runner.rb +9 -0
  149. data/lib/pg_eventstore/subscriptions/subscription.rb +9 -7
  150. data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/collection.rb +36 -0
  151. data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/index_read_strategy.rb +82 -0
  152. data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/replication_strategy.rb +75 -0
  153. data/lib/pg_eventstore/subscriptions/subscription_feed_strategy.rb +31 -0
  154. data/lib/pg_eventstore/subscriptions/subscription_feeder.rb +26 -2
  155. data/lib/pg_eventstore/subscriptions/subscription_handler_performance.rb +5 -5
  156. data/lib/pg_eventstore/subscriptions/subscription_runner.rb +20 -22
  157. data/lib/pg_eventstore/subscriptions/subscription_runner_commands/reset_position.rb +1 -1
  158. data/lib/pg_eventstore/subscriptions/subscription_runners_feeder.rb +10 -11
  159. data/lib/pg_eventstore/subscriptions/subscriptions_lifecycle.rb +0 -12
  160. data/lib/pg_eventstore/subscriptions/subscriptions_manager.rb +84 -29
  161. data/lib/pg_eventstore/{subscriptions/synchronized_array.rb → synchronized_array.rb} +15 -0
  162. data/lib/pg_eventstore/tasks/setup.rake +32 -33
  163. data/lib/pg_eventstore/utils.rb +39 -0
  164. data/lib/pg_eventstore/version.rb +1 -1
  165. data/lib/pg_eventstore/web/application.rb +104 -20
  166. data/lib/pg_eventstore/web/paginator/base_collection.rb +5 -1
  167. data/lib/pg_eventstore/web/paginator/event_types_collection.rb +14 -4
  168. data/lib/pg_eventstore/web/paginator/events_collection.rb +29 -33
  169. data/lib/pg_eventstore/web/paginator/helpers.rb +19 -12
  170. data/lib/pg_eventstore/web/paginator/markers_collection.rb +48 -0
  171. data/lib/pg_eventstore/web/paginator/stream_contexts_collection.rb +13 -2
  172. data/lib/pg_eventstore/web/paginator/stream_ids_collection.rb +21 -11
  173. data/lib/pg_eventstore/web/paginator/stream_names_collection.rb +18 -4
  174. data/lib/pg_eventstore/web/paginator/streams_collection.rb +95 -0
  175. data/lib/pg_eventstore/web/public/javascripts/pg_eventstore.js +49 -22
  176. data/lib/pg_eventstore/web/subscriptions/helpers.rb +2 -2
  177. data/lib/pg_eventstore/web/subscriptions/set_collection.rb +1 -1
  178. data/lib/pg_eventstore/web/subscriptions/subscriptions.rb +1 -1
  179. data/lib/pg_eventstore/web/subscriptions/with_state/set_collection.rb +1 -1
  180. data/lib/pg_eventstore/web/subscriptions/with_state/subscriptions.rb +1 -1
  181. data/lib/pg_eventstore/web/views/home/dashboard.erb +11 -9
  182. data/lib/pg_eventstore/web/views/home/partials/event_filter.erb +18 -5
  183. data/lib/pg_eventstore/web/views/home/partials/events.erb +38 -1
  184. data/lib/pg_eventstore/web/views/home/partials/markers_filter.erb +18 -0
  185. data/lib/pg_eventstore/web/views/layouts/application.erb +6 -0
  186. data/lib/pg_eventstore/web/views/streams/index.erb +110 -0
  187. data/lib/pg_eventstore/web/views/streams/partials/streams.erb +11 -0
  188. data/lib/pg_eventstore/web/views/subscriptions/index.erb +4 -1
  189. data/lib/pg_eventstore/web.rb +2 -0
  190. data/lib/pg_eventstore.rb +26 -63
  191. data/pg_eventstore.gemspec +6 -4
  192. data/sig/interfaces/_raw_events_handler.rbs +3 -0
  193. data/sig/interfaces/subscription_handler.rbs +1 -1
  194. data/sig/pg/result.rbs +9 -0
  195. data/sig/pg_eventstore/async_runner.rbs +13 -0
  196. data/sig/pg_eventstore/basic_config.rbs +9 -0
  197. data/sig/pg_eventstore/chunks/chunk.rbs +13 -0
  198. data/sig/pg_eventstore/chunks/read_api_events_index_chunk.rbs +30 -0
  199. data/sig/pg_eventstore/chunks/replica_events_index_chunk.rbs +11 -0
  200. data/sig/pg_eventstore/chunks/repository.rbs +22 -0
  201. data/sig/pg_eventstore/chunks/subscription_checkpoint_chunk.rbs +18 -0
  202. data/sig/pg_eventstore/chunks/subscription_events_index_chunk.rbs +37 -0
  203. data/sig/pg_eventstore/client.rbs +41 -43
  204. data/sig/pg_eventstore/commands/append.rbs +11 -25
  205. data/sig/pg_eventstore/commands/event_modifiers/prepare_link_event.rbs +9 -12
  206. data/sig/pg_eventstore/commands/event_modifiers/prepare_regular_event.rbs +5 -4
  207. data/sig/pg_eventstore/commands/link_to.rbs +6 -11
  208. data/sig/pg_eventstore/commands/multiple.rbs +1 -1
  209. data/sig/pg_eventstore/commands/read.rbs +2 -5
  210. data/sig/pg_eventstore/commands/read_grouped.rbs +7 -0
  211. data/sig/pg_eventstore/commands/read_streams.rbs +7 -0
  212. data/sig/pg_eventstore/commands/read_streams_paginated.rbs +16 -0
  213. data/sig/pg_eventstore/commands/regular_stream_read_paginated.rbs +9 -17
  214. data/sig/pg_eventstore/commands/revision_check/current_revision.rbs +25 -0
  215. data/sig/pg_eventstore/commands/revision_check/event_type_revisions_comparison.rbs +14 -0
  216. data/sig/pg_eventstore/commands/revision_check/expected_revision.rbs +67 -0
  217. data/sig/pg_eventstore/commands/revision_check/stream_revision_check.rbs +20 -0
  218. data/sig/pg_eventstore/commands/revision_check/stream_revision_comparison.rbs +9 -0
  219. data/sig/pg_eventstore/commands/stream_revision.rbs +7 -0
  220. data/sig/pg_eventstore/commands/system_stream_read_paginated.rbs +9 -14
  221. data/sig/pg_eventstore/config.rbs +15 -6
  222. data/sig/pg_eventstore/connection.rbs +11 -18
  223. data/sig/pg_eventstore/errors.rbs +64 -34
  224. data/sig/pg_eventstore/event.rbs +20 -6
  225. data/sig/pg_eventstore/event_deserializer.rbs +5 -10
  226. data/sig/pg_eventstore/event_global_index.rbs +60 -0
  227. data/sig/pg_eventstore/event_marker.rbs +9 -0
  228. data/sig/pg_eventstore/event_marker_index.rbs +12 -0
  229. data/sig/pg_eventstore/extensions/acts_as_configurable.rbs +29 -0
  230. data/sig/pg_eventstore/extensions/options_defaults.rbs +7 -0
  231. data/sig/pg_eventstore/extensions/options_extension.rbs +9 -1
  232. data/sig/pg_eventstore/feature_marker.rbs +10 -0
  233. data/sig/pg_eventstore/maintenance.rbs +12 -8
  234. data/sig/pg_eventstore/middleware/event_trace.rbs +14 -0
  235. data/sig/pg_eventstore/partition.rbs +2 -4
  236. data/sig/pg_eventstore/pg_connection.rbs +8 -0
  237. data/sig/pg_eventstore/queries/event_marker_queries.rbs +21 -0
  238. data/sig/pg_eventstore/queries/event_queries.rbs +6 -38
  239. data/sig/pg_eventstore/queries/events_global_index_queries.rbs +37 -0
  240. data/sig/pg_eventstore/queries/index_filtering_queries.rbs +50 -0
  241. data/sig/pg_eventstore/queries/links_resolver.rbs +7 -11
  242. data/sig/pg_eventstore/queries/maintenance_queries.rbs +12 -9
  243. data/sig/pg_eventstore/queries/partition_queries.rbs +32 -67
  244. data/sig/pg_eventstore/queries/replica_queries.rbs +31 -0
  245. data/sig/pg_eventstore/queries/streams_global_index_queries.rbs +39 -0
  246. data/sig/pg_eventstore/queries/transaction_queries.rbs +4 -2
  247. data/sig/pg_eventstore/queries.rbs +11 -21
  248. data/sig/pg_eventstore/query_builders/basic_filtering.rbs +10 -3
  249. data/sig/pg_eventstore/query_builders/event_markers_filtering.rbs +17 -0
  250. data/sig/pg_eventstore/query_builders/event_markers_index_filtering.rbs +69 -0
  251. data/sig/pg_eventstore/query_builders/event_subscription_positions_filtering.rbs +15 -0
  252. data/sig/pg_eventstore/query_builders/events_filtering_query.rbs +9 -51
  253. data/sig/pg_eventstore/query_builders/events_global_index_filtering.rbs +68 -0
  254. data/sig/pg_eventstore/query_builders/filters/collection.rbs +84 -0
  255. data/sig/pg_eventstore/query_builders/filters/event_type_filter.rbs +19 -0
  256. data/sig/pg_eventstore/query_builders/filters/filter_row.rbs +21 -0
  257. data/sig/pg_eventstore/query_builders/filters/marker_filter.rbs +13 -0
  258. data/sig/pg_eventstore/query_builders/filters/marker_filter_row.rbs +19 -0
  259. data/sig/pg_eventstore/query_builders/filters/stream_filter.rbs +24 -0
  260. data/sig/pg_eventstore/query_builders/index_based_events_filtering.rbs +60 -0
  261. data/sig/pg_eventstore/query_builders/partitions_filtering.rbs +29 -10
  262. data/sig/pg_eventstore/query_builders/read_cursor/stream_cursor.rbs +47 -0
  263. data/sig/pg_eventstore/query_builders/streams_global_index_filtering.rbs +27 -0
  264. data/sig/pg_eventstore/query_builders/subscription_events_filtering.rbs +26 -0
  265. data/sig/pg_eventstore/query_strategy/async.rbs +17 -0
  266. data/sig/pg_eventstore/query_strategy/foreground.rbs +11 -0
  267. data/sig/pg_eventstore/query_strategy.rbs +7 -0
  268. data/sig/pg_eventstore/raw_event.rbs +20 -0
  269. data/sig/pg_eventstore/sql_builder.rbs +32 -10
  270. data/sig/pg_eventstore/stream.rbs +10 -18
  271. data/sig/pg_eventstore/stream_global_index.rbs +14 -0
  272. data/sig/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rbs +5 -4
  273. data/sig/pg_eventstore/subscriptions/callback_handlers/events_subscription_position_worker_handlers.rbs +9 -0
  274. data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rbs +17 -12
  275. data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rbs +16 -8
  276. data/sig/pg_eventstore/subscriptions/event_subscription_position_queries.rbs +30 -0
  277. data/sig/pg_eventstore/subscriptions/events_processor.rbs +12 -5
  278. data/sig/pg_eventstore/subscriptions/events_processor_consumer/multiple.rbs +17 -0
  279. data/sig/pg_eventstore/subscriptions/events_processor_consumer/replica.rbs +17 -0
  280. data/sig/pg_eventstore/subscriptions/events_processor_consumer/single.rbs +17 -0
  281. data/sig/pg_eventstore/subscriptions/events_processor_consumer.rbs +14 -0
  282. data/sig/pg_eventstore/subscriptions/events_subscription_position_worker.rbs +28 -0
  283. data/sig/pg_eventstore/subscriptions/queries/subscription_queries.rbs +18 -50
  284. data/sig/pg_eventstore/subscriptions/replica_subscription_handler.rbs +33 -0
  285. data/sig/pg_eventstore/subscriptions/replica_subscription_runner.rbs +4 -0
  286. data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/collection.rbs +14 -0
  287. data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/index_read_strategy.rbs +23 -0
  288. data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/replication_strategy.rbs +23 -0
  289. data/sig/pg_eventstore/subscriptions/subscription_feed_strategy.rbs +11 -0
  290. data/sig/pg_eventstore/subscriptions/subscription_feeder.rbs +13 -10
  291. data/sig/pg_eventstore/subscriptions/subscription_handler_performance.rbs +1 -1
  292. data/sig/pg_eventstore/subscriptions/subscription_runner.rbs +13 -5
  293. data/sig/pg_eventstore/subscriptions/subscription_runners_feeder.rbs +5 -5
  294. data/sig/pg_eventstore/subscriptions/subscriptions_lifecycle.rbs +4 -6
  295. data/sig/pg_eventstore/subscriptions/subscriptions_manager.rbs +29 -43
  296. data/sig/pg_eventstore/synchronized_array.rbs +4 -0
  297. data/sig/pg_eventstore/utils.rbs +18 -11
  298. data/sig/pg_eventstore/web/application.rbs +13 -3
  299. data/sig/pg_eventstore/web/paginator/base_collection.rbs +2 -0
  300. data/sig/pg_eventstore/web/paginator/event_types_collection.rbs +4 -0
  301. data/sig/pg_eventstore/web/paginator/events_collection.rbs +11 -11
  302. data/sig/pg_eventstore/web/paginator/helpers.rbs +6 -15
  303. data/sig/pg_eventstore/web/paginator/markers_collection.rbs +13 -0
  304. data/sig/pg_eventstore/web/paginator/stream_contexts_collection.rbs +4 -0
  305. data/sig/pg_eventstore/web/paginator/stream_names_collection.rbs +4 -0
  306. data/sig/pg_eventstore/web/paginator/streams_collection.rbs +30 -0
  307. data/sig/pg_eventstore.rbs +8 -26
  308. metadata +181 -21
  309. data/lib/pg_eventstore/commands/all_stream_read_grouped.rb +0 -69
  310. data/lib/pg_eventstore/commands/regular_stream_read_grouped.rb +0 -31
  311. data/lib/pg_eventstore/subscriptions/queries/service_queries.rb +0 -73
  312. data/lib/pg_eventstore/subscriptions/subscription_position_evaluation.rb +0 -195
  313. data/lib/pg_eventstore/web/views/home/partials/system_stream_filter.erb +0 -15
  314. data/sig/pg_eventstore/commands/all_stream_read_grouped.rbs +0 -16
  315. data/sig/pg_eventstore/commands/regular_stream_read_grouped.rbs +0 -8
  316. data/sig/pg_eventstore/subscriptions/queries/service_queries.rbs +0 -15
  317. data/sig/pg_eventstore/subscriptions/subscription_position_evaluation.rbs +0 -53
  318. data/sig/pg_eventstore/subscriptions/synchronized_array.rbs +0 -4
  319. /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: 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
 
@@ -47,9 +61,11 @@ module PgEventstore
47
61
  # PgEventstore.client.append_to_stream(...)
48
62
  # end
49
63
  #
64
+ # @param read_only [Boolean] whether transaction is read-only. Running mutation queries within read-only transaction
65
+ # will result in exception
50
66
  # @return the result of the given block
51
- def multiple(&blk)
52
- Commands::Multiple.new(Queries.new(transactions: transaction_queries)).call(&blk)
67
+ def multiple(read_only: false, &)
68
+ Commands::Multiple.new(Queries.new(transactions: transaction_queries)).call(read_only:, &)
53
69
  end
54
70
 
55
71
  # Read events from the specific stream or from "all" stream.
@@ -59,16 +75,22 @@ module PgEventstore
59
75
  # :asc, :desc
60
76
  # @option options [Integer] :from_revision a starting revision number. **Use this option when stream name is a
61
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**
62
80
  # @option options [Integer] :from_position a starting global position number. **Use this option when reading
63
81
  # from "all" stream**
82
+ # @option options [Integer] :to_position ending global position number. **Use this option when reading from
83
+ # "all" stream**
64
84
  # @option options [Integer] :max_count max number of events to return in one response. Defaults to config.max_count
65
85
  # @option options [Boolean] :resolve_link_tos When using projections to create new events you
66
86
  # can set whether the generated events are pointers to existing events. Setting this option to true tells
67
87
  # PgEventstore to return the original event instead a link event.
68
- # @option options [Hash] :filter provide it to filter events. You can filter by: stream and by event type. Filtering
69
- # by stream is only available when reading from "all" stream.
70
- # Examples:
71
- # # 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'
72
94
  # PgEventstore.client.read(
73
95
  # PgEventstore::Stream.all_stream,
74
96
  # options: { filter: { streams: [{ context: 'User' }] } }
@@ -103,42 +125,92 @@ module PgEventstore
103
125
  #
104
126
  # # Filtering by specific event when reading from the specific stream
105
127
  # PgEventstore.client.read(stream, options: { filter: { event_types: ['MyAwesomeEvent'] } })
106
- # @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
107
142
  # @return [Array<PgEventstore::Event>]
108
143
  # @raise [PgEventstore::StreamNotFoundError]
109
144
  def read(stream, options: {}, middlewares: nil)
110
- Commands::Read.
111
- new(Queries.new(partitions: partition_queries, events: event_queries(middlewares(middlewares)))).
112
- 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
+ )
113
154
  end
114
155
 
115
156
  # @see {#read} for the detailed docs
116
157
  # @param stream [PgEventstore::Stream]
117
158
  # @param options [Hash] request options
118
- # @param middlewares [Array, nil]
119
- # @return [Enumerator] enumerator will yield PgEventstore::Event
159
+ # @param middlewares [Array<Symbol>, nil]
160
+ # @return [Enumerator] enumerator will yield Array<PgEventstore::Event>
120
161
  def read_paginated(stream, options: {}, middlewares: nil)
121
162
  cmd_class = stream.system? ? Commands::SystemStreamReadPaginated : Commands::RegularStreamReadPaginated
122
- cmd_class.
123
- new(Queries.new(partitions: partition_queries, events: event_queries(middlewares(middlewares)))).
124
- 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
+ )
125
172
  end
126
173
 
127
- # Takes a stream, determines a list of even types in it and returns most recent(or very first - depending on
128
- # :direction option) events, one of each type. If :event_types filter is provided - uses it instead of automatic
129
- # event types lookup logic. The result size is almost always less than or equal to event types list size, so passing
130
- # :max_count option does not make any effect. In case if event of same type appears in different context/stream
131
- # 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.
132
179
  # @see {#read} for the detailed docs
133
180
  # @param stream [PgEventstore::Stream]
134
181
  # @param options [Hash] request options
135
- # @param middlewares [Array, nil]
182
+ # @param middlewares [Array<Symbol>, nil]
136
183
  # @return [Array<PgEventstore::Event>]
137
184
  def read_grouped(stream, options: {}, middlewares: nil)
138
- cmd_class = stream.all_stream? ? Commands::AllStreamReadGrouped : Commands::RegularStreamReadGrouped
139
- cmd_class.
140
- new(Queries.new(partitions: partition_queries, events: event_queries(middlewares(middlewares)))).
141
- call(stream, options: 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))
142
214
  end
143
215
 
144
216
  # Links event from one stream into another stream. You can later access it by providing :resolve_link_tos option
@@ -148,25 +220,42 @@ module PgEventstore
148
220
  # @param options [Hash]
149
221
  # @option options [Integer] :expected_revision provide your own revision number
150
222
  # @option options [Symbol] :expected_revision provide one of next values: :any, :no_stream or :stream_exists
151
- # @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
152
224
  # middlewares will be applied to the "link" event
153
225
  # @return [PgEventstore::Event, Array<PgEventstore::Event>] persisted event(s)
154
226
  # @raise [PgEventstore::WrongExpectedRevisionError]
155
227
  def link_to(stream, events_or_event, options: {}, middlewares: [])
156
- result =
157
- Commands::LinkTo.new(
158
- Queries.new(
159
- partitions: partition_queries,
160
- events: event_queries(middlewares(middlewares)),
161
- transactions: transaction_queries
162
- )
163
- ).call(stream, *events_or_event, options: 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
+ )
164
246
  events_or_event.is_a?(Array) ? result : result.first
165
247
  end
166
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
+
167
256
  private
168
257
 
169
- # @param middlewares [Array, nil]
258
+ # @param middlewares [Array<Symbol>, nil]
170
259
  # @return [Array<PgEventstore::Middleware>]
171
260
  def middlewares(middlewares = nil)
172
261
  return config.middlewares.values unless middlewares
@@ -189,14 +278,40 @@ module PgEventstore
189
278
  TransactionQueries.new(connection)
190
279
  end
191
280
 
192
- # @param middlewares [Array<Object<#serialize, #deserialize>>]
193
281
  # @return [PgEventstore::EventQueries]
194
- def event_queries(middlewares)
195
- EventQueries.new(
196
- connection,
197
- EventSerializer.new(middlewares),
198
- EventDeserializer.new(middlewares, config.event_class_resolver)
199
- )
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))
200
315
  end
201
316
  end
202
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: revision, expected_revision: expected_revision, stream: 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: revision, expected_revision: expected_revision, stream: stream
61
- )
62
- end
63
- if revision > Stream::NON_EXISTING_STREAM_REVISION && expected_revision == :no_stream
64
- raise WrongExpectedRevisionError.new(
65
- revision: revision, expected_revision: expected_revision, stream: 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,20 +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(
22
- link_id: event.id, link_partition_id: partition_id(event), type: Event::LINK_TYPE, stream_revision: revision
21
+ def call(event)
22
+ event = Event.new(
23
+ link_global_position: event.global_position,
24
+ link_partition_id: partition_id(event),
25
+ type: Event::LINK_TYPE
23
26
  ).tap do |e|
24
- %i[link_id 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) }
25
28
  end
29
+ @serializer.serialize(event)
30
+ event
26
31
  end
27
32
 
28
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_id 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,32 +6,32 @@ 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: 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
24
24
 
25
- # Checks if the given events are persisted events. This is needed to prevent potentially non-existing id valuess
26
- # from appearing in #link_id column.
25
+ # Checks if the given events are persisted events. This is needed to prevent potentially non-existing
26
+ # global_position values from appearing in #link_global_position column.
27
27
  # @param events [Array<PgEventstore::Event>]
28
28
  # @return [void]
29
29
  def check_events_presence(events)
30
- ids_from_db = queries.events.ids_from_db(events)
31
- missing_ids = events.map(&:id) - ids_from_db
30
+ global_positions_from_db = queries.events_global_index.global_positions_from_db(events)
31
+ missing_ids = events.map(&:global_position) - global_positions_from_db
32
32
  return if missing_ids.empty?
33
33
 
34
- missing_event = events.find { |event| event.id == missing_ids.first }
34
+ missing_event = events.find { |event| event.global_position == missing_ids.first }
35
35
  raise NotPersistedEventError, missing_event
36
36
  end
37
37
  end
@@ -4,8 +4,8 @@ module PgEventstore
4
4
  module Commands
5
5
  # @!visibility private
6
6
  class Multiple < AbstractCommand
7
- def call(&blk)
8
- queries.transactions.transaction(&blk)
7
+ def call(read_only:, &)
8
+ queries.transactions.transaction(read_only:, &)
9
9
  end
10
10
  end
11
11
  end
@@ -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