|
| 1 | +# October 28, named and validated query arguments |
| 2 | + |
| 3 | +- **Before.** For a declared query with a parameter contract, native |
| 4 | + differed from published PHP in four ways: |
| 5 | + - it checked positional arguments only; |
| 6 | + - it refused a named-argument map as "must decode to an array"; |
| 7 | + - it answered every violation with a bare `invalid_query_arguments`; |
| 8 | + - it refused some contracts as `unsupported_query_contract` (defaults, |
| 9 | + and declared types other than a few scalars). |
| 10 | + |
| 11 | + The worker then received the arguments exactly as the client sent them. |
| 12 | +- **Contract** (published 2.11.5, Core 2.15.1; |
| 13 | + `WorkflowQueryTaskBroker::validateContractedQueryArguments`, |
| 14 | + `WorkflowQueryContract::validatedArgumentsForRun`, |
| 15 | + `normalizePositionalArguments`, `normalizeNamedArguments`, |
| 16 | + `valueMatchesDeclaredType`): |
| 17 | + - **Arguments.** Arguments decode to a PHP array. A list is positional. |
| 18 | + A string-keyed map is named; keys `0` to `n - 1` cast back to a list. |
| 19 | + - **Positional.** Values fill the parameters in order. A variadic |
| 20 | + parameter takes the rest. A missing argument takes its default or is |
| 21 | + reported if required. Extra values are reported under `arguments`. |
| 22 | + - **Named.** Each parameter takes its name's value. A variadic parameter |
| 23 | + spreads a list or a map's values. Defaults and required arguments are |
| 24 | + handled as for positional ones. Each unknown name is reported under |
| 25 | + itself. |
| 26 | + - **Values.** A null is refused unless the parameter allows it. A value |
| 27 | + must match the declared type: nullable, union, intersection, `int`, |
| 28 | + `float` (an int too), `string`, `bool`, `array`, `iterable`, `scalar`, |
| 29 | + `true`, `false`, `null`, `mixed`. A class or `object` type matches only |
| 30 | + an object, which for decoded Avro is bytes. |
| 31 | + - **Refusal.** Any violation answers `422 invalid_query_arguments`, with |
| 32 | + the message "Workflow query [<name>] argument validation failed." and |
| 33 | + `validation_errors` by argument. |
| 34 | + - **Worker.** Otherwise the worker receives the normalized positional |
| 35 | + list, encoded again with the request's codec. |
| 36 | + - **No parameter contract.** A declared query without one takes a list as |
| 37 | + given and refuses named arguments: "Named arguments require a durable |
| 38 | + or loadable workflow query contract." (a native server never loads a |
| 39 | + workflow class). |
| 40 | +- **Fixture.** `query-contract-arguments`, raw HTTP on protocol 1.20 in a |
| 41 | + fresh namespace. The worker declares `state(string $prefix)`, |
| 42 | + `greet(string $prefix = 'dflt')` and `plain`. There are twelve cases: |
| 43 | + - named, positional, default and named-default queries are routed, and |
| 44 | + the worker's blob is checked; |
| 45 | + - unknown, missing, wrong-type, null, too-many and named-without-contract |
| 46 | + queries are refused, with their messages checked. |
| 47 | +- **Native.** `query_contract.rs` ports the normalization and type rules. |
| 48 | + `check_query_contract` returns the normalized list for a declared query, |
| 49 | + or the refusal. `query_attempt` enqueues the re-encoded blob. |
| 50 | +- **Kept.** |
| 51 | + - `callable` matches only an object here: PHP's `is_callable` also |
| 52 | + accepts strings naming functions, which a native server cannot resolve. |
| 53 | + - A class name that a published PHP server can load (a real class) would |
| 54 | + refuse other objects. Native, loading no classes, accepts any object. |
| 55 | +- **Tests.** `query_contract_arguments.rs` (routed normalization; refusals |
| 56 | + with messages) fails on the previous source. `query_contract.rs` unit |
| 57 | + tests cover the type rules and integer-keyed maps. |
0 commit comments