branch: main
d1.rs
8436 bytesRaw
use crate::SomeSharedData;
use crate::{
    js_sys::{Object, Reflect},
    wasm_bindgen,
};
use serde::Deserialize;
use wasm_bindgen::JsValue;
use worker::{D1PreparedArgument, D1Type, Env, Error, Request, Response, Result};

#[derive(Deserialize)]
struct Person {
    id: u32,
    name: String,
    age: u32,
}

#[worker::send]
pub async fn prepared_statement(
    _req: Request,
    env: Env,
    _data: SomeSharedData,
) -> Result<Response> {
    let db = env.d1("DB")?;
    let unbound_stmt = worker::query!(&db, "SELECT * FROM people WHERE name = ?");

    let stmt = unbound_stmt.bind_refs(&D1Type::Text("Ryan Upton"))?;

    // All rows
    let results = stmt.all().await?;
    let people = results.results::<Person>()?;

    assert!(results.success());
    assert_eq!(results.error(), None);
    assert_eq!(people.len(), 1);
    assert_eq!(people[0].name, "Ryan Upton");
    assert_eq!(people[0].age, 21);
    assert_eq!(people[0].id, 6);

    // All columns of the first rows
    let person = stmt.first::<Person>(None).await?.unwrap();
    assert_eq!(person.name, "Ryan Upton");
    assert_eq!(person.age, 21);

    // The name of the first row
    let name = stmt.first::<String>(Some("name")).await?.unwrap();
    assert_eq!(name, "Ryan Upton");

    // All of the rows as column arrays of raw JSON values.
    let rows = stmt.raw::<serde_json::Value>().await?;
    assert_eq!(rows.len(), 1);
    let columns = &rows[0];

    assert_eq!(columns[0].as_u64(), Some(6));
    assert_eq!(columns[1].as_str(), Some("Ryan Upton"));
    assert_eq!(columns[2].as_u64(), Some(21));

    let stmt_2 = unbound_stmt.bind_refs([&D1Type::Text("John Smith")])?;
    let person = stmt_2.first::<Person>(None).await?.unwrap();
    assert_eq!(person.name, "John Smith");
    assert_eq!(person.age, 92);

    let prepared_argument = D1PreparedArgument::new(&D1Type::Text("Dorian Fischer"));
    let stmt_3 = unbound_stmt.bind_refs(&prepared_argument)?;
    let person = stmt_3.first::<Person>(None).await?.unwrap();
    assert_eq!(person.name, "Dorian Fischer");
    assert_eq!(person.age, 19);

    Response::ok("ok")
}

#[worker::send]
pub async fn batch(_req: Request, env: Env, _data: SomeSharedData) -> Result<Response> {
    let db = env.d1("DB")?;
    let mut results = db
        .batch(vec![
            worker::query!(&db, "SELECT * FROM people WHERE id < 4"),
            worker::query!(&db, "SELECT * FROM people WHERE id > 4"),
        ])
        .await?
        .into_iter();

    let first_results = results.next().unwrap().results::<Person>()?;
    assert_eq!(first_results.len(), 3);
    assert_eq!(first_results[0].id, 1);
    assert_eq!(first_results[1].id, 2);
    assert_eq!(first_results[2].id, 3);

    let second_results = results.next().unwrap().results::<Person>()?;
    assert_eq!(second_results.len(), 2);
    assert_eq!(second_results[0].id, 5);
    assert_eq!(second_results[1].id, 6);

    Response::ok("ok")
}

#[worker::send]
pub async fn exec(mut req: Request, env: Env, _data: SomeSharedData) -> Result<Response> {
    let db = env.d1("DB")?;
    let result = db
        .exec(req.text().await?.as_ref())
        .await
        .expect("doesn't exist");

    Response::ok(result.count()?.unwrap_or_default().to_string())
}

#[worker::send]
pub async fn dump(_req: Request, env: Env, _data: SomeSharedData) -> Result<Response> {
    let db = env.d1("DB")?;
    let bytes = db.dump().await?;
    Response::from_bytes(bytes)
}

#[worker::send]
pub async fn error(_req: Request, env: Env, _data: SomeSharedData) -> Result<Response> {
    let db = env.d1("DB")?;
    let error = db
        .exec("THIS IS NOT VALID SQL")
        .await
        .expect_err("did not get error");

    if let Error::D1(error) = error {
        assert_eq!(
            error.cause(),
            "Error in line 1: THIS IS NOT VALID SQL: near \"THIS\": syntax error at offset 0: SQLITE_ERROR"
        );
    } else {
        panic!("expected D1 error");
    }

    Response::ok("")
}

#[derive(Debug, Deserialize)]
struct NullablePerson {
    id: u32,
    name: Option<String>,
    age: Option<u32>,
}

