From d4ed488022505525c1ceb8c392b39711d133735c Mon Sep 17 00:00:00 2001 From: Suresh Prakash Date: Fri, 24 Nov 2023 19:25:29 +0530 Subject: [PATCH] Fix the Postgres issue with the removal of an element from a singleton list --- .../documentstore/DocStoreQueryV1Test.java | 53 +++- ...m_string_array_with_singleton_element.json | 219 +++++++++++++++++ ...t_string_array_with_singleton_element.json | 228 ++++++++++++++++++ .../PostgresRemoveAllFromListParser.java | 2 +- 4 files changed, 497 insertions(+), 5 deletions(-) create mode 100644 document-store/src/integrationTest/resources/query/update_operator/updated_remove_from_string_array_with_singleton_element.json create mode 100644 document-store/src/integrationTest/resources/query/update_operator/updated_set_string_array_with_singleton_element.json diff --git a/document-store/src/integrationTest/java/org/hypertrace/core/documentstore/DocStoreQueryV1Test.java b/document-store/src/integrationTest/java/org/hypertrace/core/documentstore/DocStoreQueryV1Test.java index 9f677ab5..d87f04cf 100644 --- a/document-store/src/integrationTest/java/org/hypertrace/core/documentstore/DocStoreQueryV1Test.java +++ b/document-store/src/integrationTest/java/org/hypertrace/core/documentstore/DocStoreQueryV1Test.java @@ -2639,7 +2639,53 @@ void testUpdateWithAllOperatorsOnObject(final String datastoreName) throws IOExc @ParameterizedTest @ArgumentsSource(AllProvider.class) - void testRemoveAllOccurrancesFromIntegerList(final String datastoreName) throws IOException { + void testRemoveFromSingletonList(final String datastoreName) throws IOException { + final Collection collection = getCollection(datastoreName, UPDATABLE_COLLECTION_NAME); + createCollectionData("query/updatable_collection_data.json", UPDATABLE_COLLECTION_NAME); + + final SubDocumentUpdate set = + SubDocumentUpdate.builder() + .subDocument("props.added.habitable_planets") + .operator(SET) + .subDocumentValue(SubDocumentValue.of(new String[] {"Earth"})) + .build(); + + final Query query = Query.builder().build(); + final List updates = List.of(set); + + final CloseableIterator iterator = + collection.bulkUpdate( + query, updates, UpdateOptions.builder().returnDocumentType(AFTER_UPDATE).build()); + + assertDocsAndSizeEqualWithoutOrder( + datastoreName, + iterator, + "query/update_operator/updated_set_string_array_with_singleton_element.json", + 9); + + final SubDocumentUpdate remove = + SubDocumentUpdate.builder() + .subDocument("props.added.habitable_planets") + .operator(REMOVE_ALL_FROM_LIST) + .subDocumentValue(SubDocumentValue.of(new String[] {"Earth"})) + .build(); + + final List newUpdates = List.of(remove); + + final CloseableIterator newIterator = + collection.bulkUpdate( + query, newUpdates, UpdateOptions.builder().returnDocumentType(AFTER_UPDATE).build()); + + assertDocsAndSizeEqualWithoutOrder( + datastoreName, + newIterator, + "query/update_operator/updated_remove_from_string_array_with_singleton_element.json", + 9); + } + + @ParameterizedTest + @ArgumentsSource(AllProvider.class) + void testRemoveAllOccurrencesFromIntegerList(final String datastoreName) throws IOException { final Collection collection = getCollection(datastoreName, UPDATABLE_COLLECTION_NAME); createCollectionData("query/updatable_collection_data.json", UPDATABLE_COLLECTION_NAME); @@ -2655,9 +2701,8 @@ void testRemoveAllOccurrancesFromIntegerList(final String datastoreName) throws final Query query = Query.builder().build(); final List updates = List.of(set, unset); - final CloseableIterator iterator = - collection.bulkUpdate( - query, updates, UpdateOptions.builder().returnDocumentType(NONE).build()); + collection.bulkUpdate( + query, updates, UpdateOptions.builder().returnDocumentType(NONE).build()); final SubDocumentUpdate remove = SubDocumentUpdate.builder() diff --git a/document-store/src/integrationTest/resources/query/update_operator/updated_remove_from_string_array_with_singleton_element.json b/document-store/src/integrationTest/resources/query/update_operator/updated_remove_from_string_array_with_singleton_element.json new file mode 100644 index 00000000..01878a71 --- /dev/null +++ b/document-store/src/integrationTest/resources/query/update_operator/updated_remove_from_string_array_with_singleton_element.json @@ -0,0 +1,219 @@ +[ + { + "item": "Soap", + "price": 10, + "quantity": 2, + "date": "2014-03-01T08:00:00Z", + "props": { + "brand": "Dettol", + "size": "M", + "seller": { + "name": "Metro Chemicals Pvt. Ltd.", + "address": { + "city": "Mumbai", + "pincode": 400004 + } + }, + "added": { + "habitable_planets": [ + ] + } + }, + "sales": [ + { + "city": "delhi", + "medium": [ + { + "type": "distributionChannel", + "volume": 1000 + }, + { + "type": "retail", + "volume": 500 + }, + { + "type": "online", + "volume": 1000 + } + ] + }, + { + "city": "pune", + "medium": [ + { + "type": "distributionChannel", + "volume": 300 + }, + { + "type": "online", + "volume": 2000 + } + ] + } + ] + }, + { + "item": "Mirror", + "price": 20, + "quantity": 1, + "date": "2014-03-01T09:00:00Z", + "sales": [ + { + "city": "delhi", + "medium": [] + } + ], + "props": { + "added": { + "habitable_planets": [ + ] + } + } + }, + { + "item": "Shampoo", + "price": 5, + "quantity": 10, + "date": "2014-03-15T09:00:00Z", + "props": { + "brand": "Sunsilk", + "size": "L", + "seller": { + "name": "Metro Chemicals Pvt. Ltd.", + "address": { + "city": "Mumbai", + "pincode": 400004 + } + }, + "added": { + "habitable_planets": [ + ] + } + }, + "sales": [ + { + "city": "delhi", + "medium": [ + { + "type": "distributionChannel", + "volume": 3000 + }, + { + "type": "retail", + "volume": 500 + }, + { + "type": "online", + "volume": 1000 + } + ] + }, + { + "city": "mumbai", + "medium": [ + { + "type": "distributionChannel", + "volume": 700 + }, + { + "type": "retail", + "volume": 500 + }, + { + "type": "online", + "volume": 5000 + } + ] + } + ] + }, + { + "item": "Shampoo", + "price": 5, + "quantity": 20, + "date": "2014-04-04T11:21:39.736Z", + "sales": [], + "props": { + "added": { + "habitable_planets": [ + ] + } + } + }, + { + "item": "Soap", + "price": 20, + "quantity": 5, + "date": "2014-04-04T21:23:13.331Z", + "props": { + "brand": "Lifebuoy", + "size": "S", + "seller": { + "name": "Hans and Co.", + "address": { + "city": "Kolkata", + "pincode": 700007 + } + }, + "added": { + "habitable_planets": [ + ] + } + } + }, + { + "item": "Comb", + "price": 7.5, + "quantity": 5, + "date": "2015-06-04T05:08:13Z", + "props": { + "added": { + "habitable_planets": [ + ] + } + } + }, + { + "item": "Comb", + "price": 7.5, + "quantity": 10, + "date": "2015-09-10T08:43:00Z", + "props": { + "seller": { + "name": "Go Go Plastics", + "address": { + "city": "Kolkata", + "pincode": 700007 + } + }, + "added": { + "habitable_planets": [ + ] + } + } + }, + { + "item": "Soap", + "price": 10, + "quantity": 5, + "date": "2016-02-06T20:20:13Z", + "props": { + "added": { + "habitable_planets": [ + ] + } + } + }, + { + "item": "Soap", + "price": 88, + "quantity": 50, + "date": "2023-08-09T18:53:17Z", + "props": { + "added": { + "habitable_planets": [ + ] + } + } + } +] diff --git a/document-store/src/integrationTest/resources/query/update_operator/updated_set_string_array_with_singleton_element.json b/document-store/src/integrationTest/resources/query/update_operator/updated_set_string_array_with_singleton_element.json new file mode 100644 index 00000000..bb5b81a5 --- /dev/null +++ b/document-store/src/integrationTest/resources/query/update_operator/updated_set_string_array_with_singleton_element.json @@ -0,0 +1,228 @@ +[ + { + "item": "Soap", + "price": 10, + "quantity": 2, + "date": "2014-03-01T08:00:00Z", + "props": { + "brand": "Dettol", + "size": "M", + "seller": { + "name": "Metro Chemicals Pvt. Ltd.", + "address": { + "city": "Mumbai", + "pincode": 400004 + } + }, + "added": { + "habitable_planets": [ + "Earth" + ] + } + }, + "sales": [ + { + "city": "delhi", + "medium": [ + { + "type": "distributionChannel", + "volume": 1000 + }, + { + "type": "retail", + "volume": 500 + }, + { + "type": "online", + "volume": 1000 + } + ] + }, + { + "city": "pune", + "medium": [ + { + "type": "distributionChannel", + "volume": 300 + }, + { + "type": "online", + "volume": 2000 + } + ] + } + ] + }, + { + "item": "Mirror", + "price": 20, + "quantity": 1, + "date": "2014-03-01T09:00:00Z", + "sales": [ + { + "city": "delhi", + "medium": [] + } + ], + "props": { + "added": { + "habitable_planets": [ + "Earth" + ] + } + } + }, + { + "item": "Shampoo", + "price": 5, + "quantity": 10, + "date": "2014-03-15T09:00:00Z", + "props": { + "brand": "Sunsilk", + "size": "L", + "seller": { + "name": "Metro Chemicals Pvt. Ltd.", + "address": { + "city": "Mumbai", + "pincode": 400004 + } + }, + "added": { + "habitable_planets": [ + "Earth" + ] + } + }, + "sales": [ + { + "city": "delhi", + "medium": [ + { + "type": "distributionChannel", + "volume": 3000 + }, + { + "type": "retail", + "volume": 500 + }, + { + "type": "online", + "volume": 1000 + } + ] + }, + { + "city": "mumbai", + "medium": [ + { + "type": "distributionChannel", + "volume": 700 + }, + { + "type": "retail", + "volume": 500 + }, + { + "type": "online", + "volume": 5000 + } + ] + } + ] + }, + { + "item": "Shampoo", + "price": 5, + "quantity": 20, + "date": "2014-04-04T11:21:39.736Z", + "sales": [], + "props": { + "added": { + "habitable_planets": [ + "Earth" + ] + } + } + }, + { + "item": "Soap", + "price": 20, + "quantity": 5, + "date": "2014-04-04T21:23:13.331Z", + "props": { + "brand": "Lifebuoy", + "size": "S", + "seller": { + "name": "Hans and Co.", + "address": { + "city": "Kolkata", + "pincode": 700007 + } + }, + "added": { + "habitable_planets": [ + "Earth" + ] + } + } + }, + { + "item": "Comb", + "price": 7.5, + "quantity": 5, + "date": "2015-06-04T05:08:13Z", + "props": { + "added": { + "habitable_planets": [ + "Earth" + ] + } + } + }, + { + "item": "Comb", + "price": 7.5, + "quantity": 10, + "date": "2015-09-10T08:43:00Z", + "props": { + "seller": { + "name": "Go Go Plastics", + "address": { + "city": "Kolkata", + "pincode": 700007 + } + }, + "added": { + "habitable_planets": [ + "Earth" + ] + } + } + }, + { + "item": "Soap", + "price": 10, + "quantity": 5, + "date": "2016-02-06T20:20:13Z", + "props": { + "added": { + "habitable_planets": [ + "Earth" + ] + } + } + }, + { + "item": "Soap", + "price": 88, + "quantity": 50, + "date": "2023-08-09T18:53:17Z", + "props": { + "added": { + "habitable_planets": [ + "Earth" + ] + } + } + } +] diff --git a/document-store/src/main/java/org/hypertrace/core/documentstore/postgres/update/parser/PostgresRemoveAllFromListParser.java b/document-store/src/main/java/org/hypertrace/core/documentstore/postgres/update/parser/PostgresRemoveAllFromListParser.java index 0e839166..a618c29d 100644 --- a/document-store/src/main/java/org/hypertrace/core/documentstore/postgres/update/parser/PostgresRemoveAllFromListParser.java +++ b/document-store/src/main/java/org/hypertrace/core/documentstore/postgres/update/parser/PostgresRemoveAllFromListParser.java @@ -69,7 +69,7 @@ public String parseLeaf(final UpdateParserInput input) { IntStream.range(0, values.length).mapToObj(i -> type.parsed()).collect(joining(", ")); return String.format( "jsonb_set(%s, ?::text[], " - + "(SELECT jsonb_agg(value) " + + "(SELECT COALESCE (jsonb_agg(value), '[]'::jsonb) " + "FROM jsonb_array_elements(%s) t(value) " + "WHERE value NOT IN (%s)))", baseField, fieldAccess, filter);