From d43b8910f3744075200ca0099d7f46fd834f6d93 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 26 Aug 2024 16:22:56 -0400 Subject: [PATCH] Organize wasm tests (#995) * organize wasm tests so they all run * make test organization much better, fix tests * fix workflow file --- .github/workflows/release-cli.yml | 1 + .github/workflows/test-wasm.yml | 31 +++- diesel-wasm-sqlite/Cargo.lock | 11 ++ diesel-wasm-sqlite/Cargo.toml | 4 +- diesel-wasm-sqlite/build.rs | 1 + diesel-wasm-sqlite/package.js | 4 + diesel-wasm-sqlite/package.json | 2 +- diesel-wasm-sqlite/src/connection/mod.rs | 6 +- diesel-wasm-sqlite/src/connection/stmt.rs | 2 +- diesel-wasm-sqlite/src/ffi.rs | 3 + diesel-wasm-sqlite/src/lib.rs | 13 -- diesel-wasm-sqlite/src/query_builder/mod.rs | 2 +- .../src/query_builder/query_fragment_impls.rs | 11 +- diesel-wasm-sqlite/src/sqlite_fixes.rs | 169 +++++++++++++++++- .../src/wa-sqlite-diesel-bundle.js | 4 + diesel-wasm-sqlite/tests/common/mod.rs | 42 +++++ .../tests/dedicated_web_worker.rs | 17 ++ .../2024-08-20-203551_create_books/down.sql | 0 .../2024-08-20-203551_create_books/up.sql | 2 +- diesel-wasm-sqlite/tests/{ => test}/row.rs | 7 +- diesel-wasm-sqlite/tests/{ => test}/web.rs | 153 ++++++++-------- 21 files changed, 373 insertions(+), 112 deletions(-) create mode 100644 diesel-wasm-sqlite/tests/common/mod.rs create mode 100755 diesel-wasm-sqlite/tests/dedicated_web_worker.rs rename diesel-wasm-sqlite/tests/{web => }/migrations/2024-08-20-203551_create_books/down.sql (100%) rename diesel-wasm-sqlite/tests/{web => }/migrations/2024-08-20-203551_create_books/up.sql (63%) rename diesel-wasm-sqlite/tests/{ => test}/row.rs (95%) rename diesel-wasm-sqlite/tests/{ => test}/web.rs (52%) diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index d15be2764..ccf6435be 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -44,6 +44,7 @@ jobs: - name: Configure x86_64-unknown-linux-musl toolchain if: ${{ matrix.target == 'x86_64-unknown-linux-musl' }} run: | + sudo apt-get update sudo apt-get install -y musl-tools - name: Install openssl windows diff --git a/.github/workflows/test-wasm.yml b/.github/workflows/test-wasm.yml index aa74e889e..b60d7d721 100644 --- a/.github/workflows/test-wasm.yml +++ b/.github/workflows/test-wasm.yml @@ -1,4 +1,4 @@ -name: Test DIesel WASM Backend +name: Test Diesel WASM Backend on: push: branches: @@ -6,7 +6,7 @@ on: pull_request: # only run tests when related changes are made paths: - - ".github/workflows/test-workspace.yml" + - ".github/workflows/test-wasm.yml" - "dev/**" - "diesel-wasm-sqlite/**" - "Cargo.toml" @@ -15,18 +15,39 @@ on: jobs: test: name: Test - runs-on: warp-ubuntu-latest-x64-16x + # running with macos since it contains the safari driver + runs-on: warp-macos-13-arm64-6x steps: - name: Checkout uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - run: brew install --cask firefox - name: Update rust toolchains run: rustup update - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - name: Setup node and yarn + uses: actions/setup-node@v4 + with: + node-version-file: ".node-version" + cache-dependency-path: "diesel-wasm-sqlite/yarn.lock" + cache: "yarn" + env: + SKIP_YARN_COREPACK_CHECK: "1" + - name: Enable corepack + run: corepack enable + - name: Run Yarn install + uses: borales/actions-yarn@v5 + with: + cmd: --cwd diesel-wasm-sqlite/ install - name: Cache uses: Swatinem/rust-cache@v2 with: workspaces: | . - - name: Run cargo test on main workspace - run: wasm-pack test --manifest-path diesel-wasm-sqlite/Cargo.toml --features test-util --features unsafe-debug-query + - run: wasm-pack test --headless --safari --features unsafe-debug-query + working-directory: diesel-wasm-sqlite + - run: wasm-pack test --headless --chrome --features unsafe-debug-query + working-directory: diesel-wasm-sqlite + - run: wasm-pack test --headless --firefox --features unsafe-debug-query + working-directory: diesel-wasm-sqlite diff --git a/diesel-wasm-sqlite/Cargo.lock b/diesel-wasm-sqlite/Cargo.lock index ae8ddc8bf..c2556b308 100644 --- a/diesel-wasm-sqlite/Cargo.lock +++ b/diesel-wasm-sqlite/Cargo.lock @@ -114,6 +114,16 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "ctor" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "darling" version = "0.20.10" @@ -166,6 +176,7 @@ version = "0.1.1" dependencies = [ "chrono", "console_error_panic_hook", + "ctor", "diesel", "diesel_derives", "diesel_migrations", diff --git a/diesel-wasm-sqlite/Cargo.toml b/diesel-wasm-sqlite/Cargo.toml index e83253ce3..f69a49156 100644 --- a/diesel-wasm-sqlite/Cargo.toml +++ b/diesel-wasm-sqlite/Cargo.toml @@ -8,7 +8,7 @@ resolver = "2" talc = { version = "4.4", default-features = false, features = ["lock_api"] } diesel = { version = "2.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] } diesel_derives = "2.2" -wasm-bindgen = "0.2.92" +wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" js-sys = { version = "0.3" } tracing = "0.1" @@ -27,6 +27,7 @@ chrono = { version = "0.4", features = ["wasmbind", "serde"] } diesel_migrations = "2.2" diesel = { version = "2.2", features = ["chrono"]} tracing-wasm = { version = "0.2" } +ctor = "0.2" [lib] @@ -38,7 +39,6 @@ r2d2 = ["diesel/r2d2"] # enables a `DebugQueryWrapper` for diesel # but is unsafe because of mem::transmute unsafe-debug-query = [] -test-util = ["unsafe-debug-query"] [build] target = "wasm32-unknown-unknown" diff --git a/diesel-wasm-sqlite/build.rs b/diesel-wasm-sqlite/build.rs index f6e5b3913..c3f197ab1 100644 --- a/diesel-wasm-sqlite/build.rs +++ b/diesel-wasm-sqlite/build.rs @@ -5,6 +5,7 @@ fn main() { println!("cargo::rerun-if-changed=package.js"); println!("cargo::rerun-if-changed=package.json"); + Command::new("yarn").args(["install"]).status().unwrap(); Command::new("yarn") .args(["run", "build"]) .status() diff --git a/diesel-wasm-sqlite/package.js b/diesel-wasm-sqlite/package.js index d322767dc..d2b30155b 100644 --- a/diesel-wasm-sqlite/package.js +++ b/diesel-wasm-sqlite/package.js @@ -34,6 +34,10 @@ export class SQLite { return this.sqlite3.version; } + filename(db, name) { + return this.sqlite3.capi.sqlite3_db_filename(db, name); + } + extended_errcode(connection) { return this.sqlite3.capi.sqlite3_extended_errcode(connection); } diff --git a/diesel-wasm-sqlite/package.json b/diesel-wasm-sqlite/package.json index f8d2b750c..889f11777 100644 --- a/diesel-wasm-sqlite/package.json +++ b/diesel-wasm-sqlite/package.json @@ -12,7 +12,7 @@ }, "packageManager": "yarn@4.3.1", "engines": { - "node": ">=20" + "node": ">=18" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.3", diff --git a/diesel-wasm-sqlite/src/connection/mod.rs b/diesel-wasm-sqlite/src/connection/mod.rs index 06087d907..6c8ca78dc 100644 --- a/diesel-wasm-sqlite/src/connection/mod.rs +++ b/diesel-wasm-sqlite/src/connection/mod.rs @@ -305,6 +305,10 @@ impl WasmSqliteConnection { fn establish_inner(database_url: &str) -> Result { let sqlite3 = crate::get_sqlite_unchecked(); let raw_connection = RawConnection::establish(database_url).unwrap(); + tracing::debug!( + "Established database at {}", + sqlite3.filename(&raw_connection.internal_connection, "main".into()) + ); sqlite3 .register_diesel_sql_functions(&raw_connection.internal_connection) .map_err(WasmSqliteError::from)?; @@ -322,6 +326,6 @@ pub struct Nothing; impl Instrumentation for Nothing { fn on_connection_event(&mut self, event: diesel::connection::InstrumentationEvent<'_>) { - tracing::info!("Inst. Event {:?}", event); + tracing::trace!("{:?}", event); } } diff --git a/diesel-wasm-sqlite/src/connection/stmt.rs b/diesel-wasm-sqlite/src/connection/stmt.rs index 64e076160..428d4163c 100644 --- a/diesel-wasm-sqlite/src/connection/stmt.rs +++ b/diesel-wasm-sqlite/src/connection/stmt.rs @@ -184,7 +184,7 @@ impl Statement { impl Drop for Statement { fn drop(&mut self) { let sqlite3 = crate::get_sqlite_unchecked(); - tracing::info!("Statement dropped & finalized!"); + tracing::trace!("Statement dropped & finalized!"); let _ = sqlite3 .finalize(&self.inner_statement) .expect("Error finalized SQLite prepared statement"); diff --git a/diesel-wasm-sqlite/src/ffi.rs b/diesel-wasm-sqlite/src/ffi.rs index 527547501..6c42cd38a 100644 --- a/diesel-wasm-sqlite/src/ffi.rs +++ b/diesel-wasm-sqlite/src/ffi.rs @@ -167,6 +167,9 @@ extern "C" { #[wasm_bindgen(method)] pub fn version(this: &SQLite) -> JsValue; + #[wasm_bindgen(method)] + pub fn filename(this: &SQLite, db: &JsValue, name: String) -> String; + #[wasm_bindgen(method)] pub fn errstr(this: &SQLite, code: i32) -> String; diff --git a/diesel-wasm-sqlite/src/lib.rs b/diesel-wasm-sqlite/src/lib.rs index 5fb80d088..0bbd97545 100755 --- a/diesel-wasm-sqlite/src/lib.rs +++ b/diesel-wasm-sqlite/src/lib.rs @@ -15,9 +15,6 @@ pub use query_builder::insert_with_default_sqlite::unsafe_debug_query::DebugQuer #[cfg(not(target_arch = "wasm32"))] compile_error!("This crate only suports the `wasm32-unknown-unknown` target"); -#[cfg(any(test))] -pub use test_common::*; - use wasm_bindgen::JsValue; pub use backend::{SqliteType, WasmSqlite}; @@ -53,13 +50,3 @@ impl From for WasmSqliteError { WasmSqliteError::Js(err) } } - -#[cfg(any(test, feature = "test-util"))] -pub mod test_common { - use super::connection::WasmSqliteConnection; - use diesel::Connection; - pub async fn connection() -> WasmSqliteConnection { - crate::init_sqlite().await; - WasmSqliteConnection::establish(":memory:").unwrap() - } -} diff --git a/diesel-wasm-sqlite/src/query_builder/mod.rs b/diesel-wasm-sqlite/src/query_builder/mod.rs index bfeff776c..09232cbb9 100644 --- a/diesel-wasm-sqlite/src/query_builder/mod.rs +++ b/diesel-wasm-sqlite/src/query_builder/mod.rs @@ -6,7 +6,7 @@ use diesel::result::QueryResult; pub(super) mod insert_with_default_sqlite; mod limit_offset; -mod query_fragment_impls; +// mod query_fragment_impls; // mod returning; /// Constructs SQL queries for use with the SQLite backend diff --git a/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs b/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs index d09773d6a..129c0bf2c 100644 --- a/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs +++ b/diesel-wasm-sqlite/src/query_builder/query_fragment_impls.rs @@ -1,13 +1,13 @@ -/* -// use diesel::query_builder::into_conflict_clause::OnConflictSelectWrapper; -// use diesel::query_builder::where_clause::BoxedWhereClause; +use crate::WasmSqlite; +use diesel::query_builder::into_conflict_clause::OnConflictSelectWrapper; +use diesel::query_builder::where_clause::BoxedWhereClause; +use diesel::query_builder::where_clause::WhereClause; use diesel::query_builder::AstPass; use diesel::query_builder::BoxedSelectStatement; use diesel::query_builder::QueryFragment; use diesel::query_builder::SelectStatement; -// use diesel::query_builder::WhereClause; -use crate::storage::wasm_sqlite::WasmSqlite; use diesel::result::QueryResult; +use diesel::QueryId; // The corresponding impl for`NoWhereClause` is missing because of // https://www.sqlite.org/lang_UPSERT.html (Parsing Ambiguity) @@ -38,4 +38,3 @@ where }) } } -*/ diff --git a/diesel-wasm-sqlite/src/sqlite_fixes.rs b/diesel-wasm-sqlite/src/sqlite_fixes.rs index 3a7afdc4c..f752df2ac 100644 --- a/diesel-wasm-sqlite/src/sqlite_fixes.rs +++ b/diesel-wasm-sqlite/src/sqlite_fixes.rs @@ -4,7 +4,7 @@ use diesel::{ query_builder::AstPass, query_builder::NoFromClause, query_builder::QueryFragment, - AppearsOnTable, Column, Expression, QueryResult, + AppearsOnTable, Column, Expression, QueryId, QueryResult, }; impl InsertValues @@ -37,13 +37,49 @@ where Ok(()) } } -/* + +#[derive(Debug, Copy, Clone, QueryId)] +pub struct InsertOrIgnore; + +impl QueryFragment for InsertOrIgnore { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + out.push_sql("INSERT OR IGNORE"); + Ok(()) + } +} + +#[derive(Debug, Copy, Clone, QueryId)] +pub struct Replace; + +impl QueryFragment for Replace { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + out.push_sql("REPLACE"); + Ok(()) + } +} + mod parenthesis_wrapper { + use super::*; + use crate::WasmSqlite; - use diesel::helper_types::{Distinct, Except, Intersect, Union}; - use diesel::query_builder::ParenthesisWrapper; + // use diesel::query_builder::combination_clause::SupportsCombinationClause; use diesel::query_builder::{AstPass, QueryFragment}; + #[derive(Debug, Copy, Clone, QueryId)] + /// Wrapper used to wrap rhs sql in parenthesis when supported by backend + pub struct ParenthesisWrapper(T); + + #[derive(Debug, Copy, Clone, QueryId)] + /// Keep duplicate rows in the result + pub struct All; + + impl QueryFragment for All { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { + out.push_sql("ALL "); + Ok(()) + } + } + impl> QueryFragment for ParenthesisWrapper { fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, WasmSqlite>) -> QueryResult<()> { // SQLite does not support parenthesis around this clause @@ -55,10 +91,133 @@ mod parenthesis_wrapper { Ok(()) } } - + /* impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} impl SupportsCombinationClause for WasmSqlite {} + */ +} + +// Anything commented here are implementation present in diesel +// but not possible because parts of it exist as private types in diesel. + +/* +impl<'b, Changes, Output> UpdateAndFetchResults for SqliteConnection +where + Changes: Copy + Identifiable, + Changes: AsChangeset::Table> + IntoUpdateTarget, + Changes::Table: FindDsl, + Update: ExecuteDsl, + Find: LoadQuery<'b, SqliteConnection, Output>, + ::AllColumns: ValidGrouping<()>, + <::AllColumns as ValidGrouping<()>>::IsAggregate: + MixedAggregates, +{ + fn update_and_fetch(&mut self, changeset: Changes) -> QueryResult { + crate::update(changeset).set(changeset).execute(self)?; + Changes::table().find(changeset.id()).get_result(self) + } +} +*/ +/* +impl AsExpression for now { + type Expression = Coerce; + + fn as_expression(self) -> Self::Expression { + Coerce::new(self) + } +} + +impl AsExpression> for now { + type Expression = Coerce>; + + fn as_expression(self) -> Self::Expression { + Coerce::new(self) + } +} +*/ + +/* +use diesel::dsl; +use diesel::expression::grouped::Grouped; +use diesel::expression::AsExpression; +use diesel::operators::*; +use diesel::sql_types::SqlType; + +/// Sqlite specific methods which are present on all expressions. +pub trait SqliteExpressionMethods: Expression + Sized { + /// Creates a Sqlite `IS` expression. + /// + /// The `IS` operator work like = except when one or both of the operands are NULL. + /// In this case, if both operands are NULL, then the `IS` operator evaluates to true. + /// If one operand is NULL and the other is not, then the `IS` operator evaluates to false. + /// It is not possible for an `IS` expression to evaluate to NULL. + /// + /// # Example + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # fn main() { + /// # run_test().unwrap(); + /// # } + /// # + /// # fn run_test() -> QueryResult<()> { + /// # use schema::animals::dsl::*; + /// # let connection = &mut establish_connection(); + /// let jack_is_a_dog = animals + /// .select(name) + /// .filter(species.is("dog")) + /// .get_results::>(connection)?; + /// assert_eq!(vec![Some("Jack".to_string())], jack_is_a_dog); + /// # Ok(()) + /// # } + /// ``` + fn is(self, other: T) -> dsl::Is + where + Self::SqlType: SqlType, + T: AsExpression, + { + Grouped(Is::new(self, other.as_expression())) + } + + /// Creates a Sqlite `IS NOT` expression. + /// + /// The `IS NOT` operator work like != except when one or both of the operands are NULL. + /// In this case, if both operands are NULL, then the `IS NOT` operator evaluates to false. + /// If one operand is NULL and the other is not, then the `IS NOT` operator is true. + /// It is not possible for an `IS NOT` expression to evaluate to NULL. + /// + /// # Example + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # fn main() { + /// # run_test().unwrap(); + /// # } + /// # + /// # fn run_test() -> QueryResult<()> { + /// # use schema::animals::dsl::*; + /// # let connection = &mut establish_connection(); + /// let jack_is_not_a_spider = animals + /// .select(name) + /// .filter(species.is_not("spider")) + /// .get_results::>(connection)?; + /// assert_eq!(vec![Some("Jack".to_string())], jack_is_not_a_spider); + /// # Ok(()) + /// # } + /// ``` + #[allow(clippy::wrong_self_convention)] // This is named after the sql operator + fn is_not(self, other: T) -> dsl::IsNot + where + Self::SqlType: SqlType, + T: AsExpression, + { + Grouped(IsNot::new(self, other.as_expression())) + } } + +impl SqliteExpressionMethods for T {} */ diff --git a/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js b/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js index 38da2f941..f6d2fbe51 100644 --- a/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js +++ b/diesel-wasm-sqlite/src/wa-sqlite-diesel-bundle.js @@ -14440,6 +14440,10 @@ class SQLite { return this.sqlite3.version; } + filename(db, name) { + return this.sqlite3.capi.sqlite3_db_filename(db, name); + } + extended_errcode(connection) { return this.sqlite3.capi.sqlite3_extended_errcode(connection); } diff --git a/diesel-wasm-sqlite/tests/common/mod.rs b/diesel-wasm-sqlite/tests/common/mod.rs new file mode 100644 index 000000000..6a3418476 --- /dev/null +++ b/diesel-wasm-sqlite/tests/common/mod.rs @@ -0,0 +1,42 @@ +//! Common utilities/imports amongst WebAssembly tests +use prelude::*; + +use tokio::sync::OnceCell; + +static INIT: OnceCell<()> = OnceCell::const_new(); + +pub async fn init() { + INIT.get_or_init(|| async { + console::log_1(&"INIT".into()); + console_error_panic_hook::set_once(); + tracing_wasm::set_as_global_default(); + diesel_wasm_sqlite::init_sqlite().await; + }) + .await; +} + +pub async fn connection() -> WasmSqliteConnection { + diesel_wasm_sqlite::init_sqlite().await; + WasmSqliteConnection::establish(":memory:").unwrap() +} + +// re-exports used in tests +#[allow(unused)] +pub mod prelude { + pub(crate) use super::init; + pub(crate) use diesel::{ + connection::{Connection, LoadConnection}, + debug_query, + deserialize::{self, FromSql, FromSqlRow}, + insert_into, + prelude::*, + sql_types::{Integer, Nullable, Text}, + }; + pub(crate) use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; + pub(crate) use diesel_wasm_sqlite::{ + connection::WasmSqliteConnection, DebugQueryWrapper, WasmSqlite, + }; + pub(crate) use serde::Deserialize; + pub(crate) use wasm_bindgen_test::*; + pub(crate) use web_sys::console; +} diff --git a/diesel-wasm-sqlite/tests/dedicated_web_worker.rs b/diesel-wasm-sqlite/tests/dedicated_web_worker.rs new file mode 100755 index 000000000..7c904c52a --- /dev/null +++ b/diesel-wasm-sqlite/tests/dedicated_web_worker.rs @@ -0,0 +1,17 @@ +//! Integration Test Organization in rust is little bit non-standard comapred to normal +//! organization in a library/binary. +//! In order to avoid being compiled as a test, common functions must be defined in +//! `common/mod.rs` +//! +//! Tests are separated into separate files in the module `test`. +#![recursion_limit = "256"] +#![cfg(target_arch = "wasm32")] + +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + +mod common; + +mod test { + mod row; + mod web; +} diff --git a/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/down.sql b/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/down.sql similarity index 100% rename from diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/down.sql rename to diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/down.sql diff --git a/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql b/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/up.sql similarity index 63% rename from diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql rename to diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/up.sql index fd3df8b20..dc1583510 100644 --- a/diesel-wasm-sqlite/tests/web/migrations/2024-08-20-203551_create_books/up.sql +++ b/diesel-wasm-sqlite/tests/migrations/2024-08-20-203551_create_books/up.sql @@ -1,5 +1,5 @@ CREATE TABLE books ( - id SERIAL PRIMARY KEY, + id INTEGER PRIMARY KEY NOT NULL, title TEXT NOT NULL, author TEXT ) diff --git a/diesel-wasm-sqlite/tests/row.rs b/diesel-wasm-sqlite/tests/test/row.rs similarity index 95% rename from diesel-wasm-sqlite/tests/row.rs rename to diesel-wasm-sqlite/tests/test/row.rs index 429f819aa..193e0da66 100644 --- a/diesel-wasm-sqlite/tests/row.rs +++ b/diesel-wasm-sqlite/tests/test/row.rs @@ -1,14 +1,9 @@ -use diesel::Connection; -use diesel_wasm_sqlite::{connection::WasmSqliteConnection, test_common::connection, WasmSqlite}; -use wasm_bindgen_test::*; -wasm_bindgen_test_configure!(run_in_dedicated_worker); +use crate::common::{connection, prelude::*}; // test copied from diesel #[wasm_bindgen_test] async fn fun_with_row_iters() { diesel_wasm_sqlite::init_sqlite().await; - console_error_panic_hook::set_once(); - tracing_wasm::set_as_global_default(); diesel::table! { #[allow(unused_parens)] diff --git a/diesel-wasm-sqlite/tests/web.rs b/diesel-wasm-sqlite/tests/test/web.rs similarity index 52% rename from diesel-wasm-sqlite/tests/web.rs rename to diesel-wasm-sqlite/tests/test/web.rs index 958e6e696..0679a1ba0 100755 --- a/diesel-wasm-sqlite/tests/web.rs +++ b/diesel-wasm-sqlite/tests/test/web.rs @@ -1,22 +1,7 @@ -//! Integration-like tests with a persistent database -#![recursion_limit = "256"] -#![cfg(target_arch = "wasm32")] +//! General tests for migrations/diesel ORM/persistant databases +use crate::common::prelude::*; -use diesel::connection::LoadConnection; -use diesel::deserialize::FromSqlRow; -use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; -use diesel_wasm_sqlite::{connection::WasmSqliteConnection, DebugQueryWrapper, WasmSqlite}; -use wasm_bindgen_test::*; -use web_sys::console; - -use diesel::debug_query; -use diesel::insert_into; -use diesel::prelude::*; -use serde::Deserialize; - -wasm_bindgen_test_configure!(run_in_dedicated_worker); - -pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./tests/web/migrations/"); +pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./tests/migrations/"); mod schema { diesel::table! { @@ -39,11 +24,14 @@ pub struct BookForm { // published_year: NaiveDateTime, } -#[derive(Queryable, Selectable, PartialEq, Debug)] +#[derive(Queryable, QueryableByName, Selectable, PartialEq, Debug)] #[diesel(table_name = books)] -pub struct Book { +pub struct StoredBook { + #[diesel(sql_type = Integer)] id: i32, + #[diesel(sql_type = Text)] title: String, + #[diesel(sql_type = Nullable)] author: Option, // published_year: NaiveDateTime, } @@ -90,72 +78,97 @@ fn examine_sql_from_insert_default_values() { #[wasm_bindgen_test] async fn test_orm_insert() { - console_error_panic_hook::set_once(); - tracing_wasm::set_as_global_default(); - + init().await; let mut conn = establish_connection().await; - - let rows_changed = insert_books( - &mut conn, + let new_books = vec![ + BookForm { + title: "Game of Thrones".into(), + author: Some("George R.R".into()), + // published_year: NaiveDate::from_ymd_opt(2015, 5, 3).unwrap(), + }, + BookForm { + title: "The Hobbit".into(), + author: Some("J.R.R. Tolkien".into()), + // published_year: NaiveDate::from_ymd_opt(1937, 9, 21).unwrap(), + }, + BookForm { + title: "To Kill a Mockingbird".into(), + author: Some("Harper Lee".into()), + // published_year: NaiveDate::from_ymd_opt(1960, 7, 11).unwrap(), + }, + BookForm { + title: "1984".into(), + author: Some("George Orwell".into()), + // published_year: NaiveDate::from_ymd_opt(1949, 6, 8).unwrap(), + }, + BookForm { + title: "Pride and Prejudice".into(), + author: Some("Jane Austen".into()), + // published_year: NaiveDate::from_ymd_opt(1813, 1, 28).unwrap(), + }, + BookForm { + title: "Moby-Dick".into(), + author: Some("Herman Melville".into()), + // published_year: NaiveDate::from_ymd_opt(1851, 10, 18).unwrap(), + }, + ]; + let rows_changed = insert_books(&mut conn, new_books).unwrap(); + assert_eq!(rows_changed, 6); + tracing::info!("{} rows changed", rows_changed); + console::log_1(&"Showing Users".into()); + let title = schema::books::table + .select(schema::books::title) + .filter(schema::books::id.eq(2)) + .first::(&mut conn) + .unwrap(); + assert_eq!(title, "The Hobbit"); + + let author = schema::books::table + .select(schema::books::author) + .filter(schema::books::id.eq(1)) + .first::>(&mut conn) + .unwrap(); + assert_eq!(author, Some("George R.R".into())); + + let id = schema::books::table + .select(schema::books::id) + .filter(schema::books::id.eq(1)) + .first::(&mut conn) + .unwrap(); + assert_eq!(id, 1); + + let loaded_books = schema::books::dsl::books + .select(StoredBook::as_select()) + .limit(5) + .load(&mut conn); + assert_eq!( + loaded_books.unwrap(), vec![ - BookForm { + StoredBook { + id: 1, title: "Game of Thrones".into(), author: Some("George R.R".into()), - // published_year: NaiveDate::from_ymd_opt(2015, 5, 3).unwrap(), }, - BookForm { + StoredBook { + id: 2, title: "The Hobbit".into(), author: Some("J.R.R. Tolkien".into()), - // published_year: NaiveDate::from_ymd_opt(1937, 9, 21).unwrap(), }, - BookForm { + StoredBook { + id: 3, title: "To Kill a Mockingbird".into(), author: Some("Harper Lee".into()), - // published_year: NaiveDate::from_ymd_opt(1960, 7, 11).unwrap(), }, - BookForm { + StoredBook { + id: 4, title: "1984".into(), author: Some("George Orwell".into()), - // published_year: NaiveDate::from_ymd_opt(1949, 6, 8).unwrap(), }, - BookForm { + StoredBook { + id: 5, title: "Pride and Prejudice".into(), author: Some("Jane Austen".into()), - // published_year: NaiveDate::from_ymd_opt(1813, 1, 28).unwrap(), }, - BookForm { - title: "Moby-Dick".into(), - author: Some("Herman Melville".into()), - // published_year: NaiveDate::from_ymd_opt(1851, 10, 18).unwrap(), - }, - ], + ] ) - .unwrap(); - assert_eq!(rows_changed, 6); - tracing::info!("{} rows changed", rows_changed); - console::log_1(&"Showing Users".into()); - let book = schema::books::table - .select(schema::books::title) - .load::(&mut conn); - tracing::info!("Loaded book {:?}", book); - let query = schema::books::table.limit(5).select(Book::as_select()); - let books = conn.load(query).unwrap().collect::>(); - /* - for row in books.iter() { - let deserialized_book = row.as_ref().map(|row| { - Book::build_from_row(row).unwrap() - }); - tracing::debug!("BOOK: {:?}", deserialized_book); - } - */ - // console::log_1(&debug_query::(&query).o_string().into()); - // .load(&mut conn) - // .await - // .expect("Error loading users"); - - /* - for book in books { - console::log_1(&format!("{}", book.title).into()); - } - */ }