From 17ae601b215fbbaba28bbddc3d0d1ce37e0d8907 Mon Sep 17 00:00:00 2001 From: Thisaru Guruge Date: Wed, 24 Apr 2024 15:02:41 +0530 Subject: [PATCH 1/3] [Automated] Update the toml files --- ballerina/Ballerina.toml | 6 +++--- ballerina/Dependencies.toml | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml index 43f0a37..40ce376 100644 --- a/ballerina/Ballerina.toml +++ b/ballerina/Ballerina.toml @@ -2,7 +2,7 @@ distribution = "2201.7.0" org = "ballerinax" name = "mongodb" -version = "5.0.0" +version = "5.0.1" license= ["Apache-2.0"] authors = ["Ballerina"] keywords = ["IT Operations/Databases", "Cost/Freemium"] @@ -15,8 +15,8 @@ graalvmCompatible = true [[platform.java17.dependency]] groupId = "io.ballerina.lib" artifactId = "mongodb-native" -version = "5.0.0" -path = "../native/build/libs/mongodb-native-5.0.0.jar" +version = "5.0.1-SNAPSHOT" +path = "../native/build/libs/mongodb-native-5.0.1-SNAPSHOT.jar" [[platform.java17.dependency]] groupId = "org.mongodb" diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index 52be793..f4ac2a1 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -10,7 +10,7 @@ distribution-version = "2201.8.6" [[package]] org = "ballerina" name = "crypto" -version = "2.5.0" +version = "2.6.2" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "time"} @@ -27,6 +27,9 @@ dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} ] +modules = [ + {org = "ballerina", packageName = "io", moduleName = "io"} +] [[package]] org = "ballerina" @@ -99,9 +102,10 @@ dependencies = [ [[package]] org = "ballerinax" name = "mongodb" -version = "5.0.0" +version = "5.0.1" dependencies = [ {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "log"}, {org = "ballerina", name = "test"} From f1a25d98bf0dcc1578d3d0747b9f0fa183c56f45 Mon Sep 17 00:00:00 2001 From: Thisaru Guruge Date: Wed, 24 Apr 2024 15:03:12 +0530 Subject: [PATCH 2/3] Fix find and aggregation not allowing to return arrays --- ballerina/Dependencies.toml | 33 ++++++++++- ballerina/build.gradle | 32 +++++----- ballerina/collection.bal | 10 ++-- ballerina/tests/03_collection_tests.bal | 77 +++++++++++++++++++++---- ballerina/tests/types.bal | 11 ++++ 5 files changed, 131 insertions(+), 32 deletions(-) diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index f4ac2a1..fe2c975 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -5,12 +5,12 @@ [ballerina] dependencies-toml-version = "2" -distribution-version = "2201.8.6" +distribution-version = "2201.9.0-20240410-095500-2653a74d" [[package]] org = "ballerina" name = "crypto" -version = "2.6.2" +version = "2.7.0" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "time"} @@ -39,6 +39,26 @@ modules = [ {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"} ] +[[package]] +org = "ballerina" +name = "lang.__internal" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.array" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"} +] + [[package]] org = "ballerina" name = "lang.error" @@ -48,6 +68,12 @@ dependencies = [ {org = "ballerina", name = "jballerina.java"} ] +[[package]] +org = "ballerina" +name = "lang.object" +version = "0.0.0" +scope = "testOnly" + [[package]] org = "ballerina" name = "lang.value" @@ -73,7 +99,7 @@ modules = [ [[package]] org = "ballerina" name = "observe" -version = "1.2.2" +version = "1.2.3" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -85,6 +111,7 @@ version = "0.0.0" scope = "testOnly" dependencies = [ {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.array"}, {org = "ballerina", name = "lang.error"} ] modules = [ diff --git a/ballerina/build.gradle b/ballerina/build.gradle index d7841cd..792442a 100644 --- a/ballerina/build.gradle +++ b/ballerina/build.gradle @@ -91,13 +91,15 @@ task commitTomlFiles { } task startMongodbServer() { - doLast { - println("Starting mongodb server...") - exec { - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - commandLine 'cmd', '/c', "docker-compose -f tests/resources/docker/docker-compose.yml up && exit %%ERRORLEVEL%%" - } else { - commandLine 'sh', '-c', "docker-compose -f tests/resources/docker/docker-compose.yml up -d" + gradle.taskGraph.whenReady { graph -> + if (graph.hasTask(":${packageName}-ballerina:test")) { + println("Starting mongodb server...") + exec { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + commandLine 'cmd', '/c', "docker-compose -f tests/resources/docker/docker-compose.yml up && exit %%ERRORLEVEL%%" + } else { + commandLine 'sh', '-c', "docker-compose -f tests/resources/docker/docker-compose.yml up -d" + } } } } @@ -105,12 +107,16 @@ task startMongodbServer() { task stopMongodbServer() { doLast { - println("Stopping mongodb server...") - exec { - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - commandLine 'cmd', '/c', "docker-compose -f tests/resources/docker/docker-compose.yml down && exit %%ERRORLEVEL%%" - } else { - commandLine 'sh', '-c', "docker-compose -f tests/resources/docker/docker-compose.yml down" + gradle.taskGraph.whenReady { graph -> + if (graph.hasTask(":${packageName}-ballerina:test")) { + println("Stopping mongodb server...") + exec { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + commandLine 'cmd', '/c', "docker-compose -f tests/resources/docker/docker-compose.yml down && exit %%ERRORLEVEL%%" + } else { + commandLine 'sh', '-c', "docker-compose -f tests/resources/docker/docker-compose.yml down" + } + } } } } diff --git a/ballerina/collection.bal b/ballerina/collection.bal index 7198cc7..c1e8e0b 100644 --- a/ballerina/collection.bal +++ b/ballerina/collection.bal @@ -51,7 +51,8 @@ public isolated client class Collection { # + documents - The documents to insert # + options - The options to apply to the operation # + return - An error if the operation failed, otherwise nil - isolated remote function insertMany(record {|anydata...;|}[] documents, InsertManyOptions options = {}) returns Error? { + isolated remote function insertMany(record {|anydata...;|}[] documents, InsertManyOptions options = {}) + returns Error? { string[] documentString = documents.'map((doc) => doc.toJsonString()); return check insertMany(self, documentString, options); } @@ -67,7 +68,8 @@ public isolated client class Collection { # + targetType - The type of the returned documents # + return - A stream of documents which match the provided filter, or an error if the operation failed isolated remote function find(map filter = {}, FindOptions findOptions = {}, map? projection = (), - typedesc targetType = <>) returns stream|Error = @java:Method { + typedesc targetType = <>) + returns stream|Error = @java:Method { 'class: "io.ballerina.lib.mongodb.Collection" } external; @@ -80,7 +82,7 @@ public isolated client class Collection { # + targetType - The type of the returned document # + return - The document which matches the provided filter, or an error if the operation failed isolated remote function findOne(map filter = {}, FindOptions findOptions = {}, map? projection = (), - typedesc targetType = <>) returns targetType|Error? = @java:Method { + typedesc targetType = <>) returns targetType|Error? = @java:Method { 'class: "io.ballerina.lib.mongodb.Collection" } external; @@ -196,7 +198,7 @@ public isolated client class Collection { # + pipeline - The aggregation pipeline # + targetType - The type of the returned documents # + return - A stream of documents which match the provided pipeline, or an error if the operation failed - isolated remote function aggregate(map[] pipeline, typedesc targetType = <>) + isolated remote function aggregate(map[] pipeline, typedesc targetType = <>) returns stream|Error = @java:Method { 'class: "io.ballerina.lib.mongodb.Collection" } external; diff --git a/ballerina/tests/03_collection_tests.bal b/ballerina/tests/03_collection_tests.bal index 91b4b74..b771abf 100644 --- a/ballerina/tests/03_collection_tests.bal +++ b/ballerina/tests/03_collection_tests.bal @@ -47,7 +47,7 @@ isolated function testInsertAndFind() returns error? { } @test:Config { - groups: ["collection", "insert", "insertOne", "find", "projection", "test"] + groups: ["collection", "insert", "insertOne", "find", "projection"] } isolated function testFindOne() returns error? { Database database = check mongoClient->getDatabase("testFindOneDB"); @@ -361,20 +361,21 @@ isolated function testUpdateUnset() returns error? { updateResult = check collection->updateOne({name: "Walter White"}, {"unset": {"address.country": ""}}); test:assertEquals(updateResult.matchedCount, 1); test:assertEquals(updateResult.modifiedCount, 1); - result = check collection->find({name: "Walter White"}); + stream findResult = check collection->find({name: "Walter White"}); - // Trapping the type conversion error and checking for the relevant error message. - // This is to confirm the field is removed from the document. - record {Person value;}|error? movieResult = trap result.next(); - if movieResult !is error { - test:assertFail("Expected an error"); + record {|anydata...;|}? movieResult = check findResult.next(); + if movieResult is () { + test:assertFail("Expected a record value from the stream"); } - var detail = movieResult.detail(); - if detail !is anydata { - test:assertFail("Expected anydata type for error detail"); + if movieResult.hasKey("address") { + var address = movieResult["address"]; + if address !is map { + test:assertFail("Expected a map value for the `address` field"); + } + if address.hasKey("country") { + test:assertFail("Expected the `country` field to be removed from the `address` field"); + } } - string message = detail["message"].toString(); - test:assertTrue(message.includes("missing required field 'address.country' of type 'string'")); check result.close(); check collection->drop(); check database->drop(); @@ -619,6 +620,58 @@ isolated function testComplexFind() returns error? { check database->drop(); } +@test:Config { + groups: ["collection", "aggregate", "sort"] +} +isolated function testFindReturningArray() returns error? { + Database database = check mongoClient->getDatabase("testFindReturningArrayDB"); + Collection tvShowsCollection = check database->getCollection("TvShows"); + Collection directorsCollection = check database->getCollection("Directors"); + + TvShow tvShow1 = {title: "Breaking Bad", year: 2008, directorId: "1"}; + TvShow tvShow2 = {title: "Game of Thrones", year: 2011, directorId: "2"}; + TvShow tvShow3 = {title: "The Walking Dead", year: 2010, directorId: "3"}; + TvShow tvShow4 = {title: "Better Call Saul", year: 2015, directorId: "1"}; + check tvShowsCollection->insertMany([tvShow1, tvShow2, tvShow3, tvShow4]); + + Director director1 = {id: "1", name: "Vince Gilligan"}; + Director director2 = {id: "2", name: "David Benioff"}; + Director director3 = {id: "3", name: "Frank Darabont"}; + check directorsCollection->insertMany([director1, director2, director3]); + + stream result = check tvShowsCollection->aggregate([ + { + \$group: { + _id: {directorId: "$directorId"}, + tvShows: { + \$push: { + title: "$title", + year: "$year", + directorId: "$directorId" + } + } + } + }, + { + \$sort: { + "tvShows.directorId": 1 + } + } + ]); + TvShow[][] actualResult = check from record { + TvShow[] tvShows; + } item in result + select item.tvShows; + TvShow[][] expectedResult = [[tvShow1, tvShow4], [tvShow2], [tvShow3]]; + check result.close(); + check tvShowsCollection->drop(); + check directorsCollection->drop(); + check database->drop(); + test:assertEquals(actualResult, expectedResult); +} + @test:Config { groups: ["collection", "insert", "aggregate", "projection"] } diff --git a/ballerina/tests/types.bal b/ballerina/tests/types.bal index 89274a2..3d96434 100644 --- a/ballerina/tests/types.bal +++ b/ballerina/tests/types.bal @@ -47,3 +47,14 @@ type Author readonly & record {| string name; Book[] books; |}; + +type TvShow record {| + string title; + int year; + string directorId; +|}; + +type Director record {| + string id; + string name; +|}; From 751a72cb5dd34ec69673f2c764301872ac560a10 Mon Sep 17 00:00:00 2001 From: Thisaru Guruge Date: Wed, 24 Apr 2024 15:08:50 +0530 Subject: [PATCH 3/3] Update the changelog --- changelog.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelog.md b/changelog.md index 495f4fd..e5a4e74 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,5 @@ # Change Log + This file contains all the notable changes done to the Ballerina GraphQL package through the releases. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to @@ -6,6 +7,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Added + +- [[#6377] Allow Returning Arrays from `find` and `aggregate` Operations](https://github.com/ballerina-platform/ballerina-standard-library/issues/6377) + +## [5.0.0] - 2024-04-02 + ### Changed - [[#5073] Revamping the connector with new Client, Database, and Collection model](https://github.com/ballerina-platform/ballerina-standard-library/issues/5073)