Skip to content

Commit 0efbbfa

Browse files
committed
refactor: split SQLPage functions into modules
1 parent 9ca655f commit 0efbbfa

40 files changed

Lines changed: 1302 additions & 1140 deletions

build.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use actix_rt::spawn;
22
use actix_rt::time::sleep;
33
use libflate::gzip;
44
use std::collections::hash_map::DefaultHasher;
5+
use std::fmt::Write as _;
56
use std::fs::File;
67
use std::hash::Hasher;
78
use 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+
3888
fn make_client() -> awc::Client {
3989
awc::ClientBuilder::new()
4090
.timeout(Duration::from_secs(10))
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Built-in SQL functions
2+
3+
Each built-in `sqlpage.*` function lives in one Rust file in [`functions/`](functions).
4+
The file name must match the SQL function name and the file must contain a declaration marker:
5+
6+
```rust
7+
// sqlpage-function: example((&RequestInfo), value: Option<Cow<str>>);
8+
9+
#[allow(clippy::wildcard_imports)]
10+
use super::*;
11+
12+
pub(super) async fn example(request: &RequestInfo, value: Option<Cow<'_, str>>) -> Option<String> {
13+
// ...
14+
}
15+
```
16+
17+
At compile time, `build.rs` scans every `.rs` file in `functions/`, generates the module declarations,
18+
and passes all marker declarations to `sqlpage_functions!`, which generates the function-name registry,
19+
argument conversion, and dispatch code. Adding a correctly named file is therefore enough to register a
20+
new SQLPage function; do not edit generated files in `OUT_DIR`.
21+
22+
Keep helpers and unit tests that are specific to a function in that function's file. Shared helpers can be
23+
made `pub(super)` and used by sibling function modules through `use super::*`.

0 commit comments

Comments
 (0)