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
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ module QueryBuilders
5
+ module ReadCursor
6
+ # @!visibility private
7
+ class StreamCursor
8
+ class RegularStreamCursor
9
+ include Extensions::OptionsExtension
10
+ include Extensions::OptionsDefaults
11
+
12
+ # @!attribute from_revision
13
+ # @return [Integer, nil]
14
+ attribute(:from_revision)
15
+ # @!attribute to_revision
16
+ # @return [Integer, nil]
17
+ attribute(:to_revision)
18
+ # @!attribute direction
19
+ # @return [String, Symbol, nil]
20
+ attribute(:direction)
21
+ # @!attribute max_count
22
+ # @return [Integer, nil]
23
+ attribute(:max_count)
24
+ end
25
+
26
+ class AllStreamCursor
27
+ include Extensions::OptionsExtension
28
+ include Extensions::OptionsDefaults
29
+
30
+ # @!attribute from_position
31
+ # @return [Integer, nil]
32
+ attribute(:from_position)
33
+ # @!attribute to_position
34
+ # @return [Integer, nil]
35
+ attribute(:to_position)
36
+ # @!attribute direction
37
+ # @return [String, Symbol, nil]
38
+ attribute(:direction)
39
+ # @!attribute max_count
40
+ # @return [Integer, nil]
41
+ attribute(:max_count)
42
+ end
43
+
44
+ class << self
45
+ # @param options [Hash]
46
+ # @option options [Integer, nil] :from_position
47
+ # @option options [Integer, nil] :to_position
48
+ # @option options [String, Symbol, nil] :direction
49
+ # @option options [Integer, nil] :max_count
50
+ # @return [PgEventstore::QueryBuilders::ReadCursor::StreamCursor]
51
+ def from_options(options)
52
+ new(AllStreamCursor.new(**options))
53
+ end
54
+
55
+ # @param options [Hash]
56
+ # @option options [Integer, nil] :from_position for "all" stream
57
+ # @option options [Integer, nil] :to_position for "all" stream
58
+ # @option options [Integer, nil] :from_revision for regular stream
59
+ # @option options [Integer, nil] :to_revision for regular stream
60
+ # @option options [String, Symbol, nil] :direction
61
+ # @option options [Integer, nil] :max_count
62
+ # @return [PgEventstore::QueryBuilders::ReadCursor::StreamCursor]
63
+ def from_stream_and_options(stream, options)
64
+ return new(AllStreamCursor.new(**options)) if stream.all_stream?
65
+
66
+ new(RegularStreamCursor.new(**options))
67
+ end
68
+ end
69
+
70
+ # @param cursor [ReadCursor::RegularStreamCursor, ReadCursor::RegularStreamCursor]
71
+ def initialize(cursor)
72
+ @cursor = cursor
73
+ end
74
+
75
+ # @return [Integer, nil]
76
+ def from
77
+ case @cursor
78
+ when RegularStreamCursor
79
+ @cursor.from_revision
80
+ when AllStreamCursor
81
+ @cursor.from_position
82
+ else
83
+ Utils.missing_implementation!(@cursor)
84
+ end
85
+ end
86
+
87
+ # @return [Integer, nil]
88
+ def to
89
+ case @cursor
90
+ when RegularStreamCursor
91
+ @cursor.to_revision
92
+ when AllStreamCursor
93
+ @cursor.to_position
94
+ else
95
+ Utils.missing_implementation!(@cursor)
96
+ end
97
+ end
98
+
99
+ # @return [String, Symbol, nil]
100
+ def direction
101
+ @cursor.direction
102
+ end
103
+
104
+ # @return [Integer, nil]
105
+ def max_count
106
+ @cursor.max_count
107
+ end
108
+
109
+ # @param val [Integer, nil]
110
+ # @return [void]
111
+ def max_count=(val)
112
+ @cursor.max_count = val
113
+ end
114
+
115
+ # @return [Boolean]
116
+ def all_stream_cursor?
117
+ @cursor.is_a?(AllStreamCursor)
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ module QueryBuilders
5
+ # @!visibility private
6
+ class StreamsGlobalIndexFiltering
7
+ include BasicFiltering
8
+
9
+ # @return [String]
10
+ PRIMARY_TABLE_NAME = 'streams_global_index'
11
+ # @return [Integer]
12
+ DEFAULT_LIMIT = 1000
13
+
14
+ class << self
15
+ # @param options [Hash]
16
+ # @option options [Integer, nil] :from_position
17
+ # @option options [Integer, nil] :max_count
18
+ # @option options [String, Symbol, nil] :direction
19
+ # @return [PgEventstore::SQLBuilder]
20
+ def sql_builder_for_basic_pagination(options)
21
+ streams_idx_filtering = QueryBuilders::StreamsGlobalIndexFiltering.new
22
+ streams_idx_filtering.from_position(options[:from_position], options[:direction])
23
+ streams_idx_filtering.limit(options[:max_count])
24
+ streams_idx_filtering.add_starting_position_direction(options[:direction])
25
+ streams_idx_filtering.to_sql_builder
26
+ end
27
+ end
28
+
29
+ def initialize
30
+ @sql_builder = SQLBuilder.new.select("#{to_table_name}.*").from(to_table_name)
31
+ end
32
+
33
+ def to_sql_builder
34
+ @sql_builder
35
+ end
36
+
37
+ # @return [String]
38
+ def to_table_name
39
+ PRIMARY_TABLE_NAME
40
+ end
41
+
42
+ # @param filter_row [PgEventstore::QueryBuilders::Filters::FilterRow]
43
+ # @return [void]
44
+ def add_filter_row(filter_row)
45
+ stream_filter = filter_row.stream_filter
46
+ raise ArgumentError, "Invalid stream filter: #{stream_filter}" unless stream_filter&.stream?
47
+
48
+ affected_partitions = PartitionsFiltering.from_filter_row(filter_row, scope: :stream_name)
49
+ builder = affected_partitions.select_id_only
50
+ @sql_builder.where_or('partition_id = ? and stream_id = ?', builder, stream_filter.stream_id)
51
+ end
52
+
53
+ # @param position [Integer, nil]
54
+ # @param direction [Symbol, String, nil]
55
+ # @return [void]
56
+ def from_position(position, direction)
57
+ return if position.nil?
58
+
59
+ @sql_builder.where("starting_position #{direction_operator_from(direction)} ?", position)
60
+ end
61
+
62
+ # @param limit [Integer, nil]
63
+ # @return [void]
64
+ def limit(limit)
65
+ @sql_builder.limit(limit || DEFAULT_LIMIT)
66
+ end
67
+
68
+ # @param direction [Symbol, String, nil]
69
+ # @return [void]
70
+ def add_starting_position_direction(direction)
71
+ @sql_builder.order("#{to_table_name}.starting_position #{SQL_DIRECTIONS[direction]}")
72
+ end
73
+
74
+ private
75
+
76
+ # @param direction [String, Symbol, nil]
77
+ # @return [String]
78
+ def direction_operator_from(direction)
79
+ SQL_DIRECTIONS[direction] == 'ASC' ? '>=' : '<='
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ module QueryBuilders
5
+ # @!visibility private
6
+ class SubscriptionEventsFiltering
7
+ include BasicFiltering
8
+
9
+ class << self
10
+ # @param id [integer]
11
+ # @param options [Hash]
12
+ # @option options [Integer] :from_position
13
+ # @option options [Integer] :to_position
14
+ # @option options [Integer] :max_count
15
+ # @return [PgEventstore::QueryBuilders::SubscriptionEventsFiltering]
16
+ def build(id, options)
17
+ index_filter = new(id)
18
+ index_filter.from_position(options[:from_position])
19
+ index_filter.to_position(options[:to_position])
20
+ index_filter.add_limit(options[:max_count])
21
+ index_filter
22
+ end
23
+ end
24
+
25
+ # @param subscription_id [Integer]
26
+ def initialize(subscription_id)
27
+ @subscription_id = subscription_id
28
+ @from_position = 0
29
+ @to_position = 0
30
+ @max_count = 0
31
+ @sql_builder = SQLBuilder.new.select("#{to_table_name}.*")
32
+ compute_from
33
+ end
34
+
35
+ def to_sql_builder
36
+ compute_from
37
+ @sql_builder
38
+ end
39
+
40
+ # @param position [Integer, nil]
41
+ # @return [void]
42
+ def from_position(position)
43
+ raise ArgumentError, 'position must be valid number' unless position.is_a?(Integer)
44
+
45
+ @from_position = position
46
+ end
47
+
48
+ # @param position [Integer, nil]
49
+ # @return [void]
50
+ def to_position(position)
51
+ raise ArgumentError, 'position must be valid number' unless position.is_a?(Integer)
52
+
53
+ @to_position = position
54
+ end
55
+
56
+ # @param limit [Integer, nil]
57
+ # @return [void]
58
+ def add_limit(limit)
59
+ raise ArgumentError, 'limit must be valid number' unless limit.is_a?(Integer)
60
+
61
+ @max_count = limit
62
+ end
63
+
64
+ # @return [String]
65
+ def to_table_name
66
+ "subscription_#{@subscription_id}"
67
+ end
68
+
69
+ private
70
+
71
+ def compute_from
72
+ @sql_builder.from(
73
+ "#{to_table_name}(#{@from_position}, #{@to_position}, #{@max_count})",
74
+ table_alias: to_table_name
75
+ )
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ module QueryStrategy
5
+ # @!visibility private
6
+ class Async
7
+ include QueryStrategy
8
+
9
+ # @param connection [PgEventstore::Connection]
10
+ def initialize(connection)
11
+ @connection = connection
12
+ end
13
+
14
+ def exec(*)
15
+ run(:send_query, *)
16
+ end
17
+
18
+ def exec_params(*)
19
+ run(:send_query_params, *)
20
+ end
21
+
22
+ private
23
+
24
+ def run(method, *exec_args)
25
+ @connection.with do |conn|
26
+ conn.public_send(method, *exec_args)
27
+ loop do
28
+ conn.consume_input
29
+ break unless conn.is_busy
30
+
31
+ Fiber.yield
32
+ end
33
+
34
+ last_result = nil
35
+ while result = conn.get_result
36
+ # Check whether result is successful. Raises error if it is not.
37
+ # Related function is pg_result_check() in pg_result.c
38
+ result.check_result
39
+ last_result = result
40
+ end
41
+ last_result
42
+ rescue AsyncRunner::Cancellation
43
+ cancel_and_drain(conn)
44
+ Fiber.current.kill
45
+ end
46
+ end
47
+
48
+ # @param conn [PG::Connection]
49
+ # @return [void]
50
+ def cancel_and_drain(conn)
51
+ cancellation_error = conn.cancel
52
+ conn.sync_reset if cancellation_error
53
+
54
+ while (result = conn.get_result)
55
+ result.clear
56
+ end
57
+ rescue PG::Error
58
+ # We have unexpected error during the cancellation process. No need to try to restore the connection at this
59
+ # point and simply throw it out
60
+ @connection.discard_current_connection
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ module QueryStrategy
5
+ class Foreground
6
+ include QueryStrategy
7
+
8
+ def initialize(connection)
9
+ @connection = connection
10
+ end
11
+
12
+ def exec(*exec_args)
13
+ @connection.with do |conn|
14
+ conn.exec(*exec_args)
15
+ end
16
+ end
17
+
18
+ def exec_params(*exec_args)
19
+ @connection.with do |conn|
20
+ conn.exec_params(*exec_args)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ # @!visibility private
5
+ module QueryStrategy
6
+ # @return [PG::Result]
7
+ def exec(*args)
8
+ raise NotImplementedError
9
+ end
10
+
11
+ # @return [PG::Result]
12
+ def exec_params(*args)
13
+ raise NotImplementedError
14
+ end
15
+ end
16
+ end
17
+
18
+ require_relative 'query_strategy/async'
19
+ require_relative 'query_strategy/foreground'
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ # @!visibility private
5
+ class RawEvent
6
+ include Extensions::OptionsExtension
7
+ include Extensions::OptionsDefaults
8
+
9
+ # @!attribute id
10
+ # @return [String]
11
+ attribute(:id)
12
+ # @!attribute context
13
+ # @return [String]
14
+ attribute(:context)
15
+ # @!attribute stream_name
16
+ # @return [String]
17
+ attribute(:stream_name)
18
+ # @!attribute stream_id
19
+ # @return [String]
20
+ attribute(:stream_id)
21
+ # @!attribute global_position
22
+ # @return [Integer]
23
+ attribute(:global_position)
24
+ # @!attribute stream_revision
25
+ # @return [Integer]
26
+ attribute(:stream_revision)
27
+ # @!attribute data
28
+ # @return [Hash]
29
+ attribute(:data)
30
+ # @!attribute metadata
31
+ # @return [Hash]
32
+ attribute(:metadata)
33
+ # @!attribute link_partition_id
34
+ # @return [Integer, nil]
35
+ attribute(:link_partition_id)
36
+ # @!attribute created_at
37
+ # @return [Time]
38
+ attribute(:created_at)
39
+ # @!attribute type
40
+ # @return [String]
41
+ attribute(:type)
42
+ # @!attribute link_global_position
43
+ # @return [Integer, nil]
44
+ attribute(:link_global_position)
45
+ end
46
+ end
@@ -3,13 +3,14 @@
3
3
  module PgEventstore
