hecks 1.0.2 → 1.1.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.
- checksums.yaml +4 -4
- data/lib/hecks/adapters/driven/claude_code.rb +3 -3
- data/lib/hecks/adapters/driven/d1.rb +48 -28
- data/lib/hecks/adapters/driven/folder.rb +10 -3
- data/lib/hecks/adapters/driven/google_authentication.rb +2 -4
- data/lib/hecks/adapters/driven/heki/journal.rb +1 -1
- data/lib/hecks/adapters/driven/heki.rb +3 -5
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +4 -1
- data/lib/hecks/adapters/driven/lambda.rb +2 -2
- data/lib/hecks/adapters/driven/local_storage.adapter +3 -0
- data/lib/hecks/adapters/driven/local_storage.rb +120 -0
- data/lib/hecks/adapters/driven/memory.rb +48 -3
- data/lib/hecks/adapters/driven/postgres/codec.rb +3 -1
- data/lib/hecks/adapters/driven/postgres/outbox.rb +97 -0
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +3 -2
- data/lib/hecks/adapters/driven/postgres.rb +25 -14
- data/lib/hecks/adapters/driven/prism.rb +11 -0
- data/lib/hecks/adapters/driven/sql_query_builder.rb +45 -20
- data/lib/hecks/adapters/driven/sqlite/codec.rb +3 -1
- data/lib/hecks/adapters/driven/sqlite/projection.rb +17 -1
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +23 -1
- data/lib/hecks/adapters/driven/sqlite.rb +87 -8
- data/lib/hecks/adapters/driven.rb +4 -0
- data/lib/hecks/adapters.rb +4 -0
- data/lib/hecks/behaviors/dsl.rb +7 -0
- data/lib/hecks/behaviors/expectations.rb +32 -4
- data/lib/hecks/behaviors/rspec.rb +2 -0
- data/lib/hecks/behaviors/runner.rb +4 -0
- data/lib/hecks/bluebook/aggregate.rb +6 -5
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +4 -4
- data/lib/hecks/bluebook/assembly/build.rb +6 -3
- data/lib/hecks/bluebook/assembly/contract.rb +5 -1
- data/lib/hecks/bluebook/assembly/contracts.rb +4 -0
- data/lib/hecks/bluebook/assembly/marks.rb +2 -1
- data/lib/hecks/bluebook/assembly.rb +1 -3
- data/lib/hecks/bluebook/attribute.rb +6 -0
- data/lib/hecks/bluebook/behaviour/policy.rb +18 -0
- data/lib/hecks/bluebook/behaviour/process_manager.rb +17 -1
- data/lib/hecks/bluebook/behaviour/traits.rb +1 -1
- data/lib/hecks/bluebook/command.rb +6 -5
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +4 -1
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +524 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +19 -472
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +14 -6
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +5 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +848 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +25 -784
- data/lib/hecks/bluebook/dsl/command_builder.rb +53 -13
- data/lib/hecks/bluebook/dsl/const_shim.rb +6 -0
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +20 -7
- data/lib/hecks/bluebook/dsl/entity_builder.rb +27 -6
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +12 -2
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +8 -1
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +24 -12
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +40 -1
- data/lib/hecks/bluebook/dsl/policy_builder.rb +10 -1
- data/lib/hecks/bluebook/dsl/port_builder.rb +6 -1
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +33 -12
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +56 -12
- data/lib/hecks/bluebook/dsl/query_builder.rb +7 -1
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +11 -3
- data/lib/hecks/bluebook/dsl/rule_reference.rb +3 -1
- data/lib/hecks/bluebook/dsl/translation_builder.rb +13 -2
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +8 -1
- data/lib/hecks/bluebook/dsl/word_gate.rb +5 -0
- data/lib/hecks/bluebook/dsl/world_builder.rb +13 -3
- data/lib/hecks/bluebook/entity.rb +5 -3
- data/lib/hecks/bluebook/expression/ast_json.rb +88 -9
- data/lib/hecks/bluebook/expression/ast_reader.rb +107 -0
- data/lib/hecks/bluebook/expression/canonical_form.rb +7 -0
- data/lib/hecks/bluebook/expression/evaluator.rb +64 -11
- data/lib/hecks/bluebook/expression/projection.json +12 -0
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +4 -3
- data/lib/hecks/bluebook/expression/resolver.rb +83 -11
- data/lib/hecks/bluebook/expression.rb +1 -0
- data/lib/hecks/bluebook/hexagon.rb +10 -0
- data/lib/hecks/bluebook/lifecycle.rb +9 -0
- data/lib/hecks/bluebook/meta_validator/judge.rb +10 -4
- data/lib/hecks/bluebook/meta_validator/plan.rb +4 -0
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/shapes.rb +3 -3
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +7 -4
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +42 -3
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +1 -1
- data/lib/hecks/bluebook/meta_validator.rb +5 -5
- data/lib/hecks/bluebook/model_check.rb +119 -82
- data/lib/hecks/bluebook/pattern_subset.rb +9 -0
- data/lib/hecks/bluebook/policy.rb +2 -1
- data/lib/hecks/bluebook/process_manager.rb +6 -0
- data/lib/hecks/bluebook/project_register.rb +45 -25
- data/lib/hecks/bluebook/query.rb +4 -0
- data/lib/hecks/bluebook/read_model.rb +2 -2
- data/lib/hecks/bluebook/smoke_test.rb +5 -0
- data/lib/hecks/bluebook/synthesizer.rb +2 -1
- data/lib/hecks/bluebook/translation.rb +3 -0
- data/lib/hecks/bluebook/value_object.rb +2 -2
- data/lib/hecks/codemod.rb +13 -0
- data/lib/hecks/doc/reference.rb +17 -11
- data/lib/hecks/facade/cli_runner.rb +2 -2
- data/lib/hecks/facade/command_request.rb +11 -11
- data/lib/hecks/facade/handle.rb +3 -3
- data/lib/hecks/facade/surface/aggregate_door.rb +52 -38
- data/lib/hecks/facade.rb +4 -0
- data/lib/hecks/forms/app.rb +10 -6
- data/lib/hecks/forms/command_form_renderer.rb +3 -3
- data/lib/hecks/forms/field_renderer.rb +14 -9
- data/lib/hecks/forms/field_shape.rb +7 -2
- data/lib/hecks/forms/html.rb +5 -2
- data/lib/hecks/forms/index_renderer.rb +1 -1
- data/lib/hecks/forms/page.rb +7 -3
- data/lib/hecks/forms/query_form_renderer.rb +3 -2
- data/lib/hecks/forms/record_renderer.rb +22 -16
- data/lib/hecks/forms.rb +4 -0
- data/lib/hecks/fqn.rb +21 -9
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +30 -8
- data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -1
- data/lib/hecks/fuzzing/isolated_boot.rb +14 -6
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +264 -0
- data/lib/hecks/fuzzing/properties/guards.rb +251 -0
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +351 -0
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +99 -0
- data/lib/hecks/fuzzing/properties/querying.rb +206 -0
- data/lib/hecks/fuzzing/properties.rb +41 -1065
- data/lib/hecks/fuzzing/replay.rb +60 -16
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +6 -2
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +2 -1
- data/lib/hecks/fuzzing/sequence_generator.rb +0 -1
- data/lib/hecks/fuzzing/value_generator.rb +2 -2
- data/lib/hecks/grammar/evolve.rb +34 -10
- data/lib/hecks/grammar/expression_operators.json +124 -0
- data/lib/hecks/grammar.rb +15 -5
- data/lib/hecks/ir.rb +9 -0
- data/lib/hecks/language/bluebook/aggregate.bluebook +4 -2
- data/lib/hecks/language/bluebook/command.bluebook +2 -1
- data/lib/hecks/language/bluebook/entity.bluebook +2 -1
- data/lib/hecks/language/bluebook/projection.bluebook +2 -1
- data/lib/hecks/language/bluebook/query.bluebook +4 -2
- data/lib/hecks/language/bluebook/shape.bluebook +2 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -0
- data/lib/hecks/literal.rb +18 -8
- data/lib/hecks/naming.rb +6 -3
- data/lib/hecks/ports/access_control.rb +1 -1
- data/lib/hecks/ports/agent.rb +5 -3
- data/lib/hecks/ports/authentication.rb +3 -2
- data/lib/hecks/ports/authorization.rb +1 -1
- data/lib/hecks/ports/clock.rb +1 -1
- data/lib/hecks/ports/extraction.rb +5 -1
- data/lib/hecks/ports/identity_assignment.rb +1 -1
- data/lib/hecks/ports/identity_generation.rb +1 -1
- data/lib/hecks/ports/identity_resolution.rb +1 -1
- data/lib/hecks/ports/loading.rb +4 -1
- data/lib/hecks/ports/persistence/append_only.rb +40 -4
- data/lib/hecks/ports/persistence/binding_policy.rb +1 -1
- data/lib/hecks/ports/persistence/plugin.rb +3 -0
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +3 -1
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +5 -5
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +14 -5
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +4 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +80 -16
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +23 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +43 -5
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +25 -4
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +49 -9
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +10 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +49 -38
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +23 -13
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +19 -21
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +27 -9
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +9 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +25 -10
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +2 -6
- data/lib/hecks/ports/persistence/plugins/era.rb +3 -1
- data/lib/hecks/ports/persistence/remote_runtime.rb +1 -1
- data/lib/hecks/ports/persistence.rb +7 -3
- data/lib/hecks/ports/projection.rb +13 -5
- data/lib/hecks/ports/query/in_memory.rb +8 -2
- data/lib/hecks/ports/query.rb +1 -3
- data/lib/hecks/ports.rb +2 -0
- data/lib/hecks/projections/diagrams.rb +11 -3
- data/lib/hecks/projections/ir.rb +2 -0
- data/lib/hecks/projections/model/deviations.rb +2 -1
- data/lib/hecks/projections/model.rb +15 -10
- data/lib/hecks/projections/vocabulary.rb +1 -3
- data/lib/hecks/projector/cli_projector.rb +49 -29
- data/lib/hecks/projector/docs_projector.rb +21 -12
- data/lib/hecks/projector/exporter.rb +10 -1
- data/lib/hecks/projector/narrate_projector.rb +83 -25
- data/lib/hecks/projector.rb +2 -2
- data/lib/hecks/query_ir.rb +60 -36
- data/lib/hecks/query_specification/common/authorization_spec.rb +1 -1
- data/lib/hecks/query_specification/common/comparators.rb +4 -0
- data/lib/hecks/query_specification/common/comparison.rb +8 -1
- data/lib/hecks/query_specification/common/dsl.rb +5 -0
- data/lib/hecks/query_specification/common/null_policy.rb +6 -2
- data/lib/hecks/query_specification/common/options.rb +17 -5
- data/lib/hecks/query_specification/field_path.rb +4 -4
- data/lib/hecks/query_specification/read_model/specification.rb +5 -2
- data/lib/hecks/router/namespace_installer.rb +22 -10
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +57 -22
- data/lib/hecks/runtime/command_interpreter.rb +104 -65
- data/lib/hecks/runtime/command_rules/admissibility.rb +26 -8
- data/lib/hecks/runtime/command_rules/arithmetic.rb +35 -14
- data/lib/hecks/runtime/dependency_planning.rb +33 -21
- data/lib/hecks/runtime/dispatcher.rb +41 -7
- data/lib/hecks/runtime/entity_element.rb +25 -6
- data/lib/hecks/runtime/entity_interpreter.rb +28 -15
- data/lib/hecks/runtime/errors.rb +28 -2
- data/lib/hecks/runtime/instance.rb +9 -3
- data/lib/hecks/runtime/interpreting.rb +29 -2
- data/lib/hecks/runtime/loader.rb +21 -0
- data/lib/hecks/runtime/outbox.rb +365 -0
- data/lib/hecks/runtime/policy_interpreter.rb +32 -17
- data/lib/hecks/runtime/query_interpreter.rb +36 -16
- data/lib/hecks/runtime/reaction_invocation.rb +35 -22
- data/lib/hecks/runtime/read_model_interpreter.rb +26 -3
- data/lib/hecks/runtime/reference_hop.rb +1 -1
- data/lib/hecks/runtime/refusal_wording.rb +55 -49
- data/lib/hecks/runtime/registry/saga_persistence.rb +3 -1
- data/lib/hecks/runtime/registry/verification.rb +39 -2
- data/lib/hecks/runtime/registry.rb +21 -11
- data/lib/hecks/runtime/remote_dispatcher.rb +3 -1
- data/lib/hecks/runtime/routing.rb +52 -39
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +7 -7
- data/lib/hecks/runtime/saga_interpreter.rb +119 -90
- data/lib/hecks/runtime/saga_pending_dispatch.rb +6 -3
- data/lib/hecks/runtime/tenant_scope.rb +7 -0
- data/lib/hecks/runtime/value/coercion.rb +207 -48
- data/lib/hecks/runtime/value.rb +1 -1
- data/lib/hecks/runtime.rb +7 -2
- data/lib/hecks/storehouse.rb +15 -8
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +1 -0
- data/lib/hecks.rb +17 -13
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +1 -1
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +1 -1
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +1 -1
- metadata +14 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require_relative "behaviour/aggregate"
|
|
2
|
+
require_relative "expression/ast_json"
|
|
2
3
|
|
|
3
4
|
module Hecks
|
|
4
5
|
module Bluebook
|
|
@@ -40,14 +41,14 @@ module Hecks
|
|
|
40
41
|
attributes: many(:attributes),
|
|
41
42
|
value_objects: many(:value_objects),
|
|
42
43
|
commands: many(:commands),
|
|
43
|
-
invariants: -> { invariants.map { |rule|
|
|
44
|
+
invariants: -> { invariants.map { |rule| Expression::AstJson.rule_row(rule) } },
|
|
44
45
|
# A PRECONDITION SHARED ACROSS COMMANDS, DECLARED ONCE (S10, ADR
|
|
45
46
|
# 0025) — the aggregate's OWN named `given`s, the declaration a
|
|
46
47
|
# referencing command's own (already-resolved) `givens` entry
|
|
47
48
|
# came from. Both sides of "declared once, referenced many"
|
|
48
49
|
# are real IR, the same shape a value object's TYPE and an
|
|
49
50
|
# attribute's own reference to it both are.
|
|
50
|
-
preconditions: -> { preconditions.map { |rule|
|
|
51
|
+
preconditions: -> { preconditions.map { |rule| Expression::AstJson.rule_row(rule) } },
|
|
51
52
|
# S12, ADR 0025 — deliberately NOT folded into `attributes`:
|
|
52
53
|
# `EraGuard::ShapeDiff` only ever walks `attributes` to decide
|
|
53
54
|
# whether a NEW field leaves an existing record with something
|
|
@@ -55,10 +56,10 @@ module Hecks
|
|
|
55
56
|
# is different — a record predating the `projects` declaration
|
|
56
57
|
# is expected to be missing it until the rebuild sweep runs,
|
|
57
58
|
# not a shape drift a translation needs to explain.
|
|
58
|
-
projected_fields:
|
|
59
|
-
projected_fields.map
|
|
59
|
+
projected_fields: lambda {
|
|
60
|
+
projected_fields.map do |field|
|
|
60
61
|
{ name: field.name.to_s, reference: field.reference.to_s, remote_field: field.remote_field.to_s }
|
|
61
|
-
|
|
62
|
+
end
|
|
62
63
|
},
|
|
63
64
|
lifecycle: one(:lifecycle),
|
|
64
65
|
entities: many(:entities),
|
|
@@ -77,11 +77,11 @@ module Hecks
|
|
|
77
77
|
# and resolve. Deliberately across every list that can carry one — a
|
|
78
78
|
# reference the walk misses resolves to nil, and a nil target is SKIPPED
|
|
79
79
|
# rather than refused, so the guarantee would go quiet instead of red.
|
|
80
|
-
def stamp_references(
|
|
81
|
-
lists = [
|
|
82
|
-
entity_reference_lists(
|
|
80
|
+
def stamp_references(aggregate)
|
|
81
|
+
lists = [aggregate.attributes, *aggregate.commands.map(&:attributes), *aggregate.queries.map(&:attributes)]
|
|
82
|
+
entity_reference_lists(aggregate.entities, lists)
|
|
83
83
|
|
|
84
|
-
lists.flatten.select(&:reference?).each { |field| field.type.declared_in =
|
|
84
|
+
lists.flatten.select(&:reference?).each { |field| field.type.declared_in = aggregate }
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
# S17, ADR 0026 — walks NESTED entities too (Dispatch, inside
|
|
@@ -20,7 +20,7 @@ module Hecks
|
|
|
20
20
|
contract = Assembly.contract(category)
|
|
21
21
|
keywords = contract.fields.to_h { |keyword, (key, reader)| [keyword, read(reader, row[key])] }
|
|
22
22
|
|
|
23
|
-
holder(contract).public_send(contract.make, **keywords
|
|
23
|
+
holder(contract).public_send(contract.make, **keywords, **extra)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def holder(contract)
|
|
@@ -37,8 +37,11 @@ module Hecks
|
|
|
37
37
|
when Array
|
|
38
38
|
# [:each, reader] maps a list ; [:option, name] reads one named option,
|
|
39
39
|
# which needs its name as well as its value.
|
|
40
|
-
reader.first == :each
|
|
41
|
-
|
|
40
|
+
if reader.first == :each
|
|
41
|
+
Array(value).map { |held| Marks.public_send(reader.last, held) }
|
|
42
|
+
else
|
|
43
|
+
Marks.option(reader.last, value)
|
|
44
|
+
end
|
|
42
45
|
else Marks.public_send(reader, value)
|
|
43
46
|
end
|
|
44
47
|
end
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Bluebook
|
|
3
|
+
# The rulebook translating between the language's own declarations and the
|
|
4
|
+
# IR objects `Build`/`Reconstruction` produce from them — the `Contract`
|
|
5
|
+
# struct format itself (this file) plus, reopened in contracts.rb, the
|
|
6
|
+
# `CONTRACTS` table of one `Contract` per construct category.
|
|
3
7
|
class Assembly
|
|
4
8
|
# WHAT A CONSTRUCT NEEDS THAT THE LANGUAGE CANNOT SAY, and how a claim that a
|
|
5
9
|
# field needs no assembling is CHECKED.
|
|
@@ -78,7 +82,7 @@ module Hecks
|
|
|
78
82
|
end
|
|
79
83
|
|
|
80
84
|
def answers?(method)
|
|
81
|
-
make == :declare ? holder.respond_to?(method) : holder.
|
|
85
|
+
make == :declare ? holder.respond_to?(method) : holder.method_defined?(method)
|
|
82
86
|
end
|
|
83
87
|
|
|
84
88
|
def accepts?(keyword)
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Bluebook
|
|
3
|
+
# Reopened here for `CONTRACTS`/`.contract(category)` — the one table of
|
|
4
|
+
# every construct category's own `Contract` (Bluebook, Aggregate,
|
|
5
|
+
# Command, ValueObject, Query, ...); see `Contract`'s own header
|
|
6
|
+
# (contract.rb) for the struct format each entry below fills in.
|
|
3
7
|
class Assembly
|
|
4
8
|
# ONE TABLE, WHERE THERE WERE FIVE HAND-WRITTEN MIRRORS OF IT.
|
|
5
9
|
#
|
|
@@ -129,7 +129,8 @@ module Hecks
|
|
|
129
129
|
# `:delegate`/`:corrects` (CommandBuilder#delegates_to's and
|
|
130
130
|
# #corrects_impl's own comments) ride the SAME multi-binding
|
|
131
131
|
# shape `:append` does.
|
|
132
|
-
return Mutation.new(target: target, op: op, source: appended(change[:fields])) if [:append, :delegate,
|
|
132
|
+
return Mutation.new(target: target, op: op, source: appended(change[:fields])) if [:append, :delegate,
|
|
133
|
+
:corrects].include?(op)
|
|
133
134
|
|
|
134
135
|
Mutation.new(target: target, op: op, source: classified(change[:source]))
|
|
135
136
|
end
|
|
@@ -38,15 +38,13 @@ module Hecks
|
|
|
38
38
|
aggregates = Array(@declaration[:aggregates]).map { |row| AggregateAssembly.new(row).aggregate }
|
|
39
39
|
models = Array(@declaration[:read_models]).map { |row| Build.call("ReadModel", row) }
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Build.call(
|
|
42
42
|
"Bluebook", @declaration,
|
|
43
43
|
aggregates: aggregates,
|
|
44
44
|
read_models: models,
|
|
45
45
|
policies: reactions(aggregates),
|
|
46
46
|
process_managers: Array(@declaration[:process_managers]).map { |row| process_manager(row) }
|
|
47
47
|
)
|
|
48
|
-
|
|
49
|
-
chapter
|
|
50
48
|
end
|
|
51
49
|
|
|
52
50
|
private
|
|
@@ -5,6 +5,12 @@ require_relative "../naming"
|
|
|
5
5
|
|
|
6
6
|
module Hecks
|
|
7
7
|
module Bluebook
|
|
8
|
+
# One declared field on a construct — name, type (a primitive, a
|
|
9
|
+
# Reference, or another construct's name, always spelled via `#spell`),
|
|
10
|
+
# whether it's a list, its default/optional/pattern, and the closed set
|
|
11
|
+
# it `admits`. What `attribute :x, Type` (or `identified_by`,
|
|
12
|
+
# `reference_to`, etc.) actually mints, on an Aggregate, Entity, Command,
|
|
13
|
+
# ValueObject, Query or PortOperation alike.
|
|
8
14
|
class Attribute
|
|
9
15
|
include Hecks::IR
|
|
10
16
|
include Behaviour::Attribute
|
|
@@ -24,6 +24,24 @@ module Hecks
|
|
|
24
24
|
# event's own payload.
|
|
25
25
|
def guarded? = !@where.to_s.empty?
|
|
26
26
|
|
|
27
|
+
# THE STRUCTURED FORM OF `where`, derived once — the same tree
|
|
28
|
+
# `AstJson.emit_predicate` spells for every rule row, memoized
|
|
29
|
+
# here because a policy is consulted once per event, not once per
|
|
30
|
+
# boot. Nil when there is no `where`, exactly as the wire carries
|
|
31
|
+
# it.
|
|
32
|
+
def where_ast
|
|
33
|
+
if defined?(@where_ast)
|
|
34
|
+
@where_ast
|
|
35
|
+
else
|
|
36
|
+
(@where_ast = guarded? ? Expression::AstJson.emit_predicate(@where) : nil)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# The rule-shaped reading of the guard, for `Evaluator.call_rule`
|
|
41
|
+
# — a policy's `where` has no description (nothing refuses with
|
|
42
|
+
# it; an unmet where is a silent skip).
|
|
43
|
+
def where_rule = @where_rule ||= Given.new(description: nil, canonical: @where, ast: where_ast)
|
|
44
|
+
|
|
27
45
|
# THE FAN-OUT QUERY'S ROUTE, split the way the runtime runs it:
|
|
28
46
|
# `[query_domain, aggregate_name, query_name]`. The query runs
|
|
29
47
|
# against the triggering event's OWN domain unless `for_each`
|
|
@@ -7,7 +7,23 @@ module Hecks
|
|
|
7
7
|
module ProcessManager
|
|
8
8
|
def hecks_name = @name
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
# THE LEG THAT ANSWERS — selected by (event, current state), C10.3
|
|
11
|
+
# (docs/semantics/bluebook-semantics.md). Two legs may answer the
|
|
12
|
+
# same event from different states; which one runs is decided by
|
|
13
|
+
# the state the instance is in, never by declaration order. With
|
|
14
|
+
# no `state` the reading is declarative — "does any leg answer this
|
|
15
|
+
# event, and what is it" — for callers that ask about the
|
|
16
|
+
# procedure rather than an instance (`saga`, the outbox's consumer
|
|
17
|
+
# selection). Build refuses two legs on one (event, state) pair
|
|
18
|
+
# (`ProcessManagerBuilder#validate!`), so a stated lookup is
|
|
19
|
+
# unambiguous by construction.
|
|
20
|
+
def handler_for(event, state = nil)
|
|
21
|
+
@handlers.find { |h| h.event_type == event.to_s && (state.nil? || h.from_state == state.to_s) }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def handlers_for(event) = @handlers.select { |h| h.event_type == event.to_s }
|
|
25
|
+
|
|
26
|
+
def handles?(event) = @handlers.any? { |h| h.event_type == event.to_s }
|
|
11
27
|
|
|
12
28
|
# WHETHER A STATE IS ONE THIS PROCEDURE DECLARES — asked of a value
|
|
13
29
|
# a real run left a saga instance holding (its live or rehydrated
|
|
@@ -29,7 +29,7 @@ module Hecks
|
|
|
29
29
|
# readers that need all of them ask for `identity_heads`.
|
|
30
30
|
module Identified
|
|
31
31
|
def derive_identity
|
|
32
|
-
@identity_paths = Array(@identified_by).map
|
|
32
|
+
@identity_paths = Array(@identified_by).map(&:to_s).reject(&:empty?)
|
|
33
33
|
@identity_heads = @identity_paths.map { |path| path.split(".").first.to_sym }.uniq
|
|
34
34
|
@identified_by = @identity_heads.size == 1 ? @identity_heads.first : nil
|
|
35
35
|
end
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
require_relative "behaviour/command"
|
|
2
2
|
require_relative "../vocabulary"
|
|
3
|
+
require_relative "expression/ast_json"
|
|
3
4
|
|
|
4
5
|
module Hecks
|
|
5
6
|
module Bluebook
|
|
6
|
-
Given = Struct.new(:description, :canonical, :predicate, keyword_init: true)
|
|
7
|
+
Given = Struct.new(:description, :canonical, :predicate, :ast, keyword_init: true)
|
|
7
8
|
|
|
8
9
|
Mutation = Struct.new(:target, :op, :source, keyword_init: true) do
|
|
9
10
|
include Hecks::IR
|
|
@@ -24,8 +25,8 @@ module Hecks
|
|
|
24
25
|
# real layering inversion (runtime depends on bluebook, not the
|
|
25
26
|
# reverse). "" (not nil) for ops with no sign, matching every other
|
|
26
27
|
# optional IR text field's own absent-is-empty-string convention.
|
|
27
|
-
def self.sign_for(
|
|
28
|
-
Hecks::Vocabulary.rows("MutationOp").find { |row| row["name"] ==
|
|
28
|
+
def self.sign_for(oper)
|
|
29
|
+
Hecks::Vocabulary.rows("MutationOp").find { |row| row["name"] == oper.to_s }&.fetch("sign", "") || ""
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
emits_ir(target: :target, op: :op, sign: -> { Mutation.sign_for(op) })
|
|
@@ -74,8 +75,8 @@ module Hecks
|
|
|
74
75
|
goal: :goal,
|
|
75
76
|
references: :references,
|
|
76
77
|
attributes: many(:attributes),
|
|
77
|
-
givens: -> { givens.map { |rule|
|
|
78
|
-
ensures: -> { ensures.map { |rule|
|
|
78
|
+
givens: -> { givens.map { |rule| Expression::AstJson.rule_row(rule) } },
|
|
79
|
+
ensures: -> { ensures.map { |rule| Expression::AstJson.rule_row(rule) } },
|
|
79
80
|
mutations: many(:mutations),
|
|
80
81
|
emits: :emits,
|
|
81
82
|
# THE LIFECYCLE STATE THIS COMMAND IS ADMISSIBLE FROM (S10, ADR
|
|
@@ -2,8 +2,11 @@ require_relative "word_gate"
|
|
|
2
2
|
module Hecks
|
|
3
3
|
module Bluebook
|
|
4
4
|
module DSL
|
|
5
|
+
# The `Hecks.adapter "Name" do port ...; field ...; secret ... end`
|
|
6
|
+
# receiver — collects the port it implements plus its own settings
|
|
7
|
+
# fields and secrets, then builds and judges an `Adapter` construct.
|
|
5
8
|
class AdapterBuilder
|
|
6
|
-
GRAMMAR_CONTEXT = "Adapter"
|
|
9
|
+
GRAMMAR_CONTEXT = "Adapter".freeze
|
|
7
10
|
|
|
8
11
|
include WordGate
|
|
9
12
|
|