Skip to content

Logical types for all types: null,bool,float,double,enum,map,array#2

Open
yoricksijsling wants to merge 1 commit into
unknown-logical-typesfrom
logical-types-everywhere
Open

Logical types for all types: null,bool,float,double,enum,map,array#2
yoricksijsling wants to merge 1 commit into
unknown-logical-typesfrom
logical-types-everywhere

Conversation

@yoricksijsling

@yoricksijsling yoricksijsling commented Mar 27, 2026

Copy link
Copy Markdown

Based upon the changes here:

This adds support for unknown logical types to all remaining types (except named and union where it doesn't make sense). There's no known logical types for these, so we're using LogicalType Void.

Please note: We're in a public repo here.

For our (current) purposes, we just needed them for Records. Did the rest to keep things consistent.

@@ -23,32 +23,32 @@ import qualified Data.Avro.Schema.ReadSchema as Read
-- Schema resolution rules are described by the specification: <https://avro.apache.org/docs/current/spec.html#Schema+Resolution>
deconflict :: Schema -> Schema -> Either String ReadSchema
deconflict writerSchema readerSchema | writerSchema == readerSchema = pure (Read.fromSchema readerSchema)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this implementation is correct. From the specification it remains quite vague whether logical types should be considered equal to their primitive types, and whether two differently-named logical types (but with the same or compatible underlying types) are compatible or not.

We do see this mention for decimal however:

For the purposes of schema resolution, two schemas that are decimal logical types match if their scales and precisions match.

So I think but am not sure, that generally speaking the logical type should be considered during schema resolution, and that mixing logical type names is an error.

import Avro.Data.Logical
import Data.Avro (decodeValue, decodeValueWithSchema, encodeValue, encodeValueWithSchema)
import Data.Avro.Schema.ReadSchema (fromSchema)
import qualified Data.Aeson as A

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nit: In 8/10 places Data.Aeson is imported as Aeson. There is one other place where it is imported as A and one where it is imported as J (?!)
Let's keep it as Aeson.

}
deriving (Ord, Show, Generic, NFData)

pattern Null' :: Schema

@Qqwy Qqwy May 22, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation/naming question: I do not know what is nicer. What do you think?

  • Name the type constructors that accept a logical type parameter Bool, Int, etc and name the patterns Bool', Int' etc. (This is what you have now)
  • Name the patterns Bool, Int etc, and name the type constructors that accept a logical type parameter Bool', Int' etc.

I am leaning somewhat towards the second option, because it would make it easier for library users to upgrade their code. Also, if you were to introduce a custom logical type as a library user, then adding a simple pattern Color = S.String' (LogicalTypeString "color") would be the only place you'd use the type constructor version with a '.

@Qqwy Qqwy left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is this big open question I have about schema resolution. Unfortunately, I was unable to find good sources on this question, maybe we need to open the code of other languages' implementations to check.

Other than that, there are two small nits you might want to take a look at.

Nice work Yorick! 🫶

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants