Skip to content

Commit

Permalink
Merge pull request #82 from daneshk/main
Browse files Browse the repository at this point in the history
Fix the issue when there is no associated entries for the given record
  • Loading branch information
daneshk authored Oct 29, 2024
2 parents b05f6be + 2cfaa58 commit af6184a
Show file tree
Hide file tree
Showing 20 changed files with 1,424 additions and 10 deletions.
6 changes: 3 additions & 3 deletions ballerina/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
org = "ballerinax"
name = "persist.sql"
version = "1.4.0"
version = "1.4.1"
authors = ["Ballerina"]
keywords = ["persist", "sql", "mysql", "mssql", "sql-server"]
repository = "https://github.com/ballerina-platform/module-ballerinax-persist.sql"
Expand All @@ -15,8 +15,8 @@ graalvmCompatible = true
[[platform.java17.dependency]]
groupId = "io.ballerina.stdlib"
artifactId = "persist.sql-native"
version = "1.4.0"
path = "../native/build/libs/persist.sql-native-1.4.0.jar"
version = "1.4.1"
path = "../native/build/libs/persist.sql-native-1.4.1-SNAPSHOT.jar"

[[platform.java17.dependency]]
groupId = "io.ballerina.stdlib"
Expand Down
2 changes: 1 addition & 1 deletion ballerina/CompilerPlugin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ id = "persist.sql-compiler-plugin"
class = "io.ballerina.stdlib.persist.sql.compiler.PersistSqlCompilerPlugin"

[[dependency]]
path = "../compiler-plugin/build/libs/persist.sql-compiler-plugin-1.4.0.jar"
path = "../compiler-plugin/build/libs/persist.sql-compiler-plugin-1.4.1-SNAPSHOT.jar"

[[dependency]]
path = "./lib/persist-native-1.4.0.jar"
Expand Down
14 changes: 9 additions & 5 deletions ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
version = "2.12.0"
version = "2.12.2"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
Expand Down Expand Up @@ -100,6 +100,9 @@ dependencies = [
{org = "ballerina", name = "jballerina.java"},
{org = "ballerina", name = "lang.value"}
]
modules = [
{org = "ballerina", packageName = "io", moduleName = "io"}
]

