hecks 0.2.0 → 0.3.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 +5 -5
- data/lib/hecks/adapters/driven/claude_code.adapter +3 -0
- data/lib/hecks/adapters/driven/claude_code.rb +127 -0
- data/lib/hecks/adapters/driven/d1.adapter +12 -0
- data/lib/hecks/adapters/driven/d1.rb +403 -0
- data/lib/hecks/adapters/driven/folder.adapter +3 -0
- data/lib/hecks/adapters/driven/folder.rb +199 -0
- data/lib/hecks/adapters/driven/google_authentication.adapter +3 -0
- data/lib/hecks/adapters/driven/google_authentication.rb +100 -0
- data/lib/hecks/adapters/driven/governance_authorization.adapter +3 -0
- data/lib/hecks/adapters/driven/governance_authorization.rb +62 -0
- data/lib/hecks/adapters/driven/heki/journal.rb +51 -0
- data/lib/hecks/adapters/driven/heki/saga_store.rb +0 -0
- data/lib/hecks/adapters/driven/heki/snapshot.rb +38 -0
- data/lib/hecks/adapters/driven/heki.adapter +4 -0
- data/lib/hecks/adapters/driven/heki.rb +148 -0
- data/lib/hecks/adapters/driven/identity_registry.adapter +3 -0
- data/lib/hecks/adapters/driven/identity_registry.rb +26 -0
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +51 -0
- data/lib/hecks/adapters/driven/lambda/client.rb +63 -0
- data/lib/hecks/adapters/driven/lambda.adapter +4 -0
- data/lib/hecks/adapters/driven/lambda.rb +131 -0
- data/lib/hecks/adapters/driven/memory.adapter +3 -0
- data/lib/hecks/adapters/driven/memory.rb +103 -0
- data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +3 -0
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +28 -0
- data/lib/hecks/adapters/driven/postgres/codec.rb +80 -0
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +168 -0
- data/lib/hecks/adapters/driven/postgres.adapter +5 -0
- data/lib/hecks/adapters/driven/postgres.rb +391 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/era_store.rb +171 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/field_cache.rb +190 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/head_compiler.rb +429 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/mint_transaction.rb +166 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/provisioning.rb +286 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/resumable_backfill.rb +168 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/tail_merge.rb +163 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/transform_installer.rb +114 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage.rb +137 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/coverage_check.rb +89 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolver.rb +82 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/merge_coordinator.rb +43 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/minter.rb +132 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager.rb +74 -0
- data/lib/hecks/adapters/driven/postgres_era.adapter +6 -0
- data/lib/hecks/adapters/driven/postgres_era.rb +671 -0
- data/lib/hecks/adapters/driven/prism.adapter +3 -0
- data/lib/hecks/adapters/driven/prism.rb +80 -0
- data/lib/hecks/adapters/driven/secure_random_identity.adapter +3 -0
- data/lib/hecks/adapters/driven/secure_random_identity.rb +14 -0
- data/lib/hecks/adapters/driven/sql_query_builder.rb +221 -0
- data/lib/hecks/adapters/driven/sqlite/codec.rb +63 -0
- data/lib/hecks/adapters/driven/sqlite/projection.rb +105 -0
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +180 -0
- data/lib/hecks/adapters/driven/sqlite.adapter +9 -0
- data/lib/hecks/adapters/driven/sqlite.rb +285 -0
- data/lib/hecks/adapters/driven/system_clock.adapter +3 -0
- data/lib/hecks/adapters/driven/system_clock.rb +14 -0
- data/lib/hecks/adapters/driven.rb +36 -0
- data/lib/hecks/adapters.rb +6 -0
- data/lib/hecks/behaviors/dsl.rb +96 -0
- data/lib/hecks/behaviors/expectations.rb +280 -0
- data/lib/hecks/behaviors/ir.rb +31 -0
- data/lib/hecks/behaviors/rspec.rb +42 -0
- data/lib/hecks/behaviors/runner.rb +96 -0
- data/lib/hecks/behaviors.rb +25 -0
- data/lib/hecks/bluebook/aggregate.rb +108 -0
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +134 -0
- data/lib/hecks/bluebook/assembly/build.rb +48 -0
- data/lib/hecks/bluebook/assembly/contract.rb +112 -0
- data/lib/hecks/bluebook/assembly/contracts.rb +409 -0
- data/lib/hecks/bluebook/assembly/marks.rb +227 -0
- data/lib/hecks/bluebook/assembly/specializer.rb +70 -0
- data/lib/hecks/bluebook/assembly.rb +78 -0
- data/lib/hecks/bluebook/attribute.rb +96 -0
- data/lib/hecks/bluebook/behaviour/aggregate.rb +83 -0
- data/lib/hecks/bluebook/behaviour/attribute.rb +27 -0
- data/lib/hecks/bluebook/behaviour/chapter.rb +72 -0
- data/lib/hecks/bluebook/behaviour/command.rb +116 -0
- data/lib/hecks/bluebook/behaviour/domain_port.rb +25 -0
- data/lib/hecks/bluebook/behaviour/entity.rb +59 -0
- data/lib/hecks/bluebook/behaviour/hexagon.rb +50 -0
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +51 -0
- data/lib/hecks/bluebook/behaviour/policy.rb +52 -0
- data/lib/hecks/bluebook/behaviour/process_manager.rb +38 -0
- data/lib/hecks/bluebook/behaviour/query.rb +10 -0
- data/lib/hecks/bluebook/behaviour/read_model.rb +29 -0
- data/lib/hecks/bluebook/behaviour/traits.rb +81 -0
- data/lib/hecks/bluebook/behaviour/value_object.rb +33 -0
- data/lib/hecks/bluebook/chapter.rb +68 -0
- data/lib/hecks/bluebook/command.rb +124 -0
- data/lib/hecks/bluebook/domain_port.rb +102 -0
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +34 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +906 -0
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +327 -0
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +71 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +1018 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +626 -0
- data/lib/hecks/bluebook/dsl/const_shim.rb +81 -0
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +79 -0
- data/lib/hecks/bluebook/dsl/entity_builder.rb +305 -0
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +366 -0
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +163 -0
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +191 -0
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +44 -0
- data/lib/hecks/bluebook/dsl/malformed.rb +7 -0
- data/lib/hecks/bluebook/dsl/policy_builder.rb +120 -0
- data/lib/hecks/bluebook/dsl/port_builder.rb +30 -0
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +142 -0
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +207 -0
- data/lib/hecks/bluebook/dsl/query_builder.rb +113 -0
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +233 -0
- data/lib/hecks/bluebook/dsl/rule_reference.rb +172 -0
- data/lib/hecks/bluebook/dsl/translation_builder.rb +243 -0
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +178 -0
- data/lib/hecks/bluebook/dsl/word_gate.rb +221 -0
- data/lib/hecks/bluebook/dsl/world_builder.rb +77 -0
- data/lib/hecks/bluebook/dsl.rb +45 -0
- data/lib/hecks/bluebook/entity.rb +103 -0
- data/lib/hecks/bluebook/expression/canonical_form.rb +55 -0
- data/lib/hecks/bluebook/expression/evaluator.rb +261 -0
- data/lib/hecks/bluebook/expression/projection.json +170 -0
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +233 -0
- data/lib/hecks/bluebook/expression/resolver.rb +630 -0
- data/lib/hecks/bluebook/expression.rb +13 -0
- data/lib/hecks/bluebook/hexagon.rb +60 -0
- data/lib/hecks/bluebook/lifecycle.rb +42 -0
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +54 -0
- data/lib/hecks/bluebook/meta_validator/judge.rb +559 -0
- data/lib/hecks/bluebook/meta_validator/plan.rb +332 -0
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +47 -0
- data/lib/hecks/bluebook/meta_validator/readings.rb +350 -0
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +312 -0
- data/lib/hecks/bluebook/meta_validator/shapes.rb +246 -0
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +255 -0
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +138 -0
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +78 -0
- data/lib/hecks/bluebook/meta_validator.rb +452 -0
- data/lib/hecks/bluebook/model_check.rb +318 -0
- data/lib/hecks/bluebook/pattern_subset.rb +120 -0
- data/lib/hecks/bluebook/policy.rb +41 -0
- data/lib/hecks/bluebook/process_manager.rb +86 -0
- data/lib/hecks/bluebook/project_discovery.rb +30 -0
- data/lib/hecks/bluebook/project_loader.rb +40 -0
- data/lib/hecks/bluebook/project_register.rb +82 -0
- data/lib/hecks/bluebook/query.rb +61 -0
- data/lib/hecks/bluebook/read_model.rb +109 -0
- data/lib/hecks/bluebook/reference.rb +74 -0
- data/lib/hecks/bluebook/smoke_test.rb +166 -0
- data/lib/hecks/bluebook/synthesizer.rb +95 -0
- data/lib/hecks/bluebook/translation.rb +92 -0
- data/lib/hecks/bluebook/value_object.rb +58 -0
- data/lib/hecks/bluebook.rb +74 -0
- data/lib/hecks/codemod.rb +342 -0
- data/lib/hecks/construct.rb +71 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +219 -0
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +4 -0
- data/lib/hecks/deploy/oidc.json +18 -0
- data/lib/hecks/doc/reference.rb +389 -0
- data/lib/hecks/embryonaut_bluebook.rb +75 -0
- data/lib/hecks/facade/cli_door.rb +116 -0
- data/lib/hecks/facade/cli_runner.rb +190 -0
- data/lib/hecks/facade/command_request.rb +105 -0
- data/lib/hecks/facade/handle.rb +173 -0
- data/lib/hecks/facade/json_door.rb +154 -0
- data/lib/hecks/facade/surface/aggregate_door.rb +185 -0
- data/lib/hecks/facade/surface/chapter.rb +107 -0
- data/lib/hecks/facade/surface.rb +48 -0
- data/lib/hecks/facade.rb +44 -0
- data/lib/hecks/forms/app.rb +300 -0
- data/lib/hecks/forms/command_form_renderer.rb +113 -0
- data/lib/hecks/forms/examples/banking_console.bluebook +3 -0
- data/lib/hecks/forms/field_renderer.rb +170 -0
- data/lib/hecks/forms/field_shape.rb +232 -0
- data/lib/hecks/forms/html.rb +53 -0
- data/lib/hecks/forms/index_renderer.rb +35 -0
- data/lib/hecks/forms/page.rb +157 -0
- data/lib/hecks/forms/params.rb +132 -0
- data/lib/hecks/forms/query_form_renderer.rb +114 -0
- data/lib/hecks/forms/record_renderer.rb +115 -0
- data/lib/hecks/forms/record_table.rb +63 -0
- data/lib/hecks/forms/reference_options.rb +30 -0
- data/lib/hecks/forms/value_object_shape.rb +46 -0
- data/lib/hecks/forms.rb +54 -0
- data/lib/hecks/fqn.rb +94 -0
- data/lib/hecks/framework/bluebook/compliance.bluebook +1 -0
- data/lib/hecks/framework/bluebook/console_settings.bluebook +489 -0
- data/lib/hecks/framework/bluebook/framework.hecksagon +32 -0
- data/lib/hecks/framework/bluebook/governance.bluebook +130 -0
- data/lib/hecks/framework/bluebook/identity.bluebook +90 -0
- data/lib/hecks/framework/oidc.json +39 -0
- data/lib/hecks/framework.rb +90 -0
- data/lib/hecks/freezer.rb +67 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +86 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +92 -0
- data/lib/hecks/fuzzing/properties.rb +1146 -0
- data/lib/hecks/fuzzing/replay.rb +635 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +93 -0
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +54 -0
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +96 -0
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +185 -0
- data/lib/hecks/fuzzing/sequence_generator.rb +130 -0
- data/lib/hecks/fuzzing/value_generator.rb +177 -0
- data/lib/hecks/fuzzing.rb +12 -0
- data/lib/hecks/grammar/evolve.rb +291 -0
- data/lib/hecks/grammar/expression.bluebook +417 -0
- data/lib/hecks/grammar/expression_operators.json +1152 -0
- data/lib/hecks/grammar/grammar.hecksagon +20 -0
- data/lib/hecks/grammar/oidc.json +69 -0
- data/lib/hecks/grammar/translation.bluebook +203 -0
- data/lib/hecks/grammar.rb +178 -0
- data/lib/hecks/ir.rb +126 -0
- data/lib/hecks/language/adapter.bluebook +116 -0
- data/lib/hecks/language/bluebook/aggregate.bluebook +581 -0
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +76 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +256 -0
- data/lib/hecks/language/bluebook/bluebook.hecksagon +24 -0
- data/lib/hecks/language/bluebook/command.bluebook +437 -0
- data/lib/hecks/language/bluebook/entity.bluebook +316 -0
- data/lib/hecks/language/bluebook/policy.bluebook +172 -0
- data/lib/hecks/language/bluebook/process_manager.bluebook +264 -0
- data/lib/hecks/language/bluebook/projection.bluebook +267 -0
- data/lib/hecks/language/bluebook/query.bluebook +245 -0
- data/lib/hecks/language/bluebook/shape.bluebook +292 -0
- data/lib/hecks/language/bluebook/syntax.bluebook +447 -0
- data/lib/hecks/language/bluebook/vocabulary.bluebook +364 -0
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +51 -0
- data/lib/hecks/language/hecksagon/domain_port.bluebook +76 -0
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +131 -0
- data/lib/hecks/language/hecksagon/port_operation.bluebook +102 -0
- data/lib/hecks/language/oidc.json +313 -0
- data/lib/hecks/language/port.bluebook +92 -0
- data/lib/hecks/language/translation/translation.bluebook +110 -0
- data/lib/hecks/language/translation/translation_aggregate.bluebook +267 -0
- data/lib/hecks/language/world/wiring.bluebook +62 -0
- data/lib/hecks/language/world/world.bluebook +84 -0
- data/lib/hecks/literal.rb +125 -0
- data/lib/hecks/naming.rb +121 -0
- data/lib/hecks/ports/access_control.port +4 -0
- data/lib/hecks/ports/access_control.rb +62 -0
- data/lib/hecks/ports/agent/answers.rb +104 -0
- data/lib/hecks/ports/agent.port +4 -0
- data/lib/hecks/ports/agent.rb +167 -0
- data/lib/hecks/ports/authentication.port +4 -0
- data/lib/hecks/ports/authentication.rb +50 -0
- data/lib/hecks/ports/authorization.port +4 -0
- data/lib/hecks/ports/authorization.rb +59 -0
- data/lib/hecks/ports/clock.port +4 -0
- data/lib/hecks/ports/clock.rb +62 -0
- data/lib/hecks/ports/extraction.port +4 -0
- data/lib/hecks/ports/extraction.rb +37 -0
- data/lib/hecks/ports/identity_assignment.port +4 -0
- data/lib/hecks/ports/identity_assignment.rb +45 -0
- data/lib/hecks/ports/identity_generation.port +4 -0
- data/lib/hecks/ports/identity_generation.rb +49 -0
- data/lib/hecks/ports/identity_resolution.port +4 -0
- data/lib/hecks/ports/identity_resolution.rb +40 -0
- data/lib/hecks/ports/loading.port +4 -0
- data/lib/hecks/ports/loading.rb +13 -0
- data/lib/hecks/ports/persistence/append_only.rb +102 -0
- data/lib/hecks/ports/persistence/binding_policy.rb +56 -0
- data/lib/hecks/ports/persistence/execution.rb +18 -0
- data/lib/hecks/ports/persistence/lineage.rb +277 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +25 -0
- data/lib/hecks/ports/persistence/remote_runtime.rb +42 -0
- data/lib/hecks/ports/persistence/repository_factory.rb +30 -0
- data/lib/hecks/ports/persistence.port +4 -0
- data/lib/hecks/ports/persistence.rb +39 -0
- data/lib/hecks/ports/projection.port +4 -0
- data/lib/hecks/ports/projection.rb +76 -0
- data/lib/hecks/ports/query/in_memory.rb +60 -0
- data/lib/hecks/ports/query/ordering.rb +41 -0
- data/lib/hecks/ports/query.rb +36 -0
- data/lib/hecks/ports.rb +27 -0
- data/lib/hecks/projections/diagrams.rb +413 -0
- data/lib/hecks/projections/ir.rb +18 -0
- data/lib/hecks/projections/model/deviations.rb +98 -0
- data/lib/hecks/projections/model.rb +145 -0
- data/lib/hecks/projections/oidc.rb +110 -0
- data/lib/hecks/projections/parser_table.rb +159 -0
- data/lib/hecks/projections/reference.rb +38 -0
- data/lib/hecks/projections/shape.rb +31 -0
- data/lib/hecks/projections/statements.rb +110 -0
- data/lib/hecks/projections/vocabulary.rb +100 -0
- data/lib/hecks/projections.rb +32 -0
- data/lib/hecks/projector/cli_projector.rb +437 -0
- data/lib/hecks/projector/docs_projector.rb +321 -0
- data/lib/hecks/projector/exporter.rb +141 -0
- data/lib/hecks/projector/ir_projector.rb +18 -0
- data/lib/hecks/projector/narrate_projector.rb +243 -0
- data/lib/hecks/projector/target.rb +97 -0
- data/lib/hecks/projector.rb +186 -0
- data/lib/hecks/query_ir.rb +392 -0
- data/lib/hecks/query_specification/common/authorization_spec.rb +9 -0
- data/lib/hecks/query_specification/common/comparators.rb +25 -0
- data/lib/hecks/query_specification/common/comparison.rb +174 -0
- data/lib/hecks/query_specification/common/cursor_spec.rb +9 -0
- data/lib/hecks/query_specification/common/dsl.rb +58 -0
- data/lib/hecks/query_specification/common/inspection_spec.rb +9 -0
- data/lib/hecks/query_specification/common/limit_spec.rb +9 -0
- data/lib/hecks/query_specification/common/null_policy.rb +80 -0
- data/lib/hecks/query_specification/common/null_semantics.rb +11 -0
- data/lib/hecks/query_specification/common/offset_spec.rb +9 -0
- data/lib/hecks/query_specification/common/options.rb +32 -0
- data/lib/hecks/query_specification/common/order_by.rb +9 -0
- data/lib/hecks/query_specification/common/specification.rb +10 -0
- data/lib/hecks/query_specification/common/where_clause.rb +9 -0
- data/lib/hecks/query_specification/field_path.rb +89 -0
- data/lib/hecks/query_specification/hop_path.rb +130 -0
- data/lib/hecks/query_specification/read_model/specification.rb +18 -0
- data/lib/hecks/query_specification.rb +14 -0
- data/lib/hecks/rendering.rb +48 -0
- data/lib/hecks/router/namespace_installer.rb +157 -0
- data/lib/hecks/router.rb +70 -0
- data/lib/hecks/runtime/caller.rb +50 -0
- data/lib/hecks/runtime/capability_graph.rb +44 -0
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +124 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +248 -0
- data/lib/hecks/runtime/command_interpreter.rb +413 -0
- data/lib/hecks/runtime/command_rules/admissibility.rb +307 -0
- data/lib/hecks/runtime/command_rules/arithmetic.rb +254 -0
- data/lib/hecks/runtime/command_rules/authorization.rb +64 -0
- data/lib/hecks/runtime/command_rules/emission.rb +34 -0
- data/lib/hecks/runtime/command_rules/references.rb +181 -0
- data/lib/hecks/runtime/command_rules.rb +28 -0
- data/lib/hecks/runtime/dependency_planning.rb +231 -0
- data/lib/hecks/runtime/dispatcher.rb +286 -0
- data/lib/hecks/runtime/entity_element.rb +253 -0
- data/lib/hecks/runtime/entity_interpreter.rb +228 -0
- data/lib/hecks/runtime/era_check.rb +136 -0
- data/lib/hecks/runtime/era_guard/shape_diff.rb +128 -0
- data/lib/hecks/runtime/era_guard.rb +193 -0
- data/lib/hecks/runtime/era_tamper.rb +61 -0
- data/lib/hecks/runtime/errors.rb +100 -0
- data/lib/hecks/runtime/event.rb +51 -0
- data/lib/hecks/runtime/identity.rb +128 -0
- data/lib/hecks/runtime/instance.rb +120 -0
- data/lib/hecks/runtime/interpreting.rb +69 -0
- data/lib/hecks/runtime/loader.rb +143 -0
- data/lib/hecks/runtime/policy_interpreter.rb +366 -0
- data/lib/hecks/runtime/port_operation_interpreter.rb +210 -0
- data/lib/hecks/runtime/query_interpreter.rb +254 -0
- data/lib/hecks/runtime/reaction_invocation.rb +245 -0
- data/lib/hecks/runtime/read_model_interpreter.rb +266 -0
- data/lib/hecks/runtime/rebuild_sweep.rb +74 -0
- data/lib/hecks/runtime/reference_hop.rb +99 -0
- data/lib/hecks/runtime/refusal_wording.rb +124 -0
- data/lib/hecks/runtime/registry/saga_persistence.rb +70 -0
- data/lib/hecks/runtime/registry/verification.rb +158 -0
- data/lib/hecks/runtime/registry.rb +218 -0
- data/lib/hecks/runtime/remote_dispatcher.rb +143 -0
- data/lib/hecks/runtime/routing.rb +96 -0
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +97 -0
- data/lib/hecks/runtime/saga_interpreter.rb +301 -0
- data/lib/hecks/runtime/storage_shape.rb +120 -0
- data/lib/hecks/runtime/tenant_check.rb +84 -0
- data/lib/hecks/runtime/tenant_scope.rb +55 -0
- data/lib/hecks/runtime/value/admission.rb +112 -0
- data/lib/hecks/runtime/value/coercion.rb +500 -0
- data/lib/hecks/runtime/value/invariant_violation.rb +5 -0
- data/lib/hecks/runtime/value.rb +125 -0
- data/lib/hecks/runtime.rb +95 -0
- data/lib/hecks/translation/audit/approval_digest.rb +31 -0
- data/lib/hecks/translation/audit/layer_one.rb +37 -0
- data/lib/hecks/translation/audit/layer_two.rb +77 -0
- data/lib/hecks/translation/audit/unfed_report.rb +42 -0
- data/lib/hecks/translation/audit.rb +70 -0
- data/lib/hecks/translation/reattest.rb +72 -0
- data/lib/hecks/translation/rule_compiler.rb +120 -0
- data/lib/hecks/translation/scaffold/differ.rb +183 -0
- data/lib/hecks/translation/scaffold/renderer.rb +41 -0
- data/lib/hecks/translation/scaffold/writer.rb +28 -0
- data/lib/hecks/translation/scaffold.rb +30 -0
- data/lib/hecks/translation.rb +11 -0
- data/lib/hecks/version.rb +16 -0
- data/lib/hecks/vocabulary.rb +213 -0
- data/lib/hecks.rb +118 -6
- metadata +401 -222
- data/bin/hecks +0 -7
- data/bin/hecks-package +0 -65
- data/bin/hecks_console +0 -12
- data/bin/hecks_serverless +0 -6
- data/lib/cli/build.rb +0 -14
- data/lib/cli/command_runner.rb +0 -28
- data/lib/cli/console.rb +0 -10
- data/lib/cli/generate.rb +0 -37
- data/lib/cli/hecks-cli.rb +0 -27
- data/lib/cli/test.rb +0 -57
- data/lib/console/commands.rb +0 -8
- data/lib/console/hecks-console.rb +0 -1
- data/lib/packager/README.md +0 -0
- data/lib/packager/app_runner.rb +0 -21
- data/lib/packager/args.rb +0 -26
- data/lib/packager/compatibility/fixnum.rb +0 -6
- data/lib/packager/hecks.rb +0 -39
- data/lib/packager/query_runner.rb +0 -21
- data/lib/packager/resources/Dockerfile +0 -11
- data/lib/packager/resources/app_binary +0 -7
- data/lib/packager/resources/bundle_config +0 -3
- data/lib/packager/resources/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz +0 -0
- data/lib/packager/resources/traveling-ruby-20150715-2.2.2-osx.tar.gz +0 -0
- data/lib/serverless/Domain +0 -32
- data/lib/serverless/cli.rb +0 -75
- data/lib/serverless/resources/command_name.js +0 -5
- data/lib/serverless/resources/environment.js +0 -7
- data/lib/serverless/resources/handler.js.tt +0 -28
- data/lib/serverless/resources/run_binary.js +0 -22
- data/lib/serverless/resources/serverless.yml +0 -20
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
Hecks.bluebook "Bluebook" do
|
|
2
|
+
aggregate "Aggregate" do
|
|
3
|
+
description "One aggregate inside a chapter — the head a domain's declarations attach to."
|
|
4
|
+
|
|
5
|
+
reference_to Bluebook
|
|
6
|
+
|
|
7
|
+
# THE CHAPTER IT IS IN, AND ITS NAME. `Order` names nothing on its own — two
|
|
8
|
+
# chapters may both declare one — so the chapter is part of the identity, not
|
|
9
|
+
# context around it. This is the derivation `MetaValidator::Judge#identify`
|
|
10
|
+
# spelled by hand as "#{parent_id}::#{name}" for as long as the language could
|
|
11
|
+
# not say it.
|
|
12
|
+
identified_by :bluebook, :name
|
|
13
|
+
|
|
14
|
+
# SPELLED AS THE IR SPELLS THEM — see the note on Command's fields.
|
|
15
|
+
attribute :name, AggregateName
|
|
16
|
+
attribute :description, Description
|
|
17
|
+
attribute :provenance, LiteralText
|
|
18
|
+
# SEVERAL PATHS, because the identity is their JOIN. One is the ordinary case ;
|
|
19
|
+
# more than one is what anything named BENEATH another thing needs, and the
|
|
20
|
+
# language's own chapters are all of that kind — a command is not named by
|
|
21
|
+
# `Declare`, which every aggregate here spells, but by the aggregate it belongs
|
|
22
|
+
# to AND that name. Held as a list for the same reason attributes are : the
|
|
23
|
+
# order is a fact about the source, and the join reads in it.
|
|
24
|
+
attribute :identified_by, list_of(IdentityPath)
|
|
25
|
+
attribute :attributes, list_of(Field)
|
|
26
|
+
attribute :value_objects, list_of(ValueName)
|
|
27
|
+
attribute :state_field, IdentityField, optional: true
|
|
28
|
+
attribute :state_start, IdentityField, optional: true
|
|
29
|
+
attribute :transitions, list_of(Transition)
|
|
30
|
+
# THE AGGREGATE BOUNDARY (S10, ADR 0025 — "Rules") — checked after
|
|
31
|
+
# every command, before save, the SAME Rule shape Command's own
|
|
32
|
+
# givens/ensures already carry (description+canonical), declared
|
|
33
|
+
# again here rather than shared: a closed set/value object is
|
|
34
|
+
# aggregate-scoped in this self-hosting domain, the same reason
|
|
35
|
+
# CommandText and LiteralText stay two separate, identically-
|
|
36
|
+
# shaped value objects rather than one reused across chapters.
|
|
37
|
+
attribute :invariants, list_of(Rule)
|
|
38
|
+
# A PRECONDITION SHARED ACROSS COMMANDS, DECLARED ONCE (S10, ADR
|
|
39
|
+
# 0025) — the SAME Rule shape, the aggregate's own named `given`s
|
|
40
|
+
# that a referencing command's own (already-resolved) `given`
|
|
41
|
+
# entry came from.
|
|
42
|
+
attribute :preconditions, list_of(Rule)
|
|
43
|
+
# A FIELD READ THROUGH A REFERENCE, HELD LOCALLY (S12, ADR 0025 —
|
|
44
|
+
# "Consistency across aggregate boundaries") — the local half of
|
|
45
|
+
# `projects :name, from: :"reference.remote_field"`. Deliberately
|
|
46
|
+
# NOT folded into `attributes` — see the comment on
|
|
47
|
+
# `Aggregate#emits_ir`'s own `projected_fields:` entry for why.
|
|
48
|
+
attribute :projected_fields, list_of(ProjectedField)
|
|
49
|
+
|
|
50
|
+
value_object "AggregateName" do
|
|
51
|
+
attribute :value, String
|
|
52
|
+
invariant("an aggregate is named") { !value.to_s.empty? }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
value_object "Description" do
|
|
56
|
+
attribute :value, String
|
|
57
|
+
invariant("a description says something") { !value.to_s.empty? }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
value_object "IdentityField" do
|
|
61
|
+
attribute :value, String
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# ONE PART OF AN IDENTITY — a path down to the SCALAR that carries it, like
|
|
65
|
+
# "number.value". A part on its own is not an identity ; the identity is every
|
|
66
|
+
# part joined, in the order they were declared.
|
|
67
|
+
#
|
|
68
|
+
# Its field is `value`, like every other one-field value object in this
|
|
69
|
+
# language, because that is the name the judge wraps a cell under. Spelling it
|
|
70
|
+
# `path` made `path.path` read nothing, and a given that reads nothing does not
|
|
71
|
+
# fail — it refuses everything, which is a far quieter way to be wrong.
|
|
72
|
+
value_object "IdentityPath" do
|
|
73
|
+
attribute :value, String
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
value_object "Field" do
|
|
77
|
+
attribute :name, String
|
|
78
|
+
attribute :type, String
|
|
79
|
+
attribute :list, String
|
|
80
|
+
attribute :optional, String, optional: true
|
|
81
|
+
attribute :pattern, String, optional: true
|
|
82
|
+
# Held as a LITERAL, written so its type survives — 0.0 rather than "0.0".
|
|
83
|
+
# Without this an aggregate attribute's default was simply dropped, and the
|
|
84
|
+
# reconstruction hardcoded nil, which happened to match every corpus member
|
|
85
|
+
# and would have lied about the first one that declared a default.
|
|
86
|
+
attribute :default, String
|
|
87
|
+
# THE CLOSED SET THIS VALUE MUST BELONG TO, named where it was already
|
|
88
|
+
# declared — `Vocabulary::QueryComparator`. Qualified by the aggregate that
|
|
89
|
+
# holds it, because a closed set is a value object INSIDE an aggregate and
|
|
90
|
+
# the aggregate is the only thing a reference can reach ; `one_of` is the
|
|
91
|
+
# other word and it can only ever SYNTHESISE a new set, never name one
|
|
92
|
+
# twice. Absent for almost every attribute, so it is optional.
|
|
93
|
+
attribute :admits, String, optional: true
|
|
94
|
+
# `reference_to`, `belongs_to`, `has_one`, or `has_many`; absent on
|
|
95
|
+
# ordinary value/entity fields. This keeps relationship language through
|
|
96
|
+
# the self-hosted round trip instead of collapsing it to a reference.
|
|
97
|
+
attribute :relationship, String, optional: true
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
value_object "ValueName" do
|
|
101
|
+
attribute :name, String
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
value_object "Transition" do
|
|
105
|
+
attribute :command, String
|
|
106
|
+
attribute :from_state, String
|
|
107
|
+
attribute :to_state, String
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# THE SAME SHAPE Command's own "Rule" value object carries — see
|
|
111
|
+
# behavior.bluebook — declared again here rather than shared, per
|
|
112
|
+
# that value object's own comment.
|
|
113
|
+
value_object "Rule" do
|
|
114
|
+
attribute :description, String
|
|
115
|
+
attribute :canonical, String
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# S12, ADR 0025 — `name` is this aggregate's own field being
|
|
119
|
+
# declared; `reference` names the local `reference_to` attribute to
|
|
120
|
+
# read through; `remote_field` names the scalar on the target. All
|
|
121
|
+
# three are plain identifiers, the same shape `Field#name`/`#type`
|
|
122
|
+
# already are.
|
|
123
|
+
value_object "ProjectedField" do
|
|
124
|
+
attribute :name, String
|
|
125
|
+
attribute :reference, String
|
|
126
|
+
attribute :remote_field, String
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
command "Declare" do
|
|
130
|
+
role "Language"
|
|
131
|
+
goal "Open an aggregate inside a chapter"
|
|
132
|
+
|
|
133
|
+
reference_to Bluebook
|
|
134
|
+
attribute :name, AggregateName
|
|
135
|
+
attribute :description, Description, optional: true
|
|
136
|
+
# See Command.Declare's own `provenance` — identical shape, one
|
|
137
|
+
# level up. LiteralText, not a dedicated value object: the field
|
|
138
|
+
# rides the same self-describing `inspect` encoding `default:`
|
|
139
|
+
# already uses, so it needs no invariant of its own.
|
|
140
|
+
attribute :provenance, LiteralText, optional: true
|
|
141
|
+
|
|
142
|
+
attribute :position, Position, optional: true
|
|
143
|
+
|
|
144
|
+
sets :bluebook
|
|
145
|
+
sets :name
|
|
146
|
+
sets :description
|
|
147
|
+
sets :provenance
|
|
148
|
+
sets :position
|
|
149
|
+
emits "RootDeclared"
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# ONE PART OF THE IDENTITY, attached the way one attribute is. It was an
|
|
153
|
+
# argument on Declare while an identity was a single field ; a list cannot be
|
|
154
|
+
# carried by one argument, and every other list in this language is filled by
|
|
155
|
+
# a verb of its own, so this is the shape that was already here.
|
|
156
|
+
command "Identify" do
|
|
157
|
+
role "Language"
|
|
158
|
+
goal "Attach one part of the aggregate's identity"
|
|
159
|
+
|
|
160
|
+
attribute :path, IdentityPath
|
|
161
|
+
|
|
162
|
+
# AN IDENTITY PART NAMES SOMETHING. This rule used to sit on Seal reading
|
|
163
|
+
# `empty? || == "id" || includes(".")` — two escapes and a check. The escapes
|
|
164
|
+
# were the whole of it : `empty?` let an aggregate say nothing and be given a
|
|
165
|
+
# minted `id`, and `== "id"` let it name that slot outright. Both are gone,
|
|
166
|
+
# so what is left is the rule itself, and it now runs on every part rather
|
|
167
|
+
# than on whichever one a single field happened to hold.
|
|
168
|
+
#
|
|
169
|
+
# THREE WAYS TO REACH A SCALAR (ADR 0025, "Identity"), and this given no
|
|
170
|
+
# longer distinguishes them — it used to accept only a dotted path
|
|
171
|
+
# (`number.value`, a value object's own field) or an `_id`-suffixed
|
|
172
|
+
# reference, and REFUSED a bare scalar field (`sku`), which is legal
|
|
173
|
+
# too : a plain primitive attribute IS already a scalar, nothing to
|
|
174
|
+
# open. That distinction belongs to the BUILDER, which resolves each
|
|
175
|
+
# spelling before an identity part ever reaches here
|
|
176
|
+
# (`AttributeCollector#resolve_identity_field!` — the single place
|
|
177
|
+
# that decides dotted-unwrap vs. reference vs. bare-scalar, and the
|
|
178
|
+
# only place that can, since it alone holds the attribute's declared
|
|
179
|
+
# type). What is left for THIS rule to say, once the builder has
|
|
180
|
+
# already resolved a real shape, is only that a part was actually
|
|
181
|
+
# given a name at all.
|
|
182
|
+
given("an identity part names something") { !path.value.to_s.empty? }
|
|
183
|
+
|
|
184
|
+
sets :identified_by, append: { value: :path }
|
|
185
|
+
emits "RootIdentified"
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# The way back, one level down: the aggregates DECLARED IN a chapter, found by
|
|
189
|
+
# the chapter that declared them. The parent reference IS the query.
|
|
190
|
+
#
|
|
191
|
+
# `bluebook_id` is an IdentityField, not an AggregateName — it holds the id of
|
|
192
|
+
# the chapter above, and calling that a name for aggregates was sloppiness that
|
|
193
|
+
# would read as a lie the first time somebody looked.
|
|
194
|
+
# WHERE IT SITS AMONG ITS SIBLINGS. Declaration order is a FACT ABOUT THE
|
|
195
|
+
# SOURCE — the IR is a contract read straight from this file,
|
|
196
|
+
# field for field AND INDEX FOR INDEX. So the language HOLDS it, instead of
|
|
197
|
+
# inheriting it from whatever order a store happens to iterate: an ask that
|
|
198
|
+
# does not say how it is ordered is answered in identity order, which is
|
|
199
|
+
# right for every other ask and fatal for the one that is the SOURCE.
|
|
200
|
+
value_object "Position" do
|
|
201
|
+
attribute :value, Integer
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
attribute :position, Position
|
|
205
|
+
|
|
206
|
+
query "DeclaredIn" do
|
|
207
|
+
attribute :bluebook, IdentityField
|
|
208
|
+
where(bluebook: :bluebook)
|
|
209
|
+
order_by :position
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
command "Attribute" do
|
|
213
|
+
role "Language"
|
|
214
|
+
goal "Attach one attribute to the aggregate"
|
|
215
|
+
|
|
216
|
+
# The TYPE is a reference to the value object it names. An attribute
|
|
217
|
+
# naming an undeclared value object then fails REFERENCE RESOLUTION —
|
|
218
|
+
# "no Shape with id …" — with no predicate at all.
|
|
219
|
+
#
|
|
220
|
+
# This is the rule "attributes must use value-object types", which could
|
|
221
|
+
# not be a `given` : it needs, for each element of a list, a check against
|
|
222
|
+
# another list, and the sublanguage has no quantifier and cannot see
|
|
223
|
+
# inside a list element. As a reference it stops being a predicate and
|
|
224
|
+
# becomes a consequence of the model.
|
|
225
|
+
reference_to ValueObject, as: :type
|
|
226
|
+
attribute :name, FieldName
|
|
227
|
+
attribute :list, ListFlag
|
|
228
|
+
attribute :optional, ListFlag, optional: true
|
|
229
|
+
# A PATTERN IS A REGEX, not a flag — see the note on ListFlag below.
|
|
230
|
+
attribute :pattern, LiteralText, optional: true
|
|
231
|
+
attribute :default, LiteralText, optional: true
|
|
232
|
+
# FREE TEXT, not a reference. A closed set is a value object INSIDE an
|
|
233
|
+
# aggregate, and `reference_to` reaches heads only — so the qualified name
|
|
234
|
+
# is carried as text and checked where it is READ, by the reader, which
|
|
235
|
+
# already raises for the other things the language cannot say about itself.
|
|
236
|
+
attribute :admits, LiteralText, optional: true
|
|
237
|
+
attribute :relationship, LiteralText, optional: true
|
|
238
|
+
|
|
239
|
+
sets :attributes, append: { name: :name, type: :type, list: :list, default: :default, optional: :optional, pattern: :pattern, admits: :admits, relationship: :relationship }
|
|
240
|
+
|
|
241
|
+
emits "AttributeAttached"
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# An attribute that points at ANOTHER aggregate's head.
|
|
245
|
+
#
|
|
246
|
+
# `Attribute` types its type as `reference_to ValueObject`, which is what makes
|
|
247
|
+
# "attributes use value-object types" a consequence of the model rather than a
|
|
248
|
+
# predicate. A cross-aggregate reference cannot go through it: its type is
|
|
249
|
+
# `Reference<Customer>`, which is not a value object and never will be. So the
|
|
250
|
+
# judge SKIPPED every one of them, and the meta-domain did not hold
|
|
251
|
+
# Account#customer_id at all — the way back was lossy for exactly one
|
|
252
|
+
# construct, and the comment excusing it said "the language does not model
|
|
253
|
+
# reference-typed attributes yet".
|
|
254
|
+
command "Reference" do
|
|
255
|
+
role "Language"
|
|
256
|
+
goal "Attach an attribute that points at another aggregate's head"
|
|
257
|
+
|
|
258
|
+
# POINTS AT a declared head, and that is the whole rule.
|
|
259
|
+
#
|
|
260
|
+
# This carried `attribute :type, ReferenceType` — a STRING — with an invariant
|
|
261
|
+
# apologising for itself, because the shape that actually tells a reference
|
|
262
|
+
# from a value object (`Reference<Something>`) is unsayable in the predicate
|
|
263
|
+
# sublanguage. That was never a sublanguage gap; a string was simply the wrong
|
|
264
|
+
# model. As a reference it stops being a predicate and becomes a consequence
|
|
265
|
+
# of the model, exactly as Attribute's type does — and it is STRONGER than the
|
|
266
|
+
# prefix match, which only ever checked that the text looked right.
|
|
267
|
+
reference_to Aggregate, as: :points_at
|
|
268
|
+
attribute :name, FieldName
|
|
269
|
+
attribute :list, ListFlag
|
|
270
|
+
attribute :optional, ListFlag, optional: true
|
|
271
|
+
# A PATTERN IS A REGEX, not a flag — see the note on ListFlag below.
|
|
272
|
+
attribute :pattern, LiteralText, optional: true
|
|
273
|
+
attribute :default, LiteralText, optional: true
|
|
274
|
+
attribute :admits, LiteralText, optional: true
|
|
275
|
+
attribute :relationship, LiteralText, optional: true
|
|
276
|
+
|
|
277
|
+
sets :attributes, append: { name: :name, type: :points_at, list: :list, default: :default, optional: :optional, pattern: :pattern, admits: :admits, relationship: :relationship }
|
|
278
|
+
|
|
279
|
+
emits "ReferenceAttached"
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# An attribute whose type names a PIECE this aggregate holds.
|
|
283
|
+
#
|
|
284
|
+
# `Account#ledger` is a list of LedgerEntry — neither a value object nor another
|
|
285
|
+
# aggregate's head — so it fitted no verb and the walk skipped it, the last
|
|
286
|
+
# construct the way back could not carry. Same trick as Reference: point at the
|
|
287
|
+
# entity's own declaration, and "an aggregate holds a piece it declared" costs
|
|
288
|
+
# no predicate at all. Entities are declared before attributes are offered, so
|
|
289
|
+
# the reference resolves.
|
|
290
|
+
command "Holds" do
|
|
291
|
+
role "Language"
|
|
292
|
+
goal "Attach an attribute whose type is a piece of this aggregate"
|
|
293
|
+
|
|
294
|
+
reference_to Entity, as: :holds
|
|
295
|
+
attribute :name, FieldName
|
|
296
|
+
attribute :list, ListFlag
|
|
297
|
+
attribute :optional, ListFlag, optional: true
|
|
298
|
+
# A PATTERN IS A REGEX, not a flag — see the note on ListFlag below.
|
|
299
|
+
attribute :pattern, LiteralText, optional: true
|
|
300
|
+
attribute :default, LiteralText, optional: true
|
|
301
|
+
attribute :admits, LiteralText, optional: true
|
|
302
|
+
attribute :relationship, LiteralText, optional: true
|
|
303
|
+
|
|
304
|
+
sets :attributes, append: { name: :name, type: :holds, list: :list, default: :default, optional: :optional, pattern: :pattern, admits: :admits, relationship: :relationship }
|
|
305
|
+
|
|
306
|
+
emits "PieceHeld"
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# THE ONLY RULE THAT CAN REFUSE AN UNNAMED ATTRIBUTE, and it lives here.
|
|
310
|
+
#
|
|
311
|
+
# Attribute, Reference and Holds each carried `given("… is named")` beside
|
|
312
|
+
# this, and not one of them could ever fire: an EMPTY name builds the value
|
|
313
|
+
# object and this invariant refuses first, while an ABSENT name builds no
|
|
314
|
+
# value object and the given did not refuse at all — probed, not reasoned.
|
|
315
|
+
# Three rules that read as rules and were decoration. A predicate cannot
|
|
316
|
+
# guard what a type already guards.
|
|
317
|
+
value_object "FieldName" do
|
|
318
|
+
attribute :value, String
|
|
319
|
+
invariant("an attribute is named") { !value.to_s.empty? }
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
value_object "TypeName" do
|
|
323
|
+
attribute :value, String
|
|
324
|
+
invariant("a type is named") { !value.to_s.empty? }
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# A literal written the way it can be read back — see Readings#encode_literal.
|
|
328
|
+
value_object "LiteralText" do
|
|
329
|
+
attribute :value, String
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# TRUE OR FALSE, AND NOTHING ELSE. `list` and `optional` are the two fields
|
|
333
|
+
# this is about — they are the answers to a yes/no question, written as text
|
|
334
|
+
# because that is what the wire carries.
|
|
335
|
+
#
|
|
336
|
+
# `pattern` was typed with it too, which is not a loose typing but a FALSE
|
|
337
|
+
# one: a pattern holds a regex, and this invariant admits exactly two strings
|
|
338
|
+
# neither of which is one. It never fired only because no aggregate-level or
|
|
339
|
+
# entity-level attribute in the corpus declares a pattern — banking's one
|
|
340
|
+
# `pattern:` sits on a VALUE OBJECT field, which is built by
|
|
341
|
+
# `ValueObject.Field` and so went down a different command entirely. The
|
|
342
|
+
# first head that declared a pattern would have been refused by a rule about
|
|
343
|
+
# lists. It is `LiteralText` now, which is what the other four element
|
|
344
|
+
# builders already say a pattern is: free text.
|
|
345
|
+
value_object "ListFlag" do
|
|
346
|
+
attribute :value, String
|
|
347
|
+
invariant("list is true or false") { value.to_s == "true" || value.to_s == "false" }
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
command "Lifecycle" do
|
|
351
|
+
role "Language"
|
|
352
|
+
goal "Name the field this aggregate's state machine runs on"
|
|
353
|
+
|
|
354
|
+
attribute :state_field, FieldName
|
|
355
|
+
attribute :state_start, FieldName
|
|
356
|
+
|
|
357
|
+
sets :state_field
|
|
358
|
+
sets :state_start
|
|
359
|
+
|
|
360
|
+
emits "LifecycleNamed"
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
command "Transition" do
|
|
364
|
+
role "Language"
|
|
365
|
+
goal "Attach one transition to the state machine"
|
|
366
|
+
|
|
367
|
+
attribute :command, FieldName
|
|
368
|
+
attribute :from_state, FieldName, optional: true
|
|
369
|
+
attribute :to_state, FieldName
|
|
370
|
+
|
|
371
|
+
sets :transitions, append: { command: :command, from_state: :from_state, to_state: :to_state }
|
|
372
|
+
|
|
373
|
+
emits "TransitionAttached"
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
command "Seal" do
|
|
377
|
+
role "Language"
|
|
378
|
+
goal "Close an aggregate — the checks that need every declaration present"
|
|
379
|
+
|
|
380
|
+
# The builders validate at `build`, once everything is collected. A given
|
|
381
|
+
# fires at DISPATCH, when later declarations do not exist yet. So the
|
|
382
|
+
# whole-document rules live on a command dispatched after the aggregate
|
|
383
|
+
# is fully declared. This is the shape the tier-3 rules need ; whether
|
|
384
|
+
# the sublanguage can express their CONTENT is the open question.
|
|
385
|
+
|
|
386
|
+
# THE RULE THAT WAS HERE WAS NOT TRUE, and nothing could tell us while Seal
|
|
387
|
+
# went undispatched. `given("an aggregate declares at least one attribute")`
|
|
388
|
+
# was invented for this command — it is not one of the rules ported from the
|
|
389
|
+
# builders, so no bluebook was ever written against it. The first time it
|
|
390
|
+
# ran it refused twenty-five of them, including every aggregate whose state
|
|
391
|
+
# is a `lifecycle` rather than an `attribute` : a state machine declares no
|
|
392
|
+
# attribute and is perfectly well formed.
|
|
393
|
+
#
|
|
394
|
+
# Seal stays. It is the right SHAPE for a whole-document rule — dispatched
|
|
395
|
+
# once every declaration is present — and it is now actually dispatched, so
|
|
396
|
+
# the next rule put here will be seen refusing instead of sitting decorative.
|
|
397
|
+
# The rule waiting for it is "a mutation names a field the aggregate has",
|
|
398
|
+
# which lives in AggregateBuilder today because saying it here needs to reach
|
|
399
|
+
# a list on another root.
|
|
400
|
+
# AN AGGREGATE SAYS WHAT IT IS KNOWN BY. Nothing falls back to `id` any more.
|
|
401
|
+
#
|
|
402
|
+
# The fallback was never a default — it was a MINT. An aggregate that said
|
|
403
|
+
# nothing got an id invented for it, so the same declaration named a
|
|
404
|
+
# different record on the next run, and nothing outside the runtime could
|
|
405
|
+
# name a record at all. The rule that stood here permitted it in as many
|
|
406
|
+
# words (`empty? || == "id"`), and the comment named exactly who was
|
|
407
|
+
# leaning on it : the language's own chapters, all fourteen of them.
|
|
408
|
+
#
|
|
409
|
+
# They derive now, like everything else does. What each PART must look like
|
|
410
|
+
# is Identify's rule ; this one only asks that there be one.
|
|
411
|
+
given("an aggregate says what it is known by") { !identified_by.empty? }
|
|
412
|
+
|
|
413
|
+
emits "RootSealed"
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
command "Value" do
|
|
417
|
+
role "Language"
|
|
418
|
+
goal "Declare a value object belonging to this aggregate"
|
|
419
|
+
|
|
420
|
+
attribute :name, FieldName
|
|
421
|
+
|
|
422
|
+
sets :value_objects, append: { name: :name }
|
|
423
|
+
|
|
424
|
+
emits "ValueDeclared"
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
# THE AGGREGATE BOUNDARY (S10, ADR 0025 — "Rules") — the same shape
|
|
428
|
+
# Command.Rule attaches a given with, one level up.
|
|
429
|
+
command "Invariant" do
|
|
430
|
+
role "Language"
|
|
431
|
+
goal "Attach one invariant to the aggregate"
|
|
432
|
+
|
|
433
|
+
attribute :description, LiteralText, optional: true
|
|
434
|
+
attribute :canonical, LiteralText
|
|
435
|
+
|
|
436
|
+
given("a rule says what it means") { !description.value.to_s.empty? }
|
|
437
|
+
given("a rule survives extraction") { !canonical.value.to_s.empty? }
|
|
438
|
+
|
|
439
|
+
sets :invariants, append: { description: :description, canonical: :canonical }
|
|
440
|
+
|
|
441
|
+
emits "InvariantAttached"
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# A PRECONDITION SHARED ACROSS COMMANDS, DECLARED ONCE (S10, ADR
|
|
445
|
+
# 0025) — the aggregate's own named `given`, referenced back by a
|
|
446
|
+
# command rather than re-typed.
|
|
447
|
+
command "Precondition" do
|
|
448
|
+
role "Language"
|
|
449
|
+
goal "Declare one precondition commands can reference by name"
|
|
450
|
+
|
|
451
|
+
attribute :description, LiteralText, optional: true
|
|
452
|
+
attribute :canonical, LiteralText
|
|
453
|
+
|
|
454
|
+
given("a rule says what it means") { !description.value.to_s.empty? }
|
|
455
|
+
given("a rule survives extraction") { !canonical.value.to_s.empty? }
|
|
456
|
+
|
|
457
|
+
sets :preconditions, append: { description: :description, canonical: :canonical }
|
|
458
|
+
|
|
459
|
+
emits "PreconditionAttached"
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
# THE LOCAL HALF OF A CROSS-AGGREGATE READ (S12, ADR 0025) — the
|
|
463
|
+
# target's own existence and shape are checked elsewhere
|
|
464
|
+
# (BluebookBuilder#validate_projected_fields!, once every aggregate
|
|
465
|
+
# in the chapter is real), the same two-tier split a query's own
|
|
466
|
+
# hop already uses.
|
|
467
|
+
command "Projects" do
|
|
468
|
+
role "Language"
|
|
469
|
+
goal "Declare a field read locally through a reference"
|
|
470
|
+
|
|
471
|
+
attribute :name, FieldName
|
|
472
|
+
attribute :reference, FieldName
|
|
473
|
+
attribute :remote_field, FieldName
|
|
474
|
+
|
|
475
|
+
given("a projected field is named") { !name.value.to_s.empty? }
|
|
476
|
+
given("a projected field reads through a reference") { !reference.value.to_s.empty? }
|
|
477
|
+
given("a projected field names a remote field") { !remote_field.value.to_s.empty? }
|
|
478
|
+
|
|
479
|
+
sets :projected_fields, append: { name: :name, reference: :reference, remote_field: :remote_field }
|
|
480
|
+
|
|
481
|
+
emits "ProjectedFieldAttached"
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
# HOW AGGREGATE IS SPELLED. These rows live with the concept
|
|
485
|
+
# they describe; SyntaxBoot discovers every aggregate-local seed table.
|
|
486
|
+
# Contexts represented here: Aggregate, Lifecycle.
|
|
487
|
+
value_object "KeywordSeed" do
|
|
488
|
+
attribute :word, String
|
|
489
|
+
attribute :context, String, admits: "Syntax::Context"
|
|
490
|
+
attribute :body, String, admits: "Syntax::Body"
|
|
491
|
+
attribute :inner, String
|
|
492
|
+
attribute :opens, String
|
|
493
|
+
attribute :fills, String
|
|
494
|
+
attribute :status, String, default: "admitted", admits: "Syntax::Status"
|
|
495
|
+
attribute :was, String
|
|
496
|
+
attribute :resolves_via, String, default: "", admits: "Syntax::ResolutionScope"
|
|
497
|
+
attribute :disambiguator, String, default: "", admits: "Syntax::Disambiguator"
|
|
498
|
+
|
|
499
|
+
member word: "description", context: "Aggregate", body: "none", inner: "", opens: "", fills: "description"
|
|
500
|
+
member word: "provenance", context: "Aggregate", body: "none", inner: "", opens: "", fills: "provenance", calls: "provenance_impl"
|
|
501
|
+
member word: "identified_by", context: "Aggregate", body: "keywords", inner: "ValueObject", opens: "ValueObject", fills: "identified_by", calls: "identified_by_impl"
|
|
502
|
+
member word: "identified_by", context: "Aggregate", body: "none", inner: "", opens: "", fills: "identified_by", calls: "identified_by_impl"
|
|
503
|
+
member word: "reference_to", context: "Aggregate", body: "none", inner: "", opens: "", fills: "attributes", calls: "reference_to_impl"
|
|
504
|
+
member word: "has_many", context: "Aggregate", body: "none", inner: "", opens: "", fills: "attributes", calls: "has_many_impl"
|
|
505
|
+
member word: "has_one", context: "Aggregate", body: "none", inner: "", opens: "", fills: "attributes", calls: "has_one_impl"
|
|
506
|
+
member word: "belongs_to", context: "Aggregate", body: "none", inner: "", opens: "", fills: "attributes", calls: "belongs_to_impl"
|
|
507
|
+
member word: "lifecycle", context: "Aggregate", body: "keywords", inner: "Lifecycle", opens: "", fills: "state_field", calls: "lifecycle_impl"
|
|
508
|
+
member word: "entity", context: "Aggregate", body: "keywords", inner: "Entity", opens: "Entity", fills: "", calls: "entity_impl"
|
|
509
|
+
member word: "query", context: "Aggregate", body: "keywords", inner: "Query", opens: "Query", fills: "", calls: "query_impl"
|
|
510
|
+
member word: "policy", context: "Aggregate", body: "keywords", inner: "Policy", opens: "Policy", fills: "", calls: "policy_impl"
|
|
511
|
+
member word: "value_object", context: "Aggregate", body: "keywords", inner: "ValueObject", opens: "ValueObject", fills: "value_objects"
|
|
512
|
+
member word: "command", context: "Aggregate", body: "keywords", inner: "Command", opens: "Command", fills: "", calls: "command_impl"
|
|
513
|
+
member word: "attribute", context: "Aggregate", body: "none", inner: "", opens: "", fills: "attributes", calls: "attribute_impl"
|
|
514
|
+
member word: "invariant", context: "Aggregate", body: "source", inner: "", opens: "", fills: "invariants", calls: "invariant_impl"
|
|
515
|
+
member word: "given", context: "Aggregate", body: "source", inner: "", opens: "", fills: "preconditions", resolves_via: "owner_keyed", disambiguator: "declared_by", calls: "given_impl"
|
|
516
|
+
member word: "projects", context: "Aggregate", body: "none", inner: "", opens: "", fills: "projected_fields", calls: "projects_impl"
|
|
517
|
+
member word: "transition", context: "Lifecycle", body: "none", inner: "", opens: "", fills: "transitions", calls: "transition_impl"
|
|
518
|
+
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
value_object "ArgumentSeed" do
|
|
522
|
+
attribute :keyword, String
|
|
523
|
+
attribute :context, String, admits: "Syntax::Context"
|
|
524
|
+
attribute :at, String
|
|
525
|
+
attribute :named, String
|
|
526
|
+
attribute :kind, String, admits: "Syntax::ArgumentKind"
|
|
527
|
+
attribute :required, String
|
|
528
|
+
attribute :fills, String
|
|
529
|
+
attribute :selects, String
|
|
530
|
+
attribute :pair_key_fills, String
|
|
531
|
+
attribute :pair_value_fills, String
|
|
532
|
+
attribute :pairs_shape, String, admits: "Syntax::PairsShape"
|
|
533
|
+
attribute :status, String, default: "admitted", admits: "Syntax::Status"
|
|
534
|
+
attribute :variadic, String
|
|
535
|
+
attribute :minimum, String
|
|
536
|
+
attribute :coerce, String
|
|
537
|
+
attribute :blank_message, String
|
|
538
|
+
|
|
539
|
+
member keyword: "description", context: "Aggregate", at: "1", named: "", kind: "text", required: "true", fills: "description", coerce: "false"
|
|
540
|
+
member keyword: "provenance", context: "Aggregate", at: "", named: "from", kind: "literal", required: "true", fills: "provenance"
|
|
541
|
+
member keyword: "identified_by", context: "Aggregate", at: "1", named: "", kind: "symbol", required: "false", fills: "identified_by", variadic: "true", minimum: "2"
|
|
542
|
+
member keyword: "identified_by", context: "Aggregate", at: "1", named: "", kind: "constant", required: "false", fills: "type"
|
|
543
|
+
member keyword: "identified_by", context: "Aggregate", at: "", named: "as", kind: "symbol", required: "false", fills: "name"
|
|
544
|
+
member keyword: "reference_to", context: "Aggregate", at: "1", named: "", kind: "constant", required: "true", fills: "type"
|
|
545
|
+
member keyword: "reference_to", context: "Aggregate", at: "", named: "as", kind: "symbol", required: "false", fills: "name"
|
|
546
|
+
member keyword: "reference_to", context: "Aggregate", at: "", named: "optional", kind: "flag", required: "false", fills: "optional"
|
|
547
|
+
member keyword: "has_many", context: "Aggregate", at: "1", named: "", kind: "constant", required: "true", fills: "type"
|
|
548
|
+
member keyword: "has_many", context: "Aggregate", at: "", named: "as", kind: "symbol", required: "false", fills: "name"
|
|
549
|
+
member keyword: "has_one", context: "Aggregate", at: "1", named: "", kind: "constant", required: "true", fills: "type"
|
|
550
|
+
member keyword: "has_one", context: "Aggregate", at: "", named: "as", kind: "symbol", required: "false", fills: "name"
|
|
551
|
+
member keyword: "has_one", context: "Aggregate", at: "", named: "optional", kind: "flag", required: "false", fills: "optional"
|
|
552
|
+
member keyword: "belongs_to", context: "Aggregate", at: "1", named: "", kind: "constant", required: "true", fills: "type"
|
|
553
|
+
member keyword: "belongs_to", context: "Aggregate", at: "", named: "as", kind: "symbol", required: "false", fills: "name"
|
|
554
|
+
member keyword: "belongs_to", context: "Aggregate", at: "", named: "optional", kind: "flag", required: "false", fills: "optional"
|
|
555
|
+
member keyword: "lifecycle", context: "Aggregate", at: "1", named: "", kind: "symbol", required: "true", fills: "state_field"
|
|
556
|
+
member keyword: "lifecycle", context: "Aggregate", at: "", named: "default", kind: "literal", required: "true", fills: "state_start"
|
|
557
|
+
member keyword: "entity", context: "Aggregate", at: "1", named: "", kind: "text", required: "true", fills: "name"
|
|
558
|
+
member keyword: "query", context: "Aggregate", at: "1", named: "", kind: "text", required: "true", fills: "name"
|
|
559
|
+
member keyword: "policy", context: "Aggregate", at: "1", named: "", kind: "text", required: "true", fills: "name"
|
|
560
|
+
member keyword: "value_object", context: "Aggregate", at: "1", named: "", kind: "text", required: "true", fills: "name"
|
|
561
|
+
member keyword: "command", context: "Aggregate", at: "1", named: "", kind: "text", required: "true", fills: "name"
|
|
562
|
+
member keyword: "command", context: "Aggregate", at: "", named: "from", kind: "literal", required: "false", fills: "from"
|
|
563
|
+
member keyword: "attribute", context: "Aggregate", at: "1", named: "", kind: "symbol", required: "true", fills: "name"
|
|
564
|
+
member keyword: "attribute", context: "Aggregate", at: "2", named: "", kind: "constant", required: "true", fills: "type"
|
|
565
|
+
member keyword: "attribute", context: "Aggregate", at: "", named: "default", kind: "literal", required: "false", fills: "default"
|
|
566
|
+
member keyword: "attribute", context: "Aggregate", at: "", named: "optional", kind: "flag", required: "false", fills: "optional"
|
|
567
|
+
member keyword: "attribute", context: "Aggregate", at: "", named: "pattern", kind: "text", required: "false", fills: "pattern"
|
|
568
|
+
member keyword: "attribute", context: "Aggregate", at: "", named: "admits", kind: "text", required: "false", fills: "admits"
|
|
569
|
+
member keyword: "attribute", context: "Aggregate", at: "", named: "one_of", kind: "list", required: "false", fills: "one_of"
|
|
570
|
+
member keyword: "invariant", context: "Aggregate", at: "1", named: "", kind: "text", required: "true", fills: "description"
|
|
571
|
+
member keyword: "given", context: "Aggregate", at: "1", named: "", kind: "text", required: "true", fills: "description"
|
|
572
|
+
member keyword: "given", context: "Aggregate", at: "", named: "declared_by", kind: "constant", required: "false", fills: "declared_by"
|
|
573
|
+
member keyword: "projects", context: "Aggregate", at: "1", named: "", kind: "symbol", required: "true", fills: "name"
|
|
574
|
+
member keyword: "projects", context: "Aggregate", at: "", named: "from", kind: "symbol", required: "true", fills: "from"
|
|
575
|
+
member keyword: "transition", context: "Lifecycle", at: "1", named: "", kind: "pairs", required: "true", fills: "", pair_key_fills: "command", pair_value_fills: "to_state", pairs_shape: "fields"
|
|
576
|
+
member keyword: "transition", context: "Lifecycle", at: "", named: "from", kind: "text", required: "false", fills: "from_state"
|
|
577
|
+
member keyword: "transition", context: "Lifecycle", at: "", named: "from", kind: "list", required: "false", fills: "from_state"
|
|
578
|
+
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Hecks.bluebook "Paging" do
|
|
2
|
+
vision "The four words a page of results is read through — limit, offset, cursor, nulls — held as their own sub-language rather than as four more rows in the core's own grammar table. ADR 0026's own worked example: the core grammar does not name its extension points, so this chapter names ITSELF onto them, with `attaches_to`."
|
|
3
|
+
generic
|
|
4
|
+
attaches_to "Query", "ReadModel"
|
|
5
|
+
|
|
6
|
+
# A PLACE TO HOLD ROWS, AND NOTHING ELSE — the same shape `Vocabulary`
|
|
7
|
+
# (vocabulary.bluebook) already is: no commands, because nothing ever
|
|
8
|
+
# dispatches this aggregate for real. `SyntaxBoot`'s own generic
|
|
9
|
+
# discovery reads `KeywordSeed`/`ArgumentSeed`'s rows straight off the
|
|
10
|
+
# declared IR, the exact way it already reads the core's own — and
|
|
11
|
+
# dispatches them through the CORE's `Bluebook::Syntax.Keyword`/
|
|
12
|
+
# `.Argument` verbs, which is why these rows need no entity, no
|
|
13
|
+
# lifecycle, no creating command of their own here: the verb they ride
|
|
14
|
+
# already exists, and a second copy of it would be the core's own
|
|
15
|
+
# machinery duplicated for no reason.
|
|
16
|
+
aggregate "Syntax" do
|
|
17
|
+
description "The rows this sub-language contributes to the core's own grammar table."
|
|
18
|
+
identified_by PagingSyntaxName, as: :name
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
value_object "PagingSyntaxName" do
|
|
22
|
+
attribute :value, String
|
|
23
|
+
invariant("a syntax table is named") { !value.to_s.empty? }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# THE SAME EIGHT ROWS syntax.bluebook held directly until now — moved,
|
|
27
|
+
# not rewritten. `limit`/`offset`/`cursor`/`nulls`, on both `Query`
|
|
28
|
+
# and `ReadModel`. See syntax.bluebook's own comment at the old site
|
|
29
|
+
# for why `limit` fills a dedicated field while the other three land
|
|
30
|
+
# on the open `options` map.
|
|
31
|
+
value_object "KeywordSeed" do
|
|
32
|
+
attribute :word, String
|
|
33
|
+
attribute :context, String
|
|
34
|
+
attribute :body, String
|
|
35
|
+
attribute :inner, String
|
|
36
|
+
attribute :opens, String
|
|
37
|
+
attribute :fills, String
|
|
38
|
+
attribute :was, String, optional: true
|
|
39
|
+
|
|
40
|
+
member word: "limit", context: "Query", body: "none", inner: "", opens: "", fills: "limit", calls: "limit_impl"
|
|
41
|
+
member word: "offset", context: "Query", body: "none", inner: "", opens: "", fills: "options", calls: "offset_impl"
|
|
42
|
+
member word: "cursor", context: "Query", body: "none", inner: "", opens: "", fills: "options"
|
|
43
|
+
member word: "nulls", context: "Query", body: "none", inner: "", opens: "", fills: "options"
|
|
44
|
+
|
|
45
|
+
member word: "limit", context: "ReadModel", body: "none", inner: "", opens: "", fills: "options", calls: "limit_impl"
|
|
46
|
+
member word: "offset", context: "ReadModel", body: "none", inner: "", opens: "", fills: "options", calls: "offset_impl"
|
|
47
|
+
member word: "cursor", context: "ReadModel", body: "none", inner: "", opens: "", fills: "options"
|
|
48
|
+
member word: "nulls", context: "ReadModel", body: "none", inner: "", opens: "", fills: "options"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
value_object "ArgumentSeed" do
|
|
52
|
+
attribute :keyword, String
|
|
53
|
+
attribute :context, String
|
|
54
|
+
attribute :at, String, optional: true
|
|
55
|
+
attribute :named, String, optional: true
|
|
56
|
+
attribute :kind, String
|
|
57
|
+
attribute :required, String
|
|
58
|
+
attribute :fills, String, optional: true
|
|
59
|
+
attribute :selects, String, optional: true
|
|
60
|
+
attribute :pair_key_fills, String, optional: true
|
|
61
|
+
attribute :pair_value_fills, String, optional: true
|
|
62
|
+
attribute :pairs_shape, String, optional: true
|
|
63
|
+
attribute :variadic, String, optional: true
|
|
64
|
+
|
|
65
|
+
member keyword: "limit", context: "Query", at: "1", named: "", kind: "number", required: "true", fills: "limit"
|
|
66
|
+
member keyword: "offset", context: "Query", at: "1", named: "", kind: "number", required: "true", fills: "value"
|
|
67
|
+
member keyword: "cursor", context: "Query", at: "1", named: "", kind: "symbol", required: "true", fills: "value"
|
|
68
|
+
member keyword: "nulls", context: "Query", at: "1", named: "", kind: "symbol", required: "true", fills: "mode"
|
|
69
|
+
|
|
70
|
+
member keyword: "limit", context: "ReadModel", at: "1", named: "", kind: "number", required: "true", fills: "value"
|
|
71
|
+
member keyword: "offset", context: "ReadModel", at: "1", named: "", kind: "number", required: "true", fills: "value"
|
|
72
|
+
member keyword: "cursor", context: "ReadModel", at: "1", named: "", kind: "symbol", required: "true", fills: "value"
|
|
73
|
+
member keyword: "nulls", context: "ReadModel", at: "1", named: "", kind: "symbol", required: "true", fills: "mode"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|