| Ocalt Query Language
Pricing Dashboard ocalt.com v1.0

Syntax & Variables

Every OQL statement follows one pattern: VERB operand [modifiers] [SET ?var]. No semicolons. No brackets. No dot notation. Statements chain with AFTER, AND, or OR.

Statement structure

VERB operand MODIFIER "value" SET ?result

Every statement starts with a verb. The operand is the primary input. Modifiers provide context (WHERE, WITH, AS, INTO, FROM, TO, AT, ON, FORMAT, USING, LIMIT, SORT BY). SET ?var captures the output. SET is optional — omit it when you only need the side effect.

(* Full form — all parts *) UPPER "hello world" SET ?u (* No SET — side effect only *) WRITE "log entry" INTO "/root/app.log" (* Chained pipeline *) UPPER "hello world" SET ?u AFTER REPLACE ?u WHERE "WORLD" WITH "OQL" SET ?r AFTER EMIT ?r
Try it ›

Comments

Block comments use (* ... *). Inline or multi-line.

(* This is a comment *) UPPER "hello" SET ?u (* inline *) AFTER EMIT ?u (* Multi-line: This whole block is ignored EMIT "this never runs" *) AFTER EMIT "done"
Try it ›

Block delimiters

OPEN NEST and CLOSE NEST wrap block bodies for control flow, operations, and nested constructs. CLOSE ALL NESTS exits all open blocks at once.

IF ?score IS GREATER THAN 90 OPEN NEST EMIT "A" CLOSE NEST ELSE OPEN NEST EMIT "B" CLOSE NEST
(* CLOSE ALL NESTS — break out of any nesting depth *) FOREACH ?items AS ?item OPEN NEST IF ?item IS EQUAL TO "stop" OPEN NEST CLOSE ALL NESTS CLOSE NEST ELSE OPEN NEST EMIT ?item CLOSE NEST CLOSE NEST
Try it ›

Variable types

PrefixTypeScope
?varScalar — mutable, holds any single valueEntire query
?var (multi)Multivariable — when AND branches share the same nameEntire query
!NOWUnix timestamp fixed at query startEntire query
!INDEX0-based position in FOREACHLoop body only
!VALUECurrent iteration item in FOREACHLoop body only
!STATE(IF)Result of the last IF conditionBlock
!STATE(WHILE)Current iteration count in WHILELoop body only
!STATE(FOREACH)Current iteration count in FOREACHLoop body only
!REQUEST(path)URL path — Site Mode onlyEntire query
!REQUEST(method)HTTP method — Site Mode onlyEntire query
!REQUEST(body)Raw request body — Site Mode onlyEntire query
!REQUEST(param:name)Query string param — Site Mode onlyEntire query
!REQUEST(form:field)Form POST field — Site Mode onlyEntire query
!REQUEST(header:name)Request header — Site Mode onlyEntire query
!GET(name)Alias for !REQUEST(param:name)Entire query
!POST(field)Alias for !REQUEST(form:field)Entire query
!COOKIE(name)Request cookie — Site Mode onlyEntire query
!EVENT(key)Injected event data in WATCH handlersHandler body only

String delimiters

Double quotes, single quotes, and backticks are interchangeable. All three produce identical tokens.

EMIT "hello world" EMIT 'hello world' EMIT `hello world`
Try it ›

Each delimiter is literal inside the other two — no escaping needed across delimiter types:

EMIT "it's fine" (* single quote literal inside double *) EMIT 'say "hello"' (* double quote literal inside single *) EMIT `it's a "test"` (* both literal inside backtick *)

Backticks are ideal for multi-line strings, HTML, and code — no internal escaping needed:

EMAIL `

Welcome!

Your account is ready.

` TO "user@example.com" WITH "Welcome"

Scalar variables & scope

Variables set with SET ?name are visible everywhere after the point of assignment — inside OPEN NEST blocks, inside operations, inside loops.

UPPER "ocalt" SET ?company AFTER IF true IS EQUAL TO true OPEN NEST EMIT "Company: " & ?company (* ?company visible inside block *) CLOSE NEST
Try it ›
(* Variables set inside a block are visible after it *) IF true IS EQUAL TO true OPEN NEST UPPER "inner" SET ?result CLOSE NEST AFTER EMIT ?result (* ?result set inside block, visible here *)
Try it ›

Property access

Access a field on an object or an element of an array using parentheses. Chain them for nested access.

(* Object field *) FETCH "https://httpbin.org/uuid" SET ?resp AFTER EMIT ?resp(uuid)
Try it ›
(* Array index — 0-based *) SPLIT "a,b,c" WITH "," SET ?arr AFTER EMIT ?arr(0) (* "a" *) AFTER EMIT ?arr(2) (* "c" *)
Try it ›
(* Nested object — chain parentheses *) PARSE JSON `{"user":{"email":"alice@example.com","role":"admin"}}` SET ?obj AFTER EMIT ?obj(user)(email) AFTER EMIT ?obj(user)(role)
Try it ›
(* Array of objects — index then field *) PARSE JSON `[{"name":"Alice"},{"name":"Bob"}]` SET ?users AFTER EMIT ?users(0)(name) (* "Alice" *) AFTER EMIT ?users(1)(name) (* "Bob" *)
Try it ›

String concatenation

Use & to concatenate values anywhere an expression is accepted — in operands, in modifier values, in SET bindings.

EMIT "Hello " & "World" (* literal *) AFTER EMIT "Name: " & ?name (* variable *) AFTER EMIT ?user(first) & " " & ?user(last) (* property chain *) AFTER WRITE "log: " & !NOW INTO "/root/logs/" & !NOW & ".txt" (* in modifier *)
Try it ›

!NOW — fixed timestamp

!NOW is set once at query start and never changes during execution. Use it when you need the same timestamp across multiple steps.

EMIT !NOW AFTER WRITE "started at " & !NOW INTO "/root/logs/" & !NOW & ".log" AFTER EMIT "Done. Timestamp was: " & !NOW
Try it ›