filters are now entities and auto-generated for all table backed types

This commit is contained in:
2026-04-17 01:46:02 -04:00
parent 8175b10a97
commit 87a845e85a
9 changed files with 399 additions and 19 deletions

View File

@ -0,0 +1,78 @@
use crate::database::object::{SchemaObject, SchemaTypeOrArray};
use crate::database::schema::Schema;
use crate::database::Database;
use std::collections::BTreeMap;
use std::sync::Arc;
impl Schema {
pub fn compile_filter(
&self,
_db: &Database,
_root_id: &str,
_errors: &mut Vec<crate::drop::Error>,
) -> Option<Schema> {
if let Some(props) = self.obj.compiled_properties.get() {
let mut filter_props = BTreeMap::new();
for (key, child) in props {
if let Some(mut filter_type) = Self::resolve_filter_type(child) {
filter_type.push("null".to_string());
let mut child_obj = SchemaObject::default();
child_obj.type_ = Some(SchemaTypeOrArray::Multiple(filter_type));
filter_props.insert(key.clone(), Arc::new(Schema { obj: child_obj, always_fail: false }));
}
}
if !filter_props.is_empty() {
let mut wrapper_obj = SchemaObject::default();
wrapper_obj.type_ = Some(SchemaTypeOrArray::Single("object".to_string()));
wrapper_obj.properties = Some(filter_props);
return Some(Schema { obj: wrapper_obj, always_fail: false });
}
}
None
}
fn resolve_filter_type(schema: &Arc<Schema>) -> Option<Vec<String>> {
if let Some(type_) = &schema.obj.type_ {
match type_ {
SchemaTypeOrArray::Single(t) => {
return Self::map_filter_string(t, schema);
}
SchemaTypeOrArray::Multiple(types) => {
for t in types {
if t != "null" {
return Self::map_filter_string(t, schema);
}
}
}
}
}
None
}
fn map_filter_string(t: &str, schema: &Arc<Schema>) -> Option<Vec<String>> {
match t {
"string" => {
if let Some(fmt) = &schema.obj.format {
if fmt == "date-time" {
return Some(vec!["date.condition".to_string()]);
}
}
Some(vec!["string.condition".to_string()])
}
"integer" => Some(vec!["integer.condition".to_string()]),
"number" => Some(vec!["number.condition".to_string()]),
"boolean" => Some(vec!["boolean.condition".to_string()]),
"object" => None, // Inline structures are ignored in Composed References
"array" => None, // We don't filter primitive arrays or map complex arrays yet
"null" => None,
custom => {
// Assume anything else is a Relational cross-boundary that already has its own .filter dynamically built
Some(vec![format!("{}.filter", custom)])
}
}
}
}

View File

@ -1,5 +1,6 @@
pub mod collection;
pub mod edges;
pub mod filters;
pub mod polymorphism;
use crate::database::schema::Schema;

View File

@ -1,3 +1,4 @@
pub mod compile;
pub mod edge;
pub mod r#enum;
pub mod executors;
@ -8,7 +9,6 @@ pub mod punc;
pub mod relation;
pub mod schema;
pub mod r#type;
pub mod compile;
// External mock exports inside the executor sub-folder
@ -210,6 +210,7 @@ impl Database {
}
pub fn compile(&mut self, errors: &mut Vec<crate::drop::Error>) {
// Collect existing schemas patched in the databse
let mut harvested = Vec::new();
for (id, schema_arc) in &self.schemas {
crate::database::schema::Schema::collect_schemas(
@ -234,6 +235,37 @@ impl Database {
.as_ref()
.compile(self, root_id, id.clone(), errors);
}
// Phase 2: Synthesize Composed Filter References
let mut filter_schemas = Vec::new();
for type_def in self.types.values() {
for (id, schema_arc) in &type_def.schemas {
// Only run synthesis on actual structured, table-backed boundaries. Exclude subschemas!
let base_name = id.split('.').last().unwrap_or(id);
let is_table_backed = base_name == type_def.name;
if is_table_backed && !id.contains('/') {
if let Some(filter_schema) = schema_arc.compile_filter(self, id, errors) {
filter_schemas.push((format!("{}.filter", id), Arc::new(filter_schema)));
}
}
}
}
let mut filter_ids = Vec::new();
for (id, filter_arc) in filter_schemas {
filter_ids.push(id.clone());
self.schemas.insert(id, filter_arc);
}
// Now actively compile the newly injected filters to lock all nested compose references natively
for id in filter_ids {
if let Some(filter_arc) = self.schemas.get(&id).cloned() {
let root_id = id.split('/').next().unwrap_or(&id);
filter_arc
.as_ref()
.compile(self, root_id, id.clone(), errors);
}
}
}
fn collect_schemas(&mut self, errors: &mut Vec<crate::drop::Error>) {