Proposal 0001: QuerySpec Host DSL
Status
draft
Summary
Introduce a host-agnostic QuerySpec model and syntax so Hyperphp can support richer domain DSLs (database, CMS, search, and similar domains) without requiring hosts to parse raw free-form text statements.
Motivation
Current host extensibility is command-oriented. This is effective for simple verbs, but awkward for query-like language.
We want script expressions such as:
tell application "database"
set user_id to id of user of request
set user_name to name of first user whose id is user_id
end tell
and:
tell application "database"
set latest_posts to every post sorted by created reverse limit 10
set author_posts to every post whose author is "patrik" and status is "published" sorted by created normal limit 5
end tell
to compile to one shared query protocol that any host can execute.
Goals
- Add a shared QuerySpec execution protocol for hosts.
- Keep syntax Apple-like and readable.
- Support v1 query capabilities:
- filter (
whose) - order (
sorted by <field> normal|reverse) - limit (
limit <n>) - Preserve backward compatibility with existing tell and query behavior.
- Fail fast with explicit runtime errors when host capabilities are missing.
Non-Goals
- SQL compatibility or SQL parsing.
- joins, grouping, projections, and aggregates in v1.
- host-specific raw-DSL parser callbacks in this proposal.
- ordering keyword aliases in v1 (
ordered by,descending,backwards).
User-Facing Syntax / Behavior
Canonical v1 forms:
every post whose author is "patrik" sorted by created reverse limit 5
every post sorted by created normal
first user whose id is user_id
name of first user whose id is user_id
Rules:
- ordering must use
sorted by. - direction must be exactly
normalorreverse. limitmust be a positive integer expression.- clause order in v1:
- base query
- optional
whose - optional
sorted by - optional
limit
Semantics
- Query expressions compile to QuerySpec objects.
- QuerySpec execution is delegated to the current tell host when the host supports QuerySpec execution.
- If QuerySpec-only features are used and the host does not support QuerySpec execution, runtime raises an error (fail fast).
- Existing simple query forms continue to work on legacy hosts.
first <kind> ...returns a single resolved item using existing object-specifier semantics.
Public API / Interface Changes
Add Hyperphp\Host\QuerySpecExecutableInterface:
executeQuerySpec(QuerySpec $spec, QueryExecutionContext $context): mixed
Add Hyperphp\Host\QuerySpec value object:
kind: stringmode: "one" | "many"source: mixed|nullpredicate: PredicateSpec|nullsort: SortSpec|nulllimit: int|null
Add Hyperphp\Host\QueryExecutionContext value object:
applicationName: stringbindings: array<string,mixed>eventContext: array<string,mixed>tellPath: list<string>(optional diagnostics)
Parser / AST Changes
- Add query AST node(s) that capture:
- query kind and mode
- optional source expression
- optional predicate
- optional sort clause
- optional limit clause
- Extend parser query path to support:
every <kind> ... sorted by ... limit ...first <kind> whose ... sorted by ...name of first <kind> whose ...- Reject non-canonical ordering aliases in v1.
Runtime Changes
- Interpreter evaluates query AST into
QuerySpec. - Interpreter builds
QueryExecutionContextfrom current runtime state. - Dispatch flow:
- If current tell object supports
QuerySpecExecutableInterface, callexecuteQuerySpec. - Else:
- if query is legacy-compatible, use existing resolver query flow.
- if QuerySpec-only features are present, raise runtime error.
Error Model
Add explicit runtime errors for:
- host does not support QuerySpec execution for requested features
- invalid sort direction token
- invalid or non-positive limit
- malformed clause ordering
Errors must include line and column context.
Testing Plan
Parser tests:
- parse canonical valid forms
- reject alias keywords and directions in v1
- reject duplicate or misordered clauses
Runtime tests:
- QuerySpec host executes filter + sort + limit correctly
- fail-fast on unsupported host capabilities
- limit coercion and validation behavior
Regression tests:
- existing
every ... whose ..., object specifiers, andofchains remain green - existing hosts continue to work for non-QuerySpec scripts
Backward Compatibility
- No breaking change for existing scripts unless they use new QuerySpec syntax.
- Legacy hosts continue working with current command and query behavior.
- QuerySpec support is opt-in through a new host interface.
Open Questions
- Should singular sugar (
user whose id is user_id) be included in v1 or deferred? - Should runtime in-memory fallback for unsupported
sorted byorlimitever be allowed in a future phase? - Do we want explicit null behavior for empty singular queries, or strict errors only?
Rollout Plan
- Add QuerySpec interfaces and value objects in host layer.
- Add parser and AST support for canonical syntax.
- Add interpreter QuerySpec execution path and fail-fast errors.
- Add one reference host example demonstrating full QuerySpec execution.
- Update language and host docs.
Acceptance Criteria
- New parser and runtime tests for QuerySpec pass.
- Existing test suite remains green.
- At least one reference host demonstrates filter + sort + limit behavior.
- Documentation clearly states canonical syntax and explicit non-goals.