@@ -2,6 +2,7 @@ use actix_rt::spawn;
22use actix_rt:: time:: sleep;
33use libflate:: gzip;
44use std:: collections:: hash_map:: DefaultHasher ;
5+ use std:: fmt:: Write as _;
56use std:: fs:: File ;
67use std:: hash:: Hasher ;
78use std:: io:: Read ;
@@ -17,6 +18,7 @@ async fn main() {
1718 . unwrap ( ) ;
1819
1920 println ! ( "cargo:rerun-if-changed=build.rs" ) ;
21+ generate_sqlpage_functions ( ) ;
2022 let c = Rc :: new ( make_client ( ) ) ;
2123
2224 for h in [
@@ -35,6 +37,54 @@ async fn main() {
3537 set_odbc_rpath ( ) ;
3638}
3739
40+ const SQLPAGE_FUNCTION_MARKER : & str = "// sqlpage-function: " ;
41+
42+ /// Generates the built-in SQL function module declarations and registry from one file per function.
43+ fn generate_sqlpage_functions ( ) {
44+ let functions_dir = Path :: new ( "src/webserver/database/sqlpage_functions/functions" ) ;
45+ println ! ( "cargo:rerun-if-changed={}" , functions_dir. display( ) ) ;
46+
47+ let mut functions = std:: fs:: read_dir ( functions_dir)
48+ . unwrap ( )
49+ . map ( |entry| entry. unwrap ( ) . path ( ) )
50+ . filter ( |path| path. extension ( ) . is_some_and ( |extension| extension == "rs" ) )
51+ . collect :: < Vec < _ > > ( ) ;
52+ functions. sort ( ) ;
53+
54+ let mut generated = String :: from ( "// @generated by build.rs; do not edit.\n \n " ) ;
55+ let mut definitions = String :: new ( ) ;
56+ for path in functions {
57+ let module_name = path. file_stem ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
58+ let source = std:: fs:: read_to_string ( & path) . unwrap ( ) ;
59+ let definition = source
60+ . lines ( )
61+ . find_map ( |line| line. strip_prefix ( SQLPAGE_FUNCTION_MARKER ) )
62+ . unwrap_or_else ( || {
63+ panic ! (
64+ "{} has no {SQLPAGE_FUNCTION_MARKER:?} declaration" ,
65+ path. display( )
66+ )
67+ } ) ;
68+ assert ! (
69+ definition. starts_with( & format!( "{module_name}(" ) ) ,
70+ "The function declared in {} must match its file name" ,
71+ path. display( )
72+ ) ;
73+ let canonical_path = path. canonicalize ( ) . unwrap ( ) ;
74+ writeln ! ( generated, "#[path = {canonical_path:?}]" ) . unwrap ( ) ;
75+ writeln ! ( generated, "mod {module_name};" ) . unwrap ( ) ;
76+ writeln ! ( generated, "#[allow(clippy::wildcard_imports)]" ) . unwrap ( ) ;
77+ writeln ! ( generated, "use {module_name}::*;\n " ) . unwrap ( ) ;
78+ writeln ! ( definitions, " {definition}" ) . unwrap ( ) ;
79+ }
80+ generated. push_str ( "super::function_definition_macro::sqlpage_functions! {\n " ) ;
81+ generated. push_str ( & definitions) ;
82+ generated. push_str ( "}\n " ) ;
83+
84+ let out_dir = PathBuf :: from ( std:: env:: var ( "OUT_DIR" ) . unwrap ( ) ) ;
85+ std:: fs:: write ( out_dir. join ( "sqlpage_functions.rs" ) , generated) . unwrap ( ) ;
86+ }
87+
3888fn make_client ( ) -> awc:: Client {
3989 awc:: ClientBuilder :: new ( )
4090 . timeout ( Duration :: from_secs ( 10 ) )
0 commit comments