1use pgrx_sql_entity_graph::{PostgresHash, PostgresOrd};
11
12use crate::{parse_postgres_type_args, PostgresTypeAttribute};
13use proc_macro2::Ident;
14use quote::{quote, ToTokens};
15use syn::DeriveInput;
16
17#[track_caller]
18fn ident_and_path(ast: &DeriveInput) -> (&Ident, proc_macro2::TokenStream) {
19 let ident = &ast.ident;
20 let args = parse_postgres_type_args(&ast.attrs);
21 let path = if args.contains(&PostgresTypeAttribute::PgVarlenaInOutFuncs) {
22 quote! { ::pgrx::datum::PgVarlena<#ident> }
23 } else {
24 quote! { #ident }
25 };
26 (ident, path)
27}
28
29#[track_caller]
30pub(crate) fn deriving_postgres_eq(ast: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
31 let mut stream = proc_macro2::TokenStream::new();
32 let (ident, path) = ident_and_path(&ast);
33 stream.extend(derive_pg_eq(ident, &path));
34 stream.extend(derive_pg_ne(ident, &path));
35
36 Ok(stream)
37}
38
39#[track_caller]
40pub(crate) fn deriving_postgres_ord(ast: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
41 let mut stream = proc_macro2::TokenStream::new();
42 let (ident, path) = ident_and_path(&ast);
43
44 stream.extend(derive_pg_lt(ident, &path));
45 stream.extend(derive_pg_gt(ident, &path));
46 stream.extend(derive_pg_le(ident, &path));
47 stream.extend(derive_pg_ge(ident, &path));
48 stream.extend(derive_pg_cmp(ident, &path));
49
50 let sql_graph_entity_item = PostgresOrd::from_derive_input(ast)?;
51 sql_graph_entity_item.to_tokens(&mut stream);
52
53 Ok(stream)
54}
55
56pub(crate) fn deriving_postgres_hash(ast: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
57 let mut stream = proc_macro2::TokenStream::new();
58 let (ident, path) = ident_and_path(&ast);
59
60 stream.extend(derive_pg_hash(ident, &path));
61
62 let sql_graph_entity_item = PostgresHash::from_derive_input(ast)?;
63 sql_graph_entity_item.to_tokens(&mut stream);
64
65 Ok(stream)
66}
67
68#[track_caller]
97pub fn derive_pg_eq(name: &Ident, path: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
98 let pg_name = Ident::new(&format!("{name}_eq").to_lowercase(), name.span());
99 quote! {
100 #[allow(non_snake_case)]
101 #[::pgrx::pgrx_macros::pg_operator(immutable, parallel_safe)]
102 #[::pgrx::pgrx_macros::opname(=)]
103 #[::pgrx::pgrx_macros::commutator(=)]
104 #[::pgrx::pgrx_macros::negator(<>)]
105 #[::pgrx::pgrx_macros::restrict(eqsel)]
106 #[::pgrx::pgrx_macros::join(eqjoinsel)]
107 #[::pgrx::pgrx_macros::merges]
108 #[::pgrx::pgrx_macros::hashes]
109 fn #pg_name(left: #path, right: #path) -> bool
110 where
111 #path: ::core::cmp::Eq,
112 {
113 left == right
114 }
115 }
116}
117
118#[track_caller]
127pub fn derive_pg_ne(name: &Ident, path: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
128 let pg_name = Ident::new(&format!("{name}_ne").to_lowercase(), name.span());
129 quote! {
130 #[allow(non_snake_case)]
131 #[::pgrx::pgrx_macros::pg_operator(immutable, parallel_safe)]
132 #[::pgrx::pgrx_macros::opname(<>)]
133 #[::pgrx::pgrx_macros::commutator(<>)]
134 #[::pgrx::pgrx_macros::negator(=)]
135 #[::pgrx::pgrx_macros::restrict(neqsel)]
136 #[::pgrx::pgrx_macros::join(neqjoinsel)]
137 fn #pg_name(left: #path, right: #path) -> bool {
138 left != right
139 }
140 }
141}
142
143#[track_caller]
144pub fn derive_pg_lt(name: &Ident, path: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
145 let pg_name = Ident::new(&format!("{name}_lt").to_lowercase(), name.span());
146 quote! {
147 #[allow(non_snake_case)]
148 #[::pgrx::pgrx_macros::pg_operator(immutable, parallel_safe)]
149 #[::pgrx::pgrx_macros::opname(<)]
150 #[::pgrx::pgrx_macros::negator(>=)]
151 #[::pgrx::pgrx_macros::commutator(>)]
152 #[::pgrx::pgrx_macros::restrict(scalarltsel)]
153 #[::pgrx::pgrx_macros::join(scalarltjoinsel)]
154 fn #pg_name(left: #path, right: #path) -> bool {
155 left < right
156 }
157
158 }
159}
160
161#[track_caller]
162pub fn derive_pg_gt(name: &Ident, path: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
163 let pg_name = Ident::new(&format!("{name}_gt").to_lowercase(), name.span());
164 quote! {
165 #[allow(non_snake_case)]
166 #[::pgrx::pgrx_macros::pg_operator(immutable, parallel_safe)]
167 #[::pgrx::pgrx_macros::opname(>)]
168 #[::pgrx::pgrx_macros::negator(<=)]
169 #[::pgrx::pgrx_macros::commutator(<)]
170 #[::pgrx::pgrx_macros::restrict(scalargtsel)]
171 #[::pgrx::pgrx_macros::join(scalargtjoinsel)]
172 fn #pg_name(left: #path, right: #path) -> bool {
173 left > right
174 }
175 }
176}
177
178#[track_caller]
179pub fn derive_pg_le(name: &Ident, path: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
180 let pg_name = Ident::new(&format!("{name}_le").to_lowercase(), name.span());
181 quote! {
182 #[allow(non_snake_case)]
183 #[::pgrx::pgrx_macros::pg_operator(immutable, parallel_safe)]
184 #[::pgrx::pgrx_macros::opname(<=)]
185 #[::pgrx::pgrx_macros::negator(>)]
186 #[::pgrx::pgrx_macros::commutator(>=)]
187 #[::pgrx::pgrx_macros::restrict(scalarlesel)]
188 #[::pgrx::pgrx_macros::join(scalarlejoinsel)]
189 fn #pg_name(left: #path, right: #path) -> bool {
190 left <= right
191 }
192 }
193}
194
195#[track_caller]
196pub fn derive_pg_ge(name: &Ident, path: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
197 let pg_name = Ident::new(&format!("{name}_ge").to_lowercase(), name.span());
198 quote! {
199 #[allow(non_snake_case)]
200 #[::pgrx::pgrx_macros::pg_operator(immutable, parallel_safe)]
201 #[::pgrx::pgrx_macros::opname(>=)]
202 #[::pgrx::pgrx_macros::negator(<)]
203 #[::pgrx::pgrx_macros::commutator(<=)]
204 #[::pgrx::pgrx_macros::restrict(scalargesel)]
205 #[::pgrx::pgrx_macros::join(scalargejoinsel)]
206 fn #pg_name(left: #path, right: #path) -> bool {
207 left >= right
208 }
209 }
210}
211
212#[track_caller]
213pub fn derive_pg_cmp(name: &Ident, path: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
214 let pg_name = Ident::new(&format!("{name}_cmp").to_lowercase(), name.span());
215 quote! {
216 #[allow(non_snake_case)]
217 #[::pgrx::pgrx_macros::pg_extern(immutable, parallel_safe)]
218 fn #pg_name(left: #path, right: #path) -> i32 {
219 ::core::cmp::Ord::cmp(&left, &right) as i32
220 }
221 }
222}
223
224#[track_caller]
239pub fn derive_pg_hash(name: &Ident, path: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
240 let pg_name = Ident::new(&format!("{name}_hash").to_lowercase(), name.span());
241 quote! {
242 #[allow(non_snake_case)]
243 #[::pgrx::pgrx_macros::pg_extern(immutable, parallel_safe)]
244 fn #pg_name(value: #path) -> i32
245 where
246 #path: ::core::hash::Hash + ::core::cmp::Eq,
247 {
248 ::pgrx::misc::pgrx_seahash(&value) as i32
249 }
250 }
251}