rquickjs_extra_sqlite/
argument.rs

1use rquickjs::{Ctx, Exception, FromJs, Result, TypedArray};
2use rquickjs_extra_utils::ffi::{CString, CVec};
3use rquickjs_extra_utils::result::ResultExt;
4use sqlx::query::Query;
5use sqlx::sqlite::SqliteArguments;
6use sqlx::Sqlite;
7
8#[derive(Debug)]
9pub enum Argument<'js> {
10    Null,
11    Integer(i64),
12    Real(f64),
13    Text(CString<'js>),
14    Blob(CVec<'js>),
15}
16
17impl<'js> FromJs<'js> for Argument<'js> {
18    fn from_js(ctx: &Ctx<'js>, value: rquickjs::Value<'js>) -> Result<Self> {
19        if value.is_undefined() || value.is_null() {
20            return Ok(Argument::Null);
21        } else if let Some(int) = value.as_int() {
22            return Ok(Argument::Integer(int as i64));
23        } else if let Some(big_int) = value.as_big_int() {
24            return Ok(Argument::Integer(big_int.clone().to_i64()?));
25        } else if let Some(float) = value.as_float() {
26            return Ok(Argument::Real(float));
27        } else if let Some(string) = value.as_string() {
28            return Ok(Argument::Text(CString::from_string(string.clone())?));
29        } else if let Some(object) = value.as_object() {
30            if object.as_typed_array::<u8>().is_some() {
31                // Lifetime issue: https://github.com/DelSkayn/rquickjs/issues/356
32                return Ok(Argument::Blob(CVec::from_array(
33                    TypedArray::<u8>::from_value(value.clone()).or_throw(ctx)?,
34                )?));
35            }
36        }
37        Err(Exception::throw_type(
38            ctx,
39            &["Value of type '", value.type_name(), "' is not supported"].concat(),
40        ))
41    }
42}
43
44impl<'js> Argument<'js> {
45    pub fn try_bind<'q>(
46        &'q self,
47        ctx: &Ctx<'js>,
48        query: &mut Query<'q, Sqlite, SqliteArguments<'q>>,
49    ) -> Result<()>
50    where
51        'js: 'q,
52    {
53        match self {
54            Argument::Null => query.try_bind::<Option<i32>>(None).or_throw(ctx),
55            Argument::Integer(int) => query.try_bind(*int).or_throw(ctx),
56            Argument::Real(float) => query.try_bind(*float).or_throw(ctx),
57            Argument::Text(string) => query.try_bind(string.as_str()?).or_throw(ctx),
58            Argument::Blob(blob) => query.try_bind(blob.as_slice()).or_throw(ctx),
59        }
60    }
61}