• Home
  • Experiences
  • Projects
  • About

SqlType

> Links
> Description
SqlType is a static SQL analysis and inference engine implemented entirely with TypeScript’s type system. It parses SQL-like query strings at compile time and infers the resulting data shape based on a provided schema. The system supports validation of selectors, function calls, joins, aliases, and SELECT * semantics — all within the type layer of TypeScript, with zero runtime logic. SqlType helps developers catch query issues during development, creating safer and more predictable data access layers in TypeScript-based systems.
> Goals
  • Enable compile-time validation of SQL queries in TypeScript.
  • Infer query result shapes based on SELECT statements and schema inputs.
  • Support advanced SQL constructs like joins, aliases, and functions all in the type layer.
> Features
  • Compile-time SQL parsing: Parses and analyzes SQL queries entirely at the type level using recursive conditional types.
  • Full query shape inference: Infers result structures from SELECT queries, including expressions and function calls.
  • Support for joins and aliases: Supports INNER, LEFT, RIGHT, and FULL OUTER JOINs with alias resolution and field mapping.
  • Function usage validation: Functions like COUNT(...) are checked at compile time for valid argument types and nesting.
  • Zero-runtime: No runtime dependency; the entire system works within TypeScript’s type checker.
> Usage
  • // Example 1: Simple SELECT with alias
    type Tables = {
      users: {
        id: number;
        name: string;
      };
    };
    
    type Query = "SELECT users.name AS username FROM users";
    
    type Result = BuildQuery<Query, Tables>;
    
    /*
      Result:
      {
        username: string;
      }
    */
  • // Example 2: COUNT aggregation with JOIN
    type Tables = {
      users: {
        id: number;
        name: string;
      };
      posts: {
        id: number;
        user_id: number;
      };
    };
    
    type Query = "SELECT COUNT(posts.id) AS totalPosts FROM users LEFT JOIN posts ON users.id = posts.user_id";
    
    type Result = BuildQuery<Query, Tables>;
    
    /*
      Result:
      {
        totalPosts: number;
      }
    */
  • // Example 3: Multiple columns with alias and join
    type Tables = {
      users: {
        id: number;
        name: string;
      };
      posts: {
        id: number;
        user_id: number;
        title: string;
      };
    };
    
    type Query = "SELECT u.name AS username, COUNT(p.id) AS total FROM users u LEFT JOIN posts p ON u.id = p.user_id";
    
    type Result = BuildQuery<Query, Tables>;
    
    /*
      Result:
      {
        username: string;
        total: number;
      }
    */
> Tech Stack
  • TypeScript
> Learning Outcomes
  • Building domain-specific compilers using the TypeScript type system
  • Designing and modeling SQL ASTs using literal and mapped types
  • Creating safe APIs with compile-time validation
  • Understanding recursion limits and type inference depth in TS