THE INCQL BOOK
1. Read a typed relation
Create a Session-owned logical CSV source and carry its intended row shape in LazyFrame[Order].
Part I
Model the work
Chapter 1 of 2
Goal
By the end of this chapter, the included consumer project can open orders.csv as a deferred LazyFrame[Order]. You will know which part is a checked Incan type, which part is a logical source registration, and which compatibility check is not yet performed.
Start from a real consumer project
The book is not compiled as part of IncQL itself. It is a small downstream project whose manifest points at this checkout, which also verifies that the public pub::incql boundary works.
Project manifest
[project]
name = "incql_tutorial_book"
version = "0.1.0"
[dependencies]
incql = { path = "../.." }
[project.scripts]
main = "src/main.incn"
The path dependency is the truthful setup for this checkout. It should not be read as evidence that IncQL has been published to a package registry.
Define the intended row shape
The Order model gives the carrier an intended row type. Later functions can accept LazyFrame[Order] rather than an untyped table handle.
Shared domain model
"""Typed row contracts shared by every tutorial-book checkpoint."""
@derive(Clone)
pub model Order:
"""The intended row shape of the tutorial CSV source."""
pub order_id: int
pub customer_id: str
pub status: str
pub amount: float
@derive(Clone)
pub model PaidOrderReview:
"""Projected row shape for the query-block beginner route."""
pub order_id: int
pub customer_id: str
pub amount: float
@derive(Clone)
pub model StatusSummary:
"""Grouped result shape for the query-block beginner route."""
pub status: str
pub order_count: int
pub total_amount: float
That type parameter is useful, but its boundary must be stated precisely: current CSV ingress does not validate every physical CSV field and type against the annotated Incan model. LazyFrame[Order] carries the author's intended model while IncQL's planned schema comes from the registered source.
The included data is small enough to keep every later result understandable:
Tutorial CSV
order_id,customer_id,status,amount
1001,C-001,paid,120.50
1002,C-002,pending,64.00
1003,C-001,paid,89.25
1004,C-003,cancelled,42.75
Register the source
Session owns source registration, backend selection, execution, materialization, and writes. read_csv(...) registers a logical relation name and returns deferred work; it does not hand you materialized rows.
With this example, you are asking the Session to register the URI orders.csv under the logical name tutorial_orders. The assignment keeps the authored carrier contract as LazyFrame[Order], while ? propagates a registration failure instead of pretending that a carrier exists. The trace separates that Incan type, the Session registration, and the resulting named-table carrier so you can see which layer owns each fact.
Source registration · before backend execution
See what read_csv(...) actually establishes
The call joins an intended Incan carrier type to a Session-owned source registration. It reads the local CSV to establish a coarse planned schema, but it does not execute the relation through DataFusion.
-
01
Intended row shapeState the carrier contract in checked Incanpub model Order: pub order_id: int pub customer_id: str pub status: str pub amount: float- Owner
- Incan authoring surface
- Artifact
Orderand the intendedLazyFrame[Order]type- Knowable now
- The row shape the consumer intends to carry
-
02
CSV registrationBind a logical name and establish a planned source schemaorders: LazyFrame[Order] = session.read_csv( # (1)! "tutorial_orders", # (2)! "orders.csv", # (3)! )? # (4)!Carrier contract.
LazyFrame[Order]is the declared result type: it carries the intendedOrderrow shape with deferred relational work. It is not a materializedDataFrame[Order].Logical name.
tutorial_ordersbecomes the Session-local name used by theReadNamedTableplan root. The name must be non-empty and not already registered in this Session; changing it does not rename the CSV file.Source URI.
orders.csvidentifies the physical CSV source. Here it is a non-empty path relative to the tutorial project; the currentread_csv(...)surface takes the logical name and URI as its two positional arguments.Failure propagation.
read_csv(...)returns aResult. The trailing?returns itsSessionErrorfrom the caller when registration or source-schema discovery fails, instead of producing a carrier that cannot be used safely.
- Owner
Sessionand its CSV source policy- Artifact
- Logical source registration plus a coarse inferred CSV schema
- Knowable now
- Header names, primitive kinds, nullability, and source identity
-
03
Deferred carrierReturn intent without materialising rows- Logical root
ReadNamedTable("tutorial_orders")- Returned carrier
LazyFrame[Order]- Backend attempt
- None
Session registration
Deferred named-table plan
Open the complete Chapter 1 checkpoint
"""Chapter 1: bind a typed row contract to a CSV-backed lazy carrier."""
from domain import Order
from pub::incql import LazyFrame, Session, SessionError, report_session_error
def read_orders(mut session: Session) -> Result[LazyFrame[Order], SessionError]:
"""Register the CSV source and return its typed lazy carrier."""
orders: LazyFrame[Order] = session.read_csv("tutorial_orders", "orders.csv")?
return Ok(orders)
def main() -> None:
mut session = Session.default()
match read_orders(session):
Ok(_) => println("Chapter 1: created a LazyFrame[Order] without executing it")
Err(error) => report_session_error("tutorial.chapter_01", error)
Run the checkpoint from the tutorial project:
incan run src/chapter_01.incn
Expected output
Chapter 1: created a LazyFrame[Order] without executing it
The checkpoint deliberately prints no schema or rows. It proves that the public consumer can register the logical source and create its lazy carrier. Later materialization exposes resolved columns, row counts, and preview text rather than typed Order iteration.
Try it
Change only the logical table name passed to read_csv(...), then run the checkpoint again. The physical CSV stays the same, but the name attached to the logical read changes. Restore the checkpoint before continuing.
Chapter complete
You can explain why LazyFrame[Order] is deferred relational intent, why the Session owns the CSV binding, and why the Order annotation is not yet proof that the physical CSV conforms field-for-field.