#sql #inline #postgresql #prelude #tiny #opinionated #write

inline-postgres

tiny and opinionated postgres SQL library

1 unstable release

0.1.0 Jun 18, 2024

#1044 in Database interfaces

MIT license

13KB
53 lines

write SQL code inline in your Rust program!

Example

You can write SQL almost like you are used to.

use inline_postgres as pg;
use pg::prelude::*;

fn main() -> Result<(), pg::Error> {
    // connect to the database
    let mut db = pg::Client::connect("host=localhost, user=postgres", pg::NoTls)?;


    // we can execute arbitrary code on the database, like creating a table.
    db.exec(stmt! {
        CREATE TABLE PERSON (
            FIRST_NAME VARCHAR(100),
            LAST_NAME  VARCHAR(100)
        )
    })?;

    
    // we can also use values from the surrounding scope to in the query like so:
    let max = 4;
    db.exec(stmt! {
        DELETE FROM PERSON
        WHERE LENGTH(LAST_NAME) > {max}
    })?;

    // note that we need to use double-quotes to write SQL string literals. 
    let given_name = "Wanda";
    db.exec(stmt! {
        INSERT INTO PERSON(FIRST_NAME, LAST_NAME) VALUES({given_name}, "Maximoff")
    })?;

    // to query values from the database we can use the `Client::fetch` method.
    // instead of returning a record object, the values are directly inserted into 
    // a generated struct which has all the queried fields.
    // 
    // the field names and types are written in the query like so:
    let rows = db.fetch(sql! {
        SELECT FIRST_NAME AS [name: String] FROM PERSON
    })?;

    assert_eq!(rows.len(), 1);
    assert_eq!(rows[0].name, "Wanda");

    Ok(())
}

Limitations

The Rust tokenizer is designed for Rust, not SQL. Hence, it does not know what to do with string literals delimited by single quotes (').

Any creation of such string literals like 'Peter Parker' cannot be parsed by Rust and cause a compile error. To work around this limitation, it was decided to use Rusts syntax of double quotes for the embedded SQL strings as well.

Safety

A query like SELECT * FROM PERSON WHERE FIRST_NAME = {name} looks like it would concatenate the value directly into the query, which would be quite unsafe. Luckily it does not do that, but instead runs the query like a prepared statement, and passes the parameters separately.

In fact, no use of the sql! macro (and related ones) can result in an SQL injection attack. It generates the SQL statements at compile time, and thus no runtime value can sneak into the query.

Dependencies

~9–21MB
~328K SLoC