1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
//! nitroglycerin - High level dynamodb crate //! //! ```ignore //! use nitroglycerin::{Attributes, Key, Query, Table, DynamoDb, dynamodb::DynamoDbClient}; //! use rusoto_core::Region; //! //! #[derive(Debug, PartialEq, Attributes, Key, Query)] //! struct Employee { //! #[nitro(partition_key)] //! id: String, //! #[nitro(rename = "firstName")] //! name: String, //! joined: i64, //! left: Option<i64>, //! } //! //! impl Table for Employee { //! fn table_name() -> String { //! "Employees".to_string() //! } //! } //! //! #[derive(Debug, PartialEq, Attributes, Query)] //! struct EmployeeNameIndex { //! #[nitro(partition_key, rename = "firstName")] //! name: String, //! #[nitro(sort_key)] //! joined: i64, //! } //! //! impl IndexTable for EmployeeNameIndex { //! type Table = Employees; //! fn index_name() -> Option<String> { //! Some("EmployeeNamesIndex".to_string()) //! } //! } //! //! let client = DynamoDbClient::new(Region::default()); //! //! let employee: Option<Employee> = client.get::<Employee>() //! .id("emp_1") // get the employee with id "emp_1" //! .execute().await?; //! //! let new_employee = Employee { //! id: "emp_1234".into(), //! name: "Conrad".into(), //! joined: 1626900000, //! left: None, //! }; //! // Put the new employee item into the db //! client.put(new_employee).execute().await?; //! //! let employees: Vec<EmployeeNameIndex> = client.query::<EmployeeNameIndex>() //! .name("John".to_string()) // query the db for all employees named "John" //! .execute().await?; //! //! let employees: Vec<EmployeeNameIndex> = client.query::<EmployeeNameIndex>() //! .name("John".to_string()) // query the db for all employees named "John" //! .joined().between(1626649200, 1626735600) // and who joined between 2021-07-19 and 2021-07-20 //! .execute().await?; //! ``` #![warn(clippy::pedantic)] #![warn(clippy::nursery)] #![warn(missing_docs)] mod client; /// module covering conversions to and from dynamodb attribute values pub mod convert; /// collection of functions and types used to make get item requests mod get; /// collection of functions and types used to make key requests pub mod key; /// collection of functions and types used to make put item requests pub mod put; /// collection of functions and types used to make query requests pub mod query; use std::{collections::HashMap, error::Error}; pub use client::DynamoDb; pub use nitroglycerin_derive::{Attributes, Key, Query}; pub use rusoto_dynamodb as dynamodb; use thiserror::Error; /// Trait indicating that a type is a dynamodb table pub trait Table { /// get the table name fn table_name() -> String; } /// Trait indicating that a type is a dynamodb index pub trait TableIndex { /// The dynamodb table this index belongs to type Table: Table; /// get the index name fn index_name() -> Option<String>; } impl<T: Table> TableIndex for T { type Table = Self; fn index_name() -> Option<String> { None } } /// Error returned by dynamodb requests #[derive(Debug, Error)] pub enum DynamoError<E: Error + 'static> { /// Error originated from an attribute value parse error #[error("could not parse dynamo attributes: {0}")] ParseError(#[from] AttributeError), /// Error originated from a dynamodb request error #[error("could not connect to dynamo: {0}")] Rusoto(#[from] rusoto_core::RusotoError<E>), } /// Convenient type for a attribute value map pub type Attributes = HashMap<String, rusoto_dynamodb::AttributeValue>; /// Error returned when parsing attribute values #[derive(Debug, Error)] pub enum AttributeError { /// Error occured because the required field was missing #[error("missing field {0}")] MissingField(String), /// Error occured because the attribute value type was not supported #[error("incorrect type")] IncorrectType, /// Error occured because value could not be parsed #[error("could not parse value: {0}")] ParseError(#[from] Box<dyn Error>), }