validator refactor progress
This commit is contained in:
105
src/lib.rs
105
src/lib.rs
@ -2,7 +2,11 @@ use pgrx::*;
|
||||
|
||||
pg_module_magic!();
|
||||
|
||||
pub mod database;
|
||||
pub mod drop;
|
||||
pub mod jspg;
|
||||
pub mod merger;
|
||||
pub mod queryer;
|
||||
pub mod validator;
|
||||
|
||||
use serde_json::json;
|
||||
@ -12,100 +16,38 @@ lazy_static::lazy_static! {
|
||||
// Global Atomic Swap Container:
|
||||
// - RwLock: To protect the SWAP of the Option.
|
||||
// - Option: Because it starts empty.
|
||||
// - Arc: Because multiple running threads might hold the OLD validator while we swap.
|
||||
// - Validator: It immutably owns the Registry.
|
||||
static ref GLOBAL_VALIDATOR: RwLock<Option<Arc<validator::Validator>>> = RwLock::new(None);
|
||||
// - Arc: Because multiple running threads might hold the OLD engine while we swap.
|
||||
// - Jspg: The root semantic engine encapsulating the database metadata, validator, queryer, and merger.
|
||||
static ref GLOBAL_JSPG: RwLock<Option<Arc<jspg::Jspg>>> = RwLock::new(None);
|
||||
}
|
||||
|
||||
#[pg_extern(strict)]
|
||||
pub fn cache_json_schemas(enums: JsonB, types: JsonB, puncs: JsonB) -> JsonB {
|
||||
// 1 & 2. Build Registry, Families, and Wrap in Validator all in one shot
|
||||
let new_validator = crate::validator::Validator::from_punc_definition(
|
||||
Some(&enums.0),
|
||||
Some(&types.0),
|
||||
Some(&puncs.0),
|
||||
);
|
||||
let new_arc = Arc::new(new_validator);
|
||||
pub fn jspg_cache_database(database: JsonB) -> JsonB {
|
||||
let new_jspg = crate::jspg::Jspg::new(&database.0);
|
||||
let new_arc = Arc::new(new_jspg);
|
||||
|
||||
// 3. ATOMIC SWAP
|
||||
{
|
||||
let mut lock = GLOBAL_VALIDATOR.write().unwrap();
|
||||
let mut lock = GLOBAL_JSPG.write().unwrap();
|
||||
*lock = Some(new_arc);
|
||||
}
|
||||
|
||||
let drop = crate::drop::Drop::success();
|
||||
JsonB(serde_json::to_value(drop).unwrap())
|
||||
}
|
||||
|
||||
#[pg_extern(strict, parallel_safe)]
|
||||
pub fn mask_json_schema(schema_id: &str, instance: JsonB) -> JsonB {
|
||||
// 1. Acquire Snapshot
|
||||
let validator_arc = {
|
||||
let lock = GLOBAL_VALIDATOR.read().unwrap();
|
||||
lock.clone()
|
||||
};
|
||||
|
||||
// 2. Validate (Lock-Free)
|
||||
if let Some(validator) = validator_arc {
|
||||
// We need a mutable copy of the value to mask it
|
||||
let mut mutable_instance = instance.0.clone();
|
||||
|
||||
match validator.mask(schema_id, &mut mutable_instance) {
|
||||
Ok(result) => {
|
||||
// If valid, return the MASKED instance
|
||||
if result.is_valid() {
|
||||
let drop = crate::drop::Drop::success_with_val(mutable_instance);
|
||||
JsonB(serde_json::to_value(drop).unwrap())
|
||||
} else {
|
||||
// If invalid, return errors (Schema Validation Errors)
|
||||
let errors: Vec<crate::drop::Error> = result
|
||||
.errors
|
||||
.into_iter()
|
||||
.map(|e| crate::drop::Error {
|
||||
code: e.code,
|
||||
message: e.message,
|
||||
details: crate::drop::ErrorDetails { path: e.path },
|
||||
})
|
||||
.collect();
|
||||
let drop = crate::drop::Drop::with_errors(errors);
|
||||
JsonB(serde_json::to_value(drop).unwrap())
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
// Schema Not Found or other fatal error
|
||||
let error = crate::drop::Error {
|
||||
code: e.code,
|
||||
message: e.message,
|
||||
details: crate::drop::ErrorDetails { path: e.path },
|
||||
};
|
||||
let drop = crate::drop::Drop::with_errors(vec![error]);
|
||||
JsonB(serde_json::to_value(drop).unwrap())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let error = crate::drop::Error {
|
||||
code: "VALIDATOR_NOT_INITIALIZED".to_string(),
|
||||
message: "JSON Schemas have not been cached yet. Run cache_json_schemas()".to_string(),
|
||||
details: crate::drop::ErrorDetails {
|
||||
path: "".to_string(),
|
||||
},
|
||||
};
|
||||
let drop = crate::drop::Drop::with_errors(vec![error]);
|
||||
JsonB(serde_json::to_value(drop).unwrap())
|
||||
}
|
||||
}
|
||||
// `mask_json_schema` has been removed as the mask architecture is fully replaced by Spi string queries during DB interactions.
|
||||
|
||||
#[pg_extern(strict, parallel_safe)]
|
||||
pub fn validate_json_schema(schema_id: &str, instance: JsonB) -> JsonB {
|
||||
// 1. Acquire Snapshot
|
||||
let validator_arc = {
|
||||
let lock = GLOBAL_VALIDATOR.read().unwrap();
|
||||
let jspg_arc = {
|
||||
let lock = GLOBAL_JSPG.read().unwrap();
|
||||
lock.clone()
|
||||
};
|
||||
|
||||
// 2. Validate (Lock-Free)
|
||||
if let Some(validator) = validator_arc {
|
||||
match validator.validate(schema_id, &instance.0) {
|
||||
if let Some(engine) = jspg_arc {
|
||||
match engine.validator.validate(schema_id, &instance.0) {
|
||||
Ok(result) => {
|
||||
if result.is_valid() {
|
||||
let drop = crate::drop::Drop::success();
|
||||
@ -137,7 +79,7 @@ pub fn validate_json_schema(schema_id: &str, instance: JsonB) -> JsonB {
|
||||
} else {
|
||||
let error = crate::drop::Error {
|
||||
code: "VALIDATOR_NOT_INITIALIZED".to_string(),
|
||||
message: "JSON Schemas have not been cached yet. Run cache_json_schemas()".to_string(),
|
||||
message: "The JSPG database has not been cached yet. Run jspg_cache_database()".to_string(),
|
||||
details: crate::drop::ErrorDetails {
|
||||
path: "".to_string(),
|
||||
},
|
||||
@ -149,8 +91,11 @@ pub fn validate_json_schema(schema_id: &str, instance: JsonB) -> JsonB {
|
||||
|
||||
#[pg_extern(strict, parallel_safe)]
|
||||
pub fn json_schema_cached(schema_id: &str) -> bool {
|
||||
if let Some(validator) = GLOBAL_VALIDATOR.read().unwrap().as_ref() {
|
||||
match validator.validate(schema_id, &serde_json::Value::Null) {
|
||||
if let Some(engine) = GLOBAL_JSPG.read().unwrap().as_ref() {
|
||||
match engine
|
||||
.validator
|
||||
.validate(schema_id, &serde_json::Value::Null)
|
||||
{
|
||||
Err(e) if e.code == "SCHEMA_NOT_FOUND" => false,
|
||||
_ => true,
|
||||
}
|
||||
@ -161,7 +106,7 @@ pub fn json_schema_cached(schema_id: &str) -> bool {
|
||||
|
||||
#[pg_extern(strict)]
|
||||
pub fn clear_json_schemas() -> JsonB {
|
||||
let mut lock = GLOBAL_VALIDATOR.write().unwrap();
|
||||
let mut lock = GLOBAL_JSPG.write().unwrap();
|
||||
*lock = None;
|
||||
let drop = crate::drop::Drop::success();
|
||||
JsonB(serde_json::to_value(drop).unwrap())
|
||||
@ -169,8 +114,8 @@ pub fn clear_json_schemas() -> JsonB {
|
||||
|
||||
#[pg_extern(strict, parallel_safe)]
|
||||
pub fn show_json_schemas() -> JsonB {
|
||||
if let Some(validator) = GLOBAL_VALIDATOR.read().unwrap().as_ref() {
|
||||
let mut keys = validator.get_schema_ids();
|
||||
if let Some(engine) = GLOBAL_JSPG.read().unwrap().as_ref() {
|
||||
let mut keys = engine.validator.get_schema_ids();
|
||||
keys.sort();
|
||||
let drop = crate::drop::Drop::success_with_val(json!(keys));
|
||||
JsonB(serde_json::to_value(drop).unwrap())
|
||||
|
||||
Reference in New Issue
Block a user