Skip to main content

icydb_schema/build/
mod.rs

1use crate::{Error, ThisError, node::Schema, prelude::*, validate::validate_schema};
2use std::sync::{LazyLock, OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard};
3
4///
5/// BuildError
6///
7
8#[derive(Debug, ThisError)]
9pub enum BuildError {
10    #[error("validation failed: {0}")]
11    Validation(ErrorTree),
12}
13
14///
15/// SCHEMA
16/// the static data structure
17///
18
19static SCHEMA: LazyLock<RwLock<Schema>> = LazyLock::new(|| RwLock::new(Schema::new()));
20
21static SCHEMA_VALIDATED: OnceLock<bool> = OnceLock::new();
22
23/// Acquire a write guard to the global schema during build-time codegen.
24pub fn schema_write() -> RwLockWriteGuard<'static, Schema> {
25    SCHEMA
26        .write()
27        .expect("schema RwLock poisoned while acquiring write lock")
28}
29
30// schema_read
31// just reads the schema directly without validation
32pub(crate) fn schema_read() -> RwLockReadGuard<'static, Schema> {
33    SCHEMA
34        .read()
35        .expect("schema RwLock poisoned while acquiring read lock")
36}
37
38/// Read the global schema, validating it exactly once per process.
39pub fn get_schema() -> Result<RwLockReadGuard<'static, Schema>, Error> {
40    let schema = schema_read();
41    validate(&schema).map_err(BuildError::Validation)?;
42
43    Ok(schema)
44}
45
46// validate
47fn validate(schema: &Schema) -> Result<(), ErrorTree> {
48    if *SCHEMA_VALIDATED.get_or_init(|| false) {
49        return Ok(());
50    }
51
52    validate_schema(schema)?;
53
54    SCHEMA_VALIDATED.set(true).ok();
55
56    Ok(())
57}