sqlfuncs 0.6.0

Scalar functions for use in SQLite through rusqlite.
Documentation
use rusqlite::{Connection, Error, functions::FunctionFlags};

use parse_size::Config;

use crate::err;


/// Add a `parse_size` function to sqlite connection.
///
/// ```
/// use rusqlite::Connection;
/// use sqlfuncs::numrepr::parse_size;
///
/// let conn = Connection::open_in_memory().unwrap();
/// parse_size(&conn).unwrap();
///
/// let val: u64 = conn.query_row_and_then(
///   "SELECT parse_size(?, 'bin');", ["64K"], |row| {
///     row.get(0)
///   }).unwrap();
/// assert_eq!(val, 65536);
///
/// let val: u64 = conn.query_row_and_then(
///   "SELECT parse_size(?, 'dec');", ["64K"], |row| {
///     row.get(0)
///   }).unwrap();
/// assert_eq!(val, 64000);
///
/// let val: u64 = conn.query_row_and_then(
///   "SELECT parse_size(?);", ["64K"], |row| {
///     row.get(0)
///   }).unwrap();
/// assert_eq!(val, 65536);
/// ```
#[allow(clippy::missing_errors_doc)]
pub fn parse_size(conn: &Connection) -> Result<(), Error> {
  conn.create_scalar_function(
    "parse_size",
    -1, // variable number of arguments
    FunctionFlags::SQLITE_UTF8
      | FunctionFlags::SQLITE_INNOCUOUS
      | FunctionFlags::SQLITE_DETERMINISTIC,
    move |ctx| {
      let val = ctx.get::<String>(0)?;
      let cfg = if ctx.len() > 1 {
        let ty = ctx.get::<String>(1)?.to_lowercase();
        match ty.as_ref() {
          "dec" => Config::new().with_decimal(),
          "bin" => Config::new().with_binary(),
          _ => {
            return Err(Error::UserFunctionError(Box::new(
              err::Error::ValidationFailed(String::from("Unknown unit type"))
            )));
          }
        }
      } else {
        Config::new().with_binary()
      };

      let val = cfg.parse_size(val).map_err(|e| {
        Error::UserFunctionError(Box::new(err::Error::ValidationFailed(
          e.to_string()
        )))
      })?;

      Ok(val)
    }
  )
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :