A CLI tool that runs real SQL queries against CSV/JSON flat files. No database server needed — files are the tables. Fully offline, measurable, and naturally extensible.
csv-sql query "SELECT name, age FROM users.csv WHERE age > 25 ORDER BY age DESC"
- Language: TypeScript (Node.js)
- No external runtime dependencies (pure implementation)
- Input: CSV / JSON files as tables
- Output: Formatted table results in terminal
src/
├── index.ts # CLI entry point
├── tokenizer/
│ ├── tokenizer.ts # Breaks SQL string into tokens
│ └── tokens.ts # Token type definitions
├── parser/
│ ├── parser.ts # Builds AST from token stream
│ └── ast.ts # AST node type definitions
├── executor/
│ ├── executor.ts # Walks AST and executes query
│ └── filter.ts # WHERE clause evaluation
├── io/
│ ├── csvReader.ts # Reads CSV into row objects
│ └── jsonReader.ts # Reads JSON array into row objects
└── formatter/
└── tableFormatter.ts # Prints results as aligned table
A working SQL engine that handles basic SELECT queries with WHERE filtering.
Define token types:
SELECT, FROM, WHERE, ORDER, BY, AS, AND, OR, NOT,
STAR, COMMA, LPAREN, RPAREN,
EQ, NEQ, LT, GT, LTE, GTE,
IDENTIFIER, STRING, NUMBER,
EOF
- Reads raw SQL string character by character
- Emits typed tokens with value and position
- Handles: keywords (case-insensitive), identifiers, string literals (
'...'), numbers, operators - Throws descriptive error with position on unknown character
Define nodes:
SelectStatement { columns, from, where?, orderBy?, limit? }
Column { name, alias? } | Wildcard
TableRef { filename, alias? }
BinaryExpr { left, op, right }
Identifier { name }
Literal { value: string | number }Recursive descent parser. Phase 1 supports:
SELECT * FROM file.csvSELECT col1, col2 FROM file.csvSELECT col AS alias FROM file.csvWHERE expr AND/OR expr- Comparison operators:
=,!=,<,>,<=,>= - String and number literals
- Parse CSV with header row
- Return
Row[]whereRow = Record<string, string> - Handle quoted fields, escaped commas
- Support both
,and;delimiters
- Takes AST + file reader
- Evaluates
WHEREclause against each row - Projects selected columns
- Returns
Row[]
- Auto-sizes columns based on max content width
- Prints header row + separator + data rows
- Shows row count at bottom
csv-sql query "<SQL>"
csv-sql query "<SQL>" --format json
csv-sql query "<SQL>" --limit 20
# Basic select
csv-sql query "SELECT * FROM data/users.csv"
# Column projection
csv-sql query "SELECT name, age FROM data/users.csv"
# WHERE filtering
csv-sql query "SELECT name FROM data/users.csv WHERE age > 25"
# AND/OR conditions
csv-sql query "SELECT * FROM data/users.csv WHERE age > 18 AND city = 'NYC'"
# Aliases
csv-sql query "SELECT name AS full_name FROM data/users.csv"All must produce correct, formatted output. Wrong results = not done.
Create data/users.csv:
id,name,age,city,salary
1,Alice,30,NYC,95000
2,Bob,25,LA,72000
3,Carol,35,NYC,110000
4,Dave,28,Chicago,85000
5,Eve,22,LA,65000Create data/orders.csv:
order_id,user_id,product,amount,date
101,1,Laptop,1200,2024-01-15
102,2,Phone,800,2024-01-16
103,1,Monitor,400,2024-01-17
104,3,Laptop,1200,2024-01-18