Lua Integrated Query (LIQ) is a SilverBullet specific Lua extension. It adds a convenient query syntax to the language in a backwards compatible way. It does so by overloading Lua’s default function call + single argument syntax when using query as the function call. As a result, Lua programs using LIQ are still syntactically valid Lua.
The syntax for LIQ is query[my query](my query). In regular Lua [my query](my query) is just another way of writing "my query" (it is an alternative string syntax). Function calls that only take a string argument can omit parentheses, therefore query[my query](my query) is equivalent to query("my query").
However, in Space Lua it interpreted as an SQL (and LINQ)-inspired integrated query language.
General syntax:
query[
from <var> in <expression>
where <expression>
order by <expression>
limit <expression>, <expression>
select <expression>
](
from <var> in <expression>
where <expression>
order by <expression>
limit <expression>, <expression>
select <expression>
)
LIQ operates on any Lua collection.
For instance, to sort a list of numbers in descending order: ${queryfrom n = {1, 2, 3} order by n desc}
However, in most cases you’ll use it in conjunction with API/index#index.tag(name). Here’s an example querying the 3 pages that were last modified:
${query from p = index.tag "page" order by p.lastModified desc select p.name limit 3}
Note that the query returns a regular Lua table, so it can be part of a bigger expression:
${some(query from p = index.tag "page" limit 0) or "Matched no pages"}
Here are the clauses that are currently supported:
The from clause specifies the source of your data. There are two syntactic variants:
Recommended: With explicit variable binding:
from v = <<expression>>
binding each item to the variable v.
However, there is also the more concise:
from <<expression>>
implicitly binding each item to the variable _ as well as making all attributes directly available as variables. The latter, while shorter, is less performant and will block future optimizations, so the variable-binding variant is preferred.
warning Warning When you use a
fromclause without explicit variable binding (so without theev insyntax), note that any attribute of the object you’re iterating over will shadow global variables. For instance, if you have an object with atableattribute, regulartableAPIs will become inaccessible within the query.Recommendation: Use the explicit variable binding syntax
Example without variable binding: ${queryfrom {1, 2, 3} select _}
With variable binding: ${queryfrom n = {1, 2, 3} select n}
A more realistic example using index.tag:
${queryfrom p = index.tag "page" order by p.lastModified select p.name limit 3}
The where clause allows you to filter data. When the expression evaluated to a truthy value, the item is included in the result.
Example:
${queryfrom n = {1, 2, 3, 4, 5} where n > 2}
Or to select 5 pages tagged with #meta:
${queryfrom p = index.tag "page" where table.includes(p.tags, "meta") limit 5 limit 5)}
Or select based on name (including folder) and a API/string|string function
${queryfrom p = index.tag "page" where p.name:startsWith("Person"))}
The order by clause allows you to sort data, when desc is specified it reverts the sort order.
As an example, the last 3 modified pages: ${query from p = index.tag "page" order by p.lastModified desc select p.name limit 3}
You can order based on multiple expressions by specifying multiple expressions separated by commas:
${query from p = index.tag "page" order by p.lastModified desc, p.name select p.name limit 3}
Sorting of strings can be adjusted with queryCollation in ^Library/Std/Config
The limit clause allows you to limit the number of results, optionally with an offset.
Example:
${queryfrom {1, 2, 3, 4, 5} limit 3}
You can also specify an offset to skip some results:
${queryfrom {1, 2, 3, 4, 5} limit 3, 2}
The select clause allows you to transform each item in the result set. If omitted, it defaults to returning the item itself.
Some examples:
Double each number: ${queryfrom n = {1, 2, 3} select n * 2}
It is convenient to combine it with the API/table#table.select(table, keys...) API: ${query from p = index.tag "page" select table.select(p, "name", "lastModified") limit 3 limit 3 )}
To render the output as a template, you can rely on the fact that queries return Lua tables. For example, to apply a template to render every page as a link:
${template.each(query from p = index.tag "page" order by p.lastModified desc limit 3, templates.pageItem)}
To render pages as links with their full local URL, use templates.fullPageItem. For more information on available templates, see ^Library/Std/Infrastructure/Query Templates.