Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow constant, inequalities and 'not' in XStore model joins #3205

Merged
merged 14 commits into from
Oct 30, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,22 @@ function <<access.private>> meta::external::store::relational::modelJoins::getCl
$classMappings->filter(c| $c.id == $id)->toOne('More than one class mapping at the given id: ' + $id);
}

function <<access.private>> meta::external::store::relational::modelJoins::getAttributeRelationalOperationElement(propertyImplementations:SimpleFunctionExpression[*], thisOrThat:String[1], id:String[1], classMappings:RootRelationalInstanceSetImplementation[*]):RelationalOperationElement[1]
function <<access.private>> meta::external::store::relational::modelJoins::convertToRelationalElement(vs:ValueSpecification[1], sourceSet:RootRelationalInstanceSetImplementation[1], targetSet: RootRelationalInstanceSetImplementation[1]):RelationalOperationElement[1]
{
let propertyImplementation = $propertyImplementations->filter(p|$p.parametersValues->cast(@VariableExpression).name->toOne()==$thisOrThat).func->toOne();
let classMapping = $classMappings->getClassMappingAtId($id);
let relationalPropertyMapping = $classMapping.propertyMappings->filter(p|$p.property==$propertyImplementation)->cast(@RelationalPropertyMapping)->toOne();
$relationalPropertyMapping.relationalOperationElement->toOne('Localized relational model joins cannot support more than one relational operation element per property mapping. Found on class mapping id: ' + $id);
$vs->match([
p : SimpleFunctionExpression[1] |
assert($p.func->instanceOf(Property),|'Expected only property function calls in model joins.');
let var = $p.parametersValues->evaluateAndDeactivate()->at(0);
assert($var->instanceOf(VariableExpression) && $var->cast(@VariableExpression).name->in(['this','that']),|'Properties of $this or $that can be accessed in model joins.');
let classMapping = if($var->cast(@VariableExpression).name == 'this', | $sourceSet, | $targetSet);
let relationalPropertyMapping = $classMapping.propertyMappings->filter(x|$x.property==$p.func)->cast(@RelationalPropertyMapping)->toOne();
$relationalPropertyMapping.relationalOperationElement->toOne('Localized relational model joins cannot support more than one relational operation element per property mapping. Found on class mapping id: ' + $classMapping.id);,

v : InstanceValue[1] |
assert($v.values->size() == 1 && ($v.values->toOne()->instanceOf(String) || $v.values->toOne()->instanceOf(Number) || $v.values->toOne()->instanceOf(Date)),|'The join key should only have one mapping.');
^Literal(value=$v.values->toOne());
]);

}

function <<access.private>> meta::external::store::relational::modelJoins::transformExpressionSequenceIntoJoin(expressionSequence: SimpleFunctionExpression[1], sourceId:String[1], targetId:String[1], classMappings:RootRelationalInstanceSetImplementation[*]): Join[1]
Expand All @@ -85,16 +95,15 @@ function <<access.private>> meta::external::store::relational::modelJoins::trans
let targetDatabase = $targetMainTableAlias.database->toOne();
let aggregatedDatabase = ^Database(includes=[$sourceDatabase, $targetDatabase]);

assertContains(['equal', 'not', 'and', 'or'], $functionOperator, 'Failed to translate XStore Property into Relational Property because function operator is not in standard list');
assertContains(['equal', 'not', 'and', 'or', 'greaterThanEqual', 'greaterThan', 'lessThanEqual', 'lessThan' ], $functionOperator, 'Failed to translate XStore Property into Relational Property because function operator is not in standard list');

let join = if(
$functionOperator=='equal' || $functionOperator=='not',
| let propertyImplementations = $expressionSequence.parametersValues->cast(@SimpleFunctionExpression)->evaluateAndDeactivate();
$functionOperator->in(['equal', 'greaterThanEqual', 'greaterThan', 'lessThanEqual', 'lessThan' ]),
| let expressionParameters = $expressionSequence.parametersValues->evaluateAndDeactivate();
let sourceSet = getClassMappingAtId($classMappings, $sourceId);
let targetSet = getClassMappingAtId($classMappings, $targetId);

let sourceRelationalOperationElement = getAttributeRelationalOperationElement($propertyImplementations, 'this', $sourceId, $classMappings);
let targetRelationalOperationElement = getAttributeRelationalOperationElement($propertyImplementations, 'that', $targetId, $classMappings);

let parameters = $sourceRelationalOperationElement->concatenate($targetRelationalOperationElement);
let parameters = $expressionParameters->map(e | $e->convertToRelationalElement($sourceSet, $targetSet));
let operation = ^DynaFunction(name=$functionOperator, parameters=$parameters);
^Join(
name=$joinName,
Expand All @@ -117,4 +126,3 @@ function <<access.private>> meta::external::store::relational::modelJoins::trans
);

}

Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ import meta::pure::alloy::connections::alloy::specification::*;

