dynamodb_helper/
lib.rs

1#![doc = include_str!("../README.md")]
2
3extern crate core;
4
5mod r#impl;
6
7use crate::r#impl::*;
8use quote::quote;
9use proc_macro::{TokenStream};
10use proc_macro2::Ident;
11use syn::{parse_macro_input, DeriveInput};
12use syn::Data::Struct;
13use syn::DataStruct;
14use syn::Fields::Named;
15use syn::FieldsNamed;
16
17#[proc_macro_derive(DynamoDb, attributes(partition,range,exclusion))]
18pub fn create_dynamodb_helper(item: TokenStream) -> TokenStream {
19    let ast = parse_macro_input!(item as DeriveInput);
20    let name = ast.ident;
21    let helper_name = format!("{name}Db");
22    let helper_ident = Ident::new(&helper_name, name.span());
23
24    let fields = match ast.data {
25        Struct(DataStruct { fields: Named(FieldsNamed { ref named, .. }), .. }) => named,
26        _ => unimplemented!("The DynamoDB procedural macro can only be used for structs"),
27    };
28
29    let exclusion_list = get_macro_attribute(&ast.attrs, EXCLUSION_ATTRIBUTE_NAME);
30    let exclusion_list_refs: Vec<&str> = exclusion_list.iter().map(|x| &**x).collect();
31
32    let (get_error, get_by_partition_error, batch_get_error, scan_error, parse_error) = generate_error_names(&helper_ident);
33    let errors = generate_helper_error(&helper_ident, &exclusion_list_refs);
34
35    let partition_key_ident_and_type = get_ident_and_type_of_field_annotated_with(fields, PARTITION_KEY_ATTRIBUTE_NAME)
36        .expect("You need to define a partition key for your DynamoDB struct! Place the field attribute `#[partition]` above the property that will serve as your key. Note that DynamoDB only supports strings, numbers and booleans as keys.");
37
38    let range_key_ident_and_type = get_ident_and_type_of_field_annotated_with(fields, RANGE_KEY_ATTRIBUTE_NAME);
39
40    let from_struct_for_hashmap = tokenstream_or_empty_if_no_put_methods(
41        from_struct_for_hashmap(&name, fields), &exclusion_list_refs
42    );
43
44    let try_from_hashmap_for_struct = tokenstream_or_empty_if_no_retrieval_methods(
45        try_from_hashmap_to_struct(&name, &parse_error, fields), &exclusion_list_refs,
46    );
47
48    let new = tokenstream_or_empty_if_exclusion(
49        new_method(&helper_ident), NEW_METHOD_NAME, &exclusion_list_refs,
50    );
51
52    let build = tokenstream_or_empty_if_exclusion(
53        build_method(&helper_ident), BUILD_METHOD_NAME, &exclusion_list_refs,
54    );
55
56    let gets = tokenstream_or_empty_if_exclusion(
57        get_methods(&name, &get_error, &get_by_partition_error, partition_key_ident_and_type, range_key_ident_and_type), GET_METHOD_NAME, &exclusion_list_refs
58    );
59
60    let batch_get = tokenstream_or_empty_if_exclusion(
61        batch_get(&name, &batch_get_error, partition_key_ident_and_type, range_key_ident_and_type), BATCH_GET_METHOD_NAME, &exclusion_list_refs
62    );
63
64    let create_table = tokenstream_or_empty_if_exclusion(
65        create_table_method(partition_key_ident_and_type, range_key_ident_and_type), CREATE_TABLE_METHOD_NAME, &exclusion_list_refs
66    );
67    let delete_table = tokenstream_or_empty_if_exclusion(
68        delete_table_method(), DELETE_TABLE_METHOD_NAME, &exclusion_list_refs
69    );
70    let put = tokenstream_or_empty_if_exclusion(
71        put_method(&name), PUT_METHOD_NAME, &exclusion_list_refs,
72    );
73    let batch_put = tokenstream_or_empty_if_exclusion(
74        batch_put_method(&name), BATCH_PUT_METHOD_NAME, &exclusion_list_refs,
75    );
76    let delete = tokenstream_or_empty_if_exclusion(
77        delete_method(&name, partition_key_ident_and_type, range_key_ident_and_type), DELETE_METHOD_NAME, &exclusion_list_refs,
78    );
79    let scan = tokenstream_or_empty_if_exclusion(
80        scan_method(&name, &scan_error), SCAN_METHOD_NAME, &exclusion_list_refs,
81    );
82
83    let public_version = quote! {
84        #from_struct_for_hashmap
85        #try_from_hashmap_for_struct
86
87        pub struct #helper_ident {
88            pub client: aws_sdk_dynamodb::Client,
89            pub table: String,
90        }
91
92        impl #helper_ident {
93            #new
94            #build
95
96            #create_table
97            #delete_table
98
99            #put
100            #gets
101            #batch_get
102            #batch_put
103            #delete
104            #scan
105        }
106
107        #errors
108    };
109
110    public_version.into()
111}