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,120 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require "digest"
|
|
3
|
+
|
|
4
|
+
module Hecks
|
|
5
|
+
module Runtime
|
|
6
|
+
# The storage-shape projection of a bluebook: exactly the parts of
|
|
7
|
+
# the IR that decide what persisted data looks like — aggregates,
|
|
8
|
+
# their attributes (with full value-object/entity structure and
|
|
9
|
+
# cardinality), references, the lifecycle field, and the identity
|
|
10
|
+
# paths. Everything behavioral — commands, invariants, queries,
|
|
11
|
+
# policies, lifecycle transitions, defaults, descriptions, comments,
|
|
12
|
+
# the declared routing `version:` — is excluded, so editing behavior
|
|
13
|
+
# never bumps an era and editing shape always does.
|
|
14
|
+
#
|
|
15
|
+
# Three attribute facts on the wire are constraints on PERSISTED
|
|
16
|
+
# VALUES, not behavior, and are still excluded — each decided, not
|
|
17
|
+
# overlooked:
|
|
18
|
+
#
|
|
19
|
+
# `optional` — required-ness is enforced at dispatch; stored rows
|
|
20
|
+
# are never re-validated on read, so flipping it
|
|
21
|
+
# strands nothing already written. Excluded.
|
|
22
|
+
# `pattern` — same argument: a fact about what may be WRITTEN
|
|
23
|
+
# next, not about what was stored. Excluded.
|
|
24
|
+
# `admits` — the sharpest of the three: narrowing a closed set
|
|
25
|
+
# CAN strand stored rows outside it, and the wire
|
|
26
|
+
# carries only the set's NAME, so a set whose members
|
|
27
|
+
# changed under a stable name is invisible even to a
|
|
28
|
+
# projection that included the fact (the same lesson
|
|
29
|
+
# recursive value-object drift taught). Excluded, and
|
|
30
|
+
# NAMED as a gap: constraint tightening has no
|
|
31
|
+
# translation-rule vocabulary to acknowledge it yet,
|
|
32
|
+
# so including it would mint era bumps nothing can
|
|
33
|
+
# explain. When the translation language grows a
|
|
34
|
+
# constraint-acknowledgment rule, `admits` (by member
|
|
35
|
+
# list, not by name) is first in line, and that
|
|
36
|
+
# change bumps FORM_VERSION.
|
|
37
|
+
#
|
|
38
|
+
# Projection runs over the canonical dump form (`to_h`, JSON
|
|
39
|
+
# round-tripped), so a verdict depends only on the IR — never on live
|
|
40
|
+
# object graphs. Structural comparison only, never a hash comparison.
|
|
41
|
+
module StorageShape
|
|
42
|
+
module_function
|
|
43
|
+
|
|
44
|
+
def project(bluebook)
|
|
45
|
+
domain = JSON.parse(JSON.generate(bluebook.to_h))
|
|
46
|
+
{
|
|
47
|
+
"name" => bluebook.name,
|
|
48
|
+
"aggregates" => (domain["aggregates"] || [])
|
|
49
|
+
.map { |aggregate| project_aggregate(aggregate) }
|
|
50
|
+
.sort_by { |aggregate| aggregate["name"] }
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def same?(held, current) = project(held) == project(current)
|
|
55
|
+
|
|
56
|
+
# The canonical serialization the Ruby scaffold hashes at MINT time
|
|
57
|
+
# — the one moment identity is computed. Nothing ever recomputes a
|
|
58
|
+
# stored era name to verify it, so this form can evolve freely.
|
|
59
|
+
def canonical(bluebook) = JSON.generate(project(bluebook))
|
|
60
|
+
|
|
61
|
+
def mint_hash(bluebook) = Digest::SHA256.hexdigest(canonical(bluebook))
|
|
62
|
+
|
|
63
|
+
LABEL_LENGTH = 6
|
|
64
|
+
def mint_label(bluebook) = mint_hash(bluebook)[0, LABEL_LENGTH]
|
|
65
|
+
|
|
66
|
+
# The version of the canonical serialization above. Minted-once
|
|
67
|
+
# means a stored name stays valid across form changes — but only
|
|
68
|
+
# if each name records WHICH form minted it, so v1-named and
|
|
69
|
+
# v2-named eras coexist legibly. Stored beside every minted hash
|
|
70
|
+
# (names.tsv fourth field / hecks_eras.canon_form); bump this in
|
|
71
|
+
# the same change that alters project/canonical output.
|
|
72
|
+
FORM_VERSION = 1
|
|
73
|
+
|
|
74
|
+
def project_aggregate(aggregate)
|
|
75
|
+
{
|
|
76
|
+
"name" => aggregate["name"],
|
|
77
|
+
# The declared identity paths, AS A LIST, in declaration order —
|
|
78
|
+
# order is semantic (the paths join in order to form the id).
|
|
79
|
+
# No "id" fallback: an aggregate that declares nothing has [],
|
|
80
|
+
# and that is a real declared state, distinct from an aggregate
|
|
81
|
+
# identified by a field named "id".
|
|
82
|
+
"identity" => Array(aggregate["identified_by"]).map(&:to_s),
|
|
83
|
+
"lifecycle_field" => aggregate.dig("lifecycle", "field"),
|
|
84
|
+
"attributes" => (aggregate["attributes"] || [])
|
|
85
|
+
.map { |attribute| project_attribute(aggregate, attribute, []) }
|
|
86
|
+
.sort_by { |attribute| attribute["name"] }
|
|
87
|
+
}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def project_attribute(aggregate, attribute, seen)
|
|
91
|
+
{
|
|
92
|
+
"name" => attribute["name"].to_s,
|
|
93
|
+
"list" => attribute["list"] ? true : false,
|
|
94
|
+
"type" => type_signature(aggregate, attribute["type"].to_s, seen)
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# A plain type name for a primitive; the type name plus its
|
|
99
|
+
# members' full signatures for a value object or entity — so two
|
|
100
|
+
# attributes with the same declared type name but different
|
|
101
|
+
# internals are never mistaken for unchanged.
|
|
102
|
+
def type_signature(aggregate, type_name, seen)
|
|
103
|
+
container = nested_type(aggregate, type_name)
|
|
104
|
+
return type_name if container.nil? || seen.include?(type_name)
|
|
105
|
+
|
|
106
|
+
{
|
|
107
|
+
"type" => type_name,
|
|
108
|
+
"members" => (container["attributes"] || [])
|
|
109
|
+
.map { |member| project_attribute(aggregate, member, seen + [type_name]) }
|
|
110
|
+
.sort_by { |member| member["name"] }
|
|
111
|
+
}
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def nested_type(aggregate, type_name)
|
|
115
|
+
(aggregate["value_objects"] || []).find { |vo| vo["name"] == type_name } ||
|
|
116
|
+
(aggregate["entities"] || []).find { |entity| entity["name"] == type_name }
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require_relative "../ports/persistence/binding_policy"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Runtime
|
|
5
|
+
# The capability idiom for MULTI-TENANT hosting — mirrors EraCheck's
|
|
6
|
+
# own `lineage_capable?`, one level over. An adapter answers
|
|
7
|
+
# `tenant_capable?` with true when its OWN instances genuinely
|
|
8
|
+
# isolate one boot's data from another's, given each tenant is its
|
|
9
|
+
# own separate `Runtime.boot` call (its own Registry, its own
|
|
10
|
+
# Dispatcher, its own adapter instances) rather than one shared
|
|
11
|
+
# process switching connections mid-dispatch.
|
|
12
|
+
#
|
|
13
|
+
# THAT LAST PART IS THE FINDING THIS MODULE ENCODES. The project
|
|
14
|
+
# register (Bluebook::ProjectRegister) already resolves an address's
|
|
15
|
+
# REALM to a DISPATCHER at registration time — Router#resolve looks
|
|
16
|
+
# the FQN up in one flat table keyed by realm::domain::aggregate.verb,
|
|
17
|
+
# and each entry already carries its OWN dispatcher from its OWN
|
|
18
|
+
# boot. So "which tenant" is decided ONCE, at boot/registration time
|
|
19
|
+
# (which of possibly many boots of the same directory a request's
|
|
20
|
+
# realm resolves to), never per-dispatch inside a shared registry.
|
|
21
|
+
# No ambient thread-local "current tenant" is needed, and no
|
|
22
|
+
# connection cache is needed beyond what booting-once-per-tenant
|
|
23
|
+
# already gives for free — each tenant's own PostgresEra instance
|
|
24
|
+
# IS its own connection, held for the life of that boot.
|
|
25
|
+
#
|
|
26
|
+
# So `tenant_capable?` asks a narrower question than it might sound:
|
|
27
|
+
# not "can this adapter switch tenants," but "does booting this
|
|
28
|
+
# adapter twice, with different settings, for the same directory,
|
|
29
|
+
# actually keep the two boots' data apart." Memory answers true
|
|
30
|
+
# trivially — a `@records` Hash is a plain instance variable, and
|
|
31
|
+
# two `Runtime.boot` calls build two entirely separate Registry
|
|
32
|
+
# objects, so two Memory adapter instances never share state by
|
|
33
|
+
# construction. PostgresEra answers true because its own `schema:`
|
|
34
|
+
# setting (already built, already the Storehouse mechanism) puts
|
|
35
|
+
# each boot's tables in their own Postgres schema via `SET
|
|
36
|
+
# search_path` — proven for real, not assumed, by
|
|
37
|
+
# tenant_isolation_spec.rb. Plain Postgres (no schema story) and D1
|
|
38
|
+
# (no schema-equivalent at all — see world.bluebook's own comment on
|
|
39
|
+
# the lifeadelics D1 tradeoff) answer false, or don't answer at all,
|
|
40
|
+
# which this module treats identically to false.
|
|
41
|
+
module TenantCheck
|
|
42
|
+
module_function
|
|
43
|
+
|
|
44
|
+
# A domain is safe to boot for MORE THAN ONE TENANT only if every
|
|
45
|
+
# aggregate's resolved persistence adapter is tenant_capable? — one
|
|
46
|
+
# ungoverned adapter sharing state across two tenant boots is a
|
|
47
|
+
# real data leak, not a theoretical one, so this is checked before
|
|
48
|
+
# a second tenant boot of the same directory is trusted, the same
|
|
49
|
+
# severity EraCheck/refuse_ungoverned_roles! already hold their
|
|
50
|
+
# own gates to.
|
|
51
|
+
def refuse_unless_tenant_capable!(registry, domain)
|
|
52
|
+
bluebook = registry.bluebook(domain)
|
|
53
|
+
return unless bluebook
|
|
54
|
+
|
|
55
|
+
offender = bluebook.aggregates.find do |aggregate|
|
|
56
|
+
adapter_name = Ports::Persistence::BindingPolicy.resolve(registry, domain, aggregate).adapter
|
|
57
|
+
!tenant_capable?(registry, adapter_name)
|
|
58
|
+
end
|
|
59
|
+
return unless offender
|
|
60
|
+
|
|
61
|
+
adapter_name = Ports::Persistence::BindingPolicy.resolve(registry, domain, offender).adapter
|
|
62
|
+
raise WiringError,
|
|
63
|
+
"#{domain}::#{offender.hecks_name} is bound to #{adapter_name}, which is not " \
|
|
64
|
+
"tenant_capable? — booting #{domain} for more than one tenant would share " \
|
|
65
|
+
"#{adapter_name}'s own storage across tenants that must never see each other's data. " \
|
|
66
|
+
"Bind a tenant-capable adapter (Memory, PostgresEra with its own schema: per tenant), " \
|
|
67
|
+
"or keep #{domain} single-tenant."
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# The capability idiom itself — an adapter CLASS that answers
|
|
71
|
+
# tenant_capable? with true keeps two boots' data apart by
|
|
72
|
+
# construction (Memory) or by an explicit per-boot isolation
|
|
73
|
+
# setting (PostgresEra's schema:). Same defensive shape
|
|
74
|
+
# EraCheck#lineage_capable? already uses: a class that doesn't
|
|
75
|
+
# respond at all is false, not an error.
|
|
76
|
+
def tenant_capable?(registry, adapter_name)
|
|
77
|
+
adapter_class = registry.adapters[adapter_name] && registry.adapter_class(adapter_name)
|
|
78
|
+
adapter_class.respond_to?(:tenant_capable?) && adapter_class.tenant_capable?
|
|
79
|
+
rescue StandardError
|
|
80
|
+
false
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require "delegate"
|
|
2
|
+
require_relative "errors"
|
|
3
|
+
require_relative "refusal_wording"
|
|
4
|
+
require_relative "../query_specification/common/where_clause"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module Runtime
|
|
8
|
+
# `authorize policy, tenant: :field` declared a tenant boundary that
|
|
9
|
+
# nothing enforced — the policy name and the field were stored and read
|
|
10
|
+
# by nothing at dispatch time. This is the half that CAN be enforced
|
|
11
|
+
# without a caller-identity/session system: the boundary itself, made
|
|
12
|
+
# mandatory. Whether THIS caller actually holds `policy` for THIS
|
|
13
|
+
# tenant needs real identity infrastructure this runtime does not have
|
|
14
|
+
# — that stays a named, open gap, not something this quietly pretends
|
|
15
|
+
# to answer.
|
|
16
|
+
#
|
|
17
|
+
# Enforcement is a synthetic `eq` where-clause, symbol-valued exactly
|
|
18
|
+
# the way a dynamic `where(field: :arg_name)` already resolves against
|
|
19
|
+
# args in every engine (QueryInterpreter#interpret,
|
|
20
|
+
# Ports::Query::InMemory, both SQL adapters via SqlQueryBuilder) — so
|
|
21
|
+
# every engine that already reads `.wheres` enforces the boundary for
|
|
22
|
+
# free, with no per-engine code and no way for one engine to forget it.
|
|
23
|
+
# `Scoped` is handed only to those engines as their `declared`/
|
|
24
|
+
# `specification` argument — never returned to a caller that might call
|
|
25
|
+
# an IR-level method (`filtered_head_name`, `to_h`, …) whose OWN
|
|
26
|
+
# internal `wheres` call would resolve against the original object, not
|
|
27
|
+
# this override, since `SimpleDelegator` only intercepts calls made
|
|
28
|
+
# directly on the wrapper.
|
|
29
|
+
module TenantScope
|
|
30
|
+
module_function
|
|
31
|
+
|
|
32
|
+
def apply(declared, args)
|
|
33
|
+
tenant = declared.authorization&.tenant
|
|
34
|
+
return declared unless tenant
|
|
35
|
+
|
|
36
|
+
tenant = tenant.to_sym
|
|
37
|
+
unless args.key?(tenant)
|
|
38
|
+
raise Unauthorized, RefusalWording.render("Unauthorized", "tenant_required",
|
|
39
|
+
query: declared.name, field: tenant)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
Scoped.new(declared, QuerySpecification::Common::WhereClause.new(field: tenant, op: "eq", value: tenant))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Scoped < SimpleDelegator
|
|
46
|
+
def initialize(declared, clause)
|
|
47
|
+
super(declared)
|
|
48
|
+
@clause = clause
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def wheres = __getobj__.wheres + [@clause]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
require_relative "invariant_violation"
|
|
2
|
+
require_relative "../refusal_wording"
|
|
3
|
+
|
|
4
|
+
module Hecks
|
|
5
|
+
module Runtime
|
|
6
|
+
class Value
|
|
7
|
+
# Closed sets — `one_of` members and `admits:` declarations — and the
|
|
8
|
+
# refusals that make them rules rather than decoration. Extended into
|
|
9
|
+
# Value beside Coercion; `self` is the Value class.
|
|
10
|
+
module Admission
|
|
11
|
+
def admit_member(value_object, fields)
|
|
12
|
+
return if value_object.members.empty?
|
|
13
|
+
|
|
14
|
+
discriminant = value_object.attributes.first.name
|
|
15
|
+
offered = fields[discriminant]
|
|
16
|
+
admitted = value_object.members.map { |member| member[discriminant].to_s }
|
|
17
|
+
return if admitted.include?(offered.to_s)
|
|
18
|
+
|
|
19
|
+
raise InvariantViolation,
|
|
20
|
+
RefusalWording.render("InvariantViolation", "closed_set_member",
|
|
21
|
+
type: value_object.hecks_name,
|
|
22
|
+
admitted: admitted.map(&:inspect).join(", "), offered: offered.inspect)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# THE SAME REFUSAL, FOR A SET NAMED SOMEWHERE ELSE.
|
|
26
|
+
#
|
|
27
|
+
# `admit_member` above refuses a non-member when the value object BEING
|
|
28
|
+
# BUILT is itself the closed set — which is the only shape `one_of` can
|
|
29
|
+
# make, because it SYNTHESISES the set from the values written inline. An
|
|
30
|
+
# `admits:` attribute is the other direction: the value is an ordinary
|
|
31
|
+
# String or a plain text holder, and the set it must belong to was
|
|
32
|
+
# declared once, elsewhere, and is named rather than restated.
|
|
33
|
+
#
|
|
34
|
+
# Without this the word was a DECLARATION and nothing more — read by
|
|
35
|
+
# projections, read by nobody at the door. A rule
|
|
36
|
+
# that cannot be the one to refuse is decoration, and this language has
|
|
37
|
+
# paid for that mistake before.
|
|
38
|
+
def admit_declared_set(owner, attribute, value)
|
|
39
|
+
return value if attribute.nil? || attribute.admits.nil? || value.nil?
|
|
40
|
+
|
|
41
|
+
admitted = admitted_members(owner, attribute)
|
|
42
|
+
offered = admitted_scalar(value)
|
|
43
|
+
return value if admitted.include?(offered.to_s)
|
|
44
|
+
|
|
45
|
+
raise InvariantViolation,
|
|
46
|
+
RefusalWording.render("InvariantViolation", "admits_declared_set",
|
|
47
|
+
name: attribute.name, admits: attribute.admits,
|
|
48
|
+
admitted: admitted.map(&:inspect).join(", "), offered: offered.inspect)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# `Vocabulary::MutationOp` — the aggregate that HOLDS the set, then the
|
|
52
|
+
# set. Qualified because a closed set is a value object INSIDE an
|
|
53
|
+
# aggregate, which is exactly why `admits` could not be spelled as a
|
|
54
|
+
# reference: `reference_to` reaches aggregate heads and nothing below one.
|
|
55
|
+
#
|
|
56
|
+
# RESOLVED LATE, like `Reference#resolve` and for the same reason — the
|
|
57
|
+
# set may be declared further down the file than the attribute that names
|
|
58
|
+
# it. And REFUSED when it resolves to nothing, also like `Reference`: a
|
|
59
|
+
# link checked against nothing is worse than no link, because it reads
|
|
60
|
+
# like a rule.
|
|
61
|
+
def admitted_members(owner, attribute)
|
|
62
|
+
aggregate_name, set_name = attribute.admits.to_s.split("::", 2)
|
|
63
|
+
chapter = chapter_of(owner)
|
|
64
|
+
set = set_name && chapter&.aggregate(aggregate_name)&.value_object(set_name)
|
|
65
|
+
|
|
66
|
+
unless set
|
|
67
|
+
raise InvariantViolation,
|
|
68
|
+
RefusalWording.render("InvariantViolation", "undeclared_set",
|
|
69
|
+
name: attribute.name, admits: attribute.admits)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
discriminant = set.attributes.first.name
|
|
73
|
+
set.members.map { |member| member.to_h[discriminant].to_s }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# UP TO THE CHAPTER, from wherever the attribute was declared. A value
|
|
77
|
+
# object's owner is its aggregate and an aggregate's owner is its chapter,
|
|
78
|
+
# so the walk stops at the first construct that can answer for an
|
|
79
|
+
# aggregate BY NAME — which is the chapter, and only the chapter.
|
|
80
|
+
def chapter_of(construct)
|
|
81
|
+
node = construct
|
|
82
|
+
node = node.hecks_owner while node && !node.respond_to?(:aggregate) && node.respond_to?(:hecks_owner)
|
|
83
|
+
node.respond_to?(:aggregate) ? node : nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# An admitted value is a SCALAR however it arrived — as a bare string on a
|
|
87
|
+
# plain field, or wrapped in the one-field holder its type names.
|
|
88
|
+
def admitted_scalar(value)
|
|
89
|
+
return value unless value.is_a?(self)
|
|
90
|
+
|
|
91
|
+
fields = value.to_h
|
|
92
|
+
fields.size == 1 ? fields.values.first : value
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# A FIELD OF A VALUE OBJECT MAY NAME A SET TOO.
|
|
96
|
+
#
|
|
97
|
+
# Beside check_patterns and for the same reason: `Query::Filter.op` is a
|
|
98
|
+
# plain String field that admits `Vocabulary::QueryComparator`, and the
|
|
99
|
+
# value object is what gets built — no attribute passes through
|
|
100
|
+
# `for_attribute` on the way. Both doors, or the word means one thing on
|
|
101
|
+
# an argument and nothing on a field.
|
|
102
|
+
private def check_admitted(value_object, fields)
|
|
103
|
+
value_object.attributes.each do |attribute|
|
|
104
|
+
next unless attribute.admits
|
|
105
|
+
|
|
106
|
+
admit_declared_set(value_object, attribute, fields[attribute.name])
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|