Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Local

Reading your data

osy query "<expression>" [path] [--as <login>] [--devname <name>] [--json]

Evaluates one Osy# expression against your app and prints what it answered — the rows, the count, the projection. The read half of `osy run`, which only ever writes. It is not a query language: the expression goes through the same compiler your source does, so anything the language expresses is evaluable here.

stablelocalclidata

Summary#

osy run puts data in. osy query gets it out.

$ osy query "Job.OrderBy(j => j.Position)"
[
  { "Title": "re-plaster the hall", "Room": "hall", "Position": 10 },
  { "Title": "paint the shed",      "Room": "garden", "Position": 20 }
]

$ osy query "Job.Where(j => !j.Done).Count()"
2

Signature#

osy query "<expression>"            // evaluate as ANONYMOUS — what a signed-out visitor sees
osy query "<expression>" --as ada@example.com   // …as one of your users — what THEY see
osy query "<expression>" --json     // the whole result envelope, for a script

Description#

It is not a query language#

The expression is lexed, parsed, resolved and run by the same compiler your source goes through. There is no second grammar to learn and none to drift: whatever you could write inside a function body, you can write here.

That includes the refusals. A verb the language does not have comes back in the resolver's own words, with the closed set it does have:

$ osy query "Job.Nope(j => j.Title)"
✗ unknown query method 'Nope' — on 'Job' rows read from the data store the verbs are: All, Any, Average,
  Count, Distinct, … OrderBy, OrderByDescending, … Where

What it answers with#

Whatever the expression evaluates to, rendered as JSON — because an expression has no single shape:

you writeyou get
Job.OrderBy(j => j.Position)an array of rows
Job.Count()a number — a scalar is a scalar, not a one-element array
Job.Select(j => j.Title)an array of strings
Job.First()one row

A row shows the values the read actually brought back. A column your acting principal may not see is simply absent, which is the honest rendering of what happened rather than a hole where a value would be.

Reading as one of your users#

--as takes no password, and that is the point. Anonymous is the wrong default to be stuck with: on an app with real security an anonymous read returns nothing, so the verb would be useless exactly where it matters — and the only alternative would be reading with security off and returning everything. Neither answers the question you actually have, which is what does this user see?

$ osy query "Job.Count()"                       // as a signed-out visitor
$ osy query "Job.Count()" --as ada@example.com  // as Ada
$ osy query "Job.Count()" --as sam@example.com  // as Sam

Your security { } applies in every case. If the three answers differ, that IS your rules working — this is the cheapest way to see them do it.

Why that is safe, and where the line is#

osy query refuses to WRITE. An expression that creates, updates or deletes is rejected before it runs, and the check is fail-closed: anything that cannot be proven read-only counts as writing.

That refusal is what makes the password-free --as sound. You already have developer authority over this app — you can compile arbitrary code into it — so reading as one of its users grants you nothing you did not already have. Writing as them is impersonation, which authority over an app does not confer over its people, so it stays behind that user's own password:

$ osy query "new Job { Title = \"sneaky\" }"
✗ `query` READS — this expression writes data, so it is refused here. Anything that creates, updates or
  deletes belongs in one of the app's own functions: run it with `osy run <Function>`.

$ osy run AddJob --arg title="re-plaster the hall" --as ada@example.com --password …

Checking what you just wrote#

The pair is the point. osy run makes something happen; osy query says whether it did:

$ osy run AddJob --arg title="re-plaster the hall"
$ osy query "Job.Count()"
1

See also#

Related

Running a function

Runs one of your app's own functions from the command line — to put the app in a known state, backfill a column, or…

Importing data

Loads your app's own data — the JSON files that live beside its source — into the app on the local platform. Rows are…

Querying data

How you read data in Osy#. You write C# LINQ; it becomes one SQL statement. The rules that follow from that are the…

Where / Single / Count

Query an entity by writing a predicate over it. The query runs in the database — not a filter over rows you already…

The security model

How authorization works in Osy#, end to end. Everything is denied until you grant it; a grant is compiled into every…