@@ -1704,6 +1704,115 @@ void testBulkCreateOrReplaceIgnoreDocumentStrategy() throws Exception {
17041704 assertEquals (200 , rs .getInt ("price" ));
17051705 });
17061706 }
1707+
1708+ @ Test
1709+ @ DisplayName ("Should bulk createOrReplace and return older documents with JSONB and arrays" )
1710+ void testBulkCreateOrReplaceReturnOlderDocuments () throws Exception {
1711+ String docId1 = "bulk-replace-return-1" ;
1712+ String docId2 = "bulk-replace-return-2" ;
1713+
1714+ String initial1Json = readFileFromResource (
1715+ "create/bulk_replace_initial_doc1.json" ).orElseThrow ();
1716+ String initial2Json = readFileFromResource (
1717+ "create/bulk_replace_initial_doc2.json" ).orElseThrow ();
1718+ String updated1Json = readFileFromResource (
1719+ "create/bulk_replace_updated_doc1.json" ).orElseThrow ();
1720+ String updated2Json = readFileFromResource (
1721+ "create/bulk_replace_updated_doc2.json" ).orElseThrow ();
1722+
1723+ flatCollection .createOrReplace (
1724+ new SingleValueKey (DEFAULT_TENANT , docId1 ), new JSONDocument (initial1Json ));
1725+ flatCollection .createOrReplace (
1726+ new SingleValueKey (DEFAULT_TENANT , docId2 ), new JSONDocument (initial2Json ));
1727+
1728+ Map <Key , Document > bulkMap = new LinkedHashMap <>();
1729+ bulkMap .put (new SingleValueKey (DEFAULT_TENANT , docId1 ), new JSONDocument (updated1Json ));
1730+ bulkMap .put (new SingleValueKey (DEFAULT_TENANT , docId2 ), new JSONDocument (updated2Json ));
1731+
1732+ // Get older documents before replacement
1733+ CloseableIterator <Document > olderDocs =
1734+ flatCollection .bulkCreateOrReplaceReturnOlderDocuments (bulkMap );
1735+
1736+ // Collect older documents
1737+ Map <String , JsonNode > olderDocsMap = new HashMap <>();
1738+ while (olderDocs .hasNext ()) {
1739+ Document doc = olderDocs .next ();
1740+ JsonNode json = OBJECT_MAPPER .readTree (doc .toJson ());
1741+ olderDocsMap .put (json .get ("id" ).asText (), json );
1742+ }
1743+ olderDocs .close ();
1744+
1745+ // Verify we got the older documents with original values including JSONB and arrays
1746+ String key1 = new SingleValueKey (DEFAULT_TENANT , docId1 ).toString ();
1747+ String key2 = new SingleValueKey (DEFAULT_TENANT , docId2 ).toString ();
1748+ assertEquals (2 , olderDocsMap .size ());
1749+ assertTrue (olderDocsMap .containsKey (key1 ));
1750+ assertTrue (olderDocsMap .containsKey (key2 ));
1751+
1752+ // Verify doc1 original values
1753+ JsonNode expectedDoc1 = OBJECT_MAPPER .readTree (initial1Json );
1754+ JsonNode oldDoc1 = olderDocsMap .get (key1 );
1755+ assertEquals (expectedDoc1 , oldDoc1 );
1756+
1757+ // Verify doc2 original values
1758+ JsonNode expectedDoc2 = OBJECT_MAPPER .readTree (initial2Json );
1759+ JsonNode oldDoc2 = olderDocsMap .get (key2 );
1760+ assertEquals (expectedDoc2 , oldDoc2 );
1761+
1762+ // Verify the documents were actually replaced with new values
1763+ String expectedResult1Json = readFileFromResource (
1764+ "expected/bulk_replace_result_doc1.json" ).orElseThrow ();
1765+ String expectedResult2Json = readFileFromResource (
1766+ "expected/bulk_replace_result_doc2.json" ).orElseThrow ();
1767+
1768+ Query query1 = Query .builder ()
1769+ .setFilter (
1770+ RelationalExpression .of (
1771+ IdentifierExpression .of ("id" ),
1772+ RelationalOperator .EQ ,
1773+ ConstantExpression .of (new SingleValueKey (DEFAULT_TENANT , docId1 ).toString ())))
1774+ .build ();
1775+ try (CloseableIterator <Document > iter = flatCollection .find (query1 )) {
1776+ assertTrue (iter .hasNext ());
1777+ JsonNode actualDoc1 = OBJECT_MAPPER .readTree (iter .next ().toJson ());
1778+ JsonNode expectedResultDoc1 = OBJECT_MAPPER .readTree (expectedResult1Json );
1779+ assertEquals (expectedResultDoc1 , actualDoc1 );
1780+ }
1781+
1782+ Query query2 = Query .builder ()
1783+ .setFilter (
1784+ RelationalExpression .of (
1785+ IdentifierExpression .of ("id" ),
1786+ RelationalOperator .EQ ,
1787+ ConstantExpression .of (new SingleValueKey (DEFAULT_TENANT , docId2 ).toString ())))
1788+ .build ();
1789+ try (CloseableIterator <Document > iter = flatCollection .find (query2 )) {
1790+ assertTrue (iter .hasNext ());
1791+ JsonNode actualDoc2 = OBJECT_MAPPER .readTree (iter .next ().toJson ());
1792+ JsonNode expectedResultDoc2 = OBJECT_MAPPER .readTree (expectedResult2Json );
1793+ assertEquals (expectedResultDoc2 , actualDoc2 );
1794+ }
1795+ }
1796+
1797+ @ Test
1798+ @ DisplayName (
1799+ "Should return empty iterator for empty map in bulkCreateOrReplaceReturnOlderDocuments" )
1800+ void testBulkCreateOrReplaceReturnOlderDocumentsEmptyMap () throws Exception {
1801+ CloseableIterator <Document > result =
1802+ flatCollection .bulkCreateOrReplaceReturnOlderDocuments (Collections .emptyMap ());
1803+ assertFalse (result .hasNext ());
1804+ result .close ();
1805+ }
1806+
1807+ @ Test
1808+ @ DisplayName (
1809+ "Should return empty iterator for null map in bulkCreateOrReplaceReturnOlderDocuments" )
1810+ void testBulkCreateOrReplaceReturnOlderDocumentsNullMap () throws Exception {
1811+ CloseableIterator <Document > result =
1812+ flatCollection .bulkCreateOrReplaceReturnOlderDocuments (null );
1813+ assertFalse (result .hasNext ());
1814+ result .close ();
1815+ }
17071816 }
17081817
17091818 @ Nested
@@ -2128,15 +2237,15 @@ void testSetAllFieldTypes() throws Exception {
21282237 SubDocumentUpdate .of ("rating" , 4.5f ),
21292238 SubDocumentUpdate .of ("weight" , 123.456 ),
21302239 // Case 2: Top-level arrays
2131- SubDocumentUpdate .of ("tags" , new String [] {"tag4" , "tag5" , "tag6" }),
2132- SubDocumentUpdate .of ("numbers" , new Integer [] {10 , 20 , 30 }),
2133- SubDocumentUpdate .of ("scores" , new Double [] {1.1 , 2.2 , 3.3 }),
2134- SubDocumentUpdate .of ("flags" , new Boolean [] {true , false , true }),
2240+ SubDocumentUpdate .of ("tags" , new String []{"tag4" , "tag5" , "tag6" }),
2241+ SubDocumentUpdate .of ("numbers" , new Integer []{10 , 20 , 30 }),
2242+ SubDocumentUpdate .of ("scores" , new Double []{1.1 , 2.2 , 3.3 }),
2243+ SubDocumentUpdate .of ("flags" , new Boolean []{true , false , true }),
21352244 // Case 3 & 4: One nested path in JSONB (props) - tests nested primitive
21362245 SubDocumentUpdate .of ("props.brand" , "NewBrand" ),
21372246 // Use 'sales' JSONB column for nested array test
21382247 SubDocumentUpdate .of (
2139- "sales.regions" , SubDocumentValue .of (new String [] {"US" , "EU" , "APAC" })));
2248+ "sales.regions" , SubDocumentValue .of (new String []{"US" , "EU" , "APAC" })));
21402249
21412250 UpdateOptions options =
21422251 UpdateOptions .builder ().returnDocumentType (ReturnDocumentType .AFTER_UPDATE ).build ();
@@ -2346,7 +2455,7 @@ void testSetMultipleNestedPathsInSameJsonbColumn() throws Exception {
23462455 SubDocumentUpdate .of ("props.size" , "XL" ),
23472456 SubDocumentUpdate .of ("props.newField" , "newValue" ),
23482457 SubDocumentUpdate .of (
2349- "props.owners" , SubDocumentValue .of (new String [] {"owner1" , "owner2" })));
2458+ "props.owners" , SubDocumentValue .of (new String []{"owner1" , "owner2" })));
23502459
23512460 UpdateOptions options =
23522461 UpdateOptions .builder ().returnDocumentType (ReturnDocumentType .AFTER_UPDATE ).build ();
@@ -2652,7 +2761,7 @@ void testAddArrayValue() {
26522761 SubDocumentUpdate .builder ()
26532762 .subDocument ("price" )
26542763 .operator (UpdateOperator .ADD )
2655- .subDocumentValue (SubDocumentValue .of (new Integer [] {1 , 2 , 3 }))
2764+ .subDocumentValue (SubDocumentValue .of (new Integer []{1 , 2 , 3 }))
26562765 .build ());
26572766
26582767 UpdateOptions options =
@@ -2699,19 +2808,19 @@ void testAppendToListAllCases() throws Exception {
26992808 SubDocumentUpdate .builder ()
27002809 .subDocument ("tags" )
27012810 .operator (UpdateOperator .APPEND_TO_LIST )
2702- .subDocumentValue (SubDocumentValue .of (new String [] {"newTag1" , "newTag2" }))
2811+ .subDocumentValue (SubDocumentValue .of (new String []{"newTag1" , "newTag2" }))
27032812 .build (),
27042813 // Nested JSONB array: append to existing props.colors
27052814 SubDocumentUpdate .builder ()
27062815 .subDocument ("props.colors" )
27072816 .operator (UpdateOperator .APPEND_TO_LIST )
2708- .subDocumentValue (SubDocumentValue .of (new String [] {"green" , "yellow" }))
2817+ .subDocumentValue (SubDocumentValue .of (new String []{"green" , "yellow" }))
27092818 .build (),
27102819 // Nested JSONB: append to non-existent array (creates it)
27112820 SubDocumentUpdate .builder ()
27122821 .subDocument ("sales.regions" )
27132822 .operator (UpdateOperator .APPEND_TO_LIST )
2714- .subDocumentValue (SubDocumentValue .of (new String [] {"US" , "EU" }))
2823+ .subDocumentValue (SubDocumentValue .of (new String []{"US" , "EU" }))
27152824 .build ());
27162825
27172826 UpdateOptions options =
@@ -2790,13 +2899,13 @@ void testAddToListIfAbsentAllCases() throws Exception {
27902899 SubDocumentUpdate .builder ()
27912900 .subDocument ("tags" )
27922901 .operator (UpdateOperator .ADD_TO_LIST_IF_ABSENT )
2793- .subDocumentValue (SubDocumentValue .of (new String [] {"existing1" , "newTag" }))
2902+ .subDocumentValue (SubDocumentValue .of (new String []{"existing1" , "newTag" }))
27942903 .build (),
27952904 // Nested JSONB: 'red' exists, 'green' is new → adds only 'green'
27962905 SubDocumentUpdate .builder ()
27972906 .subDocument ("props.colors" )
27982907 .operator (UpdateOperator .ADD_TO_LIST_IF_ABSENT )
2799- .subDocumentValue (SubDocumentValue .of (new String [] {"red" , "green" }))
2908+ .subDocumentValue (SubDocumentValue .of (new String []{"red" , "green" }))
28002909 .build ());
28012910
28022911 UpdateOptions options =
@@ -2867,13 +2976,13 @@ void testRemoveAllFromListAllCases() throws Exception {
28672976 SubDocumentUpdate .builder ()
28682977 .subDocument ("tags" )
28692978 .operator (UpdateOperator .REMOVE_ALL_FROM_LIST )
2870- .subDocumentValue (SubDocumentValue .of (new String [] {"tag1" }))
2979+ .subDocumentValue (SubDocumentValue .of (new String []{"tag1" }))
28712980 .build (),
28722981 // Nested JSONB: remove 'red' and 'blue' → leaves green
28732982 SubDocumentUpdate .builder ()
28742983 .subDocument ("props.colors" )
28752984 .operator (UpdateOperator .REMOVE_ALL_FROM_LIST )
2876- .subDocumentValue (SubDocumentValue .of (new String [] {"red" , "blue" }))
2985+ .subDocumentValue (SubDocumentValue .of (new String []{"red" , "blue" }))
28772986 .build ());
28782987
28792988 UpdateOptions options =
0 commit comments