From 3a9be02485faeadb5919a6eaa9464e43e3669019 Mon Sep 17 00:00:00 2001 From: Mohammed Ibrahim Date: Mon, 8 Jan 2024 17:26:38 -0500 Subject: [PATCH] Add validation to hosted service (#2530) * Check string length before substring * Move generation to logic to pure * fix dependencies * fix dependencies * fix dependencies * Add validation for hostedService * add validations for hosted service --- .../core_hostedservice.definition.json | 1 - .../generation/generation.pure | 28 ++++++++++++++++++- .../showcase/showcaseServices.pure | 28 +++++++++---------- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice.definition.json b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice.definition.json index 6043e6c58dc..4b56cd2529d 100644 --- a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice.definition.json +++ b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice.definition.json @@ -2,7 +2,6 @@ "name": "core_hostedservice", "pattern": "(meta::external::function::activator::hostedService|meta::protocols)(::.*)?", "dependencies": [ - "platform", "platform", "platform_dsl_graph", "platform_dsl_mapping", diff --git a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice/generation/generation.pure b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice/generation/generation.pure index c2b3322ce9f..370d4609638 100644 --- a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice/generation/generation.pure +++ b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice/generation/generation.pure @@ -23,6 +23,7 @@ function meta::external::function::activator::hostedService::generation::printPl function meta::external::function::activator::hostedService::validator::validateService(s:HostedService[1]):Boolean[1] { + $s->validateFunctionParamsInPattern(); $s.function->validateFunction(); $s->validateReturnType(); } @@ -35,6 +36,31 @@ function meta::external::function::activator::hostedService::validator::validate ); } +function meta::external::function::activator::hostedService::validator::validateFunctionParamsInPattern(h:HostedService[1]): Boolean[1] +{ + let pattern = $h.pattern; + assert($pattern->startsWith('/'),'Pattern must start with backslash'); + let params = $h.function->functionType().parameters->evaluateAndDeactivate(); + let oneParams = $params->filter(p|$p->deactivate().multiplicity == PureOne); + let nonOneParams = $params->filter(p|!$p->deactivate().multiplicity == PureOne); + //all [1] params in pattern + $oneParams->map(p| assert($pattern->contains('{'+$p.name+'}'), 'Parameter '+$p.name+' with multiplicty [1] must be in service pattern.')); + //all non [1] params not in pattern + $nonOneParams->map(p| assert($pattern->contains('{'+$p.name+'}'), 'Parameter '+$p.name+' with multiplicty not [1] cannot be in service pattern.')); + //Service has a base pattern + let firstParamIndex = $pattern->indexOf('{'); + + assert(if($firstParamIndex != -1,| $firstParamIndex != 1,| true), 'Service must have a base pattern. Cannot start with a parameter'); + //no param in pattern that doesnt exist in function + if($firstParamIndex!=-1, + | + let withoutBase = $pattern->substring($firstParamIndex, $pattern->length()); + let leftOver = $oneParams.name->fold({b, a| $a->replace('{'+$b+'}','')}, $withoutBase->replace('/','')); + assert($leftOver->length()==0, 'Found unexpected params in pattern: '+$leftOver->replace('{','')->replace('}',' ')->trim()->replace(' ',','));, + | true); + true; +} + function meta::external::function::activator::hostedService::validator::validateFunction(func:Function[1]): Boolean[1] { $func->match([ @@ -70,7 +96,7 @@ function meta::external::function::activator::hostedService::generation::needsSe function meta::external::function::activator::hostedService::generation::recomposeServiceFunction(service:HostedService[1]):HostedService[1] { let result = if($service.function->functionReturnType()->needsSerialization(), - |let tree = getTree($service.function); println($service.function->functionReturnType().rawType); + |let tree = getTree($service.function); //println($service.function->functionReturnType().rawType); assert($service.binding->isNotEmpty() || $service.contentType->isNotEmpty() , 'Service needs serialization but no binding/contentType provides'); let binding = if($service.binding->isNotEmpty(), |$service.binding, diff --git a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice/showcase/showcaseServices.pure b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice/showcase/showcaseServices.pure index fc0350c5161..fed10a366c6 100644 --- a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice/showcase/showcaseServices.pure +++ b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice/showcase/showcaseServices.pure @@ -25,7 +25,7 @@ function meta::external::function::activator::hostedService::tests::simpleServic { let service = ^HostedService ( - pattern = '/service/{var}', + pattern = '/service', ownership = ^UserList(users = ['debelp', 'harted']), documentation = 'bla bla', autoActivateUpdates = true, @@ -54,7 +54,7 @@ function meta::external::function::activator::hostedService::tests::simpleServic { let service = ^HostedService ( - pattern = '/service/{var}', + pattern = '/service', ownership = ^UserList(users = ['debelp', 'harted']), documentation = 'bla bla', autoActivateUpdates = true, @@ -84,7 +84,7 @@ function meta::external::function::activator::hostedService::tests::simpleServic { let service = ^HostedService ( - pattern = '/service/{var}', + pattern = '/service', ownership = ^UserList(users = ['debelp', 'harted']), documentation = 'bla bla', autoActivateUpdates = true, @@ -109,7 +109,7 @@ function meta::external::function::activator::hostedService::tests::simpleServic { let service = ^HostedService ( - pattern = '/service/{var}', + pattern = '/service', ownership = ^UserList(users = ['debelp', 'harted']), documentation = 'bla bla', autoActivateUpdates = true, @@ -136,7 +136,7 @@ function meta::external::function::activator::hostedService::tests::simpleServic { let service = ^HostedService ( - pattern = '/service/{var}', + pattern = '/service', ownership = ^UserList(users = ['debelp', 'harted']), documentation = 'bla bla', autoActivateUpdates = true, @@ -163,7 +163,7 @@ function meta::external::function::activator::hostedService::tests::simpleServic { let service = ^HostedService ( - pattern = '/service/{var}', + pattern = '/service', ownership = ^UserList(users = ['debelp', 'harted']), binding = ^Binding(name='serviceBinding', contentType = 'application/json',modelUnit = meta::pure::model::unit::newModelUnit()->include(PersonX)), documentation = 'bla bla', @@ -182,7 +182,7 @@ function meta::external::function::activator::hostedService::tests::simpleServic { let service = ^HostedService ( - pattern = '/service/{var}', + pattern = '/service', ownership = ^UserList(users = ['debelp', 'harted']), contentType = 'application/json', documentation = 'bla bla', @@ -230,7 +230,7 @@ function meta::external::function::activator::hostedService::tests::simpleServic { let service = ^HostedService ( - pattern = '/service/{var}', + pattern = '/service', ownership = ^UserList(users = ['debelp', 'harted']), contentType = 'application/json', documentation = 'bla bla', @@ -291,7 +291,7 @@ function meta::external::function::activator::hostedService::tests::simpleServic { let service = ^HostedService ( - pattern = '/service/{var}', + pattern = '/service', ownership = ^UserList(users = ['debelp', 'harted']), documentation = 'bla bla', binding = ^Binding(name='serviceBinding', contentType = 'application/json',modelUnit = meta::pure::model::unit::newModelUnit()->include(PersonX)), @@ -322,11 +322,11 @@ function meta::external::function::activator::hostedService::tests::simpleServic { let service = ^HostedService ( - pattern = '/service/{var}', + pattern = '/service/{name}/{length}', ownership = ^UserList(users = ['debelp', 'harted']), documentation = 'bla bla', autoActivateUpdates = true, - function= meta::external::function::activator::hostedService::tests::simpleRelationalfunction_String_1__TabularDataSet_1_ + function= meta::external::function::activator::hostedService::tests::simpleRelationalfunction_String_1__Integer_1__TabularDataSet_1_ ); //validate $service->meta::external::function::activator::hostedService::validator::validateService(); @@ -334,9 +334,9 @@ function meta::external::function::activator::hostedService::tests::simpleServic $service->meta::external::function::activator::hostedService::generation::printPlan(); } -function meta::external::function::activator::hostedService::tests::simpleRelationalfunction(name:String[1]):TabularDataSet[1] +function meta::external::function::activator::hostedService::tests::simpleRelationalfunction(name:String[1], length:Integer[1]):TabularDataSet[1] { - PersonX.all()->filter(p|$p.firstName == $name)->project([col(p|$p.firstName, 'firstName'), col(p|$p.lastName, 'lastName')]) + PersonX.all()->filter(p|$p.firstName == $name || $p.lastName->length()==$length) ->project([col(p|$p.firstName, 'firstName'), col(p|$p.lastName, 'lastName')]) ->from(simpleRelationalMapping, testRuntime(dbInc)) } @@ -346,7 +346,7 @@ function meta::external::function::activator::hostedService::tests::simpleServic { let service = ^HostedService ( - pattern = '/service/{var}', + pattern = '/service/{tree}', ownership = ^UserList(users = ['debelp', 'harted']), documentation = 'bla bla', binding = ^Binding(name='serviceBinding', contentType = 'application/json',modelUnit = meta::pure::model::unit::newModelUnit()->include(PersonX)),