Type safety primer
deet treats every model as a contract. The typechecker validates joins, aggregates, and nulls before SQL ships, so teams catch issues in code review instead of after a failed run.
The mental model
- Sources declare the shape of data.
- Models transform sources into new contracts.
deet checkenforces types and nullability.
Types + nullability
If a column can be null, it is marked with ?. In the playground contract view, that becomes a TypeScript-style optional field:
email?: string;
What deet check catches
- Mismatched join keys and filters
- Aggregates on non-numeric columns
- Missing columns or nullability violations
Example: fail fast, then fix
source users = table("users") : { id: i64, name: string, email: string? }
model broken = users
|> filter(id == "oops")
id is numeric, so comparing it to a string trips the typechecker. Fix the predicate and the contract goes clean:
model fixed = users
|> filter(id > 0)
Contract view
Every model surfaces as a contract that mirrors TypeScript interfaces:
interface users {
id: number;
name: string;
email?: string;
}
Run it locally
deet check ./main.dt