From 69bd726b25b512bfb8474b208fcf98d755f509f9 Mon Sep 17 00:00:00 2001 From: Alex Groleau Date: Fri, 17 Apr 2026 07:43:19 -0400 Subject: [PATCH] more filter fixes --- fixtures/filter.json | 54 +++++++++++++++---- fixtures/queryer.json | 4 +- .../compile/{filters.rs => filter.rs} | 18 +++++-- src/database/compile/mod.rs | 2 +- src/database/punc.rs | 1 + src/database/relation.rs | 2 + src/lib.rs | 4 +- src/queryer/mod.rs | 6 +-- src/tests/mod.rs | 6 ++- src/tests/types/case.rs | 4 +- 10 files changed, 75 insertions(+), 26 deletions(-) rename src/database/compile/{filters.rs => filter.rs} (83%) diff --git a/fixtures/filter.json b/fixtures/filter.json index 11f5d5d..d15fd1a 100644 --- a/fixtures/filter.json +++ b/fixtures/filter.json @@ -94,19 +94,30 @@ { "id": "type3", "type": "type", - "name": "filter", + "name": "search", "module": "core", - "source": "filter", + "source": "search", "hierarchy": [ - "filter" + "search" ], "variations": [ - "filter", - "string.condition", - "integer.condition", - "date.condition" + "search" ], "schemas": { + "search": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "filter": { + "type": "filter" + } + } + }, + "filter": { + "type": "object" + }, "condition": { "type": "object", "properties": { @@ -161,7 +172,7 @@ "schemas": { "person": {}, "person.filter": { - "type": "object", + "type": "filter", "compiledPropertyNames": [ "age", "billing_address", @@ -197,7 +208,7 @@ }, "address": {}, "address.filter": { - "type": "object", + "type": "filter", "compiledPropertyNames": [ "city" ], @@ -210,10 +221,33 @@ } } }, + "filter": {}, "condition": {}, "string.condition": {}, "integer.condition": {}, - "date.condition": {} + "date.condition": {}, + "search": {}, + "search.filter": { + "type": "filter", + "compiledPropertyNames": [ + "filter", + "name" + ], + "properties": { + "filter": { + "type": [ + "filter.filter", + "null" + ] + }, + "name": { + "type": [ + "string.condition", + "null" + ] + } + } + } } } } diff --git a/fixtures/queryer.json b/fixtures/queryer.json index 997f2d0..aa6671f 100644 --- a/fixtures/queryer.json +++ b/fixtures/queryer.json @@ -1195,7 +1195,7 @@ "description": "Simple entity select with multiple filters", "action": "query", "schema_id": "entity", - "filters": { + "filter": { "id": { "$eq": "123e4567-e89b-12d3-a456-426614174000", "$ne": "123e4567-e89b-12d3-a456-426614174001", @@ -1443,7 +1443,7 @@ "description": "Person select on full schema with filters", "action": "query", "schema_id": "full.person", - "filters": { + "filter": { "age": { "$eq": 30, "$gt": 20, diff --git a/src/database/compile/filters.rs b/src/database/compile/filter.rs similarity index 83% rename from src/database/compile/filters.rs rename to src/database/compile/filter.rs index 5a38c85..7b3c8ff 100644 --- a/src/database/compile/filters.rs +++ b/src/database/compile/filter.rs @@ -1,6 +1,6 @@ +use crate::database::Database; use crate::database::object::{SchemaObject, SchemaTypeOrArray}; use crate::database::schema::Schema; -use crate::database::Database; use std::collections::BTreeMap; use std::sync::Arc; @@ -20,16 +20,26 @@ impl Schema { 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 })); + 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())); + // Conceptually link this directly into the STI lineage of the base `filter` object + wrapper_obj.type_ = Some(SchemaTypeOrArray::Single("filter".to_string())); wrapper_obj.properties = Some(filter_props); - return Some(Schema { obj: wrapper_obj, always_fail: false }); + return Some(Schema { + obj: wrapper_obj, + always_fail: false, + }); } } None diff --git a/src/database/compile/mod.rs b/src/database/compile/mod.rs index d54fc0f..5c66379 100644 --- a/src/database/compile/mod.rs +++ b/src/database/compile/mod.rs @@ -1,6 +1,6 @@ pub mod collection; pub mod edges; -pub mod filters; +pub mod filter; pub mod polymorphism; use crate::database::schema::Schema; diff --git a/src/database/punc.rs b/src/database/punc.rs index 6bf41fe..55fa9d7 100644 --- a/src/database/punc.rs +++ b/src/database/punc.rs @@ -15,6 +15,7 @@ pub struct Punc { pub public: bool, pub form: bool, pub get: Option, + pub save: Option, pub page: Option, #[serde(default)] pub schemas: std::collections::BTreeMap>, diff --git a/src/database/relation.rs b/src/database/relation.rs index 3ce1739..84988ad 100644 --- a/src/database/relation.rs +++ b/src/database/relation.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(default)] pub struct Relation { + pub id: String, + pub r#type: String, pub constraint: String, pub source_type: String, pub source_columns: Vec, diff --git a/src/lib.rs b/src/lib.rs index 6d9e11d..9e81344 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,7 +72,7 @@ pub fn jspg_merge(schema_id: &str, data: JsonB) -> JsonB { } #[cfg_attr(not(test), pg_extern)] -pub fn jspg_query(schema_id: &str, filters: Option) -> JsonB { +pub fn jspg_query(schema_id: &str, filter: Option) -> JsonB { let engine_opt = { let lock = GLOBAL_JSPG.read().unwrap(); lock.clone() @@ -82,7 +82,7 @@ pub fn jspg_query(schema_id: &str, filters: Option) -> JsonB { Some(engine) => { let drop = engine .queryer - .query(schema_id, filters.as_ref().map(|f| &f.0)); + .query(schema_id, filter.as_ref().map(|f| &f.0)); JsonB(serde_json::to_value(drop).unwrap()) } None => jspg_failure(), diff --git a/src/queryer/mod.rs b/src/queryer/mod.rs index 755f93a..114ff12 100644 --- a/src/queryer/mod.rs +++ b/src/queryer/mod.rs @@ -21,9 +21,9 @@ impl Queryer { pub fn query( &self, schema_id: &str, - filters: Option<&serde_json::Value>, + filter: Option<&serde_json::Value>, ) -> crate::drop::Drop { - let filters_map = filters.and_then(|f| f.as_object()); + let filters_map = filter.and_then(|f| f.as_object()); // 1. Process filters into structured $op keys and linear values let (filter_keys, args) = match self.parse_filter_entries(filters_map) { @@ -35,7 +35,7 @@ impl Queryer { details: crate::drop::ErrorDetails { path: None, // filters apply to the root query cause: Some(msg), - context: filters.cloned(), + context: filter.cloned(), schema: Some(schema_id.to_string()), }, }]); diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 1830140..3c65476 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -92,6 +92,8 @@ fn test_library_api() { "puncs": {}, "relations": { "fk_test_target": { + "id": "11111111-1111-1111-1111-111111111111", + "type": "relation", "constraint": "fk_test_target", "destination_columns": ["id"], "destination_type": "target_schema", @@ -144,7 +146,7 @@ fn test_library_api() { "target": { "type": ["target_schema.filter", "null"] }, "type": { "type": ["string.condition", "null"] } }, - "type": "object" + "type": "filter" } }, "sensitive": false, @@ -181,7 +183,7 @@ fn test_library_api() { "properties": { "value": { "type": ["number.condition", "null"] } }, - "type": "object" + "type": "filter" } }, "sensitive": false, diff --git a/src/tests/types/case.rs b/src/tests/types/case.rs index 5124b41..4b320e5 100644 --- a/src/tests/types/case.rs +++ b/src/tests/types/case.rs @@ -17,7 +17,7 @@ pub struct Case { // For Query #[serde(default)] - pub filters: Option, + pub filter: Option, // For Merge & Validate #[serde(default)] @@ -122,7 +122,7 @@ impl Case { use crate::queryer::Queryer; let queryer = Queryer::new(db.clone()); - let result = queryer.query(&self.schema_id, self.filters.as_ref()); + let result = queryer.query(&self.schema_id, self.filter.as_ref()); let return_val = if let Some(expect) = &self.expect { if let Err(e) = expect.assert_drop(&result) {