Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dc033296d7 | |||
| 03a871bc1a | |||
| 8aa15873b0 | |||
| 0d282cc930 | |||
| 581fc8e0c0 | |||
| 6f0bff8dc7 | |||
| 99c69e27ab |
@ -87,6 +87,34 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schedule": {
|
||||
"type": [
|
||||
"opening_hours",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"season": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"opening_hours": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"open": {
|
||||
"type": "string"
|
||||
},
|
||||
"seasons": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "season"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -262,6 +290,7 @@
|
||||
"uuid_field",
|
||||
"tags",
|
||||
"ad_hoc",
|
||||
"schedule",
|
||||
"$and",
|
||||
"$or"
|
||||
],
|
||||
@ -277,6 +306,7 @@
|
||||
"uuid_field",
|
||||
"tags",
|
||||
"ad_hoc",
|
||||
"schedule",
|
||||
"$and",
|
||||
"$or"
|
||||
],
|
||||
@ -298,6 +328,7 @@
|
||||
"uuid_field",
|
||||
"tags",
|
||||
"ad_hoc",
|
||||
"schedule",
|
||||
"$and",
|
||||
"$or"
|
||||
],
|
||||
@ -366,6 +397,12 @@
|
||||
"string.condition",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"schedule": {
|
||||
"type": [
|
||||
"opening_hours.filter",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "filter"
|
||||
@ -483,10 +520,66 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"opening_hours": {},
|
||||
"season": {},
|
||||
"opening_hours.filter": {
|
||||
"type": "filter",
|
||||
"compiledPropertyNames": [
|
||||
"open",
|
||||
"seasons",
|
||||
"$and",
|
||||
"$or"
|
||||
],
|
||||
"properties": {
|
||||
"open": {
|
||||
"type": [
|
||||
"string.condition",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"seasons": {
|
||||
"type": [
|
||||
"season.filter",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"$and": {
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"items": {
|
||||
"type": "opening_hours.filter",
|
||||
"compiledPropertyNames": [
|
||||
"open",
|
||||
"seasons",
|
||||
"$and",
|
||||
"$or"
|
||||
]
|
||||
}
|
||||
},
|
||||
"$or": {
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"items": {
|
||||
"type": "opening_hours.filter",
|
||||
"compiledPropertyNames": [
|
||||
"open",
|
||||
"seasons",
|
||||
"$and",
|
||||
"$or"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"season.filter": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@ -151,6 +151,7 @@ impl Schema {
|
||||
"number" => Some(vec!["number.condition".to_string()]),
|
||||
"boolean" => Some(vec!["boolean.condition".to_string()]),
|
||||
"object" => None, // Inline structures are ignored in Composed References
|
||||
"dict" => None, // Dynamic dictionary maps are ignored in Composed References
|
||||
"array" => {
|
||||
if let Some(items) = &schema.obj.items {
|
||||
return Self::resolve_filter_type(items, db);
|
||||
@ -164,8 +165,20 @@ impl Schema {
|
||||
} else if db.enums.contains_key(custom) {
|
||||
Some(vec![format!("{}.condition", custom)])
|
||||
} else {
|
||||
// Assume anything else is a Relational cross-boundary that already has its own .filter dynamically built
|
||||
Some(vec![format!("{}.filter", custom)])
|
||||
// A named type gets a reference to its dynamically built .filter — either a
|
||||
// Relational cross-boundary (table-backed) or a named value type, whose filter
|
||||
// is likewise synthesized (see Database::compile_filters). A named type with no
|
||||
// compilable structure gets no filter — omit it rather than dangle a reference.
|
||||
let base = custom.split('.').next_back().unwrap_or(custom);
|
||||
let has_value_filter = db
|
||||
.schemas
|
||||
.get(custom)
|
||||
.map_or(false, |s| Database::is_value_filter_candidate(custom, s));
|
||||
if db.types.contains_key(base) || has_value_filter {
|
||||
Some(vec![format!("{}.filter", custom)])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,6 +125,7 @@ impl Schema {
|
||||
child.compile(db, root_id, format!("{}/{}", path, k), errors);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(items) = &self.obj.items {
|
||||
items.compile(db, root_id, format!("{}/items", path), errors);
|
||||
}
|
||||
@ -138,6 +139,7 @@ impl Schema {
|
||||
if let Some(child) = &self.obj.not {
|
||||
child.compile(db, root_id, format!("{}/not", path), errors);
|
||||
}
|
||||
|
||||
if let Some(child) = &self.obj.contains {
|
||||
child.compile(db, root_id, format!("{}/contains", path), errors);
|
||||
}
|
||||
|
||||
@ -262,15 +262,23 @@ impl Database {
|
||||
}
|
||||
}
|
||||
|
||||
/// Synthesizes Composed Filter References for all table-backed boundaries.
|
||||
/// Synthesizes Composed Filter References for all table-backed boundaries — and for
|
||||
/// named non-table value types (schema-only objects, e.g. an operating-hours config),
|
||||
/// so a property reference resolves to ONE named filter instead of inlining anonymous
|
||||
/// per-path copies (which duplicate identical leaf type names for downstream codegen).
|
||||
fn compile_filters(&mut self, errors: &mut Vec<crate::drop::Error>) -> Vec<(String, String)> {
|
||||
let mut filter_schemas = Vec::new();
|
||||
let mut seen_value_ids = std::collections::HashSet::new();
|
||||
for (type_name, type_def) in &self.types {
|
||||
for (id, schema_arc) in &type_def.schemas {
|
||||
// Only run synthesis on actual structured, table-backed boundaries. Exclude subschemas!
|
||||
// Run synthesis on structured table-backed boundaries and named value types.
|
||||
// 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('/') {
|
||||
let is_value_type = !is_table_backed
|
||||
&& Self::is_value_filter_candidate(id, schema_arc)
|
||||
&& seen_value_ids.insert(id.clone());
|
||||
if (is_table_backed || is_value_type) && !id.contains('/') {
|
||||
if let Some(filter_schema) = schema_arc.compile_filter(self, id, errors) {
|
||||
filter_schemas.push((
|
||||
type_name.clone(),
|
||||
@ -293,6 +301,20 @@ impl Database {
|
||||
filter_ids
|
||||
}
|
||||
|
||||
/// A named non-table value type that earns its own synthesized filter: a bare-named
|
||||
/// (dotless) schema-only object with compiled properties. The base `filter`/`condition`
|
||||
/// schemas are infrastructure, not value types.
|
||||
pub fn is_value_filter_candidate(id: &str, schema: &Arc<Schema>) -> bool {
|
||||
!id.contains('.')
|
||||
&& id != "filter"
|
||||
&& id != "condition"
|
||||
&& schema
|
||||
.obj
|
||||
.compiled_properties
|
||||
.get()
|
||||
.map_or(false, |props| !props.is_empty())
|
||||
}
|
||||
|
||||
/// Synthesizes strong Enum Conditions mirroring the string.condition capabilities.
|
||||
fn compile_conditions(&mut self) -> Vec<(String, String)> {
|
||||
let mut enum_conditions = Vec::new();
|
||||
|
||||
Reference in New Issue
Block a user