diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/metaExtension.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/metaExtension.pure index 8d124709cca..345a7f8f374 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/metaExtension.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/metaExtension.pure @@ -137,7 +137,7 @@ function {doc.doc = 'Recursively get all explicitly defined generalizations.'} meta::pure::functions::meta::hierarchicalAllGeneralizations(type : Type[1]) : Class[*] { let oneLevel = $type->validGeneralizations(); - $oneLevel->concatenate($oneLevel->map(c | $c->validGeneralizations()))->removeDuplicates(); + $oneLevel->concatenate($oneLevel->map(c | $c->hierarchicalAllGeneralizations()))->removeDuplicates(); } function {doc.doc = 'Get all inherited properties on the provided class'} diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/metaExtension.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/metaExtension.pure index 61856509c72..cdaa1245c65 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/metaExtension.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/metaExtension.pure @@ -355,3 +355,9 @@ function <> meta::pure::functions::meta::tests::testTypeNameAndPath() assertEquals( meta::pure::functions::tests::model::GeographicEntityType.CITY->typePath(),'meta::pure::functions::tests::model::GeographicEntityType'); } + +function <> meta::pure::functions::meta::tests::testAllGeneralizations(): Boolean[1] +{ + assertEquals(['Parent'], meta::pure::functions::meta::validGeneralizations(meta::pure::functions::meta::tests::packageA::Child)->map(t | $t.name)); + assertEquals(['Parent', 'GrandParent', 'GreatGrandParent'], meta::pure::functions::meta::hierarchicalAllGeneralizations(meta::pure::functions::meta::tests::packageA::Child)->map(t | $t.name)); +} \ No newline at end of file diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/metaExtention_funcs.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/metaExtention_funcs.pure index 0e42b3068ee..792f83c6cca 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/metaExtention_funcs.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/metaExtention_funcs.pure @@ -28,6 +28,26 @@ Class meta::pure::functions::meta::tests::packageA::ClassB } +Class meta::pure::functions::meta::tests::packageA::Child extends meta::pure::functions::meta::tests::packageA::Parent +{ + +} + +Class meta::pure::functions::meta::tests::packageA::Parent extends meta::pure::functions::meta::tests::packageA::GrandParent +{ + +} + +Class meta::pure::functions::meta::tests::packageA::GrandParent extends meta::pure::functions::meta::tests::packageA::GreatGrandParent +{ + +} + +Class meta::pure::functions::meta::tests::packageA::GreatGrandParent +{ + +} + function <> meta::pure::functions::meta::tests::packageA::myFunc():Boolean[1] { true diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/fromPure/sdl/fromPure_sdl.pure b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/fromPure/sdl/fromPure_sdl.pure index ff20e9fb6e8..d938f590a0a 100644 --- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/fromPure/sdl/fromPure_sdl.pure +++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/fromPure/sdl/fromPure_sdl.pure @@ -98,7 +98,7 @@ function meta::external::query::graphQL::binding::fromPure::sdl::transformPureTo ->distinct() ->filter(t | $t->instanceOf(Class)); - let extendedClasses = $allTypes->map(t | $t->validGeneralizations()); + let extendedClasses = $allTypes->map(t | $t->validGeneralizations())->removeDuplicates(); // Build types let graphQLTypes = $allTypes->map(c | @@ -301,11 +301,12 @@ function <> meta::external::query::graphQL::binding::fromPure::s let nonBuiltInScalars = $props->buildNonBuiltInGraphQLScalars($pureTypeToGraphQLScalarOverride); let isQueryClass = $c->hasGraphQLStereotype('Query'); let temporalStereotypes = $c->getTemporalStereotypes(); + let extended = if($isExtended, | [$c.name], | []); $nonBuiltInScalars ->concatenate( ^ObjectTypeDefinition( name = $c.name->toOne(), - implements = if($isExtended, | $c.name, | $c->validGeneralizations()->map(g | $g.name))->map(n | $n->toInterfaceTypeName()), + implements = $extended->concatenate($c->hierarchicalAllGeneralizations()->map(g | $g.name))->map(n | $n->toInterfaceTypeName()), directives = $temporalStereotypes->map(s | temporalityToDirectives()->get($s)->toOne())->map(def | ^Directive(name = $def.name))->concatenate(buildHierarchyDirective($c, false)), fields = $props ->map(p | @@ -351,7 +352,7 @@ function <> meta::external::query::graphQL::binding::fromPure::s let temporalStereotypes = $c->getTemporalStereotypes(); ^InterfaceTypeDefinition( name = $c.name->toOne()->toInterfaceTypeName(), - implements = $c->validGeneralizations()->map(g | $g.name)->map(n | $n->toInterfaceTypeName()), + implements = $c->hierarchicalAllGeneralizations()->map(g | $g.name)->map(n | $n->toInterfaceTypeName()), directives = $temporalStereotypes->map(s | temporalityToDirectives()->get($s)->toOne())->map(def | ^Directive(name = $def.name))->concatenate(buildHierarchyDirective($c, false)), fields = $props ->map(p | diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/fromPure/sdl/tests/simpleTest.pure b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/fromPure/sdl/tests/simpleTest.pure index 8cd0f84a6df..edc27b128bb 100644 --- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/fromPure/sdl/tests/simpleTest.pure +++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/fromPure/sdl/tests/simpleTest.pure @@ -21,6 +21,18 @@ Class meta::external::query::graphQL::binding::fromPure::sdl::tests::model::Pers age : Integer[1]; } +Class meta::external::query::graphQL::binding::fromPure::sdl::tests::model::NonEmployee extends meta::external::query::graphQL::binding::fromPure::sdl::tests::model::Person +{ +} + +Class meta::external::query::graphQL::binding::fromPure::sdl::tests::model::SelfEmployed extends meta::external::query::graphQL::binding::fromPure::sdl::tests::model::NonEmployee +{ +} + +Class meta::external::query::graphQL::binding::fromPure::sdl::tests::model::Contractor extends meta::external::query::graphQL::binding::fromPure::sdl::tests::model::SelfEmployed +{ +} + Class meta::external::query::graphQL::binding::fromPure::sdl::tests::model::Employee extends meta::external::query::graphQL::binding::fromPure::sdl::tests::model::Person { title: String[1]; @@ -32,6 +44,11 @@ Class meta::external::query::graphQL::binding::fromPure::sdl::tests::model::GSEm division: String[1]; } +Class meta::external::query::graphQL::binding::fromPure::sdl::tests::model::NonGSEmployee extends meta::external::query::graphQL::binding::fromPure::sdl::tests::model::Employee +{ + company: String[1]; +} + Class meta::external::query::graphQL::binding::fromPure::sdl::tests::model::Team { name: String[1]; @@ -473,7 +490,7 @@ function <> meta::external::query::graphQL::binding::fromPure::sdl::t let res = typesToGraphQLString([GSEmployee, Employee, Person]); assertEquals( - 'type Employee implements EmployeeInterface @extends(class: "Person") {\n' + + 'type Employee implements EmployeeInterface & PersonInterface @extends(class: "Person") {\n' + ' title: String!\n' + ' startDate: StrictDate!\n' + ' firstName: String\n' + @@ -502,7 +519,7 @@ function <> meta::external::query::graphQL::binding::fromPure::sdl::t ' _exists: Employee_bool_exp\n' + '}\n' + '\n' + - 'type GSEmployee implements EmployeeInterface @extends(class: "Employee") {\n' + + 'type GSEmployee implements EmployeeInterface & PersonInterface @extends(class: "Employee") {\n' + ' division: String!\n' + ' title: String!\n' + ' startDate: StrictDate!\n' + @@ -555,6 +572,93 @@ function <> meta::external::query::graphQL::binding::fromPure::sdl::t $res); } +function <> meta::external::query::graphQL::binding::fromPure::sdl::tests::testClassWithDeepMultipleInheritance():Boolean[1] +{ + let res = typesToGraphQLStringWithoutDynamicFilter([GSEmployee, NonGSEmployee, Employee, Person, NonEmployee, SelfEmployed, Contractor]); + + assertEquals( + 'type Contractor implements SelfEmployedInterface & NonEmployeeInterface & PersonInterface @extends(class: "SelfEmployed") {\n' + + ' firstName: String\n' + + ' lastName: String!\n' + + ' age: Int!\n' + + '}\n' + + '\n' + + 'type Employee implements EmployeeInterface & PersonInterface @extends(class: "Person") {\n' + + ' title: String!\n' + + ' startDate: StrictDate!\n' + + ' firstName: String\n' + + ' lastName: String!\n' + + ' age: Int!\n' + + '}\n' + + '\n' + + 'interface EmployeeInterface implements PersonInterface {\n' + + ' title: String!\n' + + ' startDate: StrictDate!\n' + + ' firstName: String\n' + + ' lastName: String!\n' + + ' age: Int!\n' + + '}\n' + + '\n' + + 'type GSEmployee implements EmployeeInterface & PersonInterface @extends(class: "Employee") {\n' + + ' division: String!\n' + + ' title: String!\n' + + ' startDate: StrictDate!\n' + + ' firstName: String\n' + + ' lastName: String!\n' + + ' age: Int!\n' + + '}\n' + + '\n' + + 'type NonEmployee implements NonEmployeeInterface & PersonInterface @extends(class: "Person") {\n' + + ' firstName: String\n' + + ' lastName: String!\n' + + ' age: Int!\n' + + '}\n' + + '\n' + + 'interface NonEmployeeInterface implements PersonInterface {\n' + + ' firstName: String\n' + + ' lastName: String!\n' + + ' age: Int!\n' + + '}\n' + + '\n' + + 'type NonGSEmployee implements EmployeeInterface & PersonInterface @extends(class: "Employee") {\n' + + ' company: String!\n' + + ' title: String!\n' + + ' startDate: StrictDate!\n' + + ' firstName: String\n' + + ' lastName: String!\n' + + ' age: Int!\n' + + '}\n' + + '\n' + + 'type Person implements PersonInterface {\n' + + ' firstName: String\n' + + ' lastName: String!\n' + + ' age: Int!\n' + + '}\n' + + '\n' + + 'interface PersonInterface {\n' + + ' firstName: String\n' + + ' lastName: String!\n' + + ' age: Int!\n' + + '}\n' + + '\n' + + 'type SelfEmployed implements SelfEmployedInterface & NonEmployeeInterface & PersonInterface @extends(class: "NonEmployee") {\n' + + ' firstName: String\n' + + ' lastName: String!\n' + + ' age: Int!\n' + + '}\n' + + '\n' + + 'interface SelfEmployedInterface implements NonEmployeeInterface & PersonInterface {\n' + + ' firstName: String\n' + + ' lastName: String!\n' + + ' age: Int!\n' + + '}\n' + + '\n' + + 'scalar StrictDate\n' + + '\n' + + 'directive @extends(class: String!) on OBJECT | INPUT_OBJECT', + $res); +} + function <> meta::external::query::graphQL::binding::fromPure::sdl::tests::testPropertyWithInheritance():Boolean[1] { let res = typesToGraphQLString([Team, Employee, Person]); diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/toPure/sdl/tests/simpleTest.pure b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/toPure/sdl/tests/simpleTest.pure index ec1033874a3..a42cab86264 100644 --- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/toPure/sdl/tests/simpleTest.pure +++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql/binding/toPure/sdl/tests/simpleTest.pure @@ -382,7 +382,7 @@ function <> meta::external::query::graphQL::binding::toPure::sdl::tes let pureTypes = graphQLToPure( '#GQL{' + - 'type Employee implements EmployeeInterface @extends(class: "Person") {\n' + + 'type Employee implements EmployeeInterface & PersonInterface @extends(class: "Person") {\n' + ' title: String!\n' + ' startDate: StrictDate!\n' + ' firstName: String\n' + @@ -398,7 +398,7 @@ function <> meta::external::query::graphQL::binding::toPure::sdl::tes ' age: Int!\n' + '}\n' + '\n' + - 'type GSEmployee implements EmployeeInterface @extends(class: "Employee") {\n' + + 'type GSEmployee implements EmployeeInterface & PersonInterface @extends(class: "Employee") {\n' + ' division: String!\n' + ' title: String!\n' + ' startDate: StrictDate!\n' +