Skip to content

Querying

Once a DirSQL instance is created, the initial directory scan is complete and you can run SQL queries against the indexed data.

Basic queries

python
# All rows from a table
results = db.query("SELECT * FROM comments")

# Filter with WHERE
results = db.query("SELECT * FROM comments WHERE author = 'alice'")

# Aggregations
results = db.query("SELECT author, COUNT(*) as n FROM comments GROUP BY author")

# JOINs across tables
results = db.query("""
    SELECT posts.title, authors.name
    FROM posts
    JOIN authors ON posts.author_id = authors.id
""")
rust
// All rows from a table
let results = db.query("SELECT * FROM comments")?;

// Filter with WHERE
let results = db.query("SELECT * FROM comments WHERE author = 'alice'")?;

// Aggregations
let results = db.query("SELECT author, COUNT(*) as n FROM comments GROUP BY author")?;

// JOINs across tables
let results = db.query(
    "SELECT posts.title, authors.name \
     FROM posts JOIN authors ON posts.author_id = authors.id"
)?;
typescript
// All rows from a table
const results = await db.query('SELECT * FROM comments');

// Filter with WHERE
const filtered = await db.query("SELECT * FROM comments WHERE author = 'alice'");

// Aggregations
const counts = await db.query('SELECT author, COUNT(*) as n FROM comments GROUP BY author');

// JOINs across tables
const joined = await db.query(`
  SELECT posts.title, authors.name
  FROM posts
  JOIN authors ON posts.author_id = authors.id
`);

Any valid SQLite SQL works. The in-memory database supports the full SQLite dialect including subqueries, CTEs, window functions, and aggregate functions.

Return format

query() returns a list of dicts (Python), a Vec<HashMap> (Rust), or an array of objects (TypeScript). Each entry maps column names to values.

python
results = db.query("SELECT title, author FROM posts")
# [
#     {"title": "Hello World", "author": "alice"},
#     {"title": "Second Post", "author": "bob"},
# ]
rust
let results = db.query("SELECT title, author FROM posts")?;
// Vec<HashMap<String, Value>>
// [{"title": "Hello World", "author": "alice"}, ...]
typescript
const results = await db.query('SELECT title, author FROM posts');
// [
//   { title: 'Hello World', author: 'alice' },
//   { title: 'Second Post', author: 'bob' },
// ]

SQLite types map back to Python types:

SQLite typePython type
TEXTstr
INTEGERint
REALfloat
BLOBbytes
NULLNone

Internal columns

dirsql adds internal tracking columns (_dirsql_file_path, _dirsql_row_index) to each table for file-change diffing. These columns are automatically excluded from SELECT * results. You do not need to account for them.

Error handling

Invalid SQL raises an exception:

python
try:
    db.query("NOT VALID SQL")
except Exception as e:
    print(f"Query error: {e}")
rust
match db.query("NOT VALID SQL") {
    Ok(results) => println!("{:?}", results),
    Err(e) => eprintln!("Query error: {}", e),
}
typescript
try {
  await db.query('NOT VALID SQL');
} catch (e) {
  console.error(`Query error: ${e}`);
}

Empty results

Queries that match no rows return an empty collection:

python
results = db.query("SELECT * FROM posts WHERE author = 'nobody'")
assert results == []
rust
let results = db.query("SELECT * FROM posts WHERE author = 'nobody'")?;
assert!(results.is_empty());
typescript
const results = await db.query("SELECT * FROM posts WHERE author = 'nobody'");
console.assert(results.length === 0);

Released under the MIT License.