nene 0.3.0

Google Cloud Spanner ORM generator.
Documentation
# 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](https://img.shields.io/crates/v/nene.svg)](https://crates.io/crates/nene)
![CI](https://github.com/yoshidan/nene/workflows/CI/badge.svg?branch=main)

## 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
```

* -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` 

### 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_gax::grpc::Status;
use google_cloud_spanner::client::{RunInTxError, TxError};
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, Struct, TryFromStruct};
use google_cloud_spanner::statement::{Kinds, Statement, ToKind, ToStruct, Types};
use google_cloud_spanner::transaction::Transaction;
use google_cloud_spanner::transaction::CallOptions;
use google_cloud_spanner::value::CommitTimestamp;
use std::convert::TryFrom;
use crate::domain::model::read_by_statement;

pub const TABLE_NAME: &str = "User";
pub const COLUMN_USER_ID: &str = "UserId";
pub const COLUMN_PREMIUM: &str = "Premium";
pub const COLUMN_UPDATED_AT: &str = "UpdatedAt";

#[derive(Debug,Clone,Default,Table,serde::Serialize,serde::Deserialize)]
pub struct User {
  pub user_id: String,
  pub premium: bool,
  pub updated_at: chrono::DateTime<chrono::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::key(&self.user_id))
  }

  pub async fn find_by_pk(
    tx: &mut Transaction, user_id: &String, options: Option<CallOptions>
  ) -> Result<Option<Self>, RunInTxError> {
    let mut stmt = Statement::new("SELECT * From User WHERE UserId = @UserId");
    stmt.add_param(COLUMN_USER_ID, user_id);
    let mut rows = Self::read_by_statement(tx, stmt, options).await?;
    if !rows.is_empty() {
      Ok(rows.pop())
    } else {
      Ok(None)
    }
  }
}
```