Skip to content

Commit

Permalink
Merge pull request #224 from abeykoon/add-distinct
Browse files Browse the repository at this point in the history
Introduce `distinct` function and improve type handling
  • Loading branch information
LakshanSS committed Sep 12, 2023
2 parents 36a8d4b + 269df72 commit e2dd509
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 52 deletions.
6 changes: 3 additions & 3 deletions ballerina/Ballerina.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
distribution = "2201.7.0"
org = "ballerinax"
name = "mongodb"
version = "4.2.1"
version = "4.3.0"
license= ["Apache-2.0"]
authors = ["Ballerina"]
keywords = ["IT Operations/Databases", "Cost/Freemium"]
Expand All @@ -13,10 +13,10 @@ repository = "https://github.com/ballerina-platform/module-ballerinax-mongodb"
graalvmCompatible = true

[[platform.java11.dependency]]
path = "../native/build/libs/mongodb-native-4.2.1.jar"
path = "../native/build/libs/mongodb-native-4.3.0.jar"
groupId = "org.ballerinalang"
artifactId = "mongodb-native"
version = "4.2.1"
version = "4.3.0"

[[platform.java11.dependency]]
groupId = "com.fasterxml.jackson.core"
Expand Down
77 changes: 44 additions & 33 deletions ballerina/client.bal
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import ballerina/jballerina.java;
public isolated client class Client {

# Initialises the `Client` object with the provided `ConnectionConfig` properties.
#
# + config - `ConnectionConfig` properties.
#
# + config - `ConnectionConfig` properties.
# + return - A `mongodb:Error` if there is any error in the provided configurations or database name
public isolated function init(ConnectionConfig config) returns Error? {
if config.connection is ConnectionParameters {
Expand All @@ -39,22 +39,22 @@ public isolated client class Client {
}
}
}
check initClient(self, config, config.databaseName);
check initClient(self, config, config.databaseName);
}

//Database management operations
# Lists the database names in the MongoDB server.
#
# + return - An array of database names on success or else a `mongodb:DatabaseError` if unable to reach the DB
# + return - An array of database names on success or else a `mongodb:DatabaseError` if unable to reach the DB
@display {label: "Get Database Names"}
remote isolated function getDatabasesNames() returns @display {label: "Database Names"} string[]|DatabaseError {
return getDatabasesNames(self);
}

