fix(inline): Nullable value in a nested struct [LNG-160] (#724)

Co-authored-by: InversionSpaces <InversionSpaces@vivaldi.net>
This commit is contained in:
Dima 2023-06-01 17:54:19 +02:00 committed by GitHub
parent 82f25dd993
commit ddb758cee0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 8 deletions

View File

@ -41,13 +41,20 @@ object CollectionRawInliner extends RawInliner[CollectionRaw] {
stream = VarModel(streamName, StreamType(raw.elementType))
streamExp = CallModel.Export(stream.name, stream.`type`)
vals <- raw.values
valsWithInlines <- raw.values
.traverse(valueToModel(_))
.map(_.toList)
.map(Chain.fromSeq)
.map(_.flatMap { case (v, t) =>
Chain.fromOption(t) :+ PushToStreamModel(v, streamExp).leaf
})
// push values to the stream, that is gathering the collection
vals = valsWithInlines.map { case (v, _) =>
PushToStreamModel(v, streamExp).leaf
}
// all inlines will be added before pushing values to the stream
inlines = valsWithInlines.flatMap { case (_, t) =>
Chain.fromOption(t)
}
canonName <-
if (raw.boxType.isStream) State.pure(streamName)
@ -61,17 +68,18 @@ object CollectionRawInliner extends RawInliner[CollectionRaw] {
raw.boxType match {
case ArrayType(_) =>
RestrictionModel(streamName, isStream = true).wrap(
SeqModel.wrap((vals :+ CanonicalizeModel(stream, canon).leaf).toList: _*)
SeqModel.wrap((inlines ++ vals :+ CanonicalizeModel(stream, canon).leaf).toList: _*)
)
case OptionType(_) =>
RestrictionModel(streamName, isStream = true).wrap(
SeqModel.wrap(
XorModel.wrap((vals :+ NullModel.leaf).toList: _*),
CanonicalizeModel(stream, canon).leaf
SeqModel.wrap(inlines.toList:_*),
XorModel.wrap((vals :+ NullModel.leaf).toList: _*),
CanonicalizeModel(stream, canon).leaf
)
)
case _ =>
SeqModel.wrap(vals.toList: _*)
SeqModel.wrap((inlines ++ vals).toList: _*)
}
)
}

View File

@ -0,0 +1,68 @@
package aqua.model.inline
import aqua.model.*
import aqua.model.inline.raw.{ApplyIntoCopyRawInliner, CollectionRawInliner}
import aqua.model.inline.state.InliningState
import aqua.raw.ops.*
import aqua.raw.value.{CollectionRaw, LiteralRaw, MakeStructRaw, VarRaw}
import aqua.types.{CanonStreamType, OptionType, ScalarType, StreamType, StructType}
import cats.data.{NonEmptyList, NonEmptyMap}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class CollectionRawInlinerSpec extends AnyFlatSpec with Matchers {
"collection inliner" should "unfold struct with nested options (bug LNG-160)" in {
val nestedType = StructType(
"nested_type",
NonEmptyMap.of("field1" -> ScalarType.u32)
)
val makeStruct =
MakeStructRaw(NonEmptyMap.of("field1" -> LiteralRaw.number(3)), nestedType)
val raw = CollectionRaw(NonEmptyList.of(makeStruct), OptionType(nestedType))
val (v, tree) =
RawValueInliner.valueToModel[InliningState](raw, false).run(InliningState()).value._2
val resultValue = VarModel("option-inline-0", CanonStreamType(nestedType))
v shouldBe resultValue
tree.get.equalsOrShowDiff(
// create a stream
RestrictionModel("option-inline", true).wrap(
SeqModel.wrap(
// create an object
CallServiceModel(
"json",
"obj",
LiteralModel.fromRaw(LiteralRaw.quote("field1")) :: LiteralModel.fromRaw(
LiteralRaw.number(3)
) :: Nil,
VarModel("nested_type_obj", nestedType)
).leaf,
XorModel.wrap(
SeqModel.wrap(
// push object to the stream
PushToStreamModel(
VarModel("nested_type_obj", nestedType),
CallModel.Export("option-inline", StreamType(nestedType))
).leaf
),
NullModel.leaf
),
// canonicalize the stream to use it after inlining
CanonicalizeModel(
VarModel("option-inline", StreamType(nestedType)),
CallModel.Export(resultValue.name, resultValue.baseType)
).leaf
)
)
) shouldBe true
}
}