Skip to content

Commit 201caac

Browse files
authored
Merge pull request #1 from mgoldenberg/expose-version-change-transaction
Provide access to active transaction in callback provided to `OpenDbRequestBuilder::with_on_upgrade_needed{_fut}`
2 parents abf8ddc + 6ec78c3 commit 201caac

File tree

27 files changed

+225
-141
lines changed

27 files changed

+225
-141
lines changed

.github/workflows/test.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Test
22
on:
3-
workflow_call: { }
3+
workflow_call: {}
44
push:
55
branches:
66
- master
@@ -41,7 +41,7 @@ jobs:
4141
uses: alorel-actions/cargo/init@v2
4242
id: toolchain
4343
with:
44-
toolchain: nightly-2024-10-18
44+
toolchain: nightly-2025-05-05
4545
cache-prefix: doc
4646
local: true
4747

@@ -104,7 +104,7 @@ jobs:
104104
include:
105105
- toolchain: nightly-2025-05-05
106106
os: ubuntu-latest
107-
- toolchain: 1.75.0
107+
- toolchain: 1.85.0
108108
os: ubuntu-latest
109109
- toolchain: stable
110110
os: ubuntu-latest
@@ -120,7 +120,7 @@ jobs:
120120
fail-fast: false
121121
matrix:
122122
flags:
123-
- ''
123+
- ""
124124
- --features cursors
125125
- --features dates
126126
- --features indices

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ name = "indexed_db_futures"
1010
version = "0.6.4"
1111
authors = ["Arturas Molcanovas <amolc@pm.me>"]
1212
edition = "2021"
13-
rust-version = "1.75.0"
13+
rust-version = "1.85.0"
1414
license = "MIT"
1515
description = "Future bindings for IndexedDB via web_sys"
1616
repository = "https://github.com/Alorel/rust-indexed-db"

internal_macros/src/generic_bounds.rs

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use crate::commons::FnTarget;
22
use crate::TokenStream1;
3-
use macroific::prelude::*;
4-
use proc_macro2::Ident;
53
use quote::ToTokens;
64
use syn::{parse_quote, Error, WherePredicate};
75

