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.

json227 B
{
  "find": [
    "?name",
    "?sal"
  ],
  "where": [
    [
      "?e",
      "salary",
      "?sal"
    ],
    [
      "?e",
      "name",
      "?name"
    ]
  ],
  "orderBy": [
    [
      "?sal",
      "desc"
    ]
  ]
}
Result / 213 B
[
  {
    "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.

json294 B
{
  "find": [
    "?dept",
    "?name"
  ],
  "where": [
    [
      "?e",
      "dept",
      "?dept"
    ],
    [
      "?e",
      "salary",
      "?sal"
    ],
    [
      "?e",
      "name",
      "?name"
    ]
  ],
  "orderBy": [
    "?dept",
    [
      "?sal",
      "desc"
    ]
  ]
}
Result / 235 B
[
  {
    "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.

json154 B
{
  "find": [
    "?dept"
  ],
  "where": [
    [
      "?e",
      "dept",
      "?dept"
    ]
  ],
  "distinct": true,
  "orderBy": [
    "?dept"
  ]
}
Result / 85 B
[
  {
    "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.

json217 B
{
  "find": [
    "?name"
  ],
  "where": [
    [
      "?e",
      "salary",
      "?sal"
    ],
    [
      "?e",
      "name",
      "?name"
    ]
  ],
  "orderBy": [
    "?name"
  ],
  "offset": 2,
  "limit": 2
}
Result / 55 B
[
  {
    "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.

json219 B
{
  "find": [
    "?name"
  ],
  "where": [
    [
      "?e",
      "salary",
      "?sal"
    ],
    [
      "?e",
      "name",
      "?name"
    ]
  ],
  "orderBy": [
    "?name"
  ],
  "page": {
    "size": 2
  }
}
Result / 56 B
[
  {
    "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.

json248 B
{
  "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:

json233 B
{
  "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.