Ordering and paging

Grouping calculates values over related rows. orderBy sets the order of those rows. distinct removes repeated rows. offset and limit cut a window from the ordered rows. page reads a long result in stable parts. Each example reads the same five entities as Queries.

Order

Each orderBy entry is a variable, or a variable with a direction. A variable without a direction uses ascending order. An entry can also be an expression. Stardust calculates it for each row and sorts the rows by the result.

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

asc and desc are the two directions. Several entries make several sort keys, and the first entry is the strongest.

dust127B
find    [?dept ?name]
where   [[?e dept ?dept]
         [?e salary ?sal]
         [?e name ?name]]
orderBy [?dept [?sal desc]]
Result / 118B
[{dept eng
  name Ada}
 {dept eng
  name Bob}
 {dept ops
  name Eve}
 {dept sales
  name Cy}
 {dept sales
  name Dan}]

Distinct

distinct true keeps the first row of each set of equal rows. It compares the find columns, and it respects the type of each value. The integer 1 and the number 1.0 are two different values.

Stardust can drop a repeated partial result during a where join. No later clause, find column or ordering key can read the distinguishing variables. Aggregates, grouping, windows and projection prevent this optimization. The result rows remain the same. A join that reaches one answer along many paths does the work once.

dust75B
find     [?dept]
where    [[?e dept ?dept]]
distinct true
orderBy  [?dept]
Result / 36B
[{dept eng} {dept ops} {dept sales}]

Offset and limit

offset and limit are counts of rows, and each one accepts 0 or more. Stardust applies them after orderBy and after distinct.

dust104B
find    [?name]
where   [[?e salary ?sal]
         [?e name ?name]]
orderBy [?name]
offset  2
limit   2
Result / 22B
[{name Cy} {name Dan}]

Pages

page reads a long result in parts. It has size, the number of rows in one page, and an optional after, the cursor of the page before it.

dust101B
find    [?name]
where   [[?e salary ?sal]
         [?e name ?name]]
orderBy [?name]
page    {size 2}
Result / 23B
[{name Ada} {name Bob}]

The reply carries hasMore. While more rows exist, it also carries nextCursor. The next page gives that cursor as after.

Copy the first page's cursor into the next query's page.after string. Stardust generates its value at runtime. It is not an entity name. Do not reuse a literal from this article.

A cursor holds the last row of the page and a fingerprint of the query. The fingerprint covers every part of the query except page. A cursor from a different query is Cursor_Mismatch, and a cursor that Stardust cannot open is Invalid_Cursor.

dust130B
find    [?name]
where   [[?e salary ?sal]
         [?e name ?name]]
orderBy [?name]
page    {size  2
         after not-a-cursor}

Error

Invalid_Cursor

When a page is rejected

A page boundary needs a total order, and it cannot share a query with the other window clauses.

ConditionReason
page without orderByA stable boundary needs a total order
page with limitlimit cuts the rows that page divides
page with offsetoffset moves the boundary of each page
page {size 0}size accepts 1 or more
page with projectA projected shape has no row boundary

Each of these conditions gives one error. This query has page and limit:

dust111B
find    [?name]
where   [[?e salary ?sal]
         [?e name ?name]]
orderBy [?name]
page    {size 2}
limit   2

Error

Invalid_Page

Bounds and history covers the limits on the work of a query.

Run it

database query · query run.