├── .github ├── CODEOWNERS ├── pull_request_template.md └── workflows │ ├── build-with-bal-test-graalvm.yml │ ├── ci.yml │ ├── daily-build.yml │ ├── dev-stg-release.yml │ ├── pull-request.yml │ ├── release.yml │ └── trivy-scan.yml ├── .gitignore ├── .trivyignore ├── LICENSE ├── README.md ├── ballerina ├── Ballerina.toml ├── Dependencies.toml ├── Module.md ├── Package.md ├── build.gradle ├── client.bal ├── collection.bal ├── database.bal ├── errors.bal ├── icon.png ├── init.bal ├── result_iterator.bal ├── tests │ ├── 01_client_tests.bal │ ├── 02_database_tests.bal │ ├── 03_collection_tests.bal │ ├── mock_functions.bal │ ├── resources │ │ └── docker │ │ │ ├── certs │ │ │ ├── mongodb-CA.pem │ │ │ ├── mongodb-client.jks │ │ │ ├── mongodb-client.pem │ │ │ └── mongodb-server.pem │ │ │ ├── docker-compose.yml │ │ │ └── init-scripts │ │ │ ├── no-ssl.js │ │ │ └── ssl.js │ ├── types.bal │ └── utils.bal └── types.bal ├── build-config ├── checkstyle │ └── build.gradle ├── resources │ └── Ballerina.toml └── spotbugs-exclude.xml ├── build.gradle ├── changelog.md ├── codecov.yml ├── docs ├── setup │ └── resources │ │ ├── mongodb-atlas-connection-method.png │ │ ├── mongodb-atlas-database-page.png │ │ └── mongodb-atlas-ip-access-list.png └── spec │ └── spec.md ├── examples ├── README.md ├── build.gradle ├── build.sh ├── movie-database │ ├── .github │ │ └── README.md │ ├── Ballerina MongoDB movie database.md │ ├── Ballerina.toml │ └── server.bal ├── order-management-system │ ├── .github │ │ └── README.md │ ├── Ballerina MongoDB order management system.md │ ├── Ballerina.toml │ └── server.bal └── resources │ └── docker │ └── docker-compose.yml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── native ├── build.gradle └── src │ └── main │ └── java │ ├── io │ └── ballerina │ │ └── lib │ │ └── mongodb │ │ ├── AuthUtils.java │ │ ├── Client.java │ │ ├── Collection.java │ │ ├── Database.java │ │ ├── ErrorType.java │ │ ├── IteratorUtils.java │ │ ├── ModuleUtils.java │ │ ├── SslUtils.java │ │ └── Utils.java │ └── module-info.java ├── pull_request_template.md └── settings.gradle /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # See: https://help.github.com/articles/about-codeowners/ 5 | 6 | # These owners will be the default owners for everything in the repo. 7 | * @ThisaruGuruge 8 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | Fixes: 4 | 5 | ## Examples 6 | 7 | ## Checklist 8 | - [ ] Linked to an issue 9 | - [ ] Updated the changelog 10 | - [ ] Added tests 11 | - [ ] Updated the spec 12 | - [ ] Checked native-image compatibility 13 | -------------------------------------------------------------------------------- /.github/workflows/build-with-bal-test-graalvm.yml: -------------------------------------------------------------------------------- 1 | name: GraalVM Check 2 | 3 | on: 4 | schedule: 5 | - cron: "30 18 * * *" 6 | workflow_dispatch: 7 | pull_request: 8 | types: [ opened, synchronize, labeled ] 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'Skip GraalVM Check') 18 | 19 | steps: 20 | - name: Checkout the Repository 21 | uses: actions/checkout@v3 22 | 23 | - name: Set Up Ballerina 24 | uses: ballerina-platform/setup-ballerina@v1.1.3 25 | with: 26 | version: nightly 27 | 28 | - name: Set up GraalVM 29 | uses: graalvm/setup-graalvm@v1 30 | with: 31 | java-version: "21" 32 | distribution: "graalvm-community" 33 | set-java-home: true 34 | github-token: ${{ secrets.GITHUB_TOKEN }} 35 | 36 | - name: Check GraalVM installation 37 | run: | 38 | echo "GRAALVM_HOME: ${{ env.GRAALVM_HOME }}" 39 | echo "JAVA_HOME: ${{ env.JAVA_HOME }}" 40 | native-image --version 41 | 42 | - name: Set ENV Variables 43 | run: | 44 | echo -e '${{ toJson(secrets) }}' | jq -r 'to_entries[] | .key + "=" + .value' >> $GITHUB_ENV 45 | 46 | - name: Build Package 47 | run: ./gradlew build -x test 48 | env: 49 | packageUser: ${{ github.actor }} 50 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 51 | 52 | - name: Remove Target Directory 53 | run: sudo rm -rf ballerina/target 54 | 55 | - name: Test with GraalVM 56 | run: | 57 | ./gradlew :mongodb-ballerina:startMongodbServer 58 | cd ballerina 59 | bal test --graalvm 60 | cd .. 61 | ./gradlew :mongodb-ballerina:stopMongodbServer 62 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - 2201.[0-9]+.x 8 | repository_dispatch: 9 | types: check_connector_for_breaking_changes 10 | 11 | jobs: 12 | call_workflow: 13 | name: Run Connector Build Workflow 14 | if: ${{ github.repository_owner == 'ballerina-platform' }} 15 | uses: ballerina-platform/ballerina-library/.github/workflows/build-connector-template.yml@main 16 | secrets: inherit 17 | with: 18 | repo-name: module-ballerinax-mongodb 19 | -------------------------------------------------------------------------------- /.github/workflows/daily-build.yml: -------------------------------------------------------------------------------- 1 | name: Daily build 2 | 3 | on: 4 | schedule: 5 | - cron: "30 2 * * *" 6 | 7 | jobs: 8 | call_workflow: 9 | name: Run Daily Build Workflow 10 | if: ${{ github.repository_owner == 'ballerina-platform' }} 11 | uses: ballerina-platform/ballerina-library/.github/workflows/daily-build-connector-template.yml@main 12 | secrets: inherit 13 | with: 14 | repo-name: module-ballerinax-mongodb 15 | -------------------------------------------------------------------------------- /.github/workflows/dev-stg-release.yml: -------------------------------------------------------------------------------- 1 | name: Publish to the Ballerina Dev\Stage Central 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | environment: 7 | type: choice 8 | description: Select Environment 9 | required: true 10 | options: 11 | - DEV CENTRAL 12 | - STAGE CENTRAL 13 | 14 | jobs: 15 | call_workflow: 16 | name: Run Dev\Stage Central Publish Workflow 17 | if: ${{ github.repository_owner == 'ballerina-platform' }} 18 | uses: ballerina-platform/ballerina-library/.github/workflows/dev-stage-central-publish-connector-template.yml@main 19 | secrets: inherit 20 | with: 21 | environment: ${{ github.event.inputs.environment }} 22 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yml: -------------------------------------------------------------------------------- 1 | name: PR Build 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} 5 | cancel-in-progress: true 6 | 7 | on: pull_request 8 | 9 | jobs: 10 | call_workflow: 11 | name: Run PR Build Workflow 12 | if: ${{ github.repository_owner == 'ballerina-platform' }} 13 | uses: ballerina-platform/ballerina-library/.github/workflows/pr-build-connector-template.yml@main 14 | secrets: inherit 15 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Publish Release 2 | 3 | on: 4 | workflow_dispatch: 5 | repository_dispatch: 6 | types: [ connector-release-pipeline ] 7 | 8 | jobs: 9 | call_workflow: 10 | name: Run Release Workflow 11 | if: ${{ github.repository_owner == 'ballerina-platform' }} 12 | uses: ballerina-platform/ballerina-library/.github/workflows/release-package-connector-template.yml@main 13 | secrets: inherit 14 | with: 15 | package-name: mongodb 16 | package-org: ballerinax 17 | -------------------------------------------------------------------------------- /.github/workflows/trivy-scan.yml: -------------------------------------------------------------------------------- 1 | name: Trivy 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | ubuntu-build: 8 | name: Build on Ubuntu 9 | runs-on: ubuntu-latest 10 | if: github.repository_owner == 'ballerina-platform' 11 | steps: 12 | - uses: actions/checkout@v3 13 | - name: Set up JDK 21 14 | uses: actions/setup-java@v3 15 | with: 16 | distribution: "temurin" 17 | java-version: 21.0.3 18 | 19 | - name: Build with Gradle 20 | env: 21 | packageUser: ${{ github.actor }} 22 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 23 | run: ./gradlew build -x check -x test 24 | 25 | - name: Create lib directory if not exists 26 | run: mkdir -p ballerina/lib 27 | 28 | - name: Run Trivy vulnerability scanner 29 | uses: aquasecurity/trivy-action@master 30 | with: 31 | scan-type: "rootfs" 32 | scan-ref: "/github/workspace/ballerina/lib" 33 | format: "table" 34 | timeout: "10m0s" 35 | exit-code: "1" 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | !gradle-wrapper/*.jar 16 | *.war 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | *.deb 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | 26 | # mac 27 | .DS_Store 28 | 29 | .classpath 30 | .project 31 | .settings 32 | .vscode 33 | 34 | target 35 | .idea 36 | *.iml 37 | *.ipr 38 | *.iws 39 | .gradle 40 | build 41 | 42 | # Environment files 43 | *.env 44 | Config.toml 45 | examples/**/Dependencies.toml 46 | -------------------------------------------------------------------------------- /.trivyignore: -------------------------------------------------------------------------------- 1 | # False Positive 2 | CVE-2021-32050 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ballerina MongoDB Connector 2 | 3 | [![Build Status](https://github.com/ballerina-platform/module-ballerinax-mongodb/workflows/CI/badge.svg)](https://github.com/ballerina-platform/module-ballerinax-mongodb/actions?query=workflow%3ACI) 4 | [![Trivy](https://github.com/ballerina-platform/module-ballerinax-mongodb/actions/workflows/trivy-scan.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerinax-mongodb/actions/workflows/trivy-scan.yml) 5 | [![codecov](https://codecov.io/gh/ballerina-platform/module-ballerinax-mongodb/branch/master/graph/badge.svg)](https://codecov.io/gh/ballerina-platform/module-ballerinax-mongodb) 6 | [![GitHub Last Commit](https://img.shields.io/github/last-commit/ballerina-platform/module-ballerinax-mongodb.svg)](https://github.com/ballerina-platform/module-ballerinax-mongodb/commits/master) 7 | [![GraalVM Check](https://github.com/ballerina-platform/module-ballerinax-mongodb/actions/workflows/build-with-bal-test-graalvm.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerinax-mongodb/actions/workflows/build-with-bal-test-graalvm.yml) 8 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 9 | 10 | ## Overview 11 | 12 | [MongoDB](https://docs.mongodb.com/v4.2/) is a general purpose, document-based, distributed database built for modern application developers and for the cloud era. MongoDB offers both a Community and an Enterprise version of the database. 13 | 14 | The `ballerinax/mongodb` package offers APIs to connect to MongoDB servers and to perform various operations including CRUD operations, indexing, and aggregation. 15 | 16 | The Ballerina MongoDB connector is compatible with MongoDB 3.6 and later versions. 17 | 18 | ## Setup guide 19 | 20 | To use the MongoDB connector, you need to have a MongoDB server running and accessible. For that, you can either install MongoDB locally or use the [MongoDB Atlas](https://www.mongodb.com/cloud/atlas/register), the cloud offering of the MongoDB. 21 | 22 | ### Setup a MongoDB server locally 23 | 24 | 1. Download and install the MongoDB server from the [MongoDB download center](https://www.mongodb.com/try/download/community). 25 | 26 | 2. Follow the installation instructions provided in the download center. 27 | 28 | 3. Follow the [instructions](https://www.mongodb.com/docs/manual/administration/install-community/#std-label-install-mdb-community-edition) for each operating system to start the MongoDB server. 29 | 30 | > **Note:** This guide uses the MongoDB community edition for the setup. Alternatively, the enterprise edition can also be used. 31 | 32 | ### Setup a MongoDB server using MongoDB Atlas 33 | 34 | 1. Sign up for a free account in [MongoDB Atlas](https://www.mongodb.com/cloud/atlas/register). 35 | 36 | 2. Follow the instructions provided in the [MongoDB Atlas documentation](https://docs.atlas.mongodb.com/getting-started/) to create a new cluster. 37 | 38 | 3. Navigate to your MongoDB Atlas cluster. 39 | 40 | 4. Select "Database" from the left navigation pane under the "Deployment" section and click "connect" button to open connection instructions. 41 | 42 | ![MongoDB Atlas Connect](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/master/docs/setup/resources/mongodb-atlas-database-page.png) 43 | 44 | 5. Add your IP address to the IP access list or select "Allow access from anywhere" to allow all IP addresses to access the cluster. 45 | 46 | ![MongoDB Atlas IP Access List](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/master/docs/setup/resources/mongodb-atlas-ip-access-list.png) 47 | 48 | 6. Click "Choose a connection method" and select "Drivers" under the "Connect your application". There you can find the connection string to connect to the MongoDB Atlas cluster. 49 | 50 | ![MongoDB Atlas Connection Method](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/master/docs/setup/resources/mongodb-atlas-connection-method.png) 51 | 52 | ## Quickstart 53 | 54 | ### Step 1: Import the module 55 | 56 | Import the `mongodb` module into the Ballerina project. 57 | 58 | ```ballerina 59 | import ballerinax/mongodb; 60 | ``` 61 | 62 | ### Step 2: Initialize the MongoDB client 63 | 64 | #### Initialize the MongoDB client using the connection parameters 65 | 66 | ```ballerina 67 | mongodb:Client mongoDb = check new ({ 68 | connection: { 69 | serverAddress: { 70 | host: "localhost", 71 | port: 27017 72 | }, 73 | auth: { 74 | username: , 75 | password: , 76 | database: 77 | } 78 | } 79 | }); 80 | ``` 81 | 82 | #### Initialize the MongoDB client using the connection string 83 | 84 | ```ballerina 85 | mongodb:Client mongoDb = check new ({ 86 | connection: 87 | }); 88 | ``` 89 | 90 | ### Step 3: Invoke the connector operation 91 | 92 | Now, you can use the available connector operations to interact with MongoDB server. 93 | 94 | #### Retrieve a Database 95 | 96 | ```ballerina 97 | mongodb:Database moviesDb = check mongoDb->getDatabase("movies"); 98 | ``` 99 | 100 | #### Retrieve a Collection 101 | 102 | ```ballerina 103 | mongodb:Collection moviesCollection = check moviesDb->getCollection("movies"); 104 | ``` 105 | 106 | #### Insert a Document 107 | 108 | ```ballerina 109 | Movie movie = {title: "Inception", year: 2010}; 110 | check moviesCollection->insert(movie); 111 | ``` 112 | 113 | ### Step 4: Run the Ballerina application 114 | 115 | Save the changes and run the Ballerina application using the following command. 116 | 117 | ```bash 118 | bal run 119 | ``` 120 | 121 | ## Examples 122 | 123 | The MongoDB connector provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/) covering common MongoDB operations. 124 | 125 | 1. [Movie database](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/movie-database) - Implement a movie database using MongoDB. 126 | 2. [Order management system](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/order-management-system) - Implement an order management system using MongoDB. 127 | 128 | ## Issues and projects 129 | 130 | The **Issues** and **Projects** tabs are disabled for this repository as this is part of the Ballerina library. To report bugs, request new features, start new discussions, view project boards, etc., visit the Ballerina library [parent repository](https://github.com/ballerina-platform/ballerina-library). 131 | 132 | ## Building from the source 133 | 134 | ### Setting up the prerequisites 135 | 136 | 1. Download and install Java SE Development Kit (JDK) version 21. You can download it from either of the following sources: 137 | 138 | * [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) 139 | * [OpenJDK](https://adoptium.net/) 140 | 141 | > **Note:** After installation, remember to set the `JAVA_HOME` environment variable to the directory where JDK was installed. 142 | 143 | 2. Download and install [Ballerina Swan Lake](https://ballerina.io/). 144 | 145 | 3. Download and install [Docker](https://www.docker.com/get-started). 146 | 147 | > **Note**: Ensure that the Docker daemon is running before executing any tests. 148 | 149 | 4. Export Github Personal access token with read package permissions as follows, 150 | 151 | ```bash 152 | export packageUser= 153 | export packagePAT= 154 | ``` 155 | 156 | ### Building the source 157 | 158 | Execute the commands below to build from the source. 159 | 160 | 1. To build the package: 161 | 162 | ```bash 163 | ./gradlew clean build 164 | ``` 165 | 166 | 2. To run the tests: 167 | 168 | ```bash 169 | ./gradlew clean test 170 | ``` 171 | 172 | 3. To build the without the tests: 173 | 174 | ```bash 175 | ./gradlew clean build -x test 176 | ``` 177 | 178 | 4. To run selected test groups: 179 | 180 | ```bash 181 | ./gradlew clean test -P groups= 182 | ``` 183 | 184 | 5. To debug package with a remote debugger: 185 | 186 | ```bash 187 | ./gradlew clean build -P debug= 188 | ``` 189 | 190 | 6. To debug with the Ballerina language: 191 | 192 | ```bash 193 | ./gradlew clean build -P balJavaDebug= 194 | ``` 195 | 196 | 7. Publish the generated artifacts to the local Ballerina Central repository: 197 | 198 | ```bash 199 | ./gradlew clean build -P publishToLocalCentral=true 200 | ``` 201 | 202 | ## Contribute to Ballerina 203 | 204 | As an open-source project, Ballerina welcomes contributions from the community. 205 | 206 | For more information, go to the [contribution guidelines](https://github.com/ballerina-platform/ballerina-lang/blob/master/CONTRIBUTING.md). 207 | 208 | ## Code of conduct 209 | 210 | All the contributors are encouraged to read the [Ballerina Code of Conduct](https://ballerina.io/code-of-conduct). 211 | 212 | ## Useful links 213 | 214 | * For more information go to the [`mongodb` package](https://lib.ballerina.io/ballerinax/mongodb/latest). 215 | * For example demonstrations of the usage, go to [Ballerina By Examples](https://ballerina.io/learn/by-example/). 216 | * Chat live with us via our [Discord server](https://discord.gg/ballerinalang). 217 | * Post all technical questions on Stack Overflow with the [#ballerina](https://stackoverflow.com/questions/tagged/ballerina) tag. 218 | -------------------------------------------------------------------------------- /ballerina/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | distribution = "2201.11.0-20241218-101200-109f6cc7" 3 | org = "ballerinax" 4 | name = "mongodb" 5 | version = "5.1.1" 6 | license= ["Apache-2.0"] 7 | authors = ["Ballerina"] 8 | keywords = ["IT Operations/Databases", "Cost/Freemium"] 9 | icon = "icon.png" 10 | repository = "https://github.com/ballerina-platform/module-ballerinax-mongodb" 11 | 12 | [platform.java21] 13 | graalvmCompatible = true 14 | 15 | [[platform.java21.dependency]] 16 | groupId = "io.ballerina.lib" 17 | artifactId = "mongodb-native" 18 | version = "5.1.1-SNAPSHOT" 19 | path = "../native/build/libs/mongodb-native-5.1.1-SNAPSHOT.jar" 20 | 21 | [[platform.java21.dependency]] 22 | groupId = "org.mongodb" 23 | artifactId = "mongodb-driver-sync" 24 | version = "5.1.0" 25 | path = "./lib/mongodb-driver-sync-5.1.0.jar" 26 | 27 | [[platform.java21.dependency]] 28 | groupId = "org.mongodb" 29 | artifactId = "mongodb-driver-core" 30 | version = "5.1.0" 31 | path = "./lib/mongodb-driver-core-5.1.0.jar" 32 | 33 | [[platform.java21.dependency]] 34 | groupId = "org.mongodb" 35 | artifactId = "bson" 36 | version = "5.1.0" 37 | path = "./lib/bson-5.1.0.jar" 38 | -------------------------------------------------------------------------------- /ballerina/Dependencies.toml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED FILE. DO NOT MODIFY. 2 | 3 | # This file is auto-generated by Ballerina for managing dependency versions. 4 | # It should not be modified by hand. 5 | 6 | [ballerina] 7 | dependencies-toml-version = "2" 8 | distribution-version = "2201.12.2" 9 | 10 | [[package]] 11 | org = "ballerina" 12 | name = "crypto" 13 | version = "2.9.0" 14 | dependencies = [ 15 | {org = "ballerina", name = "jballerina.java"}, 16 | {org = "ballerina", name = "time"} 17 | ] 18 | modules = [ 19 | {org = "ballerina", packageName = "crypto", moduleName = "crypto"} 20 | ] 21 | 22 | [[package]] 23 | org = "ballerina" 24 | name = "io" 25 | version = "1.8.0" 26 | dependencies = [ 27 | {org = "ballerina", name = "jballerina.java"}, 28 | {org = "ballerina", name = "lang.value"} 29 | ] 30 | 31 | [[package]] 32 | org = "ballerina" 33 | name = "jballerina.java" 34 | version = "0.0.0" 35 | modules = [ 36 | {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"} 37 | ] 38 | 39 | [[package]] 40 | org = "ballerina" 41 | name = "lang.__internal" 42 | version = "0.0.0" 43 | scope = "testOnly" 44 | dependencies = [ 45 | {org = "ballerina", name = "jballerina.java"}, 46 | {org = "ballerina", name = "lang.object"} 47 | ] 48 | 49 | [[package]] 50 | org = "ballerina" 51 | name = "lang.array" 52 | version = "0.0.0" 53 | scope = "testOnly" 54 | dependencies = [ 55 | {org = "ballerina", name = "jballerina.java"}, 56 | {org = "ballerina", name = "lang.__internal"} 57 | ] 58 | 59 | [[package]] 60 | org = "ballerina" 61 | name = "lang.error" 62 | version = "0.0.0" 63 | scope = "testOnly" 64 | dependencies = [ 65 | {org = "ballerina", name = "jballerina.java"} 66 | ] 67 | 68 | [[package]] 69 | org = "ballerina" 70 | name = "lang.object" 71 | version = "0.0.0" 72 | scope = "testOnly" 73 | 74 | [[package]] 75 | org = "ballerina" 76 | name = "lang.value" 77 | version = "0.0.0" 78 | dependencies = [ 79 | {org = "ballerina", name = "jballerina.java"} 80 | ] 81 | 82 | [[package]] 83 | org = "ballerina" 84 | name = "log" 85 | version = "2.12.0" 86 | dependencies = [ 87 | {org = "ballerina", name = "io"}, 88 | {org = "ballerina", name = "jballerina.java"}, 89 | {org = "ballerina", name = "lang.value"}, 90 | {org = "ballerina", name = "observe"} 91 | ] 92 | modules = [ 93 | {org = "ballerina", packageName = "log", moduleName = "log"} 94 | ] 95 | 96 | [[package]] 97 | org = "ballerina" 98 | name = "observe" 99 | version = "1.5.0" 100 | dependencies = [ 101 | {org = "ballerina", name = "jballerina.java"} 102 | ] 103 | 104 | [[package]] 105 | org = "ballerina" 106 | name = "test" 107 | version = "0.0.0" 108 | scope = "testOnly" 109 | dependencies = [ 110 | {org = "ballerina", name = "jballerina.java"}, 111 | {org = "ballerina", name = "lang.array"}, 112 | {org = "ballerina", name = "lang.error"} 113 | ] 114 | modules = [ 115 | {org = "ballerina", packageName = "test", moduleName = "test"} 116 | ] 117 | 118 | [[package]] 119 | org = "ballerina" 120 | name = "time" 121 | version = "2.7.0" 122 | dependencies = [ 123 | {org = "ballerina", name = "jballerina.java"} 124 | ] 125 | 126 | [[package]] 127 | org = "ballerinax" 128 | name = "mongodb" 129 | version = "5.1.1" 130 | dependencies = [ 131 | {org = "ballerina", name = "crypto"}, 132 | {org = "ballerina", name = "jballerina.java"}, 133 | {org = "ballerina", name = "log"}, 134 | {org = "ballerina", name = "test"} 135 | ] 136 | modules = [ 137 | {org = "ballerinax", packageName = "mongodb", moduleName = "mongodb"} 138 | ] 139 | 140 | -------------------------------------------------------------------------------- /ballerina/Module.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | [MongoDB](https://docs.mongodb.com/v4.2/) is a general purpose, document-based, distributed database built for modern application developers and for the cloud era. MongoDB offers both a Community and an Enterprise version of the database. 4 | 5 | The `ballerinax/mongodb` package offers APIs to connect to MongoDB servers and to perform various operations including CRUD operations, indexing, and aggregation. 6 | 7 | The Ballerina MongoDB connector is compatible with MongoDB 3.6 and later versions. 8 | 9 | ## Setup guide 10 | 11 | To use the MongoDB connector, you need to have a MongoDB server running and accessible. For that, you can either install MongoDB locally or use the [MongoDB Atlas](https://www.mongodb.com/cloud/atlas/register), the cloud offering of the MongoDB. 12 | 13 | ### Setup a MongoDB server locally 14 | 15 | 1. Download and install the MongoDB server from the [MongoDB download center](https://www.mongodb.com/try/download/community). 16 | 17 | 2. Follow the installation instructions provided in the download center. 18 | 19 | 3. Follow the [instructions](https://www.mongodb.com/docs/manual/administration/install-community/#std-label-install-mdb-community-edition) for each operating system to start the MongoDB server. 20 | 21 | > **Note:** This guide uses the MongoDB community edition for the setup. Alternatively, the enterprise edition can also be used. 22 | 23 | ### Setup a MongoDB server using MongoDB Atlas 24 | 25 | 1. Sign up for a free account in [MongoDB Atlas](https://www.mongodb.com/cloud/atlas/register). 26 | 27 | 2. Follow the instructions provided in the [MongoDB Atlas documentation](https://docs.atlas.mongodb.com/getting-started/) to create a new cluster. 28 | 29 | 3. Navigate to your MongoDB Atlas cluster. 30 | 31 | 4. Select "Database" from the left navigation pane under the "Deployment" section and click "connect" button to open connection instructions. 32 | 33 | ![MongoDB Atlas Connect](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/master/docs/setup/resources/mongodb-atlas-database-page.png) 34 | 35 | 5. Add your IP address to the IP access list or select "Allow access from anywhere" to allow all IP addresses to access the cluster. 36 | 37 | ![MongoDB Atlas IP Access List](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/master/docs/setup/resources/mongodb-atlas-ip-access-list.png) 38 | 39 | 6. Click "Choose a connection method" and select "Drivers" under the "Connect your application". There you can find the connection string to connect to the MongoDB Atlas cluster. 40 | 41 | ![MongoDB Atlas Connection Method](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/master/docs/setup/resources/mongodb-atlas-connection-method.png) 42 | 43 | ## Quickstart 44 | 45 | ### Step 1: Import the module 46 | 47 | Import the `mongodb` module into the Ballerina project. 48 | 49 | ```ballerina 50 | import ballerinax/mongodb; 51 | ``` 52 | 53 | ### Step 2: Initialize the MongoDB client 54 | 55 | #### Initialize the MongoDB client using the connection parameters 56 | 57 | ```ballerina 58 | mongodb:Client mongoDb = check new ({ 59 | connection: { 60 | serverAddress: { 61 | host: "localhost", 62 | port: 27017 63 | }, 64 | auth: { 65 | username: , 66 | password: , 67 | database: 68 | } 69 | } 70 | }); 71 | ``` 72 | 73 | #### Initialize the MongoDB client using the connection string 74 | 75 | ```ballerina 76 | mongodb:Client mongoDb = check new ({ 77 | connection: 78 | }); 79 | ``` 80 | 81 | ### Step 3: Invoke the connector operation 82 | 83 | Now, you can use the available connector operations to interact with MongoDB server. 84 | 85 | #### Retrieve a Database 86 | 87 | ```ballerina 88 | mongodb:Database moviesDb = check mongoDb->getDatabase("movies"); 89 | ``` 90 | 91 | #### Retrieve a Collection 92 | 93 | ```ballerina 94 | mongodb:Collection moviesCollection = check moviesDb->getCollection("movies"); 95 | ``` 96 | 97 | #### Insert a Document 98 | 99 | ```ballerina 100 | Movie movie = {title: "Inception", year: 2010}; 101 | check moviesCollection->insert(movie); 102 | ``` 103 | 104 | ### Step 4: Run the Ballerina application 105 | 106 | Save the changes and run the Ballerina application using the following command. 107 | 108 | ```bash 109 | bal run 110 | ``` 111 | 112 | ## Examples 113 | 114 | The MongoDB connector provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/) covering common MongoDB operations. 115 | 116 | 1. [Movie database](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/movie-database) - Implement a movie database using MongoDB. 117 | 2. [Order management system](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/order-management-system) - Implement an order management system using MongoDB. 118 | -------------------------------------------------------------------------------- /ballerina/Package.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | [MongoDB](https://docs.mongodb.com/v4.2/) is a general purpose, document-based, distributed database built for modern application developers and for the cloud era. MongoDB offers both a Community and an Enterprise version of the database. 4 | 5 | The `ballerinax/mongodb` package offers APIs to connect to MongoDB servers and to perform various operations including CRUD operations, indexing, and aggregation. 6 | 7 | The Ballerina MongoDB connector is compatible with MongoDB 3.6 and later versions. 8 | 9 | ## Setup guide 10 | 11 | To use the MongoDB connector, you need to have a MongoDB server running and accessible. For that, you can either install MongoDB locally or use the [MongoDB Atlas](https://www.mongodb.com/cloud/atlas/register), the cloud offering of the MongoDB. 12 | 13 | ### Setup a MongoDB server locally 14 | 15 | 1. Download and install the MongoDB server from the [MongoDB download center](https://www.mongodb.com/try/download/community). 16 | 17 | 2. Follow the installation instructions provided in the download center. 18 | 19 | 3. Follow the [instructions](https://www.mongodb.com/docs/manual/administration/install-community/#std-label-install-mdb-community-edition) for each operating system to start the MongoDB server. 20 | 21 | > **Note:** This guide uses the MongoDB community edition for the setup. Alternatively, the enterprise edition can also be used. 22 | 23 | ### Setup a MongoDB server using MongoDB Atlas 24 | 25 | 1. Sign up for a free account in [MongoDB Atlas](https://www.mongodb.com/cloud/atlas/register). 26 | 27 | 2. Follow the instructions provided in the [MongoDB Atlas documentation](https://docs.atlas.mongodb.com/getting-started/) to create a new cluster. 28 | 29 | 3. Navigate to your MongoDB Atlas cluster. 30 | 31 | 4. Select "Database" from the left navigation pane under the "Deployment" section and click "connect" button to open connection instructions. 32 | 33 | ![MongoDB Atlas Connect](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/master/docs/setup/resources/mongodb-atlas-database-page.png) 34 | 35 | 5. Add your IP address to the IP access list or select "Allow access from anywhere" to allow all IP addresses to access the cluster. 36 | 37 | ![MongoDB Atlas IP Access List](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/master/docs/setup/resources/mongodb-atlas-ip-access-list.png) 38 | 39 | 6. Click "Choose a connection method" and select "Drivers" under the "Connect your application". There you can find the connection string to connect to the MongoDB Atlas cluster. 40 | 41 | ![MongoDB Atlas Connection Method](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/master/docs/setup/resources/mongodb-atlas-connection-method.png) 42 | 43 | ## Quickstart 44 | 45 | ### Step 1: Import the module 46 | 47 | Import the `mongodb` module into the Ballerina project. 48 | 49 | ```ballerina 50 | import ballerinax/mongodb; 51 | ``` 52 | 53 | ### Step 2: Initialize the MongoDB client 54 | 55 | #### Initialize the MongoDB client using the connection parameters 56 | 57 | ```ballerina 58 | mongodb:Client mongoDb = check new ({ 59 | connection: { 60 | serverAddress: { 61 | host: "localhost", 62 | port: 27017 63 | }, 64 | auth: { 65 | username: , 66 | password: , 67 | database: 68 | } 69 | } 70 | }); 71 | ``` 72 | 73 | #### Initialize the MongoDB client using the connection string 74 | 75 | ```ballerina 76 | mongodb:Client mongoDb = check new ({ 77 | connection: 78 | }); 79 | ``` 80 | 81 | ### Step 3: Invoke the connector operation 82 | 83 | Now, you can use the available connector operations to interact with MongoDB server. 84 | 85 | #### Retrieve a Database 86 | 87 | ```ballerina 88 | mongodb:Database moviesDb = check mongoDb->getDatabase("movies"); 89 | ``` 90 | 91 | #### Retrieve a Collection 92 | 93 | ```ballerina 94 | mongodb:Collection moviesCollection = check moviesDb->getCollection("movies"); 95 | ``` 96 | 97 | #### Insert a Document 98 | 99 | ```ballerina 100 | Movie movie = {title: "Inception", year: 2010}; 101 | check moviesCollection->insert(movie); 102 | ``` 103 | 104 | ### Step 4: Run the Ballerina application 105 | 106 | Save the changes and run the Ballerina application using the following command. 107 | 108 | ```bash 109 | bal run 110 | ``` 111 | 112 | ## Examples 113 | 114 | The MongoDB connector provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/) covering common MongoDB operations. 115 | 116 | 1. [Movie database](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/movie-database) - Implement a movie database using MongoDB. 117 | 2. [Order management system](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/order-management-system) - Implement an order management system using MongoDB. 118 | -------------------------------------------------------------------------------- /ballerina/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import org.apache.tools.ant.taskdefs.condition.Os 20 | 21 | plugins { 22 | id 'io.ballerina.plugin' 23 | } 24 | 25 | description = 'Ballerina - Mongodb Ballerina Connector' 26 | 27 | def packageName = "mongodb" 28 | def packageOrg = "ballerinax" 29 | def tomlVersion = stripBallerinaExtensionVersion("${project.version}") 30 | def ballerinaTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/Ballerina.toml") 31 | def ballerinaTomlFile = new File("$project.projectDir/Ballerina.toml") 32 | 33 | def stripBallerinaExtensionVersion(String extVersion) { 34 | if (extVersion.matches(project.ext.timestampedVersionRegex)) { 35 | def splitVersion = extVersion.split('-') 36 | if (splitVersion.length > 3) { 37 | def strippedValues = splitVersion[0..-4] 38 | return strippedValues.join('-') 39 | } else { 40 | return extVersion 41 | } 42 | } else { 43 | return extVersion.replace("${project.ext.snapshotVersion}", "") 44 | } 45 | } 46 | 47 | ballerina { 48 | packageOrganization = packageOrg 49 | module = packageName 50 | testCoverageParam = "--code-coverage --coverage-format=xml" 51 | isConnector = true 52 | platform = "java21" 53 | } 54 | 55 | configurations { 56 | externalJars 57 | } 58 | 59 | dependencies { 60 | externalJars(group: 'org.mongodb', name: 'mongodb-driver-sync', version: "${mongoDriverVersion}") { 61 | transitive = false 62 | } 63 | externalJars(group: 'org.mongodb', name: 'mongodb-driver-core', version: "${mongoDriverVersion}") { 64 | transitive = false 65 | } 66 | externalJars(group: 'org.mongodb', name: 'bson', version: "${mongoDriverVersion}") { 67 | transitive = false 68 | } 69 | } 70 | 71 | task updateTomlFiles { 72 | doLast { 73 | def newBallerinaToml = ballerinaTomlFilePlaceHolder.text.replace("@project.version@", project.version) 74 | newBallerinaToml = newBallerinaToml.replace("@toml.version@", tomlVersion) 75 | newBallerinaToml = newBallerinaToml.replace("@mongodb.driver.version@", mongoDriverVersion) 76 | ballerinaTomlFile.text = newBallerinaToml 77 | } 78 | } 79 | 80 | task commitTomlFiles { 81 | doLast { 82 | project.exec { 83 | ignoreExitValue true 84 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 85 | commandLine 'cmd', '/c', "git commit -m \"[Automated] Update the toml files\" Ballerina.toml Dependencies.toml" 86 | } else { 87 | commandLine 'sh', '-c', "git commit -m '[Automated] Update the toml files' Ballerina.toml Dependencies.toml" 88 | } 89 | } 90 | } 91 | } 92 | 93 | task startMongodbServer() { 94 | doLast { 95 | println("Starting mongodb server...") 96 | exec { 97 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 98 | commandLine 'cmd', '/c', "docker compose -f tests/resources/docker/docker-compose.yml up && exit %%ERRORLEVEL%%" 99 | } else { 100 | commandLine 'sh', '-c', "docker compose -f tests/resources/docker/docker-compose.yml up -d" 101 | } 102 | } 103 | } 104 | } 105 | 106 | task stopMongodbServer() { 107 | doLast { 108 | println("Stopping mongodb server...") 109 | exec { 110 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 111 | commandLine 'cmd', '/c', "docker compose -f tests/resources/docker/docker-compose.yml down && exit %%ERRORLEVEL%%" 112 | } else { 113 | commandLine 'sh', '-c', "docker compose -f tests/resources/docker/docker-compose.yml down" 114 | } 115 | } 116 | } 117 | } 118 | 119 | clean { 120 | delete 'build' 121 | delete 'lib' 122 | } 123 | 124 | build.dependsOn copyToLib 125 | build.dependsOn ":${packageName}-native:build" 126 | build.dependsOn startMongodbServer 127 | build.finalizedBy stopMongodbServer 128 | 129 | test.dependsOn ":${packageName}-native:build" 130 | test.dependsOn startMongodbServer 131 | test.finalizedBy stopMongodbServer 132 | 133 | publish.dependsOn build 134 | publishToMavenLocal.dependsOn build 135 | -------------------------------------------------------------------------------- /ballerina/client.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | import ballerina/log; 19 | 20 | # Represents a MongoDB client that can be used to interact with a MongoDB server. 21 | @display {label: "MongoDB Client", iconPath: "icon.png"} 22 | public isolated client class Client { 23 | 24 | # Initialises the `Client` object with the provided `ConnectionConfig` properties. 25 | # 26 | # + config - The connection configurations for connecting to a MongoDB server 27 | # + return - A `mongodb:Error` if the provided configurations are invalid. `()` otherwise. 28 | public isolated function init(*ConnectionConfig config) returns Error? { 29 | ConnectionProperties? options = config.options; 30 | if options is ConnectionProperties { 31 | boolean? sslEnabled = options?.sslEnabled; 32 | SecureSocket? secureSocket = options?.secureSocket; 33 | if sslEnabled is boolean { 34 | if !sslEnabled { 35 | if secureSocket is SecureSocket { 36 | log:printWarn("The connection property `secureSocket` is ignored when ssl is disabled."); 37 | } 38 | } 39 | } 40 | } 41 | return initClient(self, config.connection, options); 42 | } 43 | 44 | # Lists the database names in the MongoDB server. 45 | # 46 | # + return - An array of database names on success or else a `mongodb:DatabaseError` if unable to reach the DB 47 | @display {label: "List Database Names"} 48 | isolated remote function listDatabaseNames() 49 | returns @display {label: "Database Names"} string[]|Error = @java:Method { 50 | 'class: "io.ballerina.lib.mongodb.Client" 51 | } external; 52 | 53 | # Retrieves a database from the MongoDB server. 54 | # 55 | # + databaseName - Name of the database 56 | # + return - A `mongodb:Database` object on success or else a `mongodb:DatabaseError` if unable to reach the DB 57 | @display {label: "Get Database"} 58 | isolated remote function getDatabase(@display {label: "Database Name"} string databaseName) returns Database|Error { 59 | return new Database(self, databaseName); 60 | } 61 | 62 | # Closes the client. 63 | # 64 | # > **Note:** Use a single client instance for the lifetime of the application and close it when the application is done. 65 | # 66 | # + return - A `mongodb:Error` if the client is already closed or failed to close the client. `()` otherwise. 67 | @display {label: "Close the Client"} 68 | remote isolated function close() returns Error? = @java:Method { 69 | 'class: "io.ballerina.lib.mongodb.Client" 70 | } external; 71 | } 72 | 73 | isolated function initClient(Client 'client, ConnectionParameters|string connection, ConnectionProperties? options) 74 | returns Error? = @java:Method { 75 | 'class: "io.ballerina.lib.mongodb.Client" 76 | } external; 77 | -------------------------------------------------------------------------------- /ballerina/collection.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | # Represents a MongoDB collection that can be used to perform operations on the collection. 20 | @display { 21 | label: "MongoDB Collection" 22 | } 23 | public isolated client class Collection { 24 | 25 | private final string collectionName; 26 | 27 | isolated function init(Database database, string collectionName) returns Error? { 28 | self.collectionName = collectionName; 29 | check initCollection(self, database, collectionName); 30 | } 31 | 32 | # Returns the name of the collection. 33 | # 34 | # + return - The name of the collection 35 | public isolated function name() returns string { 36 | return self.collectionName; 37 | } 38 | 39 | # Inserts a single document into the collection. 40 | # 41 | # + document - The document to insert 42 | # + options - The options to apply to the operation 43 | # + return - An error if the operation failed, otherwise nil 44 | isolated remote function insertOne(record {|anydata...;|} document, InsertOneOptions options = {}) returns Error? { 45 | string documentString = document.toJsonString(); 46 | return check insertOne(self, documentString, options); 47 | } 48 | 49 | # Inserts multiple documents into the collection. 50 | # 51 | # + documents - The documents to insert 52 | # + options - The options to apply to the operation 53 | # + return - An error if the operation failed, otherwise nil 54 | isolated remote function insertMany(record {|anydata...;|}[] documents, InsertManyOptions options = {}) returns Error? { 55 | string[] documentString = documents.'map((doc) => doc.toJsonString()); 56 | return check insertMany(self, documentString, options); 57 | } 58 | 59 | # Finds documents from the collection. 60 | # 61 | # > **Note:** Close the resulted stream once the operation is completed. 62 | # 63 | # + filter - The query filter to apply when retrieving documents 64 | # + findOptions - The additional options to apply to the find operation 65 | # + projection - The projection to apply to the find operation. If not provided, the projection will be generated 66 | # based on the targetType 67 | # + targetType - The type of the returned documents 68 | # + return - A stream of documents which match the provided filter, or an error if the operation failed 69 | isolated remote function find(map filter = {}, FindOptions findOptions = {}, map? projection = (), 70 | typedesc targetType = <>) returns stream|Error = @java:Method { 71 | 'class: "io.ballerina.lib.mongodb.Collection" 72 | } external; 73 | 74 | # Finds a single document from the collection. 75 | # 76 | # + filter - The query filter to apply when retrieving documents 77 | # + findOptions - The additional options to apply to the find operation 78 | # + projection - The projection to apply to the find operation. If not provided, the projection will be generated 79 | # based on the targetType 80 | # + targetType - The type of the returned document 81 | # + return - The document which matches the provided filter, or an error if the operation failed 82 | isolated remote function findOne(map filter = {}, FindOptions findOptions = {}, map? projection = (), 83 | typedesc targetType = <>) returns targetType|Error? = @java:Method { 84 | 'class: "io.ballerina.lib.mongodb.Collection" 85 | } external; 86 | 87 | # Counts the number of documents in the collection. 88 | # 89 | # + filter - The query filter to apply when counting documents 90 | # + options - The additional options to apply to the count operation 91 | # + return - The number of documents in the collection, or an error if the operation failed 92 | isolated remote function countDocuments(map filter = {}, CountOptions options = {}) returns int|Error = 93 | @java:Method { 94 | 'class: "io.ballerina.lib.mongodb.Collection" 95 | } external; 96 | 97 | # Creates an index on the collection. 98 | # 99 | # + keys - The keys to index 100 | # + options - The options to apply to the index 101 | # + return - An error if the operation failed, otherwise nil 102 | isolated remote function createIndex(map keys, CreateIndexOptions options = {}) returns Error? = 103 | @java:Method { 104 | 'class: "io.ballerina.lib.mongodb.Collection" 105 | } external; 106 | 107 | # Lists the indexes of the collection. 108 | # 109 | # > **Note:** Close the resulted stream once the operation is completed. 110 | # 111 | # + return - A stream of indexes, or an error if the operation failed 112 | isolated remote function listIndexes() returns stream|Error = 113 | @java:Method { 114 | 'class: "io.ballerina.lib.mongodb.Collection" 115 | } external; 116 | 117 | # Drops an index from the collection. 118 | # 119 | # + indexName - The name of the index to drop 120 | # + return - An error if the operation failed, otherwise nil 121 | isolated remote function dropIndex(string indexName) returns Error? = @java:Method { 122 | 'class: "io.ballerina.lib.mongodb.Collection" 123 | } external; 124 | 125 | # Drops all the indexes from the collection. 126 | # 127 | # + return - An error if the operation failed, otherwise nil 128 | isolated remote function dropIndexes() returns Error? = @java:Method { 129 | 'class: "io.ballerina.lib.mongodb.Collection" 130 | } external; 131 | 132 | # Drops the collection. 133 | # 134 | # + return - An error if the operation failed, otherwise nil 135 | isolated remote function drop() returns Error? = @java:Method { 136 | 'class: "io.ballerina.lib.mongodb.Collection" 137 | } external; 138 | 139 | # Updates a single document in the collection. 140 | # 141 | # + filter - The query filter to apply when updating documents 142 | # + update - The update operations to apply to the documents 143 | # + options - The options to apply to the update operation 144 | # + return - An error if the operation failed, otherwise nil 145 | isolated remote function updateOne(map filter, Update update, UpdateOptions options = {}) 146 | returns UpdateResult|Error = @java:Method { 147 | 'class: "io.ballerina.lib.mongodb.Collection" 148 | } external; 149 | 150 | # Updates multiple documents in the collection. 151 | # 152 | # + filter - The query filter to apply when updating documents 153 | # + update - The update operations to apply to the documents 154 | # + options - The options to apply to the update operation 155 | # + return - An error if the operation failed, otherwise nil 156 | isolated remote function updateMany(map filter, Update update, UpdateOptions options = {}) 157 | returns UpdateResult|Error = @java:Method { 158 | 'class: "io.ballerina.lib.mongodb.Collection" 159 | } external; 160 | 161 | # Retrieves the distinct values for a specified field across a collection. 162 | # 163 | # > **Note:** Close the resulted stream once the operation is completed. 164 | # 165 | # + fieldName - The field for which to return distinct values 166 | # + filter - The query filter to apply when retrieving distinct values 167 | # + targetType - The type of the returned distinct values 168 | # + return - A stream of distinct values, or an error if the operation failed 169 | isolated remote function 'distinct(string fieldName, map filter = {}, typedesc targetType = <>) 170 | returns stream|Error = @java:Method { 171 | 'class: "io.ballerina.lib.mongodb.Collection" 172 | } external; 173 | 174 | # Deletes a single document from the collection. 175 | # 176 | # + filter - The query filter to apply when deleting documents 177 | # + return - An error if the operation failed, otherwise nil 178 | isolated remote function deleteOne(map filter) returns DeleteResult|Error = 179 | @java:Method { 180 | 'class: "io.ballerina.lib.mongodb.Collection" 181 | } external; 182 | 183 | # Deletes multiple documents from the collection. 184 | # 185 | # + filter - The query filter to apply when deleting documents 186 | # + return - An error if the operation failed, otherwise nil 187 | isolated remote function deleteMany(string|map filter) returns DeleteResult|Error = 188 | @java:Method { 189 | 'class: "io.ballerina.lib.mongodb.Collection" 190 | } external; 191 | 192 | # Aggregates documents according to the specified aggregation pipeline. 193 | # 194 | # > **Note:** Close the resulted stream once the operation is completed. 195 | # 196 | # + pipeline - The aggregation pipeline 197 | # + targetType - The type of the returned documents 198 | # + return - A stream of documents which match the provided pipeline, or an error if the operation failed 199 | isolated remote function aggregate(map[] pipeline, typedesc targetType = <>) 200 | returns stream|Error = @java:Method { 201 | 'class: "io.ballerina.lib.mongodb.Collection" 202 | } external; 203 | } 204 | 205 | isolated function initCollection(Collection collection, Database database, string collectionName) returns Error? = 206 | @java:Method { 207 | 'class: "io.ballerina.lib.mongodb.Collection" 208 | } external; 209 | 210 | isolated function insertOne(Collection collection, string document, InsertOneOptions options) returns Error? = 211 | @java:Method { 212 | 'class: "io.ballerina.lib.mongodb.Collection" 213 | } external; 214 | 215 | isolated function insertMany(Collection collection, string[] documents, InsertManyOptions options) returns Error? = 216 | @java:Method { 217 | 'class: "io.ballerina.lib.mongodb.Collection" 218 | } external; 219 | -------------------------------------------------------------------------------- /ballerina/database.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | # Represents a MongoDB database. 20 | @display { 21 | label: "MongoDB Database" 22 | } 23 | public isolated client class Database { 24 | 25 | isolated function init(Client 'client, string databaseName) returns Error? { 26 | check initDatabase(self, 'client, databaseName); 27 | } 28 | 29 | # Lists all the collections in the database. 30 | # 31 | # + return - An array of collection names 32 | isolated remote function listCollectionNames() returns string[]|Error = @java:Method { 33 | 'class: "io.ballerina.lib.mongodb.Database" 34 | } external; 35 | 36 | # Creates a collection in the database. 37 | # 38 | # + collectionName - The name of the collection to be created 39 | # + return - Nil on success or else an error 40 | isolated remote function createCollection(string collectionName) returns Error? = @java:Method { 41 | 'class: "io.ballerina.lib.mongodb.Database" 42 | } external; 43 | 44 | # Get a collection from the database. 45 | # 46 | # + collectionName - The name of the collection to be retrieved 47 | # + return - The `mogodb:Collection` on success or else an error 48 | isolated remote function getCollection(string collectionName) returns Collection|Error { 49 | return new (self, collectionName); 50 | } 51 | 52 | # Drops the database. 53 | # 54 | # + return - Nil on success or else and error 55 | isolated remote function drop() returns Error? = @java:Method { 56 | 'class: "io.ballerina.lib.mongodb.Database" 57 | } external; 58 | } 59 | 60 | isolated function initDatabase(Database database, Client 'client, string databaseName) returns Error? = @java:Method { 61 | 'class: "io.ballerina.lib.mongodb.Database" 62 | } external; 63 | -------------------------------------------------------------------------------- /ballerina/errors.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | # Holds the properties of a database error. 18 | # 19 | # + mongoDBExceptionType - Type of the returned MongoDB exception 20 | public type DatabaseErrorDetail record { 21 | string mongoDBExceptionType; 22 | }; 23 | 24 | # Represents an error caused by an issue related to database accessibility, erroneous queries, constraint violations, 25 | # database resource clean-up, and other similar scenarios. 26 | public type DatabaseError distinct error; 27 | 28 | # Represents an error originating from application-level causes. 29 | public type ApplicationError distinct error; 30 | 31 | # Represents a database or application level error returned from the MongoDB client remote functions. 32 | public type Error DatabaseError|ApplicationError|error; 33 | -------------------------------------------------------------------------------- /ballerina/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/71fd7531bea6eac54a49881fd631c8adb0856cb1/ballerina/icon.png -------------------------------------------------------------------------------- /ballerina/init.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | function init() { 20 | setModule(); 21 | } 22 | 23 | function setModule() = @java:Method { 24 | 'class: "io.ballerina.lib.mongodb.ModuleUtils" 25 | } external; 26 | -------------------------------------------------------------------------------- /ballerina/result_iterator.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | # Represents the result iterator object for the MongoDB query result. 20 | isolated class ResultIterator { 21 | private boolean isClosed = false; 22 | 23 | public isolated function next() returns record {|anydata value;|}|Error? { 24 | boolean closed; 25 | lock { 26 | closed = self.isClosed; 27 | } 28 | if closed { 29 | return error ApplicationError("Cannot iterate over a closed stream"); 30 | } 31 | anydata|Error? next = check nextResult(self); 32 | if next is Error { 33 | lock { 34 | check self.close(); 35 | } 36 | return next; 37 | } else if next !is () { 38 | return {value: next}; 39 | } 40 | return self.close(); 41 | } 42 | 43 | public isolated function close() returns Error? { 44 | lock { 45 | self.isClosed = true; 46 | } 47 | return close(self); 48 | } 49 | } 50 | 51 | isolated function nextResult(ResultIterator resultIterator) returns anydata|Error? = @java:Method { 52 | 'class: "io.ballerina.lib.mongodb.IteratorUtils" 53 | } external; 54 | 55 | isolated function close(ResultIterator resultIterator) returns Error? = @java:Method { 56 | 'class: "io.ballerina.lib.mongodb.IteratorUtils" 57 | } external; 58 | -------------------------------------------------------------------------------- /ballerina/tests/01_client_tests.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/test; 18 | 19 | const string username = "admin"; 20 | const string password = "admin"; 21 | 22 | const string keystorePath = "./tests/resources/docker/certs/mongodb-client.jks"; 23 | 24 | @test:Config { 25 | groups: ["client", "negative"] 26 | } 27 | public function testInvaliClientConfig() { 28 | Client|Error mongoClient = new (invalidConfig); 29 | test:assertTrue(mongoClient is ApplicationError, "Error expected when url is invalid."); 30 | ApplicationError err = mongoClient; 31 | test:assertEquals(err.message(), "Error occurred while initializing the MongoDB client."); 32 | ApplicationError cause = err.cause(); 33 | test:assertEquals(cause.message(), 34 | "The connection string is invalid. Connection strings must start with either 'mongodb://' or 'mongodb+srv://"); 35 | } 36 | 37 | @test:Config { 38 | groups: ["client"] 39 | } 40 | isolated function testClientInitWithNamedParameters() returns error? { 41 | Client mongoClient = check new (connection = { 42 | serverAddress: { 43 | host: "localhost", 44 | port: 27016 45 | } 46 | }); 47 | string[] databaseNames = check mongoClient->listDatabaseNames(); 48 | test:assertEquals(databaseNames.length(), 3, "Expected 3 databases but found " + databaseNames.length().toString()); 49 | check mongoClient->close(); 50 | } 51 | 52 | @test:Config { 53 | groups: ["client"] 54 | } 55 | public function testCreateClient() returns error? { 56 | Client mongoClient = check new (connection = { 57 | serverAddress: { 58 | host: "localhost", 59 | port: 27017 60 | }, 61 | auth: { 62 | username: username, 63 | password: password, 64 | database: "admin" 65 | } 66 | }); 67 | string[] databaseNames = check mongoClient->listDatabaseNames(); 68 | test:assertEquals(databaseNames.length(), 3, "Expected 3 databases but found " + databaseNames.length().toString()); 69 | test:assertEquals(databaseNames, ["admin", "config", "local"]); 70 | } 71 | 72 | @test:Config { 73 | groups: ["client"] 74 | } 75 | public function testCreateClientWithConnectionString() returns error? { 76 | string connection = string `mongodb://${username}:${password}@localhost:27017/admin`; 77 | Client mongoClient = check new ({connection}); 78 | string[] databaseNames = check mongoClient->listDatabaseNames(); 79 | test:assertEquals(databaseNames.length(), 3, "Expected 3 databases but found " + databaseNames.length().toString()); 80 | test:assertEquals(databaseNames, ["admin", "config", "local"]); 81 | } 82 | 83 | @test:Config { 84 | groups: ["client"] 85 | } 86 | isolated function testCreateClientNoAuth() returns error? { 87 | ConnectionConfig clientConfigNoAuth = { 88 | connection: { 89 | serverAddress: { 90 | host: "localhost", 91 | port: 27016 92 | } 93 | } 94 | }; 95 | Client mongoClient = check new (clientConfigNoAuth); 96 | string[] databaseNames = check mongoClient->listDatabaseNames(); 97 | test:assertEquals(databaseNames.length(), 3, "Expected 3 databases but found " + databaseNames.length().toString()); 98 | test:assertEquals(databaseNames, ["admin", "config", "local"]); 99 | check mongoClient->close(); 100 | } 101 | 102 | @test:Config { 103 | groups: ["client"] 104 | } 105 | function testSslConfigWithSslDisabled() returns error? { 106 | ConnectionConfig validSslConfig = { 107 | connection: { 108 | serverAddress: { 109 | host: "localhost", 110 | port: 27018 111 | }, 112 | auth: { 113 | username: "C=LK,ST=Western,L=Colombo,O=WSO2,OU=Ballerina,CN=admin" 114 | } 115 | }, 116 | options: { 117 | socketTimeout: 10000, 118 | sslEnabled: false, 119 | secureSocket: { 120 | trustStore: { 121 | path: keystorePath, 122 | password: "123456" 123 | }, 124 | keyStore: { 125 | path: keystorePath, 126 | password: "123456" 127 | }, 128 | protocol: "TLS" 129 | } 130 | } 131 | }; 132 | test:when(logWarn).call("mockLogWarn"); 133 | Client mongodb = check new Client(validSslConfig); 134 | test:assertEquals(message, "The connection property `secureSocket` is ignored when ssl is disabled."); 135 | check mongodb->close(); 136 | } 137 | 138 | @test:Config { 139 | groups: ["client", "replicaSet"], 140 | enable: false // Configure the replica set properly with a primary node and enable this test 141 | } 142 | public function testConnectToReplicaSet() returns error? { 143 | Client mongoClient = check new (replicaSetConfig); 144 | string[] databaseNames = check mongoClient->listDatabaseNames(); 145 | test:assertEquals(databaseNames.length(), 3, "Expected 3 databases but found " + databaseNames.length().toString()); 146 | test:assertEquals(databaseNames, ["admin", "local"]); 147 | } 148 | 149 | @test:Config { 150 | groups: ["client", "atlas"], 151 | enable: false 152 | } 153 | public function testConnectionString() returns error? { 154 | Client mongoClient = check new ({connection: "connectionURL"}); 155 | string[] databaseNames = check mongoClient->listDatabaseNames(); 156 | test:assertEquals(databaseNames.length(), 3, "Expected 3 databases but found " + databaseNames.length().toString()); 157 | } 158 | 159 | @test:Config { 160 | groups: ["client", "ssl"] 161 | } 162 | public function testSSLConnection() returns error? { 163 | ConnectionConfig validSslConfig = { 164 | connection: { 165 | serverAddress: { 166 | host: "localhost", 167 | port: 27018 168 | }, 169 | auth: { 170 | username: "C=LK,ST=Western,L=Colombo,O=WSO2,OU=Ballerina,CN=admin" 171 | } 172 | }, 173 | options: { 174 | socketTimeout: 10000, 175 | sslEnabled: true, 176 | secureSocket: { 177 | trustStore: { 178 | path: keystorePath, 179 | password: "123456" 180 | }, 181 | keyStore: { 182 | path: keystorePath, 183 | password: "123456" 184 | }, 185 | protocol: "TLS" 186 | } 187 | } 188 | }; 189 | Client mongoClient = check new (validSslConfig); 190 | string[] databaseNames = check mongoClient->listDatabaseNames(); 191 | test:assertEquals(databaseNames, ["admin", "config", "local"]); 192 | check mongoClient->close(); 193 | } 194 | -------------------------------------------------------------------------------- /ballerina/tests/02_database_tests.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/test; 18 | 19 | @test:Config { 20 | groups: ["database"] 21 | } 22 | function testDatabaseConnection() returns error? { 23 | Database database = check mongoClient->getDatabase("testDatabaseConnection"); 24 | string[] collectionNames = check database->listCollectionNames(); 25 | test:assertEquals(collectionNames, []); 26 | check database->createCollection("Movies"); 27 | collectionNames = check database->listCollectionNames(); 28 | test:assertEquals(collectionNames, ["Movies"]); 29 | check database->drop(); 30 | } 31 | 32 | @test:Config { 33 | groups: ["database", "collection", "list"] 34 | } 35 | function testGetCollection() returns error? { 36 | Database database = check mongoClient->getDatabase("testGetCollection"); 37 | Collection collection = check database->getCollection("Movies"); 38 | test:assertEquals(collection.name(), "Movies"); 39 | check database->drop(); 40 | } 41 | 42 | @test:Config { 43 | groups: ["database"] 44 | } 45 | isolated function testDropDatabase() returns error? { 46 | string[] databaseNames = check mongoClient->listDatabaseNames(); 47 | test:assertTrue(databaseNames.indexOf("sampleDB") !is int); 48 | Database db = check mongoClient->getDatabase("sampleDB"); 49 | check db->createCollection("testCollection"); 50 | databaseNames = check mongoClient->listDatabaseNames(); 51 | test:assertTrue(databaseNames.indexOf("sampleDB") is int); 52 | check db->drop(); 53 | databaseNames = check mongoClient->listDatabaseNames(); 54 | test:assertTrue(databaseNames.indexOf("sampleDB") !is int); 55 | } 56 | -------------------------------------------------------------------------------- /ballerina/tests/mock_functions.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/log; 18 | import ballerina/test; 19 | 20 | @test:Mock { 21 | moduleName: "ballerina/log", 22 | functionName: "printWarn" 23 | } 24 | test:MockFunction logWarn = new(); 25 | 26 | string message = ""; 27 | 28 | public type Value anydata|Valuer; 29 | 30 | public type Valuer isolated function () returns anydata; 31 | 32 | public type KeyValues record {| 33 | never msg?; 34 | never 'error?; 35 | never stackTrace?; 36 | Value...; 37 | |}; 38 | 39 | function mockLogWarn( 40 | string|log:PrintableRawTemplate msg, error? 'error = (), error:StackFrame[]? stackTrace = (), *KeyValues keyValues) { 41 | lock { 42 | if msg is string { 43 | message = msg; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ballerina/tests/resources/docker/certs/mongodb-CA.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCOTt8cJP70dLZi 3 | iIvk4BwNtXB0hs8Io0jeL9Kz4UyzLTRfPvKL7cL4cS57HOOjfWnlzdOdcaYxjapT 4 | 6HSaF/4R/mRMD3g7X7LcczGJDBV5N8FdmPrwuvL7kDttt8bC+nINFQvGoFlSXZc8 5 | cx+bejxLs6EtanPFfqX+aOYWvAjJF9cTs3N7ZP7pmax59dB+tAhPQnKy+4QornSe 6 | npLxUjiQHAxg90yru0up1OPDPMIJthO1V7eW84aqqce0y7KwUs8xAR3Qneh88XYP 7 | 9v7uKyEOcZgzKcG69Geee9OXMIHXh+TB87y0R8twrGT8lHT7V3Oi19YeNfDjJBy7 8 | vMgMoqZ5AgMBAAECggEAGIYjENiXT01luOlLInA0pXAlJw+sUhLBlfir2O/0pdQe 9 | eGOCrPaWaPYoSnMaD6ynOUEVPMa/Gz8MoVUn8v47fKJYansn/yNo0XDQkouQj8k5 10 | +4VHiYDOKugaNbg7+pHqYbLEysALZJRYYcR9J/ASwAD+v7LerKQ8uvEc5cIVyYGe 11 | ZJ041hmux9SYfj+lwmKlzXZXLF9ua3lCtscE2Sne90X25w+eOVUAYQTuy5cV4CjG 12 | 7sHUVMp3g2irtSE57wiCbVTMRjwS/iBYj61vi7VvQyYQf+RSFkZKNJbwwNb2jM0t 13 | zXhMjBbRFH7CEFJ01FHKI8Gi1m7VcGVLZlQOoouXYQKBgQDIMlue2Z9yOSDJmpuI 14 | 3ImDcrx2DCaDWnAiyqa7B9h5r1zgPZo2MnRCCo7dLP57DE5hfvjJU8Ltjuq4qJnj 15 | MGJiY+jGeCrScizymLv0ycS2TkQeYNveG3beK2jB/j61IpqVvAB1KhR1aoigeVGv 16 | kcJVbhbn5XwUNpm925XXKjy5zQKBgQC1+bIxfayYk+0Rxhk5wrTfngE8MYovNPoi 17 | Is9HM86EU3ctp/+gLSJefJA9yqbf32EZFdll4mJShsZ33SmJIsSlEGNVDi9UXxp/ 18 | BcKa9S9zTjlFR9YSh658jgWqMi3heZdXk5278sE0T6zA88R9im97A8C8WlNpFxqJ 19 | aEGqgzzDXQKBgCiC+ENm6nsk0Fu7q6nAZxtwhm6k+s4t6O9Bbwf+CHJnaDYAgUpi 20 | X2BV3p8nUb/4t4vHM/UZvCJyf1Eq3Sk6S055xUsUWiYH8MyO18orYmE56VL0asnB 21 | aQaAZkyLdIkXHY0bZERRZZ51FnzS0BLlPhwnkP8QU1GL0wS2gNXvuCYpAoGAJ9FP 22 | EE0zat9TTERQWLcl5JgqJQWh+tpYsQd021uWoJWyyiasZFv73TjcRukEwo+aK2cA 23 | fq6eXPhojOmzoPIenQ+M7JuB97AnmAumnUlw7IX9Og+R49QUdeSNkMQSDfgRCXSf 24 | WvSvGcclQcMVB3M3GW+kyJHrFl+byt0pISo+LXECgYAatxmI8q6IOYQvTNsKM/LB 25 | i2Izymw21B9PBntMyF0QbewCnsOHjMkXdbo3RBkI74f78etNbOCu+lCqoTCkGCIB 26 | OlAGzn6MMqnTuJ65sHiT+E+5S+pMlxeNihyoxkgoN1GlQT8igNAv9OKJpAV7TwlO 27 | StUf25sqRLApTl0eQH4pSA== 28 | -----END PRIVATE KEY----- 29 | -----BEGIN CERTIFICATE----- 30 | MIIDnzCCAoegAwIBAgIUEwxERoOPiDYAZREjlV/UlOvCIZwwDQYJKoZIhvcNAQEL 31 | BQAwXjELMAkGA1UEAwwCQ0ExCzAJBgNVBAsMAkRCMRAwDgYDVQQKDAdNb25nb0RC 32 | MRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQswCQYDVQQIDAJDQTELMAkGA1UEBhMC 33 | VVMwIBcNMjMxMTIzMTEwNzAxWhgPMjA1MTA0MDkxMTA3MDFaMF4xCzAJBgNVBAMM 34 | AkNBMQswCQYDVQQLDAJEQjEQMA4GA1UECgwHTW9uZ29EQjEWMBQGA1UEBwwNU2Fu 35 | IEZyYW5jaXNjbzELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG 36 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjk7fHCT+9HS2YoiL5OAcDbVwdIbPCKNI3i/S 37 | s+FMsy00Xz7yi+3C+HEuexzjo31p5c3TnXGmMY2qU+h0mhf+Ef5kTA94O1+y3HMx 38 | iQwVeTfBXZj68Lry+5A7bbfGwvpyDRULxqBZUl2XPHMfm3o8S7OhLWpzxX6l/mjm 39 | FrwIyRfXE7Nze2T+6ZmsefXQfrQIT0JysvuEKK50np6S8VI4kBwMYPdMq7tLqdTj 40 | wzzCCbYTtVe3lvOGqqnHtMuysFLPMQEd0J3ofPF2D/b+7ishDnGYMynBuvRnnnvT 41 | lzCB14fkwfO8tEfLcKxk/JR0+1dzotfWHjXw4yQcu7zIDKKmeQIDAQABo1MwUTAd 42 | BgNVHQ4EFgQUh7jELAU5Z3FbhEeqXlnbPp2SEtUwHwYDVR0jBBgwFoAUh7jELAU5 43 | Z3FbhEeqXlnbPp2SEtUwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC 44 | AQEAPrHmFUjofdVJL9AXcL3Ey5BSw+8Kq8DzSiQ0p9jgxZzMd7zTBItqtKiL9/Ph 45 | qIyftGHcJfNUMWiEXH9R9MBkv1N43DRkDvChXdZCTgZ0lDBc9V64yUQZ/J7rvECF 46 | fIDvwh+U4/FV1hzh/+5rWlU8nfwky8xzSKOgdZDle1+xRrSaGztYvyGpCPDjyCuu 47 | yW9bha3ICPSB0fe/V4WGZYOUN9su+t+O4Xj7I9xJPVysPkdO9Ik0lyuPe2+briRP 48 | O5zY/ach9MbJ6/nH3z5fl6MQKQ4c3f+Z6klwqbRQBC0aAUfAmDetbQi0W1cAvKY8 49 | banL+FYfkeVVxgTk3ilqtWQ+rw== 50 | -----END CERTIFICATE----- 51 | -------------------------------------------------------------------------------- /ballerina/tests/resources/docker/certs/mongodb-client.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/71fd7531bea6eac54a49881fd631c8adb0856cb1/ballerina/tests/resources/docker/certs/mongodb-client.jks -------------------------------------------------------------------------------- /ballerina/tests/resources/docker/certs/mongodb-client.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCrul6TzDjh55FT 3 | OuVnPJU4NDWC58+tCsfv8LiTFtmk6F1Q7hQ28fEwG5R9EFYkSARqCn5J8Nmwe6SQ 4 | GQ7N2WHzF65XkwcYMh9GqMiAMYNGcL+2yhkuacahCo+r5I2jumSaf5Fn8YTkhW1H 5 | EFcZeo/YqNpLkJ+m4XaivUvPlx/IePz5Z5hnecbU8GuChUYUrDXBCbE4Jwd7f6J2 6 | GELokebmaKNXa4kG2hmmyrSUTk3ZKVrbxIgBZfteyMWiunSzhM4I2m3PEzcvDJcN 7 | OzprO0XMHovi0rF5smDJUxKcLi7iMuAxSwVpggB2ITu/ueBXu33rprsvDDpwpe+y 8 | cxd6vq9lAgMBAAECgf8mEWpl2R/C9FKC4Mt51zQ9AVXbbwfalEk+J17DPI2CwP/u 9 | sNhKVdfhkjuYfcaaxFw2JZ1ZRsr7FG2mg+eEOmw8N0Oupiksc+/6+e94e4FeXCAj 10 | pSlv4ILnsC+pK0E6ylcC6MSTBjcvcWSIHFcyjrjUjpnVpnm9xL1H1i64Fgg1qD6S 11 | BrSg3lZm/plSOqJCcr11nckXk3uivm+zzbp2bhHuCxbd2Vh0ySyr10MD/DEGkhZD 12 | aHdI91f1IAHM7h5OpHXrboBViGDCCqfJFZHnIoBJMcBChy3uMl0LOm7CUfg7kQrt 13 | LR+hOCBRmqZJBV+kpYGx/oGga9SxvejQzdWkhMECgYEA8MqlOIekg3fQATVuW8iH 14 | q4qaR7ZzOGYtv5YqWbt6Chp7UGXA7JkmloboETYHFK+1BIH5JpRxyoE79h+knKRf 15 | OurBiFa3eExEPa+gLxJV5eUu4OzaJITN/vrgzy9cyUua2cJsqiJYJBaUJTQB5l/p 16 | M9gANrnLQEuUXHRLdLKa8kECgYEAtpMJTkK9u/B+A2EJlcRxOo8MMU5zMD4GAHBT 17 | uJwGzIM9Ttbg6f6WupP5fszP4AVPvbmtBlWTwG8r+9SRIoxHU67vhqr0Kda9dlbi 18 | vrfU5DT/Si46O/IRS0s2mTEIwLKfzhOpIGHPnQwvoKGBILLwECWw4qTyOefXl36Z 19 | /T4WrCUCgYASbP9dpwuQv99b6FHMljjDiLSrniuM+kyv53bQLQd2tHYRPegYctPA 20 | GwyxHHhIPfXVJXkCWcOnYmJLQDqhffaHlKVAoJoji3qBWeohD/8gu3vt3FIJD1yQ 21 | EXSYhiBMiwuLdFRKZJxoDo5Blow6q8Y1oGbLyUXjYqU0ufV4NZ6jwQKBgQCIzaZU 22 | aPgooiyaNZTsDxVU7qkRLRps1JzEqWZiVy9VASXoNGS1kRm6VnTFyYwd7XzxyfZX 23 | X7ploCfR/FaAD6LGlrdOLjzkOM8gpDwk8jRohzmfiQIDtv+0bnhL040ebvoFfX/m 24 | DsR1hhMOBtZt/Qaa4tMnELecIhfOoYObWXG9rQKBgQCPpQ+2P3q3bY3w2qV3vOSl 25 | krPjsvnyd/YRo/HDGPAw9pNzuqOtk7e9EjHzxIqdiAGUjVrmtnywi2GXdfYdCKG5 26 | wZFRcMaxE0xRynRgCFB3JNbl4Ia6b7lqcPqMB96QLPynev09UcYBRL/eEyI+O27c 27 | zRtFgewpYjj+nKuNRsYIsg== 28 | -----END PRIVATE KEY----- 29 | -----BEGIN CERTIFICATE----- 30 | MIIDSzCCAjMCFFGeGkfRu4/advpy1mtdPFt7dfCaMA0GCSqGSIb3DQEBCwUAMF4x 31 | CzAJBgNVBAMMAkNBMQswCQYDVQQLDAJEQjEQMA4GA1UECgwHTW9uZ29EQjEWMBQG 32 | A1UEBwwNU2FuIEZyYW5jaXNjbzELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVTMCAX 33 | DTIzMTEyMzExMDcwMVoYDzIwNTEwNDA5MTEwNzAxWjBkMQ4wDAYDVQQDDAVhZG1p 34 | bjESMBAGA1UECwwJQmFsbGVyaW5hMQ0wCwYDVQQKDARXU08yMRAwDgYDVQQHDAdD 35 | b2xvbWJvMRAwDgYDVQQIDAdXZXN0ZXJuMQswCQYDVQQGEwJMSzCCASIwDQYJKoZI 36 | hvcNAQEBBQADggEPADCCAQoCggEBAKu6XpPMOOHnkVM65Wc8lTg0NYLnz60Kx+/w 37 | uJMW2aToXVDuFDbx8TAblH0QViRIBGoKfknw2bB7pJAZDs3ZYfMXrleTBxgyH0ao 38 | yIAxg0Zwv7bKGS5pxqEKj6vkjaO6ZJp/kWfxhOSFbUcQVxl6j9io2kuQn6bhdqK9 39 | S8+XH8h4/PlnmGd5xtTwa4KFRhSsNcEJsTgnB3t/onYYQuiR5uZoo1driQbaGabK 40 | tJROTdkpWtvEiAFl+17IxaK6dLOEzgjabc8TNy8Mlw07Oms7Rcwei+LSsXmyYMlT 41 | EpwuLuIy4DFLBWmCAHYhO7+54Fe7feumuy8MOnCl77JzF3q+r2UCAwEAATANBgkq 42 | hkiG9w0BAQsFAAOCAQEAd0Lc4wglK+dmbif9xeIbCpql1883YbuAQaV1NI2SL7K8 43 | 2pu6iwa2U6mk9LsSR01Klkrhw7zNkTCvGGXq6FcRWZTQfjK0w6YicEuhsB8Vdr6E 44 | PoLTpG6QIKwLiUpZEX4J9SqYfyrlOkFLAPS3eiLHZ41XAwFa5Fboh3822MYGoDuX 45 | RgoU1eeD099L6Swm5kOq8KOXdLHtYpoQ3FLt+YSTTr/nwbe7W4RoM1MXIcQsJ0nX 46 | WJRwh+mXvaPoo21BeXBHyL0BC+i826mn54wcOlrELVmJOuOgsOfmq/WeeP3BckMV 47 | qCo2CLuz4Zt9GTXcTLVYW2wA6Ni5/i01tvhaCuHzpw== 48 | -----END CERTIFICATE----- 49 | -------------------------------------------------------------------------------- /ballerina/tests/resources/docker/certs/mongodb-server.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2YbOLff66HOaC 3 | 0/y2pwcJEvjCmPW8nbmI+DgE9rxhBgOPaSPk0QoqnHcJyfOvfnpgY+7i7a4NMoa/ 4 | wyTONTrbiSa2jtwKgGKrK+SMJyouNGGWjYf44XzHD4AerJ4y5boQ0JVW5cBMUBzI 5 | I7a5rs/RSINdg0svh/DTfPbtzr36cI/HKRQ0mAQgOR926zFHxZY04T/wv/dmDhUD 6 | e31/aElB7hcEeHdJtNWCoUtroVdlVysuAf6J9sS01FYwRt0lt75Ln2BQu5D6dwD2 7 | HIgC88SsmsmbqOq4WxVcd9r9gFQa2sIo0Ze4cSmpEP6qwJr8uXXlfWXRgVNYEAR0 8 | qViUo2/zAgMBAAECggEAFCnSDUp1NoNKcs1YA6OMshKgYPdDN8KiSAPVQas7oWhm 9 | TV0c5Ee+HX7l5DWpFM5hXjW+K+WGGBxtbFb5Qzj8VFgh6Q37Qsf14KG+J0aPMcOF 10 | xHzKOxhG0MUkb3+7D7p5KzG8SPqmm2lB/ViBc57hh+xB5b1FuzAGzoLi0+DG/SBz 11 | x+BDwEcMGyNa8cd2oK8YLkKf86K2g7YqXrP8rsXQWPQfOjGHKkuxHfmd6CmSfS5e 12 | ILi0VX0ZTxZIdZOuCEwG5LCyOMKqLn78uEfHLr9aFP1UxbhSwVDNp8hNinfdKNkY 13 | eKyZqLUC8Qssvs/ry7t2Z71+1a12bUnqe7nAJWckmQKBgQDnsWaOsCt1cjGttE1D 14 | +/f3DOVBj3pPD40H30v3pa3TxlppD8kFJw4sgyb+5Fq6p/81r9w6ljQxhMpR0G8O 15 | YR76UW3wY31mcrPb/g0tBirt7Qo1VZV2S2A2gefS8uf74pRNgpD1RVkRZZZwEB8O 16 | 6TEUqzCvLLlB9Eg+ZNvs3eIE6QKBgQDJg/EjU9BgCN6mfSgq8hq4tODwd69CrAT/ 17 | MJMcZGPWbM8eow8K1HvAjwZFnHDLLMlh3xHjmmOygM4yqiRQ3LoBqOh2JZEFueAJ 18 | 4Jlz8uPozwaUacsl7h4LebNes65aI1Bs/Y5WDOO1nSplRAaX+lTp2bju/hdL/0P+ 19 | Cmx0s1X0ewKBgCDKN4R8JDpj5en6eXDkqQw6s/taTeoAfmodzQeIWBh/mu4BgOaM 20 | x3G/QfaS5NBD1FeJwvY7qblUXLnFcOItFpBAk/mQav/jvdallsHHfK3dfTNdIGD0 21 | e/Ja4i81l2VLhMePcep0XQ2cPfUwIuUeVYbiT2qLPtC5vLuv1HwqTsF5AoGBALkk 22 | VAQVGTlibM2h56mtTgeth4znKUqkKOMcicxoH6H9zj1jqopUtm4v+Z8zIB5LQ6p7 23 | /D+UtUxnMwsxbrQsV2j2+ryxvw/3unLYu6Pf4K0gp/brTA3JPClm4vl7NBD0qQu5 24 | 2XAN35gYkb8ARN6UzDceJd7N7DGSkbFxejuuGKbJAoGAa5rKwpGKHWDIen1X6uiO 25 | Mjg2iH+qmNf7c8GLaRlmSqoKaMRKiTO+DEX4zpxManNJYTcWcaSCtsyv2S3JWpe7 26 | /xWObYKmfUcbCKRa499cqAQmICyzo8YuYPN8of+f+G1lYSh7yMsivE6LzW2diEGT 27 | DKclDdGVZGnCrD+aHCa/0+Q= 28 | -----END PRIVATE KEY----- 29 | -----BEGIN CERTIFICATE----- 30 | MIIDTDCCAjQCFFGeGkfRu4/advpy1mtdPFt7dfCZMA0GCSqGSIb3DQEBCwUAMF4x 31 | CzAJBgNVBAMMAkNBMQswCQYDVQQLDAJEQjEQMA4GA1UECgwHTW9uZ29EQjEWMBQG 32 | A1UEBwwNU2FuIEZyYW5jaXNjbzELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVTMCAX 33 | DTIzMTEyMzExMDcwMVoYDzIwNTEwNDA5MTEwNzAxWjBlMRIwEAYDVQQDDAlsb2Nh 34 | bGhvc3QxCzAJBgNVBAsMAkRCMRAwDgYDVQQKDAdNb25nb0RCMRYwFAYDVQQHDA1T 35 | YW4gRnJhbmNpc2NvMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMwggEiMA0GCSqG 36 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2YbOLff66HOaC0/y2pwcJEvjCmPW8nbmI 37 | +DgE9rxhBgOPaSPk0QoqnHcJyfOvfnpgY+7i7a4NMoa/wyTONTrbiSa2jtwKgGKr 38 | K+SMJyouNGGWjYf44XzHD4AerJ4y5boQ0JVW5cBMUBzII7a5rs/RSINdg0svh/DT 39 | fPbtzr36cI/HKRQ0mAQgOR926zFHxZY04T/wv/dmDhUDe31/aElB7hcEeHdJtNWC 40 | oUtroVdlVysuAf6J9sS01FYwRt0lt75Ln2BQu5D6dwD2HIgC88SsmsmbqOq4WxVc 41 | d9r9gFQa2sIo0Ze4cSmpEP6qwJr8uXXlfWXRgVNYEAR0qViUo2/zAgMBAAEwDQYJ 42 | KoZIhvcNAQELBQADggEBAH7tHx7s6AQAVpOmN8jcPulFgNTUrUCT9Ww/DGUMl2i7 43 | tyj9YL4eMLkC9/WTAMqEZg9JO3f0708WhfEpxro7z8vSzczObJAtalB5uCN2NszQ 44 | L0peujUAu2mLWtXoin3CbNz6EPe6H/SUKf/zzqpw9L6iZaEju7Qf2ckBN/S0bWSw 45 | EiW9ol1TrFQB5noja3K7N3l8XXz+3TEdz7N5XeU9c3/r76yk4ODcOTkYmbZe0lev 46 | vKEC7OXxmvwekUYkX4+XPLjEU44gH8nlATSjXUGWFqLVHGp0arLCDzZBtLIQCSPi 47 | alX/ZSoXwpRSx+8Go+E1Lu+ZC3VG2Gfl8Ldu1RT+8XA= 48 | -----END CERTIFICATE----- 49 | -------------------------------------------------------------------------------- /ballerina/tests/resources/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | mongo-no-auth: 3 | image: mongo:4.2 4 | restart: always 5 | ports: 6 | - 27016:27017 7 | 8 | mongo-no-ssl: 9 | image: mongo:4.2 10 | restart: always 11 | ports: 12 | - 27017:27017 13 | volumes: 14 | - ./init-scripts/no-ssl.js:/docker-entrypoint-initdb.d/init-mongo.js:ro 15 | healthcheck: 16 | test: echo 'db.runCommand("ping").ok' | mongo localhost:27017/test --quiet 17 | interval: 30s 18 | timeout: 20s 19 | retries: 3 20 | environment: 21 | MONGO_INITDB_ROOT_USERNAME: admin 22 | MONGO_INITDB_ROOT_PASSWORD: admin 23 | 24 | mongo-with-ssl: 25 | image: mongo:4.2 26 | restart: always 27 | ports: 28 | - 27018:27018 29 | volumes: 30 | - ./init-scripts/ssl.js:/docker-entrypoint-initdb.d/init-mongo.js:ro 31 | - ./certs/mongodb-server.pem:/etc/ssl/mongodb.pem:ro 32 | - ./certs/mongodb-CA.pem:/etc/ssl/mongodb-ca.pem:ro 33 | depends_on: 34 | mongo-no-ssl: 35 | condition: service_healthy 36 | command: --port 27018 --tlsMode requireTLS --tlsCertificateKeyFile /etc/ssl/mongodb.pem --tlsCAFile /etc/ssl/mongodb-ca.pem 37 | -------------------------------------------------------------------------------- /ballerina/tests/resources/docker/init-scripts/no-ssl.js: -------------------------------------------------------------------------------- 1 | db.createUser( 2 | { 3 | user: "admin", 4 | pwd: "admin", 5 | roles: [{ role: "userAdminAnyDatabase", db: "admin" }] 6 | } 7 | ) 8 | -------------------------------------------------------------------------------- /ballerina/tests/resources/docker/init-scripts/ssl.js: -------------------------------------------------------------------------------- 1 | db.createUser( 2 | { 3 | user: "admin", 4 | pwd: "admin", 5 | roles: [{ role: "userAdminAnyDatabase", db: "admin" }] 6 | } 7 | ) 8 | 9 | db.getSiblingDB("$external").runCommand( 10 | { 11 | createUser: "C=LK,ST=Western,L=Colombo,O=WSO2,OU=Ballerina,CN=admin", 12 | roles: [ 13 | { role: "root", db: "admin" }, 14 | { role: "readWrite", db: "moviesDB" } 15 | ] 16 | } 17 | ); 18 | -------------------------------------------------------------------------------- /ballerina/tests/types.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | type Movie record { 18 | string name; 19 | int year; 20 | int rating; 21 | }; 22 | 23 | type MovieWithIdName record {| 24 | map _id; 25 | string name; 26 | |}; 27 | 28 | type Person record {| 29 | string name; 30 | int age; 31 | Address address; 32 | |}; 33 | 34 | type Address readonly & record {| 35 | string street; 36 | string city; 37 | string country; 38 | |}; 39 | 40 | type Book readonly & record {| 41 | string title; 42 | int year; 43 | int rating; 44 | |}; 45 | 46 | type Author readonly & record {| 47 | string name; 48 | Book[] books; 49 | |}; 50 | -------------------------------------------------------------------------------- /ballerina/tests/utils.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/log; 18 | import ballerina/test; 19 | 20 | @test:AfterSuite 21 | function shutDown() returns error? { 22 | check mongoClient->close(); 23 | log:printInfo("**** MongoDB client closed ****"); 24 | } 25 | 26 | final ConnectionConfig clientConfig = { 27 | connection: { 28 | auth: { 29 | username, 30 | password, 31 | database: "admin" 32 | } 33 | }, 34 | options: { 35 | sslEnabled: false 36 | } 37 | }; 38 | 39 | final ConnectionConfig invalidConfig = { 40 | connection: "invalidDB" 41 | }; 42 | 43 | final ConnectionConfig replicaSetConfig = { 44 | connection: { 45 | serverAddress: [ 46 | { 47 | host: "localhost", 48 | port: 20000 49 | }, 50 | { 51 | host: "localhost", 52 | port: 20001 53 | }, 54 | { 55 | host: "localhost", 56 | port: 20002 57 | } 58 | ], 59 | auth: { 60 | username, 61 | password, 62 | database: "admin" 63 | } 64 | } 65 | }; 66 | 67 | final Client mongoClient = check new (clientConfig); 68 | -------------------------------------------------------------------------------- /ballerina/types.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/crypto; 18 | 19 | # Represents the Client configurations for MongoDB. 20 | @display {label: "Connection Config"} 21 | public type ConnectionConfig record {| 22 | # connection - Connection string or the connection parameters for the MongoDB connection 23 | @display {label: "Connection"} 24 | ConnectionParameters|string connection; 25 | # The additional connection options for the MongoDB connection 26 | @display {label: "Connection Options"} 27 | ConnectionProperties options?; 28 | |}; 29 | 30 | # Represents the MongoDB server address. 31 | @display {label: "Server Address"} 32 | public type ServerAddress record {| 33 | # The host address of the MongoDB server 34 | @display {label: "Host"} 35 | string host = "localhost"; 36 | # The port of the MongoDB server 37 | @display {label: "Port"} 38 | int port = 27017; 39 | |}; 40 | 41 | # Represents the MongoDB connection parameters. 42 | @display {label: "Connection Parameters"} 43 | public type ConnectionParameters record {| 44 | # Server address (or the list of server addresses for replica sets) of the MongoDB server 45 | @display {label: "Server Address"} 46 | ServerAddress|ServerAddress[] serverAddress = {}; 47 | # The authentication configurations for the MongoDB connection 48 | @display {label: "Authentication"} 49 | BasicAuthCredential|ScramSha1AuthCredential|ScramSha256AuthCredential|X509Credential|GssApiCredential auth?; 50 | |}; 51 | 52 | # Represents the Basic Authentication configurations for MongoDB. 53 | @display {label: "Basic Auth Credential"} 54 | public type BasicAuthCredential record {| 55 | # The authentication mechanism to use 56 | @display {label: "Auth Mechanism"} 57 | readonly AUTH_PLAIN authMechanism = AUTH_PLAIN; 58 | # The username for the database connection 59 | @display {label: "Username"} 60 | string username; 61 | # The password for the database connection 62 | @display {label: "Password"} 63 | string password; 64 | # The source database for authenticate the client. Usually the database name 65 | @display {label: "Auth Source Database"} 66 | string database; 67 | |}; 68 | 69 | # Represents the SCRAM-SHA-1 authentication configurations for MongoDB. 70 | @display {label: "SCRAM-SHA-1 Credential"} 71 | public type ScramSha1AuthCredential record {| 72 | # The authentication mechanism to use 73 | @display {label: "Auth Mechanism"} 74 | readonly AUTH_SCRAM_SHA_1 authMechanism = AUTH_SCRAM_SHA_1; 75 | # The username for the database connection 76 | @display {label: "Username"} 77 | string username; 78 | # The password for the database connection 79 | @display {label: "Password"} 80 | string password; 81 | # The source database for authenticate the client. Usually the database name 82 | @display {label: "Auth Source Database"} 83 | string database; 84 | |}; 85 | 86 | # Represents the SCRAM-SHA-256 authentication configurations for MongoDB. 87 | @display {label: "SCRAM-SHA-256 Credential"} 88 | public type ScramSha256AuthCredential record {| 89 | # The authentication mechanism to use 90 | @display {label: "Auth Mechanism"} 91 | readonly AUTH_SCRAM_SHA_256 authMechanism = AUTH_SCRAM_SHA_256; 92 | # The username for the database connection 93 | @display {label: "Username"} 94 | string username; 95 | # The password for the database connection 96 | @display {label: "Password"} 97 | string password; 98 | # The source database for authenticate the client. Usually the database name 99 | @display {label: "Auth Source Database"} 100 | string database; 101 | |}; 102 | 103 | # Represents the X509 authentication configurations for MongoDB. 104 | @display {label: "X509 Credential"} 105 | public type X509Credential record {| 106 | # The authentication mechanism to use 107 | @display {label: "Auth Mechanism"} 108 | readonly AUTH_MONGODB_X509 authMechanism = AUTH_MONGODB_X509; 109 | # The username for authenticating the client certificate 110 | @display {label: "Username"} 111 | string username?; 112 | |}; 113 | 114 | # Represents the GSSAPI authentication configurations for MongoDB. 115 | @display {label: "GSSAPI Credential"} 116 | public type GssApiCredential record {| 117 | # The authentication mechanism to use 118 | @display {label: "Auth Mechanism"} 119 | readonly AUTH_GSSAPI authMechanism = AUTH_GSSAPI; 120 | # The username for the database connection 121 | @display {label: "Username"} 122 | string username; 123 | # The service name for the database connection. Use this to override the default service name of `mongodb` 124 | @display {label: "Service Name"} 125 | string serviceName?; 126 | |}; 127 | 128 | # Represents the MongoDB connection pool properties. 129 | @display {label: "Connection Properties"} 130 | public type ConnectionProperties record {| 131 | # The read concern level to use 132 | @display {label: "Read Concern"} 133 | ReadConcern readConcern?; 134 | # The write concern level to use 135 | @display {label: "Write Concern"} 136 | string writeConcern?; 137 | # The read preference for the replica set 138 | @display {label: "Read Preference"} 139 | string readPreference?; 140 | # The replica set name if it is to connect to replicas 141 | @display {label: "Replica Set"} 142 | string replicaSet?; 143 | # Whether SSL connection is enabled 144 | @display {label: "SSL Enabled"} 145 | boolean sslEnabled = false; 146 | # Whether invalid host names should be allowed 147 | @display {label: "SSL Invalid Host Name Allowed"} 148 | boolean invalidHostNameAllowed = false; 149 | # Configurations related to facilitating secure connection 150 | @display {label: "Secure Socket"} 151 | SecureSocket secureSocket?; 152 | # Whether to retry writing failures 153 | @display {label: "Retry Writes"} 154 | boolean retryWrites?; 155 | # The timeout for the socket 156 | @display {label: "Socket Timeout"} 157 | int socketTimeout?; 158 | # The timeout for the connection 159 | @display {label: "Connection Timeout"} 160 | int connectionTimeout?; 161 | # The maximum connection pool size 162 | @display {label: "Maximum Pool Size"} 163 | int maxPoolSize?; 164 | # The maximum idle time for a pooled connection in milliseconds 165 | @display {label: "Maximum Idle Time"} 166 | int maxIdleTime?; 167 | # The maximum life time for a pooled connection in milliseconds 168 | @display {label: "Maximum Life Time"} 169 | int maxLifeTime?; 170 | # The minimum connection pool size 171 | @display {label: "Minimum Pool Size"} 172 | int minPoolSize?; 173 | # The local threshold latency in milliseconds 174 | @display {label: "Local Threshold"} 175 | int localThreshold?; 176 | # The heartbeat frequency in milliseconds. This is the frequency that the driver will attempt 177 | # to determine the current state of each server in the cluster. 178 | @display {label: "Heartbeat Frequency"} 179 | int heartbeatFrequency?; 180 | |}; 181 | 182 | # Represents the configurations related to facilitating secure connection. 183 | @display {label: "Secure Socket"} 184 | public type SecureSocket record {| 185 | # Configurations associated with the TrustStore 186 | @display {label: "Trust Store"} 187 | crypto:TrustStore trustStore; 188 | # Configurations associated with the KeyStore 189 | @display {label: "Key Store"} 190 | crypto:KeyStore keyStore; 191 | # The standard name of the requested protocol 192 | @display {label: "Protocol"} 193 | string protocol; 194 | |}; 195 | 196 | # The PLAIN authentication mechanism. 197 | public const AUTH_PLAIN = "PLAIN"; 198 | 199 | # The SCRAM-SHA-1 authentication mechanism. 200 | public const AUTH_SCRAM_SHA_1 = "SCRAM_SHA_1"; 201 | 202 | # The SCRAM-SHA-256 authentication mechanism. 203 | public const AUTH_SCRAM_SHA_256 = "SCRAM_SHA_256"; 204 | 205 | # The X509 authentication mechanism. 206 | public const AUTH_MONGODB_X509 = "MONGODB_X509"; 207 | 208 | # The GSSAPI authentication mechanism. 209 | public const AUTH_GSSAPI = "GSSAPI"; 210 | 211 | # Read concern level. 212 | public enum ReadConcern { 213 | LOCAL = "local", 214 | AVAILABLE = "available", 215 | MAJORITY = "majority", 216 | LINEARIZABLE = "linearizable", 217 | SNAPSHOT = "snapshot" 218 | }; 219 | 220 | # Represents the options for the `Collection.insertOne()` operation. 221 | public type InsertOneOptions record {| 222 | # The comment to send with the operation 223 | @display {label: "Comment"} 224 | string comment?; 225 | # Whether to bypass the document validation 226 | @display {label: "Bypass Document Validation"} 227 | boolean bypassDocumentValidation = false; 228 | |}; 229 | 230 | # Represents the options for the `Collection.insertMany()` operation. 231 | public type InsertManyOptions record {| 232 | # The comment to send with the operation 233 | @display {label: "Comment"} 234 | string comment?; 235 | # Whether to bypass the document validation 236 | @display {label: "Bypass Document Validation"} 237 | boolean bypassDocumentValidation = false; 238 | # Whether to insert documents in the order provided 239 | @display {label: "Ordered"} 240 | boolean ordered = true; 241 | |}; 242 | 243 | # Represents the options for the `Collection.find()` operation. 244 | public type FindOptions record {| 245 | # The sort options for the query 246 | map sort = {}; 247 | # The maximum limit of the number of documents to retrive. -1 means no limit 248 | int 'limit?; 249 | # The batch size of the query 250 | int batchSize?; 251 | # The number of documents to skip 252 | int skip?; 253 | |}; 254 | 255 | # Represents the options for the `Collection.countDocuments()` operation. 256 | public type CountOptions record {| 257 | # The maximum limit of the number of documents to count 258 | int 'limit?; 259 | # The number of documents to skip 260 | int skip?; 261 | # The maximum time to count documents in milliseconds 262 | int maxTimeMS?; 263 | # The hint to use 264 | string hint?; 265 | |}; 266 | 267 | # Represents the options for the `Collection.createIndex()` operation. 268 | public type CreateIndexOptions record {| 269 | # Whether to create the index in the background 270 | @display {label: "Background"} 271 | boolean background?; 272 | # Whether to create a unique index 273 | @display {label: "Unique"} 274 | boolean unique?; 275 | # Name of the index 276 | @display {label: "Index Name"} 277 | string name?; 278 | # Should the index only reference documents with the specified field 279 | @display {label: "Sparse"} 280 | boolean sparse?; 281 | # The time to live for documents in the collection in seconds 282 | @display {label: "Time to Live"} 283 | int expireAfterSeconds?; 284 | # The version of the index 285 | @display {label: "Version"} 286 | int version?; 287 | # Sets the weighting object for use with a text index 288 | @display {label: "Weights"} 289 | map weights?; 290 | # The default language for the index 291 | @display {label: "Default Language"} 292 | string defaultLanguage?; 293 | # Sets the name of the field that contains the language string 294 | @display {label: "Language Override"} 295 | string languageOverride?; 296 | # Set the text index version number 297 | @display {label: "Text Index Version"} 298 | int textVersion?; 299 | # Sets the 2D sphere index version number 300 | @display {label: "2D Sphere Index Version"} 301 | int sphereVersion?; 302 | # Sets the number of precision of the stored geohash value of the location data in 2D indexes 303 | @display {label: "Bits"} 304 | int bits?; 305 | # Sets the lower inclusive boundary for the longitude and latitude values for 2D indexes 306 | @display {label: "Min"} 307 | float min?; 308 | # Sets the upper inclusive boundary for the longitude and latitude values for 2D indexes 309 | @display {label: "Max"} 310 | float max?; 311 | # Sets the filter expression for the documents to be included in the index 312 | @display {label: "Partial Filter Expression"} 313 | map partialFilterExpression = {}; 314 | # Should the index be hidden from the query planner 315 | @display {label: "Hidden"} 316 | boolean hidden?; 317 | |}; 318 | 319 | # Represents the options for the `Collection.updateOne()` operation. 320 | public type UpdateOptions record {| 321 | # Whether to upsert if the document does not exist 322 | @display {label: "Upsert"} 323 | boolean upsert = false; 324 | # Whether to bypass the document validation 325 | @display {label: "Bypass Document Validation"} 326 | boolean bypassDocumentValidation = false; 327 | # The comment to send with the operation 328 | @display {label: "Comment"} 329 | string comment?; 330 | # The hint to use 331 | @display {label: "Hint"} 332 | map hint?; 333 | # The hint string to use 334 | @display {label: "Hint String"} 335 | string hintString?; 336 | |}; 337 | 338 | # Represents the options for the `Collection.deleteOne()` operation. 339 | public type DeleteOptions record {| 340 | # The comment to send with the operation 341 | @display {label: "Comment"} 342 | string comment?; 343 | # The hint to use 344 | @display {label: "Hint"} 345 | map hint?; 346 | # The hint string to use 347 | @display {label: "Hint String"} 348 | string hintString?; 349 | |}; 350 | 351 | # Represents a MongoDB collection index. 352 | public type Index record { 353 | # The name space of the index 354 | @display {label: "Name Space"} 355 | string ns; 356 | # The index version 357 | @display {label: "Version"} 358 | int v; 359 | # The name of the index 360 | @display {label: "Name"} 361 | string name; 362 | # The key of the index 363 | @display {label: "Key"} 364 | map key; 365 | }; 366 | 367 | # Represents an update operation for single entry. 368 | public type Update record {| 369 | # Sets the value of a field to the current date, either as a Date or a Timestamp 370 | map currentDate?; 371 | # Increments the value of the field by the specified amount 372 | map inc?; 373 | # Only updates the field if the specified value is less than the existing field value 374 | map min?; 375 | # Only updates the field if the specified value is greater than the existing field value 376 | map max?; 377 | # Multiplies the value of the field by the specified amount 378 | map mul?; 379 | # Renames a field 380 | map rename?; 381 | # Sets the value of a field in a document 382 | map set?; 383 | # Sets the value of a field if it is an insert operation 384 | map setOnInsert?; 385 | # Unsets the value of a field in a document 386 | map unset?; 387 | // Allow user to add additional operators 388 | map...; 389 | |}; 390 | 391 | # Repsents the return type of the Update operation. 392 | public type UpdateResult record {| 393 | # The number of documents matched by the update operation 394 | @display {label: "Matched Count"} 395 | int matchedCount; 396 | # The number of documents modified by the update operation 397 | @display {label: "Modified Count"} 398 | int modifiedCount; 399 | # The identifier of the inserted document if the upsert option is used 400 | @display {label: "Upserted Id"} 401 | string upsertedId?; 402 | |}; 403 | 404 | # Represents the return type of the Delete operation. 405 | public type DeleteResult record {| 406 | # The number of documents deleted by the delete operation 407 | @display {label: "Deleted Count"} 408 | int deletedCount; 409 | # Whether the delete operation was acknowledged 410 | @display {label: "Acknowledged"} 411 | boolean acknowledged; 412 | |}; 413 | -------------------------------------------------------------------------------- /build-config/checkstyle/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | plugins { 20 | id "de.undercouch.download" 21 | } 22 | 23 | apply plugin: 'java-library' 24 | 25 | task downloadCheckstyleRuleFiles(type: Download) { 26 | src([ 27 | 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/checkstyle.xml', 28 | 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/suppressions.xml' 29 | ]) 30 | overwrite false 31 | onlyIfNewer true 32 | dest buildDir 33 | } 34 | 35 | jar { 36 | enabled = false 37 | } 38 | 39 | clean { 40 | enabled = false 41 | } 42 | 43 | artifacts.add('default', file("$project.buildDir/checkstyle.xml")) { 44 | builtBy('downloadCheckstyleRuleFiles') 45 | } 46 | 47 | artifacts.add('default', file("$project.buildDir/suppressions.xml")) { 48 | builtBy('downloadCheckstyleRuleFiles') 49 | } 50 | -------------------------------------------------------------------------------- /build-config/resources/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | distribution = "2201.11.0-20241218-101200-109f6cc7" 3 | org = "ballerinax" 4 | name = "mongodb" 5 | version = "@toml.version@" 6 | license= ["Apache-2.0"] 7 | authors = ["Ballerina"] 8 | keywords = ["IT Operations/Databases", "Cost/Freemium"] 9 | icon = "icon.png" 10 | repository = "https://github.com/ballerina-platform/module-ballerinax-mongodb" 11 | 12 | [platform.java21] 13 | graalvmCompatible = true 14 | 15 | [[platform.java21.dependency]] 16 | groupId = "io.ballerina.lib" 17 | artifactId = "mongodb-native" 18 | version = "@project.version@" 19 | path = "../native/build/libs/mongodb-native-@project.version@.jar" 20 | 21 | [[platform.java21.dependency]] 22 | groupId = "org.mongodb" 23 | artifactId = "mongodb-driver-sync" 24 | version = "@mongodb.driver.version@" 25 | path = "./lib/mongodb-driver-sync-@mongodb.driver.version@.jar" 26 | 27 | [[platform.java21.dependency]] 28 | groupId = "org.mongodb" 29 | artifactId = "mongodb-driver-core" 30 | version = "@mongodb.driver.version@" 31 | path = "./lib/mongodb-driver-core-@mongodb.driver.version@.jar" 32 | 33 | [[platform.java21.dependency]] 34 | groupId = "org.mongodb" 35 | artifactId = "bson" 36 | version = "@mongodb.driver.version@" 37 | path = "./lib/bson-@mongodb.driver.version@.jar" 38 | -------------------------------------------------------------------------------- /build-config/spotbugs-exclude.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | import org.apache.tools.ant.taskdefs.condition.Os 19 | 20 | plugins { 21 | id "com.github.spotbugs-base" 22 | id "com.github.johnrengelman.shadow" 23 | id "de.undercouch.download" 24 | id "net.researchgate.release" 25 | } 26 | 27 | description = 'Ballerina - Mongodb' 28 | 29 | allprojects { 30 | group = project.group 31 | version = project.version 32 | 33 | apply plugin: 'jacoco' 34 | apply plugin: 'maven-publish' 35 | 36 | repositories { 37 | mavenLocal() 38 | 39 | maven { 40 | url = 'https://maven.wso2.org/nexus/content/groups/wso2-public/' 41 | } 42 | 43 | maven { 44 | url = 'https://repo.maven.apache.org/maven2' 45 | } 46 | 47 | maven { 48 | url = 'https://maven.pkg.github.com/ballerina-platform/ballerina-lang' 49 | credentials { 50 | username System.getenv("packageUser") 51 | password System.getenv("packagePAT") 52 | } 53 | } 54 | } 55 | 56 | ext { 57 | snapshotVersion = '-SNAPSHOT' 58 | timestampedVersionRegex = '.*-\\d{8}-\\d{6}-\\w.*\$' 59 | } 60 | } 61 | 62 | task build { 63 | dependsOn(":mongodb-native:build") 64 | dependsOn(":mongodb-ballerina:build") 65 | } 66 | 67 | def moduleVersion = project.version.replace("-SNAPSHOT", "") 68 | 69 | release { 70 | buildTasks = ['build'] 71 | failOnSnapshotDependencies = true 72 | versionPropertyFile = 'gradle.properties' 73 | tagTemplate = 'v${version}' 74 | git { 75 | requireBranch = "release-${moduleVersion}" 76 | pushToRemote = 'origin' 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | This file contains all the notable changes done to the Ballerina GraphQL package through the releases. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to 5 | [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ### Changed 10 | 11 | - [[#5073] Revamping the connector with new Client, Database, and Collection model](https://github.com/ballerina-platform/ballerina-standard-library/issues/5073) 12 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | fixes: 2 | - "ballerina/mongodb/**/::../ballerina/" 3 | 4 | coverage: 5 | precision: 2 6 | round: down 7 | range: "60...80" 8 | status: 9 | project: 10 | default: 11 | target: 80 12 | -------------------------------------------------------------------------------- /docs/setup/resources/mongodb-atlas-connection-method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/71fd7531bea6eac54a49881fd631c8adb0856cb1/docs/setup/resources/mongodb-atlas-connection-method.png -------------------------------------------------------------------------------- /docs/setup/resources/mongodb-atlas-database-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/71fd7531bea6eac54a49881fd631c8adb0856cb1/docs/setup/resources/mongodb-atlas-database-page.png -------------------------------------------------------------------------------- /docs/setup/resources/mongodb-atlas-ip-access-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/71fd7531bea6eac54a49881fd631c8adb0856cb1/docs/setup/resources/mongodb-atlas-ip-access-list.png -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | The `ballerinax/mongodb` connector provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples), covering use cases like movie database, order management service, and more. 4 | 5 | 1. [Movie Database](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/movie-database) - Implement a movie database using MongoDB. 6 | 7 | 2. [Order Management System](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/order-management-system) - Use MongoDB to manage orders in an online store. 8 | 9 | ## Prerequisites 10 | 11 | 1. Ensure you have MongoDB server installed and running locally or on a server accessible by your application. Refer to the [Setup Guide](https://central.ballerina.io/ballerinax/mongodb/latest#setup-guide) to set up the MongoDB server locally. 12 | 13 | Alternatively, you can use the docker-compose file provided in the `https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/resources/docker` directory to start a MongoDB server as a Docker container. 14 | 15 | 2. For each example, create a `Config.toml` file with your MongoDB server configuration. Here's an example of how your `Config.toml` file should look: 16 | 17 | ```toml 18 | host="localhost" 19 | port=27017 20 | ``` 21 | 22 | > **Note:** This can be used with the docker-compose file provided. 23 | 24 | ## Running an Example 25 | 26 | Execute the following commands to build an example from the source: 27 | 28 | * To build an example: 29 | 30 | ```bash 31 | bal build 32 | ``` 33 | 34 | * To run an example: 35 | 36 | ```bash 37 | bal run 38 | ``` 39 | -------------------------------------------------------------------------------- /examples/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import org.apache.tools.ant.taskdefs.condition.Os 20 | 21 | apply plugin: 'java' 22 | 23 | def graalvmFlag = "" 24 | 25 | task testExamples { 26 | if (project.hasProperty("balGraalVMTest")) { 27 | graalvmFlag = "--graalvm" 28 | } 29 | doLast { 30 | try { 31 | exec { 32 | workingDir project.projectDir 33 | println("Working dir: ${workingDir}") 34 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 35 | commandLine 'cmd', "/c", "chmod +x ./build.sh && ./build.sh test && exit %%ERRORLEVEL%%" 36 | } else { 37 | commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh test" 38 | } 39 | } 40 | } catch (Exception e) { 41 | println("Example Build failed: " + e.message) 42 | throw e 43 | } 44 | } 45 | } 46 | 47 | task buildExamples { 48 | gradle.taskGraph.whenReady { graph -> 49 | if (graph.hasTask(":mongodb-examples:test")) { 50 | buildExamples.enabled = false 51 | } else { 52 | testExamples.enabled = false 53 | } 54 | } 55 | doLast { 56 | try { 57 | exec { 58 | workingDir project.projectDir 59 | println("Working dir: ${workingDir}") 60 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 61 | commandLine 'cmd', "/c", "chmod +x ./build.sh && ./build.sh build && exit %%ERRORLEVEL%%" 62 | } else { 63 | commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh build" 64 | } 65 | } 66 | } catch (Exception e) { 67 | println("Example Build failed: " + e.message) 68 | throw e 69 | } 70 | } 71 | } 72 | 73 | buildExamples.dependsOn ":mongodb-ballerina:build" 74 | testExamples.dependsOn ":mongodb-ballerina:build" 75 | 76 | test.dependsOn testExamples 77 | build.dependsOn buildExamples 78 | -------------------------------------------------------------------------------- /examples/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) 5 | # 6 | # WSO2 LLC. licenses this file to you under the Apache License, 7 | # Version 2.0 (the "License"); you may not use this file except 8 | # in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # 20 | 21 | BAL_EXAMPLES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 22 | BAL_CENTRAL_DIR="$HOME/.ballerina/repositories/central.ballerina.io" 23 | BAL_HOME_DIR="$BAL_EXAMPLES_DIR/../ballerina" 24 | 25 | set -e 26 | 27 | case "$1" in 28 | build) 29 | BAL_CMD="build" 30 | ;; 31 | test) 32 | BAL_CMD="test" 33 | ;; 34 | *) 35 | echo "Invalid command provided: '$1'. Please provide 'build' or 'test' as the command." 36 | exit 1 37 | ;; 38 | esac 39 | 40 | # Read Ballerina package name 41 | BAL_PACKAGE_NAME=$(awk -F'"' '/^name/ {print $2}' "$BAL_HOME_DIR/Ballerina.toml") 42 | 43 | # Push the package to the local repository 44 | cd "$BAL_HOME_DIR" && 45 | bal pack && 46 | bal push --repository=local 47 | 48 | # Remove the cache directories in the repositories 49 | cacheDirs=$(ls -d $BAL_CENTRAL_DIR/cache-* 2>/dev/null) || true 50 | for dir in "${cacheDirs[@]}"; do 51 | [ -d "$dir" ] && rm -r "$dir" 52 | done 53 | echo "Successfully cleaned the cache directories" 54 | 55 | # Create the package directory in the central repository, this will not be present if no modules are pulled 56 | mkdir -p "$BAL_CENTRAL_DIR/bala/ballerinax/$BAL_PACKAGE_NAME" 57 | 58 | # Update the central repository 59 | BAL_DESTINATION_DIR="$HOME/.ballerina/repositories/central.ballerina.io/bala/ballerinax/$BAL_PACKAGE_NAME" 60 | BAL_SOURCE_DIR="$HOME/.ballerina/repositories/local/bala/ballerinax/$BAL_PACKAGE_NAME" 61 | [ -d "$BAL_DESTINATION_DIR" ] && rm -r "$BAL_DESTINATION_DIR" 62 | [ -d "$BAL_SOURCE_DIR" ] && cp -r "$BAL_SOURCE_DIR" "$BAL_DESTINATION_DIR" 63 | echo "Successfully updated the local central repositories" 64 | 65 | echo "$BAL_DESTINATION_DIR" 66 | echo "$BAL_SOURCE_DIR" 67 | 68 | # Loop through examples in the examples directory 69 | cd "$BAL_EXAMPLES_DIR" 70 | while IFS= read -r -d '' dir 71 | do 72 | # Skip the build and resources directories 73 | if [[ "$dir" == *build ]] || [[ "$dir" == *resources ]]; then 74 | continue 75 | fi 76 | echo "$dir" 77 | (cd "$dir" && bal "$BAL_CMD" --offline && cd ..); 78 | done 79 | 80 | # Remove generated JAR files 81 | find "$BAL_HOME_DIR" -maxdepth 1 -type f -name "*.jar" | while read -r JAR_FILE; do 82 | rm "$JAR_FILE" 83 | done 84 | -------------------------------------------------------------------------------- /examples/movie-database/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Ballerina MongoDB movie database.md -------------------------------------------------------------------------------- /examples/movie-database/Ballerina MongoDB movie database.md: -------------------------------------------------------------------------------- 1 | # Movie database 2 | 3 | This example demonstrates how to do basic CRUD operation on a MongoDB database using the Ballerina MongoDB connector. It exposes an HTTP service with resources to add, retrieve, update, and delete movies from a MongoDB database. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Setup MongoDB server 8 | 9 | Ensure you have download and running a MongoDB server. (Alternatively, [provided docker-compose-file](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/resources/docker/docker-compose.yml) can be used to run the MongoDB server). 10 | 11 | ### 2. Configuration 12 | 13 | Create a `Config.toml` file inside the Ballerina project root directory with your MongoDB server configuration. Here's an example of how your `Config.toml` file should look: 14 | 15 | ```toml 16 | host = "localhost" 17 | port = 27017 18 | 19 | username = "admin" 20 | password = "admin" 21 | database = "admin" 22 | ``` 23 | 24 | ## Run the example 25 | 26 | To run the example, execute the following command. 27 | 28 | ```bash 29 | bal run 30 | ``` 31 | 32 | This will start an HTTP server at `http://localhost:9090/`. 33 | -------------------------------------------------------------------------------- /examples/movie-database/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "movie_database" 4 | version = "1.0.0" 5 | -------------------------------------------------------------------------------- /examples/movie-database/server.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/http; 18 | import ballerina/uuid; 19 | import ballerinax/mongodb; 20 | 21 | configurable string host = "localhost"; 22 | configurable int port = 27017; 23 | 24 | configurable string username = ?; 25 | configurable string password = ?; 26 | configurable string database = ?; 27 | 28 | final mongodb:Client mongoDb = check new ({ 29 | connection: { 30 | serverAddress: { 31 | host, 32 | port 33 | }, 34 | auth: { 35 | username, 36 | password, 37 | database 38 | } 39 | } 40 | }); 41 | 42 | service on new http:Listener(9091) { 43 | private final mongodb:Database moviesDb; 44 | 45 | function init() returns error? { 46 | self.moviesDb = check mongoDb->getDatabase("movies"); 47 | } 48 | 49 | resource function get movies() returns Movie[]|error { 50 | mongodb:Collection movies = check self.moviesDb->getCollection("movies"); 51 | stream result = check movies->find(); 52 | return from Movie m in result 53 | select m; 54 | } 55 | 56 | resource function get movies/[string id]() returns Movie|error { 57 | return getMovie(self.moviesDb, id); 58 | } 59 | 60 | resource function post movies(MovieInput input) returns Movie|error { 61 | string id = uuid:createType1AsString(); 62 | Movie movie = {id, ...input}; 63 | mongodb:Collection movies = check self.moviesDb->getCollection("movies"); 64 | check movies->insertOne(movie); 65 | return movie; 66 | } 67 | 68 | resource function put movies/[string id](MovieUpdate update) returns Movie|error { 69 | mongodb:Collection movies = check self.moviesDb->getCollection("movies"); 70 | mongodb:UpdateResult updateResult = check movies->updateOne({id}, {set: update}); 71 | if updateResult.modifiedCount != 1 { 72 | return error(string `Failed to update the movie with id ${id}`); 73 | } 74 | return getMovie(self.moviesDb, id); 75 | } 76 | 77 | resource function delete movies/[string id]() returns string|error { 78 | mongodb:Collection movies = check self.moviesDb->getCollection("movies"); 79 | mongodb:DeleteResult deleteResult = check movies->deleteOne({id}); 80 | if deleteResult.deletedCount != 1 { 81 | return error(string `Failed to delete the movie ${id}`); 82 | } 83 | return id; 84 | } 85 | } 86 | 87 | isolated function getMovie(mongodb:Database moviesDb, string id) returns Movie|error { 88 | mongodb:Collection movies = check moviesDb->getCollection("movies"); 89 | stream findResult = check movies->find({id}); 90 | Movie[] result = check from Movie m in findResult 91 | select m; 92 | if result.length() != 1 { 93 | return error(string `Failed to find a movie with id ${id}`); 94 | } 95 | return result[0]; 96 | } 97 | 98 | public type MovieInput record {| 99 | string title; 100 | int year; 101 | string directorId; 102 | |}; 103 | 104 | public type MovieUpdate record {| 105 | string title?; 106 | int year?; 107 | string directorId?; 108 | |}; 109 | 110 | public type Movie record {| 111 | readonly string id; 112 | *MovieInput; 113 | |}; 114 | -------------------------------------------------------------------------------- /examples/order-management-system/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Ballerina MongoDB order management system.md -------------------------------------------------------------------------------- /examples/order-management-system/Ballerina MongoDB order management system.md: -------------------------------------------------------------------------------- 1 | # Order management system 2 | 3 | This example demonstrates an implementation of sample order management system using Ballerina and the Ballerina MongoDB connector. It exposes an HTTP service with resources to add, retrieve, update, and delete orders from a MongoDB database. Additionally, this example includes an aggregation operation to retrieve the orders of a given customer. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Setup MongoDB server 8 | 9 | Ensure you have download and running a MongoDB server. (Alternatively, [provided docker-compose-file](https://github.com/ballerina-platform/module-ballerinax-mongodb/tree/master/examples/resources/docker/docker-compose.yml) can be used to run the MongoDB server). 10 | 11 | ### 2. Configuration 12 | 13 | Create a `Config.toml` file inside the Ballerina project root directory with your MongoDB server configuration. Here's an example of how your `Config.toml` file should look: 14 | 15 | ```toml 16 | host = "localhost" 17 | port = 27017 18 | 19 | username = "admin" 20 | password = "admin" 21 | database = "admin" 22 | ``` 23 | 24 | ## Run the example 25 | 26 | To run the example, execute the following command. 27 | 28 | ```bash 29 | bal run 30 | ``` 31 | 32 | This will start an HTTP server at `http://localhost:9090/`. 33 | -------------------------------------------------------------------------------- /examples/order-management-system/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "wso2" 3 | name = "movie_database" 4 | version = "1.0.0" 5 | -------------------------------------------------------------------------------- /examples/order-management-system/server.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/http; 18 | import ballerina/uuid; 19 | import ballerinax/mongodb; 20 | 21 | configurable string host = "localhost"; 22 | configurable int port = 27017; 23 | 24 | configurable string username = ?; 25 | configurable string password = ?; 26 | configurable string database = ?; 27 | 28 | final mongodb:Client mongoDb = check new ({ 29 | connection: { 30 | serverAddress: { 31 | host, 32 | port 33 | }, 34 | auth: { 35 | username, 36 | password, 37 | database 38 | } 39 | } 40 | }); 41 | 42 | service on new http:Listener(9092) { 43 | 44 | private final mongodb:Database db; 45 | 46 | function init() returns error? { 47 | self.db = check mongoDb->getDatabase("order_management"); 48 | } 49 | 50 | resource function get customers() returns Customer[]|error { 51 | mongodb:Collection customersCollection = check self.db->getCollection("customers"); 52 | stream resultStream = check customersCollection->aggregate([ 53 | { 54 | \$lookup: { 55 | 'from: "orders", 56 | localField: "id", 57 | foreignField: "customerId", 58 | 'as: "orders" 59 | } 60 | } 61 | ]); 62 | return from Customer customer in resultStream select customer; 63 | } 64 | 65 | resource function post customers(CustomerInput input) returns error? { 66 | mongodb:Collection customersCollection = check self.db->getCollection("customers"); 67 | string id = uuid:createType1AsString(); 68 | Customer customer = { 69 | id, 70 | orders: [], 71 | ...input 72 | }; 73 | check customersCollection->insertOne(customer); 74 | } 75 | 76 | resource function get customers/[string id]() returns Customer|error { 77 | mongodb:Collection customersCollection = check self.db->getCollection("customers"); 78 | stream resultStream = check customersCollection->aggregate([ 79 | { 80 | \$match: { 81 | id: id 82 | } 83 | }, 84 | { 85 | \$lookup: { 86 | 'from: "orders", 87 | localField: "id", 88 | foreignField: "customerId", 89 | 'as: "orders" 90 | } 91 | }, 92 | { 93 | \$limit: 1 94 | }, 95 | { 96 | \$project: { 97 | id: 1, 98 | name: 1, 99 | email: 1, 100 | address: 1, 101 | contactNumber: 1, 102 | orders: { 103 | id: {"orders.id": 1}, 104 | customerId: {"orders.customerId": 1}, 105 | status: {"orders.status": 1}, 106 | quantity: {"orders.quantity": 1}, 107 | total: {"orders.total": 1} 108 | } 109 | } 110 | } 111 | ]); 112 | record {Customer value;}|error? result = resultStream.next(); 113 | if result is error? { 114 | return error(string `Cannot find the customer with id: ${id}`); 115 | } 116 | return result.value; 117 | } 118 | 119 | resource function post orders(OrderInput input) returns error? { 120 | mongodb:Collection ordersCollection = check self.db->getCollection("orders"); 121 | string id = uuid:createType1AsString(); 122 | Order 'order = { 123 | id, 124 | ...input 125 | }; 126 | check ordersCollection->insertOne('order); 127 | } 128 | } 129 | 130 | type CustomerInput record {| 131 | string name; 132 | string email; 133 | string address; 134 | string contactNumber; 135 | |}; 136 | 137 | type OrderInput record {| 138 | string customerId; 139 | string status; 140 | int quantity; 141 | decimal total; 142 | |}; 143 | 144 | type Customer record {| 145 | string id; 146 | string name; 147 | string email; 148 | string address; 149 | string contactNumber; 150 | Order[] orders; 151 | |}; 152 | 153 | type Order record {| 154 | string id; 155 | string customerId; 156 | string status; 157 | int quantity; 158 | decimal total; 159 | |}; 160 | -------------------------------------------------------------------------------- /examples/resources/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | mongodb: 3 | image: mongo:4.2 4 | restart: always 5 | ports: 6 | - 27017:27017 7 | environment: 8 | MONGO_INITDB_ROOT_USERNAME: admin 9 | MONGO_INITDB_ROOT_PASSWORD: admin 10 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.caching=true 2 | group=io.ballerina.lib 3 | version=5.1.1-SNAPSHOT 4 | ballerinaLangVersion=2201.12.0 5 | 6 | checkstylePluginVersion=10.12.0 7 | spotbugsPluginVersion=6.0.18 8 | shadowJarPluginVersion=8.1.1 9 | downloadPluginVersion=5.4.0 10 | releasePluginVersion=2.8.0 11 | ballerinaGradlePluginVersion=2.3.0 12 | jacocoVersion=0.8.10 13 | 14 | slf4jVersion=1.7.21 15 | mongoDriverVersion=5.1.0 16 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-mongodb/71fd7531bea6eac54a49881fd631c8adb0856cb1/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | if ! command -v java >/dev/null 2>&1 134 | then 135 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 136 | 137 | Please set the JAVA_HOME variable in your environment to match the 138 | location of your Java installation." 139 | fi 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | 201 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 202 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 203 | 204 | # Collect all arguments for the java command; 205 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 206 | # shell script including quotes and variable substitutions, so put them in 207 | # double quotes to make sure that they get re-expanded; and 208 | # * put everything else in single quotes, so that it's not re-expanded. 209 | 210 | set -- \ 211 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 212 | -classpath "$CLASSPATH" \ 213 | org.gradle.wrapper.GradleWrapperMain \ 214 | "$@" 215 | 216 | # Stop when "xargs" is not available. 217 | if ! command -v xargs >/dev/null 2>&1 218 | then 219 | die "xargs is not available" 220 | fi 221 | 222 | # Use "xargs" to parse quoted args. 223 | # 224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 | # 226 | # In Bash we could simply go: 227 | # 228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 | # set -- "${ARGS[@]}" "$@" 230 | # 231 | # but POSIX shell has neither arrays nor command substitution, so instead we 232 | # post-process each arg (as a line of input to sed) to backslash-escape any 233 | # character that might be a shell metacharacter, then use eval to reverse 234 | # that process (while maintaining the separation between arguments), and wrap 235 | # the whole thing up as a single "set" statement. 236 | # 237 | # This will of course break if any of these variables contains a newline or 238 | # an unmatched quote. 239 | # 240 | 241 | eval "set -- $( 242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 | xargs -n1 | 244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 | tr '\n' ' ' 246 | )" '"$@"' 247 | 248 | exec "$JAVACMD" "$@" 249 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /native/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | plugins { 20 | id 'java' 21 | id 'checkstyle' 22 | id 'com.github.spotbugs' 23 | } 24 | 25 | description = 'Ballerina - Mongodb Native' 26 | 27 | configurations { 28 | dist { 29 | transitive true 30 | } 31 | } 32 | 33 | dependencies { 34 | checkstyle project(":checkstyle") 35 | checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}" 36 | 37 | implementation group: 'org.ballerinalang', name: 'ballerina-runtime', version: "${ballerinaLangVersion}" 38 | implementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}" 39 | implementation group: 'org.ballerinalang', name: 'value', version: "${ballerinaLangVersion}" 40 | 41 | implementation group: 'org.slf4j', name: 'slf4j-api', version: "${slf4jVersion}" 42 | implementation group: 'org.mongodb', name: 'mongodb-driver-sync', version: "${mongoDriverVersion}" 43 | implementation group: 'org.mongodb', name: 'mongodb-driver-core', version: "${mongoDriverVersion}" 44 | implementation group: 'org.mongodb', name: 'bson', version: "${mongoDriverVersion}" 45 | } 46 | 47 | tasks.withType(JavaCompile) { 48 | options.encoding = 'UTF-8' 49 | } 50 | 51 | test { 52 | testLogging { 53 | showStackTraces = true 54 | showStandardStreams = true 55 | events "failed" 56 | exceptionFormat "full" 57 | } 58 | jacoco { 59 | enabled = true 60 | destinationFile = file("$buildDir/coverage-reports/jacoco.exec") 61 | includeNoLocationClasses = true 62 | } 63 | } 64 | 65 | spotbugsMain { 66 | def classLoader = plugins["com.github.spotbugs"].class.classLoader 67 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") 68 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") 69 | effort = SpotBugsEffort.MAX 70 | reportLevel = SpotBugsConfidence.LOW 71 | reportsDir = file("$project.buildDir/reports/spotbugs") 72 | def excludeFile = file("${rootDir}/build-config/spotbugs-exclude.xml") 73 | if (excludeFile.exists()) { 74 | it.excludeFilter = excludeFile 75 | } 76 | reports { 77 | xml.enabled = false 78 | html.enabled = true 79 | } 80 | } 81 | 82 | spotbugsTest { 83 | enabled = false 84 | } 85 | 86 | tasks.withType(Checkstyle) { 87 | exclude '**/module-info.java' 88 | } 89 | 90 | checkstyle { 91 | toolVersion "${checkstylePluginVersion}" 92 | configFile file("${rootDir}/build-config/checkstyle/build/checkstyle.xml") 93 | configProperties = ["suppressionFile": file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] 94 | } 95 | 96 | checkstyleMain.dependsOn ':checkstyle:downloadCheckstyleRuleFiles' 97 | 98 | jar { 99 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE 100 | dependsOn configurations.dist 101 | from { configurations.dist.collect { it.isDirectory() ? it : zipTree(it) } } { 102 | exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA' 103 | } 104 | } 105 | 106 | compileJava { 107 | doFirst { 108 | options.compilerArgs = [ 109 | '--module-path', classpath.asPath, 110 | ] 111 | classpath = files() 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/lib/mongodb/AuthUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.lib.mongodb; 20 | 21 | import com.mongodb.MongoCredential; 22 | import io.ballerina.runtime.api.utils.StringUtils; 23 | import io.ballerina.runtime.api.values.BMap; 24 | import io.ballerina.runtime.api.values.BString; 25 | 26 | import static io.ballerina.lib.mongodb.Utils.createError; 27 | 28 | /** 29 | * This class contains the utility methods for authentication configurations in MongoDB client. 30 | * 31 | * @since 5.0.0 32 | */ 33 | final class AuthUtils { 34 | 35 | private AuthUtils() { 36 | } 37 | 38 | private static final String SERVICE_NAME = "SERVICE_NAME"; 39 | 40 | static MongoCredential getMongoCredential(BMap auth) { 41 | String authMechanism = auth.getStringValue(Client.RecordField.AUTH_MECHANISM).getValue(); 42 | switch (AuthMechanism.valueOf(authMechanism)) { 43 | case SCRAM_SHA_1: 44 | return getScramSha1Credential(auth); 45 | case SCRAM_SHA_256: 46 | return getScramSha256Credential(auth); 47 | case MONGODB_X509: 48 | return getMongoX509Credential(auth); 49 | case GSSAPI: 50 | return getGssapiCredential(auth); 51 | case PLAIN: 52 | return getPlainCredential(auth); 53 | default: 54 | throw createError(ErrorType.APPLICATION_ERROR, 55 | "Unsupported authentication mechanism: " + authMechanism); 56 | } 57 | } 58 | 59 | private static MongoCredential getPlainCredential(BMap auth) { 60 | String username = auth.getStringValue(RecordField.USERNAME.getFieldName()).getValue(); 61 | char[] password = auth.getStringValue(RecordField.PASSWORD.getFieldName()).getValue().toCharArray(); 62 | String source = auth.getStringValue(RecordField.DATABASE.getFieldName()).getValue(); 63 | return MongoCredential.createPlainCredential(username, source, password); 64 | } 65 | 66 | private static MongoCredential getScramSha1Credential(BMap auth) { 67 | String username = auth.getStringValue(RecordField.USERNAME.getFieldName()).getValue(); 68 | char[] password = auth.getStringValue(RecordField.PASSWORD.getFieldName()).getValue().toCharArray(); 69 | String source = auth.getStringValue(RecordField.DATABASE.getFieldName()).getValue(); 70 | return MongoCredential.createScramSha1Credential(username, source, password); 71 | } 72 | 73 | private static MongoCredential getScramSha256Credential(BMap auth) { 74 | String username = auth.getStringValue(RecordField.USERNAME.getFieldName()).getValue(); 75 | char[] password = auth.getStringValue(RecordField.PASSWORD.getFieldName()).getValue().toCharArray(); 76 | String source = auth.getStringValue(RecordField.DATABASE.getFieldName()).getValue(); 77 | return MongoCredential.createScramSha256Credential(username, source, password); 78 | } 79 | 80 | private static MongoCredential getMongoX509Credential(BMap auth) { 81 | if (auth.getStringValue(RecordField.USERNAME.getFieldName()) == null) { 82 | return MongoCredential.createMongoX509Credential(); 83 | } 84 | String username = auth.getStringValue(RecordField.USERNAME.getFieldName()).getValue(); 85 | return MongoCredential.createMongoX509Credential(username); 86 | } 87 | 88 | private static MongoCredential getGssapiCredential(BMap auth) { 89 | String username = auth.getStringValue(RecordField.USERNAME.getFieldName()).getValue(); 90 | BString serviceName = auth.getStringValue(RecordField.SERVICE_NAME.getFieldName()); 91 | if (serviceName != null) { 92 | return MongoCredential.createGSSAPICredential(username) 93 | .withMechanismProperty(SERVICE_NAME, serviceName.getValue()); 94 | } 95 | return MongoCredential.createGSSAPICredential(username); 96 | } 97 | 98 | enum AuthMechanism { 99 | SCRAM_SHA_1("SCRAM-SHA-1"), 100 | SCRAM_SHA_256("SCRAM-SHA-256"), 101 | MONGODB_X509("MONGODB-X509"), 102 | GSSAPI("GSSAPI"), 103 | PLAIN("PLAIN"), 104 | AWS("AWS"), 105 | MONGODB_CR("MONGODB-CR"); 106 | 107 | private final String mechanism; 108 | 109 | AuthMechanism(String mechanism) { 110 | this.mechanism = mechanism; 111 | } 112 | 113 | public String getMechanism() { 114 | return mechanism; 115 | } 116 | } 117 | 118 | enum RecordField { 119 | USERNAME("username"), 120 | PASSWORD("password"), 121 | DATABASE("database"), 122 | SERVICE_NAME("serviceName"); 123 | 124 | private final BString fieldName; 125 | 126 | RecordField(String fieldName) { 127 | this.fieldName = StringUtils.fromString(fieldName); 128 | } 129 | 130 | public BString getFieldName() { 131 | return fieldName; 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/lib/mongodb/Client.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.lib.mongodb; 20 | 21 | import com.mongodb.ConnectionString; 22 | import com.mongodb.MongoClientSettings; 23 | import com.mongodb.ReadConcern; 24 | import com.mongodb.ReadConcernLevel; 25 | import com.mongodb.ReadPreference; 26 | import com.mongodb.ServerAddress; 27 | import com.mongodb.WriteConcern; 28 | import com.mongodb.client.MongoClient; 29 | import com.mongodb.client.MongoClients; 30 | import com.mongodb.client.MongoIterable; 31 | import io.ballerina.runtime.api.creators.TypeCreator; 32 | import io.ballerina.runtime.api.creators.ValueCreator; 33 | import io.ballerina.runtime.api.types.PredefinedTypes; 34 | import io.ballerina.runtime.api.types.TypeTags; 35 | import io.ballerina.runtime.api.utils.StringUtils; 36 | import io.ballerina.runtime.api.values.BArray; 37 | import io.ballerina.runtime.api.values.BError; 38 | import io.ballerina.runtime.api.values.BMap; 39 | import io.ballerina.runtime.api.values.BObject; 40 | import io.ballerina.runtime.api.values.BString; 41 | import io.ballerina.runtime.api.values.BValue; 42 | 43 | import java.util.ArrayList; 44 | import java.util.List; 45 | import java.util.concurrent.TimeUnit; 46 | 47 | import javax.net.ssl.SSLContext; 48 | 49 | import static io.ballerina.lib.mongodb.Utils.MONGO_CLIENT; 50 | import static io.ballerina.lib.mongodb.Utils.createError; 51 | 52 | /** 53 | * Native methods related to the Ballerina MongoDB client. 54 | * 55 | * @since 5.0.0 56 | */ 57 | public final class Client { 58 | 59 | private Client() { 60 | } 61 | 62 | @SuppressWarnings("unchecked") 63 | public static BError initClient(BObject client, Object connection, Object options) { 64 | try { 65 | MongoClientSettings.Builder settingsBuilder = MongoClientSettings.builder(); 66 | if (options != null) { 67 | addSettings(settingsBuilder, (BMap) options); 68 | } 69 | if (connection instanceof BString) { 70 | String url = ((BString) connection).getValue(); 71 | settingsBuilder.applyConnectionString(new ConnectionString(url)); 72 | } else { 73 | BMap configs = (BMap) connection; 74 | addAuthSettings(settingsBuilder, (BMap) configs.getMapValue(RecordField.AUTH)); 75 | addServerAddressSettings(settingsBuilder, (BValue) configs.get(RecordField.SERVER_ADDRESS)); 76 | } 77 | MongoClient mongoClient = MongoClients.create(settingsBuilder.build()); 78 | client.addNativeData(MONGO_CLIENT, mongoClient); 79 | } catch (Exception e) { 80 | String errorMessage = "Error occurred while initializing the MongoDB client."; 81 | return createError(e, errorMessage); 82 | } 83 | return null; 84 | } 85 | 86 | public static Object listDatabaseNames(BObject client) { 87 | MongoClient mongoClient = (MongoClient) client.getNativeData(MONGO_CLIENT); 88 | try { 89 | MongoIterable databaseNames = mongoClient.listDatabaseNames(); 90 | BArray result = ValueCreator.createArrayValue(TypeCreator.createArrayType(PredefinedTypes.TYPE_STRING)); 91 | for (String databaseName : databaseNames) { 92 | result.append(StringUtils.fromString(databaseName)); 93 | } 94 | return result; 95 | } catch (Exception e) { 96 | String errorMessage = "Error occurred while retrieving database names."; 97 | return createError(e, errorMessage); 98 | } 99 | } 100 | 101 | public static BError createDatabase(BObject client, BString databaseName) { 102 | try { 103 | MongoClient mongoClient = (MongoClient) client.getNativeData(MONGO_CLIENT); 104 | mongoClient.getDatabase(databaseName.getValue()); 105 | } catch (Exception e) { 106 | String errorMessage = "Error occurred while creating the database."; 107 | return createError(e, errorMessage); 108 | } 109 | return null; 110 | } 111 | 112 | public static BError close(BObject client) { 113 | try { 114 | MongoClient mongoClient = (MongoClient) client.getNativeData(MONGO_CLIENT); 115 | mongoClient.close(); 116 | return null; 117 | } catch (Exception e) { 118 | String errorMessage = "Error occurred while closing the MongoDB client."; 119 | return createError(e, errorMessage); 120 | } 121 | } 122 | 123 | @SuppressWarnings("unchecked") 124 | private static void addSettings(MongoClientSettings.Builder settingsBuilder, BMap options) { 125 | if (options.getBooleanValue(RecordField.SSL_ENABLED)) { 126 | BMap secureSocket = 127 | (BMap) options.getMapValue(RecordField.SECURE_SOCKET); 128 | if (secureSocket != null) { 129 | SSLContext sslContext = SslUtils.initializeSSLContext(secureSocket); 130 | settingsBuilder.applyToSslSettings(builder -> builder.enabled(true).context(sslContext)); 131 | } 132 | } 133 | if (options.getStringValue(RecordField.READ_CONCERN) != null) { 134 | String readConcern = options.getStringValue(RecordField.READ_CONCERN).getValue(); 135 | settingsBuilder.readConcern(new ReadConcern(ReadConcernLevel.fromString(readConcern))); 136 | } 137 | if (options.getStringValue(RecordField.WRITE_CONCERN) != null) { 138 | String writeConcern = options.getStringValue(RecordField.WRITE_CONCERN).getValue(); 139 | settingsBuilder.writeConcern(new WriteConcern(writeConcern)); 140 | } 141 | if (options.getStringValue(RecordField.READ_PREFERENCE) != null) { 142 | String readPreference = options.getStringValue(RecordField.READ_PREFERENCE).getValue(); 143 | settingsBuilder.readPreference(ReadPreference.valueOf(readPreference)); 144 | } 145 | if (options.getBooleanValue(RecordField.RETRY_WRITES) != null) { 146 | settingsBuilder.retryWrites(options.getBooleanValue(RecordField.RETRY_WRITES)); 147 | } 148 | if (options.getIntValue(RecordField.SOCKET_TIMEOUT) != null) { 149 | int socketTimeout = options.getIntValue(RecordField.SOCKET_TIMEOUT).intValue(); 150 | settingsBuilder.applyToSocketSettings(builder -> builder.connectTimeout(socketTimeout, 151 | TimeUnit.MILLISECONDS)); 152 | } 153 | if (options.getIntValue(RecordField.CONNECTION_TIMEOUT) != null) { 154 | int connectionTimeout = options.getIntValue(RecordField.CONNECTION_TIMEOUT).intValue(); 155 | settingsBuilder.applyToSocketSettings(builder -> builder.connectTimeout(connectionTimeout, 156 | TimeUnit.MILLISECONDS)); 157 | } 158 | if (options.getIntValue(RecordField.LOCAL_THRESHOLD) != null) { 159 | int localThreshold = options.getIntValue(RecordField.LOCAL_THRESHOLD).intValue(); 160 | settingsBuilder.applyToClusterSettings(builder -> builder.localThreshold(localThreshold, 161 | TimeUnit.MILLISECONDS)); 162 | } 163 | if (options.getStringValue(RecordField.REPLICA_SET) != null) { 164 | String replicaSet = options.getStringValue(RecordField.REPLICA_SET).getValue(); 165 | settingsBuilder.applyToClusterSettings(builder -> builder.requiredReplicaSetName(replicaSet)); 166 | } 167 | if (options.getIntValue(RecordField.HEART_BEAT_FREQUENCY) != null) { 168 | int heartbeatFrequency = options.getIntValue(RecordField.HEART_BEAT_FREQUENCY).intValue(); 169 | settingsBuilder.applyToServerSettings(builder -> builder.heartbeatFrequency(heartbeatFrequency, 170 | TimeUnit.MILLISECONDS)); 171 | } 172 | if (options.getIntValue(RecordField.MAX_POOL_SIZE) != null) { 173 | int maxPoolSize = options.getIntValue(RecordField.MAX_POOL_SIZE).intValue(); 174 | settingsBuilder.applyToConnectionPoolSettings(builder -> builder.maxSize(maxPoolSize)); 175 | } 176 | if (options.getIntValue(RecordField.MAX_IDLE_TIME) != null) { 177 | int maxIdleTime = options.getIntValue(RecordField.MAX_IDLE_TIME).intValue(); 178 | settingsBuilder.applyToConnectionPoolSettings(builder -> builder.maxConnectionIdleTime(maxIdleTime, 179 | TimeUnit.MILLISECONDS)); 180 | } 181 | if (options.getIntValue(RecordField.MAX_LIFE_TIME) != null) { 182 | int maxLifeTime = options.getIntValue(RecordField.MAX_LIFE_TIME).intValue(); 183 | settingsBuilder.applyToConnectionPoolSettings(builder -> builder.maxConnectionLifeTime(maxLifeTime, 184 | TimeUnit.MILLISECONDS)); 185 | } 186 | if (options.getIntValue(RecordField.MIN_POOL_SIZE) != null) { 187 | int minPoolSize = options.getIntValue(RecordField.MIN_POOL_SIZE).intValue(); 188 | settingsBuilder.applyToConnectionPoolSettings(builder -> builder.minSize(minPoolSize)); 189 | } 190 | } 191 | 192 | private static void addAuthSettings(MongoClientSettings.Builder settingsBuilder, BMap auth) { 193 | if (auth == null) { 194 | return; 195 | } 196 | settingsBuilder.credential(AuthUtils.getMongoCredential(auth)); 197 | } 198 | 199 | private static void addServerAddressSettings(MongoClientSettings.Builder settingsBuilder, BValue addressConfig) { 200 | List serverAddressList = new ArrayList<>(); 201 | if (addressConfig.getType().getTag() == TypeTags.ARRAY_TAG) { 202 | BArray serverAddresses = (BArray) addressConfig; 203 | for (int i = 0; i < serverAddresses.size(); i++) { 204 | BMap server = (BMap) serverAddresses.get(i); 205 | serverAddressList.add(getServerAddress(server)); 206 | } 207 | } else { 208 | BMap serverAddress = (BMap) addressConfig; 209 | serverAddressList.add(getServerAddress(serverAddress)); 210 | } 211 | settingsBuilder.applyToClusterSettings(builder -> builder.hosts(serverAddressList)); 212 | } 213 | 214 | private static ServerAddress getServerAddress(BMap serverAddress) { 215 | String host = serverAddress.getStringValue(RecordField.HOST).getValue(); 216 | int port = serverAddress.getIntValue(RecordField.PORT).intValue(); 217 | return new ServerAddress(host, port); 218 | } 219 | 220 | /** 221 | * Constants related to MongoDB client configs. 222 | */ 223 | static class RecordField { 224 | static final BString SERVER_ADDRESS = StringUtils.fromString("serverAddress"); 225 | static final BString AUTH = StringUtils.fromString("auth"); 226 | static final BString HOST = StringUtils.fromString("host"); 227 | static final BString PORT = StringUtils.fromString("port"); 228 | static final BString MONGODB_EXCEPTION_TYPE = StringUtils.fromString("mongoDBExceptionType"); 229 | static final BString AUTH_MECHANISM = StringUtils.fromString("authMechanism"); 230 | static final BString SSL_ENABLED = StringUtils.fromString("sslEnabled"); 231 | static final BString SECURE_SOCKET = StringUtils.fromString("secureSocket"); 232 | static final BString READ_CONCERN = StringUtils.fromString("readConcern"); 233 | static final BString WRITE_CONCERN = StringUtils.fromString("writeConcern"); 234 | static final BString READ_PREFERENCE = StringUtils.fromString("readPreference"); 235 | static final BString REPLICA_SET = StringUtils.fromString("replicaSet"); 236 | static final BString RETRY_WRITES = StringUtils.fromString("retryWrites"); 237 | static final BString SOCKET_TIMEOUT = StringUtils.fromString("socketTimeout"); 238 | static final BString CONNECTION_TIMEOUT = StringUtils.fromString("connectionTimeout"); 239 | static final BString MAX_POOL_SIZE = StringUtils.fromString("maxPoolSize"); 240 | static final BString MAX_IDLE_TIME = StringUtils.fromString("maxIdleTime"); 241 | static final BString MAX_LIFE_TIME = StringUtils.fromString("maxLifeTime"); 242 | static final BString MIN_POOL_SIZE = StringUtils.fromString("minPoolSize"); 243 | static final BString LOCAL_THRESHOLD = StringUtils.fromString("localThreshold"); 244 | static final BString HEART_BEAT_FREQUENCY = StringUtils.fromString("heartbeatFrequency"); 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/lib/mongodb/Database.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.lib.mongodb; 20 | 21 | import com.mongodb.client.MongoClient; 22 | import com.mongodb.client.MongoDatabase; 23 | import com.mongodb.client.MongoIterable; 24 | import io.ballerina.runtime.api.creators.TypeCreator; 25 | import io.ballerina.runtime.api.creators.ValueCreator; 26 | import io.ballerina.runtime.api.types.PredefinedTypes; 27 | import io.ballerina.runtime.api.utils.StringUtils; 28 | import io.ballerina.runtime.api.values.BArray; 29 | import io.ballerina.runtime.api.values.BError; 30 | import io.ballerina.runtime.api.values.BObject; 31 | import io.ballerina.runtime.api.values.BString; 32 | 33 | import static io.ballerina.lib.mongodb.Utils.MONGO_CLIENT; 34 | import static io.ballerina.lib.mongodb.Utils.MONGO_DATABASE; 35 | import static io.ballerina.lib.mongodb.Utils.createError; 36 | 37 | /** 38 | * This class represents a MongoDB database in Ballerina MongoDB client. 39 | * 40 | * @since 5.0.0 41 | */ 42 | public final class Database { 43 | 44 | private Database() { 45 | } 46 | 47 | public static BError initDatabase(BObject database, BObject client, BString dbName) { 48 | try { 49 | MongoClient mongoClient = (MongoClient) client.getNativeData(MONGO_CLIENT); 50 | MongoDatabase mongoDatabase = mongoClient.getDatabase(dbName.getValue()); 51 | database.addNativeData(MONGO_DATABASE, mongoDatabase); 52 | return null; 53 | } catch (Exception e) { 54 | return createError(ErrorType.DATABASE_ERROR, e.getMessage()); 55 | } 56 | } 57 | 58 | public static Object listCollectionNames(BObject database) { 59 | try { 60 | MongoDatabase mongoDatabase = (MongoDatabase) database.getNativeData(MONGO_DATABASE); 61 | MongoIterable collectionNames = mongoDatabase.listCollectionNames(); 62 | BArray result = ValueCreator.createArrayValue(TypeCreator.createArrayType(PredefinedTypes.TYPE_STRING)); 63 | for (String collectionName : collectionNames) { 64 | result.append(StringUtils.fromString(collectionName)); 65 | } 66 | return result; 67 | } catch (Exception e) { 68 | return createError(ErrorType.DATABASE_ERROR, e.getMessage()); 69 | } 70 | } 71 | 72 | public static Object createCollection(BObject database, BString collectionName) { 73 | try { 74 | MongoDatabase mongoDatabase = (MongoDatabase) database.getNativeData(MONGO_DATABASE); 75 | mongoDatabase.createCollection(collectionName.getValue()); 76 | return null; 77 | } catch (Exception e) { 78 | return createError(ErrorType.DATABASE_ERROR, e.getMessage()); 79 | } 80 | } 81 | 82 | public static Object getCollection(BObject database, BString collectionName) { 83 | try { 84 | MongoDatabase mongoDatabase = (MongoDatabase) database.getNativeData(MONGO_DATABASE); 85 | mongoDatabase.getCollection(collectionName.getValue()); 86 | } catch (Exception e) { 87 | return createError(ErrorType.DATABASE_ERROR, e.getMessage()); 88 | } 89 | return null; 90 | } 91 | 92 | public static BError drop(BObject database) { 93 | try { 94 | MongoDatabase mongoDatabase = (MongoDatabase) database.getNativeData(MONGO_DATABASE); 95 | mongoDatabase.drop(); 96 | } catch (Exception e) { 97 | return createError(ErrorType.DATABASE_ERROR, e.getMessage()); 98 | } 99 | return null; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/lib/mongodb/ErrorType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.lib.mongodb; 20 | 21 | /** 22 | * This class contains the error types for the Ballerina MongoDB connector. 23 | * 24 | * @since 5.0.0 25 | */ 26 | enum ErrorType { 27 | APPLICATION_ERROR("ApplicationError"), 28 | DATABASE_ERROR("DatabaseError"); 29 | 30 | private final String errorType; 31 | 32 | ErrorType(String errorType) { 33 | this.errorType = errorType; 34 | } 35 | 36 | public String getErrorType() { 37 | return errorType; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/lib/mongodb/IteratorUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.lib.mongodb; 20 | 21 | import com.mongodb.client.MongoCursor; 22 | import io.ballerina.runtime.api.creators.ErrorCreator; 23 | import io.ballerina.runtime.api.creators.TypeCreator; 24 | import io.ballerina.runtime.api.creators.ValueCreator; 25 | import io.ballerina.runtime.api.types.PredefinedTypes; 26 | import io.ballerina.runtime.api.types.Type; 27 | import io.ballerina.runtime.api.types.UnionType; 28 | import io.ballerina.runtime.api.values.BError; 29 | import io.ballerina.runtime.api.values.BObject; 30 | import io.ballerina.runtime.api.values.BTypedesc; 31 | import org.ballerinalang.langlib.value.FromJsonStringWithType; 32 | import org.bson.Document; 33 | 34 | import static io.ballerina.lib.mongodb.Collection.RECORD_TYPE; 35 | import static io.ballerina.runtime.api.utils.StringUtils.fromString; 36 | 37 | /** 38 | * Utility functions for Ballerina MongoDB result iterator object. 39 | * 40 | * @since 5.0.0 41 | */ 42 | public final class IteratorUtils { 43 | private IteratorUtils() { 44 | } 45 | 46 | public static Object nextResult(BObject iterator) { 47 | MongoCursor cursor = (MongoCursor) iterator.getNativeData(Utils.MONGO_CURSOR); 48 | Type recordType = (Type) iterator.getNativeData(RECORD_TYPE); 49 | if (cursor.hasNext()) { 50 | try { 51 | Object next = cursor.next(); 52 | String result = ""; 53 | if (next instanceof Document) { 54 | result = ((Document) next).toJson(); 55 | } else { 56 | result = next.toString(); 57 | } 58 | UnionType nextValueType = TypeCreator.createUnionType(recordType, PredefinedTypes.TYPE_ERROR, 59 | PredefinedTypes.TYPE_NULL); 60 | BTypedesc nextValueTypeDesc = ValueCreator.createTypedescValue(nextValueType); 61 | return FromJsonStringWithType.fromJsonStringWithType(fromString(result), nextValueTypeDesc); 62 | } catch (Exception e) { 63 | return ErrorCreator.createError(fromString("Error while iterating elements"), e); 64 | } 65 | } 66 | return null; 67 | } 68 | 69 | public static BError close(BObject iterator) { 70 | try { 71 | MongoCursor cursor = (MongoCursor) iterator.getNativeData(Utils.MONGO_CURSOR); 72 | cursor.close(); 73 | return null; 74 | } catch (Exception e) { 75 | return Utils.createError(ErrorType.APPLICATION_ERROR, e.getMessage()); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/lib/mongodb/ModuleUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.lib.mongodb; 20 | 21 | import io.ballerina.runtime.api.Environment; 22 | import io.ballerina.runtime.api.Module; 23 | 24 | /** 25 | * Module utils for the Ballerina MongoDB connector to obtain the module info in the init. 26 | */ 27 | public class ModuleUtils { 28 | 29 | private ModuleUtils() { 30 | } 31 | 32 | private static Module module; 33 | 34 | public static void setModule(Environment environment) { 35 | module = environment.getCurrentModule(); 36 | } 37 | 38 | public static Module getModule() { 39 | return module; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/lib/mongodb/SslUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.lib.mongodb; 20 | 21 | import io.ballerina.runtime.api.utils.StringUtils; 22 | import io.ballerina.runtime.api.values.BError; 23 | import io.ballerina.runtime.api.values.BMap; 24 | import io.ballerina.runtime.api.values.BString; 25 | 26 | import java.io.FileInputStream; 27 | import java.io.FileNotFoundException; 28 | import java.io.IOException; 29 | import java.io.InputStream; 30 | import java.security.GeneralSecurityException; 31 | import java.security.KeyStore; 32 | 33 | import javax.net.ssl.KeyManager; 34 | import javax.net.ssl.KeyManagerFactory; 35 | import javax.net.ssl.SSLContext; 36 | import javax.net.ssl.TrustManager; 37 | import javax.net.ssl.TrustManagerFactory; 38 | 39 | import static io.ballerina.lib.mongodb.Utils.createError; 40 | 41 | /** 42 | * This class contains the utility methods for SSL configurations in MongoDB client. 43 | * 44 | * @since 5.0.0 45 | */ 46 | public final class SslUtils { 47 | 48 | private SslUtils() { 49 | } 50 | 51 | @SuppressWarnings("unchecked") 52 | static SSLContext initializeSSLContext(BMap secureSocket) { 53 | TrustManager[] trustManagers; 54 | KeyManager[] keyManagers; 55 | 56 | BMap trustStore = 57 | (BMap) secureSocket.getMapValue(RecordField.TRUST_STORE.getFieldName()); 58 | String trustStoreFilePath = trustStore.getStringValue(RecordField.CERTIFICATE_PATH.getFieldName()).getValue(); 59 | try (InputStream trustStream = new FileInputStream(trustStoreFilePath)) { 60 | char[] trustStorePass = 61 | trustStore.getStringValue(RecordField.CERTIFICATE_PASSWORD.getFieldName()).getValue().toCharArray(); 62 | KeyStore trustStoreJKS = KeyStore.getInstance(KeyStore.getDefaultType()); 63 | trustStoreJKS.load(trustStream, trustStorePass); 64 | 65 | TrustManagerFactory trustFactory = 66 | TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 67 | trustFactory.init(trustStoreJKS); 68 | trustManagers = trustFactory.getTrustManagers(); 69 | } catch (FileNotFoundException e) { 70 | BError cause = createError(ErrorType.APPLICATION_ERROR, e.getMessage()); 71 | String message = "Trust store file not found for secure connections to MongoDB. Trust Store file path : " + 72 | "'" + trustStoreFilePath + "'."; 73 | throw createError(ErrorType.APPLICATION_ERROR, message, cause); 74 | } catch (IOException e) { 75 | BError cause = createError(ErrorType.APPLICATION_ERROR, e.getMessage()); 76 | String message = "I/O Exception in creating trust store for secure connections to MongoDB. Trust Store " + 77 | "file path : '" + trustStoreFilePath + "'."; 78 | throw createError(ErrorType.APPLICATION_ERROR, message, cause); 79 | } catch (GeneralSecurityException e) { 80 | BError cause = createError(ErrorType.APPLICATION_ERROR, e.getMessage()); 81 | String message = "Error in initializing certs for Trust Store."; 82 | throw createError(ErrorType.APPLICATION_ERROR, message, cause); 83 | } 84 | 85 | BMap keyStore = 86 | (BMap) secureSocket.getMapValue(RecordField.KEY_STORE.getFieldName()); 87 | String keyStoreFilePath = keyStore.getStringValue(RecordField.CERTIFICATE_PATH.getFieldName()).getValue(); 88 | try (InputStream keyStream = new FileInputStream(keyStoreFilePath)) { 89 | char[] keyStorePass = 90 | keyStore.getStringValue(RecordField.CERTIFICATE_PASSWORD.fieldName).getValue().toCharArray(); 91 | KeyStore keyStoreJKS = KeyStore.getInstance(KeyStore.getDefaultType()); 92 | keyStoreJKS.load(keyStream, keyStorePass); 93 | KeyManagerFactory keyManagerFactory = 94 | KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 95 | keyManagerFactory.init(keyStoreJKS, keyStorePass); 96 | keyManagers = keyManagerFactory.getKeyManagers(); 97 | } catch (FileNotFoundException e) { 98 | BError cause = createError(ErrorType.APPLICATION_ERROR, e.getMessage()); 99 | String message = "Key store file not found for secure connections to MongoDB. Key Store file path : '" + 100 | keyStoreFilePath + "'."; 101 | throw createError(ErrorType.APPLICATION_ERROR, message, cause); 102 | } catch (IOException e) { 103 | BError cause = createError(ErrorType.APPLICATION_ERROR, e.getMessage()); 104 | String message = "I/O Exception in creating key store for secure connections to MongoDB. Key Store " + 105 | "file path : '" + keyStoreFilePath + "'."; 106 | throw createError(ErrorType.APPLICATION_ERROR, message, cause); 107 | } catch (GeneralSecurityException e) { 108 | BError cause = createError(ErrorType.APPLICATION_ERROR, e.getMessage()); 109 | String message = "Error in initializing certs for Key Store."; 110 | throw createError(ErrorType.APPLICATION_ERROR, message, cause); 111 | } 112 | 113 | try { 114 | String protocol = secureSocket.getStringValue(RecordField.PROTOCOL.getFieldName()).getValue(); 115 | SSLContext sslContext = SSLContext.getInstance(protocol); 116 | sslContext.init(keyManagers, trustManagers, null); 117 | return sslContext; 118 | } catch (GeneralSecurityException e) { 119 | BError cause = createError(ErrorType.APPLICATION_ERROR, e.getMessage()); 120 | String message = "Error in initializing SSL context with the key store/ trust store. Trust Store file " + 121 | "path : '" + trustStoreFilePath + "'. Key Store file path : '" + keyStoreFilePath + "'."; 122 | throw createError(ErrorType.APPLICATION_ERROR, message, cause); 123 | } 124 | } 125 | 126 | private enum RecordField { 127 | KEY_STORE("keyStore"), 128 | TRUST_STORE("trustStore"), 129 | CERTIFICATE_PATH("path"), 130 | CERTIFICATE_PASSWORD("password"), 131 | PROTOCOL("protocol"); 132 | 133 | private final BString fieldName; 134 | 135 | RecordField(String fieldName) { 136 | this.fieldName = StringUtils.fromString(fieldName); 137 | } 138 | 139 | public BString getFieldName() { 140 | return fieldName; 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/lib/mongodb/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.lib.mongodb; 20 | 21 | import com.mongodb.MongoClientException; 22 | import com.mongodb.MongoCommandException; 23 | import com.mongodb.MongoException; 24 | import com.mongodb.client.MongoCursor; 25 | import io.ballerina.runtime.api.creators.ErrorCreator; 26 | import io.ballerina.runtime.api.creators.TypeCreator; 27 | import io.ballerina.runtime.api.creators.ValueCreator; 28 | import io.ballerina.runtime.api.types.ArrayType; 29 | import io.ballerina.runtime.api.types.Field; 30 | import io.ballerina.runtime.api.types.PredefinedTypes; 31 | import io.ballerina.runtime.api.types.RecordType; 32 | import io.ballerina.runtime.api.types.StreamType; 33 | import io.ballerina.runtime.api.types.Type; 34 | import io.ballerina.runtime.api.types.TypeTags; 35 | import io.ballerina.runtime.api.types.UnionType; 36 | import io.ballerina.runtime.api.utils.StringUtils; 37 | import io.ballerina.runtime.api.utils.TypeUtils; 38 | import io.ballerina.runtime.api.values.BArray; 39 | import io.ballerina.runtime.api.values.BError; 40 | import io.ballerina.runtime.api.values.BMap; 41 | import io.ballerina.runtime.api.values.BObject; 42 | import io.ballerina.runtime.api.values.BStream; 43 | import io.ballerina.runtime.api.values.BString; 44 | import io.ballerina.runtime.api.values.BTypedesc; 45 | import org.bson.Document; 46 | 47 | import java.util.ArrayList; 48 | import java.util.List; 49 | import java.util.Map; 50 | 51 | import static io.ballerina.lib.mongodb.ModuleUtils.getModule; 52 | 53 | /** 54 | * Utility methods for the Ballerina MongoDB connector. 55 | */ 56 | public final class Utils { 57 | 58 | private Utils() { 59 | } 60 | 61 | static final String RESULT_ITERATOR_OBJECT_NAME = "ResultIterator"; 62 | static final String MONGO_CURSOR = "mongo.cursor"; 63 | static final String RECORD_TYPE = "record.type"; 64 | static final String MONGO_CLIENT = "mongo.native.client"; 65 | static final String MONGO_DATABASE = "mongo.native.database"; 66 | static final String MONGO_COLLECTION = "mongo.native.collection"; 67 | static final String DATABASE_ERROR_DETAIL = "DatabaseErrorDetail"; 68 | private static final String MONGO_ID_FIELD = "_id"; 69 | 70 | static final Map DISTINCT_TYPE_MAP = Map.of( 71 | TypeTags.STRING_TAG, String.class, 72 | TypeTags.INT_TAG, Long.class, 73 | TypeTags.FLOAT_TAG, Double.class, 74 | TypeTags.RECORD_TYPE_TAG, Document.class 75 | ); 76 | 77 | static BError createError(Exception e) { 78 | return createError(ErrorType.APPLICATION_ERROR, e.getMessage(), null); 79 | } 80 | 81 | static BError createError(Exception e, String message) { 82 | BError cause = createError(ErrorType.APPLICATION_ERROR, e.getMessage(), null); 83 | return createError(ErrorType.APPLICATION_ERROR, message, cause); 84 | } 85 | 86 | static BError createError(MongoClientException e) { 87 | return createError(ErrorType.APPLICATION_ERROR, e.getMessage(), null); 88 | } 89 | 90 | static BError createError(MongoClientException e, String message) { 91 | BError cause = createError(ErrorType.APPLICATION_ERROR, e.getMessage(), null); 92 | return createError(ErrorType.APPLICATION_ERROR, message, cause); 93 | } 94 | 95 | static BError createError(MongoException e) { 96 | return createError(ErrorType.APPLICATION_ERROR, e.getMessage(), null); 97 | } 98 | 99 | static BError createError(MongoException e, String message) { 100 | BError cause = createError(ErrorType.APPLICATION_ERROR, e.getMessage(), null); 101 | return createError(ErrorType.APPLICATION_ERROR, message, cause); 102 | } 103 | 104 | static BError createError(MongoCommandException e) { 105 | BMap details = ValueCreator.createRecordValue(ModuleUtils.getModule(), DATABASE_ERROR_DETAIL); 106 | details.put(Client.RecordField.MONGODB_EXCEPTION_TYPE, StringUtils.fromString(e.getErrorCodeName())); 107 | return createError(ErrorType.DATABASE_ERROR, e.getErrorMessage(), null, details); 108 | } 109 | 110 | static BError createError(ErrorType errorType, String message) { 111 | return createError(errorType, message, null, null); 112 | } 113 | 114 | static BError createError(ErrorType errorType, String message, BError cause) { 115 | return createError(errorType, message, cause, null); 116 | } 117 | 118 | static BError createError(ErrorType errorType, String errorMessage, BError cause, BMap details) { 119 | BString message = StringUtils.fromString(errorMessage); 120 | return ErrorCreator.createError(ModuleUtils.getModule(), errorType.getErrorType(), message, cause, details); 121 | } 122 | 123 | static BStream createStream(BTypedesc targetType, MongoCursor cursor) { 124 | BObject resultIterator = ValueCreator.createObjectValue(getModule(), RESULT_ITERATOR_OBJECT_NAME); 125 | resultIterator.addNativeData(MONGO_CURSOR, cursor); 126 | resultIterator.addNativeData(RECORD_TYPE, targetType.getDescribingType()); 127 | Type completionType = TypeCreator.createUnionType(PredefinedTypes.TYPE_ERROR, PredefinedTypes.TYPE_NULL); 128 | StreamType streamType = TypeCreator.createStreamType(targetType.getDescribingType(), completionType); 129 | return ValueCreator.createStreamValue(streamType, resultIterator); 130 | } 131 | 132 | static Class getResultClass(BTypedesc targetType) { 133 | if (DISTINCT_TYPE_MAP.containsKey(targetType.getDescribingType().getTag())) { 134 | return DISTINCT_TYPE_MAP.get(targetType.getDescribingType().getTag()); 135 | } 136 | return null; 137 | } 138 | 139 | static List getPipeline(BArray pipeline, Type targetType) { 140 | List documents = new ArrayList<>(); 141 | boolean projectionPresent = false; 142 | if (pipeline != null) { 143 | for (int i = 0; i < pipeline.size(); i++) { 144 | if (pipeline.get(i) instanceof BMap) { 145 | BMap stage = (BMap) pipeline.get(i); 146 | if (stage.containsKey(StringUtils.fromString("$project"))) { 147 | projectionPresent = true; 148 | } 149 | } 150 | documents.add(Document.parse(pipeline.get(i).toString())); 151 | } 152 | } 153 | if (!projectionPresent) { 154 | Document projection = new Document("$project", Document.parse(getProjectionDocument(targetType))); 155 | documents.add(projection); 156 | } 157 | return documents; 158 | } 159 | 160 | static String getProjection(Object projectionInput, BTypedesc targetType) { 161 | if (projectionInput == null) { 162 | return getProjectionDocument(targetType.getDescribingType()); 163 | } else { 164 | return projectionInput.toString(); 165 | } 166 | } 167 | 168 | static String getProjectionDocument(Type type) { 169 | StringBuilder projectionBuilder = new StringBuilder(); 170 | projectionBuilder.append("{"); 171 | getProjectionForFieldType(type, projectionBuilder, ""); 172 | projectionBuilder.append("}"); 173 | return projectionBuilder.toString(); 174 | } 175 | 176 | private static void getProjectionForFieldType(Type type, StringBuilder projectionBuilder, String parent) { 177 | Type impliedType = TypeUtils.getImpliedType(type); 178 | int tag = impliedType.getTag(); 179 | if (tag == TypeTags.RECORD_TYPE_TAG) { 180 | RecordType recordType = (RecordType) TypeUtils.getImpliedType(type); 181 | getProjectionForFieldType(recordType, projectionBuilder, parent); 182 | } else if (tag == TypeTags.ARRAY_TAG) { 183 | ArrayType arrayType = (ArrayType) type; 184 | getProjectionForFieldType(arrayType, projectionBuilder, parent); 185 | } else if (TypeUtils.isValueType(type)) { 186 | projectionBuilder.append(parent).append("\": 1, "); 187 | } else if (tag == TypeTags.UNION_TAG) { 188 | List memberTypes = ((UnionType) type).getMemberTypes(); 189 | for (Type memberType : memberTypes) { 190 | if (memberType.getTag() == TypeTags.ERROR_TAG || memberType.getTag() == TypeTags.NULL_TAG) { 191 | continue; 192 | } 193 | getProjectionForFieldType(memberType, projectionBuilder, parent); 194 | } 195 | } else { 196 | throw createError(ErrorType.APPLICATION_ERROR, "Unsupported type: " + type.getName()); 197 | } 198 | } 199 | 200 | private static void getProjectionForFieldType(RecordType recordType, StringBuilder projectionBuilder, 201 | String parent) { 202 | Map fields = recordType.getFields(); 203 | if ("".equals(parent)) { 204 | // Remove the _id field from the result when not specified by the user 205 | if (!fields.containsKey(MONGO_ID_FIELD)) { 206 | projectionBuilder.append("_id: 0, "); 207 | } 208 | } 209 | for (Map.Entry field : fields.entrySet()) { 210 | String fieldName = field.getKey(); 211 | if (parent.isEmpty() && MONGO_ID_FIELD.equals(fieldName)) { 212 | continue; 213 | } 214 | String parentValue = parent.isEmpty() ? "\"" + fieldName : parent + "." + fieldName; 215 | getProjectionForFieldType(field.getValue().getFieldType(), projectionBuilder, parentValue); 216 | } 217 | } 218 | 219 | private static void getProjectionForFieldType(ArrayType arrayType, StringBuilder projectionBuilder, String parent) { 220 | Type elementType = TypeUtils.getImpliedType(arrayType.getElementType()); 221 | if (elementType.getTag() == TypeTags.RECORD_TYPE_TAG) { 222 | RecordType recordType = (RecordType) elementType; 223 | getProjectionForFieldType(recordType, projectionBuilder, parent); 224 | } else { 225 | projectionBuilder.append("\": 1, "); 226 | } 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /native/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | module io.ballerina.lib.mongodb { 20 | requires io.ballerina.runtime; 21 | requires io.ballerina.lang.value; 22 | requires org.mongodb.driver.sync.client; 23 | requires org.mongodb.driver.core; 24 | requires org.mongodb.bson; 25 | requires slf4j.api; 26 | 27 | exports io.ballerina.lib.mongodb; 28 | } 29 | -------------------------------------------------------------------------------- /pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) 6 | 7 | Related Pull Requests (remove if not relevant) 8 | - Pull request 1 9 | - Pull request 2 10 | 11 | One line release note: 12 | - One line describing the feature/improvement/fix made by this PR 13 | 14 | ## Type of change 15 | 16 | Please delete options that are not relevant. 17 | 18 | - [ ] Bug fix (non-breaking change which fixes an issue) 19 | - [ ] New feature (non-breaking change which adds functionality) 20 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 21 | - [ ] This change requires a documentation update 22 | 23 | # How Has This Been Tested? 24 | 25 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration 26 | 27 | - [ ] Test A 28 | - [ ] Test B 29 | 30 | **Test Configuration**: 31 | * Ballerina Version: 32 | * Operating System: 33 | * Java SDK: 34 | 35 | # Checklist: 36 | 37 | ### Security checks 38 | - [ ] Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines? 39 | - [ ] Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets? 40 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | pluginManagement { 20 | plugins { 21 | id "com.github.spotbugs-base" version "${spotbugsPluginVersion}" 22 | id "com.github.johnrengelman.shadow" version "${shadowJarPluginVersion}" 23 | id "de.undercouch.download" version "${downloadPluginVersion}" 24 | id "net.researchgate.release" version "${releasePluginVersion}" 25 | id "io.ballerina.plugin" version "${ballerinaGradlePluginVersion}" 26 | } 27 | 28 | repositories { 29 | gradlePluginPortal() 30 | maven { 31 | url = 'https://maven.pkg.github.com/ballerina-platform/*' 32 | credentials { 33 | username System.getenv("packageUser") 34 | password System.getenv("packagePAT") 35 | } 36 | } 37 | } 38 | } 39 | 40 | plugins { 41 | id "com.gradle.enterprise" version "3.13.2" 42 | } 43 | 44 | def projectName = 'mongodb' 45 | rootProject.name = "ballerinax ${projectName}" 46 | 47 | include ":checkstyle" 48 | include ":${projectName}-native" 49 | include ":${projectName}-ballerina" 50 | include ":${projectName}-examples" 51 | 52 | project(':checkstyle').projectDir = file("build-config${File.separator}checkstyle") 53 | project(":${projectName}-native").projectDir = file('native') 54 | project(":${projectName}-ballerina").projectDir = file('ballerina') 55 | project(":${projectName}-examples").projectDir = file('examples') 56 | 57 | gradleEnterprise { 58 | buildScan { 59 | termsOfServiceUrl = 'https://gradle.com/terms-of-service' 60 | termsOfServiceAgree = 'yes' 61 | } 62 | } 63 | --------------------------------------------------------------------------------