Module: Hecks::Ports::Query::InMemory
- Defined in:
- lib/hecks/ports/query/in_memory.rb
Constant Summary collapse
- FieldPath =
QuerySpecification::FieldPath
- Comparison =
QuerySpecification::Common::Comparison
Class Method Summary collapse
- .comparable(value) ⇒ Object
- .execute(records, declared, args = {}, registry: nil) ⇒ Object
-
.holds?(clause, held, args, registry: nil) ⇒ Boolean
The comparator table itself lives in QuerySpecification::Common::Comparison — this module and Runtime::QueryInterpreter used to carry a copy each, and the two drifted (see that file's own comment for what it cost).
- .resolve(value, args) ⇒ Object
Class Method Details
.comparable(value) ⇒ Object
56 |
# File 'lib/hecks/ports/query/in_memory.rb', line 56 def comparable(value) = Comparison.comparable(value) |
.execute(records, declared, args = {}, registry: nil) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/hecks/ports/query/in_memory.rb', line 15 def execute(records, declared, args = {}, registry: nil) matched = records.select do |record| declared.wheres.all? { |clause| holds?(clause, comparable(FieldPath.dig(record, clause.field)), args, registry: registry) } end field = declared.order_by&.field matched = Ordering.apply(matched, declared.order_by, declared.null_semantics, identity: ->(record) { record.id.to_s }) { |record| comparable(FieldPath.dig(record, field)) } # OFFSET FIRST, THEN LIMIT — the order SQL means by `LIMIT n # OFFSET m`, which is what `SqlQueryBuilder` emits and therefore # what every SQL-backed aggregate already answers. Written the # other way round here, and the two engines disagreed on the # same declaration: `limit 2, offset 1` over three rows is rows # two and three in Postgres and Sqlite, and was row two alone in # memory. Silently — a short page reads exactly like a page that # ran out of rows. # # It gets worse the further you page, which is the case nobody # writing the first page ever sees: at `limit 10, offset 10`, # taking ten and then dropping ten leaves NOTHING, so page two # of a memory-backed query came back empty however many rows # were really there. matched = matched.drop(resolve(declared.offset.value, args).to_i) if declared.offset matched = matched.first(resolve(declared.limit.value, args).to_i) if declared.limit matched end |
.holds?(clause, held, args, registry: nil) ⇒ Boolean
The comparator table itself lives in QuerySpecification::Common::Comparison — this module and Runtime::QueryInterpreter used to carry a copy each, and the two drifted (see that file's own comment for what it cost). What stays here is how a value is REACHED for this path: a registry arrives as an argument rather than as instance state, and the field is dug through FieldPath before it arrives.
50 51 52 |
# File 'lib/hecks/ports/query/in_memory.rb', line 50 def holds?(clause, held, args, registry: nil) Comparison.holds?(clause.op, held, comparable(resolve(clause.value, args)), registry: registry) end |
.resolve(value, args) ⇒ Object
54 |
# File 'lib/hecks/ports/query/in_memory.rb', line 54 def resolve(value, args) = value.is_a?(Symbol) ? args[value] : value |