#sql-query #syntax #proc-macro #procedural #string

sqler

This crate provides a way for writing SQL queries using some of Rust syntax

2 releases

0.0.1-beta Sep 2, 2024
0.0.1-alpha Aug 25, 2024

#614 in Rust patterns

49 downloads per month

MIT/Apache

14KB
344 lines

sqler - beta

A procedural macro that helps with writing SQL queries using some of Rust syntax

Usage

First, in your Cargo.toml file add the following:

[dependencies]
sqler = "0.0.1-beta"

Example 1

To just embedding a value of a varible you can just do the following:

use sqler::sql;

fn main() {
    let first_name = String::from("Ali");
    let age = 24;
    let query = sql!(
        SELECT * FROM users
        WHERE first_name = {first_name}
        OR age = {age}
    );

    assert_eq!(
        query,
        "SELECT * FROM users WHERE first_name='Ali' OR age=24"
    );
}

This macro will handle the process of embedding value of any variable (only built-in types) in addition to converting the Rust syntax to string that contains SQL statement.

Example 2

Also you can write the value directly:

use sqler::sql;

fn main() {
    let query = sql!(
        SELECT * FROM users
        WHERE first_name = "Ali"
        OR age = 24
    );

    assert_eq!(
        query,
        "SELECT * FROM users WHERE first_name='Ali' OR age=24"
    );
}

Example 3

You can also use hexadecimal, octal, or binary number format and the macro will handle it by converting the value back to decimal.

use sqler::sql;

fn main() {
    let query = sql!(
        UPDATE employees 
        SET 
            age=0x1f,
            salery=0o5776
        WHERE
            emp_id=0b101
    );

    assert_eq!(
        query,
        "UPDATE employees SET age=31,salery=3070 WHERE emp_id=5"
    );
}

Example 4

What about variable of a custom type? variable of a custom type can be embedded by first implementing the "VarToSql" trait (which tells the macro how to embed the value of that type) as follows:

use sqler::{sql, VarToSql};

struct IntArr(Vec<i32>);

impl VarToSql for IntArr {
    #[inline]
    fn sql(&self) -> String {
        let mut sql = String::from("ARRAY[");

        for i in 0..self.0.len() - 1 {
            sql.push_str(&self.0[i].to_string());
            sql.push_str(", ");
        }

        sql.push_str(&self.0[self.0.len() - 1].to_string());
        sql.push_str("]::INT[]");
        sql
    }
}

fn main() {
    let permissions = IntArr(vec![1, 2, 3]);
    let query = sql!(
        INSERT INTO user_permissions
            (user_id, permissions)
        VALUES
            (1, {permissions})
    );

    assert_eq!(
        query,
        "INSERT INTO user_permissions(user_id,permissions) VALUES (1,ARRAY[1, 2, 3]::INT[])"
    );
}

Notes

There are a few points you should consider when using this crate:

  • Delimited Identifier - or quoted identifier is not supported. For example: SELECT "first_name" the column name first_name will be converted to a string (string is wrapped with single quote) as follows: SELECT 'first_name'.

  • Variables Of Custom Type - to use variables of a custom type the VarToSql trait should be implemented for this type.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Dependencies