Skip to content

Commit

Permalink
Validations, enhancements to serialization. Change name to AwsPersist…
Browse files Browse the repository at this point in the history
…ence (finos#496)
  • Loading branch information
rajamony committed Apr 22, 2022
1 parent d14ac88 commit 1cb1019
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,27 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import meta::external::format::cpb::generation::*;
import meta::external::format::awspersistence::generation::*;
import meta::pure::generation::metamodel::*;

Class meta::external::format::cpb::generation::CpbConfig extends GenerationConfiguration
Class meta::external::format::awspersistence::generation::AwsPersistenceConfig extends GenerationConfiguration
{
{doc.doc = 'A sample checkbox for cloud persistent backends that does nothing.'}
comment: String[0..1];
comment() {if($this.comment->isEmpty(), |'no-comment-provided', |$this.comment->toOne());} :String[1];
}


Class meta::external::format::cpb::generation::CpbOutput extends GenerationOutput
Class meta::external::format::awspersistence::generation::AwsPersistenceOutput extends GenerationOutput
{
}

function meta::external::format::cpb::generation::defaultConfig():CpbConfig[1]
function meta::external::format::awspersistence::generation::defaultConfig():AwsPersistenceConfig[1]
{
^CpbConfig();
^AwsPersistenceConfig();
}

function <<access.private, Generation.Configuration>> meta::external::format::cpb::generation::describeConfiguration():GenerationParameter[*]
function <<access.private, Generation.Configuration>> meta::external::format::awspersistence::generation::describeConfiguration():GenerationParameter[*]
{
meta::pure::generation::describeConfiguration(CpbConfig,meta::external::format::cpb::generation::defaultConfig__CpbConfig_1_,[]);
meta::pure::generation::describeConfiguration(AwsPersistenceConfig,meta::external::format::awspersistence::generation::defaultConfig__AwsPersistenceConfig_1_,[]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// TODO: Make this accessible only from meta::external::format::awspersistence::generation::generateBackend

import meta::pure::persistence::metamodel::*;
import meta::legend::service::metamodel::*;
import meta::pure::persistence::metamodel::trigger::*;
import meta::pure::persistence::metamodel::notifier::*;
import meta::pure::persistence::metamodel::persister::*;
import meta::pure::persistence::metamodel::persister::deduplication::*;
import meta::pure::persistence::metamodel::persister::ingestmode::*;
import meta::pure::persistence::metamodel::persister::audit::*;
import meta::pure::persistence::metamodel::persister::transactionmilestoning::*;
import meta::pure::runtime::*;

Class meta::external::format::awspersistence::metamodel::AwsPersistenceTargetShapeProperties
{
name: String[1];
awstype: Type[1];
}

Class meta::external::format::awspersistence::metamodel::AwsPersistenceTargetShape
{
name: String[1];
package: Package[1];
properties: meta::external::format::awspersistence::metamodel::AwsPersistenceTargetShapeProperties[*];
}

Class meta::external::format::awspersistence::metamodel::AwsPersistenceTarget
{
targetName: String[1];
connection: Connection[1];
// deduplicationStrategy: DeduplicationStrategy[1];
ingestMode: IngestMode[0..1];
shape: meta::external::format::awspersistence::metamodel::AwsPersistenceTargetShape[1];
}

Class meta::external::format::awspersistence::metamodel::AwsPersistence
{
documentation: String[1];
service: Service[1];
trigger: Trigger[1];
notifier: Notifier[1];
persister: Persister[0..1];
target: meta::external::format::awspersistence::metamodel::AwsPersistenceTarget[1..*];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2020 Goldman Sachs
//
// Licensed 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 meta::pure::persistence::metamodel::*;
import meta::legend::service::metamodel::*;
import meta::pure::persistence::metamodel::trigger::*;
import meta::pure::persistence::metamodel::notifier::*;
import meta::pure::persistence::metamodel::persister::*;
import meta::pure::persistence::metamodel::persister::targetshape::*;
import meta::pure::persistence::metamodel::persister::deduplication::*;
import meta::pure::persistence::metamodel::persister::ingestmode::snapshot::*;
import meta::pure::persistence::metamodel::persister::audit::*;
import meta::pure::persistence::metamodel::persister::transactionmilestoning::*;

import meta::external::format::awspersistence::metamodel::*;
import meta::external::format::awspersistence::serialization::*;
import meta::pure::functions::meta::*;
import meta::pure::runtime::*;


function meta::external::format::awspersistence::serialization::serialize(p: Persistence[1]): meta::external::format::awspersistence::metamodel::AwsPersistence[1]
{
let notifier = $p.notifier;
let nonpd = $notifier.notifyees->filter(n|!$n->instanceOf(PagerDutyNotifyee));
assertEmpty($nonpd, | 'AwsPersistence can currently only support PagerDuty notifees');

assert($p.persister->instanceOf(BatchPersister), | 'AwsPersistence can currently only handle batch persistence');
let bp = $p.persister->cast(@BatchPersister);

let apt = serializeShape($bp);

let pp = ^meta::external::format::awspersistence::metamodel::AwsPersistence(
documentation=$p.documentation,
notifier=$p.notifier,
trigger=$p.trigger,
service=$p.service,
// persister=$p.persister,
target=$apt
);

$pp;
}


function <<access.private>> meta::external::format::awspersistence::serialization::serializeShape(bp: BatchPersister[1]): meta::external::format::awspersistence::metamodel::AwsPersistenceTarget[1..*]
{
assert($bp.targetShape->instanceOf(FlatTarget), | 'AwsPersistence can currently only handle flat target shapes');
let ft = $bp.targetShape->cast(@FlatTarget);

let connection = $bp.connections;
assertSize($bp.connections, 1, 'Expecting exactly one Persister connection, found %s', [$bp.connections->size()]);
let c = $bp.connections->toOne();

// FIXME: Should these be validated in a common place for all generators?
let modelClass = $ft.modelClass;
assert($modelClass.generalizations.general.rawType == Any, | 'AwsPersistence requires the class in targetShape to not be generalized (i.e., not extend another class)');

let apt = serializeAwsPersistenceTarget($ft, $c, $modelClass);
$apt->toOneMany();
}

function <<access.private>> meta::external::format::awspersistence::serialization::serializeAwsPersistenceTarget(ft: FlatTarget[1], c: Connection[1], modelClass: Class<Any>[1]): meta::external::format::awspersistence::metamodel::AwsPersistenceTarget[1]
{
let properties = $modelClass.properties;
let nonprimitives = $properties->filter(p|! $p.genericType.rawType->toOne()->instanceOf(PrimitiveType));
assertEmpty($nonprimitives, 'Found non-primitive types in FlatTarget <%s>, only primitive types can be persisted', [$ft.targetName]);

let pts = $properties->map(p|
assertSize($p.name, 1, 'In FlatTarget <%s>, expected exactly one property name, found %s', [$ft.targetName, $p.name->size()]);
assertSize($p.genericType.rawType, 1, 'In FlatTarget <%s> for property <%s>, expected exactly one type, found %s', [$ft.targetName, $p.name->toOne(), $p.genericType.rawType->size()]);
^meta::external::format::awspersistence::metamodel::AwsPersistenceTargetShapeProperties(name=$p.name->toOne(), awstype=$p.genericType.rawType->toOne());
);
assertSize($modelClass.name, 1, 'Expecting exactly one modelClass name, found %s', [$modelClass.name->size()]);
assertSize($modelClass.package, 1, 'Expecting exactly one modelClass package, found %s', [$modelClass.package->size()]);

assert($ft.deduplicationStrategy->instanceOf(NoDeduplicationStrategy), 'AwsPersistence can currently only handle NoDeduplicationStrategy in FlatTarget <%s>', [$ft.targetName]);

let canHandle = 'NontemporalSnapshot, UnitemporalSnapshot';
assertSize($ft.ingestMode, 1, 'A supported IngestMode (%s) must be specified for FlatTarget <%s>', [$canHandle, $ft.targetName]);

$ft.ingestMode->toOne()->match([
u:UnitemporalSnapshot[1]|assert($u.transactionMilestoning->instanceOf(BatchIdTransactionMilestoning), 'In FlatTarget %s, for UnitemporalSnapshot, only BatchIdTransactionMilestoning is supported', [$ft.targetName]),
n:NontemporalSnapshot[1]|assert($n.auditing->instanceOf(NoAuditing), 'In FlatTarget %s, for NontemporalSnapshot, only NoAuditing is supported', [$ft.targetName]),
a:Any[1]|assert(false, 'AwsPersistence can currently only handle %s milestoning in FlatTarget <%s>', [$canHandle, $ft.targetName])
]);

let shape = ^meta::external::format::awspersistence::metamodel::AwsPersistenceTargetShape(name=$ft.modelClass.name->toOne(), package=$ft.modelClass.package->toOne(), properties=$pts);

let apt = ^meta::external::format::awspersistence::metamodel::AwsPersistenceTarget(
targetName=$ft.targetName,
connection=$c,
// deduplicationStrategy=$ft.deduplicationStrategy,
ingestMode=$ft.ingestMode,
shape=$shape
);

$apt;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import meta::external::format::cpb::generation::*;
import meta::external::format::awspersistence::generation::*;
import meta::pure::executionPlan::profiles::*;
import meta::external::format::cpb::generation::tests::*;
import meta::external::format::awspersistence::generation::tests::*;
import meta::json::*;

import meta::pure::persistence::metamodel::*;
Expand All @@ -29,19 +29,19 @@ import meta::pure::persistence::metamodel::persister::ingestmode::snapshot::*;
import meta::pure::persistence::metamodel::persister::deduplication::*;
import meta::legend::service::metamodel::*;

Profile meta::external::format::cpb::generation::tests::CpbProperty
Profile meta::external::format::awspersistence::generation::tests::AwsPersistenceProperty
{
tags: [
p1, p2, p3
];
}

Class <<access.private>> meta::external::format::cpb::generation::tests::A
Class <<access.private>> meta::external::format::awspersistence::generation::tests::A
{
a: String[1];
}

function <<access.private>> meta::external::format::cpb::generation::tests::getPersistence(): Persistence[1]
function <<access.private>> meta::external::format::awspersistence::generation::tests::getPersistence(): Persistence[1]
{
let package = meta::pure::functions::meta::pathToPackage('cnas::pipes', true);

Expand Down Expand Up @@ -85,10 +85,10 @@ function <<access.private>> meta::external::format::cpb::generation::tests::getP
}


function <<test.Test>> {serverVersion.start='v1_20_0'} meta::external::format::cpb::generation::tests::transform_persistenceToBackend(): Boolean[1]
function <<test.Test>> {serverVersion.start='v1_20_0'} meta::external::format::awspersistence::generation::tests::transform_persistenceToBackend(): Boolean[1]
{
let p = getPersistence();
let config = meta::external::format::cpb::generation::defaultConfig();
let config = meta::external::format::awspersistence::generation::defaultConfig();
let schema = transform(^$config(scopeElements=[$p]))->at(0)->at(0).content;
assertEquals('{"documentation":"Mountains persist for a long time","notifier":{"notifyees":[{"emailAddress":"basecamp@k2.com"},{"url":"http:\\/\\/mountains.are.cool"}]},"trigger":{},"service":"cnas::pipes","persister":{"targetShape":{"modelClass":{"package":"meta::external::format::cpb::generation::tests","name":"A","sourceInformation":{"source":"\\/core\\/external\\/format\\/cpb\\/tests\\/testCpbGenerator.pure","line":39,"column":74,"startLine":39,"startColumn":1,"endLine":42,"endColumn":1},"typeParameters":[],"generalizations":[{"rawType":"meta::pure::metamodel::type::Any","typeArguments":[]}],"properties":[{"name":"a","aggregation":"None","multiplicity":"1","genericType":{"rawType":"String","typeArguments":[]},"stereotypes":[],"taggedValues":[]}],"qualifiedProperties":[],"stereotypes":[{"profile":"meta::pure::profiles::access","value":"private"}],"taggedValues":[]},"targetName":"s3sink","deduplicationStrategy":{},"ingestMode":{"auditing":{}}}}}', $schema);
assertEquals('{"documentation":"Mountains persist for a long time","notifier":{"notifyees":[{"emailAddress":"basecamp@k2.com"},{"url":"http:\\/\\/mountains.are.cool"}]},"trigger":{},"service":"cnas::pipes","persister":{"targetShape":{"modelClass":{"package":"meta::external::format::awspersistence::generation::tests","name":"A","sourceInformation":{"source":"\\/core\\/external\\/format\\/awspersistence\\/tests\\/testAwsPersistenceGenerator.pure","line":39,"column":74,"startLine":39,"startColumn":1,"endLine":42,"endColumn":1},"typeParameters":[],"generalizations":[{"rawType":"meta::pure::metamodel::type::Any","typeArguments":[]}],"properties":[{"name":"a","aggregation":"None","multiplicity":"1","genericType":{"rawType":"String","typeArguments":[]},"stereotypes":[],"taggedValues":[]}],"qualifiedProperties":[],"stereotypes":[{"profile":"meta::pure::profiles::access","value":"private"}],"taggedValues":[]},"targetName":"s3sink","deduplicationStrategy":{},"ingestMode":{"auditing":{}}}}}', $schema);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import meta::json::*;
import meta::pure::generation::*;
import meta::pure::generation::metamodel::*;
import meta::pure::persistence::metamodel::*;
import meta::external::format::cpb::generation::*;
import meta::external::format::cpb::metamodel::*;
import meta::external::format::awspersistence::generation::*;
import meta::external::format::awspersistence::metamodel::*;

import meta::pure::persistence::metamodel::*;
import meta::pure::persistence::metamodel::trigger::*;
Expand All @@ -29,49 +29,48 @@ import meta::pure::persistence::metamodel::batch::mode::snapshot::*;
import meta::pure::persistence::metamodel::batch::audit::*;


function meta::external::format::cpb::generation::transform(input: CpbConfig[1]): CpbOutput[*]
function meta::external::format::awspersistence::generation::transform(input: AwsPersistenceConfig[1]): AwsPersistenceOutput[*]
{
meta::legend::test::mayExecuteLegendTest(
{clientVersion, serverVersion, serializationKind, host, port|
let fStr = 'meta::protocols::pure::'+$clientVersion+'::invocation::generation::cpb::legendGenerateCpb_CpbConfig_1__String_1__Integer_1__String_1__CpbOutput_MANY_';
let xf = $fStr->pathToElement()->cast(@Function<{CpbConfig[1], String[1], Integer[1], String[1]->CpbOutput[*]}>);
$xf->evaluate([$input, $host, $port, $serverVersion]->map(v|list($v)))->toOneMany()->cast(@CpbOutput);},
| meta::external::format::cpb::generation::internal_transform($input)
let fStr = 'meta::protocols::pure::'+$clientVersion+'::invocation::generation::awspersistence::legendGenerateAwsPersistence_AwsPersistenceConfig_1__String_1__Integer_1__String_1__AwsPersistenceOutput_MANY_';
let xf = $fStr->pathToElement()->cast(@Function<{AwsPersistenceConfig[1], String[1], Integer[1], String[1]->AwsPersistenceOutput[*]}>);
$xf->evaluate([$input, $host, $port, $serverVersion]->map(v|list($v)))->toOneMany()->cast(@AwsPersistenceOutput);},
| meta::external::format::awspersistence::generation::internal_transform($input)
)->toOneMany();
}

function <<access.private,Generation.Transformation>> meta::external::format::cpb::generation::internal_transform(input: CpbConfig[1]): CpbOutput[*]
function <<access.private,Generation.Transformation>> meta::external::format::awspersistence::generation::internal_transform(input: AwsPersistenceConfig[1]): AwsPersistenceOutput[*]
{
let possibleElement = $input.allPackageScopeElements()->filter(p|$p->instanceOf(Persistence))->cast(@Persistence);
assertNotEmpty($possibleElement, | 'No Persistence was found');
assertFalse($possibleElement->size()>1, | 'More than one Persistence was found');
$input->meta::external::format::cpb::generation::generateCpbFromPure($possibleElement->toOne()->cast(@Persistence));
$input->meta::external::format::awspersistence::generation::generateAwsPersistenceFromPure($possibleElement->toOne()->cast(@Persistence));
}


function meta::external::format::cpb::generation::generateCpbFromPureWithScope(config: CpbConfig[1]): CpbOutput[*]
function meta::external::format::awspersistence::generation::generateAwsPersistenceFromPureWithScope(config: AwsPersistenceConfig[1]): AwsPersistenceOutput[*]
{
let scopeElements = $config.allPackageScopeElements()->filter(p|$p->instanceOf(Persistence))->cast(@Persistence);
assertNotEmpty($scopeElements, 'At least one Persistence is needed to transform into cloud-persistent backend form');
$scopeElements->map(p| $config->meta::external::format::cpb::generation::generateCpbFromPure($p));
$scopeElements->map(p| $config->meta::external::format::awspersistence::generation::generateAwsPersistenceFromPure($p));
}

function meta::external::format::cpb::generation::generateCpbFromPure(config: CpbConfig[1], p: Persistence[1]): CpbOutput[*]
function meta::external::format::awspersistence::generation::generateAwsPersistenceFromPure(config: AwsPersistenceConfig[1], p: Persistence[1]): AwsPersistenceOutput[*]
{
let content = $p->generateCpbBackend();
let out = ^CpbOutput(content=$content,fileName=$p->elementToPath()->pathToFileName('cpb'), format='json');
let content = $p->generateAwsPersistenceBackend();
let out = ^AwsPersistenceOutput(content=$content,fileName=$p->elementToPath()->pathToFileName('awspersistence'), format='json');
$out;
}

function meta::external::format::cpb::generation::generateCpbBackend(p: Persistence[1]): String[1]
function meta::external::format::awspersistence::generation::generateAwsPersistenceBackend(p: Persistence[1]): String[1]
{
let jsonConfig = config(false, false, true, true);
let fileName = 'persistence/' + $p->elementToPath()->pathToFileName('json');
let content = ^PersistenceCPB(documentation=$p.documentation, notifier=$p.notifier, trigger=$p.trigger, service=$p.service, persister=$p.persister);
$content->toJSONElement(meta::external::format::cpb::generation::extraJsonSerializers(), 1000, $jsonConfig)->toCompactJSONString();
let content = meta::external::format::awspersistence::serialization::serialize($p);
$content->toJSONElement(meta::external::format::awspersistence::generation::extraJsonSerializers(), 1000, $jsonConfig)->toCompactJSONString();
}

function meta::external::format::cpb::generation::extraJsonSerializers():Function<{Nil[1],JSONState[1] ->JSONElement[1]}>[*]
function meta::external::format::awspersistence::generation::extraJsonSerializers():Function<{Nil[1],JSONState[1] ->JSONElement[1]}>[*]
{
[
// TODO: Add based on what _type we want etc. on the CNAS side
Expand Down

This file was deleted.

Loading

0 comments on commit 1cb1019

Please sign in to comment.