Skip to content

Commit

Permalink
mas avro goodness
Browse files Browse the repository at this point in the history
  • Loading branch information
VisualBean committed Jun 3, 2024
1 parent 4f53f13 commit 453db29
Show file tree
Hide file tree
Showing 14 changed files with 150 additions and 18 deletions.
14 changes: 12 additions & 2 deletions src/LEGO.AsyncAPI.Readers/V2/AsyncApiAvroSchemaDeserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace LEGO.AsyncAPI.Readers
{
using System;
using System.Collections;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Readers.Exceptions;
using LEGO.AsyncAPI.Readers.ParseNodes;
Expand All @@ -18,7 +17,7 @@ public class AsyncApiAvroSchemaDeserializer
{ "doc", (a, n) => a.Doc = n.GetScalarValue() },
{ "default", (a, n) => a.Default = n.CreateAny() },
{ "aliases", (a, n) => a.Aliases = n.CreateSimpleList(n2 => n2.GetScalarValue()) },
{ "order", (a, n) => a.Order = n.GetScalarValue() },
{ "order", (a, n) => a.Order = n.GetScalarValue().GetEnumFromDisplayName<AvroFieldOrder>() },
};

private static readonly FixedFieldMap<AvroRecord> RecordFixedFields = new()
Expand Down Expand Up @@ -130,6 +129,17 @@ public static AvroSchema LoadSchema(ParseNode node)

