# Surreal derive
# Description
Simple library for writing [**SurrealQL** ](https://surrealdb.com/docs/surrealql), this is just a verythin layer on top of [SurrealDb Rust SDK](https://surrealdb.com/docs/integration/sdks/rust).
### An interesting solution for working with RecordId and Relate statement
Take a look on my other crate call [surrealdb-id ](https://crates.io/crates/surrealdb_id).
# Installation
### 1. Install surreal-devl: https://crates.io/crates/surreal_devl
Contains the core logic of the whole library, the main purpose is to act as a bridge between SurrealDb SDK and the your defined Struct, also support working with **Array**, **ID** or **DateTime**
```console
cargo add sureal_devl
```
### 2. Install surreal-derive:
```console
cargo add surreal_derive_plus
```
### Note:
Current restriction that will be resolved in future: If your variable names coincide with any of the following supported statements: ["id", "val", "date", "duration", "record", "set", "content", "multi", "array"], kindly consider renaming them.
# Usage
### Mark your struct as surreal_derive.
This will will automatically generate code that could convert your struct into [surrealdb idioms](https://docs.rs/surrealdb/1.0.0/surrealdb/sql/struct.Idiom.html)
```rust
use serde::{Deserialize, Serialize};
use surreal_derive_plus::SurrealDerive;
#[derive(Debug, Serialize, Deserialize, SurrealDerive, Clone)]
pub struct User {
pub name: String,
pub password: String,
}
```
### Implement the Into/ trait
```rust
use surrealdb::opt::RecordId;
use crate::entities::user::User;
impl Into for User {
fn into(self) -> RecordId {
return RecordId::from(("user", self.name.as_str()));
}
}
```
### Write query by using surreal_derive_plus::surreal_quote! macro
#### Struct
```rust
use surreal_derive_plus::surreal_quote;
.... connect to your surreal db ...
let new_user = User {
name: "surreal".to_string(),
password: "000000".to_string(),
};
let created_user: Option = DB.query(surreal_quote!("CREATE #record(&new_user)")).await.unwrap().take(0).unwrap(); => CREATE user:surreal SET name='surreal', password='000000'
```
#### Variable
```rust
let age = 2;
let query_statement = surreal_derive_plus::surreal_quote!("CREATE user SET age = #age");
assert_eq!(query_statement, "CREATE user SET age = 2");
```
#### Array
```rust
let arr = vec![1,2,3,1];
let query_statement = surreal_derive_plus::surreal_quote!("CREATE user SET arr = #array(&arr)");
assert_eq!(query_statement, "CREATE user SET arr = [1, 2, 3, 1]");
```
#### Struct Array
```rust
let friends = vec![
User {
name: "Ethan".to_string(),
full_name: "Ethan Sullivan".to_string(),
password: "123123".to_string(),
},
User {
name: "Olivia".to_string(),
full_name: "Olivia Anderson".to_string(),
password: "123123".to_string(),
}
];
let query_statement = surreal_derive_plus::surreal_quote!("CREATE user SET friends = #array(&friends)");
assert_eq!(query_statement, "CREATE user SET friends = [user:Ethan, user:Olivia]");
```
#### DateTime
```rust
let birthday: DateTime = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap();
let query_statement = surreal_derive_plus::surreal_quote!("CREATE user SET birthday = #date(&birthday)");
assert_eq!(query_statement, "CREATE user SET birthday = '2020-01-01T00:00:00Z'");
```
#### Duration
```rust
let party_duration = Duration::from_millis(2 * 60 * 60 * 1000);
let party_started_at: DateTime = Utc.with_ymd_and_hms(2023, 1, 1, 14, 0, 0).unwrap();
let query_statement = surreal_derive_plus::surreal_quote!("CREATE party SET duration = #duration(&party_duration), #date(&party_started_at)");
assert_eq!(query_statement, "CREATE party SET duration = 2h, '2023-01-01T14:00:00Z'");
```
#### Surreal ID
```rust
let user = User {
name: "clay".to_string(),
full_name: "clay".to_string(),
password: "123123".to_string(),
};
let query_statement = surreal_derive_plus::surreal_quote!("UPDATE #id(&user) SET age = 10");
assert_eq!(query_statement, "UPDATE user:clay SET age = 10");
```
#### Surreal Value
This will wrap the variable inside surrealdb::sql::Value::from()
```rust
let str = String::from("string");
let statement = surreal_derive_plus::surreal_quote!("CREATE user SET full_name = #val(&str)");
assert_eq!(statement, "CREATE user SET full_name = 'string'");
```
#### Relation
Using with surrealdb-id crate we can simplify the process of working with relate statement, then you can generate entire relate statement
link here: https://crates.io/crates/surrealdb_id
Example:
```rust
let user: RecordId = RecordId::from(("user", "Devlog"));
let blogPost: RecordId = RecordId::from(("blogPost", "How to use surrealdb"));
let discussion = Discussion { content: "Hello I really want to know more".to_string(), created_at: Default::default() };
let relation = discussion.relate(user, blogPost)
assert_eq!(
surreal_quote!("#relate(&relation)"),
"RELATE user:Devlog -> discuss -> blogPost:⟨How to use surrealdb⟩ SET content = 'Hello I really want to know more', created_at = '1970-01-01T00:00:00Z'"
);
```
#### Surreal Resource
```rust
let new_user = User {
name: "surreal".to_string(),
password: "000000".to_string(),
};
db.create(Resource::RecordId(new_user.id())).content(&user);
```
# Customize setting
You can customize the setting inside cargo.toml
it is neccessary for call cargo clean to apply all of these configuration
```cargo.toml
[package.metadata]
# Will log the query command at runtime
surreal_enable_log = false
# Will log the generated code at build time
surreal_enable_compile_log = false
# Change the naming convention of generated statement into camel case
surreal_use_camel_case = false
# The log namespace, apply for both build time log and runtime log
surreal_namespace = "surrealql-derive"
# The macro name that use for info log, for example
surreal_info_log_macro = "println"
# The macro name that use for warning log, for example
surreal_warn_log_macro = "println"
```