Skip to content

Commit

Permalink
Merge pull request #2021 from aml-org/W-16006973
Browse files Browse the repository at this point in the history
W-16006973: add avro annotations
  • Loading branch information
arielmirra committed Jul 16, 2024
2 parents af33b75 + be9c755 commit fbc0c51
Show file tree
Hide file tree
Showing 21 changed files with 4,332 additions and 18 deletions.
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

0 comments on commit fbc0c51

Please sign in to comment.