hecks 3.13.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/examples/pizzas/adapters/fake_processor.rb +34 -0
- data/examples/pizzas/adapters/payment_signature.rb +66 -0
- data/examples/pizzas/adapters/payment_webhook.rb +87 -0
- data/examples/pizzas/bluebook/pizzas.behaviors +33 -0
- data/examples/pizzas/bluebook/pizzas.bluebook +4 -4
- data/examples/pizzas/bluebook/pizzas.hecksagon +5 -3
- data/examples/pizzas/config.ru +22 -0
- data/lib/hecks/adapters/driven/prism.rb +0 -2
- data/lib/hecks/adapters/driven.rb +0 -2
- data/lib/hecks/adapters/driving/json.rb +1 -7
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +15 -5
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -2
- data/lib/hecks/bluebook/dsl/derivation_words.rb +58 -0
- data/lib/hecks/bluebook/dsl/translation_builder.rb +6 -37
- data/lib/hecks/bluebook/expression/ast_json.rb +0 -9
- data/lib/hecks/bluebook/hecksagon.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +7 -10
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +4 -8
- data/lib/hecks/bluebook/meta_validator.rb +0 -11
- data/lib/hecks/bluebook/named_pattern.rb +33 -0
- data/lib/hecks/bluebook/translation.rb +18 -10
- data/lib/hecks/bluebook/translation_expression/evaluator.rb +63 -0
- data/lib/hecks/bluebook/translation_expression/parser.rb +127 -0
- data/lib/hecks/bluebook/translation_expression.rb +39 -0
- data/lib/hecks/bluebook/translation_plan.rb +70 -0
- data/lib/hecks/bluebook.rb +3 -0
- data/lib/hecks/chapters.rb +3 -3
- data/lib/hecks/cli/domain_stub.rb +1 -1
- data/lib/hecks/cli/interview_aggregate.rb +4 -4
- data/lib/hecks/composer/adapters/claude_composer.adapter +3 -0
- data/lib/hecks/composer/adapters/claude_composer.rb +83 -0
- data/lib/hecks/composer/adapters/fake_agent.adapter +3 -0
- data/lib/hecks/composer/adapters/fake_agent.rb +55 -0
- data/lib/hecks/composer/adapters/jev.adapter +3 -0
- data/lib/hecks/composer/adapters/jev.rb +66 -0
- data/lib/hecks/composer/agent.rb +113 -0
- data/lib/hecks/composer/assistant.rb +110 -0
- data/lib/hecks/composer/behavior_run.rb +53 -0
- data/lib/hecks/composer/bluebook/composer.bluebook +178 -0
- data/lib/hecks/composer/bluebook/composer.hecksagon +16 -0
- data/lib/hecks/composer/board.rb +65 -0
- data/lib/hecks/composer/board_edit/command_text.rb +39 -0
- data/lib/hecks/composer/board_edit/source.rb +84 -0
- data/lib/hecks/composer/board_edit.rb +144 -0
- data/lib/hecks/composer/check.rb +89 -0
- data/lib/hecks/composer/domains.rb +81 -0
- data/lib/hecks/composer/jobs.rb +134 -0
- data/lib/hecks/composer/layout.rb +37 -0
- data/lib/hecks/composer/live.rb +150 -0
- data/lib/hecks/composer/outline.rb +48 -0
- data/lib/hecks/composer/page.html +989 -0
- data/lib/hecks/composer/panels.rb +142 -0
- data/lib/hecks/composer/parse.rb +83 -0
- data/lib/hecks/composer/plain.rb +28 -0
- data/lib/hecks/composer/ports/composer_agent.port +7 -0
- data/lib/hecks/composer/session.rb +141 -0
- data/lib/hecks/composer/toolbox.rb +166 -0
- data/lib/hecks/composer/web.rb +156 -0
- data/lib/hecks/composer/workbench.rb +51 -0
- data/lib/hecks/composer/workspace.rb +81 -0
- data/lib/hecks/composer.rb +17 -0
- data/lib/hecks/corpus/adapters.rb +22 -0
- data/lib/hecks/corpus/rust.rb +1 -1
- data/lib/hecks/corpus/worlds.rb +19 -0
- data/lib/hecks/corpus.rb +5 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -34
- data/lib/hecks/forms/app/commands.rb +2 -3
- data/lib/hecks/forms/app/queries.rb +2 -3
- data/lib/hecks/forms/app/records.rb +17 -5
- data/lib/hecks/forms/command_form_renderer.rb +42 -16
- data/lib/hecks/forms/field_controls.rb +2 -2
- data/lib/hecks/forms/field_renderer.rb +1 -1
- data/lib/hecks/forms/field_shape.rb +36 -17
- data/lib/hecks/forms/index_renderer.rb +2 -1
- data/lib/hecks/forms/page.rb +1 -1
- data/lib/hecks/forms/params.rb +0 -13
- data/lib/hecks/forms/query_form_renderer.rb +7 -6
- data/lib/hecks/forms/record_renderer.rb +11 -7
- data/lib/hecks/forms/rule_words.rb +100 -0
- data/lib/hecks/forms/value_object_shape.rb +2 -1
- data/lib/hecks/framework/bluebook/change.bluebook +2 -2
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -3
- data/lib/hecks/fuzzing/domain_generator/block_rendering.rb +1 -1
- data/lib/hecks/fuzzing/isolated_boot/worlds.rb +3 -6
- data/lib/hecks/fuzzing/replay/filters.rb +2 -6
- data/lib/hecks/gate/stages.yml +25 -0
- data/lib/hecks/grammar/evolve/seeds.rb +0 -6
- data/lib/hecks/grammar/evolve.rb +0 -3
- data/lib/hecks/grammar/translation.bluebook +1 -1
- data/lib/hecks/hecks/adapters/codebase/composing.rb +56 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +3 -1
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +0 -26
- data/lib/hecks/hecks/adapters/journal_store/examination.rb +2 -23
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +3 -11
- data/lib/hecks/hecks/adapters/journal_store.rb +0 -11
- data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +4 -11
- data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +0 -9
- data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +0 -4
- data/lib/hecks/hecks/codebase.behaviors +6 -0
- data/lib/hecks/hecks/codebase.bluebook +58 -37
- data/lib/hecks/hecks/composer.behaviors +68 -0
- data/lib/hecks/hecks/context_map.hecksagon +1 -1
- data/lib/hecks/hecks/custodian.behaviors +0 -6
- data/lib/hecks/hecks/custodian.bluebook +15 -92
- data/lib/hecks/hecks/hecks.bluebook +2 -2
- data/lib/hecks/hecks/hecks.hecksagon +2 -2
- data/lib/hecks/hecks/hecks.world +1 -1
- data/lib/hecks/hecks/rehearsal.bluebook +10 -16
- data/lib/hecks/hecks/tooling.bluebook +22 -22
- data/lib/hecks/kernel_capabilities/templates.rb +4 -4
- data/lib/hecks/kernel_capabilities.rb +1 -1
- data/lib/hecks/language/bluebook/aggregate.bluebook +1 -0
- data/lib/hecks/language/bluebook/command.bluebook +1 -0
- data/lib/hecks/language/bluebook/entity.bluebook +1 -0
- data/lib/hecks/language/bluebook/query.bluebook +1 -0
- data/lib/hecks/language/bluebook/shape.bluebook +8 -7
- data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -3
- data/lib/hecks/language/hecksagon/port_operation.bluebook +1 -0
- data/lib/hecks/language/translation/translation_aggregate.bluebook +21 -24
- data/lib/hecks/ports/access_control.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +3 -41
- data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +7 -7
- data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +4 -4
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +17 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +0 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -22
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +0 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +3 -29
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +2 -26
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +6 -33
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +2 -4
- data/lib/hecks/ports/persistence/plugins/era/translation/expression_sql.rb +52 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +23 -29
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +0 -1
- data/lib/hecks/ports/persistence/plugins/era.rb +3 -6
- data/lib/hecks/ports.rb +0 -1
- data/lib/hecks/projection_files.rb +3 -1
- data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +1 -1
- data/lib/hecks/projections/glossary/entries.rb +10 -4
- data/lib/hecks/projections/glossary/groups.rb +42 -0
- data/lib/hecks/projections/glossary/html/page.rb +7 -2
- data/lib/hecks/projections/glossary/html/parser.rb +1 -1
- data/lib/hecks/projections/glossary/html/sections.rb +31 -11
- data/lib/hecks/projections/glossary/html.rb +1 -2
- data/lib/hecks/projections/glossary/markdown.rb +31 -28
- data/lib/hecks/projections/glossary/mermaid.rb +3 -0
- data/lib/hecks/projections/glossary/page.css +143 -153
- data/lib/hecks/projections/glossary/page.js +63 -3
- data/lib/hecks/projections/glossary/sentences/actions.rb +88 -0
- data/lib/hecks/projections/glossary/sentences/paths.rb +77 -0
- data/lib/hecks/projections/glossary/sentences/queries.rb +90 -0
- data/lib/hecks/projections/glossary/sentences/value_objects.rb +32 -5
- data/lib/hecks/projections/glossary/sentences.rb +13 -3
- data/lib/hecks/projections/glossary/slugs.rb +4 -1
- data/lib/hecks/projections/glossary.rb +2 -1
- data/lib/hecks/projections/plain_english.rb +97 -0
- data/lib/hecks/projections/rust_vocabulary/arguments.rb +2 -2
- data/lib/hecks/projections/rust_vocabulary/enum_body.rb +20 -25
- data/lib/hecks/projections/rust_vocabulary/tests.rb +2 -2
- data/lib/hecks/projections/rust_vocabulary.rb +14 -6
- data/lib/hecks/projections/site/cms_editor/color.rb +0 -6
- data/lib/hecks/projections/statements/actions.rb +99 -0
- data/lib/hecks/projections/statements/relationships.rb +86 -0
- data/lib/hecks/projections/statements.rb +15 -24
- data/lib/hecks/projector/exporter/adapters.rb +112 -0
- data/lib/hecks/projector/exporter/translations.rb +18 -35
- data/lib/hecks/projector/exporter/worlds.rb +103 -0
- data/lib/hecks/projector/exporter.rb +5 -1
- data/lib/hecks/quality_control/adapters/agent.rb +6 -7
- data/lib/hecks/quality_control/adapters/agent_profile.rb +16 -114
- data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +1 -1
- data/lib/hecks/quality_control/quality_control.bluebook +51 -51
- data/lib/hecks/runtime/loader/boot_steps.rb +0 -20
- data/lib/hecks/runtime/outbox.rb +2 -9
- data/lib/hecks/runtime/port_operation_interpreter.rb +1 -9
- data/lib/hecks/runtime/remote_dispatcher.rb +2 -2
- data/lib/hecks/runtime/value.rb +13 -0
- data/lib/hecks/rust_build/project_rust/target_ir.rb +23 -4
- data/lib/hecks/rust_build/wasm.rb +0 -12
- data/lib/hecks/rust_build/write_if_changed.rb +12 -12
- data/lib/hecks/rust_format.rb +77 -0
- data/lib/hecks/site/bluebook/site.bluebook +5 -5
- data/lib/hecks/sme/bluebook/sme.bluebook +12 -12
- data/lib/hecks/tickets/bluebook/tickets.bluebook +3 -3
- data/lib/hecks/tools/fuzz_sweep/findings.rb +3 -9
- data/lib/hecks/tools/fuzz_sweep.rb +1 -3
- data/lib/hecks/tools/translation_audit/verdicts.rb +3 -28
- data/lib/hecks/tools/translation_audit.rb +8 -10
- data/lib/hecks/tools/translation_scaffold/reporting.rb +1 -1
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +2 -1
- data/lib/hecks.rb +3 -0
- data/prebuilt/{58208399bada10b0db99928c48e38789288fc58f7b71a72b21bfa386680e32ed.marshal → 02c09c73b272c1fb5a9ae6d87bb5e5e529208e00f6b4b597dc2c0fd70a9c0964.marshal} +0 -0
- data/prebuilt/{2b59737fbdbd5f44edda0fddce2611f45d76087b3a7c782d1f1a17ea58c77948.marshal → bb84a835cf6a15136bad5ca03aa5bf93a5b92f5f72444618d3ef2412b987fb32.marshal} +0 -0
- data/prebuilt/verdicts-f1f10da14c8e8f01b4c9b7e3e2d74be8cd2bf4676364ed17fa16975d2a076d75.json +1 -0
- data/rust/Cargo.toml +40 -0
- data/rust/build/Cargo.toml +36 -0
- data/rust/build/clippy.toml +4 -0
- data/rust/build/src/adapters_pass.rs +196 -0
- data/rust/build/src/binding_pass.rs +54 -13
- data/rust/build/src/build_artifact.rs +23 -5
- data/rust/build/src/cargo_sync.rs +69 -26
- data/rust/build/src/lineage_pass.rs +101 -87
- data/rust/build/src/main.rs +11 -2
- data/rust/build/src/pipeline.rs +80 -19
- data/rust/build/src/reserved_names.rs +6 -50
- data/rust/build/src/resolve.rs +82 -35
- data/rust/build/src/rustfmt.rs +100 -0
- data/rust/build/src/seams_pass.rs +85 -16
- data/rust/build/src/subprocess.rs +30 -6
- data/rust/build/src/tmp.rs +5 -2
- data/rust/build/src/translation_pass.rs +72 -22
- data/rust/build/src/world_pass.rs +109 -0
- data/rust/clippy.toml +4 -0
- data/rust/codegen/Cargo.toml +36 -0
- data/rust/codegen/clippy.toml +4 -0
- data/rust/codegen/src/asks.rs +40 -14
- data/rust/codegen/src/attr.rs +2 -2
- data/rust/codegen/src/bridging.rs +676 -117
- data/rust/codegen/src/commands.rs +979 -373
- data/rust/codegen/src/constraints.rs +88 -25
- data/rust/codegen/src/dependency_planning.rs +128 -34
- data/rust/codegen/src/domain_generator.rs +300 -170
- data/rust/codegen/src/exemplar.rs +87 -32
- data/rust/codegen/src/expr_emitter.rs +54 -6
- data/rust/codegen/src/fielded.rs +193 -41
- data/rust/codegen/src/hecks_naming.rs +124 -16
- data/rust/codegen/src/hecks_naming_tests.rs +81 -0
- data/rust/codegen/src/json.rs +80 -44
- data/rust/codegen/src/json_codec.rs +585 -149
- data/rust/codegen/src/literal.rs +104 -138
- data/rust/codegen/src/main.rs +145 -52
- data/rust/codegen/src/manifest.rs +76 -14
- data/rust/codegen/src/mutations.rs +1212 -239
- data/rust/codegen/src/naming.rs +111 -60
- data/rust/codegen/src/optional_pass.rs +90 -28
- data/rust/codegen/src/ports.rs +5 -4
- data/rust/codegen/src/prelude.rs +139 -49
- data/rust/codegen/src/queries.rs +601 -226
- data/rust/codegen/src/reactions.rs +268 -74
- data/rust/codegen/src/read_models.rs +606 -205
- data/rust/codegen/src/reference_specs.rs +16 -3
- data/rust/codegen/src/registry.rs +128 -79
- data/rust/codegen/src/reserved_names.rs +6 -50
- data/rust/codegen/src/shared.rs +71 -22
- data/rust/codegen/src/sidecars.rs +15 -5
- data/rust/codegen/src/skip_reason.rs +8 -2
- data/rust/codegen/src/types.rs +306 -108
- data/rust/host/Cargo.lock +1 -0
- data/rust/host/Cargo.toml +40 -4
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/clippy.toml +4 -0
- data/rust/host/src/api.rs +698 -218
- data/rust/host/src/auth.rs +491 -214
- data/rust/host/src/b64.rs +91 -0
- data/rust/host/src/bin/expr_harness.rs +6 -2
- data/rust/host/src/bin/lineage_harness.rs +47 -11
- data/rust/host/src/bin/mint_harness.rs +70 -37
- data/rust/host/src/bin/validate_harness.rs +16 -8
- data/rust/host/src/boot.rs +144 -68
- data/rust/host/src/boundary_fuzz/api.rs +130 -32
- data/rust/host/src/boundary_fuzz/auth.rs +108 -23
- data/rust/host/src/boundary_fuzz/expr_json.rs +85 -11
- data/rust/host/src/boundary_fuzz/ir.rs +164 -12
- data/rust/host/src/boundary_fuzz/server.rs +283 -36
- data/rust/host/src/boundary_fuzz/web.rs +56 -8
- data/rust/host/src/checkout.rs +78 -32
- data/rust/host/src/clock.rs +8 -0
- data/rust/host/src/commerce_ir.rs +333 -95
- data/rust/host/src/crypto.rs +33 -0
- data/rust/host/src/dispatch.rs +990 -331
- data/rust/host/src/expr_json.rs +1021 -273
- data/rust/host/src/extension.rs +24 -4
- data/rust/host/src/field_hints.rs +11 -7
- data/rust/host/src/fuzz_support.rs +85 -13
- data/rust/host/src/host.rs +100 -0
- data/rust/host/src/http.rs +22 -0
- data/rust/host/src/ir.rs +326 -16
- data/rust/host/src/journal.rs +277 -176
- data/rust/host/src/lambda_client.rs +219 -53
- data/rust/host/src/lib.rs +16 -4
- data/rust/host/src/log.rs +62 -11
- data/rust/host/src/mint.rs +1153 -326
- data/rust/host/src/needs.rs +185 -44
- data/rust/host/src/payments/keystore.rs +197 -45
- data/rust/host/src/payments/roles.rs +191 -0
- data/rust/host/src/payments/tests.rs +1445 -275
- data/rust/host/src/payments.rs +409 -121
- data/rust/host/src/platform_signin/attack_tests.rs +5 -5
- data/rust/host/src/platform_signin/config.rs +11 -11
- data/rust/host/src/platform_signin/cookie.rs +2 -2
- data/rust/host/src/platform_signin/extension.rs +2 -1
- data/rust/host/src/platform_signin/handler.rs +9 -8
- data/rust/host/src/platform_signin/jti.rs +4 -2
- data/rust/host/src/platform_signin/jwks.rs +2 -1
- data/rust/host/src/platform_signin/jws.rs +2 -37
- data/rust/host/src/platform_signin/known_answer_tests.rs +5 -1
- data/rust/host/src/platform_signin/mode_tests.rs +5 -3
- data/rust/host/src/platform_signin/pages.rs +20 -20
- data/rust/host/src/platform_signin/session.rs +8 -1
- data/rust/host/src/platform_signin/settings.rs +6 -6
- data/rust/host/src/platform_signin/strict_json.rs +12 -9
- data/rust/host/src/platform_signin/verify.rs +41 -41
- data/rust/host/src/platform_signin/wiring_support.rs +13 -18
- data/rust/host/src/presentation.rs +207 -63
- data/rust/host/src/presentation_write.rs +502 -187
- data/rust/host/src/query_step.rs +69 -18
- data/rust/host/src/rate_limit.rs +541 -142
- data/rust/host/src/reference_transform.rs +77 -25
- data/rust/host/src/reference_validate.rs +443 -104
- data/rust/host/src/resend.rs +190 -55
- data/rust/host/src/secrets.rs +116 -21
- data/rust/host/src/server.rs +483 -104
- data/rust/host/src/storage_shape.rs +88 -21
- data/rust/host/src/test_pg.rs +17 -7
- data/rust/host/src/ui_schema.rs +495 -207
- data/rust/host/src/wasm_runner.rs +21 -6
- data/rust/host/src/web/commerce.rs +101 -23
- data/rust/host/src/web/newsletter/cooldown.rs +10 -3
- data/rust/host/src/web/newsletter/template.rs +26 -7
- data/rust/host/src/web/newsletter/tests.rs +112 -23
- data/rust/host/src/web/newsletter.rs +209 -59
- data/rust/host/src/web/newsletter_send.rs +251 -79
- data/rust/host/src/web/registration_receipt/tests.rs +16 -4
- data/rust/host/src/web/registration_receipt.rs +100 -24
- data/rust/host/src/web/registrations.rs +1384 -332
- data/rust/host/src/web/resend_webhook.rs +138 -80
- data/rust/host/src/web.rs +2416 -508
- data/rust/lsp/Cargo.toml +36 -0
- data/rust/lsp/clippy.toml +4 -0
- data/rust/lsp/src/json.rs +29 -22
- data/rust/lsp/src/main.rs +81 -31
- data/rust/lsp/src/outline.rs +23 -7
- data/rust/lsp/src/rpc.rs +17 -4
- data/rust/parser/Cargo.toml +36 -0
- data/rust/parser/clippy.toml +4 -0
- data/rust/parser/src/build/closed_sets.rs +6 -1
- data/rust/parser/src/build/identity.rs +4 -3
- data/rust/parser/src/build/mod.rs +1 -0
- data/rust/parser/src/build/named_pattern.rs +26 -0
- data/rust/parser/src/build/naming.rs +2 -80
- data/rust/parser/src/build/pattern_subset.rs +6 -8
- data/rust/parser/src/build/query_derive.rs +3 -1
- data/rust/parser/src/build/query_inference.rs +14 -5
- data/rust/parser/src/build/read_model.rs +4 -1
- data/rust/parser/src/build/references.rs +4 -3
- data/rust/parser/src/canonical.rs +34 -15
- data/rust/parser/src/emit.rs +187 -105
- data/rust/parser/src/expr/ast_json.rs +134 -42
- data/rust/parser/src/expr/evaluator.rs +27 -9
- data/rust/parser/src/expr/mod.rs +54 -13
- data/rust/parser/src/expr/resolver.rs +299 -92
- data/rust/parser/src/ir.rs +35 -3
- data/rust/parser/src/keywords.rs +7168 -510
- data/rust/parser/src/lex.rs +11 -25
- data/rust/parser/src/lib.rs +1 -0
- data/rust/parser/src/main.rs +65 -6
- data/rust/parser/src/parse/adapter.rs +157 -0
- data/rust/parser/src/parse/aggregate.rs +19 -10
- data/rust/parser/src/parse/chapter.rs +16 -17
- data/rust/parser/src/parse/command.rs +35 -16
- data/rust/parser/src/parse/domain_port.rs +4 -7
- data/rust/parser/src/parse/entity.rs +21 -11
- data/rust/parser/src/parse/hecksagon.rs +10 -4
- data/rust/parser/src/parse/lifecycle.rs +9 -5
- data/rust/parser/src/parse/mod.rs +43 -91
- data/rust/parser/src/parse/needs.rs +21 -12
- data/rust/parser/src/parse/policy.rs +2 -2
- data/rust/parser/src/parse/process_manager.rs +9 -11
- data/rust/parser/src/parse/query.rs +8 -4
- data/rust/parser/src/parse/read_model.rs +57 -16
- data/rust/parser/src/parse/value_object.rs +7 -2
- data/rust/parser/src/parse/world.rs +322 -0
- data/rust/parser/src/ruby_value.rs +7 -6
- data/rust/src/exemplar/json.rs +4 -4
- data/rust/src/exemplar/mutations.rs +18 -0
- data/rust/src/exemplar/read_models.rs +1 -10
- data/rust/src/kernel/attribute_shapes/composite.rs +54 -14
- data/rust/src/kernel/attribute_shapes/list.rs +2 -2
- data/rust/src/kernel/attribute_shapes/mod.rs +8 -8
- data/rust/src/kernel/attribute_shapes/scalar.rs +2 -2
- data/rust/src/kernel/cli.rs +229 -112
- data/rust/src/kernel/dispatch.rs +323 -115
- data/rust/src/kernel/dispatch_guard_tests.rs +327 -65
- data/rust/src/kernel/expr.rs +203 -86
- data/rust/src/kernel/expression_operators/arithmetic.rs +138 -25
- data/rust/src/kernel/expression_operators/comparison.rs +87 -2
- data/rust/src/kernel/expression_operators/enumeration.rs +106 -22
- data/rust/src/kernel/expression_operators/logical.rs +9 -3
- data/rust/src/kernel/expression_operators/membership.rs +3 -1
- data/rust/src/kernel/expression_operators/mod.rs +34 -21
- data/rust/src/kernel/expression_operators/pattern_match.rs +46 -11
- data/rust/src/kernel/expression_operators/positional.rs +84 -30
- data/rust/src/kernel/expression_operators/presence.rs +52 -13
- data/rust/src/kernel/expression_operators/sign_test.rs +3 -1
- data/rust/src/kernel/expression_operators/sized.rs +24 -8
- data/rust/src/kernel/expression_operators/text.rs +120 -27
- data/rust/src/kernel/expression_operators/to_string.rs +10 -4
- data/rust/src/kernel/json.rs +230 -148
- data/rust/src/kernel/mod.rs +46 -33
- data/rust/src/kernel/named_query.rs +63 -15
- data/rust/src/kernel/needs.rs +112 -25
- data/rust/src/kernel/orchestrate.rs +980 -581
- data/rust/src/kernel/orchestrate_guard_tests.rs +538 -140
- data/rust/src/kernel/pattern.rs +107 -34
- data/rust/src/kernel/query_comparators.rs +118 -41
- data/rust/src/kernel/query_ordering.rs +13 -5
- data/rust/src/kernel/read_model.rs +479 -181
- data/rust/src/kernel/reference_lookup.rs +122 -26
- data/rust/src/kernel/repository.rs +293 -66
- data/rust/src/kernel/routing.rs +58 -42
- data/rust/src/kernel/ruby_float.rs +139 -0
- data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +57 -57
- data/rust/src/kernel/vocab/entity_dispatch_order.rs +54 -54
- data/rust/src/kernel/vocab/field_hint.rs +19 -25
- data/rust/src/kernel/vocab/mod.rs +6 -6
- data/rust/src/kernel/vocab/query_comparator.rs +23 -24
- data/rust/src/kernel/vocab/refusal_template.rs +501 -297
- data/rust/src/lib.rs +50 -0
- data/rust/src/main.rs +4 -1
- data/rust/web/Cargo.toml +36 -0
- data/rust/web/clippy.toml +4 -0
- metadata +85 -15
- data/examples/pizzas/bluebook/hecksagon/mock_stripe_payment_adapter.rb +0 -36
- data/lib/hecks/adapters/driven/google_authentication.adapter +0 -3
- data/lib/hecks/adapters/driven/google_authentication.rb +0 -99
- data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +0 -3
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +0 -32
- data/lib/hecks/ports/authentication.port +0 -6
- data/lib/hecks/ports/authentication.rb +0 -67
- data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +0 -255
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +0 -22
- data/prebuilt/verdicts-48318ca172edd21443b1ad02801c697fff100b746e828f09db987647641a5df2.json +0 -1
- data/rust/host/src/approval.rs +0 -652
|
@@ -5,37 +5,13 @@ use crate::exemplar::Exemplar;
|
|
|
5
5
|
use crate::json::Json;
|
|
6
6
|
use crate::manifest::{ruby_inspect, Manifest};
|
|
7
7
|
use crate::registry::{
|
|
8
|
-
AggregateEntry, CommandEntry, EntityCommandEntry, EntityIdentityEntry,
|
|
9
|
-
ReferenceCheck, TenantBoundaryCheck,
|
|
8
|
+
AggregateEntry, CommandEntry, EntityCommandEntry, EntityIdentityEntry,
|
|
9
|
+
NestedEntityCommandEntry, PortEntry, ReferenceCheck, TenantBoundaryCheck,
|
|
10
10
|
};
|
|
11
|
+
use crate::shared::{lifecycle_extra_field, puts_blank, puts_str};
|
|
11
12
|
use crate::{commands, json_codec, mutations, ports, queries, reactions, read_models, types};
|
|
12
13
|
use std::collections::HashMap;
|
|
13
14
|
|
|
14
|
-
fn puts_str(out: &mut String, s: &str) {
|
|
15
|
-
out.push_str(s);
|
|
16
|
-
if !s.ends_with('\n') {
|
|
17
|
-
out.push('\n');
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
fn puts_blank(out: &mut String) {
|
|
22
|
-
out.push('\n');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
fn lifecycle_extra_field(node: &Json) -> Vec<(String, String)> {
|
|
26
|
-
match node.get("lifecycle") {
|
|
27
|
-
None => vec![],
|
|
28
|
-
Some(lifecycle) => {
|
|
29
|
-
let field = lifecycle.get("field").and_then(Json::as_str).unwrap_or("");
|
|
30
|
-
let ident = crate::naming::rust_ident_field(field);
|
|
31
|
-
vec![(
|
|
32
|
-
crate::naming::rust_field(field),
|
|
33
|
-
format!("crate::kernel::Json::Str(self.{ident}.clone())"),
|
|
34
|
-
)]
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
15
|
pub struct GeneratedFile {
|
|
40
16
|
pub name: String,
|
|
41
17
|
pub content: String,
|
|
@@ -63,7 +39,7 @@ fn reference_checks(
|
|
|
63
39
|
aggregates_by_name: &HashMap<String, &Json>,
|
|
64
40
|
unsupported_names: &[String],
|
|
65
41
|
) -> Vec<ReferenceCheck> {
|
|
66
|
-
let attrs = command.get("attributes").
|
|
42
|
+
let attrs = command.get("attributes").map_or_default(Json::each);
|
|
67
43
|
attrs
|
|
68
44
|
.iter()
|
|
69
45
|
.filter_map(|attr| {
|
|
@@ -72,7 +48,7 @@ fn reference_checks(
|
|
|
72
48
|
if unsupported_names.iter().any(|n| n == target_name) {
|
|
73
49
|
return None;
|
|
74
50
|
}
|
|
75
|
-
let identified_by = target.get("identified_by").
|
|
51
|
+
let identified_by = target.get("identified_by").map_or_default(Json::each);
|
|
76
52
|
let heads = identified_by
|
|
77
53
|
.iter()
|
|
78
54
|
.map(|p| p.to_s().split('.').next().unwrap_or("").to_string())
|
|
@@ -109,9 +85,9 @@ fn state_reference_checks(
|
|
|
109
85
|
unsupported_names: &[String],
|
|
110
86
|
value_objects_by_name: &HashMap<String, &Json>,
|
|
111
87
|
) -> Vec<ReferenceCheck> {
|
|
112
|
-
let agg_attrs = aggregate.get("attributes").
|
|
113
|
-
let cmd_mutations = command.get("mutations").
|
|
114
|
-
let cmd_attrs = command.get("attributes").
|
|
88
|
+
let agg_attrs = aggregate.get("attributes").map_or_default(Json::each);
|
|
89
|
+
let cmd_mutations = command.get("mutations").map_or_default(Json::each);
|
|
90
|
+
let cmd_attrs = command.get("attributes").map_or_default(Json::each);
|
|
115
91
|
|
|
116
92
|
agg_attrs
|
|
117
93
|
.iter()
|
|
@@ -122,11 +98,21 @@ fn state_reference_checks(
|
|
|
122
98
|
let mutation = cmd_mutations.iter().find(|m| {
|
|
123
99
|
m.get("op").map(Json::to_s).as_deref() == Some("set")
|
|
124
100
|
&& m.get("target").map(Json::to_s).as_deref() == Some(attr_name)
|
|
125
|
-
&& m.get("source")
|
|
101
|
+
&& m.get("source")
|
|
102
|
+
.and_then(|s| s.get("kind"))
|
|
103
|
+
.map(Json::to_s)
|
|
104
|
+
.as_deref()
|
|
105
|
+
== Some("argument")
|
|
126
106
|
})?;
|
|
127
107
|
|
|
128
|
-
let source_name = mutation
|
|
129
|
-
|
|
108
|
+
let source_name = mutation
|
|
109
|
+
.get("source")
|
|
110
|
+
.and_then(|s| s.get("name"))
|
|
111
|
+
.map(Json::to_s)
|
|
112
|
+
.unwrap_or_default();
|
|
113
|
+
let source_attr = cmd_attrs
|
|
114
|
+
.iter()
|
|
115
|
+
.find(|a| crate::attr::name(a) == source_name)?;
|
|
130
116
|
if crate::naming::reference_target(crate::attr::type_name(source_attr)).is_some() {
|
|
131
117
|
return None;
|
|
132
118
|
}
|
|
@@ -147,7 +133,7 @@ fn state_reference_checks(
|
|
|
147
133
|
return None;
|
|
148
134
|
}
|
|
149
135
|
|
|
150
|
-
let identified_by = target.get("identified_by").
|
|
136
|
+
let identified_by = target.get("identified_by").map_or_default(Json::each);
|
|
151
137
|
let heads = identified_by
|
|
152
138
|
.iter()
|
|
153
139
|
.map(|p| p.to_s().split('.').next().unwrap_or("").to_string())
|
|
@@ -178,10 +164,13 @@ fn state_reference_checks(
|
|
|
178
164
|
fn tenant_field_for(aggregate: &Json) -> Option<String> {
|
|
179
165
|
aggregate
|
|
180
166
|
.get("queries")
|
|
181
|
-
.
|
|
182
|
-
.unwrap_or(&[])
|
|
167
|
+
.map_or_default(Json::each)
|
|
183
168
|
.iter()
|
|
184
|
-
.find_map(|q|
|
|
169
|
+
.find_map(|q| {
|
|
170
|
+
q.get("authorization")
|
|
171
|
+
.and_then(|a| a.get("tenant"))
|
|
172
|
+
.map(Json::to_s)
|
|
173
|
+
})
|
|
185
174
|
}
|
|
186
175
|
|
|
187
176
|
/// Write-side tenant boundary checks for a command's references.
|
|
@@ -198,14 +187,22 @@ fn tenant_boundary_checks(
|
|
|
198
187
|
let Some(own_tenant_field) = tenant_field_for(aggregate) else {
|
|
199
188
|
return Vec::new();
|
|
200
189
|
};
|
|
201
|
-
let cmd_attrs = command.get("attributes").
|
|
202
|
-
let Some(own_tenant_attr) = cmd_attrs
|
|
190
|
+
let cmd_attrs = command.get("attributes").map_or_default(Json::each);
|
|
191
|
+
let Some(own_tenant_attr) = cmd_attrs
|
|
192
|
+
.iter()
|
|
193
|
+
.find(|a| crate::attr::name(a) == own_tenant_field)
|
|
194
|
+
else {
|
|
203
195
|
return Vec::new();
|
|
204
196
|
};
|
|
205
|
-
let Some(own_accessor) = state_reference_check_accessor(own_tenant_attr, value_objects_by_name)
|
|
197
|
+
let Some(own_accessor) = state_reference_check_accessor(own_tenant_attr, value_objects_by_name)
|
|
198
|
+
else {
|
|
206
199
|
return Vec::new();
|
|
207
200
|
};
|
|
208
|
-
let aggregate_name = aggregate
|
|
201
|
+
let aggregate_name = aggregate
|
|
202
|
+
.get("name")
|
|
203
|
+
.and_then(Json::as_str)
|
|
204
|
+
.unwrap_or("")
|
|
205
|
+
.to_string();
|
|
209
206
|
|
|
210
207
|
cmd_attrs
|
|
211
208
|
.iter()
|
|
@@ -216,12 +213,17 @@ fn tenant_boundary_checks(
|
|
|
216
213
|
return None;
|
|
217
214
|
}
|
|
218
215
|
let target_tenant_field = tenant_field_for(target)?;
|
|
219
|
-
let target_attrs = target.get("attributes").
|
|
216
|
+
let target_attrs = target.get("attributes").map_or_default(Json::each);
|
|
220
217
|
let target_tenant_attr = target_attrs
|
|
221
218
|
.iter()
|
|
222
219
|
.find(|a| crate::attr::name(a) == target_tenant_field)?;
|
|
223
|
-
let target_accessor =
|
|
224
|
-
|
|
220
|
+
let target_accessor =
|
|
221
|
+
state_reference_check_accessor(target_tenant_attr, value_objects_by_name)?;
|
|
222
|
+
let target_decl_name = target
|
|
223
|
+
.get("name")
|
|
224
|
+
.and_then(Json::as_str)
|
|
225
|
+
.unwrap_or("")
|
|
226
|
+
.to_string();
|
|
225
227
|
|
|
226
228
|
Some(TenantBoundaryCheck {
|
|
227
229
|
reference_field: crate::attr::name(attr).to_string(),
|
|
@@ -251,7 +253,7 @@ fn list_reference_check_item(
|
|
|
251
253
|
return Some("item".to_string());
|
|
252
254
|
}
|
|
253
255
|
let vo = value_objects_by_name.get(type_name)?;
|
|
254
|
-
let vo_attrs = vo.get("attributes").
|
|
256
|
+
let vo_attrs = vo.get("attributes").map_or_default(Json::each);
|
|
255
257
|
if vo_attrs.len() != 1 || crate::attr::type_name(&vo_attrs[0]) != "String" {
|
|
256
258
|
return None;
|
|
257
259
|
}
|
|
@@ -265,7 +267,10 @@ fn list_reference_check_item(
|
|
|
265
267
|
///
|
|
266
268
|
/// `None` for a multi-attribute value object, or an optional one: `check_reference`'s
|
|
267
269
|
/// optional template assumes `Option<String>`.
|
|
268
|
-
fn state_reference_check_accessor(
|
|
270
|
+
fn state_reference_check_accessor(
|
|
271
|
+
source_attr: &Json,
|
|
272
|
+
value_objects_by_name: &HashMap<String, &Json>,
|
|
273
|
+
) -> Option<String> {
|
|
269
274
|
let name = crate::attr::name(source_attr);
|
|
270
275
|
if crate::naming::effective_scalar_type(crate::attr::type_name(source_attr)).is_some() {
|
|
271
276
|
return Some(name.to_string());
|
|
@@ -275,12 +280,15 @@ fn state_reference_check_accessor(source_attr: &Json, value_objects_by_name: &Ha
|
|
|
275
280
|
if crate::attr::optional(source_attr) {
|
|
276
281
|
return None;
|
|
277
282
|
}
|
|
278
|
-
let vo_attrs = vo.get("attributes").
|
|
283
|
+
let vo_attrs = vo.get("attributes").map_or_default(Json::each);
|
|
279
284
|
if vo_attrs.len() != 1 {
|
|
280
285
|
return None;
|
|
281
286
|
}
|
|
282
287
|
|
|
283
|
-
Some(format!(
|
|
288
|
+
Some(format!(
|
|
289
|
+
"{name}.{}",
|
|
290
|
+
crate::naming::rust_ident_field(crate::attr::name(&vo_attrs[0]))
|
|
291
|
+
))
|
|
284
292
|
}
|
|
285
293
|
|
|
286
294
|
pub fn generate(
|
|
@@ -292,7 +300,7 @@ pub fn generate(
|
|
|
292
300
|
let resolved_ir = types::with_resolved_projection_types(ir);
|
|
293
301
|
let ir = &resolved_ir;
|
|
294
302
|
let domain_name = ir.get("name").and_then(Json::as_str).unwrap_or("");
|
|
295
|
-
let all_aggregates = ir.get("aggregates").
|
|
303
|
+
let all_aggregates = ir.get("aggregates").map_or_default(Json::each);
|
|
296
304
|
let aggregates_by_name: HashMap<String, &Json> = all_aggregates
|
|
297
305
|
.iter()
|
|
298
306
|
.map(|a| {
|
|
@@ -309,7 +317,7 @@ pub fn generate(
|
|
|
309
317
|
let unsupported_names: Vec<String> = all_aggregates
|
|
310
318
|
.iter()
|
|
311
319
|
.filter(|a| {
|
|
312
|
-
let vos = a.get("value_objects").
|
|
320
|
+
let vos = a.get("value_objects").map_or_default(Json::each);
|
|
313
321
|
let vo_by_name: HashMap<String, &Json> = vos
|
|
314
322
|
.iter()
|
|
315
323
|
.map(|vo| {
|
|
@@ -337,18 +345,24 @@ pub fn generate(
|
|
|
337
345
|
let mut manifest = Manifest::default();
|
|
338
346
|
let process_managers: Vec<Json> = ir
|
|
339
347
|
.get("process_managers")
|
|
340
|
-
.
|
|
341
|
-
.unwrap_or(&[])
|
|
348
|
+
.map_or_default(Json::each)
|
|
342
349
|
.to_vec();
|
|
343
350
|
|
|
344
351
|
// Owner of each value object across the whole domain: a command attribute can name a value
|
|
345
352
|
// object declared by another aggregate. Last writer wins per name.
|
|
346
353
|
let mut domain_value_object_owner: HashMap<String, String> = HashMap::new();
|
|
347
354
|
for a in all_aggregates {
|
|
348
|
-
let owner = a
|
|
349
|
-
|
|
355
|
+
let owner = a
|
|
356
|
+
.get("name")
|
|
357
|
+
.and_then(Json::as_str)
|
|
358
|
+
.unwrap_or("")
|
|
359
|
+
.to_string();
|
|
360
|
+
for vo in a.get("value_objects").map_or_default(Json::each) {
|
|
350
361
|
domain_value_object_owner.insert(
|
|
351
|
-
vo.get("name")
|
|
362
|
+
vo.get("name")
|
|
363
|
+
.and_then(Json::as_str)
|
|
364
|
+
.unwrap_or("")
|
|
365
|
+
.to_string(),
|
|
352
366
|
owner.clone(),
|
|
353
367
|
);
|
|
354
368
|
}
|
|
@@ -357,19 +371,23 @@ pub fn generate(
|
|
|
357
371
|
// a cross-aggregate argument. Each aggregate's own map wins a name collision.
|
|
358
372
|
let mut domain_value_objects_by_name: HashMap<String, &Json> = HashMap::new();
|
|
359
373
|
for a in all_aggregates {
|
|
360
|
-
for vo in a.get("value_objects").
|
|
361
|
-
domain_value_objects_by_name.insert(
|
|
374
|
+
for vo in a.get("value_objects").map_or_default(Json::each) {
|
|
375
|
+
domain_value_objects_by_name.insert(
|
|
376
|
+
vo.get("name")
|
|
377
|
+
.and_then(Json::as_str)
|
|
378
|
+
.unwrap_or("")
|
|
379
|
+
.to_string(),
|
|
380
|
+
vo,
|
|
381
|
+
);
|
|
362
382
|
}
|
|
363
383
|
}
|
|
364
384
|
|
|
365
385
|
for aggregate in all_aggregates {
|
|
366
386
|
let agg_name = aggregate.get("name").and_then(Json::as_str).unwrap_or("");
|
|
367
387
|
|
|
368
|
-
let value_objects = aggregate
|
|
369
|
-
|
|
370
|
-
.
|
|
371
|
-
.unwrap_or(&[]);
|
|
372
|
-
let mut value_objects_by_name: HashMap<String, &Json> = domain_value_objects_by_name.clone();
|
|
388
|
+
let value_objects = aggregate.get("value_objects").map_or_default(Json::each);
|
|
389
|
+
let mut value_objects_by_name: HashMap<String, &Json> =
|
|
390
|
+
domain_value_objects_by_name.clone();
|
|
373
391
|
value_objects_by_name.extend(value_objects.iter().map(|vo| {
|
|
374
392
|
(
|
|
375
393
|
vo.get("name")
|
|
@@ -388,23 +406,47 @@ pub fn generate(
|
|
|
388
406
|
"attribute type(s) {} not generated yet (a bare, non-list entity-typed attribute isn't resolved to a Rust type)",
|
|
389
407
|
unsupported.join(", ")
|
|
390
408
|
);
|
|
391
|
-
manifest.skipped_as(
|
|
409
|
+
manifest.skipped_as(
|
|
410
|
+
"aggregate",
|
|
411
|
+
format!("{domain_name}::{agg_name}"),
|
|
412
|
+
"attribute_type",
|
|
413
|
+
aggregate_reason.clone(),
|
|
414
|
+
);
|
|
392
415
|
let cascade = format!("owning aggregate not generated: {aggregate_reason}");
|
|
393
|
-
for command in aggregate.get("commands").
|
|
394
|
-
manifest.skipped_as(
|
|
416
|
+
for command in aggregate.get("commands").map_or_default(Json::each) {
|
|
417
|
+
manifest.skipped_as(
|
|
418
|
+
"command",
|
|
419
|
+
format!("{domain_name}::{agg_name}.{}", node_name(command)),
|
|
420
|
+
"owning_aggregate",
|
|
421
|
+
cascade.clone(),
|
|
422
|
+
);
|
|
395
423
|
}
|
|
396
|
-
for entity in aggregate.get("entities").
|
|
424
|
+
for entity in aggregate.get("entities").map_or_default(Json::each) {
|
|
397
425
|
let entity_verb = format!("{domain_name}::{agg_name}.{}", node_name(entity));
|
|
398
|
-
manifest.skipped_as(
|
|
399
|
-
|
|
400
|
-
|
|
426
|
+
manifest.skipped_as(
|
|
427
|
+
"entity",
|
|
428
|
+
entity_verb.clone(),
|
|
429
|
+
"owning_aggregate",
|
|
430
|
+
cascade.clone(),
|
|
431
|
+
);
|
|
432
|
+
for command in entity.get("commands").map_or_default(Json::each) {
|
|
433
|
+
manifest.skipped_as(
|
|
434
|
+
"entity_command",
|
|
435
|
+
format!("{entity_verb}.{}", node_name(command)),
|
|
436
|
+
"owning_aggregate",
|
|
437
|
+
cascade.clone(),
|
|
438
|
+
);
|
|
401
439
|
}
|
|
402
440
|
}
|
|
403
|
-
for port in aggregate.get("ports").
|
|
404
|
-
for operation in port.get("operations").
|
|
441
|
+
for port in aggregate.get("ports").map_or_default(Json::each) {
|
|
442
|
+
for operation in port.get("operations").map_or_default(Json::each) {
|
|
405
443
|
manifest.skipped_as(
|
|
406
444
|
"port_operation",
|
|
407
|
-
format!(
|
|
445
|
+
format!(
|
|
446
|
+
"{domain_name}::{agg_name}.{}.{}",
|
|
447
|
+
node_name(port),
|
|
448
|
+
node_name(operation)
|
|
449
|
+
),
|
|
408
450
|
"owning_aggregate",
|
|
409
451
|
cascade.clone(),
|
|
410
452
|
);
|
|
@@ -428,7 +470,11 @@ pub fn generate(
|
|
|
428
470
|
);
|
|
429
471
|
puts_str(&mut out, "#![allow(dead_code, unused_variables)]");
|
|
430
472
|
puts_str(&mut out, "use crate::kernel::Expr;");
|
|
431
|
-
for line in crate::bridging::cross_aggregate_vo_imports(
|
|
473
|
+
for line in crate::bridging::cross_aggregate_vo_imports(
|
|
474
|
+
aggregate,
|
|
475
|
+
&domain_value_object_owner,
|
|
476
|
+
mod_name,
|
|
477
|
+
) {
|
|
432
478
|
puts_str(&mut out, &line);
|
|
433
479
|
}
|
|
434
480
|
puts_blank(&mut out);
|
|
@@ -444,8 +490,8 @@ pub fn generate(
|
|
|
444
490
|
),
|
|
445
491
|
);
|
|
446
492
|
puts_blank(&mut out);
|
|
447
|
-
let closed_set = vo.get("closed_set").
|
|
448
|
-
let attrs = vo.get("attributes").
|
|
493
|
+
let closed_set = vo.get("closed_set").is_some_and(Json::as_bool);
|
|
494
|
+
let attrs = vo.get("attributes").map_or_default(Json::each);
|
|
449
495
|
if closed_set && attrs.len() == 1 {
|
|
450
496
|
puts_str(&mut out, &json_codec::emit_closed_set_codec(exemplar, vo));
|
|
451
497
|
} else if closed_set {
|
|
@@ -458,7 +504,7 @@ pub fn generate(
|
|
|
458
504
|
crate::naming::rust_ident(vo.get("name").and_then(Json::as_str).unwrap_or(""));
|
|
459
505
|
puts_str(
|
|
460
506
|
&mut out,
|
|
461
|
-
&json_codec::emit_to_json_flat(exemplar, &name, attrs,
|
|
507
|
+
&json_codec::emit_to_json_flat(exemplar, &name, attrs, false, &[], None),
|
|
462
508
|
);
|
|
463
509
|
puts_blank(&mut out);
|
|
464
510
|
// `Some(&[])` refuses unknown keys: without it a mistyped nested field (`value`
|
|
@@ -476,6 +522,7 @@ pub fn generate(
|
|
|
476
522
|
false,
|
|
477
523
|
false,
|
|
478
524
|
None,
|
|
525
|
+
None,
|
|
479
526
|
),
|
|
480
527
|
);
|
|
481
528
|
}
|
|
@@ -488,12 +535,21 @@ pub fn generate(
|
|
|
488
535
|
// identity shape, not its command routability.
|
|
489
536
|
let mut registry_entities: Vec<EntityIdentityEntry> = Vec::new();
|
|
490
537
|
|
|
491
|
-
for entity in aggregate.get("entities").
|
|
538
|
+
for entity in aggregate.get("entities").map_or_default(Json::each) {
|
|
492
539
|
let entity_verb = format!("{domain_name}::{agg_name}.{}", node_name(entity));
|
|
493
540
|
manifest.generated("entity", entity_verb.clone());
|
|
494
541
|
registry_entities.push(EntityIdentityEntry {
|
|
495
|
-
name: entity
|
|
496
|
-
|
|
542
|
+
name: entity
|
|
543
|
+
.get("name")
|
|
544
|
+
.and_then(Json::as_str)
|
|
545
|
+
.unwrap_or("")
|
|
546
|
+
.to_string(),
|
|
547
|
+
identified_by: entity
|
|
548
|
+
.get("identified_by")
|
|
549
|
+
.map_or_default(Json::each)
|
|
550
|
+
.iter()
|
|
551
|
+
.map(Json::to_s)
|
|
552
|
+
.collect(),
|
|
497
553
|
});
|
|
498
554
|
puts_str(
|
|
499
555
|
&mut out,
|
|
@@ -502,7 +558,7 @@ pub fn generate(
|
|
|
502
558
|
puts_blank(&mut out);
|
|
503
559
|
let entity_name_ident =
|
|
504
560
|
crate::naming::rust_ident(entity.get("name").and_then(Json::as_str).unwrap_or(""));
|
|
505
|
-
let entity_attrs = entity.get("attributes").
|
|
561
|
+
let entity_attrs = entity.get("attributes").map_or_default(Json::each);
|
|
506
562
|
let extra = lifecycle_extra_field(entity);
|
|
507
563
|
puts_str(
|
|
508
564
|
&mut out,
|
|
@@ -510,7 +566,6 @@ pub fn generate(
|
|
|
510
566
|
exemplar,
|
|
511
567
|
&entity_name_ident,
|
|
512
568
|
entity_attrs,
|
|
513
|
-
&value_objects_by_name,
|
|
514
569
|
false,
|
|
515
570
|
&extra,
|
|
516
571
|
None,
|
|
@@ -538,7 +593,7 @@ pub fn generate(
|
|
|
538
593
|
// dispatch at depth 2 additionally needs the same check on `nested`.
|
|
539
594
|
let entity_can_route = json_codec::extract_id_supported(entity);
|
|
540
595
|
|
|
541
|
-
for nested in entity.get("entities").
|
|
596
|
+
for nested in entity.get("entities").map_or_default(Json::each) {
|
|
542
597
|
let nested_verb = format!("{entity_verb}.{}", node_name(nested));
|
|
543
598
|
manifest.generated("entity", nested_verb.clone());
|
|
544
599
|
puts_str(
|
|
@@ -549,7 +604,7 @@ pub fn generate(
|
|
|
549
604
|
let nested_name_ident = crate::naming::rust_ident(
|
|
550
605
|
nested.get("name").and_then(Json::as_str).unwrap_or(""),
|
|
551
606
|
);
|
|
552
|
-
let nested_attrs = nested.get("attributes").
|
|
607
|
+
let nested_attrs = nested.get("attributes").map_or_default(Json::each);
|
|
553
608
|
let nested_extra = lifecycle_extra_field(nested);
|
|
554
609
|
puts_str(
|
|
555
610
|
&mut out,
|
|
@@ -557,7 +612,6 @@ pub fn generate(
|
|
|
557
612
|
exemplar,
|
|
558
613
|
&nested_name_ident,
|
|
559
614
|
nested_attrs,
|
|
560
|
-
&value_objects_by_name,
|
|
561
615
|
false,
|
|
562
616
|
&nested_extra,
|
|
563
617
|
None,
|
|
@@ -588,16 +642,23 @@ pub fn generate(
|
|
|
588
642
|
if unrouted_supported {
|
|
589
643
|
puts_str(&mut out, &json_codec::emit_extract_id(exemplar, nested));
|
|
590
644
|
puts_blank(&mut out);
|
|
591
|
-
puts_str(
|
|
645
|
+
puts_str(
|
|
646
|
+
&mut out,
|
|
647
|
+
&json_codec::emit_extract_id_lenient(exemplar, nested),
|
|
648
|
+
);
|
|
592
649
|
puts_blank(&mut out);
|
|
593
650
|
puts_str(&mut out, &json_codec::emit_extract_wants(exemplar, nested));
|
|
594
651
|
puts_blank(&mut out);
|
|
595
652
|
}
|
|
596
653
|
|
|
597
|
-
let nested_identified_by = nested.get("identified_by").
|
|
598
|
-
for command in nested.get("commands").
|
|
654
|
+
let nested_identified_by = nested.get("identified_by").map_or_default(Json::each);
|
|
655
|
+
for command in nested.get("commands").map_or_default(Json::each) {
|
|
599
656
|
let nested_command_verb = format!("{nested_verb}.{}", node_name(command));
|
|
600
|
-
if let Some(reason) = commands::entity_command_skip_reason(
|
|
657
|
+
if let Some(reason) = commands::entity_command_skip_reason(
|
|
658
|
+
command,
|
|
659
|
+
nested,
|
|
660
|
+
&value_objects_by_name,
|
|
661
|
+
) {
|
|
601
662
|
manifest.skipped("entity_command", nested_command_verb, reason);
|
|
602
663
|
continue;
|
|
603
664
|
}
|
|
@@ -632,7 +693,8 @@ pub fn generate(
|
|
|
632
693
|
}),
|
|
633
694
|
);
|
|
634
695
|
|
|
635
|
-
let nested_command_name =
|
|
696
|
+
let nested_command_name =
|
|
697
|
+
command.get("name").and_then(Json::as_str).unwrap_or("");
|
|
636
698
|
let entity_name_str = entity.get("name").and_then(Json::as_str).unwrap_or("");
|
|
637
699
|
let nested_name_str = nested.get("name").and_then(Json::as_str).unwrap_or("");
|
|
638
700
|
nested_entity_commands.push(NestedEntityCommandEntry {
|
|
@@ -653,15 +715,8 @@ pub fn generate(
|
|
|
653
715
|
reference_checks: reference_checks(command, &aggregates_by_name, &unsupported_names),
|
|
654
716
|
reference_specs: crate::reference_specs::reference_specs(
|
|
655
717
|
domain_name,
|
|
656
|
-
command.get("attributes").
|
|
718
|
+
command.get("attributes").map_or_default(Json::each),
|
|
657
719
|
),
|
|
658
|
-
attributes: command
|
|
659
|
-
.get("attributes")
|
|
660
|
-
.map(Json::each)
|
|
661
|
-
.unwrap_or(&[])
|
|
662
|
-
.iter()
|
|
663
|
-
.map(|a| a.get("name").map(Json::to_s).unwrap_or_default())
|
|
664
|
-
.collect(),
|
|
665
720
|
invariant_check_lines: commands::invariant_checks_for(
|
|
666
721
|
exemplar,
|
|
667
722
|
command,
|
|
@@ -672,8 +727,7 @@ pub fn generate(
|
|
|
672
727
|
entity_name: entity_name_str.to_string(),
|
|
673
728
|
entity_identity_reading: entity
|
|
674
729
|
.get("identified_by")
|
|
675
|
-
.
|
|
676
|
-
.unwrap_or(&[])
|
|
730
|
+
.map_or_default(Json::each)
|
|
677
731
|
.iter()
|
|
678
732
|
.map(Json::to_s)
|
|
679
733
|
.collect::<Vec<_>>()
|
|
@@ -692,7 +746,10 @@ pub fn generate(
|
|
|
692
746
|
if entity_can_route {
|
|
693
747
|
puts_str(&mut out, &json_codec::emit_extract_id(exemplar, entity));
|
|
694
748
|
puts_blank(&mut out);
|
|
695
|
-
puts_str(
|
|
749
|
+
puts_str(
|
|
750
|
+
&mut out,
|
|
751
|
+
&json_codec::emit_extract_id_lenient(exemplar, entity),
|
|
752
|
+
);
|
|
696
753
|
puts_blank(&mut out);
|
|
697
754
|
puts_str(&mut out, &json_codec::emit_extract_wants(exemplar, entity));
|
|
698
755
|
puts_blank(&mut out);
|
|
@@ -700,9 +757,11 @@ pub fn generate(
|
|
|
700
757
|
puts_blank(&mut out);
|
|
701
758
|
}
|
|
702
759
|
|
|
703
|
-
for command in entity.get("commands").
|
|
760
|
+
for command in entity.get("commands").map_or_default(Json::each) {
|
|
704
761
|
let entity_command_verb = format!("{entity_verb}.{}", node_name(command));
|
|
705
|
-
if let Some(reason) =
|
|
762
|
+
if let Some(reason) =
|
|
763
|
+
commands::entity_command_skip_reason(command, entity, &value_objects_by_name)
|
|
764
|
+
{
|
|
706
765
|
manifest.skipped("entity_command", entity_command_verb, reason);
|
|
707
766
|
continue;
|
|
708
767
|
}
|
|
@@ -739,7 +798,7 @@ pub fn generate(
|
|
|
739
798
|
manifest.routed("entity_command", entity_command_verb);
|
|
740
799
|
|
|
741
800
|
let entity_command_name = command.get("name").and_then(Json::as_str).unwrap_or("");
|
|
742
|
-
let identified_by = entity.get("identified_by").
|
|
801
|
+
let identified_by = entity.get("identified_by").map_or_default(Json::each);
|
|
743
802
|
entity_commands.push(EntityCommandEntry {
|
|
744
803
|
verb: format!(
|
|
745
804
|
"{domain_name}::{agg_name}.{entity_name_ident}.{entity_command_name}",
|
|
@@ -769,12 +828,11 @@ pub fn generate(
|
|
|
769
828
|
),
|
|
770
829
|
reference_specs: crate::reference_specs::reference_specs(
|
|
771
830
|
domain_name,
|
|
772
|
-
command.get("attributes").
|
|
831
|
+
command.get("attributes").map_or_default(Json::each),
|
|
773
832
|
),
|
|
774
833
|
attributes: command
|
|
775
834
|
.get("attributes")
|
|
776
|
-
.
|
|
777
|
-
.unwrap_or(&[])
|
|
835
|
+
.map_or_default(Json::each)
|
|
778
836
|
.iter()
|
|
779
837
|
.map(|a| a.get("name").map(Json::to_s).unwrap_or_default())
|
|
780
838
|
.collect(),
|
|
@@ -807,7 +865,10 @@ pub fn generate(
|
|
|
807
865
|
&types::emit_record(exemplar, &record_for_struct, &value_objects_by_name),
|
|
808
866
|
);
|
|
809
867
|
puts_blank(&mut out);
|
|
810
|
-
let record_attrs_owned = record_for_struct
|
|
868
|
+
let record_attrs_owned = record_for_struct
|
|
869
|
+
.get("attributes")
|
|
870
|
+
.map_or_default(Json::each)
|
|
871
|
+
.to_vec();
|
|
811
872
|
let record_attrs = record_attrs_owned.as_slice();
|
|
812
873
|
let extra = lifecycle_extra_field(aggregate);
|
|
813
874
|
puts_str(
|
|
@@ -816,7 +877,6 @@ pub fn generate(
|
|
|
816
877
|
exemplar,
|
|
817
878
|
&record_name,
|
|
818
879
|
record_attrs,
|
|
819
|
-
&value_objects_by_name,
|
|
820
880
|
true,
|
|
821
881
|
&extra,
|
|
822
882
|
Some(aggregate),
|
|
@@ -836,7 +896,7 @@ pub fn generate(
|
|
|
836
896
|
),
|
|
837
897
|
);
|
|
838
898
|
puts_blank(&mut out);
|
|
839
|
-
puts_str(&mut out, &format!("impl crate::kernel::ToJson for {record_name} {{\n fn to_json(&self) -> crate::kernel::Json {{\n
|
|
899
|
+
puts_str(&mut out, &format!("impl crate::kernel::ToJson for {record_name} {{\n fn to_json(&self) -> crate::kernel::Json {{\n Self::to_json(self)\n }}\n}}\n"));
|
|
840
900
|
puts_blank(&mut out);
|
|
841
901
|
puts_str(&mut out, &types::emit_set_projected_field(aggregate));
|
|
842
902
|
puts_blank(&mut out);
|
|
@@ -852,9 +912,11 @@ pub fn generate(
|
|
|
852
912
|
puts_blank(&mut out);
|
|
853
913
|
|
|
854
914
|
let mut registry_commands: Vec<CommandEntry> = Vec::new();
|
|
855
|
-
for command in aggregate.get("commands").
|
|
915
|
+
for command in aggregate.get("commands").map_or_default(Json::each) {
|
|
856
916
|
let command_verb = format!("{domain_name}::{agg_name}.{}", node_name(command));
|
|
857
|
-
if let Some(reason) =
|
|
917
|
+
if let Some(reason) =
|
|
918
|
+
commands::command_skip_reason(command, aggregate, &value_objects_by_name)
|
|
919
|
+
{
|
|
858
920
|
manifest.skipped("command", command_verb, reason);
|
|
859
921
|
continue;
|
|
860
922
|
}
|
|
@@ -874,10 +936,10 @@ pub fn generate(
|
|
|
874
936
|
|
|
875
937
|
let command_name = command.get("name").and_then(Json::as_str).unwrap_or("");
|
|
876
938
|
let args_struct = format!("{}Args", crate::naming::rust_ident(command_name));
|
|
877
|
-
let cmd_attrs = command.get("attributes").
|
|
939
|
+
let cmd_attrs = command.get("attributes").map_or_default(Json::each);
|
|
878
940
|
puts_str(
|
|
879
941
|
&mut out,
|
|
880
|
-
&json_codec::emit_to_json_flat_sparse(exemplar, &args_struct, cmd_attrs
|
|
942
|
+
&json_codec::emit_to_json_flat_sparse(exemplar, &args_struct, cmd_attrs),
|
|
881
943
|
);
|
|
882
944
|
puts_blank(&mut out);
|
|
883
945
|
let allowlist =
|
|
@@ -894,6 +956,7 @@ pub fn generate(
|
|
|
894
956
|
true,
|
|
895
957
|
true,
|
|
896
958
|
Some(&aggregates_by_name),
|
|
959
|
+
Some(agg_name),
|
|
897
960
|
),
|
|
898
961
|
);
|
|
899
962
|
puts_blank(&mut out);
|
|
@@ -901,11 +964,16 @@ pub fn generate(
|
|
|
901
964
|
// order by `kernel::decode_aggregate_arguments`.
|
|
902
965
|
puts_str(
|
|
903
966
|
&mut out,
|
|
904
|
-
&json_codec::emit_argument_gates(
|
|
967
|
+
&json_codec::emit_argument_gates(
|
|
968
|
+
&args_struct,
|
|
969
|
+
command_name,
|
|
970
|
+
cmd_attrs,
|
|
971
|
+
Some(&allowlist),
|
|
972
|
+
),
|
|
905
973
|
);
|
|
906
974
|
puts_blank(&mut out);
|
|
907
975
|
|
|
908
|
-
let creates = crate::shared::creates_owner(aggregate, command
|
|
976
|
+
let creates = crate::shared::creates_owner(aggregate, command);
|
|
909
977
|
let identity = mutations::identity_components(aggregate, command);
|
|
910
978
|
let identity_extra_params: Vec<String> = if creates {
|
|
911
979
|
identity.iter().filter_map(|c| c.head.clone()).collect()
|
|
@@ -936,8 +1004,15 @@ pub fn generate(
|
|
|
936
1004
|
identity_extra_params,
|
|
937
1005
|
// `state_reference_checks` only adds entries `reference_checks` did not cover.
|
|
938
1006
|
reference_checks: {
|
|
939
|
-
let mut checks =
|
|
940
|
-
|
|
1007
|
+
let mut checks =
|
|
1008
|
+
reference_checks(command, &aggregates_by_name, &unsupported_names);
|
|
1009
|
+
checks.extend(state_reference_checks(
|
|
1010
|
+
aggregate,
|
|
1011
|
+
command,
|
|
1012
|
+
&aggregates_by_name,
|
|
1013
|
+
&unsupported_names,
|
|
1014
|
+
&value_objects_by_name,
|
|
1015
|
+
));
|
|
941
1016
|
checks
|
|
942
1017
|
},
|
|
943
1018
|
tenant_boundary_checks: tenant_boundary_checks(
|
|
@@ -963,11 +1038,16 @@ pub fn generate(
|
|
|
963
1038
|
}
|
|
964
1039
|
|
|
965
1040
|
let mut port_operations: Vec<PortEntry> = Vec::new();
|
|
966
|
-
for port in aggregate.get("ports").
|
|
1041
|
+
for port in aggregate.get("ports").map_or_default(Json::each) {
|
|
967
1042
|
let port_name = port.get("name").and_then(Json::as_str).unwrap_or("");
|
|
968
|
-
for operation in port.get("operations").
|
|
969
|
-
let operation_verb = format!(
|
|
970
|
-
|
|
1043
|
+
for operation in port.get("operations").map_or_default(Json::each) {
|
|
1044
|
+
let operation_verb = format!(
|
|
1045
|
+
"{domain_name}::{agg_name}.{port_name}.{}",
|
|
1046
|
+
node_name(operation)
|
|
1047
|
+
);
|
|
1048
|
+
if let Some(reason) =
|
|
1049
|
+
ports::port_operation_skip_reason(operation, agg_name, &value_objects_by_name)
|
|
1050
|
+
{
|
|
971
1051
|
manifest.skipped("port_operation", operation_verb, reason);
|
|
972
1052
|
continue;
|
|
973
1053
|
}
|
|
@@ -988,7 +1068,7 @@ pub fn generate(
|
|
|
988
1068
|
puts_blank(&mut out);
|
|
989
1069
|
|
|
990
1070
|
let operation_name = operation.get("name").and_then(Json::as_str).unwrap_or("");
|
|
991
|
-
let operation_attrs = operation.get("attributes").
|
|
1071
|
+
let operation_attrs = operation.get("attributes").map_or_default(Json::each);
|
|
992
1072
|
let legacy_receiver_field = operation_attrs
|
|
993
1073
|
.iter()
|
|
994
1074
|
.find(|attr| {
|
|
@@ -999,19 +1079,19 @@ pub fn generate(
|
|
|
999
1079
|
// A `to:`-declared operation has no Reference-typed attribute; its receiver is a
|
|
1000
1080
|
// plain attribute named for the aggregate's identified_by field. Kept apart from
|
|
1001
1081
|
// legacy_receiver_field because `split_aggregate_receiver` must not strip it.
|
|
1002
|
-
let to_receiver_field =
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1082
|
+
let to_receiver_field =
|
|
1083
|
+
if operation.get("to").and_then(Json::as_str) == Some(agg_name) {
|
|
1084
|
+
// `identified_by` holds identity paths: a value-object identity is dotted
|
|
1085
|
+
// ("reference.value"), while the attribute is named "reference".
|
|
1086
|
+
aggregate
|
|
1087
|
+
.get("identified_by")
|
|
1088
|
+
.map_or_default(Json::each)
|
|
1089
|
+
.first()
|
|
1090
|
+
.map(Json::to_s)
|
|
1091
|
+
.and_then(|s| s.split('.').next().map(str::to_string))
|
|
1092
|
+
} else {
|
|
1093
|
+
None
|
|
1094
|
+
};
|
|
1015
1095
|
let operation_reference_checks =
|
|
1016
1096
|
reference_checks(operation, &aggregates_by_name, &unsupported_names)
|
|
1017
1097
|
.into_iter()
|
|
@@ -1019,7 +1099,6 @@ pub fn generate(
|
|
|
1019
1099
|
.collect();
|
|
1020
1100
|
port_operations.push(PortEntry {
|
|
1021
1101
|
verb: format!("{domain_name}::{agg_name}.{port_name}.{operation_name}"),
|
|
1022
|
-
name: operation_name.to_string(),
|
|
1023
1102
|
fn_name: format!(
|
|
1024
1103
|
"{}_{}",
|
|
1025
1104
|
port_name.to_lowercase(),
|
|
@@ -1054,9 +1133,14 @@ pub fn generate(
|
|
|
1054
1133
|
domain_name: domain_name.to_string(),
|
|
1055
1134
|
reference_specs: crate::reference_specs::reference_specs(
|
|
1056
1135
|
domain_name,
|
|
1057
|
-
aggregate.get("attributes").
|
|
1136
|
+
aggregate.get("attributes").map_or_default(Json::each),
|
|
1058
1137
|
),
|
|
1059
|
-
identified_by: aggregate
|
|
1138
|
+
identified_by: aggregate
|
|
1139
|
+
.get("identified_by")
|
|
1140
|
+
.map_or_default(Json::each)
|
|
1141
|
+
.iter()
|
|
1142
|
+
.map(Json::to_s)
|
|
1143
|
+
.collect(),
|
|
1060
1144
|
entities: registry_entities,
|
|
1061
1145
|
});
|
|
1062
1146
|
}
|
|
@@ -1065,10 +1149,7 @@ pub fn generate(
|
|
|
1065
1149
|
let assignments_verb = queries::provided_assignments(ir);
|
|
1066
1150
|
for aggregate in all_aggregates {
|
|
1067
1151
|
let agg_name = aggregate.get("name").and_then(Json::as_str).unwrap_or("");
|
|
1068
|
-
let value_objects = aggregate
|
|
1069
|
-
.get("value_objects")
|
|
1070
|
-
.map(Json::each)
|
|
1071
|
-
.unwrap_or(&[]);
|
|
1152
|
+
let value_objects = aggregate.get("value_objects").map_or_default(Json::each);
|
|
1072
1153
|
let value_objects_by_name: HashMap<String, &Json> = value_objects
|
|
1073
1154
|
.iter()
|
|
1074
1155
|
.map(|vo| {
|
|
@@ -1082,40 +1163,74 @@ pub fn generate(
|
|
|
1082
1163
|
})
|
|
1083
1164
|
.collect();
|
|
1084
1165
|
|
|
1085
|
-
for query in aggregate.get("queries").
|
|
1166
|
+
for query in aggregate.get("queries").map_or_default(Json::each) {
|
|
1086
1167
|
let query_name = query.get("name").and_then(Json::as_str).unwrap_or("");
|
|
1087
|
-
if let Some(reason) = queries::query_skip_reason(
|
|
1088
|
-
|
|
1168
|
+
if let Some(reason) = queries::query_skip_reason(
|
|
1169
|
+
query,
|
|
1170
|
+
aggregate,
|
|
1171
|
+
&value_objects_by_name,
|
|
1172
|
+
&aggregates_by_name,
|
|
1173
|
+
) {
|
|
1174
|
+
manifest.skipped(
|
|
1175
|
+
"query",
|
|
1176
|
+
format!("{domain_name}::{agg_name}.{query_name}"),
|
|
1177
|
+
reason,
|
|
1178
|
+
);
|
|
1089
1179
|
continue;
|
|
1090
1180
|
}
|
|
1091
1181
|
manifest.generated("query", format!("{domain_name}::{agg_name}.{query_name}"));
|
|
1092
1182
|
|
|
1093
|
-
let (conditions, reference_hop_conditions) = queries::query_conditions_and_hops(
|
|
1183
|
+
let (conditions, reference_hop_conditions) = queries::query_conditions_and_hops(
|
|
1184
|
+
domain_name,
|
|
1185
|
+
query,
|
|
1186
|
+
aggregate,
|
|
1187
|
+
&aggregates_by_name,
|
|
1188
|
+
);
|
|
1094
1189
|
query_defs.push(queries::QueryDef {
|
|
1095
1190
|
verb: format!("{domain_name}::{agg_name}.{query_name}"),
|
|
1096
1191
|
aggregate: format!("{domain_name}::{agg_name}"),
|
|
1097
|
-
arg_checks: queries::query_arg_checks(
|
|
1192
|
+
arg_checks: queries::query_arg_checks(
|
|
1193
|
+
query,
|
|
1194
|
+
&format!(
|
|
1195
|
+
"crate::generated::{mod_name}::{}",
|
|
1196
|
+
crate::naming::aggregate_module(agg_name)
|
|
1197
|
+
),
|
|
1198
|
+
&value_objects_by_name,
|
|
1199
|
+
),
|
|
1098
1200
|
conditions,
|
|
1099
1201
|
reference_hop_conditions,
|
|
1100
|
-
order_by: query
|
|
1202
|
+
order_by: query
|
|
1203
|
+
.get("order_by")
|
|
1204
|
+
.map(|ob| queries::emit_query_order_by(ob, query.get("null_semantics"))),
|
|
1101
1205
|
offset: query.get("offset").map(queries::emit_query_offset),
|
|
1102
1206
|
limit: query.get("limit").map(queries::emit_query_limit),
|
|
1103
|
-
authorization: queries::emit_query_authorization(
|
|
1104
|
-
|
|
1207
|
+
authorization: queries::emit_query_authorization(
|
|
1208
|
+
query_name,
|
|
1209
|
+
query.get("authorization"),
|
|
1210
|
+
),
|
|
1211
|
+
assignments: assignments_verb.as_deref()
|
|
1212
|
+
== Some(format!("{agg_name}.{query_name}").as_str()),
|
|
1105
1213
|
entity: None,
|
|
1106
1214
|
});
|
|
1107
1215
|
}
|
|
1108
1216
|
|
|
1109
1217
|
// Entity queries, one level down.
|
|
1110
1218
|
let aggregate_id = format!("{domain_name}::{agg_name}");
|
|
1111
|
-
let attrs = aggregate.get("attributes").
|
|
1112
|
-
for entity in aggregate.get("entities").
|
|
1219
|
+
let attrs = aggregate.get("attributes").map_or_default(Json::each);
|
|
1220
|
+
for entity in aggregate.get("entities").map_or_default(Json::each) {
|
|
1113
1221
|
let entity_name = entity.get("name").and_then(Json::as_str).unwrap_or("");
|
|
1114
|
-
let list_attr = attrs
|
|
1115
|
-
|
|
1222
|
+
let list_attr = attrs
|
|
1223
|
+
.iter()
|
|
1224
|
+
.find(|a| crate::attr::list(a) && crate::attr::type_name(a) == entity_name);
|
|
1225
|
+
for query in entity.get("queries").map_or_default(Json::each) {
|
|
1116
1226
|
let query_name = query.get("name").and_then(Json::as_str).unwrap_or("");
|
|
1117
1227
|
let query_verb = format!("{aggregate_id}.{entity_name}.{query_name}");
|
|
1118
|
-
if let Some(reason) = queries::entity_query_skip_reason(
|
|
1228
|
+
if let Some(reason) = queries::entity_query_skip_reason(
|
|
1229
|
+
query,
|
|
1230
|
+
entity,
|
|
1231
|
+
list_attr.is_some(),
|
|
1232
|
+
&value_objects_by_name,
|
|
1233
|
+
) {
|
|
1119
1234
|
manifest.skipped("query", query_verb, reason);
|
|
1120
1235
|
continue;
|
|
1121
1236
|
}
|
|
@@ -1123,8 +1238,7 @@ pub fn generate(
|
|
|
1123
1238
|
manifest.generated("query", query_verb);
|
|
1124
1239
|
let identity_keys = entity
|
|
1125
1240
|
.get("identified_by")
|
|
1126
|
-
.
|
|
1127
|
-
.unwrap_or(&[])
|
|
1241
|
+
.map_or_default(Json::each)
|
|
1128
1242
|
.iter()
|
|
1129
1243
|
.map(|path| Json::to_s(path).split('.').next().unwrap_or("").to_string())
|
|
1130
1244
|
.collect();
|
|
@@ -1134,26 +1248,33 @@ pub fn generate(
|
|
|
1134
1248
|
arg_checks: Vec::new(),
|
|
1135
1249
|
conditions: queries::query_conditions(query),
|
|
1136
1250
|
reference_hop_conditions: Vec::new(),
|
|
1137
|
-
order_by: query
|
|
1251
|
+
order_by: query
|
|
1252
|
+
.get("order_by")
|
|
1253
|
+
.map(|ob| queries::emit_query_order_by(ob, query.get("null_semantics"))),
|
|
1138
1254
|
offset: query.get("offset").map(queries::emit_query_offset),
|
|
1139
1255
|
limit: query.get("limit").map(queries::emit_query_limit),
|
|
1140
1256
|
authorization: None,
|
|
1141
1257
|
assignments: false,
|
|
1142
1258
|
entity: Some(queries::EntityScope {
|
|
1143
1259
|
list_field: crate::attr::name(list_attr).to_string(),
|
|
1144
|
-
parent_key: crate::
|
|
1260
|
+
parent_key: crate::hecks_naming::snake(agg_name),
|
|
1145
1261
|
identity_keys,
|
|
1146
1262
|
}),
|
|
1147
1263
|
});
|
|
1148
1264
|
}
|
|
1149
|
-
manifest.entity_query_gaps(
|
|
1265
|
+
manifest.entity_query_gaps(
|
|
1266
|
+
&format!("{aggregate_id}.{entity_name}"),
|
|
1267
|
+
entity.get("entities").map_or_default(Json::each),
|
|
1268
|
+
);
|
|
1150
1269
|
}
|
|
1151
1270
|
}
|
|
1152
1271
|
|
|
1153
1272
|
let mut read_model_defs: Vec<read_models::ReadModelDef> = Vec::new();
|
|
1154
|
-
for read_model in ir.get("read_models").
|
|
1273
|
+
for read_model in ir.get("read_models").map_or_default(Json::each) {
|
|
1155
1274
|
let read_model_id = format!("{domain_name}::{}", node_name(read_model));
|
|
1156
|
-
if let Some(reason) =
|
|
1275
|
+
if let Some(reason) =
|
|
1276
|
+
read_models::read_model_skip_reason(read_model, &aggregates_by_name, &unsupported_names)
|
|
1277
|
+
{
|
|
1157
1278
|
manifest.skipped("read_model", read_model_id, reason);
|
|
1158
1279
|
continue;
|
|
1159
1280
|
}
|
|
@@ -1166,14 +1287,20 @@ pub fn generate(
|
|
|
1166
1287
|
}
|
|
1167
1288
|
|
|
1168
1289
|
// Policies and process managers have no per-instance skip condition.
|
|
1169
|
-
for policy in ir.get("policies").
|
|
1290
|
+
for policy in ir.get("policies").map_or_default(Json::each) {
|
|
1170
1291
|
manifest.routed("policy", format!("{domain_name}::{}", node_name(policy)));
|
|
1171
1292
|
}
|
|
1172
1293
|
for pm in &process_managers {
|
|
1173
|
-
manifest.routed(
|
|
1294
|
+
manifest.routed(
|
|
1295
|
+
"process_manager",
|
|
1296
|
+
format!("{domain_name}::{}", node_name(pm)),
|
|
1297
|
+
);
|
|
1174
1298
|
}
|
|
1175
1299
|
// Lineage-capable aggregates are always generated and routed; the journal path is generic.
|
|
1176
|
-
let lineage_aggregates = ir
|
|
1300
|
+
let lineage_aggregates = ir
|
|
1301
|
+
.get("lineage")
|
|
1302
|
+
.and_then(|l| l.get("capable_aggregates"))
|
|
1303
|
+
.map_or_default(Json::each);
|
|
1177
1304
|
for lineage_aggregate in lineage_aggregates {
|
|
1178
1305
|
manifest.record(
|
|
1179
1306
|
"lineage_aggregate",
|
|
@@ -1189,10 +1316,10 @@ pub fn generate(
|
|
|
1189
1316
|
);
|
|
1190
1317
|
}
|
|
1191
1318
|
|
|
1192
|
-
let policies: Vec<Json> = ir.get("policies").
|
|
1319
|
+
let policies: Vec<Json> = ir.get("policies").map_or_default(Json::each).to_vec();
|
|
1193
1320
|
// Raw aggregate JSON: a fan-out's addressing key comes from the target command's declared
|
|
1194
1321
|
// `references`/`attributes`, which `AggregateEntry` does not carry.
|
|
1195
|
-
let policy_aggregates: Vec<Json> = ir.get("aggregates").
|
|
1322
|
+
let policy_aggregates: Vec<Json> = ir.get("aggregates").map_or_default(Json::each).to_vec();
|
|
1196
1323
|
|
|
1197
1324
|
let mut registry_rs = String::new();
|
|
1198
1325
|
puts_str(
|
|
@@ -1254,7 +1381,10 @@ pub fn generate(
|
|
|
1254
1381
|
&queries::emit_query_table(exemplar, &query_defs),
|
|
1255
1382
|
);
|
|
1256
1383
|
puts_blank(&mut registry_rs);
|
|
1257
|
-
puts_str(
|
|
1384
|
+
puts_str(
|
|
1385
|
+
&mut registry_rs,
|
|
1386
|
+
&queries::emit_query_arg_check_table(&query_defs),
|
|
1387
|
+
);
|
|
1258
1388
|
puts_blank(&mut registry_rs);
|
|
1259
1389
|
for rmd in &read_model_defs {
|
|
1260
1390
|
if let Some(body) = &rmd.group_by_fn_body {
|