@@ -22,7 +20,7 @@ macro_rules! make_opts {
2220
///
2321
/// | Option | Type |
2422
/// |--------|-----------|
25-
$($(#[doc = concat!(" | `", stringify!($extra_opt), "` | `", stringify!($extra_ty), "` |")])+)+
23+
$($(#[doc = concat!(" | `", stringify!($extra_opt), "` | `", stringify!($extra_ty), "` |")])+)*
2624
#[derive(::macroific::attr_parse::AttributeOptions)]
2725
pub(super) struct $struct_name {
2826
$($($opt: ::syn::punctuated::Punctuated<proc_macro2::Ident, ::syn::Token![,]>,)+)+
@@ -53,10 +51,8 @@ make_opts!(Opts => {
5351
db_name|index_name|store_name|key_path => ::core::convert::AsRef<str>,
5452
db_version => crate::factory::DBVersion,
5553
blocked_cb => ::core::ops::FnOnce(crate::database::VersionChangeEvent) -> crate::Result<()> + 'static,
56-
upgrade_cb => ::core::ops::FnOnce(crate::database::VersionChangeEvent, crate::database::Database) -> crate::Result<()> + 'static,
57-
[custom] => {
58-
upgrade_async_cb => UpgradeAsyncCb,
59-
},
54+
upgrade_cb => ::core::ops::FnOnce(crate::database::VersionChangeEvent, &crate::transaction::Transaction<'_>) -> crate::Result<()> + 'static,
55+
upgrade_async_cb => ::core::ops::AsyncFnOnce(crate::database::VersionChangeEvent, &crate::transaction::Transaction<'_>) -> crate::Result<()> + 'static,
6056
});
6157

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

76-
#[derive(ParseOption)]
77-
struct UpgradeAsyncCb {
78-
#[attr_opts(default = false)]
79-
fun: Ident,
80-
81-
#[attr_opts(default = false)]
82-
fut: Ident,
83-
}
84-
85-
impl UpgradeAsyncCb {
86-
fn extend_target(self, target: &mut FnTarget) {
87-
let Self { fun, fut } = self;
88-
let wheres = [
89-
parse_quote!(#fun: ::core::ops::FnOnce(crate::database::VersionChangeEvent, crate::database::Database) -> #fut + 'static),
90-
parse_quote!(#fut: ::core::future::Future<Output = crate::Result<()>> + 'static),
91-
];
92-
93-
target
94-
.generics_mut()
95-
.make_where_clause()
96-
.predicates
97-
.extend::<[WherePredicate; 2]>(wheres);
98-
}
99-
}
100-
10172
fn on_err(mut target: TokenStream1, e: Error) -> TokenStream1 {
10273
let e: TokenStream1 = e.into_compile_error().into();
10374
target.extend(e);

src/cursor.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl<'a, Qs> Cursor<'a, Qs> {
6464
/// followed by [`value`](https://developer.mozilla.org/en-US/docs/Web/API/IDBCursorWithValue/value) in JS.
6565
#[errdoc(Cursor(TransactionInactiveError, InvalidStateError))]
6666
#[inline]
67-
pub fn next_record<T>(&mut self) -> CursorNextRequest<T>
67+
pub fn next_record<T>(&mut self) -> CursorNextRequest<'_, T>
6868
where
6969
T: TryFromJs,
7070
{
@@ -73,7 +73,7 @@ impl<'a, Qs> Cursor<'a, Qs> {
7373

7474
/// Mirror of [`Self::next_record`] for `serde`-deserialisable values.
7575
#[cfg(feature = "serde")]
76-
pub fn next_record_ser<T>(&mut self) -> CursorNextRequest<T>
76+
pub fn next_record_ser<T>(&mut self) -> CursorNextRequest<'_, T>
7777
where
7878
T: crate::serde::DeserialiseFromJs,
7979
{
@@ -106,7 +106,7 @@ impl<'a, Qs> Cursor<'a, Qs> {
106106
DataCloneError,
107107
))]
108108
#[inline]
109-
pub fn update<V>(&self, value: V) -> Update<V> {
109+
pub fn update<V>(&self, value: V) -> Update<'_, V> {
110110
Update::new(self, value)
111111
}
112112

src/cursor/key_cursor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl<'a, Qs> KeyCursor<'a, Qs> {
3434
/// followed by [`key`](https://developer.mozilla.org/en-US/docs/Web/API/IDBCursor/key) in JS.
3535
#[inline]
3636
#[errdoc(Cursor(TransactionInactiveError, InvalidStateError))]
37-
pub fn next_key<T>(&mut self) -> CursorNextRequest<T>
37+
pub fn next_key<T>(&mut self) -> CursorNextRequest<'_, T>
3838
where
3939
T: TryFromJs,
4040
{
@@ -44,7 +44,7 @@ impl<'a, Qs> KeyCursor<'a, Qs> {
4444
/// Mirror of [`Self::next_key`] for `serde`-deserialisable keys.
4545
#[inline]
4646
#[cfg(feature = "serde")]
47-
pub fn next_key_ser<T>(&mut self) -> CursorNextRequest<T>
47+
pub fn next_key_ser<T>(&mut self) -> CursorNextRequest<'_, T>
4848
where
4949
T: crate::serde::DeserialiseFromJs,
5050
{

src/cursor/stream.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl<'a, Qs, T> Stream<Cursor<'a, Qs>, T> {
9090
DataErrorUpdate,
9191
DataCloneError
9292
))]
93-
pub fn update<V>(&self, value: V) -> super::Update<V> {
93+
pub fn update<V>(&self, value: V) -> super::Update<'_, V> {
9494
self.cursor.update(value)
9595
}
9696

src/database.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl Database {
5252
/// Create an object store with the given name.
5353
#[generic_bounds(store_name(N))]
5454
#[inline]
55-
pub fn create_object_store<N>(&self, name: N) -> StoreBuilder<N> {
55+
pub fn create_object_store<N>(&self, name: N) -> StoreBuilder<'_, N> {
5656
StoreBuilder::new(self, name)
5757
}
5858

@@ -99,15 +99,15 @@ impl Database {
9999

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

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

src/error/unexpected_data.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ pub enum UnexpectedDataError {
2222
#[error("`Future` polled unexpectedly.")]
2323
PollState,
2424

25+
/// Expected a Transaction to exist, but it was not found.
26+
#[error("Expected the Transaction to exist, but it was not found.")]
27+
TransactionNotFound,
28+
2529
/// Expected a Transaction to be aborted, but it was committed.
2630
#[error("Expected the Transaction to be aborted, but it was committed.")]
2731
TransactionCommitted,

src/factory/req_builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ impl<N, V, B, U, Fa> OpenDbRequestBuilder<N, V, B, U, Fa> {
102102

103103
/// Set the [upgradeneeded](https://developer.mozilla.org/en-US/docs/Web/API/IDBOpenDBRequest/upgradeneeded_event)
104104
/// event handler that returns a `Future`.
105-
#[generic_bounds(upgrade_async_cb(fun(U2), fut(U2Fut)))]
105+
#[generic_bounds(upgrade_async_cb(U2))]
106106
#[cfg(feature = "async-upgrade")]
107-
pub fn with_on_upgrade_needed_fut<U2, U2Fut>(
107+
pub fn with_on_upgrade_needed_fut<U2>(
108108
self,
109109
on_upgrade_needed: U2,
110110
) -> OpenDbRequestBuilder<N, V, B, OpenDbListener, Fa> {

src/future/open_db/listener.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::database::{Database, VersionChangeEvent};
22
use crate::error::{Error, UnexpectedDataError};
3+
use crate::transaction::{OnTransactionDrop, Transaction};
34
use internal_macros::generic_bounds;
45
use std::fmt::{Debug, Display, Formatter};
56
use std::mem;
@@ -56,9 +57,16 @@ impl OpenDbListener {
5657
#[cfg(feature = "async-upgrade")]
5758
async_notify: Self::fake_rx(),
5859
listener: Closure::once(move |evt: web_sys::IdbVersionChangeEvent| {
59-
let res = Database::from_event(&evt)
60-
.and_then(move |db| callback(VersionChangeEvent::new(evt), db));
61-
60+
let res = Database::from_event(&evt).and_then(|db| {
61+
Transaction::from_raw_version_change_event(&db, &evt).and_then(|mut tx| {
62+
callback(VersionChangeEvent::new(evt), &tx).inspect(|()| {
63+
// If the callback succeeded, we want to ensure that
64+
// the transaction is committed when dropped and not
65+
// aborted.
66+
tx.on_drop(OnTransactionDrop::Commit);
67+
})
68+
})
69+
});
6270
Self::handle_result(LBL_UPGRADE, &status, res)
6371
}),
6472
}
@@ -154,8 +162,8 @@ const _: () = {
154162
tokio::sync::mpsc::unbounded_channel().1
155163
}
156164

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

170178
Self::set_status(&status, Status::Pending, LBL_UPGRADE)?;
171-
let fut = callback(VersionChangeEvent::new(evt), db);
172-
173179
wasm_bindgen_futures::spawn_local(async move {
174-
let result = match fut.await {
175-
Ok(()) => Status::Ok,
180+
let db = db;
181+
let result = match Transaction::from_raw_version_change_event(&db, &evt) {
182+
Ok(mut transaction) => {
183+
match callback(VersionChangeEvent::new(evt), &transaction).await {
184+
Ok(()) => {
185+
// If the callback succeeded, we want to ensure that
186+
// the transaction is committed when dropped and not
187+
// aborted.
188+
transaction.on_drop(OnTransactionDrop::Commit);
189+
Status::Ok
190+
}
191+
Err(e) => Status::Err(e),
192+
}
193+
}
176194
Err(e) => Status::Err(e),
177195
};
178196
let _ = Self::set_status(&status, result, LBL_UPGRADE);

0 commit comments

Comments
 (0)