Q0 GitHub issue
- Purpose
- Actions
- select
- Narrowing
- path
- Placeholders
- create
- update
- delete
- Responses
- Transactions
- Pass-through Fields
- Error IDs
Purpose GitHub issue
vibecode
{"vibecode": { "section": "purpose", "role": "introduces Q0 as the baseline JSON query language for all mikobase engines", "key_concepts": ["Q0", "query_zero", "JSON_queries", "engine.q0", "baseline_language"] }}
Open issues (2)
File: documentation/requirements/mikobase/q0.md
Q0 is the mikobase query language. The name stands for "query zero" — it is the baseline language all mikobase engines support. Future engines may also support additional query languages such as GraphQL.
Every Q0 query is a JSON object sent to the engine via engine.q0().
Actions GitHub issue
vibecode
{"vibecode": { "section": "actions", "role": "lists all valid Q0 action values", "key_concepts": ["select", "create", "update", "delete", "transaction", "commit", "rollback"] }}
The current Q0 actions are:
select— read recordscreate— create a new recordupdate— update an existing recorddelete— delete a recordtransaction— start a transactioncommit— commit a transactionrollback— roll back a transaction
select GitHub issue
vibecode
{"vibecode": { "section": "select", "role": "documents the select action including pk, class, count, limit, offset, and sort filtering", "key_concepts": ["select", "pk_filter", "class_filter", "inheritance_aware", "count", "limit", "offset", "sort", "sorts", "qualifiers"] }}
A select query reads current visible records.
{"action": "select"}
An unfiltered select returns all active records.
Filtering by pk GitHub issue
pk selects a single record by its primary key.
{"action": "select", "pk": "92677339-df86-4f68-9397-999e40cf2c40"}
Filtering by class GitHub issue
class filters by class. It may be a string (scalar) or an array of strings. Class filtering is always inheritance-aware — subclasses are always included.
{"action": "select", "class": "foo.com/character"}
{"action": "select", "class": ["foo.com/hero", "foo.com/villain"]}
count GitHub issue
Every select resultset includes a count of the number of records actually returned, after limit and offset are applied.
results = engine.q0({"action": "select", "class": "https://foo.com/character", "limit": 10})
print(results.count) # number of records returned, up to 10
for record in results:
print(record)
limit and offset GitHub issue
limit restricts the number of records returned. offset skips the first N records. Both are optional integers.
{
"action": "select",
"class": "foo.com/character",
"limit": 10,
"offset": 20
}
sort / sorts GitHub issue
Open issues (1)
File: documentation/requirements/mikobase/q0.md § sort / sorts (#sort-sorts)
sort is a single sort path. sorts is an array of sort paths. When both are present, sort is applied first, then each entry in sorts is appended in order. sort always takes priority over sorts in the combined sequence. Using both together produces a warning in the response.
A sort path is an array of bucket keys, like path, with an optional trailing qualifier object.
{"action": "select", "class": "foo.com/character", "sort": ["name", "family"]}
{"action": "select", "class": "foo.com/character", "sort": ["name", "family", {"case-sensitive": false}]}
{
"action": "select",
"class": "foo.com/character",
"sorts": [
["name", "family", {"case-sensitive": false, "collapse": true}],
["age", {"reverse": true}]
]
}
Qualifiers:
| Qualifier | Description |
|---|---|
reverse |
If true, sort descending. Defaults to false (ascending). |
case-sensitive |
If false, sort strings case-insensitively. Defaults to true. |
collapse |
If true, normalize whitespace before sorting. Defaults to false. |
Null values always sort last, regardless of reverse.
If sort and sorts are both omitted, result ordering is undefined.
Narrowing GitHub issue
vibecode
{"vibecode": { "section": "narrowing", "role": "describes the narrowing model: then, all, any operators for progressive record filtering", "key_concepts": ["narrowing", "then", "all", "any", "AND_semantics", "OR_semantics", "not", "nesting"] }}
Q0 is built around narrowing. A query starts from a root set of records and progressively narrows it through a sequence of steps.
then GitHub issue
then narrows the current result set to a subset. It is an AND operation — only records matching the then condition survive.
{
"action": "select",
"class": "foo.com/character",
"then": {
"path": ["rank", "Captain"]
}
}
then can be nested:
{
"action": "select",
"class": "foo.com/character",
"then": {
"path": ["rank", "Captain"],
"then": {
"path": ["species", "Human"]
}
}
}
Adding "not": true to a then block negates the condition — only records that do NOT match survive:
{
"action": "select",
"class": "foo.com/character",
"then": {
"not": true,
"path": ["name", "family", "Kirk"]
}
}
all GitHub issue
all is an array of sub-queries. The record must match every sub-query (AND logic).
{
"action": "select",
"class": "foo.com/character",
"all": [
{"path": ["Starfleet Academy", {"truthy": true}]},
{"path": ["officer", {"truthy": true}]}
]
}
any GitHub issue
any is an array of sub-queries. The record must match at least one sub-query (OR logic).
{
"action": "select",
"class": "foo.com/character",
"any": [
{"path": ["name", "family", "Picard"]},
{"path": ["name", "family", "Spock"]},
{"path": ["name", "family", "Archer"]},
{"path": ["name", "family", "McCoy"]}
]
}
all, any, and then can be combined and nested:
{
"action": "select",
"class": "foo.com/character",
"any": [
{"path": ["name", "family", "Picard"]},
{"path": ["name", "family", "Spock"]},
{"path": ["name", "family", "Archer"]},
{"path": ["name", "family", "McCoy"]}
],
"all": [
{"path": ["Starfleet Academy", {"truthy": true}]},
{"path": ["officer", {"truthy": true}]}
],
"then": {
"not": true,
"path": ["commands", {"includes": "Reliant"}]
}
}
path GitHub issue
vibecode
{"vibecode": { "section": "path", "role": "documents path traversal and all path operator objects for matching", "key_concepts": ["path_traversal", "literal_match", "string_operators", "number_operators", "array_operators", "existence_operators", "truthy"] }}
path traverses nested keys in bucket and matches the final value. Each element except the last is a hash key to navigate into. The last element is either a literal value or an operator object.
Simple equality:
{"path": ["rank", "Captain"]}
Nested traversal:
{"path": ["name", "family", "Janeway"]}
Path Operators GitHub issue
The last element of a path array may be an operator object instead of a literal value.
String operators:
| Operator | Description |
|---|---|
{"value": "...", "case-sensitive": false} |
Case-insensitive equality |
{"contains": "..."} |
Substring match |
{"starts-with": "..."} |
Prefix match |
{"ends-with": "..."} |
Suffix match |
Number operators:
| Operator | Description |
|---|---|
{"gt": n} |
Greater than |
{"lt": n} |
Less than |
{"gte": n} |
Greater than or equal |
{"lte": n} |
Less than or equal |
Array operators:
| Operator | Description |
|---|---|
{"includes": "..."} |
Array contains this element |
{"includes_all": [...]} |
Array contains all of these elements |
{"includes_any": [...]} |
Array contains at least one of these elements |
Existence and truthiness operators:
| Operator | Description |
|---|---|
{"exists": true} |
Field is present and non-null |
{"exists": false} |
Field is absent or null |
{"truthy": true} |
Field is present, non-null, and truthy |
{"any": true} |
Matches any value (note: distinct from the any narrowing operator) |
Placeholders GitHub issue
vibecode
{"vibecode": { "section": "placeholders", "role": "documents placeholder variables for reusable query templates with scoping and validation", "key_concepts": ["placeholders", "template_reuse", "scoping", "inheritance", "shadowing", "dynamic_resolution", "circular_references"] }}
Placeholders allow query templates to be reused with minimal changes. They are defined at the top level of a query (or inside a then block) and referenced anywhere in the query using {"placeholder": "name"}.
{
"action": "select",
"placeholders": {
"name": "Picard"
},
"path": ["name", "family", {"placeholder": "name"}]
}
Placeholders can themselves reference other placeholders:
{
"action": "select",
"placeholders": {
"name": "Picard",
"family_match": {
"value": {"placeholder": "name"},
"case-sensitive": false,
"collapse": true
}
},
"path": ["name", "family", {"placeholder": "family_match"}]
}
Scoping and Inheritance GitHub issue
Placeholders defined in an outer query are inherited by all nested then blocks. An inner then block may define its own placeholders that shadow inherited ones with the same name. There is no mechanism to explicitly remove an inherited placeholder — only shadowing is possible.
{
"action": "select",
"placeholders": {"rank": "Captain"},
"path": ["rank", {"placeholder": "rank"}],
"then": {
"placeholders": {"rank": "Commander"},
"path": ["rank", {"placeholder": "rank"}]
}
}
Placeholder Validation GitHub issue
Placeholder validation runs without executing the query. Only checks that can be performed statically are included — errors that would only surface at runtime (e.g. a placeholder never reached due to short-circuit evaluation) are not reported.
engine.validate(query) # shorthand for run_all
engine.validator.run_all(query) # runs all validation methods
engine.validator.placeholders(query) # placeholder checks only
Rules GitHub issue
- Placeholders are resolved dynamically at the moment they are encountered during execution. There is no upfront resolution pass — placeholder values are looked up each time the placeholder is reached, not once at the start of the query.
- Circular references are an error only if the circular reference is actually reached.
- Referencing an undefined placeholder is an error only if it is actually reached.
- A placeholder never reached causes no error.
- Placeholders are local to the query and not reusable across separate queries.
- A placeholder may resolve to any JSON value.
create GitHub issue
vibecode
{"vibecode": { "section": "create", "role": "documents the create action: required bucket, optional class, engine-generated pk", "key_concepts": ["create", "bucket_required", "class_optional", "puck.uno/record_default", "engine_generated_pk"] }}
Creates a new record.
{
"action": "create",
"class": "foo.com/character",
"bucket": {"name": "Spock"}
}
Rules:
bucketis required and must be a JSON object. It holds the record's shared payload (no reserved keys).classis optional. If omitted ornull, the engine uses the default classpuck.uno/record. The engine wraps the supplied class in a platter and stores it as the only entry in the record'sclasseshash. A per-platter bucket is allocated empty.- The engine generates the
record_pkand the per-platter UUID. - Multi-platter records (a stack of classes) are constructed by passing
classes(an array of class names, or hash of platter records with preallocated per-platter buckets) instead of singularclass. Single-classcreateis the common case; multi-platter is for when the record is born with mix-ins already attached. - Successful response includes
success: trueand the newpkinresults.
update GitHub issue
vibecode
{"vibecode": { "section": "update", "role": "documents the update action: pk required, bucket required unless class-only change", "key_concepts": ["update", "pk_required", "bucket_required", "class_optional", "deleted_record_error"] }}
Updates an existing record.
{
"action": "update",
"pk": "92677339-df86-4f68-9397-999e40cf2c40",
"bucket": {"name": "Spock"}
}
Rules:
pkis required.bucketis required unless only changing the class.classis optional. If omitted, the class is unchanged.- Updating a deleted record is an error.
delete GitHub issue
vibecode
{"vibecode": { "section": "delete", "role": "documents soft-delete via tombstone; if_exists for idempotent deletes", "key_concepts": ["delete", "tombstone", "active_false", "if_exists", "idempotent", "historical_reads"] }}
Deletes a record by writing a tombstone version with active = false.
{
"action": "delete",
"pk": "92677339-df86-4f68-9397-999e40cf2c40"
}
Rules:
pkis required.if_exists: truemakes the delete idempotent — deleting an already-deleted or non-existent record returns success withdeleted: false.- The tombstone clears all business fields (
bucket,classes). - Deleted records are excluded from normal
selectqueries. - Historical reads at a cutoff timestamp may still return records that were active at that time.
Responses GitHub issue
vibecode
{"vibecode": { "section": "responses", "role": "documents the response format for success, warnings, and failure", "key_concepts": ["success", "errors", "warnings", "results", "non-fatal_warnings"] }}
Success GitHub issue
{"success": true, "results": {"pk": "92677339-df86-4f68-9397-999e40cf2c40"}}
Warnings GitHub issue
A response may include a warnings array alongside a successful result. Warnings indicate non-fatal issues — the query executed normally, but something about the request was redundant or suspicious.
{"success": true, "results": {...}, "warnings": [{"id": "redundant_fields", "details": {"fields": ["sort", "sorts"]}}]}
Failure GitHub issue
{
"success": false,
"errors": [
{"id": "invalid_request", "details": {"missing_fields": ["bucket"]}}
]
}
Transactions GitHub issue
vibecode
{"vibecode": { "section": "transactions", "role": "references the transaction model via transaction/commit/rollback actions", "key_concepts": ["transaction", "commit", "rollback", "transaction_model"] }}
Transactions are started with action: "transaction" and managed via commit and rollback. See the requirements document for the full transaction model.
Pass-through Fields GitHub issue
vibecode
{"vibecode": { "section": "pass_through_fields", "role": "documents misc and corporate as always-ignored top-level fields in Q0 requests", "key_concepts": ["misc", "corporate", "pass-through", "ignored_by_core_engines", "extension_metadata"] }}
misc and corporate are allowed at the top level of any Q0 request and are always ignored by core storage engines. Custom engines in a chain may use them for extension metadata.
Error IDs GitHub issue
vibecode
{"vibecode": { "section": "error_ids", "role": "reference table of all Q0 error ID strings and their meanings", "key_concepts": ["invalid_request", "class-not-found", "record_not_found", "record_deleted", "read-only-connection", "action-not-supported", "transaction-invalidated"] }}
| Error ID | Meaning |
|---|---|
invalid_request |
Malformed request (missing fields, wrong types, unknown fields) |
class-not-found |
Class path does not resolve to a known class |
record_not_found |
Target pk does not exist |
record_deleted |
Target record exists but is already deleted |
invalid-mode |
Syntactically invalid connection mode string |
mode-not-supported |
Valid mode string not supported by this engine |
read-only-connection |
Write action attempted on a read-only connection |
action-not-supported |
Action not implemented by this engine |
request-too-large |
Request exceeds engine-configured size limit |
transaction-not-found |
Unknown transaction id |
transaction-invalidated |
Transaction id invalidated by an ancestor rollback |