pgx_utils/sql_entity_graph/schema/
mod.rs

1/*
2Portions Copyright 2019-2021 ZomboDB, LLC.
3Portions Copyright 2021-2022 Technology Concepts & Design, Inc. <support@tcdi.com>
4
5All rights reserved.
6
7Use of this source code is governed by the MIT license that can be found in the LICENSE file.
8*/
9/*!
10
11`#[pg_schema]` related macro expansion for Rust to SQL translation
12
13> Like all of the [`sql_entity_graph`][crate::sql_entity_graph] APIs, this is considered **internal**
14to the `pgx` framework and very subject to change between versions. While you may use this, please do it with caution.
15
16*/
17pub mod entity;
18
19use proc_macro2::{Span, TokenStream as TokenStream2};
20use quote::{quote, ToTokens, TokenStreamExt};
21use std::hash::{Hash, Hasher};
22use syn::parse::{Parse, ParseStream};
23use syn::ItemMod;
24
25/// A parsed `#[pg_schema] mod example {}` item.
26///
27/// It should be used with [`syn::parse::Parse`] functions.
28///
29/// Using [`quote::ToTokens`] will output the declaration for a `pgx::datum::sql_entity_graph::InventorySchema`.
30///
31/// ```rust
32/// use syn::{Macro, parse::Parse, parse_quote, parse};
33/// use quote::{quote, ToTokens};
34/// use pgx_utils::sql_entity_graph::Schema;
35///
36/// # fn main() -> eyre::Result<()> {
37/// let parsed: Schema = parse_quote! {
38///     #[pg_schema] mod example {}
39/// };
40/// let entity_tokens = parsed.to_token_stream();
41/// # Ok(())
42/// # }
43/// ```
44#[derive(Debug, Clone)]
45pub struct Schema {
46    pub module: ItemMod,
47}
48
49impl Parse for Schema {
50    fn parse(input: ParseStream) -> Result<Self, syn::Error> {
51        let module: ItemMod = input.parse()?;
52        crate::ident_is_acceptable_to_postgres(&module.ident)?;
53        Ok(Self { module })
54    }
55}
56
57impl ToTokens for Schema {
58    fn to_tokens(&self, tokens: &mut TokenStream2) {
59        let attrs = &self.module.attrs;
60        let vis = &self.module.vis;
61        let mod_token = &self.module.mod_token;
62        let ident = &self.module.ident;
63
64        let (_content_brace, content_items) =
65            &self.module.content.as_ref().expect("Can only support `mod {}` right now.");
66
67        // A hack until https://github.com/rust-lang/rust/issues/54725 is fixed.
68        let mut hasher = std::collections::hash_map::DefaultHasher::new();
69        content_items.hash(&mut hasher);
70        let postfix = hasher.finish();
71        // End of hack
72
73        let mut updated_content = content_items.clone();
74        let sql_graph_entity_fn_name = syn::Ident::new(
75            &format!("__pgx_internals_schema_{}_{}", ident, postfix),
76            Span::call_site(),
77        );
78        updated_content.push(syn::parse_quote! {
79                #[no_mangle]
80                #[doc(hidden)]
81                pub extern "Rust" fn  #sql_graph_entity_fn_name() -> ::pgx::utils::sql_entity_graph::SqlGraphEntity {
82                    extern crate alloc;
83                    use alloc::vec::Vec;
84                    use alloc::vec;
85                    let submission = pgx::utils::sql_entity_graph::SchemaEntity {
86                            module_path: module_path!(),
87                            name: stringify!(#ident),
88                            file: file!(),
89                            line: line!(),
90                        };
91                    ::pgx::utils::sql_entity_graph::SqlGraphEntity::Schema(submission)
92                }
93        });
94        let _semi = &self.module.semi;
95
96        let inv = quote! {
97            #(#attrs)*
98            #vis #mod_token #ident {
99                #(#updated_content)*
100            }
101        };
102        tokens.append_all(inv);
103    }
104}