4
4
  module TestHelpers
5
5
  class << self
6
- def clean_up_db
7
- clean_up_data
8
- clean_up_partitions
6
+ def clean_up_db(config = :default)
7
+ clean_up_data(config)
8
+ clean_up_partitions(config)
9
+ clean_up_subscription_functions(config)
9
10
  end
10
11
 
11
- def clean_up_partitions
12
- PgEventstore.connection.with do |conn|
12
+ def clean_up_partitions(config)
13
+ PgEventstore.connection(config).with do |conn|
13
14
  # Dropping parent partition also drops all child partitions
14
15
  conn.exec("select tablename from pg_tables where tablename like 'contexts_%'").each do |attrs|
15
16
  conn.exec("drop table #{attrs['tablename']}")
@@ -17,8 +18,8 @@ module PgEventstore
17
18
  end
18
19
  end
19
20
 
20
- def clean_up_data
21
- tables_to_purge = PgEventstore.connection.with do |conn|
21
+ def clean_up_data(config)
22
+ tables_to_purge = PgEventstore.connection(config).with do |conn|
22
23
  conn.exec(<<~SQL)
23
24
  SELECT tablename
24
25
  FROM pg_catalog.pg_tables
@@ -27,7 +28,19 @@ module PgEventstore
27
28
  end
