Since my original launch post for syntaqlite, I’ve been quietly working away on it in the background. A lot of the work has been fixing correctness bugs which I discovered as I integrated it into production as the parser for PerfettoSQL in the Perfetto trace processor: as I wrote previously, this has been my dream for over 8 years so it’s amazing to see it finally realized.
Just today, I released syntaqlite 0.6, the most interesting release since the original launch, so I wanted to talk about what’s new.
The biggest step forward for real world applicability is that we now support SQLite dot commands:
.print 'running foo now';
.read foo.sql;
.print 'running bar now';
.read bar.sql;
select * from baz;
-- ^ baz will error if it's not part of the schema!
SQLite scripts are very common in the wild and in the past we would simply error
on dot commands like .read and .print, causing spurious warnings and an
inability to format files like this properly. Now, these lines will be silently
ignored while still parsing, formatting and validating the SQL inside!
In followup releases, I plan on making syntaqlite more aware of the semantics
of these dot commands, especially .read: we should be able to do things like
verify the file exists or to use the contents of those files for populating
schemas etc.
Along with this, the release of Pyodide 314.0 last week means that we can now publish Python wheels to PyPI for Pyodide: I’ve taken advantage of that to immediately add support for it. So you can now go to the Pyodide playground and run the following:
import micropip
await micropip.install('syntaqlite')
import syntaqlite
sq = syntaqlite.Syntaqlite()
# Formatting
print(sq.format_sql('select 1', keyword_case='upper'))
# SELECT 1;
# Analysis
schema = syntaqlite.Schema(
ddl="CREATE TABLE users (id INT, name TEXT, email TEXT, active INT)")
print(sq.analyze("SELECT nme FROM users WHERE active = 1", schema,
output=syntaqlite.AnalysisOutput.TEXT,
render_options=syntaqlite.RenderOptions(source_name="query.sql")))
# warning: unknown column 'nme'
# --> query.sql:1:8
# |
# 1 | SELECT nme FROM users WHERE active = 1
# | ^~~
# = help: did you mean 'name'?
This is another step on the journey towards a 1.0 release which I can now see appearing on the horizon!