This is an automated email from the ASF dual-hosted git repository.
fokko pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git
The following commit(s) were added to refs/heads/main by this push:
new 3c37b10 feat: Adding literals (#76)
3c37b10 is described below
commit 3c37b100213c4a78d17ce443ce0978a78b724759
Author: Matt Topol <[email protected]>
AuthorDate: Tue May 28 10:57:53 2024 -0400
feat: Adding literals (#76)
* feat: Adding literals
* implementing feedback
---
errors.go | 3 +
go.mod | 47 +++-
go.sum | 105 +++++---
literals.go | 780 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
literals_test.go | 729 +++++++++++++++++++++++++++++++++++++++++++++++++++
types.go | 14 +
utils.go | 5 +-
7 files changed, 1635 insertions(+), 48 deletions(-)
diff --git a/errors.go b/errors.go
index c5bd870..71f9f63 100644
--- a/errors.go
+++ b/errors.go
@@ -25,4 +25,7 @@ var (
ErrInvalidArgument = errors.New("invalid argument")
ErrInvalidSchema = errors.New("invalid schema")
ErrInvalidTransform = errors.New("invalid transform syntax")
+ ErrType = errors.New("type error")
+ ErrBadCast = errors.New("could not cast value")
+ ErrBadLiteral = errors.New("invalid literal value")
)
diff --git a/go.mod b/go.mod
index 046ee7b..5accc3f 100644
--- a/go.mod
+++ b/go.mod
@@ -20,31 +20,35 @@ module github.com/apache/iceberg-go
go 1.21
require (
+ github.com/apache/arrow/go/v16 v16.0.0
github.com/aws/aws-sdk-go-v2 v1.27.0
- github.com/aws/aws-sdk-go-v2/config v1.27.15
- github.com/aws/aws-sdk-go-v2/credentials v1.17.15
- github.com/aws/aws-sdk-go-v2/service/glue v1.81.1
- github.com/aws/aws-sdk-go-v2/service/s3 v1.54.3
+ github.com/aws/aws-sdk-go-v2/config v1.26.6
+ github.com/aws/aws-sdk-go-v2/credentials v1.17.12
+ github.com/aws/aws-sdk-go-v2/service/glue v1.73.1
+ github.com/aws/aws-sdk-go-v2/service/s3 v1.48.0
github.com/aws/smithy-go v1.20.2
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
github.com/google/uuid v1.6.0
- github.com/hamba/avro/v2 v2.22.0
- github.com/pterm/pterm v0.12.79
+ github.com/hamba/avro/v2 v2.21.1
+ github.com/pterm/pterm v0.12.78
github.com/stretchr/testify v1.9.0
github.com/wolfeidau/s3iofs v1.5.2
- golang.org/x/exp v0.0.0-20231006140011-7918f672742d
+ golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
)
require (
atomicgo.dev/cursor v0.2.0 // indirect
atomicgo.dev/keyboard v0.2.9 // indirect
atomicgo.dev/schedule v0.1.0 // indirect
- github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
- github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3 // indirect
+ github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c //
indirect
+ github.com/andybalholm/brotli v1.1.0 // indirect
+ github.com/apache/thrift v0.20.0 // indirect
+ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 // indirect
- github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
- github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2
// indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.9 //
indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 //
indirect
@@ -54,22 +58,37 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.28.9 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
+ github.com/google/flatbuffers v24.3.25+incompatible // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/asmfmt v1.3.2 // indirect
github.com/klauspost/compress v1.17.8 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/lithammer/fuzzysearch v1.1.8 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
+ github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 //
indirect
+ github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd //
indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
- golang.org/x/net v0.23.0 // indirect
- golang.org/x/sys v0.18.0 // indirect
- golang.org/x/term v0.18.0 // indirect
+ github.com/zeebo/xxh3 v1.0.2 // indirect
+ golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/net v0.24.0 // indirect
+ golang.org/x/sync v0.7.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
+ golang.org/x/term v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
+ golang.org/x/tools v0.20.0 // indirect
+ golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
+ google.golang.org/genproto/googleapis/rpc
v0.0.0-20240227224415-6ceb2ff114de // indirect
+ google.golang.org/grpc v1.63.2 // indirect
+ google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 289b8ed..8f16c6d 100644
--- a/go.sum
+++ b/go.sum
@@ -6,6 +6,8 @@ atomicgo.dev/keyboard v0.2.9
h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8=
atomicgo.dev/keyboard v0.2.9/go.mod
h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ=
atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs=
atomicgo.dev/schedule v0.1.0/go.mod
h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU=
+github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c
h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU=
+github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod
h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
github.com/MarvinJWendt/testza v0.1.0/go.mod
h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs=
github.com/MarvinJWendt/testza v0.2.1/go.mod
h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8=
github.com/MarvinJWendt/testza v0.2.8/go.mod
h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII=
@@ -15,27 +17,33 @@ github.com/MarvinJWendt/testza v0.3.0/go.mod
h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/
github.com/MarvinJWendt/testza v0.4.2/go.mod
h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE=
github.com/MarvinJWendt/testza v0.5.2
h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4=
github.com/MarvinJWendt/testza v0.5.2/go.mod
h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY=
+github.com/andybalholm/brotli v1.1.0
h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
+github.com/andybalholm/brotli v1.1.0/go.mod
h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
+github.com/apache/arrow/go/v16 v16.0.0
h1:qRLbJRPj4zaseZrjbDHa7mUoZDDIU+4pu+mE2Lucs5g=
+github.com/apache/arrow/go/v16 v16.0.0/go.mod
h1:9wnc9mn6vEDTRIm4+27pEjQpRKuTvBaessPoEXQzxWA=
+github.com/apache/thrift v0.20.0
h1:631+KvYbsBZxmuJjYwhezVsrfc/TbqtZV4QcxOX1fOI=
+github.com/apache/thrift v0.20.0/go.mod
h1:hOk1BQqcp2OLzGsyVXdfMk7YFlMxK3aoEVhjD06QhB8=
github.com/atomicgo/cursor v0.0.1/go.mod
h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
github.com/aws/aws-sdk-go-v2 v1.27.0
h1:7bZWKoXhzI+mMR/HjdMx8ZCC5+6fY0lS5tr0bbgiLlo=
github.com/aws/aws-sdk-go-v2 v1.27.0/go.mod
h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2
h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod
h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg=
-github.com/aws/aws-sdk-go-v2/config v1.27.15
h1:uNnGLZ+DutuNEkuPh6fwqK7LpEiPmzb7MIMA1mNWEUc=
-github.com/aws/aws-sdk-go-v2/config v1.27.15/go.mod
h1:7j7Kxx9/7kTmL7z4LlhwQe63MYEE5vkVV6nWg4ZAI8M=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.15
h1:YDexlvDRCA8ems2T5IP1xkMtOZ1uLJOCJdTr0igs5zo=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.15/go.mod
h1:vxHggqW6hFNaeNC0WyXS3VdyjcV0a4KMUY4dKJ96buU=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3
h1:dQLK4TjtnlRGb0czOht2CevZ5l6RSyRWAnKeGd7VAFE=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3/go.mod
h1:TL79f2P6+8Q7dTsILpiVST+AL9lkF6PPGI167Ny0Cjw=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4
h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod
h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo=
+github.com/aws/aws-sdk-go-v2/config v1.26.6
h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o=
+github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod
h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.12
h1:PVbKQ0KjDosI5+nEdRMU8ygEQDmkJTSHBqPjEX30lqc=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.12/go.mod
h1:jlWtGFRtKsqc5zqerHZYmKmRkUXo3KPM14YJ13ZEjwE=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1
h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod
h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7
h1:lf/8VTF2cM+N4SLzaYJERKEWAXq8MOMpZfU6wEPWsPk=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7/go.mod
h1:4SjkU7QiqK2M9oozyMzfZ/23LmUY+h3oFqhdeP5OMiI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7
h1:4OYVp0705xu8yjdyoWix0r9wPIRXnIzzOoUpQVHIJ/g=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7/go.mod
h1:vd7ESTEvI76T2Na050gODNmNU7+OyKrIKroYTu4ABiI=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0
h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod
h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7
h1:/FUtT3xsoHO3cfh+I/kCbcMCN98QZRsiFet/V8QkWSs=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7/go.mod
h1:MaCAgWpGooQoCWZnMur97rGn5dp350w2+CeiV5406wE=
-github.com/aws/aws-sdk-go-v2/service/glue v1.81.1
h1:+rtgF25rrZ5O5J7k8u3xQcFWAmMQxQWvcyaz1waFj38=
-github.com/aws/aws-sdk-go-v2/service/glue v1.81.1/go.mod
h1:NVgCBCXL2/W4WJbFhKUGATTBiWKkYuZyvuh7BsFvZzE=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3
h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod
h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10
h1:5oE2WzJE56/mVveuDZPJESKlg/00AaS2pY2QZcnxg4M=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10/go.mod
h1:FHbKWQtRBYUz4vO5WBWjzMD2by126ny5y/1EoaWoLfI=
+github.com/aws/aws-sdk-go-v2/service/glue v1.73.1
h1:z/NBYW8RygzWrDgNWib10fuLUBl0SLj0KruGoEHxnKQ=
+github.com/aws/aws-sdk-go-v2/service/glue v1.73.1/go.mod
h1:F3B9DC5FsIHAxUtHZdY5KUeqN+tHoGlRPzSSYdXjC38=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2
h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod
h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.9
h1:UXqEWQI0n+q0QixzU0yUUQBZXRd5037qdInTIHFTl98=
@@ -44,8 +52,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url
v1.11.9 h1:Wx0rlZoEJ
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9/go.mod
h1:aVMHdE0aHO3v+f/iw01fmXV/5DbfQ3Bi9nN7nd9bE9Y=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.7
h1:uO5XR6QGBcmPyo2gxofYJLFkcVQ4izOoGDNenlZhTEk=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.7/go.mod
h1:feeeAYfAcwTReM6vbwjEyDmiGho+YgBhaFULuXDW8kc=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.54.3
h1:57NtjG+WLims0TxIQbjTqebZUKDM03DfM11ANAekW0s=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.54.3/go.mod
h1:739CllldowZiPPsDFcJHNF4FXrVxaSGVnZ9Ez9Iz9hc=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.48.0
h1:PJTdBMsyvra6FtED7JZtDpQrIAflYDHFoZAu/sKYkwU=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.48.0/go.mod
h1:4qXHrG1Ne3VGIMZPCB8OjH/pLFO94sKABIusjh0KWPU=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.8
h1:Kv1hwNG6jHC/sxMTe5saMjH6t6ZLkgfvVxyEjfWL1ks=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.8/go.mod
h1:c1qtZUWtygI6ZdvKppzCSXsDOq5I4luJPZ0Ud3juFCA=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.2
h1:nWBZ1xHCF+A7vv9sDzJOq4NWIdzFYm0kH7Pr4OjHYsQ=
@@ -61,8 +69,14 @@ github.com/davecgh/go-spew v1.1.1
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod
h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/goccy/go-json v0.10.2
h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
+github.com/goccy/go-json v0.10.2/go.mod
h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod
h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/flatbuffers v24.3.25+incompatible
h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
+github.com/google/flatbuffers v24.3.25+incompatible/go.mod
h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod
h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod
h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod
h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -70,27 +84,34 @@ github.com/gookit/color v1.4.2/go.mod
h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQ
github.com/gookit/color v1.5.0/go.mod
h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod
h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
-github.com/hamba/avro/v2 v2.22.0
h1:IaBMFv5xmjo38f0oaP9jZiJFXg+lmHPPg7d9YotMnPg=
-github.com/hamba/avro/v2 v2.22.0/go.mod
h1:HOeTrE3kvWnBAgsufqhAzDDV5gvS0QXs65Z6BHfGgbg=
+github.com/hamba/avro/v2 v2.21.1
h1:400/jTdLWQ3ib58y83VXlTJKijRouYQszY1SO0cMGt4=
+github.com/hamba/avro/v2 v2.21.1/go.mod
h1:ouJ4PkiAEP49u0lAtQyd5Gv04MehKj+7lXwD3zpLpY0=
github.com/json-iterator/go v1.1.12
h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod
h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/klauspost/asmfmt v1.3.2
h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=
+github.com/klauspost/asmfmt v1.3.2/go.mod
h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
github.com/klauspost/compress v1.17.8
h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod
h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod
h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.10/go.mod
h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod
h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
-github.com/klauspost/cpuid/v2 v2.2.3
h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
-github.com/klauspost/cpuid/v2 v2.2.3/go.mod
h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/klauspost/cpuid/v2 v2.2.7
h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
+github.com/klauspost/cpuid/v2 v2.2.7/go.mod
h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod
h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod
h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lithammer/fuzzysearch v1.1.8
h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
github.com/lithammer/fuzzysearch v1.1.8/go.mod
h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
github.com/mattn/go-runewidth v0.0.13/go.mod
h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.15
h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod
h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8
h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
+github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod
h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
+github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3
h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
+github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod
h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
github.com/mitchellh/mapstructure v1.5.0
h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod
h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -98,6 +119,8 @@ github.com/modern-go/concurrent
v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2
h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod
h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/pierrec/lz4/v4 v4.1.21
h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
+github.com/pierrec/lz4/v4 v4.1.21/go.mod
h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pmezard/go-difflib v1.0.0
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pterm/pterm v0.12.27/go.mod
h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI=
@@ -107,8 +130,8 @@ github.com/pterm/pterm v0.12.31/go.mod
h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEej
github.com/pterm/pterm v0.12.33/go.mod
h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE=
github.com/pterm/pterm v0.12.36/go.mod
h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8=
github.com/pterm/pterm v0.12.40/go.mod
h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s=
-github.com/pterm/pterm v0.12.79 h1:lH3yrYMhdpeqX9y5Ep1u7DejyHy7NSQg9qrBjF9dFT4=
-github.com/pterm/pterm v0.12.79/go.mod
h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo=
+github.com/pterm/pterm v0.12.78 h1:QTWKaIAa4B32GKwqVXtu9m1DUMgWw3VRljMkMevX+b8=
+github.com/pterm/pterm v0.12.78/go.mod
h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo=
github.com/rivo/uniseg v0.2.0/go.mod
h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod
h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
@@ -129,21 +152,29 @@ github.com/xo/terminfo
v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1z
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e
h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod
h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yuin/goldmark v1.4.13/go.mod
h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
+github.com/zeebo/assert v1.3.0/go.mod
h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
+github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
+github.com/zeebo/xxh3 v1.0.2/go.mod
h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod
h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/exp v0.0.0-20231006140011-7918f672742d
h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
-golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod
h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
+golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
+golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod
h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod
h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod
h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod
h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod
h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
-golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
+golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -154,15 +185,15 @@ golang.org/x/sys
v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod
h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod
h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod
h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod
h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
-golang.org/x/term v0.18.0/go.mod
h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
+golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
+golang.org/x/term v0.19.0/go.mod
h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -174,7 +205,19 @@ golang.org/x/tools
v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod
h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod
h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
+golang.org/x/tools v0.20.0/go.mod
h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
+golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod
h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
+gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ=
+gonum.org/v1/gonum v0.15.0/go.mod
h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de
h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
+google.golang.org/genproto/googleapis/rpc
v0.0.0-20240227224415-6ceb2ff114de/go.mod
h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
+google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
+google.golang.org/grpc v1.63.2/go.mod
h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
+google.golang.org/protobuf v1.34.1
h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod
h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/literals.go b/literals.go
new file mode 100644
index 0000000..9b42e59
--- /dev/null
+++ b/literals.go
@@ -0,0 +1,780 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package iceberg
+
+import (
+ "bytes"
+ "cmp"
+ "errors"
+ "fmt"
+ "math"
+ "reflect"
+ "strconv"
+ "time"
+
+ "github.com/apache/arrow/go/v16/arrow"
+ "github.com/apache/arrow/go/v16/arrow/decimal128"
+ "github.com/google/uuid"
+)
+
+// LiteralType is a generic type constraint for the explicit Go types that we
allow
+// for literal values. This represents the actual primitive types that exist
in Iceberg
+type LiteralType interface {
+ bool | int32 | int64 | float32 | float64 | Date |
+ Time | Timestamp | string | []byte | uuid.UUID | Decimal
+}
+
+// Comparator is a comparison function for specific literal types:
+//
+// returns 0 if v1 == v2
+// returns <0 if v1 < v2
+// returns >0 if v1 > v2
+type Comparator[T LiteralType] func(v1, v2 T) int
+
+// Literal is a non-null literal value. It can be casted using To and be
checked for
+// equality against other literals.
+type Literal interface {
+ fmt.Stringer
+
+ Type() Type
+ To(Type) (Literal, error)
+ Equals(Literal) bool
+}
+
+// TypedLiteral is a generic interface for Literals so that you can retrieve
the value.
+// This is based on the physical representative type, which means that
FixedLiteral and
+// BinaryLiteral will both return []byte, etc.
+type TypedLiteral[T LiteralType] interface {
+ Literal
+
+ Value() T
+ Comparator() Comparator[T]
+}
+
+// NewLiteral provides a literal based on the type of T
+func NewLiteral[T LiteralType](val T) Literal {
+ switch v := any(val).(type) {
+ case bool:
+ return BoolLiteral(v)
+ case int32:
+ return Int32Literal(v)
+ case int64:
+ return Int64Literal(v)
+ case float32:
+ return Float32Literal(v)
+ case float64:
+ return Float64Literal(v)
+ case Date:
+ return DateLiteral(v)
+ case Time:
+ return TimeLiteral(v)
+ case Timestamp:
+ return TimestampLiteral(v)
+ case string:
+ return StringLiteral(v)
+ case []byte:
+ return BinaryLiteral(v)
+ case uuid.UUID:
+ return UUIDLiteral(v)
+ case Decimal:
+ return DecimalLiteral(v)
+ }
+ panic("can't happen due to literal type constraint")
+}
+
+// convenience to avoid repreating this pattern for primitive types
+func literalEq[L interface {
+ comparable
+ LiteralType
+}, T TypedLiteral[L]](lhs T, other Literal) bool {
+ rhs, ok := other.(T)
+ if !ok {
+ return false
+ }
+
+ return lhs.Value() == rhs.Value()
+}
+
+// AboveMaxLiteral represents values that are above the maximum for their type
+// such as values > math.MaxInt32 for an Int32Literal
+type AboveMaxLiteral interface {
+ Literal
+
+ aboveMax()
+}
+
+// BelowMinLiteral represents values that are below the minimum for their type
+// such as values < math.MinInt32 for an Int32Literal
+type BelowMinLiteral interface {
+ Literal
+
+ belowMin()
+}
+
+type aboveMaxLiteral[T int32 | int64 | float32 | float64] struct {
+ value T
+}
+
+func (ab aboveMaxLiteral[T]) aboveMax() {}
+
+func (ab aboveMaxLiteral[T]) Type() Type {
+ var z T
+ switch any(z).(type) {
+ case int32:
+ return PrimitiveTypes.Int32
+ case int64:
+ return PrimitiveTypes.Int64
+ case float32:
+ return PrimitiveTypes.Float32
+ case float64:
+ return PrimitiveTypes.Float64
+ default:
+ panic("should never happen")
+ }
+}
+
+func (ab aboveMaxLiteral[T]) To(t Type) (Literal, error) {
+ if ab.Type().Equals(t) {
+ return ab, nil
+ }
+ return nil, fmt.Errorf("%w: cannot change type of AboveMax%sLiteral",
+ ErrBadCast, reflect.TypeOf(T(0)).String())
+}
+
+func (ab aboveMaxLiteral[T]) Value() T { return ab.value }
+
+func (ab aboveMaxLiteral[T]) String() string { return "AboveMax" }
+func (ab aboveMaxLiteral[T]) Equals(other Literal) bool {
+ // AboveMaxLiteral isn't comparable and thus isn't even equal to itself
+ return false
+}
+
+type belowMinLiteral[T int32 | int64 | float32 | float64] struct {
+ value T
+}
+
+func (bm belowMinLiteral[T]) belowMin() {}
+
+func (bm belowMinLiteral[T]) Type() Type {
+ var z T
+ switch any(z).(type) {
+ case int32:
+ return PrimitiveTypes.Int32
+ case int64:
+ return PrimitiveTypes.Int64
+ case float32:
+ return PrimitiveTypes.Float32
+ case float64:
+ return PrimitiveTypes.Float64
+ default:
+ panic("should never happen")
+ }
+}
+
+func (bm belowMinLiteral[T]) To(t Type) (Literal, error) {
+ if bm.Type().Equals(t) {
+ return bm, nil
+ }
+ return nil, fmt.Errorf("%w: cannot change type of BelowMin%sLiteral",
+ ErrBadCast, reflect.TypeOf(T(0)).String())
+}
+
+func (bm belowMinLiteral[T]) Value() T { return bm.value }
+
+func (bm belowMinLiteral[T]) String() string { return "BelowMin" }
+func (bm belowMinLiteral[T]) Equals(other Literal) bool {
+ // BelowMinLiteral isn't comparable and thus isn't even equal to itself
+ return false
+}
+
+func Int32AboveMaxLiteral() Literal {
+ return aboveMaxLiteral[int32]{value: math.MaxInt32}
+}
+
+func Int64AboveMaxLiteral() Literal {
+ return aboveMaxLiteral[int64]{value: math.MaxInt64}
+}
+
+func Float32AboveMaxLiteral() Literal {
+ return aboveMaxLiteral[float32]{value: math.MaxFloat32}
+}
+
+func Float64AboveMaxLiteral() Literal {
+ return aboveMaxLiteral[float64]{value: math.MaxFloat64}
+}
+
+func Int32BelowMinLiteral() Literal {
+ return belowMinLiteral[int32]{value: math.MinInt32}
+}
+
+func Int64BelowMinLiteral() Literal {
+ return belowMinLiteral[int64]{value: math.MinInt64}
+}
+
+func Float32BelowMinLiteral() Literal {
+ return belowMinLiteral[float32]{value: -math.MaxFloat32}
+}
+
+func Float64BelowMinLiteral() Literal {
+ return belowMinLiteral[float64]{value: -math.MaxFloat64}
+}
+
+type BoolLiteral bool
+
+func (BoolLiteral) Comparator() Comparator[bool] {
+ return func(v1, v2 bool) int {
+ if v1 {
+ if v2 {
+ return 0
+ }
+ return 1
+ }
+ return -1
+ }
+}
+
+func (b BoolLiteral) Type() Type { return PrimitiveTypes.Bool }
+func (b BoolLiteral) Value() bool { return bool(b) }
+func (b BoolLiteral) String() string { return strconv.FormatBool(bool(b)) }
+func (b BoolLiteral) To(t Type) (Literal, error) {
+ switch t.(type) {
+ case BooleanType:
+ return b, nil
+ }
+ return nil, fmt.Errorf("%w: BoolLiteral to %s", ErrBadCast, t)
+}
+
+func (b BoolLiteral) Equals(l Literal) bool {
+ return literalEq(b, l)
+}
+
+type Int32Literal int32
+
+func (Int32Literal) Comparator() Comparator[int32] { return cmp.Compare[int32]
}
+func (i Int32Literal) Type() Type { return
PrimitiveTypes.Int32 }
+func (i Int32Literal) Value() int32 { return int32(i) }
+func (i Int32Literal) String() string { return
strconv.FormatInt(int64(i), 10) }
+func (i Int32Literal) To(t Type) (Literal, error) {
+ switch t := t.(type) {
+ case Int32Type:
+ return i, nil
+ case Int64Type:
+ return Int64Literal(i), nil
+ case Float32Type:
+ return Float32Literal(i), nil
+ case Float64Type:
+ return Float64Literal(i), nil
+ case DateType:
+ return DateLiteral(i), nil
+ case TimeType:
+ return TimeLiteral(i), nil
+ case TimestampType:
+ return TimestampLiteral(i), nil
+ case TimestampTzType:
+ return TimestampLiteral(i), nil
+ case DecimalType:
+ unscaled := Decimal{Val: decimal128.FromI64(int64(i)), Scale: 0}
+ if t.scale == 0 {
+ return DecimalLiteral(unscaled), nil
+ }
+ out, err := unscaled.Val.Rescale(0, int32(t.scale))
+ if err != nil {
+ return nil, fmt.Errorf("%w: failed to cast to
DecimalType: %s", ErrBadCast, err.Error())
+ }
+ return DecimalLiteral{Val: out, Scale: t.scale}, nil
+ }
+
+ return nil, fmt.Errorf("%w: Int32Literal to %s", ErrBadCast, t)
+}
+
+func (i Int32Literal) Equals(other Literal) bool {
+ return literalEq(i, other)
+}
+
+type Int64Literal int64
+
+func (Int64Literal) Comparator() Comparator[int64] { return cmp.Compare[int64]
}
+func (i Int64Literal) Type() Type { return
PrimitiveTypes.Int64 }
+func (i Int64Literal) Value() int64 { return int64(i) }
+func (i Int64Literal) String() string { return
strconv.FormatInt(int64(i), 10) }
+func (i Int64Literal) To(t Type) (Literal, error) {
+ switch t := t.(type) {
+ case Int32Type:
+ if math.MaxInt32 < i {
+ return Int32AboveMaxLiteral(), nil
+ } else if math.MinInt32 > i {
+ return Int32BelowMinLiteral(), nil
+ }
+ return Int32Literal(i), nil
+ case Int64Type:
+ return i, nil
+ case Float32Type:
+ return Float32Literal(i), nil
+ case Float64Type:
+ return Float64Literal(i), nil
+ case DateType:
+ return DateLiteral(i), nil
+ case TimeType:
+ return TimeLiteral(i), nil
+ case TimestampType:
+ return TimestampLiteral(i), nil
+ case TimestampTzType:
+ return TimestampLiteral(i), nil
+ case DecimalType:
+ unscaled := Decimal{Val: decimal128.FromI64(int64(i)), Scale: 0}
+ if t.scale == 0 {
+ return DecimalLiteral(unscaled), nil
+ }
+ out, err := unscaled.Val.Rescale(0, int32(t.scale))
+ if err != nil {
+ return nil, fmt.Errorf("%w: failed to cast to
DecimalType: %s", ErrBadCast, err.Error())
+ }
+ return DecimalLiteral{Val: out, Scale: t.scale}, nil
+ }
+
+ return nil, fmt.Errorf("%w: Int64Literal to %s", ErrBadCast, t)
+}
+func (i Int64Literal) Equals(other Literal) bool {
+ return literalEq(i, other)
+}
+
+type Float32Literal float32
+
+func (Float32Literal) Comparator() Comparator[float32] { return
cmp.Compare[float32] }
+func (f Float32Literal) Type() Type { return
PrimitiveTypes.Float32 }
+func (f Float32Literal) Value() float32 { return float32(f) }
+func (f Float32Literal) String() string { return
strconv.FormatFloat(float64(f), 'g', -1, 32) }
+func (f Float32Literal) To(t Type) (Literal, error) {
+ switch t := t.(type) {
+ case Float32Type:
+ return f, nil
+ case Float64Type:
+ return Float64Literal(f), nil
+ case DecimalType:
+ v, err := decimal128.FromFloat32(float32(f),
int32(t.precision), int32(t.scale))
+ if err != nil {
+ return nil, err
+ }
+ return DecimalLiteral{Val: v, Scale: t.scale}, nil
+ }
+
+ return nil, fmt.Errorf("%w: Float32Literal to %s", ErrBadCast, t)
+}
+func (f Float32Literal) Equals(other Literal) bool {
+ return literalEq(f, other)
+}
+
+type Float64Literal float64
+
+func (Float64Literal) Comparator() Comparator[float64] { return
cmp.Compare[float64] }
+func (f Float64Literal) Type() Type { return
PrimitiveTypes.Float64 }
+func (f Float64Literal) Value() float64 { return float64(f) }
+func (f Float64Literal) String() string { return
strconv.FormatFloat(float64(f), 'g', -1, 64) }
+func (f Float64Literal) To(t Type) (Literal, error) {
+ switch t := t.(type) {
+ case Float32Type:
+ if math.MaxFloat32 < f {
+ return Float32AboveMaxLiteral(), nil
+ } else if -math.MaxFloat32 > f {
+ return Float32BelowMinLiteral(), nil
+ }
+ return Float32Literal(f), nil
+ case Float64Type:
+ return f, nil
+ case DecimalType:
+ v, err := decimal128.FromFloat64(float64(f),
int32(t.precision), int32(t.scale))
+ if err != nil {
+ return nil, err
+ }
+ return DecimalLiteral{Val: v, Scale: t.scale}, nil
+ }
+
+ return nil, fmt.Errorf("%w: Float64Literal to %s", ErrBadCast, t)
+}
+func (f Float64Literal) Equals(other Literal) bool {
+ return literalEq(f, other)
+}
+
+type DateLiteral Date
+
+func (DateLiteral) Comparator() Comparator[Date] { return cmp.Compare[Date] }
+func (d DateLiteral) Type() Type { return PrimitiveTypes.Date }
+func (d DateLiteral) Value() Date { return Date(d) }
+func (d DateLiteral) String() string {
+ t := time.Unix(0, 0).UTC().AddDate(0, 0, int(d))
+ return t.Format("2006-01-02")
+}
+func (d DateLiteral) To(t Type) (Literal, error) {
+ switch t.(type) {
+ case DateType:
+ return d, nil
+ }
+ return nil, fmt.Errorf("%w: DateLiteral to %s", ErrBadCast, t)
+}
+func (d DateLiteral) Equals(other Literal) bool {
+ return literalEq(d, other)
+}
+
+type TimeLiteral Time
+
+func (TimeLiteral) Comparator() Comparator[Time] { return cmp.Compare[Time] }
+func (t TimeLiteral) Type() Type { return PrimitiveTypes.Time }
+func (t TimeLiteral) Value() Time { return Time(t) }
+func (t TimeLiteral) String() string {
+ tm := time.UnixMicro(int64(t)).UTC()
+ return tm.Format("15:04:05.000000")
+}
+func (t TimeLiteral) To(typ Type) (Literal, error) {
+ switch typ.(type) {
+ case TimeType:
+ return t, nil
+ }
+ return nil, fmt.Errorf("%w: TimeLiteral to %s", ErrBadCast, typ)
+
+}
+func (t TimeLiteral) Equals(other Literal) bool {
+ return literalEq(t, other)
+}
+
+type TimestampLiteral Timestamp
+
+func (TimestampLiteral) Comparator() Comparator[Timestamp] { return
cmp.Compare[Timestamp] }
+func (t TimestampLiteral) Type() Type { return
PrimitiveTypes.Timestamp }
+func (t TimestampLiteral) Value() Timestamp { return
Timestamp(t) }
+func (t TimestampLiteral) String() string {
+ tm := time.UnixMicro(int64(t)).UTC()
+ return tm.Format("2006-01-02 15:04:05.000000")
+}
+func (t TimestampLiteral) To(typ Type) (Literal, error) {
+ switch typ.(type) {
+ case TimestampType:
+ return t, nil
+ case TimestampTzType:
+ return t, nil
+ case DateType:
+ return DateLiteral(Timestamp(t).ToDate()), nil
+ }
+ return nil, fmt.Errorf("%w: TimestampLiteral to %s", ErrBadCast, typ)
+}
+func (t TimestampLiteral) Equals(other Literal) bool {
+ return literalEq(t, other)
+}
+
+type StringLiteral string
+
+func (StringLiteral) Comparator() Comparator[string] { return
cmp.Compare[string] }
+func (s StringLiteral) Type() Type { return
PrimitiveTypes.String }
+func (s StringLiteral) Value() string { return string(s) }
+func (s StringLiteral) String() string { return string(s) }
+func (s StringLiteral) To(typ Type) (Literal, error) {
+ switch t := typ.(type) {
+ case StringType:
+ return s, nil
+ case Int32Type:
+ n, err := strconv.ParseInt(string(s), 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("%w: casting '%s' to %s",
+ errors.Join(ErrBadCast, err), s, typ)
+ }
+
+ if math.MaxInt32 < n {
+ return Int32AboveMaxLiteral(), nil
+ } else if math.MinInt32 > n {
+ return Int32BelowMinLiteral(), nil
+ }
+
+ return Int32Literal(n), nil
+ case Int64Type:
+ n, err := strconv.ParseInt(string(s), 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("%w: casting '%s' to %s",
+ errors.Join(ErrBadCast, err), s, typ)
+ }
+
+ return Int64Literal(n), nil
+ case Float32Type:
+ n, err := strconv.ParseFloat(string(s), 32)
+ if err != nil {
+ return nil, fmt.Errorf("%w: casting '%s' to %s",
+ errors.Join(ErrBadCast, err), s, typ)
+ }
+ return Float32Literal(n), nil
+ case Float64Type:
+ n, err := strconv.ParseFloat(string(s), 64)
+ if err != nil {
+ return nil, fmt.Errorf("%w: casting '%s' to %s",
+ errors.Join(ErrBadCast, err), s, typ)
+ }
+ return Float64Literal(n), nil
+ case DateType:
+ tm, err := time.Parse("2006-01-02", string(s))
+ if err != nil {
+ return nil, fmt.Errorf("%w: casting '%s' to %s - %s",
+ ErrBadCast, s, typ, err.Error())
+ }
+ return DateLiteral(tm.Truncate(24*time.Hour).Unix() /
int64((time.Hour * 24).Seconds())), nil
+ case TimeType:
+ val, err := arrow.Time64FromString(string(s), arrow.Microsecond)
+ if err != nil {
+ return nil, fmt.Errorf("%w: casting '%s' to %s - %s",
+ ErrBadCast, s, typ, err.Error())
+ }
+
+ return TimeLiteral(val), nil
+ case TimestampType:
+ // requires RFC3339 with no time zone
+ tm, err := time.Parse("2006-01-02T15:04:05", string(s))
+ if err != nil {
+ return nil, fmt.Errorf("%w: invalid Timestamp format
for casting from string '%s': %s",
+ ErrBadCast, s, err.Error())
+ }
+
+ return TimestampLiteral(Timestamp(tm.UTC().UnixMicro())), nil
+ case TimestampTzType:
+ // requires RFC3339 format WITH time zone
+ tm, err := time.Parse(time.RFC3339, string(s))
+ if err != nil {
+ return nil, fmt.Errorf("%w: invalid TimestampTz format
for casting from string '%s': %s",
+ ErrBadCast, s, err.Error())
+ }
+
+ return TimestampLiteral(Timestamp(tm.UTC().UnixMicro())), nil
+ case UUIDType:
+ val, err := uuid.Parse(string(s))
+ if err != nil {
+ return nil, fmt.Errorf("%w: casting '%s' to %s - %s",
+ ErrBadCast, s, typ, err.Error())
+ }
+ return UUIDLiteral(val), nil
+ case DecimalType:
+ n, err := decimal128.FromString(string(s), int32(t.precision),
int32(t.scale))
+ if err != nil {
+ return nil, fmt.Errorf("%w: casting '%s' to %s - %s",
+ ErrBadCast, s, typ, err.Error())
+ }
+ return DecimalLiteral{Val: n, Scale: t.scale}, nil
+ case BooleanType:
+ val, err := strconv.ParseBool(string(s))
+ if err != nil {
+ return nil, fmt.Errorf("%w: casting '%s' to %s - %s",
+ ErrBadCast, s, typ, err.Error())
+ }
+ return BoolLiteral(val), nil
+ }
+ return nil, fmt.Errorf("%w: StringLiteral to %s", ErrBadCast, typ)
+}
+
+func (s StringLiteral) Equals(other Literal) bool {
+ return literalEq(s, other)
+}
+
+type BinaryLiteral []byte
+
+func (BinaryLiteral) Comparator() Comparator[[]byte] {
+ return bytes.Compare
+}
+func (b BinaryLiteral) Type() Type { return PrimitiveTypes.Binary }
+func (b BinaryLiteral) Value() []byte { return []byte(b) }
+func (b BinaryLiteral) String() string { return string(b) }
+func (b BinaryLiteral) To(typ Type) (Literal, error) {
+ switch t := typ.(type) {
+ case UUIDType:
+ val, err := uuid.FromBytes(b)
+ if err != nil {
+ return nil, fmt.Errorf("%w: cannot convert
BinaryLiteral to UUID",
+ errors.Join(ErrBadCast, err))
+ }
+ return UUIDLiteral(val), nil
+ case FixedType:
+ if len(b) == t.len {
+ return FixedLiteral(b), nil
+ }
+
+ return nil, fmt.Errorf("%w: cannot convert BinaryLiteral to %s,
different length - %d <> %d",
+ ErrBadCast, typ, len(b), t.len)
+ case BinaryType:
+ return b, nil
+ }
+
+ return nil, fmt.Errorf("%w: BinaryLiteral to %s", ErrBadCast, typ)
+}
+func (b BinaryLiteral) Equals(other Literal) bool {
+ rhs, ok := other.(BinaryLiteral)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal([]byte(b), rhs)
+}
+
+type FixedLiteral []byte
+
+func (FixedLiteral) Comparator() Comparator[[]byte] { return bytes.Compare }
+func (f FixedLiteral) Type() Type { return
FixedTypeOf(len(f)) }
+func (f FixedLiteral) Value() []byte { return []byte(f) }
+func (f FixedLiteral) String() string { return string(f) }
+func (f FixedLiteral) To(typ Type) (Literal, error) {
+ switch t := typ.(type) {
+ case UUIDType:
+ val, err := uuid.FromBytes(f)
+ if err != nil {
+ return nil, fmt.Errorf("%w: cannot convert FixedLiteral
to UUID - %s",
+ ErrBadCast, err.Error())
+ }
+ return UUIDLiteral(val), nil
+ case FixedType:
+ if len(f) == t.len {
+ return FixedLiteral(f), nil
+ }
+
+ return nil, fmt.Errorf("%w: cannot convert FixedLiteral to %s,
different length - %d <> %d",
+ ErrBadCast, typ, len(f), t.len)
+ case BinaryType:
+ return f, nil
+ }
+
+ return nil, fmt.Errorf("%w: FixedLiteral[%d] to %s",
+ ErrBadCast, len(f), typ)
+}
+func (f FixedLiteral) Equals(other Literal) bool {
+ rhs, ok := other.(FixedLiteral)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal([]byte(f), rhs)
+}
+
+type UUIDLiteral uuid.UUID
+
+func (UUIDLiteral) Comparator() Comparator[uuid.UUID] {
+ return func(v1, v2 uuid.UUID) int {
+ return bytes.Compare(v1[:], v2[:])
+ }
+}
+
+func (UUIDLiteral) Type() Type { return PrimitiveTypes.UUID }
+func (u UUIDLiteral) Value() uuid.UUID { return uuid.UUID(u) }
+func (u UUIDLiteral) String() string { return uuid.UUID(u).String() }
+func (u UUIDLiteral) To(typ Type) (Literal, error) {
+ switch t := typ.(type) {
+ case UUIDType:
+ return u, nil
+ case FixedType:
+ if len(u) == t.len {
+ v, _ := uuid.UUID(u).MarshalBinary()
+ return FixedLiteral(v), nil
+ }
+
+ return nil, fmt.Errorf("%w: cannot convert UUIDLiteral to %s,
different length - %d <> %d",
+ ErrBadCast, typ, len(u), t.len)
+ case BinaryType:
+ v, _ := uuid.UUID(u).MarshalBinary()
+ return BinaryLiteral(v), nil
+ }
+
+ return nil, fmt.Errorf("%w: UUIDLiteral to %s", ErrBadCast, typ)
+}
+func (u UUIDLiteral) Equals(other Literal) bool {
+ rhs, ok := other.(UUIDLiteral)
+ if !ok {
+ return false
+ }
+
+ return uuid.UUID(u) == uuid.UUID(rhs)
+}
+
+type DecimalLiteral Decimal
+
+func (DecimalLiteral) Comparator() Comparator[Decimal] {
+ return func(v1, v2 Decimal) int {
+ if v1.Scale == v2.Scale {
+ return v1.Val.Cmp(v2.Val)
+ }
+
+ rescaled, err := v2.Val.Rescale(int32(v2.Scale),
int32(v1.Scale))
+ if err != nil {
+ return -1
+ }
+
+ return v1.Val.Cmp(rescaled)
+ }
+}
+func (d DecimalLiteral) Type() Type { return DecimalTypeOf(9, d.Scale) }
+func (d DecimalLiteral) Value() Decimal { return Decimal(d) }
+func (d DecimalLiteral) String() string {
+ return d.Val.ToString(int32(d.Scale))
+}
+
+func (d DecimalLiteral) To(t Type) (Literal, error) {
+ switch t := t.(type) {
+ case DecimalType:
+ if d.Scale == t.scale {
+ return d, nil
+ }
+
+ return nil, fmt.Errorf("%w: could not convert %v to %s",
+ ErrBadCast, d, t)
+ case Int32Type:
+ v := d.Val.BigInt().Int64()
+ if v > math.MaxInt32 {
+ return Int32AboveMaxLiteral(), nil
+ } else if v < math.MinInt32 {
+ return Int32BelowMinLiteral(), nil
+ }
+
+ return Int32Literal(int32(v)), nil
+ case Int64Type:
+ v := d.Val.BigInt()
+ if !v.IsInt64() {
+ if v.Sign() > 0 {
+ return Int64AboveMaxLiteral(), nil
+ } else if v.Sign() < 0 {
+ return Int64BelowMinLiteral(), nil
+ }
+ }
+
+ return Int64Literal(v.Int64()), nil
+ case Float32Type:
+ v := d.Val.ToFloat64(int32(d.Scale))
+ if v > math.MaxFloat32 {
+ return Float32AboveMaxLiteral(), nil
+ } else if v < -math.MaxFloat32 {
+ return Float32BelowMinLiteral(), nil
+ }
+
+ return Float32Literal(float32(v)), nil
+ case Float64Type:
+ return Float64Literal(d.Val.ToFloat64(int32(d.Scale))), nil
+ }
+
+ return nil, fmt.Errorf("%w: DecimalLiteral to %s", ErrBadCast, t)
+}
+
+func (d DecimalLiteral) Equals(other Literal) bool {
+ rhs, ok := other.(DecimalLiteral)
+ if !ok {
+ return false
+ }
+
+ rescaled, err := rhs.Val.Rescale(int32(rhs.Scale), int32(d.Scale))
+ if err != nil {
+ return false
+ }
+ return d.Val == rescaled
+}
diff --git a/literals_test.go b/literals_test.go
new file mode 100644
index 0000000..f7a483b
--- /dev/null
+++ b/literals_test.go
@@ -0,0 +1,729 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package iceberg_test
+
+import (
+ "math"
+ "strconv"
+ "testing"
+ "time"
+
+ "github.com/apache/arrow/go/v16/arrow"
+ "github.com/apache/arrow/go/v16/arrow/decimal128"
+ "github.com/apache/iceberg-go"
+ "github.com/google/uuid"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestNumericLiteralCompare(t *testing.T) {
+ smallLit := iceberg.NewLiteral(int32(10)).(iceberg.Int32Literal)
+ bigLit := iceberg.NewLiteral(int32(1000)).(iceberg.Int32Literal)
+
+ assert.False(t, smallLit.Equals(bigLit))
+ assert.True(t, smallLit.Equals(iceberg.NewLiteral(int32(10))))
+
+ cmp := smallLit.Comparator()
+
+ assert.Equal(t, -1, cmp(smallLit.Value(), bigLit.Value()))
+ assert.Equal(t, 1, cmp(bigLit.Value(), smallLit.Value()))
+ assert.True(t, smallLit.Type().Equals(iceberg.PrimitiveTypes.Int32))
+}
+
+func TestIntConversion(t *testing.T) {
+ lit := iceberg.NewLiteral(int32(34))
+
+ t.Run("to int64", func(t *testing.T) {
+ longLit, err := lit.To(iceberg.PrimitiveTypes.Int64)
+ assert.NoError(t, err)
+ assert.IsType(t, iceberg.Int64Literal(0), longLit)
+ assert.EqualValues(t, 34, longLit)
+ })
+
+ t.Run("to float32", func(t *testing.T) {
+ floatLit, err := lit.To(iceberg.PrimitiveTypes.Float32)
+ assert.NoError(t, err)
+ assert.IsType(t, iceberg.Float32Literal(0), floatLit)
+ assert.EqualValues(t, 34, floatLit)
+ })
+
+ t.Run("to float64", func(t *testing.T) {
+ dblLit, err := lit.To(iceberg.PrimitiveTypes.Float64)
+ assert.NoError(t, err)
+ assert.IsType(t, iceberg.Float64Literal(0), dblLit)
+ assert.EqualValues(t, 34, dblLit)
+ })
+}
+
+func TestIntToDecimalConversion(t *testing.T) {
+ tests := []struct {
+ ty iceberg.DecimalType
+ val iceberg.Decimal
+ }{
+ {iceberg.DecimalTypeOf(9, 0),
+ iceberg.Decimal{Val: decimal128.FromI64(34), Scale: 0}},
+ {iceberg.DecimalTypeOf(9, 2),
+ iceberg.Decimal{Val: decimal128.FromI64(3400), Scale:
2}},
+ {iceberg.DecimalTypeOf(9, 4),
+ iceberg.Decimal{Val: decimal128.FromI64(340000), Scale:
4}},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.ty.String(), func(t *testing.T) {
+ lit := iceberg.Int32Literal(34)
+
+ dec, err := lit.To(tt.ty)
+ require.NoError(t, err)
+ assert.IsType(t, iceberg.DecimalLiteral(tt.val), dec)
+ assert.EqualValues(t, tt.val, dec)
+ })
+ }
+}
+
+func TestIntToDateConversion(t *testing.T) {
+ oneDay, _ := time.Parse("2006-01-02", "2022-03-28")
+ val := int32(arrow.Date32FromTime(oneDay))
+ dateLit, err := iceberg.NewLiteral(val).To(iceberg.PrimitiveTypes.Date)
+ require.NoError(t, err)
+ assert.True(t, dateLit.Type().Equals(iceberg.PrimitiveTypes.Date))
+ assert.EqualValues(t, val, dateLit)
+
+ lit := iceberg.Int32Literal(34)
+ tm, err := lit.To(iceberg.PrimitiveTypes.Time)
+ require.NoError(t, err)
+ assert.EqualValues(t, lit, tm)
+
+ tm, err = lit.To(iceberg.PrimitiveTypes.Timestamp)
+ require.NoError(t, err)
+ assert.EqualValues(t, lit, tm)
+
+ tm, err = lit.To(iceberg.PrimitiveTypes.TimestampTz)
+ require.NoError(t, err)
+ assert.EqualValues(t, lit, tm)
+}
+
+func TestInt64Conversions(t *testing.T) {
+ tests := []struct {
+ from iceberg.Int64Literal
+ to iceberg.Literal
+ }{
+ {iceberg.Int64Literal(34), iceberg.NewLiteral(int32(34))},
+ {iceberg.Int64Literal(34), iceberg.NewLiteral(float32(34))},
+ {iceberg.Int64Literal(34), iceberg.NewLiteral(float64(34))},
+ {iceberg.Int64Literal(19709),
iceberg.NewLiteral(iceberg.Date(19709))},
+ {iceberg.Int64Literal(51661919000),
iceberg.NewLiteral(iceberg.Time(51661919000))},
+ {iceberg.Int64Literal(1647305201),
iceberg.NewLiteral(iceberg.Timestamp(1647305201))},
+ {iceberg.Int64Literal(34),
+ iceberg.NewLiteral(iceberg.Decimal{Val:
decimal128.FromI64(34), Scale: 0})},
+ {iceberg.Int64Literal(34),
+ iceberg.NewLiteral(iceberg.Decimal{Val:
decimal128.FromI64(3400), Scale: 2})},
+ {iceberg.Int64Literal(34),
+ iceberg.NewLiteral(iceberg.Decimal{Val:
decimal128.FromI64(340000), Scale: 4})},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.to.Type().String(), func(t *testing.T) {
+ got, err := tt.from.To(tt.to.Type())
+ require.NoError(t, err)
+ assert.True(t, tt.to.Equals(got))
+ })
+ }
+}
+
+func TestInt64ToInt32OutsideBound(t *testing.T) {
+ bigLit := iceberg.NewLiteral(int64(math.MaxInt32 + 1))
+ aboveMax, err := bigLit.To(iceberg.PrimitiveTypes.Int32)
+ require.NoError(t, err)
+ assert.Implements(t, (*iceberg.AboveMaxLiteral)(nil), aboveMax)
+ assert.Equal(t, iceberg.Int32AboveMaxLiteral(), aboveMax)
+ assert.Equal(t, iceberg.PrimitiveTypes.Int32, aboveMax.Type())
+
+ smallLit := iceberg.NewLiteral(int64(math.MinInt32 - 1))
+ belowMin, err := smallLit.To(iceberg.PrimitiveTypes.Int32)
+ require.NoError(t, err)
+ assert.Implements(t, (*iceberg.BelowMinLiteral)(nil), belowMin)
+ assert.Equal(t, iceberg.Int32BelowMinLiteral(), belowMin)
+ assert.Equal(t, iceberg.PrimitiveTypes.Int32, belowMin.Type())
+}
+
+func TestFloatConversions(t *testing.T) {
+ n1, _ := decimal128.FromFloat32(34.56, 9, 1)
+ n2, _ := decimal128.FromFloat32(34.56, 9, 2)
+ n3, _ := decimal128.FromFloat32(34.56, 9, 4)
+
+ tests := []struct {
+ from iceberg.Float32Literal
+ to iceberg.Literal
+ }{
+ {iceberg.Float32Literal(34.5),
iceberg.NewLiteral(float64(34.5))},
+ {iceberg.Float32Literal(34.56),
+ iceberg.NewLiteral(iceberg.Decimal{Val: n1, Scale: 1})},
+ {iceberg.Float32Literal(34.56),
+ iceberg.NewLiteral(iceberg.Decimal{Val: n2, Scale: 2})},
+ {iceberg.Float32Literal(34.56),
+ iceberg.NewLiteral(iceberg.Decimal{Val: n3, Scale: 4})},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.to.Type().String(), func(t *testing.T) {
+ got, err := tt.from.To(tt.to.Type())
+ require.NoError(t, err)
+ assert.Truef(t, tt.to.Equals(got), "expected: %s, got:
%s", tt.to, got)
+ })
+ }
+}
+
+func TestFloat64Conversions(t *testing.T) {
+ n1, _ := decimal128.FromFloat64(34.56, 9, 1)
+ n2, _ := decimal128.FromFloat64(34.56, 9, 2)
+ n3, _ := decimal128.FromFloat64(34.56, 9, 4)
+
+ tests := []struct {
+ from iceberg.Float64Literal
+ to iceberg.Literal
+ }{
+ {iceberg.Float64Literal(34.5),
iceberg.NewLiteral(float32(34.5))},
+ {iceberg.Float64Literal(34.56),
+ iceberg.NewLiteral(iceberg.Decimal{Val: n1, Scale: 1})},
+ {iceberg.Float64Literal(34.56),
+ iceberg.NewLiteral(iceberg.Decimal{Val: n2, Scale: 2})},
+ {iceberg.Float64Literal(34.56),
+ iceberg.NewLiteral(iceberg.Decimal{Val: n3, Scale: 4})},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.to.Type().String(), func(t *testing.T) {
+ got, err := tt.from.To(tt.to.Type())
+ require.NoError(t, err)
+ assert.Truef(t, tt.to.Equals(got), "expected: %s, got:
%s", tt.to, got)
+ })
+ }
+}
+
+func TestFloat64toFloat32OutsideBounds(t *testing.T) {
+ bigLit := iceberg.NewLiteral(float64(math.MaxFloat32 + 1.0e37))
+ aboveMax, err := bigLit.To(iceberg.PrimitiveTypes.Float32)
+ require.NoError(t, err)
+ assert.Equal(t, iceberg.Float32AboveMaxLiteral(), aboveMax)
+
+ smallLit := iceberg.NewLiteral(float64(-math.MaxFloat32 - 1.0e37))
+ belowMin, err := smallLit.To(iceberg.PrimitiveTypes.Float32)
+ require.NoError(t, err)
+ assert.Equal(t, iceberg.Float32BelowMinLiteral(), belowMin)
+}
+
+func TestDecimalToDecimalConversion(t *testing.T) {
+ lit := iceberg.NewLiteral(iceberg.Decimal{Val:
decimal128.FromI64(3411), Scale: 2})
+
+ v, err := lit.To(iceberg.DecimalTypeOf(9, 2))
+ require.NoError(t, err)
+ assert.Equal(t, lit, v)
+
+ v, err = lit.To(iceberg.DecimalTypeOf(11, 2))
+ require.NoError(t, err)
+ assert.Equal(t, lit, v)
+
+ _, err = lit.To(iceberg.DecimalTypeOf(9, 0))
+ assert.ErrorIs(t, err, iceberg.ErrBadCast)
+ assert.ErrorContains(t, err, "could not convert 34.11 to decimal(9, 0)")
+
+ _, err = lit.To(iceberg.DecimalTypeOf(9, 1))
+ assert.ErrorIs(t, err, iceberg.ErrBadCast)
+ assert.ErrorContains(t, err, "could not convert 34.11 to decimal(9, 1)")
+
+ _, err = lit.To(iceberg.DecimalTypeOf(9, 3))
+ assert.ErrorIs(t, err, iceberg.ErrBadCast)
+ assert.ErrorContains(t, err, "could not convert 34.11 to decimal(9, 3)")
+}
+
+func TestDecimalLiteralConversions(t *testing.T) {
+ n1 := iceberg.Decimal{Val: decimal128.FromI64(1234), Scale: 2}
+ n2 := iceberg.Decimal{Val: decimal128.FromI64(math.MaxInt32 + 1),
Scale: 0}
+ n3 := iceberg.Decimal{Val: decimal128.FromI64(math.MinInt32 - 1),
Scale: 10}
+
+ tests := []struct {
+ from iceberg.DecimalLiteral
+ to iceberg.Literal
+ }{
+ {iceberg.DecimalLiteral(n1), iceberg.NewLiteral(int32(1234))},
+ {iceberg.DecimalLiteral(n1), iceberg.NewLiteral(int64(1234))},
+ {iceberg.DecimalLiteral(n2),
iceberg.NewLiteral(int64(math.MaxInt32 + 1))},
+ {iceberg.DecimalLiteral(n1),
iceberg.NewLiteral(float32(12.34))},
+ {iceberg.DecimalLiteral(n1),
iceberg.NewLiteral(float64(12.34))},
+ {iceberg.DecimalLiteral(n3),
iceberg.NewLiteral(int64(math.MinInt32 - 1))},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.to.Type().String(), func(t *testing.T) {
+ got, err := tt.from.To(tt.to.Type())
+ require.NoError(t, err)
+ assert.Truef(t, tt.to.Equals(got), "expected: %s, got:
%s", tt.to, got)
+ })
+ }
+
+ above, err :=
iceberg.DecimalLiteral(n2).To(iceberg.PrimitiveTypes.Int32)
+ require.NoError(t, err)
+ assert.Equal(t, iceberg.Int32AboveMaxLiteral(), above)
+ assert.Equal(t, iceberg.PrimitiveTypes.Int32, above.Type())
+
+ below, err :=
iceberg.DecimalLiteral(n3).To(iceberg.PrimitiveTypes.Int32)
+ require.NoError(t, err)
+ assert.Equal(t, iceberg.Int32BelowMinLiteral(), below)
+ assert.Equal(t, iceberg.PrimitiveTypes.Int32, below.Type())
+
+ n4 := iceberg.Decimal{Val: decimal128.FromU64(math.MaxInt64 + 1),
Scale: 0}
+ n5 := iceberg.Decimal{Val: decimal128.FromU64(math.MaxUint64).Negate(),
Scale: 20}
+
+ above, err = iceberg.DecimalLiteral(n4).To(iceberg.PrimitiveTypes.Int64)
+ require.NoError(t, err)
+ assert.Equal(t, iceberg.Int64AboveMaxLiteral(), above)
+ assert.Equal(t, iceberg.PrimitiveTypes.Int64, above.Type())
+
+ below, err = iceberg.DecimalLiteral(n5).To(iceberg.PrimitiveTypes.Int64)
+ require.NoError(t, err)
+ assert.Equal(t, iceberg.Int64BelowMinLiteral(), below)
+ assert.Equal(t, iceberg.PrimitiveTypes.Int64, below.Type())
+
+ v, err := decimal128.FromFloat64(math.MaxFloat32+1e37, 38, -1)
+ require.NoError(t, err)
+ above, err = iceberg.DecimalLiteral(iceberg.Decimal{Val: v, Scale: -1}).
+ To(iceberg.PrimitiveTypes.Float32)
+ require.NoError(t, err)
+ assert.Equal(t, iceberg.Float32AboveMaxLiteral(), above)
+ assert.Equal(t, iceberg.PrimitiveTypes.Float32, above.Type())
+
+ below, err = iceberg.DecimalLiteral(iceberg.Decimal{Val: v.Negate(),
Scale: -1}).
+ To(iceberg.PrimitiveTypes.Float32)
+ require.NoError(t, err)
+ assert.Equal(t, iceberg.Float32BelowMinLiteral(), below)
+ assert.Equal(t, iceberg.PrimitiveTypes.Float32, below.Type())
+}
+
+func TestLiteralTimestampToDate(t *testing.T) {
+ v, _ := arrow.TimestampFromString("1970-01-01T00:00:00.000000+00:00",
arrow.Microsecond)
+ tsLit := iceberg.NewLiteral(iceberg.Timestamp(v))
+ dateLit, err := tsLit.To(iceberg.PrimitiveTypes.Date)
+ require.NoError(t, err)
+ assert.Zero(t, dateLit)
+}
+
+func TestStringLiterals(t *testing.T) {
+ sqrt2 := iceberg.NewLiteral("1.414")
+ pi := iceberg.NewLiteral("3.141")
+ piStr := iceberg.StringLiteral("3.141")
+ piDbl := iceberg.NewLiteral(float64(3.141))
+
+ v, err := pi.To(iceberg.PrimitiveTypes.Float64)
+ require.NoError(t, err)
+ assert.Equal(t, piDbl, v)
+
+ assert.False(t, sqrt2.Equals(pi))
+ assert.True(t, pi.Equals(piStr))
+ assert.False(t, pi.Equals(piDbl))
+ assert.Equal(t, "3.141", pi.String())
+
+ cmp := piStr.Comparator()
+ assert.Equal(t, -1, cmp(sqrt2.(iceberg.StringLiteral).Value(),
piStr.Value()))
+ assert.Equal(t, 1, cmp(piStr.Value(),
sqrt2.(iceberg.StringLiteral).Value()))
+
+ v, err = pi.To(iceberg.PrimitiveTypes.String)
+ require.NoError(t, err)
+ assert.Equal(t, pi, v)
+}
+
+func TestStringLiteralConversion(t *testing.T) {
+ tm, _ := time.Parse("2006-01-02", "2017-08-18")
+ expected := uuid.New()
+
+ tests := []struct {
+ from iceberg.StringLiteral
+ to iceberg.Literal
+ }{
+ {iceberg.StringLiteral("2017-08-18"),
+
iceberg.NewLiteral(iceberg.Date(arrow.Date32FromTime(tm)))},
+ {iceberg.StringLiteral("14:21:01.919"),
+ iceberg.NewLiteral(iceberg.Time(51661919000))},
+ {iceberg.StringLiteral("2017-08-18T14:21:01.919234"),
+
iceberg.NewLiteral(iceberg.Timestamp(1503066061919234))},
+ {iceberg.StringLiteral(expected.String()),
iceberg.NewLiteral(expected)},
+ {iceberg.StringLiteral("34.560"),
+ iceberg.NewLiteral(iceberg.Decimal{Val:
decimal128.FromI64(34560), Scale: 3})},
+ {iceberg.StringLiteral("true"), iceberg.NewLiteral(true)},
+ {iceberg.StringLiteral("True"), iceberg.NewLiteral(true)},
+ {iceberg.StringLiteral("false"), iceberg.NewLiteral(false)},
+ {iceberg.StringLiteral("False"), iceberg.NewLiteral(false)},
+ {iceberg.StringLiteral("12345"),
iceberg.NewLiteral(int32(12345))},
+ {iceberg.StringLiteral("12345123456"),
iceberg.NewLiteral(int64(12345123456))},
+ {iceberg.StringLiteral("3.14"),
iceberg.NewLiteral(float32(3.14))},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.to.Type().String(), func(t *testing.T) {
+ got, err := tt.from.To(tt.to.Type())
+ require.NoError(t, err)
+ assert.Truef(t, tt.to.Equals(got), "expected: %s, got:
%s", tt.to, got)
+ })
+ }
+
+ lit := iceberg.StringLiteral("2017-08-18T14:21:01.919234-07:00")
+ casted, err := lit.To(iceberg.PrimitiveTypes.TimestampTz)
+ require.NoError(t, err)
+ expectedTimestamp :=
iceberg.NewLiteral(iceberg.Timestamp(1503091261919234))
+ assert.Truef(t, casted.Equals(expectedTimestamp), "expected: %s, got:
%s",
+ expectedTimestamp, casted)
+
+ _, err = lit.To(iceberg.PrimitiveTypes.Timestamp)
+ require.Error(t, err)
+ assert.ErrorIs(t, err, iceberg.ErrBadCast)
+ assert.ErrorContains(t, err, `parsing time
"2017-08-18T14:21:01.919234-07:00": extra text: "-07:00"`)
+ assert.ErrorContains(t, err, "invalid Timestamp format for casting from
string")
+
+ _, err =
iceberg.StringLiteral("2017-08-18T14:21:01.919234").To(iceberg.PrimitiveTypes.TimestampTz)
+ require.Error(t, err)
+ assert.ErrorIs(t, err, iceberg.ErrBadCast)
+ assert.ErrorContains(t, err, `cannot parse "" as "Z07:00"`)
+}
+
+func TestLiteralIdentityConversions(t *testing.T) {
+ fixedLit, _ := iceberg.NewLiteral([]byte{0x01, 0x02,
0x03}).To(iceberg.FixedTypeOf(3))
+
+ tests := []struct {
+ lit iceberg.Literal
+ typ iceberg.PrimitiveType
+ }{
+ {iceberg.NewLiteral(true), iceberg.PrimitiveTypes.Bool},
+ {iceberg.NewLiteral(int32(34)), iceberg.PrimitiveTypes.Int32},
+ {iceberg.NewLiteral(int64(340000000)),
iceberg.PrimitiveTypes.Int64},
+ {iceberg.NewLiteral(float32(34.11)),
iceberg.PrimitiveTypes.Float32},
+ {iceberg.NewLiteral(float64(3.5028235e38)),
iceberg.PrimitiveTypes.Float64},
+ {iceberg.NewLiteral(iceberg.Decimal{Val:
decimal128.FromI64(3455), Scale: 2}),
+ iceberg.DecimalTypeOf(9, 2)},
+ {iceberg.NewLiteral(iceberg.Date(19079)),
iceberg.PrimitiveTypes.Date},
+ {iceberg.NewLiteral(iceberg.Timestamp(1503091261919234)),
+ iceberg.PrimitiveTypes.Timestamp},
+ {iceberg.NewLiteral("abc"), iceberg.PrimitiveTypes.String},
+ {iceberg.NewLiteral(uuid.New()), iceberg.PrimitiveTypes.UUID},
+ {fixedLit, iceberg.FixedTypeOf(3)},
+ {iceberg.NewLiteral([]byte{0x01, 0x02, 0x03}),
iceberg.PrimitiveTypes.Binary},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.typ.String(), func(t *testing.T) {
+ expected, err := tt.lit.To(tt.typ)
+ require.NoError(t, err)
+ assert.Equal(t, expected, tt.lit)
+ })
+ }
+}
+
+func TestFixedLiteral(t *testing.T) {
+ fixedLit012 := iceberg.FixedLiteral{0x00, 0x01, 0x02}
+ fixedLit013 := iceberg.FixedLiteral{0x00, 0x01, 0x03}
+ assert.True(t, fixedLit012.Equals(fixedLit012))
+ assert.False(t, fixedLit012.Equals(fixedLit013))
+
+ cmp := fixedLit012.Comparator()
+ assert.Equal(t, -1, cmp(fixedLit012, fixedLit013))
+ assert.Equal(t, 1, cmp(fixedLit013, fixedLit012))
+ assert.Equal(t, 0, cmp(fixedLit013, fixedLit013))
+
+ testUuid := uuid.New()
+ lit, err := iceberg.NewLiteral(testUuid[:]).To(iceberg.FixedTypeOf(16))
+ require.NoError(t, err)
+ uuidLit, err := lit.To(iceberg.PrimitiveTypes.UUID)
+ require.NoError(t, err)
+
+ assert.EqualValues(t, uuidLit, testUuid)
+
+ fixedUuid, err := uuidLit.To(iceberg.FixedTypeOf(16))
+ require.NoError(t, err)
+ assert.EqualValues(t, testUuid[:], fixedUuid)
+
+ binUuid, err := uuidLit.To(iceberg.PrimitiveTypes.Binary)
+ require.NoError(t, err)
+ assert.EqualValues(t, testUuid[:], binUuid)
+
+ binlit, err := fixedLit012.To(iceberg.PrimitiveTypes.Binary)
+ require.NoError(t, err)
+ assert.EqualValues(t, fixedLit012, binlit)
+}
+
+func TestBinaryLiteral(t *testing.T) {
+ binLit012 := iceberg.NewLiteral([]byte{0x00, 0x01,
0x02}).(iceberg.BinaryLiteral)
+ binLit013 := iceberg.NewLiteral([]byte{0x00, 0x01,
0x03}).(iceberg.BinaryLiteral)
+ assert.True(t, binLit012.Equals(binLit012))
+ assert.False(t, binLit012.Equals(binLit013))
+
+ cmp := binLit012.Comparator()
+ assert.Equal(t, -1, cmp(binLit012, binLit013))
+ assert.Equal(t, 1, cmp(binLit013, binLit012))
+ assert.Equal(t, 0, cmp(binLit013, binLit013))
+}
+
+func TestBinaryLiteralConversions(t *testing.T) {
+ binLit012 := iceberg.NewLiteral([]byte{0x00, 0x01, 0x02})
+ fixed, err := binLit012.To(iceberg.FixedTypeOf(3))
+ require.NoError(t, err)
+ assert.Equal(t, iceberg.FixedLiteral{0x00, 0x01, 0x02}, fixed)
+
+ _, err = binLit012.To(iceberg.FixedTypeOf(4))
+ assert.ErrorIs(t, err, iceberg.ErrBadCast)
+ assert.ErrorContains(t, err, "cannot convert BinaryLiteral to fixed[4],
different length - 3 <> 4")
+
+ _, err = binLit012.To(iceberg.FixedTypeOf(2))
+ assert.ErrorIs(t, err, iceberg.ErrBadCast)
+ assert.ErrorContains(t, err, "cannot convert BinaryLiteral to fixed[2],
different length - 3 <> 2")
+
+ testUuid := uuid.New()
+ lit := iceberg.NewLiteral(testUuid[:])
+ uuidLit, err := lit.To(iceberg.PrimitiveTypes.UUID)
+ require.NoError(t, err)
+ assert.EqualValues(t, testUuid, uuidLit)
+
+ _, err = binLit012.To(iceberg.PrimitiveTypes.UUID)
+ assert.ErrorIs(t, err, iceberg.ErrBadCast)
+ assert.ErrorContains(t, err, "cannot convert BinaryLiteral to UUID")
+}
+
+func testInvalidLiteralConversions(t *testing.T, lit iceberg.Literal, typs
[]iceberg.Type) {
+ t.Run(lit.Type().String(), func(t *testing.T) {
+ for _, tt := range typs {
+ t.Run(tt.String(), func(t *testing.T) {
+ _, err := lit.To(tt)
+ assert.ErrorIs(t, err, iceberg.ErrBadCast)
+ })
+ }
+ })
+}
+
+func TestInvalidBoolLiteralConversions(t *testing.T) {
+ testInvalidLiteralConversions(t, iceberg.NewLiteral(true),
[]iceberg.Type{
+ iceberg.PrimitiveTypes.Int32,
+ iceberg.PrimitiveTypes.Int64,
+ iceberg.PrimitiveTypes.Float32,
+ iceberg.PrimitiveTypes.Float64,
+ iceberg.PrimitiveTypes.Date,
+ iceberg.PrimitiveTypes.Time,
+ iceberg.PrimitiveTypes.Timestamp,
+ iceberg.PrimitiveTypes.TimestampTz,
+ iceberg.DecimalTypeOf(9, 2),
+ iceberg.PrimitiveTypes.String,
+ iceberg.PrimitiveTypes.UUID,
+ iceberg.PrimitiveTypes.Binary,
+ iceberg.FixedTypeOf(2),
+ })
+}
+
+func TestInvalidNumericConversions(t *testing.T) {
+ testInvalidLiteralConversions(t, iceberg.NewLiteral(int32(34)),
[]iceberg.Type{
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.PrimitiveTypes.String,
+ iceberg.PrimitiveTypes.UUID,
+ iceberg.FixedTypeOf(1),
+ iceberg.PrimitiveTypes.Binary,
+ })
+
+ testInvalidLiteralConversions(t, iceberg.NewLiteral(int64(34)),
[]iceberg.Type{
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.PrimitiveTypes.String,
+ iceberg.PrimitiveTypes.UUID,
+ iceberg.FixedTypeOf(1),
+ iceberg.PrimitiveTypes.Binary,
+ })
+
+ testInvalidLiteralConversions(t, iceberg.NewLiteral(float32(34)),
[]iceberg.Type{
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.PrimitiveTypes.Int32,
+ iceberg.PrimitiveTypes.Int64,
+ iceberg.PrimitiveTypes.Date,
+ iceberg.PrimitiveTypes.Time,
+ iceberg.PrimitiveTypes.Timestamp,
+ iceberg.PrimitiveTypes.TimestampTz,
+ iceberg.PrimitiveTypes.String,
+ iceberg.PrimitiveTypes.UUID,
+ iceberg.FixedTypeOf(1),
+ iceberg.PrimitiveTypes.Binary,
+ })
+
+ testInvalidLiteralConversions(t, iceberg.NewLiteral(float64(34)),
[]iceberg.Type{
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.PrimitiveTypes.Int32,
+ iceberg.PrimitiveTypes.Int64,
+ iceberg.PrimitiveTypes.Date,
+ iceberg.PrimitiveTypes.Time,
+ iceberg.PrimitiveTypes.Timestamp,
+ iceberg.PrimitiveTypes.TimestampTz,
+ iceberg.PrimitiveTypes.String,
+ iceberg.PrimitiveTypes.UUID,
+ iceberg.FixedTypeOf(1),
+ iceberg.PrimitiveTypes.Binary,
+ })
+
+ testInvalidLiteralConversions(t,
iceberg.NewLiteral(iceberg.Decimal{Val: decimal128.FromI64(3411), Scale: 2}),
+ []iceberg.Type{
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.PrimitiveTypes.Date,
+ iceberg.PrimitiveTypes.Time,
+ iceberg.PrimitiveTypes.Timestamp,
+ iceberg.PrimitiveTypes.TimestampTz,
+ iceberg.PrimitiveTypes.String,
+ iceberg.PrimitiveTypes.UUID,
+ iceberg.FixedTypeOf(1),
+ iceberg.PrimitiveTypes.Binary,
+ })
+}
+
+func TestInvalidDateTimeLiteralConversions(t *testing.T) {
+ lit, _ :=
iceberg.NewLiteral("2017-08-18").To(iceberg.PrimitiveTypes.Date)
+ testInvalidLiteralConversions(t, lit, []iceberg.Type{
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.PrimitiveTypes.Int32,
+ iceberg.PrimitiveTypes.Int64,
+ iceberg.PrimitiveTypes.Float32,
+ iceberg.PrimitiveTypes.Float64,
+ iceberg.PrimitiveTypes.Time,
+ iceberg.PrimitiveTypes.Timestamp,
+ iceberg.PrimitiveTypes.TimestampTz,
+ iceberg.DecimalTypeOf(9, 2),
+ iceberg.PrimitiveTypes.String,
+ iceberg.PrimitiveTypes.UUID,
+ iceberg.FixedTypeOf(1),
+ iceberg.PrimitiveTypes.Binary,
+ })
+
+ lit, _ =
iceberg.NewLiteral("14:21:01.919").To(iceberg.PrimitiveTypes.Time)
+ testInvalidLiteralConversions(t, lit, []iceberg.Type{
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.PrimitiveTypes.Int32,
+ iceberg.PrimitiveTypes.Int64,
+ iceberg.PrimitiveTypes.Float32,
+ iceberg.PrimitiveTypes.Float64,
+ iceberg.PrimitiveTypes.Date,
+ iceberg.PrimitiveTypes.Timestamp,
+ iceberg.PrimitiveTypes.TimestampTz,
+ iceberg.DecimalTypeOf(9, 2),
+ iceberg.PrimitiveTypes.String,
+ iceberg.PrimitiveTypes.UUID,
+ iceberg.FixedTypeOf(1),
+ iceberg.PrimitiveTypes.Binary,
+ })
+
+ lit, _ =
iceberg.NewLiteral("2017-08-18T14:21:01.919").To(iceberg.PrimitiveTypes.Timestamp)
+ testInvalidLiteralConversions(t, lit, []iceberg.Type{
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.PrimitiveTypes.Int32,
+ iceberg.PrimitiveTypes.Int64,
+ iceberg.PrimitiveTypes.Float32,
+ iceberg.PrimitiveTypes.Float64,
+ iceberg.PrimitiveTypes.Time,
+ iceberg.DecimalTypeOf(9, 2),
+ iceberg.PrimitiveTypes.String,
+ iceberg.PrimitiveTypes.UUID,
+ iceberg.FixedTypeOf(1),
+ iceberg.PrimitiveTypes.Binary,
+ })
+}
+
+func TestInvalidStringLiteralConversions(t *testing.T) {
+ testInvalidLiteralConversions(t, iceberg.NewLiteral("abc"),
[]iceberg.Type{
+ iceberg.FixedTypeOf(1), iceberg.PrimitiveTypes.Binary,
+ })
+}
+
+func TestInvalidBinaryLiteralConversions(t *testing.T) {
+ testInvalidLiteralConversions(t, iceberg.NewLiteral(uuid.New()),
[]iceberg.Type{
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.PrimitiveTypes.Int32,
+ iceberg.PrimitiveTypes.Int64,
+ iceberg.PrimitiveTypes.Float32,
+ iceberg.PrimitiveTypes.Float64,
+ iceberg.PrimitiveTypes.Date,
+ iceberg.PrimitiveTypes.Time,
+ iceberg.PrimitiveTypes.Timestamp,
+ iceberg.PrimitiveTypes.TimestampTz,
+ iceberg.DecimalTypeOf(9, 2),
+ iceberg.PrimitiveTypes.String,
+ iceberg.FixedTypeOf(1),
+ })
+
+ lit, _ := iceberg.NewLiteral([]byte{0x00, 0x01,
0x02}).To(iceberg.FixedTypeOf(3))
+ testInvalidLiteralConversions(t, lit, []iceberg.Type{
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.PrimitiveTypes.Int32,
+ iceberg.PrimitiveTypes.Int64,
+ iceberg.PrimitiveTypes.Float32,
+ iceberg.PrimitiveTypes.Float64,
+ iceberg.PrimitiveTypes.Date,
+ iceberg.PrimitiveTypes.Time,
+ iceberg.PrimitiveTypes.Timestamp,
+ iceberg.PrimitiveTypes.TimestampTz,
+ iceberg.DecimalTypeOf(9, 2),
+ iceberg.PrimitiveTypes.String,
+ iceberg.PrimitiveTypes.UUID,
+ })
+
+ testInvalidLiteralConversions(t, iceberg.NewLiteral([]byte{0x00, 0x01,
0x02}), []iceberg.Type{
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.PrimitiveTypes.Int32,
+ iceberg.PrimitiveTypes.Int64,
+ iceberg.PrimitiveTypes.Float32,
+ iceberg.PrimitiveTypes.Float64,
+ iceberg.PrimitiveTypes.Date,
+ iceberg.PrimitiveTypes.Time,
+ iceberg.PrimitiveTypes.Timestamp,
+ iceberg.PrimitiveTypes.TimestampTz,
+ iceberg.DecimalTypeOf(9, 2),
+ iceberg.PrimitiveTypes.String,
+ iceberg.PrimitiveTypes.UUID,
+ })
+}
+
+func TestBadStringLiteralCasts(t *testing.T) {
+ tests := []iceberg.Type{
+ iceberg.PrimitiveTypes.Int32,
+ iceberg.PrimitiveTypes.Int64,
+ iceberg.PrimitiveTypes.Float32,
+ iceberg.PrimitiveTypes.Float64,
+ iceberg.PrimitiveTypes.Date,
+ iceberg.PrimitiveTypes.Time,
+ iceberg.PrimitiveTypes.Timestamp,
+ iceberg.PrimitiveTypes.TimestampTz,
+ iceberg.PrimitiveTypes.Bool,
+ iceberg.DecimalTypeOf(9, 2),
+ iceberg.PrimitiveTypes.UUID,
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.String(), func(t *testing.T) {
+ _, err := iceberg.NewLiteral("abc").To(tt)
+ assert.ErrorIs(t, err, iceberg.ErrBadCast)
+ })
+ }
+}
+
+func TestStringLiteralToIntMaxMinValue(t *testing.T) {
+ above, err := iceberg.NewLiteral(strconv.FormatInt(math.MaxInt32+1,
10)).
+ To(iceberg.PrimitiveTypes.Int32)
+ require.NoError(t, err)
+ assert.Equal(t, iceberg.Int32AboveMaxLiteral(), above)
+
+ below, err := iceberg.NewLiteral(strconv.FormatInt(math.MinInt32-1,
10)).
+ To(iceberg.PrimitiveTypes.Int32)
+ require.NoError(t, err)
+ assert.Equal(t, iceberg.Int32BelowMinLiteral(), below)
+}
diff --git a/types.go b/types.go
index 8ca0ad7..5aabdb4 100644
--- a/types.go
+++ b/types.go
@@ -23,7 +23,9 @@ import (
"regexp"
"strconv"
"strings"
+ "time"
+ "github.com/apache/arrow/go/v16/arrow/decimal128"
"golang.org/x/exp/slices"
)
@@ -407,6 +409,7 @@ func (f FixedType) Equals(other Type) bool {
func (f FixedType) Len() int { return f.len }
func (f FixedType) Type() string { return fmt.Sprintf("fixed[%d]", f.len) }
func (f FixedType) String() string { return fmt.Sprintf("fixed[%d]", f.len) }
+func (f FixedType) primitive() {}
func DecimalTypeOf(prec, scale int) DecimalType {
return DecimalType{precision: prec, scale: scale}
@@ -430,6 +433,12 @@ func (d DecimalType) Type() string { return
fmt.Sprintf("decimal(%d, %d)", d.p
func (d DecimalType) String() string { return fmt.Sprintf("decimal(%d, %d)",
d.precision, d.scale) }
func (d DecimalType) Precision() int { return d.precision }
func (d DecimalType) Scale() int { return d.scale }
+func (DecimalType) primitive() {}
+
+type Decimal struct {
+ Val decimal128.Num
+ Scale int
+}
type PrimitiveType interface {
Type
@@ -527,6 +536,11 @@ func (TimeType) String() string { return "time" }
type Timestamp int64
+func (t Timestamp) ToDate() Date {
+ tm := time.UnixMicro(int64(t)).UTC()
+ return Date(tm.Truncate(24*time.Hour).Unix() / int64((time.Hour *
24).Seconds()))
+}
+
// TimestampType represents a number of microseconds since the unix epoch
// without regard for timezone.
type TimestampType struct{}
diff --git a/utils.go b/utils.go
index 907a35f..fd669f8 100644
--- a/utils.go
+++ b/utils.go
@@ -18,10 +18,9 @@
package iceberg
import (
+ "cmp"
"runtime/debug"
"strings"
-
- "golang.org/x/exp/constraints"
)
var version string
@@ -40,7 +39,7 @@ func init() {
func Version() string { return version }
-func max[T constraints.Ordered](vals ...T) T {
+func max[T cmp.Ordered](vals ...T) T {
if len(vals) == 0 {
panic("can't call max with no arguments")
}