A hybrid CLI & Web tool to run SQL queries on CSV, XLSX, and JSON files, written in Go.
- CLI Mode: Execute SQL queries from the terminal with Unix philosophy
- Web Mode: Spin up a localhost server with a GUI for non-technical users
- Multi-Format Support: Parse and query CSV, XLSX, and JSON files
- In-Memory SQLite: Load files into SQLite for fast querying
- Type Inference: Automatically detect column types (INTEGER, REAL, TEXT)
- Multiple Output Formats: Table, JSON, or CSV output
- Hexagonal Architecture: Clean separation of concerns (Ports & Adapters)
- Go 1.21+
- SQLite3 (with CGO enabled for
go-sqlite3) - Windows/Linux/macOS (cross-platform support)
# Clone or download the repository
git clone https://github.com/zulfikawr/runsql
cd runsql
# Install dependencies
go mod download
# Build the executable
go build -o runsql ./cmd/runsql
# or
go build -o runsql.exe ./cmd/runsql # for WindowsDownload the compiled executable from the Releases page.
Execute SQL queries directly from the terminal.
./runsql -f <file> -q <query> -o <format>| Flag | Description | Default | Example |
|---|---|---|---|
-f |
File path (CSV, XLSX, or JSON) | Required | -f data/sales.csv |
-q |
SQL query | Required | -q "SELECT * FROM sales LIMIT 10" |
-o |
Output format: table, json, csv |
table |
-o json |
Example 1: Query CSV with table output
./runsql -f sample/sample.csv -q "SELECT industry, COUNT(*) as count FROM sample WHERE level = 0 GROUP BY industry" -o tableOutput:
| industry | count |
+----------+-------+
| total | 705 |
Example 2: Query JSON with JSON output
./runsql -f sample/sample.json -q "SELECT language, COUNT(*) as users FROM sample GROUP BY language ORDER BY users DESC" -o jsonOutput:
[
{
"language": "Sindhi",
"users": 1000
}
]Example 3: Query with CSV output
./runsql -f data.csv -q "SELECT name, email FROM data WHERE age > 30" -o csvOutput:
name,email
John Doe,john@example.com
Jane Smith,jane@example.comExample 4: JOIN Query (Multi-File)
./runsql -f users.csv,orders.json -q "SELECT users.name, orders.item FROM users JOIN orders ON users.id = orders.user_id"Launch an interactive web interface for querying files.
./runsql -web -addr ":8080"| Flag | Description | Default |
|---|---|---|
-web |
Enable web mode | false (CLI mode) |
-addr |
Server address (host:port) | :8080 |
./runsql -web -addr ":3000"Then open your browser to http://localhost:3000 and:
- Upload a CSV, XLSX, or JSON file
- Enter an SQL query
- View results in the browser
runsql/
βββ cmd/
β βββ runsql/ # Entry point
β βββ main.go # CLI/Web mode dispatcher
βββ internal/
β βββ adapter/ # Interface adapters (Ports & Adapters pattern)
β β βββ cli/ # CLI-specific logic
β β β βββ cli.go
β β βββ web/ # HTTP handlers & server
β β βββ web.go
β βββ core/ # Business logic (The Brain)
β β βββ domain.go # Struct definitions
β β βββ engine.go # SQLite lifecycle & query execution
β β βββ engine_test.go # Unit tests
β β βββ infer.go # Type inference logic
β βββ parsers/ # File readers (Ports)
β β βββ parser.go # Interface definition
β β βββ csv.go # CSV parser
β β βββ json.go # JSON parser
β β βββ xlsx.go # Excel parser
β β βββ parsers_test.go # Unit tests
β βββ ui/ # UI logic
β βββ colors.go # Colors definition
βββ web/ # Static frontend assets
β βββ index.html # Web UI
β βββ script.js # JavaScript
β βββ style.css # Styling
βββ go.mod # Go module definition
βββ go.sum # Go module lock file
βββ LICENSE # MIT License
βββ .gitignore # Git ignore rules
βββ README.md # This file
RunSQL follows the Hexagonal Architecture (Ports & Adapters) pattern:
ββββββββββββββββββββββββββββββββββββββ
β User Interfaces β
β (CLI Adapter) β (Web Adapter) β
ββββββββββ¬βββββββββ΄βββββββββ¬ββββββββββ
β β
ββββββΌβββββββββββββββββΌβββββ
β Ports (Interfaces) β
β - Source (Parser) β
β - Engine (SQLite) β
ββββββ¬ββββββββββββββββββ¬ββββ
β β
ββββββΌβββββββββββββββββββΌβββββ
β Core Business Logic β
β - Type Inference β
β - Database Engine β
β - Query Execution β
ββββββ¬ββββββββββββββββββ¬ββββββ
β β
ββββββΌββββββββββββββββββΌβββββ
β Adapters (Implementations)β
β - CSV, JSON, XLSX Parsers β
β - SQLite Engine β
βββββββββββββββββββββββββββββ
- Separation of Concerns: Core logic is independent of UI and data sources
- Testability: Each layer can be tested independently
- Extensibility: Add new file formats or UI modes without changing core logic
- Clean Dependencies: Always point toward the core business logic
go test ./...go test ./internal/parsers
go test ./internal/corego test -cover ./...- Standard RFC 4180 format
- Automatic header detection
- Custom delimiters supported
- Array of objects:
[{"col1": value1, "col2": value2}, ...] - Flat structures only (no nested objects)
- Type inference from values
- Reads first sheet by default
- Treats first row as headers
- All other sheets can be ignored
Problem: Query references a column that doesn't exist in the file.
Solution:
- Check header row in your file
- Use column names exactly as they appear (case-sensitive in some databases)
- Run a
SELECT *query first to see all available columns
Problem: Query expects INTEGER but column contains TEXT.
Solution:
- RunSQL infers types from the first 100 rows
- If your file has mixed types, try casting:
CAST(column AS TEXT)
Problem: File is too large or has memory issues.
Solution:
- Files should be < 500MB for optimal performance
- For larger files, consider splitting into multiple files
- Use WHERE clauses to filter data early
Problem: Port is already in use or permissions issue.
Solution:
# Try a different port
./runsql -web -addr ":3000"
# On Linux/Mac, use sudo for ports < 1024
sudo ./runsql -web -addr ":80"Problem: "missing gcc" or CGO compilation errors.
Solution:
- Install MinGW or TDM-GCC for CGO support
- Or use WSL (Windows Subsystem for Linux)
- Or download pre-built binary from releases
This project is licensed under the MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
- Bug Reports: Open an issue with reproduction steps
- Feature Requests: Suggest new features or improvements
- Code: Submit PRs with improvements or fixes
- Documentation: Help improve this README or add examples
Happy Querying! π
