Skip to content

Commit df099a1

Browse files
committed
Add derives
1 parent b1018d6 commit df099a1

File tree

5 files changed

+106
-20
lines changed

5 files changed

+106
-20
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
Cargo.lock
33
.vscode
44
.DS_Store
5-
examples/target
65
scripts
7-
src/bin
6+
src/bin
7+
sky-derive/target

sky-derive/Cargo.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
name = "sky-derive"
3+
version = "0.2.0"
4+
edition = "2021"
5+
license = "Apache-2.0"
6+
description = "Macros for the Skytable client driver"
7+
homepage = "https://skytable.io"
8+
documentation = "https://docs.rs/skytable"
9+
repository = "https://github.com/skytable/client-rust"
10+
readme = "README.md"
11+
12+
# Cargo.toml for the macro crate
13+
[lib]
14+
proc-macro = true
15+
16+
[dependencies]
17+
syn = { version = "1", features = ["full"] }
18+
quote = "1"
19+
proc-macro2 = "1"

sky-derive/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Skytable client driver macros
2+
3+
This crate is meant to be used with the [Skytable Rust Client Driver](https://github.com/skytable/client-rust) and will not work otherwise (this crate has no standalone functionality).

sky-derive/src/lib.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
extern crate proc_macro;
2+
3+
use proc_macro::TokenStream;
4+
use quote::quote;
5+
use syn::{parse_macro_input, DeriveInput, Data, Fields};
6+
7+
#[proc_macro_derive(Query)]
8+
pub fn derive_query(input: TokenStream) -> TokenStream {
9+
let input = parse_macro_input!(input as DeriveInput);
10+
let name = input.ident;
11+
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
12+
let ret = match input.data {
13+
Data::Struct(data_struct) => {
14+
match data_struct.fields {
15+
Fields::Named(fields) => {
16+
let field_names: Vec<_> = fields.named.iter().map(|f| &f.ident).collect();
17+
assert!(!field_names.is_empty(), "can't derive on empty field");
18+
quote! {
19+
impl #impl_generics ::skytable::query::SQParam for #name #ty_generics #where_clause {
20+
fn append_param(&self, q: &mut Vec<u8>) -> usize {
21+
let mut size = 0;
22+
#(size += ::skytable::query::SQParam::append_param(&self.#field_names, q);)*
23+
size
24+
}
25+
}
26+
}
27+
},
28+
_ => unimplemented!(),
29+
}
30+
},
31+
_ => unimplemented!(),
32+
};
33+
TokenStream::from(ret)
34+
}
35+
36+
#[proc_macro_derive(Response)]
37+
pub fn derive_response(input: TokenStream) -> TokenStream {
38+
let input = parse_macro_input!(input as DeriveInput);
39+
let name = input.ident;
40+
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
41+
let ret = match input.data {
42+
Data::Struct(data_struct) => {
43+
match data_struct.fields {
44+
Fields::Named(fields) => {
45+
let field_names: Vec<_> = fields.named.iter().map(|f| &f.ident).collect();
46+
assert!(!field_names.is_empty(), "can't derive on empty field");
47+
let tuple_pattern = quote! { (#(#field_names),*) };
48+
let struct_instantiation = quote! { Self { #(#field_names),* } };
49+
quote! {
50+
impl #impl_generics skytable::response::FromResponse for #name #ty_generics #where_clause {
51+
fn from_response(resp: skytable::response::Response) -> skytable::ClientResult<Self> {
52+
let #tuple_pattern = skytable::response::FromResponse::from_response(resp)?;
53+
Ok(#struct_instantiation)
54+
}
55+
}
56+
}
57+
},
58+
_ => unimplemented!(),
59+
}
60+
},
61+
_ => unimplemented!(),
62+
};
63+
TokenStream::from(ret)
64+
}

src/lib.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,64 +16,64 @@
1616

1717
//! # Skytable driver
1818
//! [![Crates.io](https://img.shields.io/crates/v/skytable?style=flat-square)](https://crates.io/crates/skytable) [![Test](https://github.com/skytable/client-rust/actions/workflows/test.yml/badge.svg)](https://github.com/skytable/client-rust/actions/workflows/test.yml) [![docs.rs](https://img.shields.io/docsrs/skytable?style=flat-square)](https://docs.rs/skytable) [![GitHub release (latest SemVer including pre-releases)](https://img.shields.io/github/v/release/skytable/client-rust?include_prereleases&style=flat-square)](https://github.com/skytable/client-rust/releases)
19-
//!
19+
//!
2020
//! This is [Skytable](https://github.com/skytable/skytable)'s official client driver for Rust that you can use to build applications.
2121
//! The client-driver is distributed under the liberal [Apache-2.0 License](https://www.apache.org/licenses/LICENSE-2.0) and hence
2222
//! you can use it in your applications without any licensing issues.
23-
//!
23+
//!
2424
//! ## Getting started
25-
//!
25+
//!
2626
//! Make sure you have Skytable set up. If not, follow the [official installation guide here](https://docs.skytable.io/installation)
2727
//! and then come back here.
28-
//!
28+
//!
2929
//! Let's run our first query. Connections are set up using the [`Config`] object and then we establish a connection by calling
3030
//! [`Config::connect`] or use other functions for different connection configurations (for TLS or async).
31-
//!
31+
//!
3232
//! ```no_run
3333
//! use skytable::{Config, query};
3434
//! let mut db = Config::new_default("username", "password").connect().unwrap();
3535
//! // the query `sysctl report status` returns a `Response::Empty` indicating that everything is okay. This is equivalent to
3636
//! // rust's unit type `()` so that's what the driver uses
3737
//! db.query_parse::<()>(&query!("sysctl report status")).unwrap();
3838
//! ```
39-
//!
39+
//!
4040
//! We used the [`query!`] macro above which allows us to conveniently create queries when we don't need to handle complex
4141
//! cases and we have a fixed number of arguments.
42-
//!
42+
//!
4343
//! ## Diving in
44-
//!
44+
//!
4545
//! Now let's say that we have a model `create model myspace.mymodel(username: string, password: string, followers: uint64)`
4646
//! and we want to do some DML operations. Here's how we do it.
47-
//!
47+
//!
4848
//! ```no_run
4949
//! use skytable::{Config, query};
5050
//! let mut db = Config::new_default("username", "password").connect().unwrap();
51-
//!
51+
//!
5252
//! let insert_query = query!("insert into myspace.mymodel(?, ?, ?)", "sayan", "pass123", 1_500_000_u64);
5353
//! db.query_parse::<()>(&insert_query).unwrap(); // insert will return empty on success
54-
//!
54+
//!
5555
//! let select_query = query!("select password, followers FROM myspace.mymodel WHERE username = ?", "sayan");
5656
//! let (pass, followers): (String, u64) = db.query_parse(&select_query).unwrap();
5757
//! assert_eq!(pass, "pass123");
5858
//! assert_eq!(followers, 1_500_000_u64);
59-
//!
59+
//!
6060
//! let update_query = query!("update myspace.mymodel set followers += ? where username = ?", 1u64, "sayan");
6161
//! db.query_parse::<()>(&update_query).unwrap(); // update will return empty on success
6262
//! ```
63-
//!
63+
//!
6464
//! Now you're ready to run your own queries!
65-
//!
65+
//!
6666
//! ## Going advanced
67-
//!
67+
//!
6868
//! - Custom [`mod@query`] generation
6969
//! - Custom [`response`] parsing
7070
//! - [`Connection pooling`](pool)
71-
//!
71+
//!
7272
//! ## Need help? Get help!
73-
//!
73+
//!
7474
//! Jump into [Skytable's official Discord server](https://discord.com/invite/QptWFdx) where maintainers, developers and fellow
7575
//! users help each other out.
76-
//!
76+
//!
7777
7878
// internal modules
7979
#[macro_use]

0 commit comments

Comments
 (0)