1mod sqlfunc;
17
18pub use sqlfunc::sqlfunc;
19
20#[cfg(any(feature = "test", test))]
22fn sqlfunc_for_test(
23 attr: proc_macro2::TokenStream,
24 item: proc_macro2::TokenStream,
25) -> darling::Result<proc_macro2::TokenStream> {
26 sqlfunc(attr, item, false)
27}
28
29#[cfg(any(feature = "test", test))]
30pub fn test_sqlfunc(
31 attr: proc_macro2::TokenStream,
32 item: proc_macro2::TokenStream,
33) -> (String, String) {
34 fn rust_fmt(input: &str) -> String {
35 let file = syn::parse_file(input).unwrap();
36 prettyplease::unparse(&file)
37 }
38
39 let input = rust_fmt(&format!("#[sqlfunc({attr})]\n{item}"));
40 let output = rust_fmt(
41 &sqlfunc_for_test(attr, item)
42 .unwrap_or_else(|err| err.write_errors())
43 .to_string(),
44 );
45 (output, input)
46}
47
48#[cfg(any(feature = "test", test))]
49pub fn test_sqlfunc_str(attr: &str, item: &str) -> (String, String) {
50 test_sqlfunc(attr.parse().unwrap(), item.parse().unwrap())
51}
52
53#[cfg(test)]
54mod test {
55 use quote::quote;
56
57 #[cfg_attr(miri, ignore)] #[mz_ore::test]
59 fn insta_test_add_int16() {
60 let attr = quote! {
61 is_monotone = (true, true),
62 output_type = i16,
63 is_infix_op = true,
64 sqlname = "+",
65 propagates_nulls = true,
66 test = true,
67 };
68 let item = quote! {
69 fn add_int16<'a>(a: Datum<'a>, b: Datum<'a>) -> Result<Datum<'a>, EvalError> {
70 a.unwrap_int16()
71 .checked_add(b.unwrap_int16())
72 .ok_or(EvalError::NumericFieldOverflow)
73 .map(Datum::from)
74 }
75 };
76 let (output, input) = super::test_sqlfunc(attr, item);
77 insta::assert_snapshot!("add_int16", output, &input);
78 }
79
80 #[cfg_attr(miri, ignore)] #[mz_ore::test]
82 fn insta_test_unary() {
83 let attr = quote! {test = true};
84 let item = quote! {
85 fn unary_fn<'a>(a: Datum<'a>) -> bool {
86 unimplemented!()
87 }
88 };
89 let (output, input) = super::test_sqlfunc(attr, item);
90 insta::assert_snapshot!("unary_fn", output, &input);
91 }
92
93 #[cfg_attr(miri, ignore)] #[mz_ore::test]
95 fn insta_test_unary_arena() {
96 let attr = quote! {test = true};
97 let item = quote! {
98 fn unary_fn<'a>(a: Datum<'a>, temp_storage: &RowArena) -> bool {
99 unimplemented!()
100 }
101 };
102 let (output, input) = super::test_sqlfunc(attr, item);
103 insta::assert_snapshot!("unary_arena_fn", output, &input);
104 }
105
106 #[cfg_attr(miri, ignore)] #[mz_ore::test]
108 fn insta_test_unary_ref() {
109 let attr = quote! {test = true};
110 let item = quote! {
111 fn unary_fn<'a>(a: &i16) -> bool {
112 unimplemented!()
113 }
114 };
115 let (output, input) = super::test_sqlfunc(attr, item);
116 insta::assert_snapshot!("unary_ref", output, &input);
117 }
118
119 #[cfg_attr(miri, ignore)] #[mz_ore::test]
121 fn insta_test_complex_output_type() {
122 let attr = quote! {
123 is_monotone = (true, true),
124 output_type = "Option<bool>",
125 is_infix_op = true,
126 sqlname = "test",
127 propagates_nulls = true,
128 test = true,
129 };
130 let item = quote! {
131 fn complex_output_type_fn<'a>(
132 a: Datum<'a>,
133 b: Datum<'a>,
134 ) -> Result<Datum<'a>, EvalError> {
135 unimplemented!()
136 }
137 };
138 let (output, input) = super::test_sqlfunc(attr, item);
139 insta::assert_snapshot!("complex_type", output, &input);
140 }
141
142 #[cfg_attr(miri, ignore)] #[mz_ore::test]
144 fn insta_test_binary_arena() {
145 let attr = quote! {test = true};
146 let item = quote! {
147 fn unary_fn<'a>(a: Datum<'a>, b: u16, temp_storage: &RowArena) -> bool {
148 unimplemented!()
149 }
150 };
151 let (output, input) = super::test_sqlfunc(attr, item);
152 insta::assert_snapshot!("binary_arena_fn", output, &input);
153 }
154
155 #[cfg_attr(miri, ignore)] #[mz_ore::test]
157 fn insta_test_variadic_tuple() {
158 let attr = quote! {
159 Replace,
160 sqlname = "replace",
161 };
162 let item = quote! {
163 fn replace(text: &str, from: &str, to: &str) -> Result<String, EvalError> {
164 Ok(text.replace(from, to))
165 }
166 };
167 let (output, input) = super::test_sqlfunc(attr, item);
168 insta::assert_snapshot!("variadic_tuple", output, &input);
169 }
170
171 #[cfg_attr(miri, ignore)] #[mz_ore::test]
173 fn insta_test_variadic_variadic_type() {
174 let attr = quote! {
175 Concat,
176 sqlname = "concat",
177 is_associative = true,
178 };
179 let item = quote! {
180 fn concat(strs: Variadic<Option<&str>>) -> Result<String, EvalError> {
181 Ok(strs.into_iter().flatten().collect())
182 }
183 };
184 let (output, input) = super::test_sqlfunc(attr, item);
185 insta::assert_snapshot!("variadic_variadic_type", output, &input);
186 }
187
188 #[cfg_attr(miri, ignore)] #[mz_ore::test]
190 fn insta_test_variadic_arena() {
191 let attr = quote! {
192 ArrayFill,
193 sqlname = "array_fill",
194 introduces_nulls = false,
195 };
196 let item = quote! {
197 fn array_fill<'a>(
198 &self,
199 fill: Datum<'a>,
200 dims: Datum<'a>,
201 lb: OptionalArg<Datum<'a>>,
202 temp_storage: &RowArena,
203 ) -> Result<Datum<'a>, EvalError> {
204 unimplemented!()
205 }
206 };
207 let (output, input) = super::test_sqlfunc(attr, item);
208 insta::assert_snapshot!("variadic_arena", output, &input);
209 }
210
211 #[cfg_attr(miri, ignore)] #[mz_ore::test]
213 fn insta_test_variadic_modifiers() {
214 let attr = quote! {
215 Greatest,
216 sqlname = "greatest",
217 could_error = false,
218 is_monotone = true,
219 };
220 let item = quote! {
221 fn greatest<'a>(datums: Variadic<Datum<'a>>) -> Datum<'a> {
222 datums.into_iter().max().unwrap_or(Datum::Null)
223 }
224 };
225 let (output, input) = super::test_sqlfunc(attr, item);
226 insta::assert_snapshot!("variadic_modifiers", output, &input);
227 }
228}