Embedded SQL
syntaqlite can analyze SQL that doesn't live in a plain .sql file: sqlite3
command-line shell scripts (with .read and friends) and SQL string literals
inside Python and TypeScript source files. In each case it isolates the SQL,
then runs the full pipeline on it — syntax checking, schema validation, and
function/arity checks all work exactly as they do on standalone SQL.
sqlite3 shell scripts
Scripts written for the sqlite3 command-line shell interleave SQL with shell
dot-commands (.read, .print, .import, …), # comments, and GO / /
statement terminators. Those lines are not valid SQL, so a plain SQL parser
fails with a syntax error on the first . command.
syntaqlite detects such scripts automatically — no --experimental-lang flag
required. When a file looks like a sqlite3 script, the non-SQL lines are set
aside and only the SQL between them is parsed, validated, and formatted:
syntaqlite fmt schema.sql
.read tables.sql
.read views.sql
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);
Detection is content-based: a file is treated as a shell script only when it
contains a dot-command (or other shell marker) at the start of a line. A .
inside a string literal or mid-statement stays ordinary SQL. This works across
the CLI (fmt, analyze, parse, lineage) and in the language server, so
the same files behave identically on the command line and in your editor.
SQL in Python and TypeScript
syntaqlite also extracts SQL string literals from Python and TypeScript source
files, without needing to maintain separate .sql files for validation.
syntaqlite analyze --experimental-lang python app.py
syntaqlite analyze --experimental-lang typescript db.ts
syntaqlite finds SQL strings in the host language, then runs the same
validation pipeline on each fragment, handling interpolation holes
({var}, ${expr}, ?).
How string extraction works
The extractor looks for string literals that contain SQL keywords (SELECT,
INSERT, CREATE TABLE, etc.) and parses them as SQL. Multi-line strings,
f-strings, and template literals are supported:
# Python — all of these are recognized
cursor.execute("SELECT id, name FROM users WHERE active = 1")
query = """
SELECT u.name, p.title
FROM users u
JOIN posts p ON p.user_id = u.id
"""
cursor.execute(f"SELECT * FROM {table_name} WHERE id = ?")
// TypeScript — template literals work too
const query = `
SELECT id, name
FROM users
WHERE role = 'admin'
`;
Limitations
This feature is experimental. Some patterns are not recognized:
- String concatenation across multiple statements (
query += "...") - SQL built dynamically at runtime
- Complex interpolation where the SQL structure itself is parameterized
- Languages other than Python and TypeScript
Schema validation
Embedded SQL validation respects syntaqlite.toml. If you have a schema
configured, references are checked against it. You can also pass schema
explicitly:
syntaqlite analyze --experimental-lang python --schema schema.sql app.py
In CI
Add embedded SQL checks alongside your regular SQL validation:
- name: Check embedded SQL
run: |
syntaqlite analyze --experimental-lang python "src/**/*.py"
syntaqlite analyze --experimental-lang typescript "src/**/*.ts"