Skip to content

Commit

Permalink
Merge pull request #20 from dinukaamarasinghe817/connection-uri
Browse files Browse the repository at this point in the history
Fix issues with multiple associations between same entities
  • Loading branch information
dinukaamarasinghe817 authored Mar 23, 2024
2 parents 0f5ff0b + 180df91 commit 5ae4397
Show file tree
Hide file tree
Showing 10 changed files with 1,195 additions and 200 deletions.
2 changes: 2 additions & 0 deletions ballerina/metadata_types.bal
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public type RelationMetadata record {|
# + entity - The name of the entity that is being joined
# + fieldName - The name of the field in the `entity` that is being joined
# + refCollection - The name of the Redis collection to be joined
# + refMetaDataKey - The name of the Redis collection to be joined
# + refFields - The names of the fields of the refered collection
# + joinFields - The names of the join fields
# + joinCollection - The name of the joining collection used for a many-to-many relation
Expand All @@ -79,6 +80,7 @@ public type RefMetadata record {|
typedesc<record {}> entity;
string fieldName;
string refCollection;
string refMetaDataKey?;
string[] refFields;
string[] joinFields;
string joinCollection?;
Expand Down
20 changes: 10 additions & 10 deletions ballerina/redis_client.bal
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,12 @@ public isolated client class RedisClient {
if allRefFields.length() > 0 {
map<any> currentObject = check self.dbClient->hMGet(keyWithPrefix, allRefFields);
self.logQuery(HMGET, {key: keyWithPrefix, fieldNames: allRefFields.toJsonString()});
foreach RefMetadata refMedaData in self.refMetadata {
string refKey = refMedaData.refCollection;
foreach string refField in refMedaData.joinFields {
foreach RefMetadata refMetaData in self.refMetadata {
string refKey = refMetaData.refCollection;
foreach string refField in refMetaData.joinFields {
refKey += string `${KEY_SEPERATOR}${currentObject[refField].toString()}`;
}
string setKey = string `${refKey}${KEY_SEPERATOR}${self.collectionName}`;
string setKey = string `${refKey}${KEY_SEPERATOR}${refMetaData.refMetaDataKey ?: ""}`;
_ = check self.dbClient->sRem(setKey, [keySuffix.substring(1)]);
self.logQuery(SREM, {key: setKey, suffixes: [keySuffix].toJsonString()});
}
Expand Down Expand Up @@ -339,7 +339,7 @@ public isolated client class RedisClient {
}

// Get keys of existing associations
string setKey = string `${newRelatedRecordKey}${KEY_SEPERATOR}${self.collectionName}`;
string setKey = string `${newRelatedRecordKey}${KEY_SEPERATOR}${refMetaData.refMetaDataKey ?: ""}`;
int isKeyExists = check self.dbClient->exists([setKey]);
self.logQuery(EXISTS, [setKey]);
if isKeyExists != 0 {
Expand Down Expand Up @@ -394,15 +394,15 @@ public isolated client class RedisClient {
prevRelatedRecordKey += string `${KEY_SEPERATOR}${prevRecord[joinField].toString()}`;
}
// Attach to new association
string newSetKey = string `${newRelatedRecordKey}${KEY_SEPERATOR}${self.collectionName}`;
string newSetKey = string `${newRelatedRecordKey}${KEY_SEPERATOR}${refMetaData.refMetaDataKey ?: ""}`;
int|error sAdd = self.dbClient->sAdd(newSetKey, [recordKeySuffix.substring(1)]);
if sAdd is error {
return error persist:Error(sAdd.message(), sAdd);
}
self.logQuery(SADD, {key: newSetKey, suffixes: [recordKeySuffix].toJsonString()});

// Detach from previous association
string prevSetKey = string `${prevRelatedRecordKey}${KEY_SEPERATOR}${self.collectionName}`;
string prevSetKey = string `${prevRelatedRecordKey}${KEY_SEPERATOR}${refMetaData.refMetaDataKey ?: ""}`;
int|error sRem = self.dbClient->sRem(prevSetKey, [recordKeySuffix.substring(1)]);
if sRem is error {
return error persist:Error(sRem.message(), sRem);
Expand Down Expand Up @@ -521,7 +521,7 @@ public isolated client class RedisClient {

if refMetaData.joinFields == self.keyFields {
// Non-owner have direct access to the association set
string setKey = string `${self.getKeyFromObject('object)}${KEY_SEPERATOR}${refMetaData.refCollection}`;
string setKey = string `${self.getKeyFromObject('object)}${KEY_SEPERATOR}${refMetaData.fieldName}`;
string[] keys = check self.dbClient->sMembers(setKey);
self.logQuery(SMEMBERS, setKey);
return from string key in keys
Expand Down Expand Up @@ -666,7 +666,7 @@ public isolated client class RedisClient {
}

// Check the cardinality of refered entity record
string setKey = string `${refRecordKey}${KEY_SEPERATOR}${self.collectionName}`;
string setKey = string `${refRecordKey}${KEY_SEPERATOR}${refMetadataValue.refMetaDataKey ?: ""}`;
int|error sCard = self.dbClient->sCard(setKey);
self.logQuery(SCARD, setKey);
if sCard is int && sCard > 0 && refMetadataValue.'type == ONE_TO_ONE {
Expand Down Expand Up @@ -756,7 +756,7 @@ public isolated client class RedisClient {
time:TimeOfDay output = {
hour: check int:fromString(timeValues[0]),
minute: check int:fromString(
timeValues[1]),
timeValues[1]),
second: check decimal:fromString(timeValues[2])
};
return output;
Expand Down
156 changes: 141 additions & 15 deletions ballerina/tests/init-test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/test;
import ballerina/time;
import ballerinax/redis;
Expand All @@ -36,8 +35,16 @@ AllTypes allTypes1 = {
dateType: {year: 1993, month: 11, day: 3},
timeOfDayType: {hour: 12, minute: 32, second: 34},
utcType: [1684493685, 0.998012],
civilType: {utcOffset: {hours: 5, minutes: 30, seconds: 0}, timeAbbrev: "Asia/Colombo", year: 2024, month: 2,
day: 27, hour: 10, minute: 30, second: 21},
civilType: {
utcOffset: {hours: 5, minutes: 30, seconds: 0},
timeAbbrev: "Asia/Colombo",
year: 2024,
month: 2,
day: 27,
hour: 10,
minute: 30,
second: 21
},
booleanTypeOptional: false,
intTypeOptional: 5,
floatTypeOptional: 6.0,
Expand All @@ -46,8 +53,16 @@ AllTypes allTypes1 = {
dateTypeOptional: {year: 1993, month: 11, day: 3},
timeOfDayTypeOptional: {hour: 12, minute: 32, second: 34},
utcTypeOptional: [1684493685, 0.998012],
civilTypeOptional: {utcOffset: {hours: 5, minutes: 30, seconds: 0}, timeAbbrev: "Asia/Colombo", year: 2024,
month: 2, day: 27, hour: 10, minute: 30, second: 21},
civilTypeOptional: {
utcOffset: {hours: 5, minutes: 30, seconds: 0},
timeAbbrev: "Asia/Colombo",
year: 2024,
month: 2,
day: 27,
hour: 10,
minute: 30,
second: 21
},
enumType: "TYPE_3",
enumTypeOptional: "TYPE_2"
};
Expand Down Expand Up @@ -86,8 +101,16 @@ AllTypes allTypes2 = {
dateType: {year: 1996, month: 11, day: 3},
timeOfDayType: {hour: 17, minute: 32, second: 34},
utcType: [1684493685, 0.998012],
civilType: {utcOffset: {hours: 5, minutes: 30, seconds: 0}, timeAbbrev: "Asia/Colombo", year: 2024, month: 2,
day: 27, hour: 10, minute: 30, second: 21},
civilType: {
utcOffset: {hours: 5, minutes: 30, seconds: 0},
timeAbbrev: "Asia/Colombo",
year: 2024,
month: 2,
day: 27,
hour: 10,
minute: 30,
second: 21
},
booleanTypeOptional: true,
intTypeOptional: 6,
floatTypeOptional: 66.0,
Expand All @@ -96,8 +119,16 @@ AllTypes allTypes2 = {
dateTypeOptional: {year: 1293, month: 11, day: 3},
timeOfDayTypeOptional: {hour: 19, minute: 32, second: 34},
utcTypeOptional: [1684493685, 0.998012],
civilTypeOptional: {utcOffset: {hours: 5, minutes: 30, seconds: 0}, timeAbbrev: "Asia/Colombo", year: 2024,
month: 2, day: 27, hour: 10, minute: 30, second: 21},
civilTypeOptional: {
utcOffset: {hours: 5, minutes: 30, seconds: 0},
timeAbbrev: "Asia/Colombo",
year: 2024,
month: 2,
day: 27,
hour: 10,
minute: 30,
second: 21
},
enumType: "TYPE_1",
enumTypeOptional: "TYPE_3"
};
Expand Down Expand Up @@ -136,8 +167,16 @@ AllTypes allTypes3 = {
dateType: {year: 1996, month: 11, day: 3},
timeOfDayType: {hour: 17, minute: 32, second: 34},
utcType: [1684493685, 0.998012],
civilType: {utcOffset: {hours: 5, minutes: 30, seconds: 0}, timeAbbrev: "Asia/Colombo", year: 2024, month: 2,
day: 27, hour: 10, minute: 30, second: 21},
civilType: {
utcOffset: {hours: 5, minutes: 30, seconds: 0},
timeAbbrev: "Asia/Colombo",
year: 2024,
month: 2,
day: 27,
hour: 10,
minute: 30,
second: 21
},
enumType: "TYPE_1"
};

Expand Down Expand Up @@ -165,8 +204,16 @@ AllTypes allTypes1Updated = {
dateType: {year: 1996, month: 12, day: 13},
timeOfDayType: {hour: 16, minute: 12, second: 14},
utcType: [1686493685, 0.996012],
civilType: {utcOffset: {hours: 6, minutes: 0, seconds: 0}, timeAbbrev: "Asia/Colombo", year: 2022, month: 12,
day: 7, hour: 14, minute: 5, second: 43},
civilType: {
utcOffset: {hours: 6, minutes: 0, seconds: 0},
timeAbbrev: "Asia/Colombo",
year: 2022,
month: 12,
day: 7,
hour: 14,
minute: 5,
second: 43
},
booleanTypeOptional: true,
intTypeOptional: 53,
floatTypeOptional: 26.0,
Expand All @@ -175,8 +222,16 @@ AllTypes allTypes1Updated = {
dateTypeOptional: {year: 1923, month: 11, day: 3},
timeOfDayTypeOptional: {hour: 18, minute: 32, second: 34},
utcTypeOptional: [1686493685, 0.996012],
civilTypeOptional: {utcOffset: {hours: 6, minutes: 0, seconds: 0}, timeAbbrev: "Asia/Colombo", year: 2022,
month: 12, day: 7, hour: 14, minute: 5, second: 43},
civilTypeOptional: {
utcOffset: {hours: 6, minutes: 0, seconds: 0},
timeAbbrev: "Asia/Colombo",
year: 2022,
month: 12,
day: 7,
hour: 14,
minute: 5,
second: 43
},
enumType: "TYPE_4",
enumTypeOptional: "TYPE_4"
};
Expand Down Expand Up @@ -740,3 +795,74 @@ EmployeeInfo employeeInfoNative3 = {
locationBuildingCode: "building-native-3"
}
};

public type PersonWithAssociations record {|
int id;
string name;
record {|
string code;
|}[] soldBuildings;
record {|
string code;
|}[] ownBuildings;
|};

Person person1 = {
id: 1,
name: "Jane"
};

Person person2 = {
id: 2,
name: "Mike"
};

PersonUpdate person1Update = {
name: "Mary"
};

Person person1Updated = {
id: 1,
name: "Mary"
};

Apartment apartment1 = {
code: "B001",
city: "New York",
state: "New York",
country: "USA",
postalCode: "10001",
'type: "Studio",
soldpersonId: 1,
ownpersonId: 2
};

ApartmentUpdate apartmentUpdate = {
postalCode: "00002"
};

Apartment apartment1Updated = {
code: "B001",
city: "New York",
state: "New York",
country: "USA",
postalCode: "00002",
'type: "Studio",
soldpersonId: 1,
ownpersonId: 2
};

PersonWithAssociations person1WithAssociations = {
id: 1,
name: "Jane",
soldBuildings: [
{
code: "B001"
}
],
ownBuildings: [
{
code: "B002"
}
]
};
36 changes: 36 additions & 0 deletions ballerina/tests/persist/associations.bal
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com).
//
// 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/persist as _;

type Person record {|
readonly int id;
string name;

Apartment[] soldBuildings;
Apartment[] ownBuildings;
|};

type Apartment record {|
readonly string code;
string city;
string state;
string country;
string postalCode;
string 'type;

Person soldPerson;
Person ownPerson;
|};
3 changes: 2 additions & 1 deletion ballerina/tests/persist/rainier.bal
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/time;

enum Gender {
Expand All @@ -30,6 +29,7 @@ type Employee record {|
time:Date hireDate;

Department department;
Department? headOf;
Workspace workspace;
|};

Expand Down Expand Up @@ -57,6 +57,7 @@ type Department record {|
string deptName;

Employee[] employees;
Employee departmentHead;
|};

type OrderItem record {|
Expand Down
Loading

0 comments on commit 5ae4397

Please sign in to comment.