[[package]]
org = "ballerina"
Expand Down Expand Up @@ -241,7 +244,7 @@ modules = [
[[package]]
org = "ballerina"
name = "mime"
version = "2.10.0"
version = "2.10.1"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "io"},
Expand Down Expand Up @@ -296,7 +299,7 @@ modules = [
[[package]]
org = "ballerina"
name = "sql"
version = "1.14.0"
version = "1.14.1"
dependencies = [
{org = "ballerina", name = "io"},
{org = "ballerina", name = "jballerina.java"},
Expand Down Expand Up @@ -437,7 +440,7 @@ modules = [
[[package]]
org = "ballerinax"
name = "mysql"
version = "1.13.0"
version = "1.13.1"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "crypto"},
Expand All @@ -462,8 +465,9 @@ modules = [
[[package]]
org = "ballerinax"
name = "persist.sql"
version = "1.4.0"
version = "1.4.1"
dependencies = [
{org = "ballerina", name = "io"},
{org = "ballerina", name = "jballerina.java"},
{org = "ballerina", name = "log"},
{org = "ballerina", name = "persist"},
Expand Down
56 changes: 56 additions & 0 deletions ballerina/sql_client.bal
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,62 @@ public isolated client class SQLClient {
}
}

# Check whether associated entries exist for the given record.
#
# + 'object - The record to which the retrieved records should be appended
# + fields - The fields to be retrieved
# + include - The relations to be retrieved (SQL `JOINs` to be performed)
# + return - `()` if the operation is performed successfully or a `persist:Error` if the operation fails
public isolated function verifyEntityAssociation(anydata 'object, string[] fields, string[] include) returns persist:Error? {
if 'object !is record {} {
return error persist:Error("The 'object' parameter should be a record");
}

do {
// check the values of included entities are ()
foreach string joinKey in self.getJoinFields(include) {
JoinMetadata joinMetadata = self.joinMetadata.get(joinKey);
anydata associatedEntity = 'object.get(joinMetadata.fieldName);
if associatedEntity is record {} {
// check if the fields are empty in the associated record.
map<anydata> nonEmptyAssocEntity = associatedEntity.filter(value => value != ());
// If the associated entity has non-empty fields, then the association is already verified.
if nonEmptyAssocEntity.length() > 0 {
continue;
}

// check if the associated record values contain the foreign fields, if so, we can skip the query.
boolean hasKeys = true;
foreach string refColumn in joinMetadata.refColumns {
if !associatedEntity.hasKey(refColumn) {
hasKeys = false;
break;
}
}
if hasKeys {
'object[joinMetadata.fieldName] = ();
continue;
}
// construct the query to check whether the associated entries are exists
sql:ParameterizedQuery query = ``;
map<string> whereFilter = check self.getManyRelationWhereFilter('object, joinMetadata);
query = sql:queryConcat(
` SELECT COUNT(*) AS count`,
` FROM `, stringToParameterizedQuery(self.escape(joinMetadata.refTable)),
` WHERE`, check self.getWhereClauses(whereFilter, true)
);
// execute the query and check the count of the associated entries
int count = check self.dbClient->queryRow(query);
if count == 0 {
'object[joinMetadata.fieldName] = ();
}
}
}
} on fail error err {
return error persist:Error(err.message(), err);
}
}

public isolated function getKeyFields() returns string[] {
return self.keyFields;
}
Expand Down
2 changes: 2 additions & 0 deletions ballerina/stream_types.bal
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public class PersistSQLStream {
return <persist:Error>error(value.message());
}
check (<SQLClient>self.persistClient).getManyRelations(value, self.fields, self.include, self.typeDescriptions);
// verifies the entity association whether associated entity is available in the database.
check (<SQLClient>self.persistClient).verifyEntityAssociation(value, self.fields, self.include);

string[] keyFields = (<SQLClient>self.persistClient).getKeyFields();
foreach string keyField in keyFields {
Expand Down
73 changes: 73 additions & 0 deletions ballerina/tests/api_subscription_types.bal
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.org).
//
// WSO2 LLC. licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

public type Subscription record {|
readonly string subscriptionId;
string userName;
string apimetadataApiId;
string apimetadataOrgId;
|};

public type SubscriptionOptionalized record {|
string subscriptionId?;
string userName?;
string apimetadataApiId?;
string apimetadataOrgId?;
|};

public type SubscriptionWithRelations record {|
*SubscriptionOptionalized;
ApiMetadataOptionalized apimetadata?;
|};

public type SubscriptionTargetType typedesc<SubscriptionWithRelations>;

public type SubscriptionInsert Subscription;

public type SubscriptionUpdate record {|
string userName?;
string apimetadataApiId?;
string apimetadataOrgId?;
|};

public type ApiMetadata record {|
readonly string apiId;
readonly string orgId;
string apiName;
string metadata;

|};

public type ApiMetadataOptionalized record {|
string apiId?;
string orgId?;
string apiName?;
string metadata?;
|};

public type ApiMetadataWithRelations record {|
*ApiMetadataOptionalized;
SubscriptionOptionalized subscription?;
|};

public type ApiMetadataTargetType typedesc<ApiMetadataWithRelations>;

public type ApiMetadataInsert ApiMetadata;

public type ApiMetadataUpdate record {|
string apiName?;
string metadata?;
|};
118 changes: 118 additions & 0 deletions ballerina/tests/h2-optional-assoc-tests.bal
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.org).
//
// WSO2 LLC. licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/test;
import ballerina/persist;

@test:Config {
groups: ["assoc", "h2"]
}
function h2APMNoRelationsTest() returns error? {
H2ApimClient apimClient = check new ();

[string, string][] metaId = check apimClient->/apimetadata.post([{
apiId: "123457",
orgId: "wso2",
apiName: "abc",
metadata: "metadata"
}]);
test:assertEquals(metaId, [["123457", "wso2"]]);

stream<H2ApimWithSubscriptions, persist:Error?> streamResult = apimClient->/apimetadata();
H2ApimWithSubscriptions[] apimResults = check from H2ApimWithSubscriptions apiMetadata in streamResult
select apiMetadata;

test:assertEquals(apimResults.length(), 1);
test:assertEquals(apimResults[0].subscription, ());
check apimClient.close();
}

@test:Config {
groups: ["assoc", "h2"],
dependsOn: [mssqlAPMNoRelationsTest, mssqlAPMWithRelationsTest]
}
function h2APMWithoutRelationsTest() returns error? {
H2ApimClient apimClient = check new ();

stream<H2ApimWithoutSubscriptions, persist:Error?> streamResult = apimClient->/apimetadata();
H2ApimWithoutSubscriptions[] apimResults = check from H2ApimWithoutSubscriptions apiMetadata in streamResult
select apiMetadata;

test:assertEquals(apimResults.length(), 2);
test:assertEquals(apimResults[0], {
apiId: "123457",
orgId: "wso2",
apiName: "abc",
metadata: "metadata"
});
check apimClient.close();
}

@test:Config {
groups: ["assoc", "h2"],
dependsOn: [h2APMNoRelationsTest]
}
function h2APMWithRelationsTest() returns error? {
H2ApimClient apimClient = check new ();

[string, string][] metaId = check apimClient->/apimetadata.post([{
apiId: "123458",
orgId: "wso2",
apiName: "abc",
metadata: "metadata"
}]);
test:assertEquals(metaId, [["123458", "wso2"]]);

string[] subId = check apimClient->/subscriptions.post([{
subscriptionId: "123",
userName: "ballerina",
apimetadataApiId: "123458",
apimetadataOrgId: "wso2"
}]);
test:assertEquals(subId, ["123"]);

stream<H2ApimWithSubscriptions, persist:Error?> streamResult = apimClient->/apimetadata();
H2ApimWithSubscriptions[] apimResults = check from H2ApimWithSubscriptions apiMetadata in streamResult
select apiMetadata;

test:assertEquals(apimResults.length(), 2);

test:assertEquals(apimResults[0].subscription, ());
test:assertEquals(apimResults[1].subscription, {
subscriptionId: "123",
apimetadataApiId: "123458"
});
check apimClient.close();
}

type H2ApimWithSubscriptions record {|
string apiId;
string orgId;
string apiName;
string metadata;
record {|
string subscriptionId;
string apimetadataApiId;
|} subscription?;
|};


type H2ApimWithoutSubscriptions record {|
string apiId;
string orgId;
string apiName;
string metadata;
|};
Loading

0 comments on commit af6184a

Please sign in to comment.