function <<test.BeforePackage>> meta::external::store::relational::modelJoins::test::setUp():Boolean[1]
{
let connection = meta::external::store::relational::tests::testRuntime(LocalTradesDatabase).connectionStores.connection->toOne()->cast(@DatabaseConnection);
let connection = meta::external::store::relational::tests::testRuntime(LocalTradesDatabase).connectionStores.connection->toOne()->cast(@meta::external::store::relational::runtime::DatabaseConnection);

executeInDb('Drop table if exists LegalEntity;', $connection);
executeInDb('Create Table LegalEntity (ENTITY_ID INT, name VARCHAR(32));', $connection);
executeInDb('insert into LegalEntity (ENTITY_ID, name) values (1, \'Firm X\');', $connection);
executeInDb('insert into LegalEntity (ENTITY_ID, name) values (2, \'Firm A\');', $connection);
executeInDb('Create Table LegalEntity (ENTITY_ID INT, name VARCHAR(32), value INT);', $connection);
executeInDb('insert into LegalEntity (ENTITY_ID, name, value) values (1, \'Firm X\', 12);', $connection);
executeInDb('insert into LegalEntity (ENTITY_ID, name, value) values (2, \'Firm A\', 13);', $connection);

executeInDb('Drop table if exists Trade;', $connection);
executeInDb('Create Table Trade(id INT, ENTITY_NAME_FK VARCHAR(32), value INT, ENTITY_ID_FK INT);', $connection);
executeInDb('insert into Trade (id, ENTITY_NAME_FK, value, ENTITY_ID_FK) values (1, \'Firm X\', 8, 1);', $connection);
executeInDb('insert into Trade (id, ENTITY_NAME_FK, value, ENTITY_ID_FK) values (2, \'Firm A\', 9, 2);', $connection);
executeInDb('insert into Trade (id, ENTITY_NAME_FK, value, ENTITY_ID_FK) values (3, \'Firm X\', 10, 1);', $connection);
executeInDb('insert into Trade (id, ENTITY_NAME_FK, value, ENTITY_ID_FK) values (4, \'Firm X\', 11, 1);', $connection);
executeInDb('Create Table Trade(id INT, ENTITY_NAME_FK VARCHAR(32), value INT, ENTITY_ID_FK INT, date DATE);', $connection);
executeInDb('insert into Trade (id, ENTITY_NAME_FK, value, ENTITY_ID_FK, date) values (1, \'Firm X\', 8, 1, \'2022-01-01\');', $connection);
executeInDb('insert into Trade (id, ENTITY_NAME_FK, value, ENTITY_ID_FK, date) values (2, \'Firm A\', 9, 2, \'2023-01-01\');', $connection);
executeInDb('insert into Trade (id, ENTITY_NAME_FK, value, ENTITY_ID_FK, date) values (3, \'Firm X\', 10, 1, \'2024-01-01\');', $connection);
executeInDb('insert into Trade (id, ENTITY_NAME_FK, value, ENTITY_ID_FK, date) values (4, \'Firm X\', 11, 1, \'2025-01-01\');', $connection);
true;
}

Expand Down Expand Up @@ -69,6 +69,38 @@ function <<test.Test>> meta::external::store::relational::modelJoins::test::test
);
}


function <<test.Test>> meta::external::store::relational::modelJoins::test::testJoinWithConstantDouble():Boolean[1]
{
let query = {|Trade.all()->project([x|$x.value,x|$x.client.name],['Value','Client/Name']);};
let xstoreResult = executionPlan($query, XStoreTradesMapping_withConstantDouble, getXStoreRuntime(),meta::relational::extension::relationalExtensions());
assertEquals('select "root".value as "Value", "legalentity_view_0".name as "Client/Name" from Trades.Trade as "root" left outer join (select "root".ENTITY_ID as ENTITY_ID, "root".name as name, "root".value as value from Entity.LegalEntity as "root" group by "root".ENTITY_ID) as "legalentity_view_0" on ("root".ENTITY_ID_FK = "legalentity_view_0".ENTITY_ID and "root".value = 1 and (2 <> "root".value OR "root".value is null) and 1 = 1)',
$xstoreResult.rootExecutionNode.executionNodes->at(0)->cast(@SQLExecutionNode).sqlQuery);
}

