Skip to main content

Crate slipql

Crate slipql 

Source
Expand description

§slipql

A query language for Slipcase metadata. Point it at a directory of .slpc containers and ask questions in select, from, and where: each container is a row, each metadata key a column.

$ slipql ./contracts --recursive
Connected to: ./contracts (recursive). Type "help" for commands, "quit" to exit.

slipql> select @path, title, governance.owner where status = "draft" or tags contains "legal"
| @path                  | title                     | governance.owner |
| ---------------------- | ------------------------- | ---------------- |
| 2026/renewal.docx.slpc | Renewal, 2026             |                  |
| msa.pdf.slpc           | Master services agreement | Kim              |
| q3.xlsx.slpc           | Q3 report                 | Lee              |
(3 rows)

§Why

A Slipcase container carries a TOML document describing its payload, and that description travels with the file. Once a directory holds a few hundred of them, the question stops being “what is in this file” and becomes “which files say this”. Unpacking every container to find out, or keeping an index that goes stale the moment someone copies a file in, both defeat the point of metadata that lives with the document.

slipql reads each container’s metadata in place, through the same library the slipcase command uses, and never unpacks a payload. It keeps no index and no state: every query is a fresh scan, so the answer is what is on disk now. It changes nothing.

The language borrows SQL’s clause shape and TOML’s literals, so anyone who can write a metadata document can write a query against one without learning a second date syntax or a second way to quote a string.

§Install

§Debian and Ubuntu

Add the Excelano apt repository once:

curl -fsSL https://excelano.com/apt/setup.sh | sudo sh

Then install it, so apt upgrade keeps it current:

sudo apt install slipql

§Homebrew

brew install excelano/tap/slipql

§crates.io

cargo install slipql

§Windows

winget install Excelano.slipql

§The command

slipql <dir> opens a prompt bound to a directory, so queries can leave out from. Add --recursive to descend into subdirectories. --exec runs one query and exits, and a query on standard input runs without a prompt, one per line, which is how a script uses it:

slipql ./contracts -r -e 'select title, signed where signed >= 2026-01-01' --mode csv > signed.csv

Output is a table at a terminal and tab-separated in a pipe; --mode picks table, tsv, csv, or json explicitly. CSV output is meant as a feed for the rest of the tabular family, xled among them. JSON keeps TOML’s types where JSON has them. A container that cannot be read is skipped and reported on standard error after the rows, as is any comparison the query made across types, so a pipe stays clean and nothing is silently ignored.

slipql --help states the flags and the exit status contract.

§The language

select <columns> from '<dir>' [recursive] [where <condition>] [limit <n>]

Columns are metadata keys, with dots into nested tables and [n] into arrays: governance.privacy_flag, tags[0]. @path is the container’s path under the from directory. select * gives @path and then every leaf value across the rows returned, as dotted columns. A column a row does not have renders empty rather than failing the query, because metadata keys are ad hoc by design.

Conditions compare a column with a literal using =, !=, <, >, <=, and >=, test membership with in (...), match strings with like and ilike, look inside arrays with contains, and test for a key with exists. Combine with and, or, not, and parentheses. Literals are TOML’s: "strings" or 'literal strings', 42, 1.5, true, and datetimes as TOML writes them, 2026-01-01 or 2026-01-01T09:00:00+02:00.

Keywords are lowercase. TOML has no null, so there is no is null; a key is present or it is absent, and exists is the one test for that. Comparing a column that is absent, or one whose type does not match the literal, is neither true nor false and does not select the row. Values compare within their type: integers with floats, strings with strings, each of TOML’s four datetime forms with itself, and offset datetimes as instants. There is no coercion between strings and numbers, on purpose, since a "3" where a 3 was meant is a mistake worth seeing rather than one worth hiding.

GRAMMAR.md is the exact grammar and the semantics of every operator.

§The library

The crate is the query engine, and the command is a thin shell over it. A program that embeds it takes the crate with default-features = false, which leaves out the command’s own dependencies.

use slipql::{execute, parse};

fn main() -> slipql::Result<()> {
    let query = parse("select @path, title from '.' recursive where exists title")?;
    let mut results = execute(&query)?;
    for row in results.by_ref() {
        println!("{}: {:?}", row.path, row.cells[1].value);
    }
    for skipped in results.tally().skipped() {
        eprintln!("skipped {}: {}", skipped.path.display(), skipped.reason);
    }
    Ok(())
}

Rows come out of an iterator as the scan reaches them, so a query over a large tree starts answering at once, limit stops the scan early, and dropping the iterator cancels it. Once the rows are out, the tally says what was skipped and which comparisons crossed types. docs.rs/slipql is the library’s own page.

§License

MIT. See LICENSE.

Re-exports§

pub use slpc;

Modules§

ast
The shape of a parsed query.
render
Rows to text: a table for a terminal, CSV and TSV for a pipe, JSON for anything that wants the types kept.

Structs§

Cell
One cell of a row.
Options
Knobs for a run.
Results
The rows of a running query, produced as the scan reaches them.
Row
One result row.
Skipped
A file or directory the scan could not use.
Tally
Everything a scan noticed on the way.

Enums§

Error
The ways a query can fail before or while it runs.
Kind
The type of a value, at the granularity comparison cares about.
Value
A value read from metadata or written in a query.

Functions§

execute
Run a query with default options.
execute_with
Run a query.
parse
Parse a query. from is required.
parse_with
Parse a query, supplying the from clause when the text omits one.

Type Aliases§

Result
Every fallible operation in this crate returns this.