The shell
One statement against the project's classes, kv and databases, spelled as a script spells it, with an immediate answer.
Where it is
The project has one shell: the Shell entry in the console's
sidebar, or actias shell <project> in the cli. Every class page's
open the shell lands there with that class filled in.
Auction:find { status = "open", high_bid = { gt = 100 } }
3 entries · 41 ms
name status high_bid closes_at
lot-42 open 120 1788292618009
lot-57 open 340 1788292700114
lot-61 open 105 1788293001922
The line is typed by the analyser that checks a script: a misspelled
field underlines before anything is sent, and after
page = Auction:find { ... } the next line completes page.entries.
Names complete from what the project holds, inside the quotes of
kv(" and database(".
What binds
| Binding | Spelled | Resolves into |
|---|---|---|
| a class with a directory | Auction:list {…}, Auction:find {…}, Auction:visit {…} | the class page's directory query |
| an instance | Auction("lot-42"):bid("ada", 120) | one call through the object's own lane (write mode) |
| a kv namespace | kv("users"):get("ada"), :list(), :set("k", v), :delete("k") | the KV page's requests |
| a database | database("main"):query(sql, params), :exec(sql, params) | the database page's query and execute |
Each of those is one statement: it resolves where you typed it
into the request the corresponding console page already makes, and
nothing is woken. \resources lists what the project holds;
\fields Auction lists a class's declared fields and methods.
kv("presence"):list()
kv("presence"):get("ada")
database("directory"):query("select name from handles limit 3")
Auction:list { where = { status = "open" }, order = { high_bid = "desc" }, limit = 20 }
Auction:visit { where = { status = "open" } } -- every row checked against its object
Read-only and write mode
A session starts read-only. \write lifts it; \read puts it back.
| Runs read-only | Needs \write |
|---|---|
list, find, visit; kv get, list; database query | kv set, delete; database exec; every method call |
A method call goes through the object's own lane, serialized with every other call, exactly as a script's call would. Nothing declares which methods write, so a read-only session refuses a call rather than hiding it. Naming an instance that does not exist creates it, admission permitting.
In write mode every call and every chunk is logged by the api against your account, one line per action:
shell call by ada on 3f2de568-…: Auction("lot-42"):bid
shell run by ada on 3f2de568-…: 95 chars, write
Chunks
A loop, an expression, a value used as an argument: those are not one
statement, and the shell does not pretend otherwise. Such a line runs
as a chunk, in a fresh vm on a worker, under your grants. So does
anything you give to \run or \paste.
Auction:get(Auction:find().entries[1].name) -- a nested call: a chunk
-- \run, then paste; an impromptu join across a class and a namespace
local presence = kv "presence"
local rows = {}
for _, e in Auction:find({ status = "open" }).entries do
table.insert(rows, { lot = e.name, seen = presence:get("lot:" .. e.name) ~= nil })
end
return rows
| In a chunk | What it is |
|---|---|
kv "…", database "…", objects "…" | the bindings a script has, scoped to every namespace, database and class the project holds |
Auction, every class by name | pre-bound class handles |
Auction:get("lot-42") | a handle to call, as in a script; the row is Auction:find({ name = "lot-42" }).entries[1] |
| a bare expression | returned, the way a repl does |
print and log.* | captured and shown in order with the value |
| the budget | a request's work budget, and 30 seconds of wall time (60 at most) |
| errors | reported with the line number in what you pasted |
The session's mode travels with the chunk. In a read-only session the
vm refuses kv set, set_batch and delete, database exec and
every method call inside the chunk, naming \write:
runtime error: kv set is a write, and this shell session is read-only; \write allows it
A chunk is possible and not encouraged: the one-statement forms are what the shell is for, and a chunk you would run twice is a script.
Commands
| Command | Does |
|---|---|
\write, \read | switch the session's mode |
\fields Auction | the class's declared fields and methods |
\resources | the classes, kv namespaces and databases the project holds |
\run (console) | open a buffer for a chunk; ctrl+enter runs it |
\run <path> (cli) | run a file as a chunk |
\paste … \end (cli) | read lines until \end, then run them as a chunk |
\clear | forget the history and the names it bound |
\help, \quit | as named |
A line starting with -- is a comment and does nothing.
From a pipe
The cli shell reads statements from stdin when it is not a terminal, one per line, and prints each answer, so a scripted check is a heredoc:
actias shell 3f2de568-f50b-4bcd-8877-a9c8a1f58797 <<'EOF'
\resources
Auction:find { status = "open" }
kv("presence"):list()
\quit
EOF
Completions come from the language service when actias-luau is
beside the binary or on your PATH, and from the project's contract
otherwise; the banner says which.
Access
| Statement | Needs on the project |
|---|---|
directory reads, database query | database read |
kv get, list | kv read |
kv set, delete | kv write |
database exec, method calls, chunks | database write, whatever the session's mode |
Limits
| Limit | Value |
|---|---|
| rows per directory page | 500, whatever the statement asks for; the cursor is how to have more |
kv list page | 100 by default, 1000 at most |
| chunk wall time | 30 seconds by default, 60 at most |
| chunk work | a request's budget |
| history | the session's; \clear forgets it |
Gotchas
Auction:get("lot-42")in a chunk is a handle, not the row. In a statement, the same spelling reads the row.- A bare
namein{ name = name }is a variable, and an undefined one: the analyser says so before enter, and a chunk seesnil. ordertakes one field, as everywhere.- The shell is per project. A class, namespace or database another project holds is "not in this project".