Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Test
on:
workflow_call: { }
workflow_call: {}
push:
branches:
- master
Expand Down Expand Up @@ -41,7 +41,7 @@ jobs:
uses: alorel-actions/cargo/init@v2
id: toolchain
with:
toolchain: nightly-2024-10-18
toolchain: nightly-2025-05-05
cache-prefix: doc
local: true

Expand Down Expand Up @@ -104,7 +104,7 @@ jobs:
include:
- toolchain: nightly-2025-05-05
os: ubuntu-latest
- toolchain: 1.75.0
- toolchain: 1.85.0
os: ubuntu-latest
- toolchain: stable
os: ubuntu-latest
Expand All @@ -120,7 +120,7 @@ jobs:
fail-fast: false
matrix:
flags:
- ''
- ""
- --features cursors
- --features dates
- --features indices
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ name = "indexed_db_futures"
version = "0.6.4"
authors = ["Arturas Molcanovas <amolc@pm.me>"]
edition = "2021"
rust-version = "1.75.0"
rust-version = "1.85.0"
license = "MIT"
description = "Future bindings for IndexedDB via web_sys"
repository = "https://github.com/Alorel/rust-indexed-db"
Expand Down
35 changes: 3 additions & 32 deletions internal_macros/src/generic_bounds.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::commons::FnTarget;
use crate::TokenStream1;
use macroific::prelude::*;
use proc_macro2::Ident;
use quote::ToTokens;
use syn::{parse_quote, Error, WherePredicate};

