CLI · CommandsService data

Service data

Query and change data in a deployed database, from the terminal.

eqs db runs a statement against a database you deployed from the marketplace. The api holds the credentials, checks the permission and records what ran, so nothing has to be copied to your machine first.

eqs db query <svc> "<statement>"

Read. Held to reading by the engine, not by us reading your statement.

--param <v>A bound value. Repeatable
--limit <n>Rows before truncating (default 100)
--json / --csvMachine-readable output
shell
eqs db query pg-main "select id, email from users order by id desc"
eqs db exec <svc> "<statement>"

Change rows: insert, update, delete.

--param <v>A bound value. Repeatable
shell
eqs db exec pg-main "delete from sessions where expires_at < now()"
eqs db ddl <svc> "<statement>"

Change structure: create, alter, drop. Its own permission.

shell
eqs db ddl pg-main "alter table users add column nickname text"
eqs db tables <svc>

What the service holds: tables, collections, or labels and relationship types.

--jsonRaw JSON
shell
eqs db tables pg-main
eqs db describe <svc> <name>

A table's columns, a collection's indexes, or a label's observed properties.

shell
eqs db describe pg-main users

The statement is the engine's own

There is no common dialect to learn, on purpose. A query language that covered SQL, Redis commands, Mongo documents and Cypher at once would be a worse version of each. What is uniform is everything around the statement: how you address the service, which permission you need, how results come back, and what gets recorded.

EngineStatementParameters
PostgreSQLSQL$1, $2 …
MySQL / MariaDBSQL?
ClickHouseSQL{p1:String} …
Redisa command lineappended as arguments
MongoDBone JSON command documentnone — values live in the document
Neo4jCypher$p1, $p2 …
bash
eqs db query cache "LRANGE queue 0 -1"
eqs db query docs '{"find":"users","filter":{"active":true},"limit":20}'
eqs db query graph "MATCH (p:Person) RETURN p.name AS name LIMIT 10"

How firmly "read-only" holds

eqs db query never guesses whether your statement writes. Reading SQL to decide that is brittle and fails open, so the engine decides instead — and the output tells you which of three answers you got.

EnginesWhat it means
enforcedPostgreSQL, MySQL, ClickHouse, Neo4jThe engine refuses the write itself, inside a read-only transaction. Nothing had to be detected
checkedRedis, MongoDBThe engine classified the command and we refused on its answer. Still not a guess at your statement, but it can let through what a transaction could not
declared—The verb was a declaration and the audit record is what makes it accountable
One case slips past checked: a MongoDB aggregate ending in $out or $merge writes, and MongoDB classifies aggregate as a read. Catching it would mean parsing the pipeline, which is the guessing this design avoids — so it is written down here instead of quietly assumed away.

Permissions

Each verb needs its own action, and they are not interchangeable.

VerbNeedsHeld by
query, tables, describedata.readReader, Contributor, Owner
execdata.writeContributor, Owner
ddldata.ddlOwner

data.ddl is separate from data.write on purpose: editing a row and dropping a table are not the same risk, and a role that can do the first should not silently do the second.

Values, limits and the record

Prefer --param over pasting a value into the statement. It is bound by the driver rather than spliced in, so a quote or a semicolon inside it is data and never syntax — and it stays out of the audit log.

Every statement is recorded: who ran it, against which service, how long it took and whether it worked. Failures are recorded too, because a statement that errored still happened. What is never recorded is your --param values, which are the ones most likely to be personal data.

Reads stop at 100 rows by default, and the limit is applied before the rows reach the api — a cursor on PostgreSQL, a streamed result on MySQL — so a wide select * is never buffered whole just to be cut. Raise it with --limit, up to 10000, and --timeout up to 120000 ms. When a result was cut, the output says so rather than letting it read as "that is all there is".