From f5bf21eb58be2c2d04cf33f13ee2eeb04c5bb718 Mon Sep 17 00:00:00 2001 From: Alex Groleau Date: Wed, 25 Mar 2026 21:37:01 -0400 Subject: [PATCH] fixed root array queries --- fixtures/queryer.json | 60 +++++++++++++++++++++++++++++++++++++++++ src/queryer/compiler.rs | 38 +++++++++++++------------- src/tests/fixtures.rs | 6 +++++ 3 files changed, 85 insertions(+), 19 deletions(-) diff --git a/fixtures/queryer.json b/fixtures/queryer.json index 144a1eb..e7576b4 100644 --- a/fixtures/queryer.json +++ b/fixtures/queryer.json @@ -20,6 +20,16 @@ "$family": "base.person" } ] + }, + { + "name": "get_orders", + "schemas": [ + { + "$id": "get_orders.response", + "type": "array", + "items": { "$ref": "light.order" } + } + ] } ], "enums": [], @@ -664,6 +674,15 @@ } } }, + { + "$id": "light.order", + "$ref": "order", + "properties": { + "customer": { + "$ref": "base.person" + } + } + }, { "$id": "full.order", "$ref": "order", @@ -1569,6 +1588,47 @@ ] ] } + }, + { + "description": "Root Array SQL evaluation for Order fetching Light Order", + "action": "query", + "schema_id": "get_orders.response", + "expect": { + "success": true, + "sql": [ + [ + "(SELECT COALESCE(jsonb_agg(jsonb_build_object(", + " 'archived', entity_2.archived,", + " 'created_at', entity_2.created_at,", + " 'customer',", + " (SELECT jsonb_build_object(", + " 'age', person_3.age,", + " 'archived', entity_5.archived,", + " 'created_at', entity_5.created_at,", + " 'first_name', person_3.first_name,", + " 'id', entity_5.id,", + " 'last_name', person_3.last_name,", + " 'name', entity_5.name,", + " 'type', entity_5.type", + " )", + " FROM agreego.person person_3", + " JOIN agreego.organization organization_4 ON organization_4.id = person_3.id", + " JOIN agreego.entity entity_5 ON entity_5.id = organization_4.id", + " WHERE", + " NOT entity_5.archived", + " AND order_1.customer_id = person_3.id),", + " 'customer_id', order_1.customer_id,", + " 'id', entity_2.id,", + " 'name', entity_2.name,", + " 'total', order_1.total,", + " 'type', entity_2.type", + ")), '[]'::jsonb)", + "FROM agreego.order order_1", + "JOIN agreego.entity entity_2 ON entity_2.id = order_1.id", + "WHERE NOT entity_2.archived)" + ] + ] + } } ] } diff --git a/src/queryer/compiler.rs b/src/queryer/compiler.rs index 7899988..351d546 100644 --- a/src/queryer/compiler.rs +++ b/src/queryer/compiler.rs @@ -63,33 +63,33 @@ impl<'a> Compiler<'a> { } fn compile_array(&mut self, node: Node<'a>) -> Result<(String, String), String> { + // 1. Array of DB Entities (`$ref` or `$family` pointing to a table limit) if let Some(items) = &node.schema.obj.items { - let next_path = node.ast_path.clone(); - - if let Some(ref_id) = &items.obj.r#ref { - if let Some(type_def) = self.db.types.get(ref_id) { - let mut entity_node = node.clone(); - entity_node.ast_path = next_path; - entity_node.schema = std::sync::Arc::clone(items); - return self.compile_entity(type_def, entity_node, true); - } + let mut resolved_type = None; + if let Some(family_target) = items.obj.family.as_ref() { + let base_type_name = family_target.split('.').next_back().unwrap_or(family_target); + resolved_type = self.db.types.get(base_type_name); + } else if let Some(base_type_name) = items.obj.identifier() { + resolved_type = self.db.types.get(&base_type_name); } - let mut next_node = node.clone(); - next_node.depth += 1; - next_node.ast_path = next_path; - next_node.schema = std::sync::Arc::clone(items); - let (item_sql, _) = self.compile_node(next_node)?; + if let Some(type_def) = resolved_type { + let mut entity_node = node.clone(); + entity_node.schema = std::sync::Arc::clone(items); + return self.compile_entity(type_def, entity_node, true); + } + } + + // 2. Arrays of mapped Native Postgres Columns (e.g. `jsonb`, `text[]`) + if let Some(prop) = &node.property_name { return Ok(( - format!("(SELECT jsonb_agg({}) FROM TODO)", item_sql), + format!("{}.{}", node.parent_alias, prop), "array".to_string(), )); } - Ok(( - "SELECT jsonb_agg(TODO) FROM TODO".to_string(), - "array".to_string(), - )) + // 3. Fallback for root execution of standalone non-entity arrays + Err("Cannot compile a root array without a valid entity reference or table mapped via `items`.".to_string()) } fn compile_reference(&mut self, node: Node<'a>) -> Result<(String, String), String> { diff --git a/src/tests/fixtures.rs b/src/tests/fixtures.rs index 1d9a396..9bacdf3 100644 --- a/src/tests/fixtures.rs +++ b/src/tests/fixtures.rs @@ -1457,6 +1457,12 @@ fn test_queryer_0_7() { crate::tests::runner::run_test_case(&path, 0, 7).unwrap(); } +#[test] +fn test_queryer_0_8() { + let path = format!("{}/fixtures/queryer.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 0, 8).unwrap(); +} + #[test] fn test_not_0_0() { let path = format!("{}/fixtures/not.json", env!("CARGO_MANIFEST_DIR"));