google-cloud-spanner-derive

Procedural macro for google-cloud-spanner.

crates.io

Installation

[dependencies] google-cloud-spanner-derive = <version>

Quick Start

Table derive

#[derive(Table)] generates the implementation for following traits. * TryFromStruct * ToStruct * TryFrom<Row>

```rust use chrono::{DateTime, Utc}; use googlecloudspanner::client::Client; use googlecloudspanner::mutation::insertstruct; use googlecloudspanner::reader::AsyncIterator; use googlecloudspanner::statement::Statement; use googlecloudspannerderive::Table;

[derive(Table, Default)]

pub struct UserCharacter { pub userid: String, pub characterid: i64, // #[spanner(name=...) is used when the column name does not appear in camel case of the field name #[spanner(name="LevelX")] pub level: i64, #[spanner(commitTimestamp)] pub updated_at: DateTime, }

async fn run(client: &Client) -> Result, anyhow::Error> { let user = UserCharacter { userid: "userid".tostring(), ..Default::default() }; client.apply(vec![insertstruct("UserCharacter", user)]).await?;

let mut tx = client.read_only_transaction().await?;
let stmt = Statement::new("SELECT * From UserCharacter Limit 10");
let mut reader = tx.query(stmt).await?;
let mut result = vec![];
while let Some(row) = reader.next().await? {
    result.push(row.try_into()?);
}
Ok(result)

} ```

Here is the generated implementation. ```rust impl ToStruct for UserCharacter { fn tokinds(&self) -> Kinds { vec![ ("UserId", self.userid.tokind()), ("CharacterId", self.characterid.tokind()), ("LevelX", self.level.tokind()), ("UpdatedAt", self.updatedat.tokind()), ] }

fn get_types() -> Types {
    vec![
        ("UserId", String::get_type()),
        ("CharacterId", i64::get_type()),
        ("LevelX", i64::get_type()),
        ("UpdatedAt", CommitTimestamp::get_type()),
    ]
}

}

impl TryFromStruct for UserCharacter { fn tryfromstruct(s: Struct<'>) -> Result { Ok(UserCharacter { userid: s.columnbyname("UserId")?, characterid: s.columnbyname("CharacterId")?, level: s.columnbyname("LevelX")?, updatedat: s.columnbyname("UpdatedAt")?, }) } }

impl TryFrom for UserCharacter { type Error = RowError; fn tryfrom(s: Row) -> Result { Ok(UserCharacter { userid: s.columnbyname("UserId")?, characterid: s.columnbyname("CharacterId")?, level: s.columnbyname("LevelX")?, updatedat: s.columnbyname("UpdatedAt")?, }) } } ```

Query derive

#[derive(Query)] generates the implementation for following traits. * TryFrom<Row>

```rust use chrono::{DateTime, Utc}; use googlecloudspanner::transaction::Transaction; use googlecloudspanner::reader::AsyncIterator; use googlecloudspanner::statement::Statement; use googlecloudspanner_derive::{Table, Query};

[derive(Table, Default)]

pub struct UserCharacter { pub userid: String, pub characterid: i64, }

[derive(Table, Default)]

pub struct UserItem { pub userid: String, pub itemid: i64, }

[derive(Query, Default)]

pub struct UserBundle { pub userid: String, pub usercharacters: Vec, #[spanner(name="Items")] pub user_items: Vec }

async fn run(userid: &str, tx: &mut Transaction) -> Result, anyhow::Error> { let mut stmt = Statement::new(" SELECT UserId, ARRAY(SELECT AS STRUCT * FROM UserCharacter WHERE UserId = @UserId) AS UserCharacters, ARRAY(SELECT AS STRUCT * FROM UserItem WHERE UserId = @UserId) AS Items, From User WHERE UserID = @UserID", ); stmt.addparam("UserID", &userid); let mut reader = tx.query(stmt).await?; match reader.next().await? { Some(row) => Ok(row.tryinto()?), None => Ok(None) } } ```