https://github.com/yoshidan/nene
command-line tool to generate Rust code for Google Cloud Spanner
https://github.com/yoshidan/nene
gcp rust spanner
Last synced: 10 months ago
JSON representation
command-line tool to generate Rust code for Google Cloud Spanner
- Host: GitHub
- URL: https://github.com/yoshidan/nene
- Owner: yoshidan
- License: mit
- Created: 2021-12-04T01:16:39.000Z (about 4 years ago)
- Default Branch: main
- Last Pushed: 2024-05-02T04:31:22.000Z (over 1 year ago)
- Last Synced: 2025-03-18T05:07:57.562Z (10 months ago)
- Topics: gcp, rust, spanner
- Language: Rust
- Homepage:
- Size: 60.5 KB
- Stars: 6
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# 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.
[](https://crates.io/crates/nene)

## Installation
```
cargo install nene
```
## Usage
```bash
export RUST_LOG=info
export SPANNER_DSN=projects/local-project/instances/test-instance/databases/local-database
# if you don't use emulator use GOOGLE_APPLICATION_CREDENTIALS instead of SPANNER_EMULATOR_HOST
export SPANNER_EMULATOR_HOST=localhost:9010
mkdir ./gen
nene -o ./gen -j -d
```
* -i
- template directory.
- see template directory [structure](./src/default)
- if not specified default template are used.
* -o
- output directory
- default directory is `./gen`
* -j
- add `serde::Serialize` and `serde::Deserialize`
* -d
- implements `Default` trait
### Generated file with default template
Default template generates the files for [google-cloud-spanner](https://github.com/yoshidan/google-cloud-rust/tree/main/spanner).
```rust
// DON'T EDIT. this code is generated by nene.
use google_cloud_googleapis::spanner::v1::Mutation;
use google_cloud_spanner::client::{Error};
use google_cloud_spanner::key::Key;
use google_cloud_spanner::mutation::{
delete, insert_or_update_struct, insert_struct, replace_struct, update_struct,
};
use google_cloud_spanner::reader::AsyncIterator;
use google_cloud_spanner::row::{Error as RowError, Row};
use google_cloud_spanner::statement::Statement;
use google_cloud_spanner::transaction::Transaction;
use google_cloud_spanner::transaction::CallOptions;
use google_cloud_spanner_derive::Table;
use std::convert::TryFrom;
pub const TABLE_NAME: &str = "User";
pub const COLUMN_USER_ID: &str = "UserId";
pub const COLUMN_NOT_NULL_INT_64: &str = "NotNullINT64";
pub const COLUMN_NULLABLE_INT_64: &str = "NullableINT64";
pub const COLUMN_NOT_NULL_FLOAT_64: &str = "NotNullFloat64";
pub const COLUMN_NULLABLE_FLOAT_64: &str = "NullableFloat64";
pub const COLUMN_NOT_NULL_BOOL: &str = "NotNullBool";
pub const COLUMN_NULLABLE_BOOL: &str = "NullableBool";
pub const COLUMN_NOT_NULL_BYTE_ARRAY: &str = "NotNullByteArray";
pub const COLUMN_NULLABLE_BYTE_ARRAY: &str = "NullableByteArray";
pub const COLUMN_NOT_NULL_NUMERIC: &str = "NotNullNumeric";
pub const COLUMN_NULLABLE_NUMERIC: &str = "NullableNumeric";
pub const COLUMN_NOT_NULL_TIMESTAMP: &str = "NotNullTimestamp";
pub const COLUMN_NULLABLE_TIMESTAMP: &str = "NullableTimestamp";
pub const COLUMN_NOT_NULL_DATE: &str = "NotNullDate";
pub const COLUMN_NULLABLE_DATE: &str = "NullableDate";
pub const COLUMN_NOT_NULL_ARRAY: &str = "NotNullArray";
pub const COLUMN_NULLABLE_ARRAY: &str = "NullableArray";
pub const COLUMN_NULLABLE_STRING: &str = "NullableString";
pub const COLUMN_UPDATED_AT: &str = "UpdatedAt";
#[derive(Debug,Clone,Table,serde::Serialize,serde::Deserialize)]
pub struct User {
#[spanner(name = "UserId")]
pub user_id: String,
#[spanner(name = "NotNullINT64")]
pub not_null_int_64: i64,
#[spanner(name = "NullableINT64")]
pub nullable_int_64: Option,
#[spanner(name = "NotNullFloat64")]
pub not_null_float_64: f64,
#[spanner(name = "NullableFloat64")]
pub nullable_float_64: Option,
#[spanner(name = "NotNullBool")]
pub not_null_bool: bool,
#[spanner(name = "NullableBool")]
pub nullable_bool: Option,
#[spanner(name = "NotNullByteArray")]
pub not_null_byte_array: Vec,
#[spanner(name = "NullableByteArray")]
pub nullable_byte_array: Option>,
#[spanner(name = "NotNullNumeric")]
pub not_null_numeric: google_cloud_spanner::bigdecimal::BigDecimal,
#[spanner(name = "NullableNumeric")]
pub nullable_numeric: Option,
#[serde(with = "time::serde::rfc3339")]
#[spanner(name = "NotNullTimestamp")]
pub not_null_timestamp: time::OffsetDateTime,
#[serde(default,with = "time::serde::rfc3339::option")]
#[spanner(name = "NullableTimestamp")]
pub nullable_timestamp: Option,
#[spanner(name = "NotNullDate")]
pub not_null_date: time::Date,
#[spanner(name = "NullableDate")]
pub nullable_date: Option,
#[spanner(name = "NotNullArray")]
pub not_null_array: Vec,
#[spanner(name = "NullableArray")]
pub nullable_array: Option>,
#[spanner(name = "NullableString")]
pub nullable_string: Option,
#[serde(with = "time::serde::rfc3339")]
#[spanner(name = "UpdatedAt",commitTimestamp)]
pub updated_at: time::OffsetDateTime,
}
impl Default for User {
fn default() -> Self {
Self {
user_id: Default::default(),
not_null_int_64: Default::default(),
nullable_int_64: Default::default(),
not_null_float_64: Default::default(),
nullable_float_64: Default::default(),
not_null_bool: Default::default(),
nullable_bool: Default::default(),
not_null_byte_array: Default::default(),
nullable_byte_array: Default::default(),
not_null_numeric: Default::default(),
nullable_numeric: Default::default(),
not_null_timestamp: time::OffsetDateTime::now_utc(),
nullable_timestamp: Default::default(),
not_null_date: time::OffsetDateTime::now_utc().date(),
nullable_date: Default::default(),
not_null_array: Default::default(),
nullable_array: Default::default(),
nullable_string: Default::default(),
updated_at: time::OffsetDateTime::now_utc(),
}
}
}
impl User {
pub fn insert(&self) -> Mutation {
insert_struct(TABLE_NAME, &self)
}
pub fn update(&self) -> Mutation {
update_struct(TABLE_NAME, &self)
}
pub fn replace(&self) -> Mutation {
replace_struct(TABLE_NAME, &self)
}
pub fn insert_or_update(&self) -> Mutation {
insert_or_update_struct(TABLE_NAME, &self)
}
pub fn delete(&self) -> Mutation {
delete(TABLE_NAME, Key::new(&self.user_id))
}
pub async fn find_by_pk(
tx: &mut Transaction, user_id: &str, options: Option
) -> Result, Error> {
let mut stmt = Statement::new("SELECT * From User WHERE UserId = @UserId");
stmt.add_param(COLUMN_USER_ID, &user_id);
let mut rows = read_by_statement(tx, stmt, options).await?;
if !rows.is_empty() {
Ok(rows.pop())
} else {
Ok(None)
}
}
}
async fn read_by_statement>(
tx: &mut Transaction,
stmt: Statement,
options: Option,
) -> Result, Error> {
let mut reader = tx.query(stmt).await?;
if options.is_some() {
reader.set_call_options(options.unwrap());
}
let mut result = vec![];
while let Some(row) = reader.next().await? {
result.push(row.try_into()?);
}
Ok(result)
}
```