Class: Hecks::Bluebook::DSL::ReadModelBuilder
- Inherits:
-
Object
- Object
- Hecks::Bluebook::DSL::ReadModelBuilder
- Includes:
- WordGate, QuerySpecification::Common::DSL
- Defined in:
- lib/hecks/bluebook/dsl/read_model_builder.rb
Constant Summary collapse
- GRAMMAR_CONTEXT =
"ReadModel"
Constants included from WordGate
Class Method Summary collapse
Instance Method Summary collapse
-
#build ⇒ Object
reference_tois now OPTIONAL — a read model with no root is a BULK one: everyincluded head reads its own aggregate whole (no FK match against a root that doesn't exist), and dispatch takes no id argument at all. - #description(value) ⇒ Object
-
#group_by_impl(*fields) ⇒ Object
NAMES which of the eligible head's own fields to nest its rows under — one level per field, the leaf being that row with the named fields removed (they're already spent, as the keys that reached it).
-
#include_impl(type, as: nil) ⇒ Object
Order-independent.
-
#initialize(name) ⇒ ReadModelBuilder
constructor
A new instance of ReadModelBuilder.
-
#reference_to_impl(type, as: nil) ⇒ Object
RENAMED FROM
reference_to— item #13's full metaprogrammed dispatch (slice 4b).
Methods included from QuerySpecification::Common::DSL
#authorize_impl, #cursor, #inspect_query, #limit_impl, #nulls, #offset_impl, #order_by_impl, #where_impl
Constructor Details
#initialize(name) ⇒ ReadModelBuilder
Returns a new instance of ReadModelBuilder.
11 12 13 |
# File 'lib/hecks/bluebook/dsl/read_model_builder.rb', line 11 def initialize(name) @name = name end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class Hecks::Bluebook::DSL::WordGate
Class Method Details
.build(name, &block) ⇒ Object
129 130 131 132 133 |
# File 'lib/hecks/bluebook/dsl/read_model_builder.rb', line 129 def self.build(name, &block) builder = new(name) builder.instance_eval(&block) if block builder.build end |
Instance Method Details
#build ⇒ Object
reference_to is now OPTIONAL — a read model with no root is a
BULK one: every included head reads its own aggregate whole
(no FK match against a root that doesn't exist), and dispatch
takes no id argument at all. This used to be REQUIRED, on the
assumption a read model was always "one root record's own
cross-aggregate view" — true of every real corpus report so
far, but not a truth about read models themselves: group_by's
own real use (nesting an aggregate's OWN whole table by its own
field values) has no root to speak of. Still needs to describe
SOMETHING — zero includes AND no reference is refused.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/hecks/bluebook/dsl/read_model_builder.rb', line 109 def build raise Malformed, "#{@name} needs an aggregate-head reference or at least one include" if !@reference_target && Array(@includes).empty? Array(@includes).each do |target, as| add_aggregate_head(target, as, many: target != @reference_target) end seal_group_by seal_aggregation seal_cursor ReadModel.new(name: @name, description: @description, reference_name: @reference_name, reference_target: @reference_target, aggregate_heads: @aggregate_heads || [], wheres: @wheres || [], order_by: @order_by, limit: @limit, offset: @offset, cursor: @cursor, authorization: @authorization, null_semantics: @null_semantics, inspection: @inspection, group_by: @group_by || [], count: @count, median_field: @median_field) end |
#description(value) ⇒ Object
15 16 17 18 |
# File 'lib/hecks/bluebook/dsl/read_model_builder.rb', line 15 def description(value) # moved to the language: ProjectionText / purpose, on Projection.Declare @description = value end |
#group_by_impl(*fields) ⇒ Object
NAMES which of the eligible head's own fields to nest its rows
under — one level per field, the leaf being that row with the
named fields removed (they're already spent, as the keys that
reached it). The same "exactly one many-side head" rule
seal_query_options already enforces for where/order_by/etc
applies here too (seal_group_by) — grouping is a question
about ONE collection's own rows, same as those are.
58 59 60 61 62 63 64 65 66 |
# File 'lib/hecks/bluebook/dsl/read_model_builder.rb', line 58 def group_by_impl(*fields) # Hash rows, `{field:}`, not bare symbols — same shape # `aggregate_heads` already uses for exactly the reason it # does: the language's own self-hosted grammar (`projection # .bluebook`'s `GroupByField`) has to have SOMETHING to read a # `field:` off of when `Judge` walks this list generically: a # bare `Symbol` has no attribute of its own to read. @group_by = fields.map { |field| { field: field.to_sym } } end |
#include_impl(type, as: nil) ⇒ Object
Order-independent. many: is decided by comparing the included type
against the reference target, so this used to REFUSE an include
declared before the reference — a rule guarding an implementation
limitation rather than a truth about read models. The includes are
collected raw and resolved at build, when the reference is known, so
there is no rule left to enforce.
RENAMED FROM include/group_by — item #13's full
metaprogrammed dispatch (slice 4c). include IS bootstrap-
reachable (every core chapter's own read_model names which
aggregates it includes with it — a first grep dismissed this
as Module#include noise and was wrong; the cold-boot test
after this rename caught it directly), so it's in
BOOTSTRAP_CALLS_FALLBACK; group_by is not (no core read_model
groups). The class-level include WordGate this file's own
class body uses is Module#include, a different receiver,
unaffected by renaming this INSTANCE method either way.
46 47 48 49 |
# File 'lib/hecks/bluebook/dsl/read_model_builder.rb', line 46 def include_impl(type, as: nil) @includes ||= [] @includes << [Naming.demodulise(type), as] end |
#reference_to_impl(type, as: nil) ⇒ Object
RENAMED FROM reference_to — item #13's full metaprogrammed
dispatch (slice 4b). Bootstrap-reachable, in
GenericDispatch::BOOTSTRAP_CALLS_FALLBACK.
23 24 25 26 27 28 |
# File 'lib/hecks/bluebook/dsl/read_model_builder.rb', line 23 def reference_to_impl(type, as: nil) raise Malformed, "#{@name} already has a projection reference" if @reference_target @reference_target = Naming.demodulise(type) @reference_name = (as || Naming.snake(@reference_target)).to_sym end |