Skip to content

kuindji/sql-type-parser

Repository files navigation

Type-Level SQL Parser

🎵 Vibe-coded with Claude Opus 4.5

🙏 Inspired by and built upon telefrek/sql - a TypeScript SQL parsing series

@kuindji/sql-type-parser is a type-level SQL parser for TypeScript that transforms SQL query string literals into their corresponding AST types at compile time. It enables:

  • Compile-time SQL parsing: Parse SQL queries entirely within TypeScript's type system
  • Type-safe result inference: Automatically infer result types from SQL queries
  • Query validation: Catch SQL errors at compile time, not runtime
  • Zero runtime overhead: Pure type-level operations with no runtime code

Installation

npm install @kuindji/sql-type-parser

Define Your Schema

First, describe your database structure as a TypeScript type:

type MySchema = {
    defaultSchema: "public";
    schemas: {
        public: {
            users: {
                id: number;
                name: string;
                email: string;
                role: "admin" | "user";
            };
            orders: {
                id: number;
                user_id: number;
                total: number;
                status: "pending" | "completed";
            };
        };
    };
};

API

QueryResult<SQL, Schema>

Infers the result type of a SELECT query:

import type { QueryResult } from "@kuindji/sql-type-parser";

type Result = QueryResult<"SELECT id, name, role FROM users", MySchema>;
// { id: number; name: string; role: "admin" | "user" }

type JoinResult = QueryResult<
    `SELECT u.name, o.total 
     FROM users AS u 
     INNER JOIN orders AS o ON u.id = o.user_id`,
    MySchema
>;
// { name: string; total: number }

ValidateSQL<SQL, Schema>

Validates a query at compile time. Returns true if valid, or an error message:

import type { ValidateSQL } from "@kuindji/sql-type-parser";

type Valid = ValidateSQL<"SELECT id FROM users", MySchema>;
// true

type Invalid = ValidateSQL<"SELECT unknown_col FROM users", MySchema>;
// "Column 'unknown_col' not found in any table"

InsertResult<SQL, Schema>

Infers the RETURNING clause result for INSERT queries:

import type { InsertResult } from "@kuindji/sql-type-parser";

type Result = InsertResult<
    "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name",
    MySchema
>;
// { id: number; name: string }

UpdateResult<SQL, Schema>

Infers the RETURNING clause result for UPDATE queries:

import type { UpdateResult } from "@kuindji/sql-type-parser";

type Result = UpdateResult<
    "UPDATE users SET name = $1 WHERE id = $2 RETURNING id, name, email",
    MySchema
>;
// { id: number; name: string; email: string }

DeleteResult<SQL, Schema>

Infers the RETURNING clause result for DELETE queries:

import type { DeleteResult } from "@kuindji/sql-type-parser";

type Result = DeleteResult<
    "DELETE FROM users WHERE id = $1 RETURNING *",
    MySchema
>;
// { id: number; name: string; email: string; role: "admin" | "user" }

ParseSQL<SQL>

Parses a SQL string into an AST type (for advanced use cases):

import type { ParseSQL, SQLSelectQuery } from "@kuindji/sql-type-parser";

type AST = ParseSQL<"SELECT id FROM users">;
// SQLSelectQuery<SelectClause<...>>

Supported SQL

The parser handles SELECT, INSERT, UPDATE, and DELETE queries with:

  • JOINs (INNER, LEFT, RIGHT, FULL, CROSS)
  • Subqueries and derived tables
  • Common Table Expressions (WITH)
  • Aggregates (COUNT, SUM, AVG, MIN, MAX)
  • UNION, INTERSECT, EXCEPT
  • PostgreSQL syntax (JSON operators, type casting, arrays)
  • MySQL syntax (backtick quotes, specific functions)

See SPECIFICATION.md for full details.

Limitations

  • TypeScript's recursion limits may be hit with very complex queries
  • Quoted identifiers with spaces not supported: use "user-id" not "user id"

License

MIT

About

Type-level SQL parser for TypeScript

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published