@@ -3894,4 +3894,136 @@ void testFlatPostgresCollectionNestedFieldQuery(String dataStoreName) throws IOE
38943894 long cityCountQuery = flatCollection .count (cityQuery );
38953895 assertEquals (2 , cityCountQuery );
38963896 }
3897+
3898+ @ ParameterizedTest
3899+ @ ArgumentsSource (PostgresProvider .class )
3900+ void testFlatVsNestedCollectionConsistency (String dataStoreName ) throws IOException {
3901+ Datastore datastore = datastoreMap .get (dataStoreName );
3902+
3903+ // Get both collection types
3904+ Collection nestedCollection =
3905+ datastore .getCollection (COLLECTION_NAME ); // Default nested collection
3906+ Collection flatCollection =
3907+ datastore .getCollectionForType (FLAT_COLLECTION_NAME , DocumentType .FLAT );
3908+
3909+ // Test 1: Count all documents - should be equal
3910+ Query countAllQuery = Query .builder ().build ();
3911+ long nestedCount = nestedCollection .count (countAllQuery );
3912+ long flatCount = flatCollection .count (countAllQuery );
3913+ assertEquals (
3914+ nestedCount , flatCount , "Total document count should be equal in both collections" );
3915+
3916+ // Test 2: Filter by top-level field - item
3917+ Query itemFilterQuery =
3918+ Query .builder ()
3919+ .setFilter (
3920+ RelationalExpression .of (
3921+ IdentifierExpression .of ("item" ), EQ , ConstantExpression .of ("Soap" )))
3922+ .build ();
3923+
3924+ long nestedSoapCount = nestedCollection .count (itemFilterQuery );
3925+ long flatSoapCount = flatCollection .count (itemFilterQuery );
3926+ assertEquals (nestedSoapCount , flatSoapCount , "Soap count should be equal in both collections" );
3927+
3928+ // Test 3: Filter by numeric field - price
3929+ Query priceFilterQuery =
3930+ Query .builder ()
3931+ .setFilter (
3932+ RelationalExpression .of (
3933+ IdentifierExpression .of ("price" ), GT , ConstantExpression .of (10 )))
3934+ .build ();
3935+
3936+ long nestedPriceCount = nestedCollection .count (priceFilterQuery );
3937+ long flatPriceCount = flatCollection .count (priceFilterQuery );
3938+ assertEquals (
3939+ nestedPriceCount , flatPriceCount , "Price > 10 count should be equal in both collections" );
3940+
3941+ // Test 4: Compare actual document content for same filter
3942+ CloseableIterator <Document > nestedIterator = nestedCollection .find (itemFilterQuery );
3943+ CloseableIterator <Document > flatIterator = flatCollection .find (itemFilterQuery );
3944+
3945+ // Collect documents from both collections
3946+ java .util .List <String > nestedDocs = new java .util .ArrayList <>();
3947+ java .util .List <String > flatDocs = new java .util .ArrayList <>();
3948+
3949+ while (nestedIterator .hasNext ()) {
3950+ nestedDocs .add (nestedIterator .next ().toJson ());
3951+ }
3952+ nestedIterator .close ();
3953+
3954+ while (flatIterator .hasNext ()) {
3955+ flatDocs .add (flatIterator .next ().toJson ());
3956+ }
3957+ flatIterator .close ();
3958+
3959+ // Both should return the same number of documents
3960+ assertEquals (
3961+ nestedDocs .size (),
3962+ flatDocs .size (),
3963+ "Both collections should return same number of documents" );
3964+
3965+ // Test 5: Verify document structure consistency
3966+ if (!nestedDocs .isEmpty () && !flatDocs .isEmpty ()) {
3967+ // Parse and compare first document from each collection
3968+ ObjectMapper mapper = new ObjectMapper ();
3969+ JsonNode nestedDoc = mapper .readTree (nestedDocs .get (0 ));
3970+ JsonNode flatDoc = mapper .readTree (flatDocs .get (0 ));
3971+
3972+ // Verify both have the same top-level fields
3973+ assertTrue (nestedDoc .has ("item" ) && flatDoc .has ("item" ), "Both should have 'item' field" );
3974+ assertTrue (nestedDoc .has ("price" ) && flatDoc .has ("price" ), "Both should have 'price' field" );
3975+ assertTrue (
3976+ nestedDoc .has ("quantity" ) && flatDoc .has ("quantity" ),
3977+ "Both should have 'quantity' field" );
3978+ assertTrue (nestedDoc .has ("date" ) && flatDoc .has ("date" ), "Both should have 'date' field" );
3979+
3980+ // Verify the values are the same for basic fields
3981+ assertEquals (
3982+ nestedDoc .get ("item" ).asText (), flatDoc .get ("item" ).asText (), "Item values should match" );
3983+ assertEquals (
3984+ nestedDoc .get ("price" ).asInt (),
3985+ flatDoc .get ("price" ).asInt (),
3986+ "Price values should match" );
3987+ assertEquals (
3988+ nestedDoc .get ("quantity" ).asInt (),
3989+ flatDoc .get ("quantity" ).asInt (),
3990+ "Quantity values should match" );
3991+ }
3992+
3993+ // Test 6: Test with different filter - quantity
3994+ Query quantityFilterQuery =
3995+ Query .builder ()
3996+ .setFilter (
3997+ RelationalExpression .of (
3998+ IdentifierExpression .of ("quantity" ), EQ , ConstantExpression .of (10 )))
3999+ .build ();
4000+
4001+ long nestedQuantityCount = nestedCollection .count (quantityFilterQuery );
4002+ long flatQuantityCount = flatCollection .count (quantityFilterQuery );
4003+ assertEquals (
4004+ nestedQuantityCount ,
4005+ flatQuantityCount ,
4006+ "Quantity = 10 count should be equal in both collections" );
4007+
4008+ // Test 7: Verify DocumentType is different
4009+ CloseableIterator <Document > nestedDocIterator = nestedCollection .find (Query .builder ().build ());
4010+ CloseableIterator <Document > flatDocIterator = flatCollection .find (Query .builder ().build ());
4011+
4012+ if (nestedDocIterator .hasNext () && flatDocIterator .hasNext ()) {
4013+ Document nestedDocument = nestedDocIterator .next ();
4014+ Document flatDocument = flatDocIterator .next ();
4015+
4016+ assertEquals (
4017+ DocumentType .NESTED ,
4018+ nestedDocument .getDocumentType (),
4019+ "Nested collection should return NESTED documents" );
4020+ assertEquals (
4021+ DocumentType .FLAT ,
4022+ flatDocument .getDocumentType (),
4023+ "Flat collection should return FLAT documents" );
4024+ }
4025+
4026+ nestedDocIterator .close ();
4027+ flatDocIterator .close ();
4028+ }
38974029}
0 commit comments