if (node is MapNode mapNode)
{
var pointer = mapNode.GetReferencePointer();

if (pointer != null)
{
return new AvroRecord
{
UnresolvedReference = true,
Reference = node.Context.VersionService.ConvertToAsyncApiReference(pointer, ReferenceType.Schema),
};
}

var type = mapNode["type"]?.Value.GetScalarValue();

switch (type)
Expand Down
4 changes: 4 additions & 0 deletions src/LEGO.AsyncAPI.Readers/V2/AsyncApiMessageDeserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public static IAsyncApiMessagePayload LoadAvroPayload(ParseNode n)

private static IAsyncApiMessagePayload LoadPayload(ParseNode n, string format)
{

if (n == null)
{
return null;
Expand Down Expand Up @@ -107,6 +108,9 @@ private static IAsyncApiMessagePayload LoadPayload(ParseNode n, string format)

static readonly IEnumerable<string> SupportedAvroSchemaFormats = new List<string>
{
"application/vnd.apache.avro",
"application/vnd.apache.avro+json",
"application/vnd.apache.avro+yaml",
"application/vnd.apache.avro+json;version=1.9.0",
"application/vnd.apache.avro+yaml;version=1.9.0",
};
Expand Down
11 changes: 9 additions & 2 deletions src/LEGO.AsyncAPI/Models/AsyncApiAvroSchemaPayload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,16 @@ public AsyncApiAvroSchemaPayload()
{
}

public bool UnresolvedReference { get; set; }
public bool TryGetAs<T>(out T schema)
where T : AvroSchema
{
schema = this.Schema as T;
return schema != null;
}

public bool UnresolvedReference { get => this.Schema.UnresolvedReference; set => this.Schema.UnresolvedReference = value; }

public AsyncApiReference Reference { get; set; }
public AsyncApiReference Reference { get => this.Schema.Reference; set => this.Schema.Reference = value; }

public void SerializeV2(IAsyncApiWriter writer)
{
Expand Down
2 changes: 1 addition & 1 deletion src/LEGO.AsyncAPI/Models/Avro/AvroArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class AvroArray : AvroSchema
/// </summary>
public override IDictionary<string, AsyncApiAny> Metadata { get; set; } = new Dictionary<string, AsyncApiAny>();

public override void SerializeV2(IAsyncApiWriter writer)
public override void SerializeV2WithoutReference(IAsyncApiWriter writer)
{
writer.WriteStartObject();
writer.WriteOptionalProperty("type", this.Type);
Expand Down
2 changes: 1 addition & 1 deletion src/LEGO.AsyncAPI/Models/Avro/AvroEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class AvroEnum : AvroSchema
/// </summary>
public override IDictionary<string, AsyncApiAny> Metadata { get; set; } = new Dictionary<string, AsyncApiAny>();

public override void SerializeV2(IAsyncApiWriter writer)
public override void SerializeV2WithoutReference(IAsyncApiWriter writer)
{
writer.WriteStartObject();
writer.WriteOptionalProperty("type", this.Type);
Expand Down
22 changes: 20 additions & 2 deletions src/LEGO.AsyncAPI/Models/Avro/AvroField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,23 @@ namespace LEGO.AsyncAPI.Models
{
using System.Collections.Generic;
using System.Linq;
using LEGO.AsyncAPI.Attributes;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Writers;

public enum AvroFieldOrder
{
None = 0,

[Display("ascending")]
Ascending,

[Display("descending")]
Descending,

[Display("ignore")]
Ignore,
}
/// <summary>

Check warning on line 24 in src/LEGO.AsyncAPI/Models/Avro/AvroField.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Check warning on line 24 in src/LEGO.AsyncAPI/Models/Avro/AvroField.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

/// Represents a field within an Avro record schema.
/// </summary>
Expand Down Expand Up @@ -35,7 +49,7 @@ public class AvroField : IAsyncApiSerializable
/// <summary>
/// The order of the field, can be 'ascending', 'descending', or 'ignore'.
/// </summary>
public string Order { get; set; }
public AvroFieldOrder Order { get; set; }

/// <summary>
/// Alternate names for this record (optional).
Expand All @@ -54,7 +68,11 @@ public void SerializeV2(IAsyncApiWriter writer)
writer.WriteOptionalObject("type", this.Type, (w, s) => s.SerializeV2(w));
writer.WriteOptionalProperty("doc", this.Doc);
writer.WriteOptionalObject("default", this.Default, (w, s) => w.WriteAny(s));
writer.WriteOptionalProperty("order", this.Order);
if (this.Order != AvroFieldOrder.None)
{
writer.WriteOptionalProperty("order", this.Order.GetDisplayName());
}

writer.WriteOptionalCollection("aliases", this.Aliases, (w, s) => w.WriteValue(s));
if (this.Metadata.Any())
{
Expand Down
2 changes: 1 addition & 1 deletion src/LEGO.AsyncAPI/Models/Avro/AvroFixed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class AvroFixed : AvroSchema
/// </summary>
public override IDictionary<string, AsyncApiAny> Metadata { get; set; } = new Dictionary<string, AsyncApiAny>();

public override void SerializeV2(IAsyncApiWriter writer)
public override void SerializeV2WithoutReference(IAsyncApiWriter writer)
{
writer.WriteStartObject();
writer.WriteOptionalProperty("type", this.Type);
Expand Down
2 changes: 1 addition & 1 deletion src/LEGO.AsyncAPI/Models/Avro/AvroMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class AvroMap : AvroSchema
/// </summary>
public override IDictionary<string, AsyncApiAny> Metadata { get; set; } = new Dictionary<string, AsyncApiAny>();

public override void SerializeV2(IAsyncApiWriter writer)
public override void SerializeV2WithoutReference(IAsyncApiWriter writer)
{
writer.WriteStartObject();
writer.WriteOptionalProperty("type", this.Type);
Expand Down
2 changes: 1 addition & 1 deletion src/LEGO.AsyncAPI/Models/Avro/AvroPrimitive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public AvroPrimitive()
{
}

public override void SerializeV2(IAsyncApiWriter writer)
public override void SerializeV2WithoutReference(IAsyncApiWriter writer)
{
writer.WriteValue(this.Type);
if (this.Metadata.Any())
Expand Down
2 changes: 1 addition & 1 deletion src/LEGO.AsyncAPI/Models/Avro/AvroRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class AvroRecord : AvroSchema
/// </summary>
public override IDictionary<string, AsyncApiAny> Metadata { get; set; } = new Dictionary<string, AsyncApiAny>();

public override void SerializeV2(IAsyncApiWriter writer)
public override void SerializeV2WithoutReference(IAsyncApiWriter writer)
{
writer.WriteStartObject();
writer.WriteOptionalProperty("type", this.Type);
Expand Down
25 changes: 23 additions & 2 deletions src/LEGO.AsyncAPI/Models/Avro/AvroSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

namespace LEGO.AsyncAPI.Models
{
using System;
using System.Collections.Generic;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Writers;

public abstract class AvroSchema : IAsyncApiSerializable
public abstract class AvroSchema : IAsyncApiSerializable, IAsyncApiReferenceable
{
public abstract string Type { get; }

Expand All @@ -15,11 +16,31 @@ public abstract class AvroSchema : IAsyncApiSerializable
/// </summary>
public abstract IDictionary<string, AsyncApiAny> Metadata { get; set; }

public bool UnresolvedReference { get; set; }

public AsyncApiReference Reference { get; set; }

public static implicit operator AvroSchema(AvroPrimitiveType type)
{
return new AvroPrimitive(type);
}

public abstract void SerializeV2(IAsyncApiWriter writer);
public void SerializeV2(IAsyncApiWriter writer)
{
if (writer is null)
{
throw new ArgumentNullException(nameof(writer));
}

if (this.Reference != null && !writer.GetSettings().ShouldInlineReference(this.Reference))
{
this.Reference.SerializeV2(writer);
return;
}

this.SerializeV2WithoutReference(writer);
}

public abstract void SerializeV2WithoutReference(IAsyncApiWriter writer);
}
}
2 changes: 1 addition & 1 deletion src/LEGO.AsyncAPI/Models/Avro/AvroUnion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class AvroUnion : AvroSchema
/// </summary>
public override IDictionary<string, AsyncApiAny> Metadata { get; set; } = new Dictionary<string, AsyncApiAny>();

public override void SerializeV2(IAsyncApiWriter writer)
public override void SerializeV2WithoutReference(IAsyncApiWriter writer)
{
writer.WriteStartArray();
foreach (var type in this.Types)
Expand Down
74 changes: 73 additions & 1 deletion test/LEGO.AsyncAPI.Tests/Models/AsyncApiMessage_Should.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public void AsyncApiMessage_WithNoSchemaFormat_DoesNotSerializeSchemaFormat()
}

[Test]
public void AsyncApiMessage_WithSchemaFormat_Serializes()
public void AsyncApiMessage_WithJsonSchemaFormat_Serializes()
{
// Arrange
var expected =
Expand Down Expand Up @@ -168,6 +168,78 @@ public void AsyncApiMessage_WithSchemaFormat_Serializes()
message.Should().BeEquivalentTo(deserializedMessage);
}

[Test]
public void AsyncApiMessage_WithAvroSchemaFormat_Serializes()
{
// Arrange
var expected =
"""
payload:
type: record
name: User
namespace: com.example
fields:
- name: username
type: string
doc: The username of the user.
default: guest
order: ascending
schemaFormat: application/vnd.apache.avro
""";

var message = new AsyncApiMessage();
message.SchemaFormat = "application/vnd.apache.avro";
message.Payload = new AsyncApiAvroSchemaPayload()
{
Schema = new AvroRecord()
{
Name = "User",
Namespace = "com.example",
Fields = new List<AvroField>
{
new AvroField()
{
Name = "username",
Type = AvroPrimitiveType.String,
Doc = "The username of the user.",
Default = new AsyncApiAny("guest"),
Order = AvroFieldOrder.Ascending,
},
},
},
};

// Act
var actual = message.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0);
var deserializedMessage = new AsyncApiStringReader().ReadFragment<AsyncApiMessage>(expected, AsyncApiVersion.AsyncApi2_0, out _);

// Assert
actual.Should()
.BePlatformAgnosticEquivalentTo(expected);
message.Should().BeEquivalentTo(deserializedMessage);
}

[Test]
public void AsyncApiMessage_WithAvroAsReference_Deserializes()
{
// Arrange
var input =
"""
schemaFormat: 'application/vnd.apache.avro+yaml;version=1.9.0'
payload:
$ref: 'path/to/user-create.avsc/#UserCreate'
""";

// Act
var deserializedMessage = new AsyncApiStringReader().ReadFragment<AsyncApiMessage>(input, AsyncApiVersion.AsyncApi2_0, out _);

// Assert
deserializedMessage.Payload.Reference.Should().NotBeNull();
deserializedMessage.Payload.Reference.IsExternal.Should().BeTrue();
deserializedMessage.Payload.Reference.IsFragment.Should().BeTrue();

}

[Test]
public void AsyncApiMessage_WithFilledObject_Serializes()
{
Expand Down
4 changes: 2 additions & 2 deletions test/LEGO.AsyncAPI.Tests/Models/AvroSchema_Should.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public void SerializeV2_SerializesCorrectly()
Type = AvroPrimitiveType.String,
Doc = "The username of the user.",
Default = new AsyncApiAny("guest"),
Order = "ascending",
Order = AvroFieldOrder.Ascending,
},
new AvroField
{
Expand Down Expand Up @@ -292,7 +292,7 @@ public void ReadFragment_DeserializesCorrectly()
Type = AvroPrimitiveType.String,
Doc = "The username of the user.",
Default = new AsyncApiAny("guest"),
Order = "ascending",
Order = AvroFieldOrder.Ascending,
},
new AvroField
{
Expand Down

0 comments on commit 453db29

Please sign in to comment.