ソースを参照

feat(orm): use LEFT JOIN for select_many to support empty collections

Change join generation from INNER JOIN to LEFT JOIN in SQLite dialect.
This ensures parent rows are returned even when no matching child rows
exist, allowing select_many projections to correctly represent empty
collections rather than excluding the parent row entirely.

Update test_select_many_empty_collection to verify the new behavior:
- Parent rows without children are now returned
- Child collection properties are empty Enumerable<T>, not null
Billy Barrow 1 ヶ月 前
コミット
31ca195330
2 ファイル変更16 行追加19 行削除
  1. 1 1
      src/dialects/sqlite-dialect.vala
  2. 15 18
      src/tests/projection-test.vala

+ 1 - 1
src/dialects/sqlite-dialect.vala

@@ -922,7 +922,7 @@ namespace InvercargillSql.Dialects {
             JoinDefinition join,
             VariableTranslator translator
         ) {
-            sql.append("JOIN ");
+            sql.append("LEFT JOIN ");
             sql.append(join.table_name);
             sql.append(" ");
             sql.append(translator.translate_variable(join.variable_name));

+ 15 - 18
src/tests/projection-test.vala

@@ -1808,11 +1808,8 @@ void test_select_many_projections() throws Error {
  * Test: select_many returns empty collection when no child rows exist.
  * 
  * This test verifies that:
- * 1. When a join has no matching rows, the collection property is not null
- * 2. The collection is an empty Enumerable<T>, not null
- * 
- * KNOWN LIMITATION: The current implementation generates NULL for scalar collections
- * in the SQL builder. This test documents the expected behavior once fully implemented.
+ * 1. When a join has no matching rows, the parent row is still returned (via LEFT JOIN)
+ * 2. The collection property is an empty Enumerable<T>, not null
  */
 void test_select_many_empty_collection() throws Error {
     print("Test: select_many empty collection... ");
@@ -1883,22 +1880,22 @@ void test_select_many_empty_collection() throws Error {
         return;
     }
     
-    // NOTE: This test uses INNER JOIN which does NOT return rows without matches.
-    // To get users with empty collections, the projection system would need LEFT JOIN support.
-    // With INNER JOIN, Dave (who has no permissions) won't be returned at all.
-    // This is expected behavior for INNER JOIN.
-    //
-    // When LEFT JOIN is implemented, this test should be updated to verify:
-    // 1. Dave is returned in results
-    // 2. Dave's permissions is an empty collection (not null)
-    
+    // With LEFT JOIN, Dave should be returned even though he has no permissions
     var results = query.materialise();
     
-    // With INNER JOIN, Dave won't be returned since he has no matching permissions
-    // This is correct SQL behavior - the test expectation was wrong for INNER JOIN
-    assert(results.length == 0);
+    // Verify Dave is returned
+    assert(results.length == 1);
+    var arr = results.to_array();
+    assert(arr[0].user_name == "Dave");
     
-    print("PASSED (Note: INNER JOIN correctly returns no rows for user without permissions)\n");
+    // Verify Dave's permissions is an empty collection (not null)
+    int count = 0;
+    foreach (var perm in arr[0].permissions) {
+        count++;
+    }
+    assert(count == 0);
+    
+    print("PASSED\n");
 }
 
 // ========================================