Qwiratry — SQL-AST-Qwiratry-Mapping
SQL AST ↔ Qwiratry mapping
Extracted from SQL-AST-Comparison.md §3 (AST object comparison). Side-by-side mapping of SQL constructs to Red, SQL::Abstract, Qwiratry Query AST, RakuAST, and (where both SQL ASTs lack a node) SQL Mapping.
AST object comparison
For each SQL construct, the concrete AST type (or role) each library uses. — = no dedicated node; behaviour may still exist via driver defaults, projection tricks, model metadata, or runtime Raku code.
Qwiratry today is the Query AST (Qwiratry::Operator::* classes, all
RakuAST::Node descendants). There is no separate SQL AST yet (planned in
TOP plan §12.1). Filters and join conditions are Raku Blocks / callables,
not structured expression nodes.
RakuAST column lists compiler AST equivalents only where a row’s SQL-ish
construct maps to ordinary Raku expression or statement forms (typically
predicates inside mold when blocks). Empty where there is no meaningful
RakuAST counterpart at that abstraction level.
SQL Mapping is filled only for rows where both Red and SQL::Abstract
have no AST node (—): how that item can still show up in actual SQL
(keyword, encode-as-pattern, or “not SQL”).
| Represented item | Red | SQL::Abstract | Qwiratry | RakuAST | SQL Mapping | ||
|---|---|---|---|---|---|---|---|
| AST root | Red::AST (role) | SQL::Abstract::Expression / SQL::Abstract::Query roles | RakuAST::Node (all Qwiratry::Operator::*::*Operator classes) | RakuAST::Node | — | ||
| Clause chain bag | Red::AST::Chained (filter, order, group, limit, offset, table-list) | fields on each query class (via SQL::Abstract::Query::Common) | Qwiratry::Operator::Capability::ChainedOperator $.subject pipeline | — | — | ||
| SELECT | Red::AST::Select | SQL::Abstract::Select | composed operator pipeline (no Select root); read entry often Qwiratry::Operator::IO::SourceOperator (functionally ≈ SELECT) | — | — | ||
| INSERT | Red::AST::Insert | SQL::Abstract::Insert::Values, SQL::Abstract::Insert::Select, SQL::Abstract::Insert::Defaults | write sink Qwiratry::Operator::IO::OverwriteDestinationOperator / Destination family (among CREATE/INSERT/UPDATE/DELETE) | — | — | ||
| UPDATE | Red::AST::Update | SQL::Abstract::Update | write sink Qwiratry::Operator::IO::OverwriteDestinationOperator / Destination family (among CREATE/INSERT/UPDATE/DELETE) | — | — | ||
| DELETE | Red::AST::Delete | SQL::Abstract::Delete | write sink Qwiratry::Operator::IO::OverwriteDestinationOperator / Destination family (among CREATE/INSERT/UPDATE/DELETE) | — | — | ||
| UPSERT / ON CONFLICT | — | SQL::Abstract::Conflicts, SQL::Abstract::Conflict::Update, SQL::Abstract::Conflict::Nothing, SQL::Abstract::Conflict::Target::* on SQL::Abstract::Insert | — | — | — | ||
| UNION / INTERSECT / EXCEPT | Red::AST::Union, Red::AST::Intersect, Red::AST::Minus (Red::AST::MultiSelect) | SQL::Abstract::Compound on SQL::Abstract::Select | Qwiratry::Operator::Set::UnionOperator, Qwiratry::Operator::Set::IntersectionOperator, Qwiratry::Operator::Set::SetDifferenceOperator | — | — | ||
| VALUES (inline relation) | — | SQL::Abstract::Values | — | — | — | ||
| CREATE TABLE | Red::AST::CreateTable | — | write sink Qwiratry::Operator::IO::OverwriteDestinationOperator / Destination family (among CREATE/INSERT/UPDATE/DELETE) | — | — | ||
| CREATE VIEW | Red::AST::CreateView | — | reusable named join ≈ Qwiratry::Operator::Set::NamedJoinOperator + Qwiratry::Query::NamedJoins (see Named join recall) | — | — | ||
| ADD / CHANGE / DROP COLUMN | Red::AST::CreateColumn, Red::AST::ChangeColumn, Red::AST::DropColumn | — | write sink Qwiratry::Operator::IO::OverwriteDestinationOperator / Destination family (schema change / DDL write) | — | — | ||
| ADD FOREIGN KEY | Red::AST::AddForeignKeyOnTable | — | — | — | — | ||
| BEGIN / COMMIT / ROLLBACK | Red::AST::BeginTransaction, Red::AST::CommitTransaction, Red::AST::RollbackTransaction | — | — | — | — | ||
| Column reference | Red::Column (also does Red::AST) | SQL::Abstract::Identifier | Qwiratry::Operator::Navigation::AttributeOperator (⥷); column keys in selectors | RakuAST::Var::Lexical, RakuAST::Postcircumfix::* | — | ||
| Table reference | Red::Model in Red::AST::Select.of / @.table-list | SQL::Abstract::Table::Simple, SQL::Abstract::Table::Renamed | Qwiratry::Operator::IO::SourceOperator, Qwiratry::Operator::Navigation::ChildOperator on table | — | — | ||
| Literal value | Red::AST::Value | SQL::Abstract::Literal | values in predicate/join Blocks at runtime | RakuAST::IntLiteral, RakuAST::StrLiteral, RakuAST::NumLiteral, … | — | ||
| Bind placeholder | Red::AST::Value / unary·infix $.bind | SQL::Abstract::Placeholder | — | RakuAST::Var::Lexical (in compiled blocks) | — | ||
| Function call | Red::AST::Function | SQL::Abstract::Function | calls inside predicate/join Blocks | RakuAST::Call::Name, RakuAST::Call::Method, … | — | ||
Column alias (AS) | projection via map / @.fields | SQL::Abstract::Expression::Renamed | Qwiratry::Operator::Set::RenameOperator (ρ) | — | — | ||
* in projection | model column expansion | SQL::Abstract::Star | Qwiratry::Operator::Set::ProjectionOperator with columns list = all column keys (expanded before execution); wildcard selectors often use * / Whatever | RakuAST::Term::Whatever | — | ||
| WHERE | Red::AST on Red::AST::Select/Red::AST::Chained $.filter | SQL::Abstract::Conditions on SQL::Abstract::Select $.where | Qwiratry::Operator::MapReduce::SelectionOperator (σ, &predicate) | RakuAST::Block / expression subtree | — | ||
| AND / OR | Red::AST::AND, Red::AST::OR | SQL::Abstract::Op::And, SQL::Abstract::Op::Or (in SQL::Abstract::Conditions) | inside &predicate Block | RakuAST::ApplyInfix (&&/` | , and/or`) | — | |
| NOT | Red::AST::Not | SQL::Abstract::Op::Not | inside &predicate Block | RakuAST::ApplyPrefix (!, not) | — | ||
Comparisons (=, <, …) | Red::AST::Eq, Red::AST::Lt, Red::AST::Gt, Red::AST::Le, Red::AST::Ge, Red::AST::Ne | SQL::Abstract::Op::Equals, SQL::Abstract::Op::LessThan, SQL::Abstract::Op::GreaterThan, … | inside &predicate Block | RakuAST::ApplyInfix (==, <, >, …) | — | ||
| LIKE | Red::AST::Like | SQL::Abstract::Op::Like, SQL::Abstract::Op::NotLike | inside &predicate Block | RakuAST::ApplyInfix (~~) + RakuAST::QuotedRegex, or RakuAST::Call::Method | — | ||
| IN (value list) | Red::AST::In | SQL::Abstract::Op::In::List | Qwiratry::Operator::Set::ElementOfOperator (∈); also in Block | RakuAST::ApplyInfix (∈, ~~) + list / junction | — | ||
| IN / EXISTS (subquery) | Red::AST::In + nested Red::AST::Select | SQL::Abstract::Op::In::Query, SQL::Abstract::Op::Exists | nested operator trees | — | — | ||
| BETWEEN | Red::AST::Between | SQL::Abstract::Op::Between, SQL::Abstract::Op::NotBetween | inside &predicate Block | RakuAST::ApplyInfix (..) or chained comparisons | — | ||
| IS NULL / definedness | Red::AST::IsDefined | SQL::Abstract::Op::IsNull | inside &predicate Block | RakuAST::ApplyPrefix + .defined, or RakuAST::Type::Definedness | — | ||
| CASE | Red::AST::Case | SQL::Abstract::Op::Case | inside &predicate Block | RakuAST::Ternary, or RakuAST::Statement::If chain | — | ||
| CAST | Red::AST::Cast | SQL::Abstract::Op::Cast | inside &predicate Block | RakuAST::Type::Coercion, RakuAST::Call::Method (.Int, …) | — | ||
| JSON path ops | Red::AST::JsonItem, Red::AST::JsonRemoveItem | SQL::Abstract::Op::JSON::GetElem, SQL::Abstract::Op::JSON::GetElemText, SQL::Abstract::Op::JSON::GetPath, SQL::Abstract::Op::JSON::GetPathText | inside &predicate Block; structured JSON via Qwiratry::Operator::IO::ParseOperator / RenderOperator (parse = treat as document; render = serialize back) | RakuAST::Postcircumfix::LiteralHashIndex, RakuAST::Postcircumfix::HashIndex | — | ||
| XML path ops | — | — | inside &predicate Block; structured XML via Qwiratry::Operator::IO::ParseOperator / RenderOperator (parse = treat as document; render = serialize back); tree navigation axes often apply | — | dialect XML/XPath (xpath, XMLEXTRACT, XMLQUERY, …) when the column is treated as a document, not opaque text | ||
| Arithmetic / concat | Red::AST::Sum, Red::AST::Sub, Red::AST::Mul, Red::AST::Div, Red::AST::Concat, … | SQL::Abstract::Op::Plus, SQL::Abstract::Op::Minus, SQL::Abstract::Op::Times, SQL::Abstract::Op::Concat, … | inside &predicate Block | RakuAST::ApplyInfix, RakuAST::ApplyPrefix, RakuAST::ApplyPostfix | — | ||
| Generic operator | Red::AST::Generic::Infix, Red::AST::Generic::Prefix, Red::AST::Generic::Postfix | typed SQL::Abstract::Op::* hierarchy | inside &predicate Block | RakuAST::ApplyInfix, RakuAST::ApplyPrefix, RakuAST::ApplyPostfix, RakuAST::ApplyListInfix | — | ||
| FROM / joined tables | @.table-list + primary $.of (Red::Model) | SQL::Abstract::Source (SQL::Abstract::Table, SQL::Abstract::Join, …) | Qwiratry::Operator::IO::SourceOperator + join operator tree | — | — | ||
| JOIN … ON | join metadata on joined Red::Model entries | SQL::Abstract::Join::On | Qwiratry::Operator::Set::InnerJoinOperator, … + Qwiratry::Operator::Set::JoinOperatorNode $.condition | RakuAST::Block (join condition) | — | ||
| JOIN … USING | — | SQL::Abstract::Join::Using | — | — | — | ||
| NATURAL / CROSS JOIN | — | SQL::Abstract::Join::Natural, SQL::Abstract::Join::Cross | Qwiratry::Operator::Set::NaturalJoinOperator, Qwiratry::Operator::Set::CrossJoinOperator | — | — | ||
| Subquery in FROM | Red::AST::Select (:sub-select) | SQL::Abstract::Source::Query | nested operator pipeline | — | — | ||
| GROUP BY | @.group on Red::AST::Select/Red::AST::Chained | SQL::Abstract::GroupBy | — (Qwiratry::Operator::MapReduce::ReduceOperator approximates aggregation only) | — | — | ||
| HAVING | — | SQL::Abstract::Conditions on SQL::Abstract::Select $.having | no dedicated node; same as Qwiratry::Operator::MapReduce::SelectionOperator (σ / grep) applied after grouping/aggregation (WHERE is σ before) — Qwiratry has no first-class GROUP BY, so HAVING is only a pipeline-position distinction | — | — | ||
| DISTINCT | Red::AST::Function (func<DISTINCT>) in projection | SQL::Abstract::Distinction, SQL::Abstract::Distinction::Columns on SQL::Abstract::Select | no UniqueOperator; not what ReduceOperator (⌿) does (fold → one accumulator). Approximable by reducing into a set, or by set-algebra pipelines, but not first-class DISTINCT | — | — | ||
| ORDER BY | @.order (Red::AST / Red::Column) | SQL::Abstract::OrderBy, SQL::Abstract::Order::Modifier | Qwiratry::Operator::MapReduce::SortOperator (⇅) | — | — | ||
| LIMIT / OFFSET | Int on Red::AST::Select/Red::AST::Chained | SQL::Abstract::Limit, SQL::Abstract::Offset | — | — | — | ||
CTE (WITH) | — | SQL::Abstract::Common (+ SQL::Abstract::Query::Common $.common) | — | — | — | ||
| Window definition / use | — | SQL::Abstract::Window::Clauses, SQL::Abstract::Window::Definition, SQL::Abstract::Window::Function | — | — | — | ||
Row locking (FOR UPDATE, …) | Red::LockType on Red::AST::Select $.for | SQL::Abstract::Locking, SQL::Abstract::Locking::Clause | — | — | — | ||
| RETURNING | driver emit context (e.g. "delete-returning") | SQL::Abstract::Column::List on DML queries | — | — | — | ||
| String functions | Red::AST::Substring, Red::AST::Index, Red::AST::Lowercase, Red::AST::Uppercase | SQL::Abstract::Function | inside Block | RakuAST::Call::Method | — | ||
| Date/time functions | Red::AST::DateTimePart, Red::AST::DateTimeCoerce, Red::AST::DateTimeNow, Red::AST::DateTimeToday | SQL::Abstract::Function, SQL::Abstract::Current | inside Block | RakuAST::Call::Name, RakuAST::Call::Method | — | ||
| PK / table constraints | Red::AST::Pk, Red::AST::Constraint | — | Qwiratry::Table::Catalog, Qwiratry::Table::ForeignKey (metadata, not query nodes) | — | — | ||
| SQL comments | Red::AST::Comment, Red::AST::TableComment | — | — | — | — | ||
| Custom / escape SQL | — | SQL::Abstract::Expression::Custom | — | — | — | ||
| Map / transform rows | via map / Red::ResultSeq | — | Qwiratry::Operator::MapReduce::AggMapOperator (⇶) | — | — | ||
| Aggregate / fold | via classify / aggregates | — | Qwiratry::Operator::MapReduce::ReduceOperator (⌿) | — | — | ||
| Projection (column pick) | @.fields / map | SQL::Abstract::Column::List | Qwiratry::Operator::Set::ProjectionOperator (Π) | — | — | ||
| Navigation axes (⪪ ⪫ ⪪⪪ …) | — | — | Qwiratry::Operator::Navigation::ChildOperator, Qwiratry::Operator::Navigation::ParentOperator, Qwiratry::Operator::Navigation::DescendantOperator, Qwiratry::Operator::Navigation::AncestorOperator, Qwiratry::Operator::Navigation::FollowingSiblingOperator, Qwiratry::Operator::Navigation::PrecedingSiblingOperator, Qwiratry::Operator::Navigation::FollowingOperator, Qwiratry::Operator::Navigation::PrecedingOperator, Qwiratry::Operator::Navigation::RootOperator (⇤) | — | FK follow ≈ joins; hierarchy ≈ recursive CTE / CONNECT BY; siblings/following ≈ LAG/LEAD or ordered self-joins (not XPath-style first-class axes) | ||
| Equijoin / outer / semijoin / antijoin | via model join metadata | SQL::Abstract::Join::* variants | Qwiratry::Operator::Set::EquijoinOperator, Qwiratry::Operator::Set::LeftOuterJoinOperator, Qwiratry::Operator::Set::RightOuterJoinOperator, Qwiratry::Operator::Set::FullOuterJoinOperator, Qwiratry::Operator::Set::LeftSemijoinOperator, Qwiratry::Operator::Set::RightSemijoinOperator, Qwiratry::Operator::Set::LeftAntijoinOperator, Qwiratry::Operator::Set::RightAntijoinOperator | — | — | ||
| Named join recall (▵) | — | — | Qwiratry::Operator::Set::NamedJoinOperator + Qwiratry::Query::NamedJoins registry | — | reusable named join ≈ CREATE VIEW (or a named CTE) wrapping the join (see CREATE VIEW) | ||
| Symmetric difference (⊖) | — | — | Qwiratry::Operator::Set::SymmetricDifferenceOperator | — | (A EXCEPT B) UNION (B EXCEPT A) (or EXCEPT ALL variants) | ||
| Membership / subset / identity (excluding IN/ElementOf) | — | — | Qwiratry::Operator::Set::ContainsOperator, Qwiratry::Operator::Set::SubsetOperator, Qwiratry::Operator::Set::SubsetOrEqualOperator, Qwiratry::Operator::Set::IdentityOperator | RakuAST::ApplyInfix (∋, (<=), eqv, …) | partial: set equality/containment via EXCEPT / INTERSECT / EXISTS / row comparisons (no first-class ⊆/≡) | ||
| Relational division (÷) | — | — | Qwiratry::Operator::Set::DivisionOperator | — | classic algebra; expressible with nested NOT EXISTS / grouping — no DIVIDE keyword | ||
| Power set (𝒫 / ℘) | — | — | Qwiratry::Operator::Set::PowerSetOperator | — | not SQL | ||
| Operator capability roles | — | — | Qwiratry::Operator::Capability::OperatorBase, Qwiratry::Operator::Capability::ChainedOperator, Qwiratry::Operator::Capability::LazyEvaluatedOperator, Qwiratry::Operator::Capability::EagerEvaluatedOperator, Qwiratry::Operator::Capability::MapReduceOperator, Qwiratry::Operator::Capability::SetOperator, Qwiratry::Operator::Capability::NavigationOperator, Qwiratry::Operator::Set::JoinOperatorNode, Qwiratry::Operator::Capability::IOOperator, Qwiratry::Operator::Capability::FormatOperator, Qwiratry::Operator::Capability::LocationOperator, … | — | not SQL (Walker/operator metadata) |
Red spreads SELECT clauses across Red::AST::Select and a linked
Red::AST::Chained bag on Red::ResultSeq; Abstract keeps them as typed
fields on SQL::Abstract::Select (and siblings). Red joins are not separate
AST nodes — joined tables appear as Red::Model-shaped entries in
@.table-list with join type/on supplied via model metaclass. Abstract models
joins explicitly as SQL::Abstract::Join::* implementing
SQL::Abstract::Source.
Qwiratry expresses queries as a tree of operator nodes chained by
Qwiratry::Operator::Capability::ChainedOperator.subject, with σ/Π/ρ and join
operators covering much of relational algebra plus navigation and I/O layers.
Expression-level SQL (comparisons, CASE, CAST, …) lives in compiled Raku
blocks today rather than in the Query AST itself; the RakuAST column shows
what those blocks lower to when extracted from mold source.
Type-name prefixes in the table: Red::*, SQL::Abstract::* (nested in the
SQL::Abstract unit class), Qwiratry::Operator::* / Qwiratry::Table::* /
Qwiratry::Query::*, and RakuAST::*.