Skip to content

Conversation

@if0ne
Copy link
Contributor

@if0ne if0ne commented Nov 14, 2025

Hi, I’m back again. This is a continuation of this PR: #3712

I’ve returned with a draft of the asynchronous traits. They fully mirror the synchronous API (with a couple of differences in input arguments), adding Future + Send as the return type.

As further development, I can propose:

  • Abstract away from async executors and introduce an AsyncExecutor trait with a single block_on method. In adbc_core, add helper structures like SyncDriverWrapper<E: AsyncExecutor, D: AsyncDriver> and others, and implement the corresponding synchronous traits for them.

  • Add some procedural macro magic to automatically implement the synchronous traits by generating the code described above.

@if0ne if0ne requested a review from wjones127 as a code owner November 14, 2025 08:07
@if0ne if0ne marked this pull request as draft November 14, 2025 08:07
@github-actions github-actions bot added this to the ADBC Libraries 22 milestone Nov 14, 2025
@if0ne
Copy link
Contributor Author

if0ne commented Nov 14, 2025

What do you think? @lidavidm and @eitsupi

@lidavidm
Copy link
Member

CC @felipecrv @mbrobbel too

@if0ne if0ne changed the title feat(rust/adbc_core): add async traits for Driver, Database, Connection, Statement feat(rust/core): add async traits for Driver, Database, Connection, Statement Nov 14, 2025
Copy link
Member

@mbrobbel mbrobbel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the Send bound stuff I would suggest using https://docs.rs/trait-variant/0.1.2/trait_variant/ (as suggested in https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits/#async-fn-in-public-traits).

For async vs sync I would suggest using the async trait as the default and provided sync helper traits and structs. But the truth is; there is no elegant solution available today for this.

@if0ne
Copy link
Contributor Author

if0ne commented Nov 14, 2025

trait_variant will help solve the Send bound problem, but it introduces another problem: the macro does not add additional Send bound to function input arguments if they are of an opaque type. Should we use explicit types instead?

@if0ne if0ne force-pushed the rust/async-trait branch 2 times, most recently from 2888512 to 61963f8 Compare November 14, 2025 14:09
Copy link
Contributor

@felipecrv felipecrv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the code in blocking is moved back to the current location I can give another review.

@lidavidm do we really need everything to be a Future, even get/set options?

@@ -0,0 +1,793 @@
// Licensed to the Apache Software Foundation (ASF) under one
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can skip creating the blocking namespace altogether and keep the symbols where they were. "Blocking" has bad connotations and I don't think a blocking database API is as bad as the name "blocking" suggests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can skip creating the blocking namespace altogether and keep the symbols where they were. "Blocking" has bad connotations and I don't think a blocking database API is as bad as the name "blocking" suggests.

I’m a bit confused. @mbrobbel suggests that the async traits should be used by default. To me, this means they should be at the root of the crate, with the corresponding sync version in a separate module.

I don’t see anything wrong with using the namespace blocking. I relied on existing crates. For example reqwest

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async being the default for database APIs is a bad idea IMO. Database connections are stateful objects that accumulates statements in transactions. Async may re-order actual execution of the queries on the connection. A world of pain.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made the sync traits the default, but I won’t move them back to the crate root. Let them stay in the sync mod.

@if0ne
Copy link
Contributor Author

if0ne commented Nov 14, 2025

Once the code in blocking is moved back to the current location I can give another review.

@lidavidm do we really need everything to be a Future, even get/set options?

I made the AsyncOptionable because in the DataFusion implementation, setting options involved asynchronous operations. It might be possible to make get_option_* sync, but I would keep set_option async.

https://github.com/if0ne/arrow-adbc/blob/61963f8e450926da1657f31112db9498f789b380/rust/driver/datafusion/src/lib.rs#L247

@lidavidm
Copy link
Member

Even get_option may involve I/O in some cases (e.g. if the driver has to run a query to fetch some information), unfortunately

@if0ne if0ne marked this pull request as ready for review November 26, 2025 10:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants