Skip to content

Commit 9d1bed3

Browse files
committedDec 13, 2023
Add support for some list functions (finos#49)
* Add support for some list functions Adds basic support for: - `List.map` with lambda returning record - `List.map` with lambda returning a single value - `List.filter` with lambda predicate - `List.sum` with `List.map` as its collection * Fixes for Code review comments
1 parent b128a69 commit 9d1bed3

File tree

4 files changed

+131
-14
lines changed

4 files changed

+131
-14
lines changed
 

‎src/Morphir/Snowpark/AccessElementMapping.elm

-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ mapVariableAccess : (IrType.Type a) -> Name.Name -> ValueMappingContext -> Scala
4343
mapVariableAccess _ name _ =
4444
Scala.Variable (name |> Name.toCamelCase)
4545

46-
47-
4846
mapConstructorAccess : (IrType.Type a) -> FQName.FQName -> ValueMappingContext -> Scala.Value
4947
mapConstructorAccess tpe name ctx =
5048
case tpe of
+103-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1-
module Morphir.Snowpark.MapFunctionsMapping exposing (..)
1+
module Morphir.Snowpark.MapFunctionsMapping exposing (mapFunctionsMapping)
2+
3+
import Dict as Dict
24
import Morphir.Scala.AST as Scala
35
import Morphir.IR.Value as Value exposing (Pattern(..), Value(..))
46
import Morphir.IR.Type exposing (Type)
5-
import Morphir.Snowpark.MappingContext exposing (ValueMappingContext)
7+
import Morphir.Snowpark.MappingContext exposing (ValueMappingContext, isCandidateForDataFrame)
8+
import Morphir.IR.Value exposing (valueAttribute)
9+
import Morphir.IR.Type as Type
10+
import Morphir.Snowpark.MappingContext exposing (isAnonymousRecordWithSimpleTypes)
11+
import Morphir.IR.Name as Name
12+
import Morphir.Snowpark.Constants exposing (applySnowparkFunc)
13+
import Morphir.Snowpark.MappingContext exposing (isBasicType)
614

15+
type alias MapValueType ta = Value ta (Type ()) -> ValueMappingContext -> Scala.Value
716

8-
mapFunctionsMapping : Value ta (Type ()) -> (Value ta (Type ()) -> ValueMappingContext -> Scala.Value) -> ValueMappingContext -> Scala.Value
17+
mapFunctionsMapping : Value ta (Type ()) -> MapValueType ta -> ValueMappingContext -> Scala.Value
918
mapFunctionsMapping value mapValue ctx =
1019
case value of
1120
Value.Apply _ (Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "member" ] )) predicate) sourceRelation ->
@@ -14,5 +23,95 @@ mapFunctionsMapping value mapValue ctx =
1423
applySequence = mapValue sourceRelation ctx
1524
in
1625
Scala.Apply (Scala.Select variable "in") [ Scala.ArgValue Nothing applySequence ]
26+
Value.Apply _ (Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "map" ] )) projection) sourceRelation ->
27+
generateForListMap projection sourceRelation ctx mapValue
28+
Value.Apply _ (Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "filter" ] )) predicate) sourceRelation ->
29+
generateForListFilter predicate sourceRelation ctx mapValue
30+
Value.Apply _ (Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "filter", "map" ] )) predicateAction) sourceRelation ->
31+
generateForListFilterMap predicateAction sourceRelation ctx mapValue
32+
Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "sum" ] )) collection ->
33+
generateForListSum collection ctx mapValue
34+
_ ->
35+
Scala.Literal (Scala.StringLit "To Do")
36+
37+
38+
generateForListSum : Value ta (Type ()) -> ValueMappingContext -> MapValueType ta -> Scala.Value
39+
generateForListSum collection ctx mapValue =
40+
case collection of
41+
Value.Apply _ (Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "map" ] )) _) sourceRelation ->
42+
if isCandidateForDataFrame (valueAttribute sourceRelation) ctx.typesContextInfo then
43+
case mapValue collection ctx of
44+
Scala.Apply col [Scala.ArgValue argName projectedExpr] ->
45+
let
46+
resultName = Scala.Literal (Scala.StringLit "result")
47+
asCall = Scala.Apply (Scala.Select projectedExpr "as") [Scala.ArgValue Nothing resultName]
48+
newSelect = Scala.Apply col [Scala.ArgValue argName asCall]
49+
sumCall = applySnowparkFunc "sum" [applySnowparkFunc "col" [resultName]]
50+
in
51+
Scala.Apply (Scala.Select newSelect "select") [Scala.ArgValue Nothing sumCall]
52+
_ ->
53+
Scala.Literal (Scala.StringLit "Unsupported sum scenario")
54+
else
55+
Scala.Literal (Scala.StringLit "Unsupported sum scenario")
56+
_ ->
57+
Scala.Literal (Scala.StringLit "Unsupported sum scenario")
58+
59+
generateForListFilter : Value ta (Type ()) -> (Value ta (Type ())) -> ValueMappingContext -> MapValueType ta -> Scala.Value
60+
generateForListFilter predicate sourceRelation ctx mapValue =
61+
if isCandidateForDataFrame (valueAttribute sourceRelation) ctx.typesContextInfo then
62+
case predicate of
63+
Value.Lambda _ _ binExpr ->
64+
Scala.Apply (Scala.Select (mapValue sourceRelation ctx) "filter") [Scala.ArgValue Nothing <| mapValue binExpr ctx]
65+
_ ->
66+
Scala.Literal (Scala.StringLit "To Do")
67+
else
68+
Scala.Literal (Scala.StringLit "Unsupported filter scenario")
69+
70+
71+
generateForListFilterMap : Value ta (Type ()) -> (Value ta (Type ())) -> ValueMappingContext -> MapValueType ta -> Scala.Value
72+
generateForListFilterMap predicate sourceRelation ctx mapValue =
73+
if isCandidateForDataFrame (valueAttribute sourceRelation) ctx.typesContextInfo then
74+
case predicate of
75+
Value.Lambda _ _ binExpr ->
76+
let
77+
selectCall = Scala.Apply (Scala.Select (mapValue sourceRelation ctx) "select") [Scala.ArgValue Nothing <| mapValue binExpr ctx]
78+
resultId = Scala.Literal <| Scala.StringLit "result"
79+
selectColumnAlias = Scala.Apply (Scala.Select selectCall "as ") [ Scala.ArgValue Nothing resultId ]
80+
isNotNullCall = Scala.Select (applySnowparkFunc "col" [ resultId ]) "is_not_null"
81+
in
82+
Scala.Apply (Scala.Select selectColumnAlias "filter") [Scala.ArgValue Nothing isNotNullCall]
83+
_ ->
84+
Scala.Literal (Scala.StringLit "Unsupported filterMap scenario")
85+
else
86+
Scala.Literal (Scala.StringLit "Unsupported filterMap scenario")
87+
88+
generateForListMap : Value ta (Type ()) -> (Value ta (Type ())) -> ValueMappingContext -> MapValueType ta -> Scala.Value
89+
generateForListMap projection sourceRelation ctx mapValue =
90+
if isCandidateForDataFrame (valueAttribute sourceRelation) ctx.typesContextInfo then
91+
case processLambdaWithRecordBody projection ctx mapValue of
92+
Just arguments ->
93+
Scala.Apply (Scala.Select (mapValue sourceRelation ctx) "select") arguments
94+
Nothing ->
95+
Scala.Literal (Scala.StringLit "Unsupported map scenario")
96+
else
97+
Scala.Literal (Scala.StringLit "Unsupported map scenario")
98+
99+
processLambdaWithRecordBody : Value ta (Type ()) -> ValueMappingContext -> MapValueType ta -> Maybe (List Scala.ArgValue)
100+
processLambdaWithRecordBody functionExpr ctx mapValue =
101+
case functionExpr of
102+
Value.Lambda (Type.Function _ _ returnType) (Value.AsPattern _ _ _) (Value.Record _ fields) ->
103+
if isAnonymousRecordWithSimpleTypes returnType ctx.typesContextInfo then
104+
Just (fields
105+
|> Dict.toList
106+
|> List.map (\(fieldName, value) -> (Name.toCamelCase fieldName, (mapValue value ctx)))
107+
|> List.map (\(fieldName, value) -> Scala.Apply (Scala.Select value "as") [Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit fieldName))])
108+
|> List.map (Scala.ArgValue Nothing))
109+
else
110+
Nothing
111+
Value.Lambda (Type.Function _ _ returnType) (Value.AsPattern _ _ _) expr ->
112+
if isBasicType returnType then
113+
Just [ Scala.ArgValue Nothing <| mapValue expr ctx ]
114+
else
115+
Nothing
17116
_ ->
18-
Scala.Literal (Scala.StringLit "To Do")
117+
Nothing

‎src/Morphir/Snowpark/MappingContext.elm

+25-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ module Morphir.Snowpark.MappingContext exposing
1111
, emptyContext
1212
, isCandidateForDataFrame
1313
, ValueMappingContext
14-
, emptyValueMappingContext )
14+
, emptyValueMappingContext
15+
, isAnonymousRecordWithSimpleTypes )
1516

1617
{-| This module contains functions to collect information about type definitions in a distribution.
1718
It classifies type definitions in the following kinds:
@@ -79,7 +80,6 @@ isUnionTypeRefWithoutParams tpe ctx =
7980
Type.Reference _ name _ -> isUnionTypeWithoutParams name ctx
8081
_ -> False
8182

82-
8383
isUnionTypeWithParams : FQName -> MappingContextInfo a -> Bool
8484
isUnionTypeWithParams name ctx =
8585
case Dict.get name ctx of
@@ -100,6 +100,13 @@ isCandidateForDataFrame typeRef ctx=
100100
isRecordWithSimpleTypes itemTypeName ctx
101101
_ -> False
102102

103+
isAnonymousRecordWithSimpleTypes : Type.Type () -> MappingContextInfo () -> Bool
104+
isAnonymousRecordWithSimpleTypes tpe ctx =
105+
case tpe of
106+
Type.Record _ fields ->
107+
List.all (\field -> isDataFrameFriendlyType field.tpe ctx) fields
108+
_ ->
109+
False
103110

104111
type TypeClassificationState a =
105112
TypeClassified (TypeDefinitionClassification a)
@@ -162,13 +169,26 @@ isAliasOfBasicType tpe ctx =
162169
|> Maybe.withDefault False
163170
_ -> False
164171

172+
isMaybeOfDataFrameFriendlyType : Type a -> MappingContextInfo a -> Bool
173+
isMaybeOfDataFrameFriendlyType tpe ctx =
174+
case tpe of
175+
Type.Reference _ ([["morphir"],["s","d","k"]],[["maybe"]],["maybe"]) [typeArg] ->
176+
isDataFrameFriendlyType typeArg ctx
177+
_ ->
178+
False
179+
180+
isDataFrameFriendlyType : Type a -> MappingContextInfo a -> Bool
181+
isDataFrameFriendlyType tpe ctx =
182+
isBasicType tpe
183+
|| (isUnionType tpe ctx)
184+
|| (isAliasOfBasicType tpe ctx)
185+
|| (isMaybeOfDataFrameFriendlyType tpe ctx)
186+
165187
classifyActualType : Type a -> MappingContextInfo a -> TypeClassificationState a
166188
classifyActualType tpe ctx =
167189
case tpe of
168190
Record _ members ->
169-
if List.all (\t -> (isBasicType t.tpe)
170-
|| (isUnionType t.tpe ctx)
171-
|| (isAliasOfBasicType t.tpe ctx)) members then
191+
if List.all (\t -> isDataFrameFriendlyType t.tpe ctx) members then
172192
TypeClassified RecordWithSimpleTypes
173193
else
174194
TypeWithPendingClassification (Just tpe)

‎tests/Morphir/Snowpark/MapValueListTests.elm

+3-3
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ memberTest =
7777
memberExpectedTest: Scala.Value
7878
memberExpectedTest =
7979
Scala.Apply (Scala.Select (Scala.Variable "v") "in") [ Scala.ArgValue Nothing listExpectedTest ]
80-
80+
8181
mapValueListTest : Test
8282
mapValueListTest =
8383
let
@@ -93,7 +93,7 @@ mapValueListTest =
9393
in
9494
describe "List functions"
9595
[
96-
assertListTest,
97-
assertMemberTest
96+
assertListTest
97+
, assertMemberTest
9898
]
9999

0 commit comments

Comments
 (0)
Please sign in to comment.