28
29
  tables_to_purge = tables_to_purge.map { |attrs| attrs['tablename'] }
29
30
  tables_to_purge.each do |table_name|
30
- PgEventstore.connection.with { |c| c.exec("DELETE FROM #{table_name}") }
31
+ PgEventstore.connection(config).with { |c| c.exec("DELETE FROM #{table_name}") }
32
+ end
33
+ end
34
+
35
+ def clean_up_subscription_functions(config)
36
+ functions_to_purge = PgEventstore.connection(config).with do |conn|
37
+ conn.exec(<<~SQL)
38
+ SELECT proname FROM pg_proc WHERE proname LIKE 'subscription_%'
39
+ SQL
40
+ end
41
+ functions_to_purge = functions_to_purge.map { _1['proname'] }
42
+ functions_to_purge.each do |function_name|
43
+ PgEventstore.connection(config).with { |c| c.exec("drop function #{function_name}") }
31
44
  end
32
45
  end
33
46
  end
@@ -6,16 +6,35 @@ module PgEventstore
6
6
  class SQLBuilder
7
7
  class << self
8
8
  # @param builders [Array<PgEventstore::SQLBuilder>]
9
+ # @param mode [Symbol]
9
10
  # @return [PgEventstore::SQLBuilder]
10
- def union_builders(builders)
11
- builders[1..].each_with_object(builders[0]) do |builder, first_builder|
11
+ def union_builders(builders, mode: :union_all)
12
+ Utils.assert!(!builders.empty?, "Can't union empty array!")
13
+
14
+ union_builder = builders[1..].each_with_object(builders[0]) do |builder, first_builder|
12
15
  first_builder.union(builder)
