Mesh database access: SQLite (Sqlite module), PostgreSQL (Pg module), and ORM patterns with deriving Row and query builder.
Rules:
Sqlite.open(path) -> Result<Db, String> — opens a database file; use ":memory:" for in-memory.Sqlite.execute(db, sql, params) -> Result<Int, String> — DDL and DML; returns rows affected.Sqlite.query(db, sql, params) -> Result<List<Map<String, String>>, String> — SELECT; returns list of row maps.Sqlite.close(db) — closes the connection.List<String> using ? placeholders in SQL.String — use deriving(Row) to coerce types (see below).? operator on results propagates errors up cleanly.Code example (from tests/e2e/stdlib_sqlite.mpl):
fn run_db() -> Int!String do
let db = Sqlite.open(":memory:")?
let _ = Sqlite.execute(db, "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age TEXT)", [])?
let _ = Sqlite.execute(db, "INSERT INTO users (name, age) VALUES (?, ?)", ["Alice", "30"])?
let _ = Sqlite.execute(db, "INSERT INTO users (name, age) VALUES (?, ?)", ["Bob", "25"])?
let rows = Sqlite.query(db, "SELECT name, age FROM users ORDER BY name", [])?
List.map(rows, fn(row) do
let name = Map.get(row, "name")
let age = Map.get(row, "age")
println("#{name}:#{age}")
end)
Sqlite.close(db)
Ok(0)
end
fn main() do
case run_db() do
Ok(_) -> println("done")
Err(msg) -> println("error: #{msg}")
end
end
Rules:
Pg.connect(connection_string) -> Result<Conn, String> — connects to PostgreSQL.Pg.execute(conn, sql, params) -> Result<Int, String> — DDL and DML.Pg.query(conn, sql, params) -> Result<List<Map<String, String>>, String> — SELECT.Pg.close(conn) — closes the connection.$1, $2, ... placeholders (PostgreSQL syntax).List<String>.Code example (from tests/e2e/stdlib_pg.mpl):
fn run_db() -> Int!String do
let conn = Pg.connect("postgres://mesh_test:mesh_test@localhost:5432/mesh_test")?
let _ = Pg.execute(conn, "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT, age INTEGER)", [])?
let _ = Pg.execute(conn, "INSERT INTO users (name, age) VALUES ($1, $2)", ["Alice", "30"])?
let rows = Pg.query(conn, "SELECT name FROM users WHERE age > $1", ["26"])?
List.map(rows, fn(row) do
println(Map.get(row, "name"))
end)
Pg.close(conn)
Ok(0)
end
Rules:
end deriving(Row) on a struct generates TypeName.from_row(map) -> Result<TypeName, String>.Map<String, String> (as returned by Sqlite.query / Pg.query).Int fields parse from string, Float from string, Bool from "t"/"true"/"1".List.map to convert rows to typed structs.Code example (from tests/e2e/deriving_row_basic.mpl):
struct User do
name :: String
age :: Int
score :: Float
active :: Bool
end deriving(Row)
let rows = Sqlite.query(db, "SELECT name, age, score, active FROM users", [])?
let users = List.map(rows, fn(row) do
case User.from_row(row) do
Ok(u) -> u
Err(e) -> panic("row conversion failed: #{e}")
end
end)
Rules:
ON CONFLICT ... DO UPDATE SET ... RETURNING uses Sqlite.query (not execute) to get results.DELETE ... RETURNING similarly uses Sqlite.query to capture deleted rows.IN (SELECT ...).RETURNING gives back the affected row data as a query result.Code example (from tests/e2e/sqlite_upsert_subquery_runtime.mpl):
# Upsert (insert-or-update):
let rows = Sqlite.query(db,
"INSERT INTO projects (id, name, status) VALUES (?, ?, ?) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name RETURNING id, name",
["p1", "Alpha", "active"])?
let row = List.head(rows)
println("upserted: #{Map.get(row, "name")}")
# DELETE RETURNING:
let deleted = Sqlite.query(db,
"DELETE FROM projects WHERE id = ? RETURNING id, name",
["p3"])?
let del_row = List.head(deleted)
println("deleted: #{Map.get(del_row, "name")}")
# Subquery:
let results = Sqlite.query(db,
"SELECT name FROM projects WHERE org_id IN (SELECT id FROM organizations WHERE name = ?)",
["Acme Corp"])?
Rules:
INNER JOIN, LEFT JOIN, etc. — no special Mesh syntax.COUNT, SUM, AVG, MAX, MIN) use SQL directly.GROUP BY and ORDER BY are plain SQL.List<Map<String, String>> — column aliases work as map keys.Code example (from tests/e2e/sqlite_join_runtime.mpl):
let rows = Sqlite.query(db,
"SELECT u.name, COUNT(p.id) AS project_count FROM users u LEFT JOIN projects p ON u.id = p.user_id GROUP BY u.id ORDER BY u.name",
[])?
List.map(rows, fn(row) do
let name = Map.get(row, "name")
let count = Map.get(row, "project_count")
println("#{name}: #{count} projects")
end)
Rules:
Sqlite.close(db) / Pg.close(conn) — connections are not auto-closed.? placeholders; PostgreSQL uses $1, $2, ...String — no implicit type conversion without deriving(Row).INSERT/UPDATE/DELETE without RETURNING, use execute (not query).INSERT ... RETURNING or DELETE ... RETURNING, use query to receive the rows.