//Collection management operations
//Collection management operations
# Lists the collection names in the MongoDB database.
#
# + databaseName - Name of the database
# + databaseName - Name of the database
# + return - An array of collection names on success or else a `mongodb:Error` if unable to reach the DB
@display {label: "Get Collection Names"}
remote isolated function getCollectionNames(string? databaseName = ()) returns string[]|Error = @java:Method {
Expand All @@ -69,9 +69,9 @@ public isolated client class Client {
# + filter - Filter for the count ($where & $near can be used)
# + return - Count of the documents in the collection or else `mongodb:Error` if unable to reach the DB
@display {label: "Count Documents"}
remote isolated function countDocuments(@display {label: "Collection Name"} string collectionName,
@display {label: "Database Name"} string? databaseName = (),
@display {label: "Filter"} map<json>? filter = ())
remote isolated function countDocuments(@display {label: "Collection Name"} string collectionName,
@display {label: "Database Name"} string? databaseName = (),
@display {label: "Filter"} map<json>? filter = ())
returns @display {label: "Number of Documents"} int|Error {
handle collection = check getCollection(self, collectionName, databaseName);
if (filter is ()) {
Expand All @@ -83,8 +83,8 @@ public isolated client class Client {

# Lists the indices associated with the collection.
#
# + collectionName - Name of the collection
# + databaseName - Name of the database
# + collectionName - Name of the collection
# + databaseName - Name of the database
# + rowType - The `typedesc` of the record that should be returned as a result.
# + return - A A stream<rowType, error?> with indices on success or else a `mongodb:Error` if unable to reach the DB
@display {label: "List Indices"}
Expand All @@ -96,14 +96,14 @@ public isolated client class Client {
} external;

# Inserts a document.
#
#
# + document - Document to be inserted as a JSON map
# + collectionName - Name of the collection
# + databaseName - Name of the database
# + databaseName - Name of the database
# + return - `()` on success or else a `mongodb:Error` if unable to reach the DB
@display {label: "Insert Document"}
remote isolated function insert(@display {label: "Document"} map<json> document,
@display {label: "Collection Name"} string collectionName,
remote isolated function insert(@display {label: "Document"} map<json> document,
@display {label: "Collection Name"} string collectionName,
@display {label: "Database Name"} string? databaseName = ()) returns Error? {
handle collection = check getCollection(self, collectionName, databaseName);
string documentStr = document.toJsonString();
Expand All @@ -112,15 +112,16 @@ public isolated client class Client {

# Queries collection for documents, which sorts and limits the returned results.
#
# + collectionName - Name of the collection
# + databaseName - Name of the database
# + filter - Filter for the query
# + collectionName - Name of the collection
# + databaseName - Name of the database
# + filter - Filter for the query
# + projection - The projection document
# + sort - Sort options for the query
# + sort - Sort options for the query
# + 'limit - The limit of documents that should be returned. If the limit is -1, all the documents in the result
# will be returned.
# + skip - The number of documents that should be skipped. If the skip is -1, no documents will be skipped.
# + rowType - The `typedesc` of the record that should be returned as a result.
# + return - A stream<rowType, error?> of the documents in the collection or else a `mongodb:Error`
# + return - A stream<rowType, error?> of the documents in the collection or else a `mongodb:Error`
# if unable to reach the DB
@display {label: "Query for Documents"}
remote isolated function find(@display {label: "Collection Name"} string collectionName,
Expand All @@ -129,14 +130,15 @@ public isolated client class Client {
@display {label: "Projection"} map<json>? projection = (),
@display {label: "Sort Options"} map<json>? sort = (),
@display {label: "Limit"} int 'limit = -1,
@display {label: "Record Type"} typedesc<record {}> rowType = <>)
@display {label: "Skip"} int skip = -1,
@display {label: "Record Type"} typedesc<record {}> rowType = <>)
returns stream<rowType, error?>|Error = @java:Method {
'class: "org.ballerinalang.mongodb.MongoDBCollectionUtil"
} external;

# Updates a document based on a condition.
#
# + updateStatement - Document for the update condition. Eg: { "$set": { <field1>: <value1>, ... } } ,
# + updateStatement - Document for the update condition. Eg: { "$set": { <field1>: <value1>, ... } } ,
# { "$push": { <field>: { "$each": [ <value1>, <value2> ... ] } } }.
# + collectionName - Name of the collection
# + databaseName - Name of the database
Expand All @@ -145,12 +147,12 @@ public isolated client class Client {
# + upsert - Whether to insert if update cannot be achieved
# + return - The number of updated documents or else a `mongodb:Error` if unable to reach the DB
@display {label: "Update Document"}
remote isolated function update(@display {label: "Document to Update"} map<json> updateStatement,
@display {label: "Collection Name"} string collectionName,
remote isolated function update(@display {label: "Document to Update"} map<json> updateStatement,
@display {label: "Collection Name"} string collectionName,
@display {label: "Database Name"} string? databaseName = (),
@display {label: "Filter for Query"} map<json>? filter = (),
@display {label: "Filter for Query"} map<json>? filter = (),
@display {label: "Is Multiple Documents"} boolean isMultiple = false,
@display {label: "Is Upsert"} boolean upsert = false)
@display {label: "Is Upsert"} boolean upsert = false)
returns @display {label: "Number of Updated Documents"} int|Error {
handle collection = check getCollection(self, collectionName, databaseName);
string updateDoc = updateStatement.toJsonString();
Expand All @@ -162,17 +164,17 @@ public isolated client class Client {
}

# Deletes a document based on a condition.
#
#
# + collectionName - Name of the collection
# + databaseName - Name of the database
# + databaseName - Name of the database
# + filter - Filter for the query
# + isMultiple - Delete multiple documents if the condition is matched
# + return - The number of deleted documents or else a `mongodb:Error` if unable to reach the DB
@display {label: "Delete Document"}
remote isolated function delete(@display {label: "Collection Name"} string collectionName,
remote isolated function delete(@display {label: "Collection Name"} string collectionName,
@display {label: "Database Name"} string? databaseName = (),
@display {label: "Filter"} map<json>? filter = (),
@display {label: "Is Multiple Documents"} boolean isMultiple = false)
@display {label: "Filter"} map<json>? filter = (),
@display {label: "Is Multiple Documents"} boolean isMultiple = false)
returns @display {label: "Number of Deleted Documents"} int|Error {
handle collection = check getCollection(self, collectionName, databaseName);
if (filter is ()) {
Expand All @@ -182,6 +184,15 @@ public isolated client class Client {
return delete(collection, java:fromString(filterStr), isMultiple);
}

remote isolated function 'distinct(@display {label: "Collection Name"} string collectionName,
@display {label: "Field Name"} string 'field,
@display {label: "Database Name"} string? databaseName = (),
@display {label: "Filter"} map<json>? filter = (),
@display {label: "Return Type"} typedesc<anydata> rowType = <>)
returns stream<rowType, error?>|Error = @java:Method {
'class: "org.ballerinalang.mongodb.MongoDBCollectionUtil"
} external;

# Closes the client.
@display {label: "Close the Client"}
remote isolated function close() {
Expand All @@ -202,7 +213,7 @@ isolated function close(Client mongoClient) = @java:Method {
'class: "org.ballerinalang.mongodb.MongoDBDataSourceUtil"
} external;

//Database Client Java
//Database Client Java
isolated function getCollection(Client mongoClient, string collectionName, string? databaseName)
returns handle|DatabaseError = @java:Method {
'class: "org.ballerinalang.mongodb.MongoDBDatabaseUtil"
Expand Down
59 changes: 57 additions & 2 deletions ballerina/iterator.bal
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import ballerina/jballerina.java;

# Represents ResultIterator.
# Represents ResultIterator.
public class ResultIterator {
private boolean isClosed = false;
private Error? err;
Expand Down Expand Up @@ -75,9 +75,64 @@ isolated function closeResult(ResultIterator iterator) returns Error? = @java:Me
'class: "org.ballerinalang.mongodb.RecordIteratorUtils"
} external;

# Represents MongoResultIterator.
# Represents MongoResultIterator.
public class MongoResultIterator {
public isolated function nextResult(ResultIterator iterator) returns record {}|Error? = @java:Method {
'class: "org.ballerinalang.mongodb.RecordIteratorUtils"
} external;
}

public class PlainResultIterator {
private boolean isClosed = false;
private Error? err;

public isolated function init(Error? err = ()) {
self.err = err;
}

public isolated function next() returns record {|anydata value;|}|Error? {
if (self.isClosed) {
return closedStreamInvocationError();
}
if (self.err is Error) {
return self.err;
} else {
anydata|Error? result;
result = nextPlainResult(self);
if (result is anydata) {
if result is () {
check self.close();
return result;
}
record {|
anydata value;
|} streamRecord = {value: result};
return streamRecord;
} else {
self.err = result;
check self.close();
return self.err;
}
}
}

public isolated function close() returns Error? {
if (!self.isClosed) {
if (self.err is ()) {
Error? e = closePlainResult(self);
if (e is ()) {
self.isClosed = true;
}
return e;
}
}
}
}

isolated function nextPlainResult(PlainResultIterator iterator) returns anydata|Error? = @java:Method {
'class: "org.ballerinalang.mongodb.RecordIteratorUtils"
} external;

isolated function closePlainResult(PlainResultIterator iterator) returns Error? = @java:Method {
'class: "org.ballerinalang.mongodb.RecordIteratorUtils"
} external;
23 changes: 20 additions & 3 deletions ballerina/tests/main_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ ConnectionConfig mongoConfig = {
password: testPass
},
options: {
sslEnabled: false,
sslEnabled: false,
serverSelectionTimeout: 15000
}
}
},
databaseName: DATABASE_NAME
};
Expand Down Expand Up @@ -222,7 +222,24 @@ public function testFindDataWithProjection() returns error? {
}

@test:Config {
dependsOn: [ testFindDataWithProjection ],
dependsOn: [testFindDataWithProjection],
groups: ["mongodb"]
}
function testFindDistinctValues() returns error? {
log:printInfo("----------------- Querying Distinct Values ----------------");
string[] distictiveValues = [];
stream<string, error?> result = check mongoClient->'distinct(COLLECTION_NAME, "year");
check result.forEach(function(string data){
log:printInfo(data);
distictiveValues.push(data);
});
test:assertEquals(distictiveValues.length(), 2, "Querying distinct values failed. " +
"Expected 2 but found " + distictiveValues.length().toString());
log:printInfo("Querying distinct values tested successfully");
}

@test:Config {
dependsOn: [testFindDistinctValues],
groups: ["mongodb"]
}
function testUpdateDocument() returns error? {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
org.gradle.caching=true
group=org.ballerinalang.mongodb
version=4.2.1
version=4.3.0

puppycrawlCheckstyleVersion=8.18
checkstyleToolVersion=7.8.2
Expand Down

0 comments on commit e2dd509

Please sign in to comment.