refactor!(collections): don't panic when initializing collections (#14323)
This commit is contained in:
parent
bc46bbbec0
commit
1d2de854d1
@ -2,11 +2,12 @@ package collections
|
||||
|
||||
import (
|
||||
"context"
|
||||
"cosmossdk.io/core/store"
|
||||
db "github.com/tendermint/tm-db"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"cosmossdk.io/core/store"
|
||||
db "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ go 1.19
|
||||
|
||||
require (
|
||||
cosmossdk.io/core v0.3.4
|
||||
github.com/hashicorp/go-multierror v1.1.1 // TODO: remove with go 1.20 release
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/tendermint/tm-db v0.6.7
|
||||
)
|
||||
@ -17,13 +18,16 @@ require (
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/golang/glog v1.0.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/jmhodges/levigo v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.15.12 // indirect
|
||||
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||
github.com/onsi/gomega v1.20.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||
|
||||
@ -33,8 +33,9 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojt
|
||||
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
|
||||
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
||||
@ -59,6 +60,11 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
@ -75,15 +81,18 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q=
|
||||
github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@ -105,6 +114,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
@ -115,19 +125,25 @@ github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu
|
||||
github.com/tendermint/tm-db v0.6.7/go.mod h1:byQDzFkZV1syXr/ReXS808NxA2xvyuuVgXOJ/088L6I=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -140,7 +156,9 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -149,8 +167,11 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
@ -171,7 +192,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@ -12,12 +12,12 @@ type Item[V any] Map[noKey, V]
|
||||
// Name and prefix must be unique within the schema and name must match the format specified by NameRegex, or
|
||||
// else this method will panic.
|
||||
func NewItem[V any](
|
||||
schema Schema,
|
||||
schema *SchemaBuilder,
|
||||
prefix Prefix,
|
||||
name string,
|
||||
valueCodec ValueCodec[V],
|
||||
) Item[V] {
|
||||
item := (Item[V])(newMap[noKey, V](schema, prefix, name, noKey{}, valueCodec))
|
||||
item := (Item[V])(newMap[noKey](schema, prefix, name, noKey{}, valueCodec))
|
||||
schema.addCollection(item)
|
||||
return item
|
||||
}
|
||||
|
||||
@ -8,10 +8,13 @@ import (
|
||||
|
||||
func TestItem(t *testing.T) {
|
||||
sk, ctx := deps()
|
||||
schema := NewSchema(sk)
|
||||
item := NewItem(schema, NewPrefix("item"), "item", Uint64Value)
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
item := NewItem(schemaBuilder, NewPrefix("item"), "item", Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.NoError(t, err)
|
||||
|
||||
// set
|
||||
err := item.Set(ctx, 1000)
|
||||
err = item.Set(ctx, 1000)
|
||||
require.NoError(t, err)
|
||||
|
||||
// get
|
||||
|
||||
@ -104,8 +104,10 @@ func (r *Range[K]) Descending() *Range[K] {
|
||||
}
|
||||
|
||||
// test sentinel error
|
||||
var errRange = errors.New("collections: range error")
|
||||
var errOrder = errors.New("collections: invalid order")
|
||||
var (
|
||||
errRange = errors.New("collections: range error")
|
||||
errOrder = errors.New("collections: invalid order")
|
||||
)
|
||||
|
||||
func (r *Range[K]) RangeValues() (prefix *K, start *Bound[K], end *Bound[K], order Order, err error) {
|
||||
if r.prefix != nil && (r.end != nil || r.start != nil) {
|
||||
|
||||
@ -2,14 +2,17 @@ package collections
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestIteratorBasic(t *testing.T) {
|
||||
sk, ctx := deps()
|
||||
schema := NewSchema(sk)
|
||||
m := NewMap(schema, NewPrefix("some super amazing prefix"), "m", StringKey, Uint64Value)
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
m := NewMap(schemaBuilder, NewPrefix("some super amazing prefix"), "m", StringKey, Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := uint64(1); i <= 2; i++ {
|
||||
require.NoError(t, m.Set(ctx, fmt.Sprintf("%d", i), i))
|
||||
@ -55,8 +58,10 @@ func TestIteratorBasic(t *testing.T) {
|
||||
|
||||
func TestIteratorKeyValues(t *testing.T) {
|
||||
sk, ctx := deps()
|
||||
schema := NewSchema(sk)
|
||||
m := NewMap(schema, NewPrefix("some super amazing prefix"), "m", StringKey, Uint64Value)
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
m := NewMap(schemaBuilder, NewPrefix("some super amazing prefix"), "m", StringKey, Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := uint64(0); i <= 5; i++ {
|
||||
require.NoError(t, m.Set(ctx, fmt.Sprintf("%d", i), i))
|
||||
@ -102,8 +107,10 @@ func TestIteratorKeyValues(t *testing.T) {
|
||||
|
||||
func TestIteratorPrefixing(t *testing.T) {
|
||||
sk, ctx := deps()
|
||||
schema := NewSchema(sk)
|
||||
m := NewMap(schema, NewPrefix("cool"), "cool", StringKey, Uint64Value)
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
m := NewMap(schemaBuilder, NewPrefix("cool"), "cool", StringKey, Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, m.Set(ctx, "A1", 11))
|
||||
require.NoError(t, m.Set(ctx, "A2", 12))
|
||||
@ -118,8 +125,10 @@ func TestIteratorPrefixing(t *testing.T) {
|
||||
|
||||
func TestIteratorRanging(t *testing.T) {
|
||||
sk, ctx := deps()
|
||||
schema := NewSchema(sk)
|
||||
m := NewMap(schema, NewPrefix("cool"), "cool", Uint64Key, Uint64Value)
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
m := NewMap(schemaBuilder, NewPrefix("cool"), "cool", Uint64Key, Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := uint64(0); i <= 7; i++ {
|
||||
require.NoError(t, m.Set(ctx, i, i))
|
||||
|
||||
@ -12,7 +12,7 @@ import (
|
||||
type KeySet[K any] Map[K, noValue]
|
||||
|
||||
// NewKeySet returns a KeySet given a Schema, Prefix a human name for the collection and a KeyCodec for the key K.
|
||||
func NewKeySet[K any](schema Schema, prefix Prefix, name string, keyCodec KeyCodec[K]) KeySet[K] {
|
||||
func NewKeySet[K any](schema *SchemaBuilder, prefix Prefix, name string, keyCodec KeyCodec[K]) KeySet[K] {
|
||||
return (KeySet[K])(NewMap(schema, prefix, name, keyCodec, noValueCodec))
|
||||
}
|
||||
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
package collections
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestKeySet(t *testing.T) {
|
||||
sk, ctx := deps()
|
||||
schema := NewSchema(sk)
|
||||
schema := NewSchemaBuilder(sk)
|
||||
ks := NewKeySet(schema, NewPrefix("keyset"), "keyset", StringKey)
|
||||
|
||||
// set
|
||||
@ -65,5 +66,4 @@ func Test_noValue(t *testing.T) {
|
||||
|
||||
_, err = noValueCodec.Decode([]byte("bad"))
|
||||
require.ErrorIs(t, err, ErrEncoding)
|
||||
|
||||
}
|
||||
|
||||
@ -24,25 +24,25 @@ type Map[K, V any] struct {
|
||||
// Name and prefix must be unique within the schema and name must match the format specified by NameRegex, or
|
||||
// else this method will panic.
|
||||
func NewMap[K, V any](
|
||||
schema Schema,
|
||||
schemaBuilder *SchemaBuilder,
|
||||
prefix Prefix,
|
||||
name string,
|
||||
keyCodec KeyCodec[K],
|
||||
valueCodec ValueCodec[V],
|
||||
) Map[K, V] {
|
||||
m := newMap(schema, prefix, name, keyCodec, valueCodec)
|
||||
schema.addCollection(m)
|
||||
m := newMap(schemaBuilder, prefix, name, keyCodec, valueCodec)
|
||||
schemaBuilder.addCollection(m)
|
||||
return m
|
||||
}
|
||||
|
||||
func newMap[K, V any](
|
||||
schema Schema, prefix Prefix, name string,
|
||||
schemaBuilder *SchemaBuilder, prefix Prefix, name string,
|
||||
keyCodec KeyCodec[K], valueCodec ValueCodec[V],
|
||||
) Map[K, V] {
|
||||
return Map[K, V]{
|
||||
kc: keyCodec,
|
||||
vc: valueCodec,
|
||||
sa: schema.storeAccessor,
|
||||
sa: schemaBuilder.schema.storeAccessor,
|
||||
prefix: prefix.Bytes(),
|
||||
name: name,
|
||||
}
|
||||
@ -60,7 +60,6 @@ func (m Map[K, V]) getPrefix() []byte {
|
||||
// Errors with ErrEncoding if key or value encoding fails.
|
||||
func (m Map[K, V]) Set(ctx context.Context, key K, value V) error {
|
||||
bytesKey, err := encodeKeyWithPrefix(m.prefix, m.kc, key)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -8,8 +8,10 @@ import (
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
sk, ctx := deps()
|
||||
schema := NewSchema(sk)
|
||||
m := NewMap(schema, NewPrefix("hi"), "m", Uint64Key, Uint64Value)
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
m := NewMap(schemaBuilder, NewPrefix("hi"), "m", Uint64Key, Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.NoError(t, err)
|
||||
|
||||
// test not has
|
||||
has, err := m.Has(ctx, 1)
|
||||
|
||||
@ -2,11 +2,102 @@ package collections
|
||||
|
||||
import (
|
||||
"context"
|
||||
"cosmossdk.io/core/store"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"cosmossdk.io/core/store"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
)
|
||||
|
||||
// SchemaBuilder is used for building schemas. The Build method should always
|
||||
// be called after all collections have been initialized. Initializing new
|
||||
// collections with the builder after initialization will result in panics.
|
||||
type SchemaBuilder struct {
|
||||
schema *Schema
|
||||
err *multierror.Error
|
||||
}
|
||||
|
||||
// NewSchemaBuilder creates a new schema builder from the provided store key.
|
||||
// Callers should always call the SchemaBuilder.Build method when they are
|
||||
// done adding collections to the schema.
|
||||
func NewSchemaBuilder(service store.KVStoreService) *SchemaBuilder {
|
||||
return &SchemaBuilder{
|
||||
schema: &Schema{
|
||||
storeAccessor: service.OpenKVStore,
|
||||
collectionsByName: map[string]collection{},
|
||||
collectionsByPrefix: map[string]collection{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Build should be called after all collections that are part of the schema
|
||||
// have been initialized in order to get a reference to the Schema. It is
|
||||
// important to check the returned error for any initialization errors.
|
||||
// The SchemaBuilder CANNOT be used after Build is called - doing so will
|
||||
// result in panics.
|
||||
func (s *SchemaBuilder) Build() (Schema, error) {
|
||||
if s.err != nil {
|
||||
return Schema{}, s.err
|
||||
}
|
||||
|
||||
// check for any overlapping prefixes
|
||||
for prefix := range s.schema.collectionsByPrefix {
|
||||
for prefix2 := range s.schema.collectionsByPrefix {
|
||||
// don't compare the prefix to itself
|
||||
if prefix == prefix2 {
|
||||
continue
|
||||
}
|
||||
|
||||
// if one prefix is the prefix of the other we have an overlap and
|
||||
// this schema is corrupt
|
||||
if strings.HasPrefix(prefix, prefix2) {
|
||||
return Schema{}, fmt.Errorf("schema has overlapping prefixes 0x%x and 0x%x", prefix, prefix2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.schema == nil {
|
||||
// explicit panic to avoid nil pointer dereference
|
||||
panic("schema is nil")
|
||||
}
|
||||
|
||||
schema := *s.schema
|
||||
|
||||
s.schema = nil // this makes the builder unusable
|
||||
|
||||
return schema, nil
|
||||
}
|
||||
|
||||
func (s *SchemaBuilder) addCollection(collection collection) {
|
||||
prefix := collection.getPrefix()
|
||||
name := collection.getName()
|
||||
|
||||
if _, ok := s.schema.collectionsByPrefix[string(prefix)]; ok {
|
||||
s.err = multierror.Append(s.err, fmt.Errorf("prefix %v already taken within schema", prefix))
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := s.schema.collectionsByName[name]; ok {
|
||||
s.err = multierror.Append(s.err, fmt.Errorf("name %s already taken within schema", name))
|
||||
return
|
||||
}
|
||||
|
||||
if !nameRegex.MatchString(name) {
|
||||
s.err = multierror.Append(s.err, fmt.Errorf("name must match regex %s, got %s", NameRegex, name))
|
||||
return
|
||||
}
|
||||
|
||||
s.schema.collectionsByPrefix[string(prefix)] = collection
|
||||
s.schema.collectionsByName[name] = collection
|
||||
}
|
||||
|
||||
// NameRegex is the regular expression that all valid collection names must match.
|
||||
const NameRegex = "[A-Za-z][A-Za-z0-9_]*"
|
||||
|
||||
var nameRegex = regexp.MustCompile("^" + NameRegex + "$")
|
||||
|
||||
// Schema specifies a group of collections stored within the storage specified
|
||||
// by a single store key. All the collections within the schema must have a
|
||||
// unique binary prefix and human-readable name. Schema will eventually include
|
||||
@ -47,28 +138,3 @@ func NewSchemaFromAccessor(accessor func(context.Context) store.KVStore) Schema
|
||||
collectionsByPrefix: map[string]collection{},
|
||||
}
|
||||
}
|
||||
|
||||
func (s Schema) addCollection(collection collection) {
|
||||
prefix := collection.getPrefix()
|
||||
name := collection.getName()
|
||||
|
||||
if _, ok := s.collectionsByPrefix[string(prefix)]; ok {
|
||||
panic(fmt.Errorf("prefix %v already taken within schema", prefix))
|
||||
}
|
||||
|
||||
if _, ok := s.collectionsByName[name]; ok {
|
||||
panic(fmt.Errorf("name %s already taken within schema", name))
|
||||
}
|
||||
|
||||
if !nameRegex.MatchString(name) {
|
||||
panic(fmt.Errorf("name must match regex %s, got %s", NameRegex, name))
|
||||
}
|
||||
|
||||
s.collectionsByPrefix[string(prefix)] = collection
|
||||
s.collectionsByName[name] = collection
|
||||
}
|
||||
|
||||
// NameRegex is the regular expression that all valid collection names must match.
|
||||
const NameRegex = "[A-Za-z][A-Za-z0-9_]*"
|
||||
|
||||
var nameRegex = regexp.MustCompile("^" + NameRegex + "$")
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
package collections
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNameRegex(t *testing.T) {
|
||||
@ -14,27 +15,58 @@ func TestNameRegex(t *testing.T) {
|
||||
require.NotRegexp(t, nameRegex, "abc-xyz")
|
||||
}
|
||||
|
||||
func TestAddCollection(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
schema := NewSchema(nil)
|
||||
NewMap(schema, NewPrefix(1), "abc", Uint64Key, Uint64Value)
|
||||
NewMap(schema, NewPrefix(2), "def", Uint64Key, Uint64Value)
|
||||
})
|
||||
func TestGoodSchema(t *testing.T) {
|
||||
sk, _ := deps()
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
NewMap(schemaBuilder, NewPrefix(1), "abc", Uint64Key, Uint64Value)
|
||||
NewMap(schemaBuilder, NewPrefix(2), "def", Uint64Key, Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
require.PanicsWithError(t, "name must match regex [A-Za-z][A-Za-z0-9_]*, got 123", func() {
|
||||
schema := NewSchema(nil)
|
||||
NewMap(schema, NewPrefix(1), "123", Uint64Key, Uint64Value)
|
||||
})
|
||||
func TestBadName(t *testing.T) {
|
||||
sk, _ := deps()
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
NewMap(schemaBuilder, NewPrefix(1), "123", Uint64Key, Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.ErrorContains(t, err, "name must match regex")
|
||||
}
|
||||
|
||||
require.PanicsWithError(t, "prefix [1] already taken within schema", func() {
|
||||
schema := NewSchema(nil)
|
||||
NewMap(schema, NewPrefix(1), "abc", Uint64Key, Uint64Value)
|
||||
NewMap(schema, NewPrefix(1), "def", Uint64Key, Uint64Value)
|
||||
})
|
||||
func TestDuplicatePrefix(t *testing.T) {
|
||||
sk, _ := deps()
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
NewMap(schemaBuilder, NewPrefix(1), "abc", Uint64Key, Uint64Value)
|
||||
NewMap(schemaBuilder, NewPrefix(1), "def", Uint64Key, Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.ErrorContains(t, err, "prefix [1] already taken")
|
||||
}
|
||||
|
||||
require.PanicsWithError(t, "name abc already taken within schema", func() {
|
||||
schema := NewSchema(nil)
|
||||
NewMap(schema, NewPrefix(1), "abc", Uint64Key, Uint64Value)
|
||||
NewMap(schema, NewPrefix(2), "abc", Uint64Key, Uint64Value)
|
||||
func TestDuplicateName(t *testing.T) {
|
||||
sk, _ := deps()
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
NewMap(schemaBuilder, NewPrefix(1), "abc", Uint64Key, Uint64Value)
|
||||
NewMap(schemaBuilder, NewPrefix(2), "abc", Uint64Key, Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.ErrorContains(t, err, "name abc already taken")
|
||||
}
|
||||
|
||||
func TestOverlappingPrefixes(t *testing.T) {
|
||||
sk, _ := deps()
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
NewMap(schemaBuilder, NewPrefix("ab"), "ab", Uint64Key, Uint64Value)
|
||||
NewMap(schemaBuilder, NewPrefix("abc"), "abc", Uint64Key, Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.ErrorContains(t, err, "overlapping prefixes")
|
||||
}
|
||||
|
||||
func TestSchemaBuilderCantBeUsedAfterBuild(t *testing.T) {
|
||||
sk, _ := deps()
|
||||
schemaBuilder := NewSchemaBuilder(sk)
|
||||
NewMap(schemaBuilder, NewPrefix(1), "abc", Uint64Key, Uint64Value)
|
||||
_, err := schemaBuilder.Build()
|
||||
require.NoError(t, err)
|
||||
// can't use schema builder safely after calling build
|
||||
require.Panics(t, func() {
|
||||
NewMap(schemaBuilder, NewPrefix(2), "def", Uint64Key, Uint64Value)
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ type Sequence Item[uint64]
|
||||
|
||||
// NewSequence instantiates a new sequence given
|
||||
// a Schema, a Prefix and humanised name for the sequence.
|
||||
func NewSequence(schema Schema, prefix Prefix, name string) Sequence {
|
||||
func NewSequence(schema *SchemaBuilder, prefix Prefix, name string) Sequence {
|
||||
return (Sequence)(NewItem(schema, prefix, name, Uint64Value))
|
||||
}
|
||||
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
package collections
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSequence(t *testing.T) {
|
||||
sk, ctx := deps()
|
||||
schema := NewSchema(sk)
|
||||
schema := NewSchemaBuilder(sk)
|
||||
seq := NewSequence(schema, NewPrefix(0), "sequence")
|
||||
// initially the first available number is DefaultSequenceStart
|
||||
n, err := seq.Peek(ctx)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user