function <<test.Test>> meta::external::store::relational::modelJoins::test::testJoinWithConstantString():Boolean[1]
{
let query = {|Trade.all()->project([x|$x.value,x|$x.client.name],['Value','Client/Name']);};
let xstoreResult = executionPlan($query, XStoreTradesMapping_withConstantString, getXStoreRuntime(),meta::relational::extension::relationalExtensions());
assertEquals('select "root".value as "Value", "legalentity_view_0".name as "Client/Name" from Trades.Trade as "root" left outer join (select "root".ENTITY_ID as ENTITY_ID, "root".name as name, "root".value as value from Entity.LegalEntity as "root" group by "root".ENTITY_ID) as "legalentity_view_0" on ("root".ENTITY_ID_FK = "legalentity_view_0".ENTITY_ID and "root".ENTITY_ID_FK = \'foo\' and (\'bar\' <> "root".ENTITY_ID_FK OR "root".ENTITY_ID_FK is null))', $xstoreResult.rootExecutionNode.executionNodes->at(0)->cast(@SQLExecutionNode).sqlQuery);
}

function <<test.Test>> meta::external::store::relational::modelJoins::test::testJoinWithConstantDate():Boolean[1]
{
let query = {|Trade.all()->project([x|$x.value,x|$x.client.name],['Value','Client/Name']);};
let xstoreResult = executionPlan($query, XStoreTradesMapping_withConstantDate, getXStoreRuntime(),meta::relational::extension::relationalExtensions());
assertEquals('select "root".value as "Value", "legalentity_view_0".name as "Client/Name" from Trades.Trade as "root" left outer join (select "root".ENTITY_ID as ENTITY_ID, "root".name as name, "root".value as value from Entity.LegalEntity as "root" group by "root".ENTITY_ID) as "legalentity_view_0" on ("root".ENTITY_ID_FK = "legalentity_view_0".ENTITY_ID and "root".date = DATE\'2024-01-01\' and (DATE\'2024-01-01\' <> "root".date OR "root".date is null))',
$xstoreResult.rootExecutionNode.executionNodes->at(0)->cast(@SQLExecutionNode).sqlQuery);
}

function <<test.Test>> meta::external::store::relational::modelJoins::test::testJoinWithInequalities():Boolean[1]
{
let query = {|Trade.all()->project([x|$x.value,x|$x.client.name],['Value','Client/Name']);};
let xstoreResult = executionPlan($query, XStoreTradesMapping_withInequalities, getXStoreRuntime(),meta::relational::extension::relationalExtensions());
assertEquals('select "root".value as "Value", "legalentity_view_0".name as "Client/Name" from Trades.Trade as "root" left outer join (select "root".ENTITY_ID as ENTITY_ID, "root".name as name, "root".value as value from Entity.LegalEntity as "root" group by "root".ENTITY_ID) as "legalentity_view_0" on ("root".value >= "legalentity_view_0".value and "root".value > "legalentity_view_0".value and "root".value <= "legalentity_view_0".value and "root".value < "legalentity_view_0".value)',
$xstoreResult.rootExecutionNode.executionNodes->at(0)->cast(@SQLExecutionNode).sqlQuery);
}

function <<test.Test>> meta::external::store::relational::modelJoins::test::testPersonToFirmUsingFromProject():Boolean[1]
{
let xstoreResult = executionPlan({|Trade.all()->from(XStoreTradesMapping, getXStoreRuntime())->project([x|$x.value,x|$x.client.name],['Value','Client/Name']);}, meta::relational::extension::relationalExtensions());
Expand Down Expand Up @@ -115,12 +147,14 @@ Class meta::external::store::relational::modelJoins::test::LegalEntity
{
entityId: String[1];
name: String[1];
value: Integer[1];
}

Class meta::external::store::relational::modelJoins::test::Trade
{
id: String[1];
value: Integer[1];
date: Date[1];
}

Class meta::external::store::relational::modelJoins::test::OtherEntity
Expand Down Expand Up @@ -149,14 +183,16 @@ Database meta::external::store::relational::modelJoins::test::EntityDatabase
Table LegalEntity
(
ENTITY_ID VARCHAR(32) PRIMARY KEY,
name VARCHAR(32) NOT NULL
name VARCHAR(32) NOT NULL,
value INT NOT NULL
)

View LegalEntity_View
(
~groupBy (Entity.LegalEntity.ENTITY_ID)
ENTITY_ID: Entity.LegalEntity.ENTITY_ID,
name: Entity.LegalEntity.name
name: Entity.LegalEntity.name,
value: Entity.LegalEntity.value
)
)
)
Expand Down Expand Up @@ -192,7 +228,8 @@ Database meta::external::store::relational::modelJoins::test::XStoreTradesDataba
id VARCHAR(32) PRIMARY KEY,
value INTEGER NOT NULL,
ENTITY_ID_FK VARCHAR(32) NOT NULL,
ENTITY_NAME_FK VARCHAR(32) NOT NULL
ENTITY_NAME_FK VARCHAR(32) NOT NULL,
date DATE NOT NULL
)
)
)
Expand All @@ -211,7 +248,8 @@ Mapping meta::external::store::relational::modelJoins::test::LegalEntityMapping
)
~mainTable [meta::external::store::relational::modelJoins::test::EntityDatabase]Entity.LegalEntity_View
entityId: [meta::external::store::relational::modelJoins::test::EntityDatabase]Entity.LegalEntity_View.ENTITY_ID,
name: [meta::external::store::relational::modelJoins::test::EntityDatabase]Entity.LegalEntity_View.name
name: [meta::external::store::relational::modelJoins::test::EntityDatabase]Entity.LegalEntity_View.name,
value : [meta::external::store::relational::modelJoins::test::EntityDatabase]Entity.LegalEntity_View.value
}
)

