Queries

A query is a document that reads facts and gives rows. It writes nothing. A query needs find, and most queries add where.

Query execution measures CPU work on its thread, in 100-nanosecond ticks. Its budget includes planning, scans, expressions and result construction. Bounds describes the limits. The public API returns rows. Optional explain records give measurements for individual calls.

The examples with result blocks read these five entities. This merge patch creates them in a fresh database: Ada has ID 1, Bob 2, Cy 3, Dan 4 and Eve 5. The returned commit records these IDs for the patch's temporary names.

dust423B
#_ada {name   Ada
       role   engineer
       age    36
       dept   eng
       salary 120}
#_bob {name   Bob
       role   engineer
       age    41
       mentor {#link #_ada}
       dept   eng
       salary 100}
#_cy  {name   Cy
       role   designer
       age    29
       dept   sales
       salary 90}
#_dan {name   Dan
       dept   sales
       salary 70}
#_eve {name   Eve
       dept   ops
       salary 80}

Find and where

find gives the columns. where gives the clauses that bind them. A variable that appears in more than one clause joins those clauses.

dust114B
find    [?name ?sal]
where   [[?e dept ?dept]
         [?e salary ?sal]
         [?e name ?name]]
orderBy [?name]
Result / 111B
[{name Ada
  sal  120}
 {name Bob
  sal  100}
 {name Cy
  sal  90}
 {name Dan
  sal  70}
 {name Eve
  sal  80}]

Clauses

A where clause has one of these forms.

KindShapePurpose
Fact[?e field ?v]Matches stored facts
Member[member ?e field ?key ?v]Matches members of an object field
Negation[not [...]]Drops each solution that matches inside
Predicate[> ?v 5]Keeps each solution the expression accepts
Derivation[[expression] ?out]Binds a calculated value to a new variable
Schema[schema name ?e]Keeps entities that match a stored schema

A fact clause has an entity, a field and a value. Each position accepts a variable, a literal, or _ for a position that you do not read. An entity position also accepts an entity reference such as {#link 1}, the id of that entity. A fourth term binds the transaction of the fact.

A member clause reads each immediate member of an object field. It binds the member name as a string and the member value as stored. A sixth term can bind the transaction of the field.

dust66B
find  [?key ?artist]
where [[member ?track artists ?key ?artist]]

For example, this field has one member. Its name is a MusicBrainz GID. Its value is a link to artist entity 8306.

dust56B
artists {af1e76f062864cd4b4989a72a8df7de1 {#link 8306}}

If you do not need the member name, use _. A bound link value and a known field use the reference index for current reads. The engine then checks the current object to exclude removed or changed links.

dust159B
find  [?title]
where [[?artist
        name
        John Lennon]
       [member ?track artists _ ?artist]
       [?track track _]
       [?track name ?title]]

Member clauses accept objects. Arrays and tagged scalar values have no matching members. Two keys with the same value produce two matches. Use distinct true to remove repeated result rows. An ordinary fact clause still reads the complete field value.

A negation drops each solution that matches the clause inside it.

dust87B
find    [?name]
where   [[?e name ?name]
         [not [?e dept eng]]]
orderBy [?name]
Result / 33B
[{name Cy} {name Dan} {name Eve}]

A predicate keeps each solution that its expression accepts.

dust105B
find    [?name]
where   [[?e salary ?sal]
         [?e name ?name]
         [> ?sal 85]]
orderBy [?name]
Result / 33B
[{name Ada} {name Bob} {name Cy}]

A derivation calculates a value and binds it to a new variable. The expression comes first, and the new variable follows it.

dust122B
find    [?name ?double]
where   [[?e salary ?sal]
         [?e name ?name]
         [[* ?sal 2] ?double]]
orderBy [?name]
Result / 134B
[{name   Ada
  double 240}
 {name   Bob
  double 200}
 {name   Cy
  double 180}
 {name   Dan
  double 140}
 {name   Eve
  double 160}]

A schema clause keeps the entities whose current document matches a stored schema. It names the schema by its path below definitions/schemas, without a suffix. A stored schema supplies the validation rule.

Exact indexes

An exact index maps the values of a field to the entities that hold them. Stardust makes one for each field that a stored query or mutation compares with a value:

  • a fact clause with a constant or parameter value, such as [?e dept sales] or [?e dept ?dept] when ?dept is a parameter.
  • a =, <, <=, > or >= predicate on the value of a fact clause, such as [?e age ?age] with [>= ?age 18].
  • an in predicate on the value of a fact clause, with a list of constants or a list parameter. For example, [?e name ?name] with [in ?name ?names] reads only the listed values.

The database maintains exact indexes for fields that stored definitions or ad-hoc native runs compare. A scan gives the same rows while an index is not yet active. The engine tracks index status internally.

Parameters

A ?variable that no clause binds becomes a required input when only a predicate, a derivation or a having entry reads it. Stardust rejects an evaluation without a value for it.

dust109B
find    [?name]
where   [[?e salary ?sal]
         [?e name ?name]
         [> ?sal ?floor]]
orderBy [?name]

Error

Missing_Parameter

The caller gives the value with the query. With floor set to 95:

Result / 23B
floor
95
[{name Ada} {name Bob}]

A parameters block gives a default instead, which makes the input optional. A declaration key uses ?name, like every other binding.

dust147B
parameters {?floor 95}
find       [?name]
where      [[?e salary ?sal]
            [?e name ?name]
            [> ?sal ?floor]]
orderBy    [?name]
Result / 23B
[{name Ada} {name Bob}]

A variable that no clause binds, and that no predicate reads, is an error. In this query, no clause binds ?dept:

dust44B
find  [?name ?dept]
where [[?e name ?name]]

Error

Unbound_Variable

Result mode

A query gives one object for each row, keyed by the find columns. With resultMode positional, it gives one list for each row, in find order.

dust123B
find       [?name ?sal]
where      [[?e salary ?sal]
            [?e name ?name]]
orderBy    [?name]
resultMode positional
Result / 51B
[[Ada 120]
 [Bob 100]
 [Cy 90]
 [Dan 70]
 [Eve 80]]

Project shapes each row into a document instead. Grouping adds aggregates and window functions.

Run it

database query · query run.