Module: EventStoreRuby::Postgres::QueryBuilder

Defined in:
lib/eventstore_ruby/postgres/query.rb

Class Method Summary collapse

Class Method Details

.build_context_query(filter_or_query) ⇒ Object

Returns [sql, params] for a SELECT query returning all matching events, ordered by ascending sequence number. Accepts an EventFilter or an EventQuery (logical OR of filters).



13
14
15
16
# File 'lib/eventstore_ruby/postgres/query.rb', line 13

def build_context_query(filter_or_query)
  where_sql, params = compile_conditions(filter_or_query)
  ["SELECT * FROM events WHERE #{where_sql} ORDER BY sequence_number ASC", params]
end

.build_context_version_query(filter_or_query) ⇒ Object

Returns [where_sql, params] for usage inside CTEs (no SELECT/ORDER BY).



19
20
21
# File 'lib/eventstore_ruby/postgres/query.rb', line 19

def build_context_version_query(filter_or_query)
  compile_conditions(filter_or_query)
end

.compile_conditions(filter_or_query) ⇒ Object


Internal helpers




27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/eventstore_ruby/postgres/query.rb', line 27

def compile_conditions(filter_or_query)
  sql_fragments = []
  params = []

  if filter_or_query.is_a?(EventStoreRuby::EventQuery)
    filter_or_query.filters.each do |flt|
      sql_fragments << single_filter_condition(flt, params)
    end
  else
    sql_fragments << single_filter_condition(filter_or_query, params)
  end

  [sql_fragments.join(' OR '), params]
end

.pg_array_literal(strings) ⇒ Object



6
7
8
# File 'lib/eventstore_ruby/postgres/query.rb', line 6

def pg_array_literal(strings)
  '{' + strings.map { |s| s.gsub('"', '""') }.join(',') + '}'
end

.single_filter_condition(filter, params) ⇒ Object

Builds the SQL condition for a single EventFilter and pushes the corresponding parameters onto params Array. Returns the condition string wrapped in parentheses.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/eventstore_ruby/postgres/query.rb', line 45

def single_filter_condition(filter, params)
  param_index = params.length + 1
  params << pg_array_literal(filter.event_types)
  condition = "event_type = ANY($#{param_index}::text[])"

  if filter.payload_predicates&.any?
    or_conditions = filter.payload_predicates.map do |predicate|
      param_index = params.length + 1
      params << predicate.to_json
      "payload @> $#{param_index}"
    end
    condition += " AND (#{or_conditions.join(' OR ')})"
  end

  "(#{condition})"
end