nene

nene is a command-line tool to generate Rust code for Google Cloud Spanner.
nene uses database schema to generate code by using Information Schema. nene runs SQL queries against tables in INFORMATION_SCHEMA to fetch metadata for a database, and applies the metadata to Go templates to generate code/models to acccess Cloud Spanner.

crates.io CI

Installation

cargo install nene

Usage

```bash export RUSTLOG=info export SPANNERDSN=projects/local-project/instances/test-instance/databases/local-database

if you don't use emulator use GOOGLEAPPLICATIONCREDENTIALS instead of SPANNEREMULATORHOST

export SPANNEREMULATORHOST=localhost:9010 mkdir ./gen nene -o ./gen -j -d ```

Generated file with default template

Default template generates the files for google-cloud-spanner.

```rust // DON'T EDIT. this code is generated by nene. use googlecloudgoogleapis::spanner::v1::Mutation; use googlecloudspanner::client::{Error}; use googlecloudspanner::key::Key; use googlecloudspanner::mutation::{ delete, insertorupdatestruct, insertstruct, replacestruct, updatestruct, }; use googlecloudspanner::reader::AsyncIterator; use googlecloudspanner::row::{Error as RowError, Row}; use googlecloudspanner::statement::Statement; use googlecloudspanner::transaction::Transaction; use googlecloudspanner::transaction::CallOptions; use googlecloudspanner_derive::Table; use std::convert::TryFrom;

pub const TABLENAME: &str = "User"; pub const COLUMNUSERID: &str = "UserId"; pub const COLUMNNOTNULLINT64: &str = "NotNullINT64"; pub const COLUMNNULLABLEINT64: &str = "NullableINT64"; pub const COLUMNNOTNULLFLOAT64: &str = "NotNullFloat64"; pub const COLUMNNULLABLEFLOAT64: &str = "NullableFloat64"; pub const COLUMNNOTNULLBOOL: &str = "NotNullBool"; pub const COLUMNNULLABLEBOOL: &str = "NullableBool"; pub const COLUMNNOTNULLBYTEARRAY: &str = "NotNullByteArray"; pub const COLUMNNULLABLEBYTEARRAY: &str = "NullableByteArray"; pub const COLUMNNOTNULLNUMERIC: &str = "NotNullNumeric"; pub const COLUMNNULLABLENUMERIC: &str = "NullableNumeric"; pub const COLUMNNOTNULLTIMESTAMP: &str = "NotNullTimestamp"; pub const COLUMNNULLABLETIMESTAMP: &str = "NullableTimestamp"; pub const COLUMNNOTNULLDATE: &str = "NotNullDate"; pub const COLUMNNULLABLEDATE: &str = "NullableDate"; pub const COLUMNNOTNULLARRAY: &str = "NotNullArray"; pub const COLUMNNULLABLEARRAY: &str = "NullableArray"; pub const COLUMNNULLABLESTRING: &str = "NullableString"; pub const COLUMNUPDATED_AT: &str = "UpdatedAt";

[derive(Debug,Clone,Table,serde::Serialize,serde::Deserialize)]

pub struct User { #[spanner(name = "UserId")] pub userid: String, #[spanner(name = "NotNullINT64")] pub notnullint64: i64, #[spanner(name = "NullableINT64")] pub nullableint64: Option, #[spanner(name = "NotNullFloat64")] pub notnullfloat64: f64, #[spanner(name = "NullableFloat64")] pub nullablefloat64: Option, #[spanner(name = "NotNullBool")] pub notnullbool: bool, #[spanner(name = "NullableBool")] pub nullablebool: Option, #[spanner(name = "NotNullByteArray")] pub notnullbytearray: Vec, #[spanner(name = "NullableByteArray")] pub nullablebytearray: Option>, #[spanner(name = "NotNullNumeric")] pub notnullnumeric: googlecloudspanner::value::SpannerNumeric, #[spanner(name = "NullableNumeric")] pub nullablenumeric: Option, #[serde(with = "time::serde::rfc3339")] #[spanner(name = "NotNullTimestamp")] pub notnulltimestamp: time::OffsetDateTime, #[serde(default,with = "time::serde::rfc3339::option")] #[spanner(name = "NullableTimestamp")] pub nullabletimestamp: Option, #[spanner(name = "NotNullDate")] pub notnulldate: time::Date, #[spanner(name = "NullableDate")] pub nullabledate: Option, #[spanner(name = "NotNullArray")] pub notnullarray: Vec, #[spanner(name = "NullableArray")] pub nullablearray: Option>, #[spanner(name = "NullableString")] pub nullablestring: Option, #[serde(with = "time::serde::rfc3339")] #[spanner(name = "UpdatedAt",commitTimestamp)] pub updated_at: time::OffsetDateTime, }

impl Default for User { fn default() -> Self { Self { userid: Default::default(), notnullint64: Default::default(), nullableint64: Default::default(), notnullfloat64: Default::default(), nullablefloat64: Default::default(), notnullbool: Default::default(), nullablebool: Default::default(), notnullbytearray: Default::default(), nullablebytearray: Default::default(), notnullnumeric: Default::default(), nullablenumeric: Default::default(), notnulltimestamp: time::OffsetDateTime::nowutc(), nullabletimestamp: Default::default(), notnulldate: time::OffsetDateTime::nowutc().date(), nullabledate: Default::default(), notnullarray: Default::default(), nullablearray: Default::default(), nullablestring: Default::default(), updatedat: time::OffsetDateTime::nowutc(), } } } impl User { pub fn insert(&self) -> Mutation { insertstruct(TABLENAME, &self) }

pub fn update(&self) -> Mutation { updatestruct(TABLENAME, &self) }

pub fn replace(&self) -> Mutation { replacestruct(TABLENAME, &self) }

pub fn insertorupdate(&self) -> Mutation { insertorupdatestruct(TABLENAME, &self) }

pub fn delete(&self) -> Mutation { delete(TABLENAME, Key::new(&self.userid)) }

pub async fn findbypk( tx: &mut Transaction, userid: &str, options: Option ) -> Result, Error> { let mut stmt = Statement::new("SELECT * From User WHERE UserId = @UserId"); stmt.addparam(COLUMNUSERID, &userid); let mut rows = readbystatement(tx, stmt, options).await?; if !rows.isempty() { Ok(rows.pop()) } else { Ok(None) } } }

async fn readbystatement>( tx: &mut Transaction, stmt: Statement, options: Option, ) -> Result, Error> { let mut reader = tx.query(stmt).await?; if options.issome() { reader.setcalloptions(options.unwrap()); } let mut result = vec![]; while let Some(row) = reader.next().await? { result.push(row.tryinto()?); } Ok(result) }

```