13
16
  end
17
+ union_builder.union_mode = mode
18
+ union_builder
19
+ end
20
+
21
+ # @param builder [PgEventstore::SQLBuilder]
22
+ # @return [PgEventstore::SQLBuilder]
23
+ def wrap_union_builder(builder)
24
+ new.tap do |b|
25
+ b.select('*')
26
+ b.from(builder)
27
+ end
14
28
  end
15
29
  end
16
30
 
31
+ UNION_MODES = %i[union_all union_distinct intersect_all intersect_distinct].freeze
32
+ private_constant :UNION_MODES
33
+
17
34
  # @return [Array<Object>] sql positional values
18
35
  attr_reader :positional_values
36
+ # @return [String, nil]
37
+ attr_reader :table_alias
19
38
  # @return [Integer]
20
39
  attr_writer :positional_values_size
21
40
 
@@ -33,6 +52,8 @@ module PgEventstore
33
52
  @positional_values = []
34
53
  @positional_values_size = 0
35
54
  @union_values = []
55
+ @union_mode = :union_all
56
+ @table_alias = nil
36
57
  end
37
58
 
38
59
  # @param sql [String]
@@ -42,6 +63,14 @@ module PgEventstore
42
63
  self
43
64
  end
44
65
 
66
+ # @return [PgEventstore::SQLBuilder]
67
+ def select_id_only
68
+ raise 'You have to call #from first' unless @table_alias
69
+
70
+ remove_order.unselect.select("#{@table_alias}.id")
71
+ self
72
+ end
73
+
45
74
  # @return [self]