Expand Down Expand Up @@ -274,3 +312,68 @@ Mapping meta::external::store::relational::modelJoins::test::XStoreTradesMapping
$that.entityIdFk && $this.name == $that.entityNameFk
}
)

Mapping meta::external::store::relational::modelJoins::test::TradesMapping
(
Trade[trade]: Relational
{
~primaryKey
(
[XStoreTradesDatabase]Trades.Trade.id
)
~mainTable [XStoreTradesDatabase]Trades.Trade
id: [XStoreTradesDatabase]Trades.Trade.id,
value: [XStoreTradesDatabase]Trades.Trade.value,
date: [XStoreTradesDatabase]Trades.Trade.date,
+entityIdFk: String[1]: [XStoreTradesDatabase]Trades.Trade.ENTITY_ID_FK,
+entityNameFk: String[1]: [XStoreTradesDatabase]Trades.Trade.ENTITY_NAME_FK
}
)

Mapping meta::external::store::relational::modelJoins::test::XStoreTradesMapping_withConstantDouble
(
include meta::external::store::relational::modelJoins::test::LegalEntityMapping
include meta::external::store::relational::modelJoins::test::TradesMapping

meta::external::store::relational::modelJoins::test::Trade_LegalEntity: XStore
{
client[trade, legal_entity]: $this.entityIdFk == $that.entityId && $this.value == 1 && 2 != $this.value && 1 == 1,
trades[legal_entity, trade]: $this.entityId == $that.entityIdFk && $that.value == 1 && 2 != $that.value && 1 == 1
}
)

Mapping meta::external::store::relational::modelJoins::test::XStoreTradesMapping_withConstantString
(
include meta::external::store::relational::modelJoins::test::LegalEntityMapping
include meta::external::store::relational::modelJoins::test::TradesMapping

meta::external::store::relational::modelJoins::test::Trade_LegalEntity: XStore
{
client[trade, legal_entity]: $this.entityIdFk == $that.entityId && $this.entityIdFk == 'foo' && 'bar' != $this.entityIdFk,
trades[legal_entity, trade]: $this.entityId == $that.entityIdFk && $that.entityIdFk == 'foo' && 'bar' != $that.entityIdFk
}
)

Mapping meta::external::store::relational::modelJoins::test::XStoreTradesMapping_withConstantDate
(
include meta::external::store::relational::modelJoins::test::LegalEntityMapping
include meta::external::store::relational::modelJoins::test::TradesMapping

meta::external::store::relational::modelJoins::test::Trade_LegalEntity: XStore
{
client[trade, legal_entity]: $this.entityIdFk == $that.entityId && $this.date == %2024-01-01 && %2024-01-01 != $this.date,
trades[legal_entity, trade]: $this.entityId == $that.entityIdFk && $that.date == %2024-01-01 && %2024-01-01 != $that.date
}
)

Mapping meta::external::store::relational::modelJoins::test::XStoreTradesMapping_withInequalities
(
include meta::external::store::relational::modelJoins::test::LegalEntityMapping
include meta::external::store::relational::modelJoins::test::TradesMapping

meta::external::store::relational::modelJoins::test::Trade_LegalEntity: XStore
{
client[trade, legal_entity]: ($this.value >= $that.value) && ($this.value > $that.value) && ($this.value <= $that.value) && ($this.value < $that.value),
trades[legal_entity, trade]: ($that.value >= $this.value) && ($that.value > $this.value) && ($that.value <= $this.value) && ($that.value < $this.value)
}
)
Loading