---
title: "Rust: sqlx without macros"
author: "James Pace"
date: "2024/01/01"
---

[`sqlx`](https://github.com/launchbadge/sqlx) is a Rust crate that allows
for interacting with a SQL database.
One of the more popular features of `sqlx` is that it does compile time checking
of database queries (giving you some ORM-ish properties) while still allowing
you to write straight SQL queries without the abstraction of an ORM though use
of their [`query!`](https://docs.rs/sqlx/0.5.5/sqlx/macro.query.html).

To make this work, `sqlx` requires:

1. access to a database at compile time, OR
2. config files to be generated from a running database everytime
   the database queries are modified.

I don't particularly like either of those options, though I admittedly
have not tried either of them long term.
Requring a running database at compile time would seem to make compilation
a lot slower.
It also adds a unexpected step (run a container hosting a development database)
before you can compile, which just feels wrong.
The configuation files are better in the sense they don't require a running
database at compile time, but it's an extra thing that has to be kept in sync
with the code.

Luckily, `sqlx` provides functions that can be used to do queries that aren't
checked at compile time for people with the same concerns as I have.
Because this isn't the recommended path though, the number of examples of
using the functions online is a little lacking, which I'll make an effort
to improve in this post.

The other thing I'll show in this post is working with JSON in Postgres.
Postgres has native support for working with JSON documents, providing
a lot of the benefits of NoSQL databases, but in a SQL database.
`sqlx`'s API for json documents integrates well with serde, and is resonably
easy to work with.

# Pre-reqs

Running the example requires a running Postgres database, which I'm going to run
locally via [`podman`](https://podman.io/) using the bash script below.

```bash
#!/usr/bin/env bash

DATA_DIR="$PWD/data"

if [ ! -d "$DATA_DIR" ]; then
  echo "Making data directory."
  mkdir $DATA_DIR
fi
podman run --rm --name test-db --network=host \
       -e POSTGRES_USER=postgres \
       -e POSTGRES_PASSWORD=devpassword \
       -e PGDATA=/var/lib/postgresql/data/pgdata \
	   -v $DATA_DIR:/var/lib/postgresql/data \
       docker.io/library/postgres:latest
```

The script:

1. Defines `DATA_DIR` which will be a local host directory we will mount
   in the database container and tell the database to save its files to
   so they persist beyond container restarts.
2. Makes that directory if it is missing.
3. Starts a container running the official postgres image.
   Environment variables are used to set some settings to values suitable
   for local testing.

# Example
