Module: Hecks::Adapters::InMemoryOrdering

Defined in:
lib/hecks/adapters/driven/in_memory_ordering.rb

Overview

SHARED BY every adapter that holds decoded Ruby records rather than running real SQL (Memory, Lambda, Heki) — the identical dotted-path value-object member-picking Postgres/Sqlite/D1's own order_expression does (numeric member wins, else the one-field convention "value"), just walked in Ruby instead of compiled to a JSONB/json_extract path, because there is no query engine underneath any of these three to hide that walk inside.

Class Method Summary collapse

Class Method Details

.ordered(records, aggregate:, order_by:, direction:) ⇒ Object

order_by IS A RUNTIME VALUE (an HTTP query param, in the console's case), not framework-authored bluebook source — see postgres.rb's own all for the full reasoning. Whitelisted the identical way before FieldPath.dig ever runs.



23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/hecks/adapters/driven/in_memory_ordering.rb', line 23

def ordered(records, aggregate:, order_by:, direction:)
  return records unless order_by

  name = order_by.to_s.split(".").first
  raise Runtime::WiringError, "#{aggregate.name} has no attribute #{order_by.inspect} to order by" unless aggregate.lifecycle&.field.to_s == name || aggregate.attribute(name)

  path = sortable_path(aggregate, order_by)
  spec = QuerySpecification::Common::OrderBy.new(field: order_by, direction: direction)
  Ports::Query::Ordering.apply(records, spec, nil, identity: ->(record) { record.id.to_s }) do |record|
    Ports::Query::InMemory.comparable(QuerySpecification::FieldPath.dig(record, path))
  end
end

.sortable_path(aggregate, field) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/hecks/adapters/driven/in_memory_ordering.rb', line 36

def sortable_path(aggregate, field)
  name, *path = field.to_s.split(".")
  return field.to_s unless path.empty?

  attribute = aggregate.attribute(name)
  return field.to_s if aggregate.lifecycle&.field.to_s == name || attribute.nil?

  vo = aggregate.value_object(attribute.type)
  return field.to_s unless vo

  member = vo.attributes.find { |a| %w[Integer Float].include?(a.type) }&.name || "value"
  "#{name}.#{member}"
end