ormx icon indicating copy to clipboard operation
ormx copied to clipboard

Postgres: get_by_any getters

Open bram209 opened this issue 4 years ago • 10 comments

Description

This PR adds get_by_any getters. These getters will return all records that match any of the provided values/ids.

Usage

My current use case is a graphql api that utilizes data loaders to avoid N+1 queries:

#[derive(Debug, Clone, SimpleObject, ormx::Table)]
#[ormx(table = "addresses", id = id, insertable)]
pub struct Address {
    #[ormx(get_optional = get_by_id(&Uuid), get_by_any)]
    pub id: Uuid,
    pub address_line1: Option<String>,
    pub address_line2: Option<String>,
    pub city: Option<String>,
    pub province_code: Option<String>,
    pub country_code: Option<String>,
    pub postal_code: Option<String>
}
#[async_trait]
impl<'a> Loader<Uuid> for AddressDataLoader {
    type Value = Address;

    type Error = Arc<sqlx::Error>;

    async fn load(
        &self,
        keys: &[Uuid],
    ) -> Result<std::collections::HashMap<Uuid, Self::Value>, Self::Error> {
        let mut conn = self.0.acquire().await?;
        let addresses = Address::get_by_any_id(&mut conn, keys).await?; // <- generated getter
        Ok(addresses.into_iter().map(|a| (a.id, a)).collect())
    }
}

Implementation

It generates the following SQL, to be type checked by sqlx: SELECT {} FROM {} WHERE {} = ANY($1). It is only available for postgres since mysql does not support arrays.

bram209 avatar Jul 26 '21 16:07 bram209

closes #7

bram209 avatar Jul 27 '21 13:07 bram209

great work! could you add a small example and note it in the documentation?

NyxCode avatar Jul 29 '21 17:07 NyxCode

yes no problem, will add an example + documentation this weekend : )

bram209 avatar Jul 30 '21 11:07 bram209

On another (related) note, I was thinking... ormx offloads the heavy lifting to sqlx, so the different backends of ormx in essence just have to come up with the correct SQL statements at compile time.

Would it make sense to refactor the backend trait towards something like:

pub trait Backend: Sized + Clone {
    // ...

    fn insert_statement(table: &Table<Self>) -> String {
        common::insert_statement(table)
    }

    fn get_statement(table: &Table<Self>) -> String {
        common::get_statement(table)
    }

    // ...

    fn get_any_statement(table: &Table<Self>) -> String
}
impl Backend for MySqlBackend {
    
    // ...

    fn get_any_statement(table: &Table<Self>) -> String {
        compile_error!("'get_many' getters are not supported with the MySql driver")
    }
}

This way we would not end up with feature flags throughout the code base

tldr: sqlx's fetch_one, fetch_many, fetch_optional, execute work on all drivers, the only thing that distinguishes them at the API surface is the database-specific SQL statements. Are there any differences in the actual code generation between different ormx drivers except the SQL itself?

bram209 avatar Jul 30 '21 11:07 bram209

@NyxCode added small example and note in docs

bram209 avatar Aug 02 '21 12:08 bram209

Anything happening with this PR?

Milo123459 avatar Sep 07 '21 18:09 Milo123459

Anything happening with this PR?

Just waiting for @bram209 to rename it to get_to_any 🙂

NyxCode avatar Sep 21 '21 23:09 NyxCode

@bram209 are you still working on this? If not, I'd happily rename the attribute myself and merge it.

NyxCode avatar Oct 04 '21 10:10 NyxCode

@bram209 are you still working on this? If not, I'd happily rename the attribute myself and merge it.

Sorry, this one slipped through : /

You can do it if you want, I am a bit busy rest of the week

bram209 avatar Oct 04 '21 12:10 bram209

Sry have been extremely busy lately :/ @NyxCode did the renaming, should be good to go now

bram209 avatar Nov 12 '21 10:11 bram209

cleaning up my PR list

bram209 avatar Oct 12 '23 09:10 bram209