Expand All @@ -22,7 +20,7 @@ macro_rules! make_opts {
///
/// | Option | Type |
/// |--------|-----------|
$($(#[doc = concat!(" | `", stringify!($extra_opt), "` | `", stringify!($extra_ty), "` |")])+)+
$($(#[doc = concat!(" | `", stringify!($extra_opt), "` | `", stringify!($extra_ty), "` |")])+)*
#[derive(::macroific::attr_parse::AttributeOptions)]
pub(super) struct $struct_name {
$($($opt: ::syn::punctuated::Punctuated<proc_macro2::Ident, ::syn::Token![,]>,)+)+
Expand Down Expand Up @@ -53,10 +51,8 @@ make_opts!(Opts => {
db_name|index_name|store_name|key_path => ::core::convert::AsRef<str>,
db_version => crate::factory::DBVersion,
blocked_cb => ::core::ops::FnOnce(crate::database::VersionChangeEvent) -> crate::Result<()> + 'static,
upgrade_cb => ::core::ops::FnOnce(crate::database::VersionChangeEvent, crate::database::Database) -> crate::Result<()> + 'static,
[custom] => {
upgrade_async_cb => UpgradeAsyncCb,
},
upgrade_cb => ::core::ops::FnOnce(crate::database::VersionChangeEvent, &crate::transaction::Transaction<'_>) -> crate::Result<()> + 'static,
upgrade_async_cb => ::core::ops::AsyncFnOnce(crate::database::VersionChangeEvent, &crate::transaction::Transaction<'_>) -> crate::Result<()> + 'static,
});

#[inline]
Expand All @@ -73,31 +69,6 @@ pub(super) fn exec(spec: TokenStream1, target: TokenStream1) -> TokenStream1 {
}
}

#[derive(ParseOption)]
struct UpgradeAsyncCb {
#[attr_opts(default = false)]
fun: Ident,

#[attr_opts(default = false)]
fut: Ident,
}

impl UpgradeAsyncCb {
fn extend_target(self, target: &mut FnTarget) {
let Self { fun, fut } = self;
let wheres = [
parse_quote!(#fun: ::core::ops::FnOnce(crate::database::VersionChangeEvent, crate::database::Database) -> #fut + 'static),
parse_quote!(#fut: ::core::future::Future<Output = crate::Result<()>> + 'static),
];

target
.generics_mut()
.make_where_clause()
.predicates
.extend::<[WherePredicate; 2]>(wheres);
}
}

fn on_err(mut target: TokenStream1, e: Error) -> TokenStream1 {
let e: TokenStream1 = e.into_compile_error().into();
target.extend(e);
Expand Down
6 changes: 3 additions & 3 deletions src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<'a, Qs> Cursor<'a, Qs> {
/// followed by [`value`](https://developer.mozilla.org/en-US/docs/Web/API/IDBCursorWithValue/value) in JS.
#[errdoc(Cursor(TransactionInactiveError, InvalidStateError))]
#[inline]
pub fn next_record<T>(&mut self) -> CursorNextRequest<T>
pub fn next_record<T>(&mut self) -> CursorNextRequest<'_, T>
where
T: TryFromJs,
{
Expand All @@ -73,7 +73,7 @@ impl<'a, Qs> Cursor<'a, Qs> {

/// Mirror of [`Self::next_record`] for `serde`-deserialisable values.
#[cfg(feature = "serde")]
pub fn next_record_ser<T>(&mut self) -> CursorNextRequest<T>
pub fn next_record_ser<T>(&mut self) -> CursorNextRequest<'_, T>
where
T: crate::serde::DeserialiseFromJs,
{
Expand Down Expand Up @@ -106,7 +106,7 @@ impl<'a, Qs> Cursor<'a, Qs> {
DataCloneError,
))]
#[inline]
pub fn update<V>(&self, value: V) -> Update<V> {
pub fn update<V>(&self, value: V) -> Update<'_, V> {
Update::new(self, value)
}

Expand Down
4 changes: 2 additions & 2 deletions src/cursor/key_cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl<'a, Qs> KeyCursor<'a, Qs> {
/// followed by [`key`](https://developer.mozilla.org/en-US/docs/Web/API/IDBCursor/key) in JS.
#[inline]
#[errdoc(Cursor(TransactionInactiveError, InvalidStateError))]
pub fn next_key<T>(&mut self) -> CursorNextRequest<T>
pub fn next_key<T>(&mut self) -> CursorNextRequest<'_, T>
where
T: TryFromJs,
{
Expand All @@ -44,7 +44,7 @@ impl<'a, Qs> KeyCursor<'a, Qs> {
/// Mirror of [`Self::next_key`] for `serde`-deserialisable keys.
#[inline]
#[cfg(feature = "serde")]
pub fn next_key_ser<T>(&mut self) -> CursorNextRequest<T>
pub fn next_key_ser<T>(&mut self) -> CursorNextRequest<'_, T>
where
T: crate::serde::DeserialiseFromJs,
{
Expand Down
2 changes: 1 addition & 1 deletion src/cursor/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ impl<'a, Qs, T> Stream<Cursor<'a, Qs>, T> {
DataErrorUpdate,
DataCloneError
))]
pub fn update<V>(&self, value: V) -> super::Update<V> {
pub fn update<V>(&self, value: V) -> super::Update<'_, V> {
self.cursor.update(value)
}

Expand Down
6 changes: 3 additions & 3 deletions src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl Database {
/// Create an object store with the given name.
#[generic_bounds(store_name(N))]
#[inline]
pub fn create_object_store<N>(&self, name: N) -> StoreBuilder<N> {
pub fn create_object_store<N>(&self, name: N) -> StoreBuilder<'_, N> {
StoreBuilder::new(self, name)
}

Expand Down Expand Up @@ -99,15 +99,15 @@ impl Database {

/// List the names of the object stores within this database.
#[inline]
pub fn object_store_names(&self) -> DomStringIter {
pub fn object_store_names(&self) -> DomStringIter<'_> {
DomStringIter::new(self.as_sys().object_store_names())
}

/// Start a transaction on the given store name(s). Finish the builder with a call to
/// [`Build::build`](crate::Build::build).
#[errdoc(Database(NotFoundErrorTx, InvalidAccessErrorTx))]
#[inline]
pub fn transaction<S: ObjectStoreName>(&self, store_names: S) -> TransactionBuilder<S> {
pub fn transaction<S: ObjectStoreName>(&self, store_names: S) -> TransactionBuilder<'_, S> {
TransactionBuilder::new(self, store_names)
}

Expand Down
4 changes: 4 additions & 0 deletions src/error/unexpected_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ pub enum UnexpectedDataError {
#[error("`Future` polled unexpectedly.")]
PollState,

/// Expected a Transaction to exist, but it was not found.
#[error("Expected the Transaction to exist, but it was not found.")]
TransactionNotFound,

/// Expected a Transaction to be aborted, but it was committed.
#[error("Expected the Transaction to be aborted, but it was committed.")]
TransactionCommitted,
Expand Down
4 changes: 2 additions & 2 deletions src/factory/req_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ impl<N, V, B, U, Fa> OpenDbRequestBuilder<N, V, B, U, Fa> {

/// Set the [upgradeneeded](https://developer.mozilla.org/en-US/docs/Web/API/IDBOpenDBRequest/upgradeneeded_event)
/// event handler that returns a `Future`.
#[generic_bounds(upgrade_async_cb(fun(U2), fut(U2Fut)))]
#[generic_bounds(upgrade_async_cb(U2))]
#[cfg(feature = "async-upgrade")]
pub fn with_on_upgrade_needed_fut<U2, U2Fut>(
pub fn with_on_upgrade_needed_fut<U2>(
self,
on_upgrade_needed: U2,
) -> OpenDbRequestBuilder<N, V, B, OpenDbListener, Fa> {
Expand Down
36 changes: 27 additions & 9 deletions src/future/open_db/listener.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::database::{Database, VersionChangeEvent};
use crate::error::{Error, UnexpectedDataError};
use crate::transaction::{OnTransactionDrop, Transaction};
use internal_macros::generic_bounds;
use std::fmt::{Debug, Display, Formatter};
use std::mem;
Expand Down Expand Up @@ -56,9 +57,16 @@ impl OpenDbListener {
#[cfg(feature = "async-upgrade")]
async_notify: Self::fake_rx(),
listener: Closure::once(move |evt: web_sys::IdbVersionChangeEvent| {
let res = Database::from_event(&evt)
.and_then(move |db| callback(VersionChangeEvent::new(evt), db));

let res = Database::from_event(&evt).and_then(|db| {
Transaction::from_raw_version_change_event(&db, &evt).and_then(|mut tx| {
callback(VersionChangeEvent::new(evt), &tx).inspect(|()| {
// If the callback succeeded, we want to ensure that
// the transaction is committed when dropped and not
// aborted.
tx.on_drop(OnTransactionDrop::Commit);
})
})
});
Self::handle_result(LBL_UPGRADE, &status, res)
}),
}
Expand Down Expand Up @@ -154,8 +162,8 @@ const _: () = {
tokio::sync::mpsc::unbounded_channel().1
}

#[generic_bounds(upgrade_async_cb(fun(Fn), fut(Fut)))]
pub(crate) fn new_upgrade_fut<Fn, Fut>(callback: Fn) -> Self {
#[generic_bounds(upgrade_async_cb(Fn))]
pub(crate) fn new_upgrade_fut<Fn>(callback: Fn) -> Self {
let status = Status::new();
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
Self {
Expand All @@ -168,11 +176,21 @@ const _: () = {
};

Self::set_status(&status, Status::Pending, LBL_UPGRADE)?;
let fut = callback(VersionChangeEvent::new(evt), db);

wasm_bindgen_futures::spawn_local(async move {
let result = match fut.await {
Ok(()) => Status::Ok,
let db = db;
let result = match Transaction::from_raw_version_change_event(&db, &evt) {
Ok(mut transaction) => {
match callback(VersionChangeEvent::new(evt), &transaction).await {
Ok(()) => {
// If the callback succeeded, we want to ensure that
// the transaction is committed when dropped and not
// aborted.
transaction.on_drop(OnTransactionDrop::Commit);
Status::Ok
}
Err(e) => Status::Err(e),
}
}
Err(e) => Status::Err(e),
};
let _ = Self::set_status(&status, result, LBL_UPGRADE);
Expand Down
6 changes: 3 additions & 3 deletions src/index/object_store_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl ObjectStore<'_> {
))]
#[generic_bounds(index_name(N), key_path(KP))]
#[inline]
pub fn create_index<N, KP>(&self, name: N, key_path: KeyPath<KP>) -> IndexBuilder<N, KP> {
pub fn create_index<N, KP>(&self, name: N, key_path: KeyPath<KP>) -> IndexBuilder<'_, N, KP> {
IndexBuilder::new(self, name, key_path)
}

Expand All @@ -38,15 +38,15 @@ impl ObjectStore<'_> {
/// Open an index with the given name
#[errdoc(Index(InvalidStateErrorIndex, NotFoundError))]
#[allow(clippy::missing_errors_doc)]
pub fn index(&self, name: &str) -> crate::Result<Index> {
pub fn index(&self, name: &str) -> crate::Result<Index<'_>> {
match self.as_sys().index(name) {
Ok(sys) => Ok(Index::new(self, sys)),
Err(e) => Err(e.into()),
}
}

/// Return the names of the indices on this object store.
pub fn index_names(&self) -> DomStringIter {
pub fn index_names(&self) -> DomStringIter<'_> {
DomStringIter::new(self.as_sys().index_names())
}
}
2 changes: 1 addition & 1 deletion src/key_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub enum KeyPath<T = String> {

#[generic_bounds(key_path(T))]
impl<T> KeyPath<T> {
/// Convert the key path to a JsValue.
/// Convert the key path to a `JsValue`.
pub fn to_js(&self) -> JsValue {
match self {
Self::One(v) => JsValue::from_str(v.as_ref()),
Expand Down
15 changes: 12 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,21 @@
//! ## Opening a database & making some schema changes
//!
//! ```
//! use indexed_db_futures::database::Database;
//! use indexed_db_futures::database::{Database, VersionChangeEvent};
//! use indexed_db_futures::prelude::*;
//! use indexed_db_futures::transaction::TransactionMode;
//! use indexed_db_futures::transaction::{Transaction, TransactionMode};
//!
//! # async fn example() -> indexed_db_futures::OpenDbResult<()> {
//! # #[allow(dead_code)]
//! # #[cfg(all(feature = "async-upgrade", feature = "tx-done"))]
//! let db = Database::open("my_db")
//! .with_version(2u8)
//! .with_on_blocked(|event| {
//! log::debug!("DB upgrade blocked: {:?}", event);
//! Ok(())
//! })
//! .with_on_upgrade_needed_fut(|event, db| async move {
//! .with_on_upgrade_needed_fut(async |event: VersionChangeEvent, tx: &Transaction<'_>| {
//! let db = tx.db();
//! // Convert versions from floats to integers to allow using them in match expressions
//! let old_version = event.old_version() as u64;
//! let new_version = event.new_version().map(|v| v as u64);
Expand Down Expand Up @@ -141,6 +143,8 @@
//! ## Reading/writing with `serde`
//!
//! ```
//! # #[cfg(feature = "serde")]
//! # mod wrapper {
//! # use indexed_db_futures::object_store::ObjectStore;
//! # use indexed_db_futures::prelude::*;
//! # use serde::{Deserialize, Serialize};
Expand All @@ -157,6 +161,7 @@
//! let user: Option<UserRef> = object_store.get(1u32).serde()?.await?;
//! # Ok(())
//! # }
//! # }
//! ```
//!
//! # Iterating a cursor
Expand All @@ -166,6 +171,7 @@
//! # use indexed_db_futures::prelude::*;
//! #
//! # #[allow(dead_code)]
//! # #[cfg(feature = "cursors")]
//! # async fn example(object_store: ObjectStore<'_>) -> indexed_db_futures::Result<()> {
//! let Some(mut cursor) = object_store.open_cursor().await? else {
//! log::debug!("Cursor empty");
Expand All @@ -181,6 +187,8 @@
//! # Iterating an index as a stream
//!
//! ```
//! # #[cfg(all(feature = "serde", feature = "indices", feature = "cursors", feature = "streams"))]
//! # mod wrapper {
//! # use indexed_db_futures::object_store::ObjectStore;
//! # use indexed_db_futures::prelude::*;
//! # use serde::{Deserialize, Serialize};
Expand All @@ -203,6 +211,7 @@
//! let records = stream.try_collect::<Vec<_>>().await?;
//! # Ok(())
//! # }
//! # }
//! ```
//!

Expand Down
Loading