use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum Role {
Source,
Search,
Bound,
Order,
Count,
Aggregate,
Shape,
Group,
Target,
Measure,
StageNotYet,
JqKeyword,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum Status {
Served,
NotYet,
}
#[derive(Debug, Serialize)]
pub struct Word {
pub name: &'static str,
pub role: Role,
pub status: Status,
pub arguments: &'static [&'static str],
pub meaning: &'static str,
#[serde(skip)]
pub refusal: Option<&'static str>,
}
const fn served(
name: &'static str,
role: Role,
arguments: &'static [&'static str],
meaning: &'static str,
) -> Word {
Word {
name,
role,
status: Status::Served,
arguments,
meaning,
refusal: None,
}
}
const fn reserved_stage(
name: &'static str,
arguments: &'static [&'static str],
meaning: &'static str,
refusal: &'static str,
) -> Word {
Word {
name,
role: Role::StageNotYet,
status: Status::NotYet,
arguments,
meaning,
refusal: Some(refusal),
}
}
pub const WORDS: &[Word] = &[
served(
"collection",
Role::Source,
&["name: a nonempty collection name in double quotes"],
"Read records from the named collection, including names that cannot be written bare.",
),
served(
"and",
Role::JqKeyword,
&[
"source: join field equalities inside collection arguments",
"jq: combine two boolean expressions",
],
"Join collection equalities or combine boolean expressions inside quoted jq.",
),
served(
"similar",
Role::Search,
&[
"field: a top-level vector field with a leading dot",
"question: double-quoted text or record(\"id\")",
"measure: cosine, l2 or dot",
],
"Search by vector similarity first after its source or later over the records that reached it.",
),
served(
"record",
Role::Target,
&["id: a record id in double quotes"],
"Use the stored vector of the named record as the similarity question.",
),
served(
"limit",
Role::Bound,
&["n: a whole number from 1 to 4294967295"],
"Stop the upstream after at most n records or values at this point in the pipeline.",
),
served(
"sort",
Role::Order,
&[
"field: a top-level field with a leading dot",
"direction: optional desc after a semicolon",
],
"Order the whole upstream by a field before the quoted jq stage.",
),
served(
"desc",
Role::Order,
&[],
"Order the sort field from greatest to least instead of ascending order.",
),
served(
"count",
Role::Count,
&[],
"Consume the whole upstream and answer its size as the last stage.",
),
served(
"cosine",
Role::Measure,
&[],
"Compare vectors by their cosine similarity.",
),
served(
"l2",
Role::Measure,
&[],
"Compare vectors by their Euclidean distance.",
),
served(
"dot",
Role::Measure,
&[],
"Compare vectors by their dot product.",
),
served(
"match",
Role::Source,
&[
"nodes: (binding:collection) or up to eight labelled nodes joined by directed relations",
"binding: distinct names matching [a-z_][a-z0-9_]*",
"relation: -[:kind]-> or <-[:kind]- at each of up to seven hops",
],
"Match a labelled collection or a fixed chain of directed relations first or immediately after its collection.",
),
served(
"rg",
Role::Search,
&[
"field: optional top-level field with a leading dot",
"pattern: a regular expression in double quotes",
"flags: optional quoted -i, -s, -S, -w, -x, -F, -v and -U switches and their long forms; --no-ignore-case resets case sensitivity; -U dot matches newlines",
],
"Keep whole records in order when their compact JSON or named field matches the pattern.",
),
served(
"grep",
Role::Search,
&[
"field: optional top-level field with a leading dot",
"pattern: a regular expression in double quotes",
"flags: optional quoted -i, -s, -S, -w, -x, -F, -v and -U switches and their long forms; --no-ignore-case resets case sensitivity; -U dot matches newlines",
],
"Alias of rg: keep whole records in order when their compact JSON or named field matches the pattern.",
),
served(
"rerank",
Role::Order,
&[
"field: a top-level vector field with a leading dot",
"question: double-quoted text or record(\"id\")",
"measure: cosine, l2 or dot",
],
"Drain the bounded upstream, reorder by vector score, replace scores and count unscored records last; no continuation.",
),
reserved_stage(
"sort_by",
&["expression: a sort key"],
"Reserve an unquoted sort_by stage that is not available yet.",
"a `sort_by` stage",
),
served(
"window",
Role::Bound,
&[
"from: an included unsigned version or quoted RFC 3339 instant",
"to: an excluded bound of the same form, or $now",
],
"Keep records by their revision append version, never by a time inside the record.",
),
served(
"group_by",
Role::Group,
&["field: a top-level field with a leading dot"],
"Drain records before jq into key, count and values groups in jq value order; missing fields group under null and no continuation is available.",
),
served(
"percentile",
Role::Aggregate,
&[
"field: a top-level numeric field with a leading dot",
"percentile: a number from 0 to 100 inclusive",
],
"Drain records before jq into one nearest-rank JSON number; empty numeric input gives null, zero selects the minimum, non-numbers are counted as skipped, and no continuation is available.",
),
served(
"{",
Role::Shape,
&[
"fields: bare names with nested selection sets",
"source: one or several collection roots in a first-stage shape",
],
"Keep selected fields in record order; a first-stage shape reads collections in root order before worker Input.",
),
served(
"as",
Role::JqKeyword,
&["pattern: bind a jq value to variables"],
"Bind values to variables within a quoted jq expression.",
),
served(
"def",
Role::JqKeyword,
&["name and parameters: the filter definition"],
"Define a reusable filter inside quoted jq.",
),
served(
"if",
Role::JqKeyword,
&["condition: the tested expression"],
"Start a conditional expression inside quoted jq.",
),
served(
"then",
Role::JqKeyword,
&["expression: the branch to evaluate"],
"Introduce a conditional branch inside quoted jq.",
),
served(
"elif",
Role::JqKeyword,
&["condition: an additional test"],
"Add another conditional test inside quoted jq.",
),
served(
"else",
Role::JqKeyword,
&["expression: the alternative branch"],
"Introduce the alternative branch inside quoted jq.",
),
served(
"end",
Role::JqKeyword,
&[],
"Close a conditional expression inside quoted jq.",
),
served(
"or",
Role::JqKeyword,
&["expressions: the boolean operands"],
"Combine boolean expressions by disjunction inside quoted jq.",
),
served(
"reduce",
Role::JqKeyword,
&["generator and accumulator: the reduction expressions"],
"Fold generated values into an accumulator inside quoted jq.",
),
served(
"foreach",
Role::JqKeyword,
&["generator, accumulator and output: the iteration expressions"],
"Fold generated values while emitting intermediate results inside quoted jq.",
),
served(
"in",
Role::JqKeyword,
&["container: the object or array to inspect"],
"Test whether the current key belongs to a container inside quoted jq.",
),
served(
"try",
Role::JqKeyword,
&["expression: the expression whose errors are caught"],
"Evaluate an expression with error handling inside quoted jq.",
),
served(
"catch",
Role::JqKeyword,
&["expression: the error handler"],
"Handle an error from a try expression inside quoted jq.",
),
served(
"label",
Role::JqKeyword,
&["name: a label variable"],
"Name a control-flow boundary inside quoted jq.",
),
served(
"break",
Role::JqKeyword,
&["name: the label to exit"],
"Exit a named control-flow boundary inside quoted jq.",
),
served(
"module",
Role::JqKeyword,
&["metadata: a JSON object"],
"Declare module metadata inside a jq program.",
),
served(
"import",
Role::JqKeyword,
&["path and alias: the module to load"],
"Import a module under an alias inside a jq program.",
),
served(
"include",
Role::JqKeyword,
&["path: the module to load"],
"Include a module directly inside a jq program.",
),
served(
"true",
Role::JqKeyword,
&[],
"Produce the boolean true inside quoted jq or a collection argument.",
),
served(
"false",
Role::JqKeyword,
&[],
"Produce the boolean false inside quoted jq or a collection argument.",
),
served(
"null",
Role::JqKeyword,
&[],
"Produce the null value inside quoted jq or a collection argument.",
),
];
pub(super) fn reserved(name: &str) -> Option<&'static str> {
WORDS
.iter()
.find(|word| word.name == name && word.status == Status::NotYet)
.and_then(|word| word.refusal)
}