Skip to content

CLI: add ergonomic query flags while keeping --queries backwards compatible #1455

@ChiragAgg5k

Description

@ChiragAgg5k

Summary

The generated CLI currently exposes Appwrite query input through --queries, but in practice users have to pass pre-serialized Appwrite JSON query strings. That format is not intuitive for shell usage, and the current command help/examples do not make the expected syntax clear.

This issue proposes a backwards-compatible CLI UX redesign:

  • add ergonomic first-class flags for common query operations
  • keep the existing --queries behavior working unchanged for advanced users and automation
  • improve help text, examples, and runtime error hints

Problem

Today, users commonly try forms like:

appwrite databases list-documents --queries 'limit(100)'
appwrite databases list-documents --queries '["limit(100)"]'

Those inputs are forwarded as-is to the API, which then rejects them because the CLI expects each query token to already be an Appwrite JSON query string.

Internally, the CLI already uses serialized JSON query objects in several places, for example:

JSON.stringify({ method: "orderDesc", attribute: "$id" })
JSON.stringify({ method: "limit", values: [100] })

So the current UX is technically consistent, but not intuitive.

Goals

  • make common list/filter/sort/pagination operations easy to express from a shell
  • avoid requiring JSON arrays or nested escaping for normal usage
  • preserve full power for advanced queries
  • remain fully backwards compatible with existing --queries usage

Proposed UX

1. First-class flags for common query operations

Add dedicated flags for the common query methods users expect to use directly from the CLI:

appwrite databases list-documents \
  --database-id <DATABASE_ID> \
  --collection-id memory \
  --sort-desc '$createdAt' \
  --limit 5

Suggested initial flag surface:

  • --limit <number>
  • --offset <number>
  • --cursor-after <id>
  • --cursor-before <id>
  • --sort-asc <field>
  • --sort-desc <field>
  • --select <csv-or-repeatable>

2. Repeatable --where for common filters

Support a shell-friendly repeatable filter flag:

appwrite databases list-documents \
  --database-id <DATABASE_ID> \
  --collection-id memory \
  --where 'status=active' \
  --where 'score>=10' \
  --sort-desc '$createdAt' \
  --limit 5

Initial grammar can target the most common cases first:

  • field=value
  • field!=value
  • field>value
  • field>=value
  • field<value
  • field<=value
  • field contains value
  • field search value
  • field is null
  • field is not null
  • field in [a,b,c]
  • field between [a,b]

This can compile internally into the existing Appwrite JSON query strings.

3. Keep a raw escape hatch for advanced use cases

Advanced users should still have access to raw query input.

Two acceptable options:

  • keep --queries as-is and document it clearly as the low-level interface
  • optionally add an alias like --query-json for readability, while keeping --queries

Example:

appwrite databases list-documents \
  --database-id <DATABASE_ID> \
  --collection-id memory \
  --queries '{"method":"or","values":[...]}'

Backwards Compatibility

This change should be explicitly backwards compatible.

  • Existing --queries behavior remains supported unchanged.
  • Existing scripts, CI jobs, and automation using serialized Appwrite query strings continue to work.
  • New flags are translated internally into the same JSON query format already used today.
  • Users may mix new ergonomic flags with raw --queries where that combination makes sense.

If mixed usage is allowed, the merge order should be documented and deterministic.

Detailed Implementation Plan

Phase 1: Shared query builder/parsing utilities

Add shared CLI-side utilities in the generated CLI templates to:

  • build Appwrite JSON query strings from ergonomic flags
  • parse repeatable --where expressions
  • normalize scalar vs array values
  • merge generated query strings with existing raw --queries

This should live in a shared template instead of ad hoc per command.

Phase 2: Command generation changes

Update the CLI command generator so query-capable commands can emit the new ergonomic flags.

Likely touch points:

  • src/SDK/Language/CLI.php
  • templates/cli/lib/commands/services/services.ts.twig
  • generated command output in examples/cli/lib/commands/services/*.ts

The generator should only add these flags where query parameters are actually supported.

Phase 3: Help text and examples

Update generated help and docs so users can discover the new syntax immediately.

This should include:

  • command help text for --queries clarifying that it is raw JSON-query input
  • examples for common cases like latest documents, pagination, and filtering
  • generated docs/examples in examples/cli/docs/examples/...

Phase 4: Runtime error guidance

When the API returns errors like:

  • Invalid query
  • Invalid query method
  • Syntax error

show a targeted CLI hint with a correct example and point users to the ergonomic flags where available.

Phase 5: Verification

After template changes:

  • regenerate the CLI via php example.php cli
  • rebuild the binary
  • verify generated command help and example docs
  • verify raw --queries still works exactly as before
  • verify new flags generate equivalent query payloads

Suggested Acceptance Criteria

  • --limit, --offset, --sort-asc, and --sort-desc are supported on query-capable list commands.
  • A repeatable --where flag is supported for common comparison/filter operations.
  • --queries remains fully supported and unchanged.
  • Help output clearly distinguishes ergonomic flags from raw query input.
  • Generated docs include working examples for common list/filter/sort usage.
  • Invalid query errors include actionable hints.
  • Regenerated CLI output in examples/cli/ reflects the new UX.

Non-Goals

  • removing or breaking --queries
  • requiring all Appwrite query methods to be supported in --where on day one
  • changing the Appwrite API query format itself

Why this belongs in sdk-generator

The confusing UX is produced by the generated CLI surface and its generated docs/examples. Even if website docs also need updates elsewhere, the source of truth for the CLI command interface lives here.

Example End State

Simple latest rows query:

appwrite databases list-documents \
  --database-id <DATABASE_ID> \
  --collection-id memory \
  --sort-desc '$createdAt' \
  --limit 5 \
  --json

Advanced raw query remains available:

appwrite databases list-documents \
  --database-id <DATABASE_ID> \
  --collection-id memory \
  --queries '{"method":"orderDesc","attribute":"$createdAt"}' '{"method":"limit","values":[5]}' \
  --json

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions