Skip to content

Commit def1fba

Browse files
committed
Add query generation on tabular Function
1 parent 59e691b commit def1fba

File tree

19 files changed

+632
-2
lines changed

19 files changed

+632
-2
lines changed

legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-snowflake/legend-engine-xt-relationalStore-snowflake-pure/src/main/resources/core_relational_snowflake/relational/sqlQueryToString/snowflakeExtension.pure

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ function <<access.private>> meta::relational::functions::sqlQueryToString::snowf
5151
windowColumnProcessor = processWindowColumn_WindowColumn_1__SqlGenerationContext_1__String_1_,
5252
semiStructuredElementProcessor = processSemiStructuredElementForSnowflake_RelationalOperationElement_1__SqlGenerationContext_1__String_1_,
5353
tableFunctionParamProcessor = processTableFunctionParamPlaceHolder_RelationalOperationElement_1__SqlGenerationContext_1__String_1_,
54+
tabularFunctionProcessor = meta::relational::functions::sqlQueryToString::snowflake::tabularFunctionProcessor_String_1__String_1__String_1_,
5455
lateralJoinProcessor = processJoinTreeNodeWithLateralJoinForSnowflake_JoinTreeNode_1__DbConfig_1__Format_1__Extension_MANY__String_1_,
5556
joinProcessor = meta::relational::functions::sqlQueryToString::snowflake::processJoinForSnowflake_JoinTreeNode_1__DbConfig_1__Format_1__Extension_MANY__String_1_,
5657
joinStringsProcessor = processJoinStringsOperationForSnowflake_JoinStrings_1__SqlGenerationContext_1__String_1_,
@@ -98,6 +99,11 @@ function <<access.private>> meta::relational::functions::sqlQueryToString::snowf
9899
);
99100
}
100101

102+
function meta::relational::functions::sqlQueryToString::snowflake::tabularFunctionProcessor(schema:String[1], functionName: String[1]):String[1]
103+
{
104+
'table('+ if($schema=='', | $functionName,| $schema+'.'+$functionName) + '())';
105+
}
106+
101107
function meta::relational::functions::sqlQueryToString::snowflake::schemaIdentifierToString(identifier:String[1], dbConfig: DbConfig[1]):String[1]
102108
{
103109
$identifier->split('.')->map(s|$s->processIdentifierWithQuoteChar('"', $dbConfig))->joinStrings('.');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
// Copyright 2024 Goldman Sachs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
###Relational
16+
Database demo::udtf::DemoDb
17+
(
18+
Schema Org
19+
(
20+
Table Firm
21+
(
22+
firmId INTEGER,
23+
legalname VARCHAR(200)
24+
)
25+
TabularFunction Person
26+
(
27+
firstname VARCHAR(200),
28+
lastname VARCHAR(200),
29+
age INTEGER,
30+
associatedFirmId INTEGER
31+
)
32+
TabularFunction Person2
33+
(
34+
firstname VARCHAR(200),
35+
lastname VARCHAR(200),
36+
age INTEGER,
37+
associatedFirmId INTEGER
38+
)
39+
TabularFunction ParentAndChildren
40+
(
41+
firstname VARCHAR(200),
42+
lastname VARCHAR(200),
43+
id INTEGER,
44+
age INTEGER,
45+
parentId INTEGER
46+
)
47+
)
48+
49+
Join firm_person(Org.Firm.firmId = Org.Person.associatedFirmId)
50+
Join firm_person2(Org.Firm.firmId = Org.Person2.associatedFirmId)
51+
Join relationship(Org.ParentAndChildren.parentId = {target}.id)
52+
53+
)
54+
55+
56+
###Pure
57+
Class demo::udtf::Org::Firm
58+
{
59+
firmId: Integer[1];
60+
legalname: String[1];
61+
}
62+
63+
Class demo::udtf::Org::Person
64+
{
65+
firstname: String[1];
66+
lastname: String[1];
67+
age: Integer[1];
68+
associatedFirmId: Integer[1];
69+
id: Integer[1];
70+
}
71+
72+
Association demo::udtf::Person_person
73+
{
74+
parent: demo::udtf::Org::Person[1];
75+
children: demo::udtf::Org::Person[1..*];
76+
}
77+
78+
Association demo::udtf::firm_person
79+
{
80+
assoacitedFirm: demo::udtf::Org::Firm[1];
81+
associatedPerson: demo::udtf::Org::Person[1..*];
82+
}
83+
84+
function demo::udtf::Org::FirmToPerson(): meta::pure::tds::TabularDataSet[1]
85+
{
86+
demo::udtf::Org::Firm.all()
87+
->project(
88+
[
89+
x|$x.firmId,
90+
x|$x.associatedPerson.age
91+
],
92+
[
93+
'Firm Id',
94+
'Associated Person/Age'
95+
]
96+
)->from(
97+
demo::udtf::DemoMapping,
98+
demo::runtimes::DemoRuntime
99+
)
100+
}
101+
102+
function demo::udtf::Org::FirmToPersonWithFilterOnPerson(): meta::pure::tds::TabularDataSet[1]
103+
{
104+
demo::udtf::Org::Firm.all()->filter(
105+
x|$x.associatedPerson->exists(
106+
x_1|$x_1.firstname == 'David'
107+
)
108+
)->project(
109+
[
110+
x|$x.firmId,
111+
x|$x.associatedPerson.age
112+
],
113+
[
114+
'Firm Id',
115+
'Associated Person/Age'
116+
]
117+
)->from(
118+
demo::udtf::DemoMapping,
119+
demo::runtimes::DemoRuntime
120+
)
121+
}
122+
123+
function demo::udtf::Org::FirmToPersonWithFilterOnPersonUsingUnion(): meta::pure::tds::TabularDataSet[1]
124+
{
125+
demo::udtf::Org::Firm.all()->filter(
126+
x|$x.associatedPerson->exists(
127+
x_1|$x_1.firstname == 'David'
128+
)
129+
)->project(
130+
[
131+
x|$x.firmId,
132+
x|$x.associatedPerson.age
133+
],
134+
[
135+
'Firm Id',
136+
'Associated Person/Age'
137+
]
138+
)->from(
139+
demo::udtf::DemoMappingUnion,
140+
demo::runtimes::DemoRuntime
141+
)
142+
}
143+
144+
145+
function demo::udtf::Org::FetchChildrenViaSelfJoin(): meta::pure::tds::TabularDataSet[1]
146+
{
147+
demo::udtf::Org::Person.all()->project(
148+
[
149+
x|$x.firstname,
150+
x|$x.id,
151+
x|$x.children.age,
152+
x|$x.children.id,
153+
x|$x.children.firstname
154+
],
155+
[
156+
'Firstname',
157+
'Id',
158+
'Children/Age',
159+
'Children/Id',
160+
'Children/Firstname'
161+
]
162+
)->from(
163+
demo::udtf::DemoMappingSelfJoin,
164+
demo::runtimes::DemoRuntime
165+
)
166+
}
167+
168+
169+
###Mapping
170+
Mapping demo::udtf::DemoMapping
171+
(
172+
*demo::udtf::Org::Firm[f]: Relational
173+
{
174+
~primaryKey
175+
(
176+
[demo::udtf::DemoDb]Org.Firm.firmId,
177+
[demo::udtf::DemoDb]Org.Firm.legalname
178+
)
179+
~mainTable [demo::udtf::DemoDb]Org.Firm
180+
firmId: [demo::udtf::DemoDb]Org.Firm.firmId,
181+
legalname: [demo::udtf::DemoDb]Org.Firm.legalname
182+
}
183+
*demo::udtf::Org::Person[p]: Relational
184+
{
185+
186+
~mainTable [demo::udtf::DemoDb]Org.Person
187+
firstname: [demo::udtf::DemoDb]Org.Person.firstname,
188+
lastname: [demo::udtf::DemoDb]Org.Person.lastname,
189+
age: [demo::udtf::DemoDb]Org.Person.age
190+
}
191+
192+
demo::udtf::firm_person: Relational
193+
{
194+
AssociationMapping
195+
(
196+
assoacitedFirm[p,f]: [demo::udtf::DemoDb]@firm_person,
197+
associatedPerson[f,p]: [demo::udtf::DemoDb]@firm_person
198+
)
199+
}
200+
)
201+
202+
###Mapping
203+
Mapping demo::udtf::DemoMappingUnion
204+
(
205+
*demo::udtf::Org::Person: Operation
206+
{
207+
meta::pure::router::operations::union_OperationSetImplementation_1__SetImplementation_MANY_(p1,p2)
208+
}
209+
*demo::udtf::Org::Firm[f]: Relational
210+
{
211+
~primaryKey
212+
(
213+
[demo::udtf::DemoDb]Org.Firm.firmId,
214+
[demo::udtf::DemoDb]Org.Firm.legalname
215+
)
216+
~mainTable [demo::udtf::DemoDb]Org.Firm
217+
firmId: [demo::udtf::DemoDb]Org.Firm.firmId,
218+
legalname: [demo::udtf::DemoDb]Org.Firm.legalname
219+
}
220+
demo::udtf::Org::Person[p1]: Relational
221+
{
222+
~mainTable [demo::udtf::DemoDb]Org.Person
223+
firstname: [demo::udtf::DemoDb]Org.Person.firstname,
224+
lastname: [demo::udtf::DemoDb]Org.Person.lastname,
225+
age: [demo::udtf::DemoDb]Org.Person.age
226+
}
227+
demo::udtf::Org::Person[p2]: Relational
228+
{
229+
~mainTable [demo::udtf::DemoDb]Org.Person2
230+
firstname: [demo::udtf::DemoDb]Org.Person2.firstname,
231+
lastname: [demo::udtf::DemoDb]Org.Person2.lastname,
232+
age: [demo::udtf::DemoDb]Org.Person2.age
233+
}
234+
235+
demo::udtf::firm_person: Relational
236+
{
237+
AssociationMapping
238+
(
239+
assoacitedFirm[p1,f]: [demo::udtf::DemoDb]@firm_person,
240+
assoacitedFirm[p2,f]: [demo::udtf::DemoDb]@firm_person2,
241+
associatedPerson[f,p1]: [demo::udtf::DemoDb]@firm_person,
242+
associatedPerson[f,p2]: [demo::udtf::DemoDb]@firm_person2
243+
)
244+
}
245+
)
246+
247+
###Mapping
248+
Mapping demo::udtf::DemoMappingSelfJoin
249+
(
250+
*demo::udtf::Org::Person[p1]: Relational
251+
{
252+
~primaryKey
253+
(
254+
[demo::udtf::DemoDb]Org.ParentAndChildren.firstname
255+
)
256+
~mainTable [demo::udtf::DemoDb]Org.ParentAndChildren
257+
firstname: [demo::udtf::DemoDb]Org.ParentAndChildren.firstname,
258+
lastname: [demo::udtf::DemoDb]Org.ParentAndChildren.lastname,
259+
id: [demo::udtf::DemoDb]Org.ParentAndChildren.id,
260+
age: [demo::udtf::DemoDb]Org.ParentAndChildren.age
261+
}
262+
263+
demo::udtf::Person_person: Relational
264+
{
265+
AssociationMapping
266+
(
267+
children[p1,p1]: [demo::udtf::DemoDb]@relationship,
268+
parent[p1,p1]: [demo::udtf::DemoDb]@relationship
269+
)
270+
}
271+
)
272+
273+
###Connection
274+
RelationalDatabaseConnection demo::udtf::DemoSnowflakeConnection
275+
{
276+
store: demo::udtf::DemoDb;
277+
type: Snowflake;
278+
specification: Snowflake
279+
{
280+
name: 'SUMMIT_MDM_DATA';
281+
account: 'sfcedeawseast1d01';
282+
warehouse: 'DEMO_WH';
283+
region: 'us-east-1';
284+
};
285+
auth: SnowflakePublic
286+
{
287+
publicUserName: 'isThis';
288+
privateKeyVaultReference: 'Hi';
289+
passPhraseVaultReference: 'What';
290+
};
291+
}
292+
293+
294+
###Runtime
295+
Runtime demo::runtimes::DemoRuntime
296+
{
297+
mappings:
298+
[
299+
demo::udtf::DemoMapping
300+
];
301+
connections:
302+
[
303+
demo::udtf::DemoDb:
304+
[
305+
connection_2: demo::udtf::DemoSnowflakeConnection
306+
]
307+
];
308+
}
309+
310+
###Snowflake
311+
SnowflakeApp demo::udtf::snowflakeApp::App1
312+
{
313+
applicationName : 'App1_revised';
314+
function : demo::udtf::Org::FirmToPersonWithFilterOnPersonUsingUnion():TabularDataSet[1];
315+
ownership : Deployment { identifier: '441143'};
316+
description : 'test App';
317+
activationConfiguration : demo::udtf::DemoSnowflakeConnection;
318+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2024 Goldman Sachs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import meta::pure::executionPlan::toString::*;
16+
import meta::pure::profiles::*;
17+
18+
function <<test.Test>> meta::relational::tests::query::snowflake::testSimpleSelect():Any[*]
19+
{
20+
let result = meta::legend::compileLegendGrammar(readFile('/core_relational_snowflake/relational/tests/tabularFunctionModel.txt')->toOne());
21+
let func = $result->filter(f|$f->instanceOf(ConcreteFunctionDefinition))
22+
->cast(@ConcreteFunctionDefinition<Any>)->filter(c| $c.name=='FirmToPerson__TabularDataSet_1_')->toOne();
23+
let query = 'select "root".firmId as "Firm Id", "person_0".age as "Associated Person/Age" from Org.Firm as "root" left outer join table(Org.Person()) as "person_0" on ("root".firmId = "person_0".associatedFirmId)';
24+
assert(meta::pure::executionPlan::executionPlan($func, meta::relational::extension::relationalExtensions())->planToString(meta::relational::extension::relationalExtensions())->contains($query));
25+
}
26+
27+
function <<test.Test>> meta::relational::tests::query::snowflake::testExists():Any[*]
28+
{
29+
let result = meta::legend::compileLegendGrammar(readFile('/core_relational_snowflake/relational/tests/tabularFunctionModel.txt')->toOne());
30+
let func = $result->filter(f|$f->instanceOf(ConcreteFunctionDefinition))
31+
->cast(@ConcreteFunctionDefinition<Any>)->filter(c| $c.name=='FirmToPersonWithFilterOnPerson__TabularDataSet_1_')->toOne();
32+
let query = 'select "root".firmId as "Firm Id", "person_2".age as "Associated Person/Age" from Org.Firm as "root" left outer join (select distinct "person_1".associatedFirmId from table(Org.Person()) as "person_1" where "person_1".firstname = \'David\') as "person_0" on ("root".firmId = "person_0".associatedFirmId) left outer join table(Org.Person()) as "person_2" on ("root".firmId = "person_2".associatedFirmId) where "person_0".associatedFirmId is not null';
33+
assert(meta::pure::executionPlan::executionPlan($func, meta::relational::extension::relationalExtensions())->planToString(meta::relational::extension::relationalExtensions())->contains($query));
34+
}
35+
36+
function <<test.Test>> meta::relational::tests::query::snowflake::testExistsAndUnion():Any[*]
37+
{
38+
let result = meta::legend::compileLegendGrammar(readFile('/core_relational_snowflake/relational/tests/tabularFunctionModel.txt')->toOne());
39+
let func = $result->filter(f|$f->instanceOf(ConcreteFunctionDefinition))
40+
->cast(@ConcreteFunctionDefinition<Any>)->filter(c| $c.name=='FirmToPersonWithFilterOnPersonUsingUnion__TabularDataSet_1_')->toOne();
41+
let query = 'select "root".firmId as "Firm Id", "unionalias_0"."Personage_Person2age" as "Associated Person/Age" from Org.Firm as "root" left outer join (select "root".associatedFirmId as associatedFirmId_0, null as associatedFirmId_1, "root".age as "Personage_Person2age" from table(Org.Person()) as "root" UNION ALL select null as associatedFirmId_0, "root".associatedFirmId as associatedFirmId_1, "root".age as "Personage_Person2age" from table(Org.Person2()) as "root") as "unionalias_0" on ("root".firmId = "unionalias_0".associatedFirmId_0 or "root".firmId = "unionalias_0".associatedFirmId_1) where exists(select 1 from (select "root".associatedFirmId as associatedFirmId_0, null as associatedFirmId_1, "root".firstname as "Personfirstname_Person2firstname" from table(Org.Person()) as "root" UNION ALL select null as associatedFirmId_0, "root".associatedFirmId as associatedFirmId_1, "root".firstname as "Personfirstname_Person2firstname" from table(Org.Person2()) as "root") as "unionalias_1" where ("root".firmId = "unionalias_1".associatedFirmId_0 or "root".firmId = "unionalias_1".associatedFirmId_1) and "unionalias_1"."Personfirstname_Person2firstname" = \'David\')';
42+
assert(meta::pure::executionPlan::executionPlan($func, meta::relational::extension::relationalExtensions())->planToString(meta::relational::extension::relationalExtensions())->contains($query));
43+
}
44+
45+
function <<test.Test>> meta::relational::tests::query::snowflake::testSelfJoin():Any[*]
46+
{
47+
let result = meta::legend::compileLegendGrammar(readFile('/core_relational_snowflake/relational/tests/tabularFunctionModel.txt')->toOne());
48+
let func = $result->filter(f|$f->instanceOf(ConcreteFunctionDefinition))
49+
->cast(@ConcreteFunctionDefinition<Any>)->filter(c| $c.name=='FetchChildrenViaSelfJoin__TabularDataSet_1_')->toOne();
50+
let query = 'select "root".firstname as "Firstname", "root".id as "Id", "parentandchildren_1".age as "Children/Age", "parentandchildren_1".id as "Children/Id", "parentandchildren_1".firstname as "Children/Firstname" from table(Org.ParentAndChildren()) as "root" left outer join table(Org.ParentAndChildren()) as "parentandchildren_1" on ("root".parentId = "parentandchildren_1".id)';
51+
assert(meta::pure::executionPlan::executionPlan($func, meta::relational::extension::relationalExtensions())->planToString(meta::relational::extension::relationalExtensions())->contains($query));
52+
}

0 commit comments

Comments
 (0)