46
75
  def unselect
47
76
  @select_values.clear
@@ -64,10 +93,12 @@ module PgEventstore
64
93
  self
65
94
  end
66
95
 
67
- # @param table_name [String | SQLBuilder]
96
+ # @param table_name [String, SQLBuilder]
97
+ # @param table_alias [String, nil]
68
98
  # @return [self]
69
- def from(table_name)
99
+ def from(table_name, table_alias: nil)
70
100
  @from_value = table_name
101
+ @table_alias = table_alias || (table_name.is_a?(SQLBuilder) ? table_name.table_alias : table_name)
71
102
  self
72
103
  end
73
104
 
@@ -92,10 +123,16 @@ module PgEventstore
92
123
  self
93
124
  end
94
125
 
95
- # @param limit [Integer]
126
+ # @param limit [String, Integer]
96
127
  # @return [self]
97
128
  def limit(limit)
98
- @limit_value = limit.to_i
129
+ @limit_value =
130
+ case limit
131
+ when String
132
+ limit.start_with?(/\d/) ? limit.to_i : PG::Connection.escape(limit)
133
+ else
134
+ limit
135
+ end
99
136
  self
100
137
  end
101
138
 
@@ -139,6 +176,34 @@ module PgEventstore
139
176
  _to_exec_params
140
177
  end
141
178
 
179
+ def dup
180
+ self.class.new.tap do |inst|
181
+ inst.instance_variable_set(:@select_values, @select_values.map(&:dup))
182
+ inst.instance_variable_set(:@from_value, @from_value&.dup)
183
+ inst.instance_variable_set(:@where_values, @where_values.dup.transform_values(&:dup))
184
+ inst.instance_variable_set(:@join_values, @join_values.map(&:dup))
185
+ inst.instance_variable_set(:@group_values, @group_values.map(&:dup))
186
+ inst.instance_variable_set(:@order_values, @order_values.map(&:dup))
187
+ inst.instance_variable_set(:@limit_value, @limit_value&.dup)
188
+ inst.instance_variable_set(:@offset_value, @offset_value&.dup)
189
+ inst.instance_variable_set(:@positional_values, @positional_values.map(&:dup))
190
+ inst.instance_variable_set(:@positional_values_size, @positional_values_size)
191
+ inst.instance_variable_set(:@union_values, @union_values.map(&:dup))
192
+ inst.instance_variable_set(:@union_mode, @union_mode.dup)
193
+ inst.instance_variable_set(:@table_alias, @table_alias.dup)
194
+ end
195
+ end
196
+
197
+ def union_builder?
198
+ @union_values.any?
199
+ end
200
+
201
+ def union_mode=(val)
202
+ raise "Unknown UNION mode #{val.inspect}. Available modes are: #{UNION_MODES}" unless UNION_MODES.include?(val)
203
+
204
+ @union_mode = val
205
+ end
206
+
142
207
  protected
143
208
 
144
209
  # @return [[String, Array<_>]]
@@ -153,7 +218,7 @@ module PgEventstore
153
218
  return @from_value if @from_value.is_a?(String)
154
219
 
155
220
  sql = merge(@from_value)
156
- "(#{sql}) #{@from_value.from_sql}"
221
+ "(#{sql}) #{@table_alias}"
157
222
  end
158
223
 
159
224
  private
@@ -178,7 +243,20 @@ module PgEventstore
178
243
  union_parts += @union_values.map do |builder|
179
244
  "(#{merge(builder)})"
180
245
  end
181
- union_parts.join(' UNION ALL ')
246
+ union_mode_sql =
247
+ case @union_mode
248
+ when :union_all
249
+ 'UNION ALL'
250
+ when :union_distinct
251
+ 'UNION'
252
+ when :intersect_all
253
+ 'INTERSECT ALL'
254
+ when :intersect_distinct
255
+ 'INTERSECT'
256
+ else
257
+ Utils.missing_implementation!(@union_mode)
258
+ end
259
+ union_parts.join(" #{union_mode_sql} ")
182
260
  end
183
261
 
184
262
  # @return [String]
@@ -207,6 +285,7 @@ module PgEventstore
207
285
  # @param builder [PgEventstore::SQLBuilder]
208
286
  # @return [String]
209
287
  def merge(builder)
288
+ builder = builder.dup
210
289
  builder.positional_values_size = @positional_values_size
211
290
  sql_query, positional_values = builder._to_exec_params
212
291
  @positional_values.push(*positional_values)