#[worker::send]
pub async fn jsvalue_null_is_null(
    _req: Request,
    _env: Env,
    _data: SomeSharedData,
) -> Result<Response> {
    assert!(wasm_bindgen::JsValue::NULL.is_null());

    Response::ok("ok")
}

#[worker::send]
pub async fn serialize_optional_none(
    _req: Request,
    _env: Env,
    _data: SomeSharedData,
) -> Result<Response> {
    let serializer = serde_wasm_bindgen::Serializer::new().serialize_missing_as_null(true);

    let none: Option<String> = None;
    let js_none = ::serde::ser::Serialize::serialize(&none, &serializer).unwrap();
    assert!(js_none.is_null());

    Response::ok("ok")
}

#[worker::send]
pub async fn serialize_optional_some(
    _req: Request,
    _env: Env,
    _data: SomeSharedData,
) -> Result<Response> {
    let serializer = serde_wasm_bindgen::Serializer::new().serialize_missing_as_null(true);

    let some: Option<String> = Some("Hello".to_string());
    let js_some = ::serde::ser::Serialize::serialize(&some, &serializer).unwrap();
    assert!(js_some.is_string());

    Response::ok("ok")
}

#[worker::send]
pub async fn deserialize_optional_none(
    _req: Request,
    _env: Env,
    _data: SomeSharedData,
) -> Result<Response> {
    let js_value = Object::new();
    Reflect::set(&js_value, &JsValue::from_str("id"), &JsValue::from_f64(1.0)).unwrap();
    Reflect::set(&js_value, &JsValue::from_str("name"), &JsValue::NULL).unwrap();
    Reflect::set(&js_value, &JsValue::from_str("age"), &JsValue::NULL).unwrap();

    let js_value: JsValue = js_value.into();

    let value: NullablePerson = serde_wasm_bindgen::from_value(js_value).unwrap();

    assert_eq!(value.id, 1);
    assert_eq!(value.name, None);
    assert_eq!(value.age, None);

    Response::ok("ok")
}

#[worker::send]
pub async fn insert_and_retrieve_optional_none(
    _req: Request,
    env: Env,
    _data: SomeSharedData,
) -> Result<Response> {
    let db = env.d1("DB")?;

    let query = worker::query!(
        &db,
        "INSERT INTO nullable_people (id, name, age) VALUES (?1, ?2, ?3)",
        &3,
        &None::<String>,
        &None::<u32>
    )?;
    query.run().await?;

    let stmt = worker::query!(&db, "SELECT * FROM nullable_people WHERE id = 3");
    let person = stmt.first::<NullablePerson>(None).await?.unwrap();
    assert_eq!(person.id, 3);
    assert_eq!(person.name, None);
    assert_eq!(person.age, None);

    Response::ok("ok")
}

#[worker::send]
pub async fn insert_and_retrieve_optional_some(
    _req: Request,
    env: Env,
    _data: SomeSharedData,
) -> Result<Response> {
    let db = env.d1("DB")?;
    let query = worker::query!(
        &db,
        "INSERT INTO nullable_people (id, name, age) VALUES (?1, ?2, ?3)",
        &4,
        &"Dude",
        &12
    )?;
    query.run().await?;

    let stmt = worker::query!(&db, "SELECT * FROM nullable_people WHERE id = 4");
    let person = stmt.first::<NullablePerson>(None).await?.unwrap();
    assert_eq!(person.id, 4);
    assert_eq!(person.name, Some("Dude".to_string()));
    assert_eq!(person.age, Some(12));

    Response::ok("ok")
}

#[worker::send]
pub async fn retrieve_optional_none(
    _req: Request,
    env: Env,
    _data: SomeSharedData,
) -> Result<Response> {
    let db = env.d1("DB")?;

    let stmt = worker::query!(&db, "SELECT * FROM nullable_people WHERE id = 1");
    let person = stmt.first::<NullablePerson>(None).await?.unwrap();
    assert_eq!(person.id, 1);
    assert_eq!(person.name, None);
    assert_eq!(person.age, None);

    Response::ok("ok")
}

#[worker::send]
pub async fn retrieve_optional_some(
    _req: Request,
    env: Env,
    _data: SomeSharedData,
) -> Result<Response> {
    let db = env.d1("DB")?;

    let stmt = worker::query!(&db, "SELECT * FROM nullable_people WHERE id = 2");
    let person = stmt.first::<NullablePerson>(None).await?.unwrap();
    assert_eq!(person.id, 2);
    assert_eq!(person.name, Some("Wynne Ogley".to_string()));
    assert_eq!(person.age, Some(67));

    Response::ok("ok")
}

#[worker::send]
pub async fn retrive_first_none(
    _req: Request,
    env: Env,
    _data: SomeSharedData,
) -> Result<Response> {
    let db = env.d1("DB")?;

    let stmt = worker::query!(&db, "SELECT * FROM nullable_people WHERE id = 9999");
    assert!(stmt.first::<NullablePerson>(None).await?.is_none());

    Response::ok("ok")
}