Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

W-16006973: add avro annotations #2021

Merged
merged 4 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
import amf.core.internal.parser.YMapOps
import amf.shapes.client.scala.model.domain.AnyShape
import org.yaml.model.{YMap, YMapEntry}
import amf.shapes.internal.annotations.AVROSchemaType
import org.yaml.model.YScalar

abstract class AvroCollectionShapeParser[T <: AnyShape](map: YMap, membersKey: String)(implicit ctx: AvroSchemaContext)
extends AvroComplexShapeParser(map) {
Expand All @@ -20,5 +22,14 @@ abstract class AvroCollectionShapeParser[T <: AnyShape](map: YMap, membersKey: S
shape
}

protected def parseMembers(e: YMapEntry): AnyShape = AvroTextTypeParser(e.value.as[String], None).parse()
protected def parseMembers(e: YMapEntry): AnyShape = {
e.value.value match {
case scalar: YScalar =>
val avroType = scalar.text
val parsedShape = AvroTextTypeParser(avroType, None).parse()
parsedShape.annotations += AVROSchemaType(avroType)
parsedShape
case map: YMap => new AvroShapeParser(map).parse().getOrElse(AnyShape())
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package amf.apicontract.internal.spec.avro.parser.domain

import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
import amf.core.client.scala.model.domain.Shape
import amf.core.internal.datanode.DataNodeParser
import amf.core.internal.metamodel.domain.ShapeModel
import amf.core.internal.parser.YMapOps
import amf.core.internal.parser.domain.Annotations
import amf.shapes.client.scala.model.domain.AnyShape
import amf.shapes.internal.annotations.AVROSchemaType
import amf.shapes.internal.domain.metamodel.AnyShapeModel
import amf.shapes.internal.spec.common.parser.QuickFieldParserOps
import org.yaml.model._
Expand Down Expand Up @@ -63,4 +65,6 @@ trait AvroKeyExtractor {
def isPrimitive: Boolean =
Seq("null", "boolean", "int", "long", "float", "double", "bytes", "string").contains(value)
}

def getAvroType(shape: Shape): Option[AVROSchemaType] = shape.annotations.find(classOf[AVROSchemaType])
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package amf.apicontract.internal.spec.avro.parser.domain

import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
import amf.core.client.scala.model.DataType
import amf.core.client.scala.model.domain.ScalarNode
import amf.core.client.scala.model.domain.{AmfArray, ScalarNode}
import amf.core.internal.metamodel.domain.ShapeModel
import amf.core.internal.parser.domain.Annotations
import amf.core.internal.parser.{YMapOps, YScalarYRead}
import amf.shapes.client.scala.model.domain.AnyShape
import org.yaml.model._
Expand All @@ -18,10 +20,10 @@ class AvroEnumParser(map: YMap)(implicit ctx: AvroSchemaContext) extends AvroTex
}

override def parseSpecificFields(): Unit = {
map
.key("symbols")
.map(parseSymbols)
.map(shape.withValues)
map.key("symbols").map { entry =>
val symbols = parseSymbols(entry)
shape.setWithoutId(ShapeModel.Values, AmfArray(symbols, Annotations(entry.value)), Annotations(entry))
}
}

private def parseSymbols(e: YMapEntry): Seq[ScalarNode] = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package amf.apicontract.internal.spec.avro.parser.domain

import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
import amf.core.internal.parser.domain.Annotations
import amf.shapes.client.scala.model.domain.{AnyShape, NodeShape}
import amf.shapes.internal.domain.metamodel.NodeShapeModel.AdditionalPropertiesSchema
import org.yaml.model.YMap

case class AvroMapShapeParser(map: YMap)(implicit ctx: AvroSchemaContext)
extends AvroCollectionShapeParser[NodeShape](map, "values") {
override val shape: NodeShape = NodeShape(map)
override def setMembers(anyShape: AnyShape): Unit = shape.withAdditionalPropertiesSchema(anyShape)
override val shape: NodeShape = NodeShape(map)
override def setMembers(anyShape: AnyShape): Unit =
shape.setWithoutId(AdditionalPropertiesSchema, anyShape, Annotations(map))

override def parseSpecificFields(): Unit = {}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package amf.apicontract.internal.spec.avro.parser.domain

import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
import amf.core.client.scala.model.domain.AmfArray
import amf.core.client.scala.model.domain.extensions.PropertyShape
import amf.core.internal.datanode.DataNodeParser
import amf.core.internal.metamodel.domain.ShapeModel
Expand All @@ -9,6 +10,7 @@ import amf.core.internal.parser.YMapOps
import amf.core.internal.parser.domain.Annotations
import amf.shapes.client.scala.model.domain.{AnyShape, NodeShape}
import amf.shapes.internal.domain.metamodel.AnyShapeModel
import amf.shapes.internal.domain.metamodel.NodeShapeModel.Properties
import org.yaml.model.{YMap, YMapEntry, YNode}

class AvroRecordParser(map: YMap)(implicit ctx: AvroSchemaContext) extends AvroComplexShapeParser(map) {
Expand All @@ -21,15 +23,25 @@ class AvroRecordParser(map: YMap)(implicit ctx: AvroSchemaContext) extends AvroC

private def parseFieldsEntry(e: YMapEntry): Unit = {
val fields = e.value.as[Seq[YMap]].flatMap(parseField)
shape.withProperties(fields)
shape.setWithoutId(Properties, AmfArray(fields, Annotations(e.value)), Annotations(e))
}

def parseField(map: YMap): Option[PropertyShape] = {
val maybeShape: Option[PropertyShape] = AvroRecordFieldParser(map).parse().map(buildProperty)
val maybeShape =
AvroRecordFieldParser(map)
.parse()
.map { s =>
// add the map annotations + the avro type annotation to the PropertyShape wrapper
var ann = Annotations(map)
getAvroType(s).foreach(avroTypeAnnotation => ann = ann += avroTypeAnnotation)
val p = PropertyShape(ann).withRange(s)
p.setWithoutId(PropertyShapeModel.Range, s, s.annotations)
}
maybeShape.foreach { p =>
map.key("name", AnyShapeModel.Name in p)
map.key("aliases", AnyShapeModel.Aliases in p)
map.key("doc", AnyShapeModel.Description in p)
// todo: change to new field Order (being a string)
map.key("order", PropertyShapeModel.SerializationOrder in p)
map.key(
"default",
Expand All @@ -41,9 +53,6 @@ class AvroRecordParser(map: YMap)(implicit ctx: AvroSchemaContext) extends AvroC
}
maybeShape
}

private def buildProperty(anyShape: AnyShape): PropertyShape =
PropertyShape(Annotations.virtual()).withName("field").withRange(anyShape)
}

case class AvroRecordFieldParser(map: YMap)(implicit ctx: AvroSchemaContext) extends AvroShapeParser(map) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class AvroShapeParser(map: YMap)(implicit ctx: AvroSchemaContext) extends AvroKe
// todo: should validate invalid type when using the AVRO Validator
(None, "invalid avro type")
}
maybeShape.map(_.annotations += AVROSchemaType(avroType))
maybeShape.map(_.annotations += AVROSchemaType(avroType)) // avroType = record, enum, fixed, array, map, etc.
maybeShape
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package amf.apicontract.internal.spec.avro.parser.domain

import amf.apicontract.internal.spec.avro.parser.context.AvroSchemaContext
import amf.core.internal.parser.domain.Annotations
import amf.shapes.client.scala.model.domain.UnionShape
import org.yaml.model.{YMap, YNode}

Expand All @@ -10,6 +11,6 @@ case class AvroUnionShapeParser(members: Seq[YNode], node: YNode)(implicit ctx:

override def parseSpecificFields(): Unit = {
val parsedMembers = members.map(node => AvroTextParser(node).parse())
shape.withAnyOf(parsedMembers)
shape.withAnyOf(parsedMembers, Annotations(node))
}
}
Loading