{"id":16714713,"url":"https://github.com/yoshidan/nene","last_synced_at":"2025-03-21T20:33:47.450Z","repository":{"id":57644148,"uuid":"434777014","full_name":"yoshidan/nene","owner":"yoshidan","description":"command-line tool to generate Rust code for Google Cloud Spanner","archived":false,"fork":false,"pushed_at":"2024-05-02T04:31:22.000Z","size":62,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-18T05:07:57.562Z","etag":null,"topics":["gcp","rust","spanner"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yoshidan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-04T01:16:39.000Z","updated_at":"2024-07-04T15:38:07.000Z","dependencies_parsed_at":"2024-05-02T04:01:11.305Z","dependency_job_id":"f61271f8-2508-4845-b331-4e683910391e","html_url":"https://github.com/yoshidan/nene","commit_stats":{"total_commits":38,"total_committers":1,"mean_commits":38.0,"dds":0.0,"last_synced_commit":"af4ed235f647c6b31bcb08831c4862bb7354f25e"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoshidan%2Fnene","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoshidan%2Fnene/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoshidan%2Fnene/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoshidan%2Fnene/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yoshidan","download_url":"https://codeload.github.com/yoshidan/nene/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244866439,"owners_count":20523517,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gcp","rust","spanner"],"created_at":"2024-10-12T21:06:41.416Z","updated_at":"2025-03-21T20:33:47.183Z","avatar_url":"https://github.com/yoshidan.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nene\n`nene` is a command-line tool to generate Rust code for Google Cloud Spanner.  \n`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.\n\n[![crates.io](https://img.shields.io/crates/v/nene.svg)](https://crates.io/crates/nene)\n![CI](https://github.com/yoshidan/nene/workflows/CI/badge.svg?branch=main)\n\n## Installation\n\n```\ncargo install nene\n```\n\n## Usage\n```bash\nexport RUST_LOG=info\nexport SPANNER_DSN=projects/local-project/instances/test-instance/databases/local-database\n# if you don't use emulator use GOOGLE_APPLICATION_CREDENTIALS instead of SPANNER_EMULATOR_HOST\nexport SPANNER_EMULATOR_HOST=localhost:9010 \nmkdir ./gen\nnene -o ./gen -j -d\n```\n\n* -i\n  - template directory.\n  - see template directory [structure](./src/default)\n  - if not specified default template are used.\n\n* -o\n  - output directory\n  - default directory is `./gen`\n\n* -j\n  - add `serde::Serialize` and `serde::Deserialize` \n\n* -d\n  - implements `Default` trait\n\n### Generated file with default template\n\nDefault template generates the files for [google-cloud-spanner](https://github.com/yoshidan/google-cloud-rust/tree/main/spanner).\n\n```rust\n// DON'T EDIT. this code is generated by nene.\nuse google_cloud_googleapis::spanner::v1::Mutation;\nuse google_cloud_spanner::client::{Error};\nuse google_cloud_spanner::key::Key;\nuse google_cloud_spanner::mutation::{\n  delete, insert_or_update_struct, insert_struct, replace_struct, update_struct,\n};\nuse google_cloud_spanner::reader::AsyncIterator;\nuse google_cloud_spanner::row::{Error as RowError, Row};\nuse google_cloud_spanner::statement::Statement;\nuse google_cloud_spanner::transaction::Transaction;\nuse google_cloud_spanner::transaction::CallOptions;\nuse google_cloud_spanner_derive::Table;\nuse std::convert::TryFrom;\n\npub const TABLE_NAME: \u0026str = \"User\";\npub const COLUMN_USER_ID: \u0026str = \"UserId\";\npub const COLUMN_NOT_NULL_INT_64: \u0026str = \"NotNullINT64\";\npub const COLUMN_NULLABLE_INT_64: \u0026str = \"NullableINT64\";\npub const COLUMN_NOT_NULL_FLOAT_64: \u0026str = \"NotNullFloat64\";\npub const COLUMN_NULLABLE_FLOAT_64: \u0026str = \"NullableFloat64\";\npub const COLUMN_NOT_NULL_BOOL: \u0026str = \"NotNullBool\";\npub const COLUMN_NULLABLE_BOOL: \u0026str = \"NullableBool\";\npub const COLUMN_NOT_NULL_BYTE_ARRAY: \u0026str = \"NotNullByteArray\";\npub const COLUMN_NULLABLE_BYTE_ARRAY: \u0026str = \"NullableByteArray\";\npub const COLUMN_NOT_NULL_NUMERIC: \u0026str = \"NotNullNumeric\";\npub const COLUMN_NULLABLE_NUMERIC: \u0026str = \"NullableNumeric\";\npub const COLUMN_NOT_NULL_TIMESTAMP: \u0026str = \"NotNullTimestamp\";\npub const COLUMN_NULLABLE_TIMESTAMP: \u0026str = \"NullableTimestamp\";\npub const COLUMN_NOT_NULL_DATE: \u0026str = \"NotNullDate\";\npub const COLUMN_NULLABLE_DATE: \u0026str = \"NullableDate\";\npub const COLUMN_NOT_NULL_ARRAY: \u0026str = \"NotNullArray\";\npub const COLUMN_NULLABLE_ARRAY: \u0026str = \"NullableArray\";\npub const COLUMN_NULLABLE_STRING: \u0026str = \"NullableString\";\npub const COLUMN_UPDATED_AT: \u0026str = \"UpdatedAt\";\n\n#[derive(Debug,Clone,Table,serde::Serialize,serde::Deserialize)]\npub struct User {\n  #[spanner(name = \"UserId\")]\n  pub user_id: String,\n  #[spanner(name = \"NotNullINT64\")]\n  pub not_null_int_64: i64,\n  #[spanner(name = \"NullableINT64\")]\n  pub nullable_int_64: Option\u003ci64\u003e,\n  #[spanner(name = \"NotNullFloat64\")]\n  pub not_null_float_64: f64,\n  #[spanner(name = \"NullableFloat64\")]\n  pub nullable_float_64: Option\u003cf64\u003e,\n  #[spanner(name = \"NotNullBool\")]\n  pub not_null_bool: bool,\n  #[spanner(name = \"NullableBool\")]\n  pub nullable_bool: Option\u003cbool\u003e,\n  #[spanner(name = \"NotNullByteArray\")]\n  pub not_null_byte_array: Vec\u003cu8\u003e,\n  #[spanner(name = \"NullableByteArray\")]\n  pub nullable_byte_array: Option\u003cVec\u003cu8\u003e\u003e,\n  #[spanner(name = \"NotNullNumeric\")]\n  pub not_null_numeric: google_cloud_spanner::bigdecimal::BigDecimal,\n  #[spanner(name = \"NullableNumeric\")]\n  pub nullable_numeric: Option\u003cgoogle_cloud_spanner::bigdecimal::BigDecimal\u003e,\n  #[serde(with = \"time::serde::rfc3339\")]\n  #[spanner(name = \"NotNullTimestamp\")]\n  pub not_null_timestamp: time::OffsetDateTime,\n  #[serde(default,with = \"time::serde::rfc3339::option\")]\n  #[spanner(name = \"NullableTimestamp\")]\n  pub nullable_timestamp: Option\u003ctime::OffsetDateTime\u003e,\n  #[spanner(name = \"NotNullDate\")]\n  pub not_null_date: time::Date,\n  #[spanner(name = \"NullableDate\")]\n  pub nullable_date: Option\u003ctime::Date\u003e,\n  #[spanner(name = \"NotNullArray\")]\n  pub not_null_array: Vec\u003ci64\u003e,\n  #[spanner(name = \"NullableArray\")]\n  pub nullable_array: Option\u003cVec\u003ci64\u003e\u003e,\n  #[spanner(name = \"NullableString\")]\n  pub nullable_string: Option\u003cString\u003e,\n  #[serde(with = \"time::serde::rfc3339\")]\n  #[spanner(name = \"UpdatedAt\",commitTimestamp)]\n  pub updated_at: time::OffsetDateTime,\n}\n\nimpl Default for User {\n  fn default() -\u003e Self {\n    Self {\n      user_id: Default::default(),\n      not_null_int_64: Default::default(),\n      nullable_int_64: Default::default(),\n      not_null_float_64: Default::default(),\n      nullable_float_64: Default::default(),\n      not_null_bool: Default::default(),\n      nullable_bool: Default::default(),\n      not_null_byte_array: Default::default(),\n      nullable_byte_array: Default::default(),\n      not_null_numeric: Default::default(),\n      nullable_numeric: Default::default(),\n      not_null_timestamp: time::OffsetDateTime::now_utc(),\n      nullable_timestamp: Default::default(),\n      not_null_date: time::OffsetDateTime::now_utc().date(),\n      nullable_date: Default::default(),\n      not_null_array: Default::default(),\n      nullable_array: Default::default(),\n      nullable_string: Default::default(),\n      updated_at: time::OffsetDateTime::now_utc(),\n    }\n  }\n}\nimpl User {\n  pub fn insert(\u0026self) -\u003e Mutation {\n    insert_struct(TABLE_NAME, \u0026self)\n  }\n\n  pub fn update(\u0026self) -\u003e Mutation {\n    update_struct(TABLE_NAME, \u0026self)\n  }\n\n  pub fn replace(\u0026self) -\u003e Mutation {\n    replace_struct(TABLE_NAME, \u0026self)\n  }\n\n  pub fn insert_or_update(\u0026self) -\u003e Mutation {\n    insert_or_update_struct(TABLE_NAME, \u0026self)\n  }\n\n  pub fn delete(\u0026self) -\u003e Mutation {\n    delete(TABLE_NAME, Key::new(\u0026self.user_id))\n  }\n\n  pub async fn find_by_pk(\n    tx: \u0026mut Transaction, user_id: \u0026str, options: Option\u003cCallOptions\u003e\n  ) -\u003e Result\u003cOption\u003cSelf\u003e, Error\u003e {\n    let mut stmt = Statement::new(\"SELECT * From User WHERE UserId = @UserId\");\n    stmt.add_param(COLUMN_USER_ID, \u0026user_id);\n    let mut rows = read_by_statement(tx, stmt, options).await?;\n    if !rows.is_empty() {\n      Ok(rows.pop())\n    } else {\n      Ok(None)\n    }\n  }\n}\n\nasync fn read_by_statement\u003cT: TryFrom\u003cRow, Error = RowError\u003e\u003e(\n  tx: \u0026mut Transaction,\n  stmt: Statement,\n  options: Option\u003cCallOptions\u003e,\n) -\u003e Result\u003cVec\u003cT\u003e, Error\u003e {\n  let mut reader = tx.query(stmt).await?;\n  if options.is_some() {\n    reader.set_call_options(options.unwrap());\n  }\n  let mut result = vec![];\n  while let Some(row) = reader.next().await? {\n    result.push(row.try_into()?);\n  }\n  Ok(result)\n}\n\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoshidan%2Fnene","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyoshidan%2Fnene","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoshidan%2Fnene/lists"}