From 4d88791c76a9e2e971c19f114c2bd55c03c8dccd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 05:12:41 -0500 Subject: [PATCH 1/5] bot: Update dependencies (bulk dependabot PRs) 03-02-2025 (#3424) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✅ This PR was created by combining the following PRs: #3422 bot: Bump swagger-ui-react and @types/swagger-ui-react in /playground #3420 bot: Bump github.com/libp2p/go-libp2p-kad-dht from 0.28.2 to 0.29.0 #3419 bot: Bump github.com/spf13/pflag from 1.0.5 to 1.0.6 ⚠️ The following PRs were resolved manually due to merge conflicts: #3421 bot: Bump react and @types/react in /playground --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Shahzad Lone --- go.mod | 18 +- go.sum | 35 +-- playground/package-lock.json | 427 +++++++++++++++++------------------ playground/package.json | 8 +- 4 files changed, 241 insertions(+), 247 deletions(-) diff --git a/go.mod b/go.mod index c0245e34ca..c00e0582cd 100644 --- a/go.mod +++ b/go.mod @@ -34,9 +34,9 @@ require ( github.com/lestrrat-go/jwx/v2 v2.1.3 github.com/libp2p/go-libp2p v0.38.2 github.com/libp2p/go-libp2p-gostream v0.6.0 - github.com/libp2p/go-libp2p-kad-dht v0.28.2 + github.com/libp2p/go-libp2p-kad-dht v0.29.0 github.com/libp2p/go-libp2p-pubsub v0.12.0 - github.com/libp2p/go-libp2p-record v0.2.0 + github.com/libp2p/go-libp2p-record v0.3.1 github.com/mr-tron/base58 v1.2.0 github.com/multiformats/go-multiaddr v0.14.0 github.com/multiformats/go-multibase v0.2.0 @@ -52,7 +52,7 @@ require ( github.com/sourcenetwork/immutable v0.3.0 github.com/sourcenetwork/sourcehub v0.2.1-0.20240704194128-f43f5e427274 github.com/spf13/cobra v1.8.1 - github.com/spf13/pflag v1.0.5 + github.com/spf13/pflag v1.0.6 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/btree v1.7.0 @@ -63,7 +63,7 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.34.0 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.32.0 - golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 + golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 google.golang.org/grpc v1.70.0 ) @@ -316,7 +316,7 @@ require ( github.com/pquerna/cachecontrol v0.1.0 // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.61.0 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/quic-go v0.48.2 // indirect @@ -365,20 +365,20 @@ require ( go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.33.0 // indirect + golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.29.0 // indirect golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.28.0 // indirect - gonum.org/v1/gonum v0.15.0 // indirect + golang.org/x/tools v0.29.0 // indirect + gonum.org/v1/gonum v0.15.1 // indirect google.golang.org/api v0.171.0 // indirect google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect - google.golang.org/protobuf v1.36.0 // indirect + google.golang.org/protobuf v1.36.3 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 6f35b03ab2..1bb4fd7e5d 100644 --- a/go.sum +++ b/go.sum @@ -1006,14 +1006,14 @@ github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl9 github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-gostream v0.6.0 h1:QfAiWeQRce6pqnYfmIVWJFXNdDyfiR/qkCnjyaZUPYU= github.com/libp2p/go-libp2p-gostream v0.6.0/go.mod h1:Nywu0gYZwfj7Jc91PQvbGU8dIpqbQQkjWgDuOrFaRdA= -github.com/libp2p/go-libp2p-kad-dht v0.28.2 h1:/VivUl/Ru0tVgkWNhDDBy8pK6q+gRdI+z8VfqmSUJWo= -github.com/libp2p/go-libp2p-kad-dht v0.28.2/go.mod h1:sUR/qh4p/5+YFXBtwOiCmIBeBA2YD94ttmL+Xk8+pTE= +github.com/libp2p/go-libp2p-kad-dht v0.29.0 h1:045eW21lGlMSD9aKSZZGH4fnBMIInPwQLxIQ35P962I= +github.com/libp2p/go-libp2p-kad-dht v0.29.0/go.mod h1:mIci3rHSwDsxQWcCjfmxD8vMTgh5xLuvwb1D5WP8ZNk= github.com/libp2p/go-libp2p-kbucket v0.6.4 h1:OjfiYxU42TKQSB8t8WYd8MKhYhMJeO2If+NiuKfb6iQ= github.com/libp2p/go-libp2p-kbucket v0.6.4/go.mod h1:jp6w82sczYaBsAypt5ayACcRJi0lgsba7o4TzJKEfWA= github.com/libp2p/go-libp2p-pubsub v0.12.0 h1:PENNZjSfk8KYxANRlpipdS7+BfLmOl3L2E/6vSNjbdI= github.com/libp2p/go-libp2p-pubsub v0.12.0/go.mod h1:Oi0zw9aw8/Y5GC99zt+Ef2gYAl+0nZlwdJonDyOz/sE= -github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= -github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= +github.com/libp2p/go-libp2p-record v0.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg= +github.com/libp2p/go-libp2p-record v0.3.1/go.mod h1:T8itUkLcWQLCYMqtX7Th6r7SexyUJpIyPgks757td/E= github.com/libp2p/go-libp2p-routing-helpers v0.7.4 h1:6LqS1Bzn5CfDJ4tzvP9uwh42IB7TJLNFJA6dEeGBv84= github.com/libp2p/go-libp2p-routing-helpers v0.7.4/go.mod h1:we5WDj9tbolBXOuF1hGOkR+r7Uh1408tQbAKaT5n1LE= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= @@ -1301,8 +1301,8 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ= -github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1428,8 +1428,9 @@ github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3k github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= @@ -1622,8 +1623,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= -golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1721,8 +1722,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1977,8 +1978,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 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.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= +golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= 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= @@ -1989,8 +1990,8 @@ golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNq golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/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= +gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0= +gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -2231,8 +2232,8 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= -google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/playground/package-lock.json b/playground/package-lock.json index b18c957e4e..dcfd5db9c1 100644 --- a/playground/package-lock.json +++ b/playground/package-lock.json @@ -10,14 +10,14 @@ "dependencies": { "graphiql": "^3.8.3", "graphql": "^16.10.0", - "react": "^18.3.1", + "react": "^19.0.0", "react-dom": "^19.0.0", - "swagger-ui-react": "^5.18.2" + "swagger-ui-react": "^5.18.3" }, "devDependencies": { - "@types/react": "^18.3.12", + "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", - "@types/swagger-ui-react": "^4.19.0", + "@types/swagger-ui-react": "^5.18.0", "@typescript-eslint/eslint-plugin": "^8.20.0", "@typescript-eslint/parser": "^8.21.0", "@vitejs/plugin-react-swc": "^3.7.2", @@ -524,13 +524,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", - "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.5", + "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -634,9 +634,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", - "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1544,9 +1544,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.0.tgz", - "integrity": "sha512-G2fUQQANtBPsNwiVFg4zKiPQyjVKZCUdQUol53R8E71J7AsheRMV/Yv/nB8giOcOVqP7//eB5xPqieBYZe9bGg==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.1.tgz", + "integrity": "sha512-kwctwVlswSEsr4ljpmxKrRKp1eG1v2NAhlzFzDf1x1OdYaMjBYjDCbHkzWm57ZXzTwqn8stMXgROrnMw8dJK3w==", "cpu": [ "arm" ], @@ -1558,9 +1558,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.0.tgz", - "integrity": "sha512-qhFwQ+ljoymC+j5lXRv8DlaJYY/+8vyvYmVx074zrLsu5ZGWYsJNLjPPVJJjhZQpyAKUGPydOq9hRLLNvh1s3A==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.1.tgz", + "integrity": "sha512-4H5ZtZitBPlbPsTv6HBB8zh1g5d0T8TzCmpndQdqq20Ugle/nroOyDMf9p7f88Gsu8vBLU78/cuh8FYHZqdXxw==", "cpu": [ "arm64" ], @@ -1572,9 +1572,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.0.tgz", - "integrity": "sha512-44n/X3lAlWsEY6vF8CzgCx+LQaoqWGN7TzUfbJDiTIOjJm4+L2Yq+r5a8ytQRGyPqgJDs3Rgyo8eVL7n9iW6AQ==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.1.tgz", + "integrity": "sha512-f2AJ7Qwx9z25hikXvg+asco8Sfuc5NCLg8rmqQBIOUoWys5sb/ZX9RkMZDPdnnDevXAMJA5AWLnRBmgdXGEUiA==", "cpu": [ "arm64" ], @@ -1586,9 +1586,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.0.tgz", - "integrity": "sha512-F9ct0+ZX5Np6+ZDztxiGCIvlCaW87HBdHcozUfsHnj1WCUTBUubAoanhHUfnUHZABlElyRikI0mgcw/qdEm2VQ==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.1.tgz", + "integrity": "sha512-+/2JBrRfISCsWE4aEFXxd+7k9nWGXA8+wh7ZUHn/u8UDXOU9LN+QYKKhd57sIn6WRcorOnlqPMYFIwie/OHXWw==", "cpu": [ "x64" ], @@ -1600,9 +1600,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.0.tgz", - "integrity": "sha512-JpsGxLBB2EFXBsTLHfkZDsXSpSmKD3VxXCgBQtlPcuAqB8TlqtLcbeMhxXQkCDv1avgwNjF8uEIbq5p+Cee0PA==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.1.tgz", + "integrity": "sha512-SUeB0pYjIXwT2vfAMQ7E4ERPq9VGRrPR7Z+S4AMssah5EHIilYqjWQoTn5dkDtuIJUSTs8H+C9dwoEcg3b0sCA==", "cpu": [ "arm64" ], @@ -1614,9 +1614,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.0.tgz", - "integrity": "sha512-wegiyBT6rawdpvnD9lmbOpx5Sph+yVZKHbhnSP9MqUEDX08G4UzMU+D87jrazGE7lRSyTRs6NEYHtzfkJ3FjjQ==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.1.tgz", + "integrity": "sha512-L3T66wAZiB/ooiPbxz0s6JEX6Sr2+HfgPSK+LMuZkaGZFAFCQAHiP3dbyqovYdNaiUXcl9TlgnIbcsIicAnOZg==", "cpu": [ "x64" ], @@ -1628,9 +1628,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.0.tgz", - "integrity": "sha512-3pA7xecItbgOs1A5H58dDvOUEboG5UfpTq3WzAdF54acBbUM+olDJAPkgj1GRJ4ZqE12DZ9/hNS2QZk166v92A==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.1.tgz", + "integrity": "sha512-UBXdQ4+ATARuFgsFrQ+tAsKvBi/Hly99aSVdeCUiHV9dRTTpMU7OrM3WXGys1l40wKVNiOl0QYY6cZQJ2xhKlQ==", "cpu": [ "arm" ], @@ -1642,9 +1642,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.0.tgz", - "integrity": "sha512-Y7XUZEVISGyge51QbYyYAEHwpGgmRrAxQXO3siyYo2kmaj72USSG8LtlQQgAtlGfxYiOwu+2BdbPjzEpcOpRmQ==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.1.tgz", + "integrity": "sha512-m/yfZ25HGdcCSwmopEJm00GP7xAUyVcBPjttGLRAqZ60X/bB4Qn6gP7XTwCIU6bITeKmIhhwZ4AMh2XLro+4+w==", "cpu": [ "arm" ], @@ -1656,9 +1656,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.0.tgz", - "integrity": "sha512-r7/OTF5MqeBrZo5omPXcTnjvv1GsrdH8a8RerARvDFiDwFpDVDnJyByYM/nX+mvks8XXsgPUxkwe/ltaX2VH7w==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.1.tgz", + "integrity": "sha512-Wy+cUmFuvziNL9qWRRzboNprqSQ/n38orbjRvd6byYWridp5TJ3CD+0+HUsbcWVSNz9bxkDUkyASGP0zS7GAvg==", "cpu": [ "arm64" ], @@ -1670,9 +1670,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.0.tgz", - "integrity": "sha512-HJbifC9vex9NqnlodV2BHVFNuzKL5OnsV2dvTw6e1dpZKkNjPG6WUq+nhEYV6Hv2Bv++BXkwcyoGlXnPrjAKXw==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.1.tgz", + "integrity": "sha512-CQ3MAGgiFmQW5XJX5W3wnxOBxKwFlUAgSXFA2SwgVRjrIiVt5LHfcQLeNSHKq5OEZwv+VCBwlD1+YKCjDG8cpg==", "cpu": [ "arm64" ], @@ -1684,9 +1684,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.0.tgz", - "integrity": "sha512-VAEzZTD63YglFlWwRj3taofmkV1V3xhebDXffon7msNz4b14xKsz7utO6F8F4cqt8K/ktTl9rm88yryvDpsfOw==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.1.tgz", + "integrity": "sha512-rSzb1TsY4lSwH811cYC3OC2O2mzNMhM13vcnA7/0T6Mtreqr3/qs6WMDriMRs8yvHDI54qxHgOk8EV5YRAHFbw==", "cpu": [ "loong64" ], @@ -1698,9 +1698,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.0.tgz", - "integrity": "sha512-Sts5DST1jXAc9YH/iik1C9QRsLcCoOScf3dfbY5i4kH9RJpKxiTBXqm7qU5O6zTXBTEZry69bGszr3SMgYmMcQ==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.1.tgz", + "integrity": "sha512-fwr0n6NS0pG3QxxlqVYpfiY64Fd1Dqd8Cecje4ILAV01ROMp4aEdCj5ssHjRY3UwU7RJmeWd5fi89DBqMaTawg==", "cpu": [ "ppc64" ], @@ -1712,9 +1712,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.0.tgz", - "integrity": "sha512-qhlXeV9AqxIyY9/R1h1hBD6eMvQCO34ZmdYvry/K+/MBs6d1nRFLm6BOiITLVI+nFAAB9kUB6sdJRKyVHXnqZw==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.1.tgz", + "integrity": "sha512-4uJb9qz7+Z/yUp5RPxDGGGUcoh0PnKF33QyWgEZ3X/GocpWb6Mb+skDh59FEt5d8+Skxqs9mng6Swa6B2AmQZg==", "cpu": [ "riscv64" ], @@ -1726,9 +1726,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.0.tgz", - "integrity": "sha512-8ZGN7ExnV0qjXa155Rsfi6H8M4iBBwNLBM9lcVS+4NcSzOFaNqmt7djlox8pN1lWrRPMRRQ8NeDlozIGx3Omsw==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.1.tgz", + "integrity": "sha512-QlIo8ndocWBEnfmkYqj8vVtIUpIqJjfqKggjy7IdUncnt8BGixte1wDON7NJEvLg3Kzvqxtbo8tk+U1acYEBlw==", "cpu": [ "s390x" ], @@ -1740,9 +1740,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.0.tgz", - "integrity": "sha512-VDzNHtLLI5s7xd/VubyS10mq6TxvZBp+4NRWoW+Hi3tgV05RtVm4qK99+dClwTN1McA6PHwob6DEJ6PlXbY83A==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.1.tgz", + "integrity": "sha512-hzpleiKtq14GWjz3ahWvJXgU1DQC9DteiwcsY4HgqUJUGxZThlL66MotdUEK9zEo0PK/2ADeZGM9LIondE302A==", "cpu": [ "x64" ], @@ -1754,9 +1754,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.0.tgz", - "integrity": "sha512-qcb9qYDlkxz9DxJo7SDhWxTWV1gFuwznjbTiov289pASxlfGbaOD54mgbs9+z94VwrXtKTu+2RqwlSTbiOqxGg==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.1.tgz", + "integrity": "sha512-jqtKrO715hDlvUcEsPn55tZt2TEiBvBtCMkUuU0R6fO/WPT7lO9AONjPbd8II7/asSiNVQHCMn4OLGigSuxVQA==", "cpu": [ "x64" ], @@ -1768,9 +1768,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.0.tgz", - "integrity": "sha512-pFDdotFDMXW2AXVbfdUEfidPAk/OtwE/Hd4eYMTNVVaCQ6Yl8et0meDaKNL63L44Haxv4UExpv9ydSf3aSayDg==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.1.tgz", + "integrity": "sha512-RnHy7yFf2Wz8Jj1+h8klB93N0NHNHXFhNwAmiy9zJdpY7DE01VbEVtPdrK1kkILeIbHGRJjvfBDBhnxBr8kD4g==", "cpu": [ "arm64" ], @@ -1782,9 +1782,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.0.tgz", - "integrity": "sha512-/TG7WfrCAjeRNDvI4+0AAMoHxea/USWhAzf9PVDFHbcqrQ7hMMKp4jZIy4VEjk72AAfN5k4TiSMRXRKf/0akSw==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.1.tgz", + "integrity": "sha512-i7aT5HdiZIcd7quhzvwQ2oAuX7zPYrYfkrd1QFfs28Po/i0q6kas/oRrzGlDhAEyug+1UfUtkWdmoVlLJj5x9Q==", "cpu": [ "ia32" ], @@ -1796,9 +1796,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.0.tgz", - "integrity": "sha512-5hqO5S3PTEO2E5VjCePxv40gIgyS2KvO7E7/vvC/NbIW4SIRamkMr1hqj+5Y67fbBWv/bQLB6KelBQmXlyCjWA==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.1.tgz", + "integrity": "sha512-k3MVFD9Oq+laHkw2N2v7ILgoa9017ZMF/inTtHzyTVZjYs9cSH18sdyAf6spBAJIGwJ5UaC7et2ZH1WCdlhkMw==", "cpu": [ "x64" ], @@ -2346,9 +2346,9 @@ } }, "node_modules/@swc/core": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.10.11.tgz", - "integrity": "sha512-3zGU5y3S20cAwot9ZcsxVFNsSVaptG+dKdmAxORSE3EX7ixe1Xn5kUwLlgIsM4qrwTUWCJDLNhRS+2HLFivcDg==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.10.14.tgz", + "integrity": "sha512-WSrnE6JRnH20ZYjOOgSS4aOaPv9gxlkI2KRkN24kagbZnPZMnN8bZZyzw1rrLvwgpuRGv17Uz+hflosbR+SP6w==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -2364,16 +2364,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.10.11", - "@swc/core-darwin-x64": "1.10.11", - "@swc/core-linux-arm-gnueabihf": "1.10.11", - "@swc/core-linux-arm64-gnu": "1.10.11", - "@swc/core-linux-arm64-musl": "1.10.11", - "@swc/core-linux-x64-gnu": "1.10.11", - "@swc/core-linux-x64-musl": "1.10.11", - "@swc/core-win32-arm64-msvc": "1.10.11", - "@swc/core-win32-ia32-msvc": "1.10.11", - "@swc/core-win32-x64-msvc": "1.10.11" + "@swc/core-darwin-arm64": "1.10.14", + "@swc/core-darwin-x64": "1.10.14", + "@swc/core-linux-arm-gnueabihf": "1.10.14", + "@swc/core-linux-arm64-gnu": "1.10.14", + "@swc/core-linux-arm64-musl": "1.10.14", + "@swc/core-linux-x64-gnu": "1.10.14", + "@swc/core-linux-x64-musl": "1.10.14", + "@swc/core-win32-arm64-msvc": "1.10.14", + "@swc/core-win32-ia32-msvc": "1.10.14", + "@swc/core-win32-x64-msvc": "1.10.14" }, "peerDependencies": { "@swc/helpers": "*" @@ -2385,9 +2385,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.10.11.tgz", - "integrity": "sha512-ZpgEaNcx2e5D+Pd0yZGVbpSrEDOEubn7r2JXoNBf0O85lPjUm3HDzGRfLlV/MwxRPAkwm93eLP4l7gYnc50l3g==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.10.14.tgz", + "integrity": "sha512-Dh4VyrhDDb05tdRmqJ/MucOPMTnrB4pRJol18HVyLlqu1HOT5EzonUniNTCdQbUXjgdv5UVJSTE1lYTzrp+myA==", "cpu": [ "arm64" ], @@ -2402,9 +2402,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.10.11.tgz", - "integrity": "sha512-szObinnq2o7spXMDU5pdunmUeLrfV67Q77rV+DyojAiGJI1RSbEQotLOk+ONOLpoapwGUxOijFG4IuX1xiwQ2g==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.10.14.tgz", + "integrity": "sha512-KpzotL/I0O12RE3tF8NmQErINv0cQe/0mnN/Q50ESFzB5kU6bLgp2HMnnwDTm/XEZZRJCNe0oc9WJ5rKbAJFRQ==", "cpu": [ "x64" ], @@ -2419,9 +2419,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.10.11.tgz", - "integrity": "sha512-tVE8aXQwd8JUB9fOGLawFJa76nrpvp3dvErjozMmWSKWqtoeO7HV83aOrVtc8G66cj4Vq7FjTE9pOJeV1FbKRw==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.10.14.tgz", + "integrity": "sha512-20yRXZjMJVz1wp1TcscKiGTVXistG+saIaxOmxSNQia1Qun3hSWLL+u6+5kXbfYGr7R2N6kqSwtZbIfJI25r9Q==", "cpu": [ "arm" ], @@ -2436,9 +2436,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.10.11.tgz", - "integrity": "sha512-geFkENU5GMEKO7FqHOaw9HVlpQEW10nICoM6ubFc0hXBv8dwRXU4vQbh9s/isLSFRftw1m4jEEWixAnXSw8bxQ==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.10.14.tgz", + "integrity": "sha512-Gy7cGrNkiMfPxQyLGxdgXPwyWzNzbHuWycJFcoKBihxZKZIW8hkPBttkGivuLC+0qOgsV2/U+S7tlvAju7FtmQ==", "cpu": [ "arm64" ], @@ -2453,9 +2453,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.10.11.tgz", - "integrity": "sha512-2mMscXe/ivq8c4tO3eQSbQDFBvagMJGlalXCspn0DgDImLYTEnt/8KHMUMGVfh0gMJTZ9q4FlGLo7mlnbx99MQ==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.10.14.tgz", + "integrity": "sha512-+oYVqJvFw62InZ8PIy1rBACJPC2WTe4vbVb9kM1jJj2D7dKLm9acnnYIVIDsM5Wo7Uab8RvPHXVbs19IBurzuw==", "cpu": [ "arm64" ], @@ -2470,9 +2470,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.10.11.tgz", - "integrity": "sha512-eu2apgDbC4xwsigpl6LS+iyw6a3mL6kB4I+6PZMbFF2nIb1Dh7RGnu70Ai6mMn1o80fTmRSKsCT3CKMfVdeNFg==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.10.14.tgz", + "integrity": "sha512-OmEbVEKQFLQVHwo4EJl9osmlulURy46k232Opfpn/1ji0t2KcNCci3POsnfMuoZjLkGJv8vGNJdPQxX+CP+wSA==", "cpu": [ "x64" ], @@ -2487,9 +2487,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.10.11.tgz", - "integrity": "sha512-0n+wPWpDigwqRay4IL2JIvAqSKCXv6nKxPig9M7+epAlEQlqX+8Oq/Ap3yHtuhjNPb7HmnqNJLCXT1Wx+BZo0w==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.10.14.tgz", + "integrity": "sha512-OZW+Icm8DMPqHbhdxplkuG8qrNnPk5i7xJOZWYi1y5bTjgGFI4nEzrsmmeHKMdQTaWwsFrm3uK1rlyQ48MmXmg==", "cpu": [ "x64" ], @@ -2504,9 +2504,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.10.11.tgz", - "integrity": "sha512-7+bMSIoqcbXKosIVd314YjckDRPneA4OpG1cb3/GrkQTEDXmWT3pFBBlJf82hzJfw7b6lfv6rDVEFBX7/PJoLA==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.10.14.tgz", + "integrity": "sha512-sTvc+xrDQXy3HXZFtTEClY35Efvuc3D+busYm0+rb1+Thau4HLRY9WP+sOKeGwH9/16rzfzYEqD7Ds8A9ykrHw==", "cpu": [ "arm64" ], @@ -2521,9 +2521,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.10.11.tgz", - "integrity": "sha512-6hkLl4+3KjP/OFTryWxpW7YFN+w4R689TSPwiII4fFgsFNupyEmLWWakKfkGgV2JVA59L4Oi02elHy/O1sbgtw==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.10.14.tgz", + "integrity": "sha512-j2iQ4y9GWTKtES5eMU0sDsFdYni7IxME7ejFej25Tv3Fq4B+U9tgtYWlJwh1858nIWDXelHiKcSh/UICAyVMdQ==", "cpu": [ "ia32" ], @@ -2538,9 +2538,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.10.11.tgz", - "integrity": "sha512-kKNE2BGu/La2k2WFHovenqZvGQAHRIU+rd2/6a7D6EiQ6EyimtbhUqjCCZ+N1f5fIAnvM+sMdLiQJq4jdd/oOQ==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.10.14.tgz", + "integrity": "sha512-TYtWkUSMkjs0jGPeWdtWbex4B+DlQZmN/ySVLiPI+EltYCLEXsFMkVFq6aWn48dqFHggFK0UYfvDrJUR2c3Qxg==", "cpu": [ "x64" ], @@ -2572,12 +2572,12 @@ } }, "node_modules/@tanstack/react-virtual": { - "version": "3.11.3", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.11.3.tgz", - "integrity": "sha512-vCU+OTylXN3hdC8RKg68tPlBPjjxtzon7Ys46MgrSLE+JhSjSTPvoQifV6DQJeJmA8Q3KT6CphJbejupx85vFw==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.12.0.tgz", + "integrity": "sha512-6krceiPN07kpxXmU6m8AY7EL0X1gHLu8m3nJdh4phvktzVNxkQfBmSwnRUpoUjGQO1PAn8wSAhYaL8hY1cS1vw==", "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.11.3" + "@tanstack/virtual-core": "3.12.0" }, "funding": { "type": "github", @@ -2589,9 +2589,9 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.11.3", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.11.3.tgz", - "integrity": "sha512-v2mrNSnMwnPJtcVqNvV0c5roGCBqeogN8jDtgtuHCphdwBasOZ17x8UV8qpHUh+u0MLfX43c0uUHKje0s+Zb0w==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.12.0.tgz", + "integrity": "sha512-7mDINtua3v/pOnn6WUmuT9dPXYSO7WidFej7JzoAfqEOcbbpt/iZ1WPqd+eg+FnrL9nUJK8radqj4iAU51Zchg==", "license": "MIT", "funding": { "type": "github", @@ -2647,11 +2647,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/prop-types": { - "version": "15.7.12", - "dev": true, - "license": "MIT" - }, "node_modules/@types/ramda": { "version": "0.30.2", "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.30.2.tgz", @@ -2662,13 +2657,12 @@ } }, "node_modules/@types/react": { - "version": "18.3.18", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", - "integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==", + "version": "19.0.8", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.8.tgz", + "integrity": "sha512-9P/o1IGdfmQxrujGbIMDyYaaCykhLKc0NGCtYcECNUr9UAaDe4gwvV9bR6tvd5Br1SG0j+PBpbKr2UYY8CwqSw==", "dev": true, "license": "MIT", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.0.2" } }, @@ -2683,9 +2677,9 @@ } }, "node_modules/@types/swagger-ui-react": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@types/swagger-ui-react/-/swagger-ui-react-4.19.0.tgz", - "integrity": "sha512-uScp1xkLZJej0bt3/lO4U11ywWEBnI5CFCR0tqp+5Rvxl1Mj1v6VkGED0W70jJwqlBvbD+/a6bDiK8rjepCr8g==", + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@types/swagger-ui-react/-/swagger-ui-react-5.18.0.tgz", + "integrity": "sha512-c2M9adVG7t28t1pq19K9Jt20VLQf0P/fwJwnfcmsVVsdkwCWhRmbKDu+tIs0/NGwJ/7GY8lBx+iKZxuDI5gDbw==", "dev": true, "license": "MIT", "dependencies": { @@ -2710,21 +2704,21 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.22.0.tgz", - "integrity": "sha512-4Uta6REnz/xEJMvwf72wdUnC3rr4jAQf5jnTkeRQ9b6soxLxhDEbS/pfMPoJLDfFPNVRdryqWUIV/2GZzDJFZw==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.23.0.tgz", + "integrity": "sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/type-utils": "8.22.0", - "@typescript-eslint/utils": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "@typescript-eslint/scope-manager": "8.23.0", + "@typescript-eslint/type-utils": "8.23.0", + "@typescript-eslint/utils": "8.23.0", + "@typescript-eslint/visitor-keys": "8.23.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2740,16 +2734,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.22.0.tgz", - "integrity": "sha512-MqtmbdNEdoNxTPzpWiWnqNac54h8JDAmkWtJExBVVnSrSmi9z+sZUt0LfKqk9rjqmKOIeRhO4fHHJ1nQIjduIQ==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.23.0.tgz", + "integrity": "sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/typescript-estree": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "@typescript-eslint/scope-manager": "8.23.0", + "@typescript-eslint/types": "8.23.0", + "@typescript-eslint/typescript-estree": "8.23.0", + "@typescript-eslint/visitor-keys": "8.23.0", "debug": "^4.3.4" }, "engines": { @@ -2765,14 +2759,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.22.0.tgz", - "integrity": "sha512-/lwVV0UYgkj7wPSw0o8URy6YI64QmcOdwHuGuxWIYznO6d45ER0wXUbksr9pYdViAofpUCNJx/tAzNukgvaaiQ==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.23.0.tgz", + "integrity": "sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0" + "@typescript-eslint/types": "8.23.0", + "@typescript-eslint/visitor-keys": "8.23.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2783,16 +2777,16 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.22.0.tgz", - "integrity": "sha512-NzE3aB62fDEaGjaAYZE4LH7I1MUwHooQ98Byq0G0y3kkibPJQIXVUspzlFOmOfHhiDLwKzMlWxaNv+/qcZurJA==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.23.0.tgz", + "integrity": "sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.22.0", - "@typescript-eslint/utils": "8.22.0", + "@typescript-eslint/typescript-estree": "8.23.0", + "@typescript-eslint/utils": "8.23.0", "debug": "^4.3.4", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2807,9 +2801,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.22.0.tgz", - "integrity": "sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz", + "integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==", "dev": true, "license": "MIT", "engines": { @@ -2821,20 +2815,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.22.0.tgz", - "integrity": "sha512-SJX99NAS2ugGOzpyhMza/tX+zDwjvwAtQFLsBo3GQxiGcvaKlqGBkmZ+Y1IdiSi9h4Q0Lr5ey+Cp9CGWNY/F/w==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.23.0.tgz", + "integrity": "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "@typescript-eslint/types": "8.23.0", + "@typescript-eslint/visitor-keys": "8.23.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2848,16 +2842,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.22.0.tgz", - "integrity": "sha512-T8oc1MbF8L+Bk2msAvCUzjxVB2Z2f+vXYfcucE2wOmYs7ZUwco5Ep0fYZw8quNwOiw9K8GYVL+Kgc2pETNTLOg==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.23.0.tgz", + "integrity": "sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/typescript-estree": "8.22.0" + "@typescript-eslint/scope-manager": "8.23.0", + "@typescript-eslint/types": "8.23.0", + "@typescript-eslint/typescript-estree": "8.23.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2872,13 +2866,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.22.0.tgz", - "integrity": "sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz", + "integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", + "@typescript-eslint/types": "8.23.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -3652,9 +3646,9 @@ "license": "MIT" }, "node_modules/fastq": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", - "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", + "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", "dev": true, "license": "ISC", "dependencies": { @@ -3983,9 +3977,9 @@ } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4780,11 +4774,10 @@ } }, "node_modules/react": { - "version": "18.3.1", + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } @@ -5066,9 +5059,9 @@ } }, "node_modules/rollup": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.0.tgz", - "integrity": "sha512-JmrhfQR31Q4AuNBjjAX4s+a/Pu/Q8Q9iwjWBsjRH1q52SPFE2NqRMK6fUZKKnvKO6id+h7JIRf0oYsph53eATg==", + "version": "4.34.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.1.tgz", + "integrity": "sha512-iYZ/+PcdLYSGfH3S+dGahlW/RWmsqDhLgj1BT9DH/xXJ0ggZN7xkdP9wipPNjjNLczI+fmMLmTB9pye+d2r4GQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5082,25 +5075,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.32.0", - "@rollup/rollup-android-arm64": "4.32.0", - "@rollup/rollup-darwin-arm64": "4.32.0", - "@rollup/rollup-darwin-x64": "4.32.0", - "@rollup/rollup-freebsd-arm64": "4.32.0", - "@rollup/rollup-freebsd-x64": "4.32.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.32.0", - "@rollup/rollup-linux-arm-musleabihf": "4.32.0", - "@rollup/rollup-linux-arm64-gnu": "4.32.0", - "@rollup/rollup-linux-arm64-musl": "4.32.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.32.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.32.0", - "@rollup/rollup-linux-riscv64-gnu": "4.32.0", - "@rollup/rollup-linux-s390x-gnu": "4.32.0", - "@rollup/rollup-linux-x64-gnu": "4.32.0", - "@rollup/rollup-linux-x64-musl": "4.32.0", - "@rollup/rollup-win32-arm64-msvc": "4.32.0", - "@rollup/rollup-win32-ia32-msvc": "4.32.0", - "@rollup/rollup-win32-x64-msvc": "4.32.0", + "@rollup/rollup-android-arm-eabi": "4.34.1", + "@rollup/rollup-android-arm64": "4.34.1", + "@rollup/rollup-darwin-arm64": "4.34.1", + "@rollup/rollup-darwin-x64": "4.34.1", + "@rollup/rollup-freebsd-arm64": "4.34.1", + "@rollup/rollup-freebsd-x64": "4.34.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.1", + "@rollup/rollup-linux-arm-musleabihf": "4.34.1", + "@rollup/rollup-linux-arm64-gnu": "4.34.1", + "@rollup/rollup-linux-arm64-musl": "4.34.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.1", + "@rollup/rollup-linux-riscv64-gnu": "4.34.1", + "@rollup/rollup-linux-s390x-gnu": "4.34.1", + "@rollup/rollup-linux-x64-gnu": "4.34.1", + "@rollup/rollup-linux-x64-musl": "4.34.1", + "@rollup/rollup-win32-arm64-msvc": "4.34.1", + "@rollup/rollup-win32-ia32-msvc": "4.34.1", + "@rollup/rollup-win32-x64-msvc": "4.34.1", "fsevents": "~2.3.2" } }, @@ -5153,9 +5146,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -5323,9 +5316,9 @@ } }, "node_modules/swagger-ui-react": { - "version": "5.18.2", - "resolved": "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-5.18.2.tgz", - "integrity": "sha512-vpW7AmkRYdz578iq7C5WrPsg6reBgRzj5xL/fIYR6KTfvY3lvBchpzegFaqg09LWDoL3U2MZvIgOS/1Q9kSJ9g==", + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-5.18.3.tgz", + "integrity": "sha512-TlcIdQlcbdvRpUP3+B/J08ARM6cC29eMRrNxhTjP/MtYlbuGg6DWET7Is65YTlsk3TE6NhRYVgf3sdqcLooIBw==", "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.24.7", @@ -5357,7 +5350,7 @@ "reselect": "^5.1.1", "serialize-error": "^8.1.0", "sha.js": "^2.4.11", - "swagger-client": "^3.31.0", + "swagger-client": "^3.34.0", "url-parse": "^1.5.10", "xml": "=1.0.1", "xml-but-prettier": "^1.0.1", @@ -5418,9 +5411,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", - "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", "dev": true, "license": "MIT", "engines": { diff --git a/playground/package.json b/playground/package.json index f9c2390366..0faf945219 100644 --- a/playground/package.json +++ b/playground/package.json @@ -12,14 +12,14 @@ "dependencies": { "graphiql": "^3.8.3", "graphql": "^16.10.0", - "react": "^18.3.1", + "react": "^19.0.0", "react-dom": "^19.0.0", - "swagger-ui-react": "^5.18.2" + "swagger-ui-react": "^5.18.3" }, "devDependencies": { - "@types/react": "^18.3.12", + "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", - "@types/swagger-ui-react": "^4.19.0", + "@types/swagger-ui-react": "^5.18.0", "@typescript-eslint/eslint-plugin": "^8.20.0", "@typescript-eslint/parser": "^8.21.0", "@vitejs/plugin-react-swc": "^3.7.2", From a2b8971405e7aafb5c30bb786f071ee2032486b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 05:39:09 -0500 Subject: [PATCH 2/5] bot: Bump github.com/golang/glog from 1.2.3 to 1.2.4 (#3425) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [github.com/golang/glog](https://github.com/golang/glog) from 1.2.3 to 1.2.4.
Release notes

Sourced from github.com/golang/glog's releases.

v1.2.4

What's Changed

  • Fail if log file already exists by @​chressie in golang/glog#74:
    • glog: Don't try to create/rotate a given syncBuffer twice in the same second
    • glog: introduce createInDir function as in internal version
    • glog: have createInDir fail if the file already exists

Full Changelog: https://github.com/golang/glog/compare/v1.2.3...v1.2.4

Commits
  • a0e3c40 glog: have createInDir fail if the file already exists
  • 7139da2 glog: introduce createInDir function as in internal version
  • dd58629 glog: Don't try to create/rotate a given syncBuffer twice in the same second
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/golang/glog&package-manager=go_modules&previous-version=1.2.3&new-version=1.2.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/sourcenetwork/defradb/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c00e0582cd..f9bd6d33c7 100644 --- a/go.mod +++ b/go.mod @@ -173,7 +173,7 @@ require ( github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.2.3 // indirect + github.com/golang/glog v1.2.4 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.4 // indirect diff --git a/go.sum b/go.sum index 1bb4fd7e5d..fb03ef888d 100644 --- a/go.sum +++ b/go.sum @@ -610,8 +610,8 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.3 h1:oDTdz9f5VGVVNGu/Q7UXKWYsD0873HXLHdJUNBsSEKM= -github.com/golang/glog v1.2.3/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc= +github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= From 2443c8c1a406a4f45ec17ab9e61433722b773c16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 11:25:45 -0500 Subject: [PATCH 3/5] bot: Bump github.com/getkin/kin-openapi from 0.128.0 to 0.129.0 (#3418) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.128.0 to 0.129.0.
Release notes

Sourced from github.com/getkin/kin-openapi's releases.

v0.129.0

What's Changed

New Contributors

Full Changelog: https://github.com/getkin/kin-openapi/compare/v0.128.0...v0.129.0

Commits
  • cea0a13 openapi2conv: convert references in nested additionalProperties schemas (#1047)
  • f476f7b openapi3filter: validation of x-www-form-urlencoded with arbitrary nested a...
  • 325cecc openapi3filter: simplify ValidateRequest implementation (#1041)
  • 20441ea openapi3,openapi3filter: replace interface{} with any (#1040)
  • b82c647 openapi3: update date schema formats to not match months or days of '00' (#1042)
  • d819171 use forked yaml modules without "replace" (#1038)
  • 793b28d test: fix expected-actual parameters in require.Equal (#1035)
  • be48da5 openapi3: fix deprecation comments (#1034)
  • 02a0d6f openapi3: simplify by replacing math.Min with min (#1032)
  • e230c13 openapi2conv: convert schemaRef for additional props (#1030)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/getkin/kin-openapi&package-manager=go_modules&previous-version=0.128.0&new-version=0.129.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shahzad Lone --- go.mod | 7 ++++--- go.sum | 10 ++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index f9bd6d33c7..dd0e560e45 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/sourcenetwork/defradb -go 1.22.0 +go 1.22.5 toolchain go1.22.7 @@ -13,7 +13,7 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 github.com/evanphx/json-patch/v5 v5.9.0 github.com/fxamacker/cbor/v2 v2.7.0 - github.com/getkin/kin-openapi v0.128.0 + github.com/getkin/kin-openapi v0.129.0 github.com/go-chi/chi/v5 v5.2.0 github.com/go-chi/cors v1.2.1 github.com/go-errors/errors v1.5.1 @@ -220,7 +220,6 @@ require ( github.com/ignite/cli/v28 v28.4.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/invopop/yaml v0.3.1 // indirect github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/go-ipfs-delay v0.0.1 // indirect github.com/ipfs/go-ipfs-pq v0.0.3 // indirect @@ -284,6 +283,8 @@ require ( github.com/multiformats/go-multistream v0.6.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80 // indirect + github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect github.com/oklog/run v1.1.0 // indirect github.com/onsi/ginkgo/v2 v2.22.0 // indirect diff --git a/go.sum b/go.sum index fb03ef888d..dc19b0dcb1 100644 --- a/go.sum +++ b/go.sum @@ -518,8 +518,8 @@ github.com/gammazero/chanqueue v1.0.0 h1:FER/sMailGFA3DDvFooEkipAMU+3c9Bg3bheloP github.com/gammazero/chanqueue v1.0.0/go.mod h1:fMwpwEiuUgpab0sH4VHiVcEoji1pSi+EIzeG4TPeKPc= github.com/gammazero/deque v1.0.0 h1:LTmimT8H7bXkkCy6gZX7zNLtkbz4NdS2z8LZuor3j34= github.com/gammazero/deque v1.0.0/go.mod h1:iflpYvtGfM3U8S8j+sZEKIak3SAKYpA5/SQewgfXDKo= -github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.129.0 h1:QGYTNcmyP5X0AtFQ2Dkou9DGBJsUETeLH9rFrJXZh30= +github.com/getkin/kin-openapi v0.129.0/go.mod h1:gmWI+b/J45xqpyK5wJmRRZse5wefA5H0RDMK46kLUtI= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -858,8 +858,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= -github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= github.com/ipfs/boxo v0.27.2 h1:sGo4KdwBaMjdBjH08lqPJyt27Z4CO6sugne3ryX513s= @@ -1149,6 +1147,10 @@ github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= +github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80 h1:nZspmSkneBbtxU9TopEAE0CY+SBJLxO8LPUlw2vG4pU= +github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80/go.mod h1:7tFDb+Y51LcDpn26GccuUgQXUk6t0CXZsivKjyimYX8= +github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349 h1:t05Ww3DxZutOqbMN+7OIuqDwXbhl32HiZGpLy26BAPc= +github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a h1:dlRvE5fWabOchtH7znfiFCcOvmIYgOeAS5ifBXBlh9Q= github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= From 83e252330b83875de9f9162b8ecc42b143f46a47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 12:10:27 -0500 Subject: [PATCH 4/5] bot: Bump github.com/cometbft/cometbft from 0.38.12 to 0.38.17 (#3423) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ Rebasing might not happen immediately, so don't worry if this takes some time. Note: if you make any changes to this PR yourself, they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps [github.com/cometbft/cometbft](https://github.com/cometbft/cometbft) from 0.38.12 to 0.38.17.
Release notes

Sourced from github.com/cometbft/cometbft's releases.

v0.38.17

See the CHANGELOG for this release.

v0.38.16

See the CHANGELOG for this release.

v0.38.15

See the CHANGELOG for this release.

v0.38.13

See the CHANGELOG for this release.

Changelog

Sourced from github.com/cometbft/cometbft's changelog.

v0.38.17

February 3, 2025

This release fixes two security issues (ASA-2025-001, ASA-2025-002). Users are encouraged to upgrade as soon as possible.

BUG FIXES

  • [blocksync] Ban peer if it reports height lower than what was previously reported (ASA-2025-001)
  • [types] Check that Part.Index equals Part.Proof.Index (ASA-2025-001)

DEPENDENCIES

  • [go/runtime] Bump minimum Go version to 1.22.11 (#4891)

v0.38.16

December 20 2024

This release:

  • fixes a bug that caused a node produce errors caused by the sending of next PEX requests too soon. As a consequence of this incorrect behavior a node would be marked as BAD.
  • Adds a proper description of ExtendedVoteInfo and VoteInfo in the spec.

BUG FIXES

  • [mocks] Mockery v2.49.0 broke the mocks. We had to add a .mockery.yaml to properly handle this change. (#4521)

v0.38.15

November 6, 2024

This release supersedes v0.38.14, which mistakenly updated the Go version to 1.23, introducing an unintended breaking change. It sets the Go version back to 1.22.7 by reverting #4297.

The release includes the bug fixes, performance improvements, and importantly, the fix for the security vulnerability in the vote extensions (VE) validation logic that were part of v0.38.14. For more details, please refer to ASA-2024-011.

v0.38.14

November 6, 2024

... (truncated)

Commits
  • d03254d chore: v0.38.17 release (#4909)
  • d8b51b4 build(deps): Bump google.golang.org/grpc from 1.69.4 to 1.70.0 (#4901)
  • 415c0da Merge commit from fork
  • 2cebfde Merge commit from fork
  • 68f79b1 build(deps): Bump google.golang.org/protobuf from 1.36.3 to 1.36.4 (#4900)
  • 4f70ba6 build(deps): bump Go version to 1.22.11 (#4891)
  • 930813e build(deps): Bump docker/build-push-action from 6.12.0 to 6.13.0 (#4882)
  • c86f898 build(deps): Bump github.com/prometheus/common from 0.61.0 to 0.62.0 (#4865)
  • 807bd18 build(deps): Bump github.com/go-git/go-git/v5 from 5.13.0 to 5.13.2 (#4861)
  • 7d8440b build(deps): Bump golang.org/x/net from 0.33.0 to 0.34.0 (#4859)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/cometbft/cometbft&package-manager=go_modules&previous-version=0.38.12&new-version=0.38.17)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/sourcenetwork/defradb/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: Shahzad Lone --- go.mod | 25 +++++++++------------- go.sum | 66 +++++++++++++++++++--------------------------------------- 2 files changed, 31 insertions(+), 60 deletions(-) diff --git a/go.mod b/go.mod index dd0e560e45..2671639f76 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/sourcenetwork/defradb -go 1.22.5 - -toolchain go1.22.7 +go 1.22.11 require ( github.com/bits-and-blooms/bitset v1.20.0 @@ -103,11 +101,9 @@ require ( github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect - github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect github.com/bytecodealliance/wasmtime-go/v15 v15.0.0 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudflare/circl v1.3.7 // indirect @@ -118,8 +114,8 @@ require ( github.com/cockroachdb/pebble v1.1.2 // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect - github.com/cometbft/cometbft v0.38.12 // indirect - github.com/cometbft/cometbft-db v0.11.0 // indirect + github.com/cometbft/cometbft v0.38.17 // indirect + github.com/cometbft/cometbft-db v0.14.1 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect @@ -138,9 +134,8 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect - github.com/dgraph-io/badger/v2 v2.2007.4 // indirect + github.com/dgraph-io/badger/v4 v4.2.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect @@ -157,7 +152,7 @@ require ( github.com/gammazero/deque v1.0.0 // indirect github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-jose/go-jose/v3 v3.0.1-0.20221117193127-916db76e8214 // indirect - github.com/go-kit/kit v0.12.0 // indirect + github.com/go-kit/kit v0.13.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -269,7 +264,7 @@ require ( github.com/miekg/dns v1.1.62 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect - github.com/minio/highwayhash v1.0.2 // indirect + github.com/minio/highwayhash v1.0.3 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -293,7 +288,7 @@ require ( github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect + github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pion/datachannel v1.5.10 // indirect github.com/pion/dtls/v2 v2.2.12 // indirect github.com/pion/ice/v2 v2.3.37 // indirect @@ -330,7 +325,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -353,7 +348,7 @@ require ( github.com/x448/float16 v0.8.4 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect - go.etcd.io/bbolt v1.3.10 // indirect + go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect @@ -379,7 +374,7 @@ require ( google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect - google.golang.org/protobuf v1.36.3 // indirect + google.golang.org/protobuf v1.36.4 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index dc19b0dcb1..de9464689f 100644 --- a/go.sum +++ b/go.sum @@ -246,16 +246,14 @@ github.com/NathanBaulch/protoc-gen-cobra v1.2.1/go.mod h1:ZLPLEPQgV3jP3a7IEp+xxY github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= -github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/TBD54566975/ssi-sdk v0.0.4-alpha h1:GbZG0S3xeaWQi2suWw2VjGRhM/S2RrIsfiubxSHlViE= github.com/TBD54566975/ssi-sdk v0.0.4-alpha/go.mod h1:O4iANflxGCX0NbjHOhthq0X0il2ZYNMYlUnjEa0rsC0= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= -github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= +github.com/adlio/schema v1.3.6 h1:k1/zc2jNfeiZBA5aFTRy37jlBIuCkXCm0XmvpzCKI9I= +github.com/adlio/schema v1.3.6/go.mod h1:qkxwLgPBd1FgLRHYVCmQT/rrBr3JH38J9LjmVzWNudg= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -269,7 +267,6 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= @@ -304,8 +301,6 @@ github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurT github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= -github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= -github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/bufbuild/protocompile v0.6.0 h1:Uu7WiSQ6Yj9DbkdnOe7U4mNKp58y9WDMKDn28/ZlunY= @@ -371,17 +366,15 @@ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/cometbft/cometbft v0.38.12 h1:OWsLZN2KcSSFe8bet9xCn07VwhBnavPea3VyPnNq1bg= -github.com/cometbft/cometbft v0.38.12/go.mod h1:GPHp3/pehPqgX1930HmK1BpBLZPxB75v/dZg8Viwy+o= -github.com/cometbft/cometbft-db v0.11.0 h1:M3Lscmpogx5NTbb1EGyGDaFRdsoLWrUWimFEyf7jej8= -github.com/cometbft/cometbft-db v0.11.0/go.mod h1:GDPJAC/iFHNjmZZPN8V8C1yr/eyityhi2W1hz2MGKSc= +github.com/cometbft/cometbft v0.38.17 h1:FkrQNbAjiFqXydeAO81FUzriL4Bz0abYxN/eOHrQGOk= +github.com/cometbft/cometbft v0.38.17/go.mod h1:5l0SkgeLRXi6bBfQuevXjKqML1jjfJJlvI1Ulp02/o4= +github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ= +github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -414,7 +407,6 @@ github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5Rtn github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= @@ -442,11 +434,10 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3 github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= -github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= -github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= github.com/dgraph-io/badger/v3 v3.2011.1 h1:Hmyof0WMEF/QtutX5SQHzIMnJQxb/IrSzhjckV2SD6g= github.com/dgraph-io/badger/v3 v3.2011.1/go.mod h1:0rLLrQpKVQAL0or/lBLMQznhr6dWWX7h5AKnmnqx268= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs= +github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -544,8 +535,8 @@ github.com/go-jose/go-jose/v3 v3.0.1-0.20221117193127-916db76e8214/go.mod h1:RNk github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= -github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= -github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= +github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= +github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= @@ -951,7 +942,6 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= @@ -1036,7 +1026,6 @@ github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc= github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -1073,8 +1062,8 @@ github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKo github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= -github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= +github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= @@ -1206,7 +1195,6 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= @@ -1214,9 +1202,8 @@ github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= -github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 h1:jik8PHtAIsPlCRJjJzl4udgEf7hawInF9texMeO2jrU= -github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= @@ -1349,8 +1336,8 @@ github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWR github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= -github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= +github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= @@ -1417,23 +1404,17 @@ github.com/sourcenetwork/zanzi v0.3.1-0.20250119215940-5b0336b71030/go.mod h1:A/ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -1481,7 +1462,6 @@ github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EU github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= @@ -1514,7 +1494,6 @@ github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguH github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1528,8 +1507,8 @@ github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWp github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= -go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= +go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 h1:qxen9oVGzDdIRP6ejyAJc760RwW4SnVDiTYTzwnXuxo= +go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5/go.mod h1:eW0HG9/oHQhvRCvb1/pIXW4cOvtDqeQK+XSi3TnwaXY= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -1594,7 +1573,6 @@ golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -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-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1783,8 +1761,6 @@ golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1794,7 +1770,6 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1881,6 +1856,7 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2234,8 +2210,8 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= -google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= +google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From d6b003bf91a8e41e59d2273793af36b602c45ec5 Mon Sep 17 00:00:00 2001 From: Islam Aliev Date: Thu, 6 Feb 2025 11:57:47 +0100 Subject: [PATCH 5/5] feat: Enable secondary index for compound filter conditions (#3417) ## Relevant issue(s) Resolves #3299 ## Description Utilize secondary indexes even when compound filter conditions are present. For this to work new filter traversing utility function is introduced that can be configured to different needs. And not that indexes are exposed to more complex conditions they started to produce more false positive docs that weren't checked by the filter because the index fetcher was not part of the new fetcher chain. Make index fetcher implement new fetcher interface so that the documents it fetches can be checked against the scanner filter and permissions. Change behavior of connor to recognize if a field exists. It's need to distinguish if _ne filter returns false because 2 values are different or becuase the document doesn't have the field. Make fieldFetched explain metric count all fields fetched, not only fields that were requested. --- ...17-sec-index-compound-filter-conditions.md | 3 + internal/connor/all.go | 2 +- internal/connor/and.go | 2 +- internal/connor/any.go | 2 +- internal/connor/connor.go | 12 +- internal/connor/eq.go | 16 +- internal/connor/in.go | 2 +- internal/connor/key.go | 20 +- internal/connor/ne.go | 9 +- internal/connor/none.go | 2 +- internal/connor/not.go | 2 +- internal/connor/not_test.go | 4 +- internal/connor/or.go | 2 +- internal/db/collection_get.go | 5 +- internal/db/collection_index.go | 1 + internal/db/fetcher/document.go | 10 +- internal/db/fetcher/fetcher.go | 1 + internal/db/fetcher/indexer.go | 250 +++------ internal/db/fetcher/indexer_iterators.go | 272 +++++----- internal/db/fetcher/indexer_matchers.go | 173 ++++-- internal/db/fetcher/mocks/fetcher.go | 21 +- internal/db/fetcher/mocks/utils.go | 1 + internal/db/fetcher/versioned.go | 2 + internal/db/fetcher/wrapper.go | 75 +-- internal/db/indexed_docs_test.go | 7 + internal/lens/fetcher.go | 2 + internal/lens/registry.go | 4 +- internal/planner/filter/traverse.go | 140 +++++ internal/planner/filter/traverse_test.go | 494 ++++++++++++++++++ internal/planner/mapper/targetable.go | 19 +- internal/planner/planner.go | 15 +- internal/planner/scan.go | 38 +- internal/planner/select.go | 38 +- internal/planner/type_join.go | 140 +++-- .../explain/execute/create_test.go | 2 +- .../explain/execute/delete_test.go | 4 +- .../explain/execute/top_level_test.go | 4 +- .../explain/execute/type_join_test.go | 16 +- .../explain/execute/with_average_test.go | 6 +- .../explain/execute/with_count_test.go | 4 +- .../explain/execute/with_limit_test.go | 6 +- .../explain/execute/with_max_test.go | 6 +- .../explain/execute/with_min_test.go | 6 +- .../explain/execute/with_order_test.go | 10 +- .../explain/execute/with_sum_test.go | 6 +- tests/integration/index/array_test.go | 7 +- .../integration/index/json_composite_test.go | 6 +- tests/integration/index/json_test.go | 237 ++++++++- ...y_with_composite_index_only_filter_test.go | 46 +- .../query_with_index_combined_filter_test.go | 6 +- .../query_with_index_on_datetime_test.go | 2 +- .../query_with_index_only_filter_test.go | 381 +++++++++++++- .../index/query_with_relation_filter_test.go | 200 +++---- ...with_unique_composite_index_filter_test.go | 48 +- ...uery_with_unique_index_only_filter_test.go | 34 +- tests/integration/query/json/with_ne_test.go | 208 ++++++++ .../updates/add/field/with_index_test.go | 4 +- 57 files changed, 2276 insertions(+), 759 deletions(-) create mode 100644 docs/data_format_changes/i3417-sec-index-compound-filter-conditions.md create mode 100644 internal/planner/filter/traverse.go create mode 100644 internal/planner/filter/traverse_test.go diff --git a/docs/data_format_changes/i3417-sec-index-compound-filter-conditions.md b/docs/data_format_changes/i3417-sec-index-compound-filter-conditions.md new file mode 100644 index 0000000000..b236fa96b0 --- /dev/null +++ b/docs/data_format_changes/i3417-sec-index-compound-filter-conditions.md @@ -0,0 +1,3 @@ +# Enabled compound filter conditions for secondary indexes + +Changed the way fieldFetched are counted for explain directive diff --git a/internal/connor/all.go b/internal/connor/all.go index bf607b583b..12c2209bad 100644 --- a/internal/connor/all.go +++ b/internal/connor/all.go @@ -43,7 +43,7 @@ func all(condition, data any) (bool, error) { func allSlice[T any](condition any, data []T) (bool, error) { for _, c := range data { - m, err := eq(condition, c) + m, err := eq(condition, c, true) if err != nil { return false, err } else if !m { diff --git a/internal/connor/and.go b/internal/connor/and.go index d302617dc8..2cef6e23ce 100644 --- a/internal/connor/and.go +++ b/internal/connor/and.go @@ -8,7 +8,7 @@ func and(condition, data any) (bool, error) { switch cn := condition.(type) { case []any: for _, c := range cn { - if m, err := eq(c, data); err != nil { + if m, err := eq(c, data, true); err != nil { return false, err } else if !m { return false, nil diff --git a/internal/connor/any.go b/internal/connor/any.go index ecd16ce992..63f20499a3 100644 --- a/internal/connor/any.go +++ b/internal/connor/any.go @@ -43,7 +43,7 @@ func anyOp(condition, data any) (bool, error) { func anySlice[T any](condition any, data []T) (bool, error) { for _, c := range data { - m, err := eq(condition, c) + m, err := eq(condition, c, true) if err != nil { return false, err } else if m { diff --git a/internal/connor/connor.go b/internal/connor/connor.go index cdb49d2973..6260b32aa7 100644 --- a/internal/connor/connor.go +++ b/internal/connor/connor.go @@ -49,13 +49,17 @@ func IsOpSimple(op string) bool { // Match is the default method used in Connor to match some data to a // set of conditions. func Match(conditions map[FilterKey]any, data any) (bool, error) { - return eq(conditions, data) + return eq(conditions, data, true) } // matchWith can be used to specify the exact operator to use when performing // a match operation. This is primarily used when building custom operators or // if you wish to override the behavior of another operator. -func matchWith(op string, conditions, data any) (bool, error) { +// It also takes a propExists boolean to indicate if the property exists in the data. +// It's needed because the behavior of the operators can change if the property doesn't exist. +// For example, _ne operator should return true if the property doesn't exist. +// This can also be used in the future if we introduce operators line _has. +func matchWith(op string, conditions, data any, propExists bool) (bool, error) { switch op { case AndOp: return and(conditions, data) @@ -64,7 +68,7 @@ func matchWith(op string, conditions, data any) (bool, error) { case AllOp: return all(conditions, data) case EqualOp, AliasOp: - return eq(conditions, data) + return eq(conditions, data, propExists) case GreaterOrEqualOp: return ge(conditions, data) case GreaterOp: @@ -76,7 +80,7 @@ func matchWith(op string, conditions, data any) (bool, error) { case LesserOp: return lt(conditions, data) case NotEqualOp: - return ne(conditions, data) + return ne(conditions, data, propExists) case NotInOp: return nin(conditions, data) case OrOp: diff --git a/internal/connor/eq.go b/internal/connor/eq.go index 1caa43e81b..d6944573dd 100644 --- a/internal/connor/eq.go +++ b/internal/connor/eq.go @@ -11,9 +11,12 @@ import ( "github.com/sourcenetwork/defradb/internal/core" ) -// eq is an operator which performs object equality -// tests. -func eq(condition, data any) (bool, error) { +// eq is an operator which performs object equality tests. +// It also takes a propExists boolean to indicate if the property exists in the data. +// It's needed because the behavior of the operators can change if the property doesn't exist. +// For example, _ne operator should return true if the property doesn't exist. +// This can also be used in the future if we introduce operators line _has. +func eq(condition, data any, propExists bool) (bool, error) { switch arr := data.(type) { case []core.Doc: return anySlice(condition, arr) @@ -34,11 +37,12 @@ func eq(condition, data any) (bool, error) { switch cn := condition.(type) { case map[FilterKey]any: for prop, cond := range cn { - d, op, err := prop.PropertyAndOperator(data, EqualOp) + res, err := prop.PropertyAndOperator(data, EqualOp) if err != nil { return false, err } - m, err := matchWith(op, cond, d) + // If the property doesn't exist, we should pass it forward to nested operators. + m, err := matchWith(res.Operator, cond, res.Data, !res.MissProp && propExists) if err != nil { return false, err } @@ -85,7 +89,7 @@ func objectsEqual(condition map[string]any, data any) (bool, error) { return false, nil } for k, v := range d { - m, err := eq(condition[k], v) + m, err := eq(condition[k], v, true) if err != nil { return false, err } else if !m { diff --git a/internal/connor/in.go b/internal/connor/in.go index b9978b4bae..8a70826c74 100644 --- a/internal/connor/in.go +++ b/internal/connor/in.go @@ -8,7 +8,7 @@ func in(conditions, data any) (bool, error) { switch cn := conditions.(type) { case []any: for _, ce := range cn { - if m, err := eq(ce, data); err != nil { + if m, err := eq(ce, data, true); err != nil { return false, err } else if m { return true, nil diff --git a/internal/connor/key.go b/internal/connor/key.go index 98e8d747ea..45c9dcc291 100644 --- a/internal/connor/key.go +++ b/internal/connor/key.go @@ -1,13 +1,23 @@ package connor +// KeyResult represents the result of a filter key operation. +type KeyResult struct { + // Data is the data that should be used to filter the value matching the key. + Data any + // MissProp is true if the key is missing a property, otherwise false. + // It's relevant for object of dynamic type, like JSON. + MissProp bool + // Operator is the operator that should be used to filter the value matching the key. + // If the key does not have an operator the given defaultOp will be returned. + Operator string +} + // FilterKey represents a type that may be used as a map key // in a filter. type FilterKey interface { - // PropertyAndOperator returns the data and operator that should be used - // to filter the value matching this key. - // - // If the key does not have an operator the given defaultOp will be returned. - PropertyAndOperator(data any, defaultOp string) (any, string, error) + // PropertyAndOperator returns [KeyResult] that contains data and operator that should be + // used to filter the value matching this key. + PropertyAndOperator(data any, defaultOp string) (KeyResult, error) // Equal returns true if other is equal, otherwise returns false. Equal(other FilterKey) bool } diff --git a/internal/connor/ne.go b/internal/connor/ne.go index a677229d93..8751e00fd5 100644 --- a/internal/connor/ne.go +++ b/internal/connor/ne.go @@ -2,8 +2,13 @@ package connor // ne performs object inequality comparisons by inverting // the result of the EqualOperator for non-error cases. -func ne(conditions, data any) (bool, error) { - m, err := eq(conditions, data) +func ne(conditions, data any, propExists bool) (bool, error) { + // _ne operator should return false if the property does not exist. + if !propExists { + return false, nil + } + + m, err := eq(conditions, data, propExists) if err != nil { return false, err diff --git a/internal/connor/none.go b/internal/connor/none.go index 742d4dc977..b135b0da85 100644 --- a/internal/connor/none.go +++ b/internal/connor/none.go @@ -41,7 +41,7 @@ func none(condition, data any) (bool, error) { func noneSlice[T any](condition any, data []T) (bool, error) { for _, c := range data { - m, err := eq(condition, c) + m, err := eq(condition, c, true) if err != nil { return false, err } else if m { diff --git a/internal/connor/not.go b/internal/connor/not.go index 96fcd87ff8..49309ca415 100644 --- a/internal/connor/not.go +++ b/internal/connor/not.go @@ -3,7 +3,7 @@ package connor // not is an operator which performs object equality test // and returns the inverse of the result. func not(condition, data any) (bool, error) { - m, err := eq(condition, data) + m, err := eq(condition, data, true) if err != nil { return false, err } diff --git a/internal/connor/not_test.go b/internal/connor/not_test.go index 959ef04177..c5fabfcfe5 100644 --- a/internal/connor/not_test.go +++ b/internal/connor/not_test.go @@ -34,8 +34,8 @@ type operator struct { Operation string } -func (k *operator) PropertyAndOperator(data any, defaultOp string) (any, string, error) { - return data, k.Operation, nil +func (k *operator) PropertyAndOperator(data any, defaultOp string) (KeyResult, error) { + return KeyResult{Data: data, Operator: k.Operation}, nil } func (k *operator) Equal(other FilterKey) bool { diff --git a/internal/connor/or.go b/internal/connor/or.go index c15e27393f..c8555fdf48 100644 --- a/internal/connor/or.go +++ b/internal/connor/or.go @@ -8,7 +8,7 @@ func or(condition, data any) (bool, error) { switch cn := condition.(type) { case []any: for _, c := range cn { - if m, err := eq(c, data); err != nil { + if m, err := eq(c, data, true); err != nil { return false, err } else if m { return true, nil diff --git a/internal/db/collection_get.go b/internal/db/collection_get.go index c67f30e9b5..94806d47de 100644 --- a/internal/db/collection_get.go +++ b/internal/db/collection_get.go @@ -13,6 +13,8 @@ package db import ( "context" + "github.com/sourcenetwork/immutable" + "github.com/sourcenetwork/defradb/acp/identity" "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/internal/db/base" @@ -63,7 +65,8 @@ func (c *collection) get( // create a new document fetcher df := c.newFetcher() // initialize it with the primary index - err := df.Init(ctx, identity.FromContext(ctx), txn, c.db.acp, c, fields, nil, nil, showDeleted) + err := df.Init(ctx, identity.FromContext(ctx), txn, c.db.acp, immutable.Option[client.IndexDescription]{}, + c, fields, nil, nil, showDeleted) if err != nil { _ = df.Close() return nil, err diff --git a/internal/db/collection_index.go b/internal/db/collection_index.go index 7347ff3348..227942394c 100644 --- a/internal/db/collection_index.go +++ b/internal/db/collection_index.go @@ -311,6 +311,7 @@ func (c *collection) iterateAllDocs( identity.FromContext(ctx), txn, c.db.acp, + immutable.None[client.IndexDescription](), c, fields, nil, diff --git a/internal/db/fetcher/document.go b/internal/db/fetcher/document.go index f3b638e26e..7ec9a66f45 100644 --- a/internal/db/fetcher/document.go +++ b/internal/db/fetcher/document.go @@ -135,6 +135,9 @@ func (f *documentFetcher) GetFields() (immutable.Option[EncodedDocument], error) for { res, ok := f.kvResultsIter.NextSync() + if res.Error != nil { + return immutable.None[EncodedDocument](), res.Error + } if !ok { break } @@ -179,13 +182,16 @@ func (f *documentFetcher) appendKV(doc *encodedDocument, kv keyValue) error { return err } + // we count the fields fetched here instead of after checking if the field was requested + // because we need to count all fields fetched to see more accurate picture of the performance + // of the query + f.execInfo.FieldsFetched++ + fieldDesc, ok := f.fieldsByID[fieldID] if !ok { return nil } - f.execInfo.FieldsFetched++ - doc.properties[fieldDesc] = &encProperty{ Desc: fieldDesc, Raw: kv.Value, diff --git a/internal/db/fetcher/fetcher.go b/internal/db/fetcher/fetcher.go index 61c4ef5166..0b58a39d6c 100644 --- a/internal/db/fetcher/fetcher.go +++ b/internal/db/fetcher/fetcher.go @@ -56,6 +56,7 @@ type Fetcher interface { identity immutable.Option[acpIdentity.Identity], txn datastore.Txn, acp immutable.Option[acp.ACP], + index immutable.Option[client.IndexDescription], col client.Collection, fields []client.FieldDefinition, filter *mapper.Filter, diff --git a/internal/db/fetcher/indexer.go b/internal/db/fetcher/indexer.go index ec3c5dd4e9..414ebfbce9 100644 --- a/internal/db/fetcher/indexer.go +++ b/internal/db/fetcher/indexer.go @@ -12,68 +12,68 @@ package fetcher import ( "context" - "errors" "github.com/sourcenetwork/immutable" - "github.com/sourcenetwork/defradb/acp" - acpIdentity "github.com/sourcenetwork/defradb/acp/identity" "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/datastore" + "github.com/sourcenetwork/defradb/errors" "github.com/sourcenetwork/defradb/internal/core" "github.com/sourcenetwork/defradb/internal/db/base" "github.com/sourcenetwork/defradb/internal/keys" + "github.com/sourcenetwork/defradb/internal/planner/filter" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) -// IndexFetcher is a fetcher that fetches documents by index. +// indexFetcher is a fetcher that fetches documents by index. // It fetches only the indexed field and the rest of the fields are fetched by the internal fetcher. -type IndexFetcher struct { - docFetcher Fetcher - col client.Collection +type indexFetcher struct { + ctx context.Context txn datastore.Txn + col client.Collection indexFilter *mapper.Filter - doc *encodedDocument mapping *core.DocumentMapping indexedFields []client.FieldDefinition - docFields []client.FieldDefinition + fieldsByID map[uint32]client.FieldDefinition indexDesc client.IndexDescription indexIter indexIterator - execInfo ExecInfo + currentDocID immutable.Option[string] + execInfo *ExecInfo } -var _ Fetcher = (*IndexFetcher)(nil) +var _ fetcher = (*indexFetcher)(nil) -// NewIndexFetcher creates a new IndexFetcher. -func NewIndexFetcher( - docFetcher Fetcher, - indexDesc client.IndexDescription, - indexFilter *mapper.Filter, -) *IndexFetcher { - return &IndexFetcher{ - docFetcher: docFetcher, - indexDesc: indexDesc, - indexFilter: indexFilter, - } -} - -func (f *IndexFetcher) Init( +// newIndexFetcher creates a new IndexFetcher. +// It can return nil, if there is no efficient way to fetch indexes with given filter conditions. +func newIndexFetcher( ctx context.Context, - identity immutable.Option[acpIdentity.Identity], txn datastore.Txn, - acp immutable.Option[acp.ACP], + fieldsByID map[uint32]client.FieldDefinition, + indexDesc client.IndexDescription, + docFilter *mapper.Filter, col client.Collection, - fields []client.FieldDefinition, - filter *mapper.Filter, docMapper *core.DocumentMapping, - showDeleted bool, -) error { - f.resetState() + execInfo *ExecInfo, +) (*indexFetcher, error) { + f := &indexFetcher{ + ctx: ctx, + txn: txn, + col: col, + mapping: docMapper, + indexDesc: indexDesc, + fieldsByID: fieldsByID, + execInfo: execInfo, + } - f.col = col - f.doc = &encodedDocument{} - f.mapping = docMapper - f.txn = txn + fieldsToCopy := make([]mapper.Field, 0, len(indexDesc.Fields)) + for _, field := range indexDesc.Fields { + typeIndex := docMapper.FirstIndexOfName(field.Name) + indexField := mapper.Field{Index: typeIndex, Name: field.Name} + fieldsToCopy = append(fieldsToCopy, indexField) + } + for i := range fieldsToCopy { + f.indexFilter = filter.Merge(f.indexFilter, filter.CopyField(docFilter, fieldsToCopy[i])) + } for _, indexedField := range f.indexDesc.Fields { field, ok := f.col.Definition().GetFieldByName(indexedField.Name) @@ -82,158 +82,62 @@ func (f *IndexFetcher) Init( } } - f.docFields = make([]client.FieldDefinition, 0, len(fields)) -outer: - for i := range fields { - for j := range f.indexedFields { - // If the field is array, we want to keep it also for the document fetcher - // because the index only contains one array elements, not the whole array. - // The doc fetcher will fetch the whole array for us. - if fields[i].Name == f.indexedFields[j].Name && !fields[i].Kind.IsArray() { - continue outer - } - } - f.docFields = append(f.docFields, fields[i]) - } - iter, err := f.createIndexIterator() - if err != nil { - return err - } - f.indexIter = iter - - // if it turns out that we can't use the index, we need to fall back to the document fetcher - if f.indexIter == nil { - f.docFields = fields + if err != nil || iter == nil { + return nil, err } - if len(f.docFields) > 0 { - err = f.docFetcher.Init( - ctx, - identity, - f.txn, - acp, - f.col, - f.docFields, - filter, - f.mapping, - false, - ) - } - - return err + f.indexIter = iter + return f, iter.Init(ctx, txn.Datastore()) } -func (f *IndexFetcher) Start(ctx context.Context, prefixes ...keys.Walkable) error { - if f.indexIter == nil { - return f.docFetcher.Start(ctx, prefixes...) - } - return f.indexIter.Init(ctx, f.txn.Datastore()) -} +func (f *indexFetcher) NextDoc() (immutable.Option[string], error) { + f.currentDocID = immutable.None[string]() -func (f *IndexFetcher) FetchNext(ctx context.Context) (EncodedDocument, ExecInfo, error) { - if f.indexIter == nil { - return f.docFetcher.FetchNext(ctx) + res, err := f.indexIter.Next() + if err != nil || !res.foundKey { + return immutable.None[string](), err } - totalExecInfo := f.execInfo - defer func() { f.execInfo.Add(totalExecInfo) }() - f.execInfo.Reset() - for { - f.doc.Reset() - - res, err := f.indexIter.Next() - if err != nil { - return nil, ExecInfo{}, err - } - - if !res.foundKey { - return nil, f.execInfo, nil - } - - hasNilField := false - for i, indexedField := range f.indexedFields { - property := &encProperty{Desc: indexedField} - - field := res.key.Fields[i] - if field.Value.IsNil() { - hasNilField = true - } - - // Index will fetch only 1 array element. So we skip it here and let doc fetcher - // fetch the whole array. - if indexedField.Kind.IsArray() { - continue - } - - // We need to convert it to cbor bytes as this is what it will be encoded from on value retrieval. - // In the future we have to either get rid of CBOR or properly handle different encoding - // for properties in a single document. - fieldBytes, err := client.NewFieldValue(client.NONE_CRDT, field.Value).Bytes() - if err != nil { - return nil, ExecInfo{}, err - } - property.Raw = fieldBytes - - f.doc.properties[indexedField] = property - } - if f.indexDesc.Unique && !hasNilField { - f.doc.id = res.value - } else { - lastVal := res.key.Fields[len(res.key.Fields)-1].Value - if str, ok := lastVal.String(); ok { - f.doc.id = []byte(str) - } else if bytes, ok := lastVal.Bytes(); ok { - f.doc.id = bytes - } else { - return nil, ExecInfo{}, err - } - } + hasNilField := false + for i := range f.indexedFields { + hasNilField = hasNilField || res.key.Fields[i].Value.IsNil() + } - if len(f.docFields) > 0 { - targetKey := base.MakeDataStoreKeyWithCollectionAndDocID(f.col.Description(), string(f.doc.id)) - err := f.docFetcher.Start(ctx, targetKey) - if err != nil { - return nil, ExecInfo{}, err - } - encDoc, execInfo, err := f.docFetcher.FetchNext(ctx) - if err != nil { - return nil, ExecInfo{}, errors.Join(err, f.docFetcher.Close()) - } - err = f.docFetcher.Close() - if err != nil { - return nil, ExecInfo{}, err - } - f.execInfo.Add(execInfo) - if encDoc == nil { - continue - } - f.doc.MergeProperties(encDoc) + if f.indexDesc.Unique && !hasNilField { + f.currentDocID = immutable.Some(string(res.value)) + } else { + lastVal := res.key.Fields[len(res.key.Fields)-1].Value + if str, ok := lastVal.String(); ok { + f.currentDocID = immutable.Some(str) } else { - f.execInfo.DocsFetched++ + f.currentDocID = immutable.None[string]() } - return f.doc, f.execInfo, nil } + return f.currentDocID, nil } -func (f *IndexFetcher) Close() error { - if f.indexIter == nil { - return f.docFetcher.Close() +func (f *indexFetcher) GetFields() (immutable.Option[EncodedDocument], error) { + if !f.currentDocID.HasValue() { + return immutable.Option[EncodedDocument]{}, nil + } + prefix := base.MakeDataStoreKeyWithCollectionAndDocID(f.col.Description(), f.currentDocID.Value()) + prefixFetcher, err := newPrefixFetcher(f.ctx, f.txn, []keys.DataStoreKey{prefix}, f.col, + f.fieldsByID, client.Active, f.execInfo) + if err != nil { + return immutable.Option[EncodedDocument]{}, err + } + _, err = prefixFetcher.NextDoc() + if err != nil { + return immutable.Option[EncodedDocument]{}, err } - return f.indexIter.Close() + doc, err := prefixFetcher.GetFields() + return doc, errors.Join(err, prefixFetcher.Close()) } -// resetState resets the mutable state of this IndexFetcher, returning the state to how it -// was immediately after construction. -func (f *IndexFetcher) resetState() { - // WARNING: Do not reset properties set in the constructor! - - f.col = nil - f.txn = nil - f.doc = nil - f.mapping = nil - f.indexedFields = nil - f.docFields = nil - f.indexIter = nil - f.execInfo.Reset() +func (f *indexFetcher) Close() error { + if f.indexIter != nil { + return f.indexIter.Close() + } + return nil } diff --git a/internal/db/fetcher/indexer_iterators.go b/internal/db/fetcher/indexer_iterators.go index 3fba778344..39fcab006f 100644 --- a/internal/db/fetcher/indexer_iterators.go +++ b/internal/db/fetcher/indexer_iterators.go @@ -14,13 +14,13 @@ import ( "context" ds "github.com/ipfs/go-datastore" - "golang.org/x/exp/slices" "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/datastore" "github.com/sourcenetwork/defradb/errors" "github.com/sourcenetwork/defradb/internal/connor" "github.com/sourcenetwork/defradb/internal/keys" + "github.com/sourcenetwork/defradb/internal/planner/filter" "github.com/sourcenetwork/defradb/internal/planner/mapper" "github.com/ipfs/go-datastore/query" @@ -42,6 +42,7 @@ const ( compOpAny = "_any" compOpAll = "_all" compOpNone = "_none" + opNot = "_not" // it's just there for composite indexes. We construct a slice of value matchers with // every matcher being responsible for a corresponding field in the index to match. // For some fields there might not be any criteria to match. For examples if you have @@ -309,7 +310,7 @@ func (iter *memorizingIndexIterator) Close() error { // newPrefixIteratorFromConditions creates a new eqPrefixIndexIterator for fetching indexed data. // It can modify the input matchers slice. -func (f *IndexFetcher) newPrefixIteratorFromConditions( +func (f *indexFetcher) newPrefixIteratorFromConditions( fieldConditions []fieldFilterCond, matchers []valueMatcher, ) (*indexPrefixIterator, error) { @@ -339,11 +340,10 @@ func (f *IndexFetcher) newPrefixIteratorFromConditions( } key := f.newIndexDataStoreKeyWithValues(keyFieldValues) - - return f.newPrefixIterator(key, matchers, &f.execInfo), nil + return f.newPrefixIterator(key, matchers, f.execInfo), nil } -func (f *IndexFetcher) newPrefixIterator( +func (f *indexFetcher) newPrefixIterator( indexKey keys.IndexDataStoreKey, matchers []valueMatcher, execInfo *ExecInfo, @@ -359,7 +359,7 @@ func (f *IndexFetcher) newPrefixIterator( // newInIndexIterator creates a new inIndexIterator for fetching indexed data. // It can modify the input matchers slice. -func (f *IndexFetcher) newInIndexIterator( +func (f *indexFetcher) newInIndexIterator( fieldConditions []fieldFilterCond, matchers []valueMatcher, ) (*inIndexIterator, error) { @@ -382,28 +382,21 @@ func (f *IndexFetcher) newInIndexIterator( } key := f.newIndexDataStoreKeyWithValues(keyFieldValues) - - iter = &eqSingleIndexIterator{ - indexKey: key, - execInfo: &f.execInfo, - } + iter = &eqSingleIndexIterator{indexKey: key, execInfo: f.execInfo} } else { indexKey := f.newIndexDataStoreKey() indexKey.Fields = []keys.IndexedField{{Descending: f.indexDesc.Fields[0].Descending}} - iter = f.newPrefixIterator(indexKey, matchers, &f.execInfo) + iter = f.newPrefixIterator(indexKey, matchers, f.execInfo) } - return &inIndexIterator{ - indexIterator: iter, - inValues: inValues, - }, nil + return &inIndexIterator{indexIterator: iter, inValues: inValues}, nil } -func (f *IndexFetcher) newIndexDataStoreKey() keys.IndexDataStoreKey { +func (f *indexFetcher) newIndexDataStoreKey() keys.IndexDataStoreKey { return keys.IndexDataStoreKey{CollectionID: f.col.Description().RootID, IndexID: f.indexDesc.ID} } -func (f *IndexFetcher) newIndexDataStoreKeyWithValues(values []client.NormalValue) keys.IndexDataStoreKey { +func (f *indexFetcher) newIndexDataStoreKeyWithValues(values []client.NormalValue) keys.IndexDataStoreKey { fields := make([]keys.IndexedField, len(values)) for i := range values { fields[i].Value = values[i] @@ -412,13 +405,13 @@ func (f *IndexFetcher) newIndexDataStoreKeyWithValues(values []client.NormalValu return keys.NewIndexDataStoreKey(f.col.Description().RootID, f.indexDesc.ID, fields) } -func (f *IndexFetcher) createIndexIterator() (indexIterator, error) { +func (f *indexFetcher) createIndexIterator() (indexIterator, error) { fieldConditions, err := f.determineFieldFilterConditions() if err != nil { return nil, err } - // this can happen if a query contains an empty condition like User(filter: {name: {}}) + // fieldConditions might be empty if a query contains an empty condition like User(filter: {name: {}}) if len(fieldConditions) == 0 { return nil, nil } @@ -428,24 +421,6 @@ func (f *IndexFetcher) createIndexIterator() (indexIterator, error) { return nil, err } - hasArray := false - for i := range fieldConditions { - if len(fieldConditions[i].arrOp) > 0 { - hasArray = true - if fieldConditions[i].arrOp == compOpNone { - matchers[i] = &invertedMatcher{matcher: matchers[i]} - } - } - } - - hasJSON := false - for i := range fieldConditions { - if fieldConditions[i].kind == client.FieldKind_NILLABLE_JSON { - hasJSON = true - break - } - } - var iter indexIterator if fieldConditions[0].op == opEq { @@ -456,7 +431,7 @@ func (f *IndexFetcher) createIndexIterator() (indexIterator, error) { } key := f.newIndexDataStoreKeyWithValues(keyFieldValues) - iter = &eqSingleIndexIterator{indexKey: key, execInfo: &f.execInfo} + iter = &eqSingleIndexIterator{indexKey: key, execInfo: f.execInfo} } else { iter, err = f.newPrefixIteratorFromConditions(fieldConditions, matchers) } @@ -464,13 +439,14 @@ func (f *IndexFetcher) createIndexIterator() (indexIterator, error) { iter, err = f.newInIndexIterator(fieldConditions, matchers) } else { key := f.newIndexDataStoreKey() + // if the first field is JSON, we want to add the JSON path prefix to scope the search if fieldConditions[0].kind == client.FieldKind_NILLABLE_JSON { key.Fields = []keys.IndexedField{{ Descending: f.indexDesc.Fields[0].Descending, Value: client.NewNormalJSON(client.MakeVoidJSON(fieldConditions[0].jsonPath)), }} } - iter, err = f.newPrefixIterator(key, matchers, &f.execInfo), nil + iter, err = f.newPrefixIterator(key, matchers, f.execInfo), nil } if err != nil { @@ -481,13 +457,23 @@ func (f *IndexFetcher) createIndexIterator() (indexIterator, error) { return nil, NewErrInvalidFilterOperator(fieldConditions[0].op) } - if hasJSON || hasArray { + if doConditionsHaveArrayOrJSON(fieldConditions) { iter = &memorizingIndexIterator{inner: iter} } return iter, nil } +func doConditionsHaveArrayOrJSON(conditions []fieldFilterCond) bool { + hasArray := false + hasJSON := false + for i := range conditions { + hasJSON = hasJSON || conditions[i].kind == client.FieldKind_NILLABLE_JSON + hasArray = hasArray || conditions[i].kind.IsArray() + } + return hasArray || hasJSON +} + type fieldFilterCond struct { op string arrOp string @@ -499,106 +485,146 @@ type fieldFilterCond struct { // determineFieldFilterConditions determines the conditions and their corresponding operation // for each indexed field. // It returns a slice of fieldFilterCond, where each element corresponds to a field in the index. -func (f *IndexFetcher) determineFieldFilterConditions() ([]fieldFilterCond, error) { +func (f *indexFetcher) determineFieldFilterConditions() ([]fieldFilterCond, error) { result := make([]fieldFilterCond, 0, len(f.indexedFields)) - for i := range f.indexedFields { - fieldInd := f.mapping.FirstIndexOfName(f.indexedFields[i].Name) - found := false - // iterate through conditions and find the one that matches the current field - for filterKey, indexFilterCond := range f.indexFilter.Conditions { - propKey, ok := filterKey.(*mapper.PropertyIndex) - if !ok || fieldInd != propKey.Index { - continue - } + // we process first the conditions that match composite index fields starting from the first one + for i := range f.indexDesc.Fields { + indexedField := f.indexedFields[i] + fieldInd := f.mapping.FirstIndexOfName(indexedField.Name) + var err error + + filter.TraverseProperties( + f.indexFilter.Conditions, + func(prop *mapper.PropertyIndex, condMap map[connor.FilterKey]any) bool { + if fieldInd != prop.Index { + return true + } - found = true - - fieldDef := f.indexedFields[slices.IndexFunc(f.indexedFields, func(f client.FieldDefinition) bool { - return int(f.ID) == fieldInd - })] - - condMap := indexFilterCond.(map[connor.FilterKey]any) - - jsonPath := client.JSONPath{} - if fieldDef.Kind == client.FieldKind_NILLABLE_JSON { - jsonPathLoop: - for { - for key, filterVal := range condMap { - prop, ok := key.(*mapper.ObjectProperty) - if !ok { - // if filter contains an array condition, we need to append index 0 to the json path - // to limit the search only to array elements - op, ok := key.(*mapper.Operator) - if ok && isArrayCondition(op.Operation) { - if op.Operation == compOpNone { - // if the array condition is _none it doesn't make sense to use index because - // values picked by the index is random guessing. For example if we have doc1 - // with array of [3, 5, 1] and doc2 with [7, 4, 8] the index first fetches - // value 1 of doc1, let it go through the filter and then fetches value 3 of doc1 - // again, skips it (because it cached doc1 id) and fetches value 4 of doc2, and - // so on until it exhaust all prefixes in ascending order. - // It might be even less effective than just scanning all documents. - return nil, nil - } - jsonPath = jsonPath.AppendIndex(0) - } - break jsonPathLoop - } - jsonPath = jsonPath.AppendProperty(prop.Name) - condMap = filterVal.(map[connor.FilterKey]any) + var jsonPath client.JSONPath + condMap, jsonPath = getNestedOperatorConditionIfJSON(indexedField, condMap) + + for key, filterVal := range condMap { + op := key.(*mapper.Operator).Operation + + // if the array condition is _none it doesn't make sense to use index because + // values picked by the index is random guessing. For example if we have doc1 + // with array of [3, 5, 1] and doc2 with [7, 4, 8] the index first fetches + // value 1 of doc1, let it go through the filter and then fetches value 3 of doc1 + // again, skips it (because it cached doc1 id) and fetches value 4 of doc2, and + // so on until it exhaust all prefixes in ascending order. + // It might be even less effective than just scanning all documents. + if op == compOpNone { + return true } - } - } - for key, filterVal := range condMap { - cond := fieldFilterCond{ - op: key.(*mapper.Operator).Operation, - jsonPath: jsonPath, - kind: f.indexedFields[i].Kind, - } + cond, err := makeFieldFilterCondition(op, jsonPath, indexedField, filterVal) - var err error - if len(jsonPath) > 0 { - err = setJSONFilterCondition(&cond, filterVal, jsonPath) - } else if filterVal == nil { - cond.val, err = client.NewNormalNil(cond.kind) - } else if !f.indexedFields[i].Kind.IsArray() { - cond.val, err = client.NewNormalValue(filterVal) - } else { - subCondMap := filterVal.(map[connor.FilterKey]any) - for subKey, subVal := range subCondMap { - if subVal == nil { - arrKind := cond.kind.(client.ScalarArrayKind) - cond.val, err = client.NewNormalNil(arrKind.SubKind()) - } else { - cond.val, err = client.NewNormalValue(subVal) - } - cond.arrOp = cond.op - cond.op = subKey.(*mapper.Operator).Operation - // the sub condition is supposed to have only 1 record - break + if err != nil { + return false } - } - if err != nil { - return nil, err + result = append(result, cond) + break } - result = append(result, cond) - break - } - break + return false + }, + // if the filter contains _not operator, we ignore the entire branch because in this + // case index will do more harm. For example if we have _not: {_eq: 5} and the index + // fetches value 5, it will skip all documents with value 5, but we need to return them. + opNot, + ) + + // if after traversing the filter for the first field we didn't find any condition that can + // be used with the index, we return nil indicating that the index can't be used. + if len(result) == 0 { + return nil, err } - if !found { + + // if traversing for the current (not first) field of the composite index didn't find any + // condition, we add a dummy that will match any value for this field. + if len(result) == i { result = append(result, fieldFilterCond{ op: opAny, val: client.NormalVoid{}, - kind: f.indexedFields[i].Kind, + kind: indexedField.Kind, }) } } return result, nil } +// makeFieldFilterCondition creates a fieldFilterCond based on the given operator and filter value on +// the given indexed field. +// If jsonPath is not empty, it means that the indexed field is a JSON field and the filter value +// should be treated as a JSON value. +func makeFieldFilterCondition( + op string, + jsonPath client.JSONPath, + indexedField client.FieldDefinition, + filterVal any, +) (fieldFilterCond, error) { + cond := fieldFilterCond{ + op: op, + jsonPath: jsonPath, + kind: indexedField.Kind, + } + + var err error + if len(jsonPath) > 0 { + err = setJSONFilterCondition(&cond, filterVal, jsonPath) + } else if filterVal == nil { + cond.val, err = client.NewNormalNil(cond.kind) + } else if !indexedField.Kind.IsArray() { + cond.val, err = client.NewNormalValue(filterVal) + } else { + subCondMap := filterVal.(map[connor.FilterKey]any) + for subKey, subVal := range subCondMap { + if subVal == nil { + arrKind := cond.kind.(client.ScalarArrayKind) + cond.val, err = client.NewNormalNil(arrKind.SubKind()) + } else { + cond.val, err = client.NewNormalValue(subVal) + } + cond.arrOp = cond.op + cond.op = subKey.(*mapper.Operator).Operation + // the sub condition is supposed to have only 1 record + break + } + } + return cond, err +} + +// getNestedOperatorConditionIfJSON traverses the filter map if the indexed field is JSON to find the +// nested operator condition and returns it along with the JSON path to the nested field. +// If the indexed field is not JSON, it returns the original condition map. +func getNestedOperatorConditionIfJSON( + indexedField client.FieldDefinition, + condMap map[connor.FilterKey]any, +) (map[connor.FilterKey]any, client.JSONPath) { + if indexedField.Kind != client.FieldKind_NILLABLE_JSON { + return condMap, client.JSONPath{} + } + var jsonPath client.JSONPath + for { + for key, filterVal := range condMap { + prop, ok := key.(*mapper.ObjectProperty) + if !ok { + // if filter contains an array condition, we need to append index 0 to the json path + // to limit the search only to array elements + op, ok := key.(*mapper.Operator) + if ok && isArrayCondition(op.Operation) { + jsonPath = jsonPath.AppendIndex(0) + } + return condMap, jsonPath + } + jsonPath = jsonPath.AppendProperty(prop.Name) + // if key is ObjectProperty it's safe to cast filterVal to map[connor.FilterKey]any + // containing either another nested ObjectProperty or Operator + condMap = filterVal.(map[connor.FilterKey]any) + } + } +} + // setJSONFilterCondition sets up the given condition struct based on the filter value and JSON path so that // it can be used to fetch the indexed data. func setJSONFilterCondition(cond *fieldFilterCond, filterVal any, jsonPath client.JSONPath) error { diff --git a/internal/db/fetcher/indexer_matchers.go b/internal/db/fetcher/indexer_matchers.go index 05214af2c1..987e7687e4 100644 --- a/internal/db/fetcher/indexer_matchers.go +++ b/internal/db/fetcher/indexer_matchers.go @@ -147,6 +147,28 @@ func (m *nilMatcher) Match(value client.NormalValue) (bool, error) { return value.IsNil() == m.matchNil, nil } +// compositeMatcher checks if the value satisfies any of the matchers +type compositeMatcher struct { + matchers []valueMatcher +} + +func newCompositeMatcher(matchers ...valueMatcher) *compositeMatcher { + return &compositeMatcher{matchers: matchers} +} + +func (m *compositeMatcher) Match(value client.NormalValue) (bool, error) { + for i := range m.matchers { + res, err := m.matchers[i].Match(value) + if err != nil { + return false, err + } + if res { + return true, nil + } + } + return false, nil +} + // checks if the index value is or is not in the given array type indexInArrayMatcher struct { inValues []client.NormalValue @@ -241,26 +263,13 @@ type anyMatcher struct{} func (m *anyMatcher) Match(client.NormalValue) (bool, error) { return true, nil } -// invertedMatcher inverts the result of the inner matcher. -type invertedMatcher struct { - matcher valueMatcher -} - -func (m *invertedMatcher) Match(val client.NormalValue) (bool, error) { - res, err := m.matcher.Match(val) - if err != nil { - return false, err - } - return !res, nil -} - -type jsonComparableMatcher[T comparable] struct { +type jsonComparingMatcher[T comparable] struct { value T getValueFunc func(client.JSON) (T, bool) evalFunc func(T, T) bool } -func (m *jsonComparableMatcher[T]) Match(value client.NormalValue) (bool, error) { +func (m *jsonComparingMatcher[T]) Match(value client.NormalValue) (bool, error) { if jsonVal, ok := value.JSON(); ok { if val, ok := m.getValueFunc(jsonVal); ok { return m.evalFunc(val, m.value), nil @@ -270,6 +279,20 @@ func (m *jsonComparableMatcher[T]) Match(value client.NormalValue) (bool, error) return false, NewErrUnexpectedTypeValue[float64](value) } +// jsonTypeMatcher checks if the value is of the expected type +type jsonTypeMatcher[T comparable] struct { + getValueFunc func(client.JSON) (T, bool) + shouldMatch bool +} + +func (m *jsonTypeMatcher[T]) Match(value client.NormalValue) (bool, error) { + if jsonVal, ok := value.JSON(); ok { + _, ok := m.getValueFunc(jsonVal) + return ok == m.shouldMatch, nil + } + return false, NewErrUnexpectedTypeValue[float64](value) +} + type jsonBoolMatcher struct { value bool isEq bool @@ -287,7 +310,6 @@ func (m *jsonBoolMatcher) Match(value client.NormalValue) (bool, error) { } type jsonNullMatcher struct { - // TODO: _ne null is not handled yet matchNull bool } @@ -303,51 +325,13 @@ func createValueMatcher(condition *fieldFilterCond) (valueMatcher, error) { return &anyMatcher{}, nil } - // TODO: test json null if condition.val.IsNil() { return &nilMatcher{matchNil: condition.op == opEq}, nil } switch condition.op { case opEq, opGt, opGe, opLt, opLe, opNe: - if v, ok := condition.val.Int(); ok { - return &intMatcher{value: v, evalFunc: getCompareValsFunc[int64](condition.op)}, nil - } - if v, ok := condition.val.Float(); ok { - return &floatMatcher{value: v, evalFunc: getCompareValsFunc[float64](condition.op)}, nil - } - if v, ok := condition.val.String(); ok { - return &stringMatcher{value: v, evalFunc: getCompareValsFunc[string](condition.op)}, nil - } - if v, ok := condition.val.Time(); ok { - return &timeMatcher{value: v, op: condition.op}, nil - } - if v, ok := condition.val.Bool(); ok { - return &boolMatcher{value: v, isEq: condition.op == opEq}, nil - } - if v, ok := condition.val.JSON(); ok { - if jsonVal, ok := v.Number(); ok { - return &jsonComparableMatcher[float64]{ - value: jsonVal, - getValueFunc: func(j client.JSON) (float64, bool) { return j.Number() }, - evalFunc: getCompareValsFunc[float64](condition.op), - }, nil - } - if jsonVal, ok := v.String(); ok { - return &jsonComparableMatcher[string]{ - value: jsonVal, - getValueFunc: func(j client.JSON) (string, bool) { return j.String() }, - evalFunc: getCompareValsFunc[string](condition.op), - }, nil - } - if jsonVal, ok := v.Bool(); ok { - // TODO: test bool not equal - return &jsonBoolMatcher{value: jsonVal, isEq: condition.op == opEq}, nil - } - if v.IsNull() { - return &jsonNullMatcher{matchNull: condition.op == opEq}, nil - } - } + return createComparingMatcher(condition), nil case opIn, opNin: inVals, err := client.ToArrayOfNormalValues(condition.val) if err != nil { @@ -369,6 +353,85 @@ func createValueMatcher(condition *fieldFilterCond) (valueMatcher, error) { return nil, NewErrInvalidFilterOperator(condition.op) } +func createComparingMatcher(condition *fieldFilterCond) valueMatcher { + // JSON type needs a special handling if the op is _ne, because _ne should check also + // difference of types + if v, ok := condition.val.JSON(); ok { + // we have a separate branch for null matcher because default matching behavior + // is what we need: for filter `_ne: null` it will match all non-null values + if v.IsNull() { + return &jsonNullMatcher{matchNull: condition.op == opEq} + } + + if condition.op != opNe { + return createJSONComparingMatcher(v, condition.op) + } + + // _ne filter on JSON fields should also accept values of different types + var typeMatcher valueMatcher + if _, ok := v.Number(); ok { + typeMatcher = &jsonTypeMatcher[float64]{ + getValueFunc: func(j client.JSON) (float64, bool) { return j.Number() }, + } + } else if _, ok := v.String(); ok { + typeMatcher = &jsonTypeMatcher[string]{ + getValueFunc: func(j client.JSON) (string, bool) { return j.String() }, + } + } else if _, ok := v.Bool(); ok { + typeMatcher = &jsonTypeMatcher[bool]{ + getValueFunc: func(j client.JSON) (bool, bool) { return j.Bool() }, + } + } + return newCompositeMatcher(typeMatcher, createJSONComparingMatcher(v, condition.op)) + } + + matcher := createScalarComparingMatcher(condition) + + // for _ne filter on regular (non-JSON) fields the index should also accept nil values + // there won't be `_ne: null` because nil check is done before this function is called + if condition.op == opNe { + matcher = newCompositeMatcher(&nilMatcher{matchNil: true}, matcher) + } + + return matcher +} + +// createJSONComparingMatcher creates a matcher for JSON values +func createJSONComparingMatcher(val client.JSON, op string) valueMatcher { + if jsonVal, ok := val.Number(); ok { + return &jsonComparingMatcher[float64]{ + value: jsonVal, + getValueFunc: func(j client.JSON) (float64, bool) { return j.Number() }, + evalFunc: getCompareValsFunc[float64](op), + } + } else if jsonVal, ok := val.String(); ok { + return &jsonComparingMatcher[string]{ + value: jsonVal, + getValueFunc: func(j client.JSON) (string, bool) { return j.String() }, + evalFunc: getCompareValsFunc[string](op), + } + } else if jsonVal, ok := val.Bool(); ok { + return &jsonBoolMatcher{value: jsonVal, isEq: op == opEq} + } + return nil +} + +// createScalarComparingMatcher creates a matcher for scalar values (int, float, string, time, bool) +func createScalarComparingMatcher(condition *fieldFilterCond) valueMatcher { + if v, ok := condition.val.Int(); ok { + return &intMatcher{value: v, evalFunc: getCompareValsFunc[int64](condition.op)} + } else if v, ok := condition.val.Float(); ok { + return &floatMatcher{value: v, evalFunc: getCompareValsFunc[float64](condition.op)} + } else if v, ok := condition.val.String(); ok { + return &stringMatcher{value: v, evalFunc: getCompareValsFunc[string](condition.op)} + } else if v, ok := condition.val.Time(); ok { + return &timeMatcher{value: v, op: condition.op} + } else if v, ok := condition.val.Bool(); ok { + return &boolMatcher{value: v, isEq: condition.op == opEq} + } + return nil +} + func extractStringFromNormalValue(val client.NormalValue) (string, error) { strVal, ok := val.String() if !ok { diff --git a/internal/db/fetcher/mocks/fetcher.go b/internal/db/fetcher/mocks/fetcher.go index 723403723f..5306b484f9 100644 --- a/internal/db/fetcher/mocks/fetcher.go +++ b/internal/db/fetcher/mocks/fetcher.go @@ -148,17 +148,17 @@ func (_c *Fetcher_FetchNext_Call) RunAndReturn(run func(context.Context) (fetche return _c } -// Init provides a mock function with given fields: ctx, _a1, txn, _a3, col, fields, filter, docmapper, showDeleted -func (_m *Fetcher) Init(ctx context.Context, _a1 immutable.Option[identity.Identity], txn datastore.Txn, _a3 immutable.Option[acp.ACP], col client.Collection, fields []client.FieldDefinition, filter *mapper.Filter, docmapper *core.DocumentMapping, showDeleted bool) error { - ret := _m.Called(ctx, _a1, txn, _a3, col, fields, filter, docmapper, showDeleted) +// Init provides a mock function with given fields: ctx, _a1, txn, _a3, index, col, fields, filter, docmapper, showDeleted +func (_m *Fetcher) Init(ctx context.Context, _a1 immutable.Option[identity.Identity], txn datastore.Txn, _a3 immutable.Option[acp.ACP], index immutable.Option[client.IndexDescription], col client.Collection, fields []client.FieldDefinition, filter *mapper.Filter, docmapper *core.DocumentMapping, showDeleted bool) error { + ret := _m.Called(ctx, _a1, txn, _a3, index, col, fields, filter, docmapper, showDeleted) if len(ret) == 0 { panic("no return value specified for Init") } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, immutable.Option[identity.Identity], datastore.Txn, immutable.Option[acp.ACP], client.Collection, []client.FieldDefinition, *mapper.Filter, *core.DocumentMapping, bool) error); ok { - r0 = rf(ctx, _a1, txn, _a3, col, fields, filter, docmapper, showDeleted) + if rf, ok := ret.Get(0).(func(context.Context, immutable.Option[identity.Identity], datastore.Txn, immutable.Option[acp.ACP], immutable.Option[client.IndexDescription], client.Collection, []client.FieldDefinition, *mapper.Filter, *core.DocumentMapping, bool) error); ok { + r0 = rf(ctx, _a1, txn, _a3, index, col, fields, filter, docmapper, showDeleted) } else { r0 = ret.Error(0) } @@ -176,18 +176,19 @@ type Fetcher_Init_Call struct { // - _a1 immutable.Option[identity.Identity] // - txn datastore.Txn // - _a3 immutable.Option[acp.ACP] +// - index immutable.Option[client.IndexDescription] // - col client.Collection // - fields []client.FieldDefinition // - filter *mapper.Filter // - docmapper *core.DocumentMapping // - showDeleted bool -func (_e *Fetcher_Expecter) Init(ctx interface{}, _a1 interface{}, txn interface{}, _a3 interface{}, col interface{}, fields interface{}, filter interface{}, docmapper interface{}, showDeleted interface{}) *Fetcher_Init_Call { - return &Fetcher_Init_Call{Call: _e.mock.On("Init", ctx, _a1, txn, _a3, col, fields, filter, docmapper, showDeleted)} +func (_e *Fetcher_Expecter) Init(ctx interface{}, _a1 interface{}, txn interface{}, _a3 interface{}, index interface{}, col interface{}, fields interface{}, filter interface{}, docmapper interface{}, showDeleted interface{}) *Fetcher_Init_Call { + return &Fetcher_Init_Call{Call: _e.mock.On("Init", ctx, _a1, txn, _a3, index, col, fields, filter, docmapper, showDeleted)} } -func (_c *Fetcher_Init_Call) Run(run func(ctx context.Context, _a1 immutable.Option[identity.Identity], txn datastore.Txn, _a3 immutable.Option[acp.ACP], col client.Collection, fields []client.FieldDefinition, filter *mapper.Filter, docmapper *core.DocumentMapping, showDeleted bool)) *Fetcher_Init_Call { +func (_c *Fetcher_Init_Call) Run(run func(ctx context.Context, _a1 immutable.Option[identity.Identity], txn datastore.Txn, _a3 immutable.Option[acp.ACP], index immutable.Option[client.IndexDescription], col client.Collection, fields []client.FieldDefinition, filter *mapper.Filter, docmapper *core.DocumentMapping, showDeleted bool)) *Fetcher_Init_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(immutable.Option[identity.Identity]), args[2].(datastore.Txn), args[3].(immutable.Option[acp.ACP]), args[4].(client.Collection), args[5].([]client.FieldDefinition), args[6].(*mapper.Filter), args[7].(*core.DocumentMapping), args[8].(bool)) + run(args[0].(context.Context), args[1].(immutable.Option[identity.Identity]), args[2].(datastore.Txn), args[3].(immutable.Option[acp.ACP]), args[4].(immutable.Option[client.IndexDescription]), args[5].(client.Collection), args[6].([]client.FieldDefinition), args[7].(*mapper.Filter), args[8].(*core.DocumentMapping), args[9].(bool)) }) return _c } @@ -197,7 +198,7 @@ func (_c *Fetcher_Init_Call) Return(_a0 error) *Fetcher_Init_Call { return _c } -func (_c *Fetcher_Init_Call) RunAndReturn(run func(context.Context, immutable.Option[identity.Identity], datastore.Txn, immutable.Option[acp.ACP], client.Collection, []client.FieldDefinition, *mapper.Filter, *core.DocumentMapping, bool) error) *Fetcher_Init_Call { +func (_c *Fetcher_Init_Call) RunAndReturn(run func(context.Context, immutable.Option[identity.Identity], datastore.Txn, immutable.Option[acp.ACP], immutable.Option[client.IndexDescription], client.Collection, []client.FieldDefinition, *mapper.Filter, *core.DocumentMapping, bool) error) *Fetcher_Init_Call { _c.Call.Return(run) return _c } diff --git a/internal/db/fetcher/mocks/utils.go b/internal/db/fetcher/mocks/utils.go index d12f4fdd98..524c46fc9e 100644 --- a/internal/db/fetcher/mocks/utils.go +++ b/internal/db/fetcher/mocks/utils.go @@ -28,6 +28,7 @@ func NewStubbedFetcher(t *testing.T) *Fetcher { mock.Anything, mock.Anything, mock.Anything, + mock.Anything, ).Maybe().Return(nil) f.EXPECT().Start(mock.Anything, mock.Anything).Maybe().Return(nil) f.EXPECT().FetchNext(mock.Anything).Maybe().Return(nil, nil) diff --git a/internal/db/fetcher/versioned.go b/internal/db/fetcher/versioned.go index de829514ba..4fdb016b87 100644 --- a/internal/db/fetcher/versioned.go +++ b/internal/db/fetcher/versioned.go @@ -102,6 +102,7 @@ func (vf *VersionedFetcher) Init( identity immutable.Option[acpIdentity.Identity], txn datastore.Txn, acp immutable.Option[acp.ACP], + index immutable.Option[client.IndexDescription], col client.Collection, fields []client.FieldDefinition, filter *mapper.Filter, @@ -136,6 +137,7 @@ func (vf *VersionedFetcher) Init( identity, vf.store, acp, + index, col, fields, filter, diff --git a/internal/db/fetcher/wrapper.go b/internal/db/fetcher/wrapper.go index 6b55f86a1f..845ecf68ce 100644 --- a/internal/db/fetcher/wrapper.go +++ b/internal/db/fetcher/wrapper.go @@ -29,13 +29,14 @@ import ( // and the newer [fetcher] interface. type wrappingFetcher struct { fetcher fetcher - execInfo *ExecInfo + execInfo ExecInfo - // The below properties are only held in state in order to temporarily adhear to the [Fetcher] + // The below properties are only held in state in order to temporarily adhere to the [Fetcher] // interface. They can be remove from state once the [Fetcher] interface is cleaned up. identity immutable.Option[acpIdentity.Identity] txn datastore.Txn acp immutable.Option[acp.ACP] + index immutable.Option[client.IndexDescription] col client.Collection fields []client.FieldDefinition filter *mapper.Filter @@ -54,6 +55,7 @@ func (f *wrappingFetcher) Init( identity immutable.Option[acpIdentity.Identity], txn datastore.Txn, acp immutable.Option[acp.ACP], + index immutable.Option[client.IndexDescription], col client.Collection, fields []client.FieldDefinition, filter *mapper.Filter, @@ -63,6 +65,7 @@ func (f *wrappingFetcher) Init( f.identity = identity f.txn = txn f.acp = acp + f.index = index f.col = col f.fields = fields f.filter = filter @@ -90,7 +93,7 @@ func (f *wrappingFetcher) Start(ctx context.Context, prefixes ...keys.Walkable) if f.filter != nil && len(f.fields) > 0 { conditions := f.filter.ToMap(f.docMapper) - parsedfilterFields, err := parser.ParseFilterFieldsForDescription(conditions, f.col.Definition()) + parsedFilterFields, err := parser.ParseFilterFieldsForDescription(conditions, f.col.Definition()) if err != nil { return err } @@ -100,7 +103,7 @@ func (f *wrappingFetcher) Start(ctx context.Context, prefixes ...keys.Walkable) existingFields[field.ID] = struct{}{} } - for _, field := range parsedfilterFields { + for _, field := range parsedFilterFields { if _, ok := existingFields[field.ID]; !ok { f.fields = append(f.fields, field) } @@ -117,17 +120,31 @@ func (f *wrappingFetcher) Start(ctx context.Context, prefixes ...keys.Walkable) fieldsByID[uint32(field.ID)] = field } - var execInfo ExecInfo - f.execInfo = &execInfo + f.execInfo.Reset() var top fetcher - top, err = newPrefixFetcher(ctx, f.txn, dsPrefixes, f.col, fieldsByID, client.Active, &execInfo) - if err != nil { - return err + if f.index.HasValue() { + indexFetcher, err := newIndexFetcher(ctx, f.txn, fieldsByID, f.index.Value(), f.filter, f.col, + f.docMapper, &f.execInfo) + if err != nil { + return err + } + if indexFetcher != nil { + top = indexFetcher + } + } + + // the index fetcher might not have been created if there is no efficient way to use fetch indexes + // with given filter conditions. In this case we fall back to the prefix fetcher + if top == nil { + top, err = newPrefixFetcher(ctx, f.txn, dsPrefixes, f.col, fieldsByID, client.Active, &f.execInfo) + if err != nil { + return err + } } if f.showDeleted { - deletedFetcher, err := newPrefixFetcher(ctx, f.txn, dsPrefixes, f.col, fieldsByID, client.Deleted, &execInfo) + deletedFetcher, err := newPrefixFetcher(ctx, f.txn, dsPrefixes, f.col, fieldsByID, client.Deleted, &f.execInfo) if err != nil { return err } @@ -148,31 +165,29 @@ func (f *wrappingFetcher) Start(ctx context.Context, prefixes ...keys.Walkable) } func (f *wrappingFetcher) FetchNext(ctx context.Context) (EncodedDocument, ExecInfo, error) { - docID, err := f.fetcher.NextDoc() - if err != nil { - return nil, ExecInfo{}, err - } - - if !docID.HasValue() { - execInfo := *f.execInfo - f.execInfo.Reset() + f.execInfo.Reset() - return nil, execInfo, nil - } + for { + docID, err := f.fetcher.NextDoc() + if err != nil { + return nil, ExecInfo{}, err + } - doc, err := f.fetcher.GetFields() - if err != nil { - return nil, ExecInfo{}, err - } + if !docID.HasValue() { + return nil, f.execInfo, nil + } - if !doc.HasValue() { - return f.FetchNext(ctx) - } + doc, err := f.fetcher.GetFields() + if err != nil { + return nil, ExecInfo{}, err + } - execInfo := *f.execInfo - f.execInfo.Reset() + if !doc.HasValue() { + continue + } - return doc.Value(), execInfo, nil + return doc.Value(), f.execInfo, nil + } } func (f *wrappingFetcher) Close() error { diff --git a/internal/db/indexed_docs_test.go b/internal/db/indexed_docs_test.go index e436f30b38..ad91944614 100644 --- a/internal/db/indexed_docs_test.go +++ b/internal/db/indexed_docs_test.go @@ -630,6 +630,7 @@ func TestNonUniqueCreate_IfUponIndexingExistingDocsFetcherFails_ReturnError(t *t mock.Anything, mock.Anything, mock.Anything, + mock.Anything, ).Unset() f.EXPECT().Init( mock.Anything, @@ -641,6 +642,7 @@ func TestNonUniqueCreate_IfUponIndexingExistingDocsFetcherFails_ReturnError(t *t mock.Anything, mock.Anything, mock.Anything, + mock.Anything, ).Return(testError) f.EXPECT().Close().Unset() f.EXPECT().Close().Return(nil) @@ -861,6 +863,7 @@ func TestNonUniqueUpdate_IfFetcherFails_ReturnError(t *testing.T) { mock.Anything, mock.Anything, mock.Anything, + mock.Anything, ).Unset() f.EXPECT().Init( mock.Anything, @@ -872,6 +875,7 @@ func TestNonUniqueUpdate_IfFetcherFails_ReturnError(t *testing.T) { mock.Anything, mock.Anything, mock.Anything, + mock.Anything, ).Return(testError) f.EXPECT().Close().Unset() f.EXPECT().Close().Return(nil) @@ -980,6 +984,7 @@ func TestNonUniqueUpdate_ShouldPassToFetcherOnlyRelevantFields(t *testing.T) { mock.Anything, mock.Anything, mock.Anything, + mock.Anything, ).Unset() f.EXPECT().Init( mock.Anything, @@ -991,12 +996,14 @@ func TestNonUniqueUpdate_ShouldPassToFetcherOnlyRelevantFields(t *testing.T) { mock.Anything, mock.Anything, mock.Anything, + mock.Anything, ). RunAndReturn(func( ctx context.Context, identity immutable.Option[acpIdentity.Identity], txn datastore.Txn, acp immutable.Option[acp.ACP], + index immutable.Option[client.IndexDescription], col client.Collection, fields []client.FieldDefinition, filter *mapper.Filter, diff --git a/internal/lens/fetcher.go b/internal/lens/fetcher.go index e5c1f3f8e5..d8f533e96f 100644 --- a/internal/lens/fetcher.go +++ b/internal/lens/fetcher.go @@ -66,6 +66,7 @@ func (f *lensedFetcher) Init( identity immutable.Option[acpIdentity.Identity], txn datastore.Txn, acp immutable.Option[acp.ACP], + index immutable.Option[client.IndexDescription], col client.Collection, fields []client.FieldDefinition, filter *mapper.Filter, @@ -117,6 +118,7 @@ historyLoop: identity, txn, acp, + index, col, innerFetcherFields, filter, diff --git a/internal/lens/registry.go b/internal/lens/registry.go index c0fc87a14f..cba0d2a90a 100644 --- a/internal/lens/registry.go +++ b/internal/lens/registry.go @@ -144,7 +144,7 @@ func (r *lensRegistry) getCtx(txn datastore.Txn, readonly bool) *txnContext { } func (r *lensRegistry) setMigration( - ctx context.Context, + _ context.Context, txnCtx *txnContext, collectionID uint32, cfg model.Lens, @@ -182,7 +182,7 @@ func (r *lensRegistry) setMigration( } func (r *lensRegistry) cachePool( - txn datastore.Txn, + _ datastore.Txn, target map[uint32]*lensPool, cfg model.Lens, collectionID uint32, diff --git a/internal/planner/filter/traverse.go b/internal/planner/filter/traverse.go new file mode 100644 index 0000000000..0f837efe67 --- /dev/null +++ b/internal/planner/filter/traverse.go @@ -0,0 +1,140 @@ +// Copyright 2025 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. +package filter + +import ( + "github.com/sourcenetwork/defradb/client/request" + "github.com/sourcenetwork/defradb/internal/connor" + "github.com/sourcenetwork/defradb/internal/planner/mapper" +) + +// TraverseFields walks through a filter condition tree and calls the provided function f +// for each leaf node (field value) encountered. The function f receives the path to the field +// (as a string slice) and its value. If f returns false, traversal stops immediately. +// +// The path parameter in f represents the nested field names leading to the value, excluding +// operator keys (those starting with '_'). For example, given the filter: +// +// { +// "author": { +// "books": { +// "title": {"_eq": "Sample"} +// } +// } +// } +// +// The callback would receive path=["author", "books", "title"] and value="Sample" +func TraverseFields(conditions map[string]any, f func([]string, any) bool) { + traverseFields(nil, "", conditions, f) +} + +func traverseFields(path []string, key string, value any, f func([]string, any) bool) bool { + isKeyOp := func(k string) bool { return len(k) > 0 && k[0] == '_' && k != request.DocIDFieldName } + isOpComplex := func(k string) bool { + switch k { + // all these ops should have a map or an array as value and can not have a single value + case request.AliasFieldName, request.FilterOpOr, request.FilterOpAnd, request.FilterOpNot: + return true + } + return false + } + switch t := value.(type) { + case map[string]any: + for key, value := range t { + if isKeyOp(key) { + if !traverseFields(path, key, value, f) { + return false + } + } else { + newPath := make([]string, len(path), len(path)+1) + copy(newPath, path) + newPath = append(newPath, key) + if !traverseFields(newPath, key, value, f) { + return false + } + } + } + case []any: + for _, v := range t { + if !traverseFields(path, "", v, f) { + return false + } + } + default: + if isKeyOp(key) && isOpComplex(key) { + return false + } + return f(path, value) + } + return true +} + +// TraverseProperties walks through a mapper filter tree and calls the provided function f +// for each PropertyIndex node encountered. Unlike TraverseFields, this function works with +// the internal filter representation using mapper.PropertyIndex and connor.FilterKey types. +// +// The function f receives: +// - The property index node being visited +// - A map of its conditions +// +// If f returns false, traversal stops immediately. +func TraverseProperties( + conditions map[connor.FilterKey]any, + f func(*mapper.PropertyIndex, map[connor.FilterKey]any) bool, + skipOps ...string, +) { + traverseProperties(nil, conditions, f, skipOps) +} + +func traverseProperties( + path []string, + conditions map[connor.FilterKey]any, + f func(*mapper.PropertyIndex, map[connor.FilterKey]any) bool, + skipOps []string, +) bool { + for filterKey, cond := range conditions { + switch t := filterKey.(type) { + case *mapper.PropertyIndex: + if condMap, ok := cond.(map[connor.FilterKey]any); ok { + if !f(t, condMap) { + return false + } + } + case *mapper.Operator: + // Skip this operator if it's in the ignore list + shouldIgnore := false + for _, ignore := range skipOps { + if t.Operation == ignore { + shouldIgnore = true + break + } + } + if shouldIgnore { + continue + } + + switch condVal := cond.(type) { + case map[connor.FilterKey]any: + if !traverseProperties(path, condVal, f, skipOps) { + return false + } + case []any: + for _, elem := range condVal { + if elemMap, ok := elem.(map[connor.FilterKey]any); ok { + if !traverseProperties(path, elemMap, f, skipOps) { + return false + } + } + } + } + } + } + return true +} diff --git a/internal/planner/filter/traverse_test.go b/internal/planner/filter/traverse_test.go new file mode 100644 index 0000000000..b5dfb23c6e --- /dev/null +++ b/internal/planner/filter/traverse_test.go @@ -0,0 +1,494 @@ +// Copyright 2025 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. +package filter + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/sourcenetwork/defradb/client/request" + "github.com/sourcenetwork/defradb/internal/connor" + "github.com/sourcenetwork/defradb/internal/planner/mapper" +) + +func TestTraverseFields(t *testing.T) { + tests := []struct { + name string + input map[string]any + expectedPaths [][]string + expectedVals []any + }{ + { + name: "simple field", + input: map[string]any{ + "name": map[string]any{ + "_eq": "John", + }, + }, + expectedPaths: [][]string{{"name"}}, + expectedVals: []any{"John"}, + }, + { + name: "multiple fields", + input: map[string]any{ + "name": map[string]any{"_eq": "John"}, + "age": map[string]any{"_gt": 25}, + }, + expectedPaths: [][]string{{"name"}, {"age"}}, + expectedVals: []any{"John", 25}, + }, + { + name: "nested fields", + input: map[string]any{ + "author": map[string]any{ + "books": map[string]any{ + "title": map[string]any{ + "_eq": "Sample Book", + }, + }, + }, + }, + expectedPaths: [][]string{{"author", "books", "title"}}, + expectedVals: []any{"Sample Book"}, + }, + { + name: "with _or operator", + input: map[string]any{ + request.FilterOpOr: []any{ + map[string]any{ + "name": map[string]any{"_eq": "John"}, + }, + map[string]any{ + "age": map[string]any{"_gt": 30}, + }, + }, + }, + expectedPaths: [][]string{{"name"}, {"age"}}, + expectedVals: []any{"John", 30}, + }, + { + name: "with _or operator with nil value", + input: map[string]any{ + request.FilterOpOr: nil, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with _or operator with empty array value", + input: map[string]any{ + request.FilterOpOr: []any{}, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with _or operator with empty map value", + input: map[string]any{ + request.FilterOpOr: map[string]any{}, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with _or operator with invalid value", + input: map[string]any{ + request.FilterOpOr: 1, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with _and operator", + input: map[string]any{ + request.FilterOpAnd: []any{ + map[string]any{ + "name": map[string]any{"_eq": "John"}, + }, + map[string]any{ + "age": map[string]any{"_gt": 30}, + }, + }, + }, + expectedPaths: [][]string{{"name"}, {"age"}}, + expectedVals: []any{"John", 30}, + }, + { + name: "with _and operator with nil value", + input: map[string]any{ + request.FilterOpAnd: nil, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with _and operator with empty array value", + input: map[string]any{ + request.FilterOpAnd: []any{}, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with _and operator with empty map value", + input: map[string]any{ + request.FilterOpAnd: map[string]any{}, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with _and operator with invalid value", + input: map[string]any{ + request.FilterOpAnd: 1, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with _not operator", + input: map[string]any{ + request.FilterOpNot: []any{ + map[string]any{ + "name": map[string]any{"_eq": "John"}, + }, + }, + }, + expectedPaths: [][]string{{"name"}}, + expectedVals: []any{"John"}, + }, + { + name: "with _not operator with nil value", + input: map[string]any{ + request.FilterOpNot: nil, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with _not operator with empty array value", + input: map[string]any{ + request.FilterOpNot: []any{}, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with _not operator with empty map value", + input: map[string]any{ + request.FilterOpNot: map[string]any{}, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with _not operator with invalid value", + input: map[string]any{ + request.FilterOpNot: 1, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with alias operator with nil value", + input: map[string]any{ + request.AliasFieldName: nil, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with alias operator", + input: map[string]any{ + request.AliasFieldName: map[string]any{ + "age": map[string]any{"_eq": 30}, + }, + }, + expectedPaths: [][]string{{"age"}}, + expectedVals: []any{30}, + }, + { + name: "with empty alias operator", + input: map[string]any{ + request.AliasFieldName: map[string]any{}, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + { + name: "with alias operator of invalid type", + input: map[string]any{ + request.AliasFieldName: 1, + }, + expectedPaths: [][]string{}, + expectedVals: []any{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var actualPaths [][]string + var actualVals []any + + TraverseFields(tt.input, func(path []string, val any) bool { + pathCopy := make([]string, len(path)) + copy(pathCopy, path) + actualPaths = append(actualPaths, pathCopy) + actualVals = append(actualVals, val) + return true // continue traversal + }) + + assert.ElementsMatch(t, tt.expectedPaths, actualPaths) + assert.ElementsMatch(t, tt.expectedVals, actualVals) + }) + } +} + +func TestTraverseFieldsEarlyExit(t *testing.T) { + tests := []struct { + name string + input map[string]any + expectedCount int + exitAfter int + }{ + { + name: "exit in flat fields", + input: map[string]any{ + "name": map[string]any{"_eq": "John"}, + "age": map[string]any{"_gt": 25}, + "city": map[string]any{"_eq": "New York"}, + }, + expectedCount: 2, + exitAfter: 2, + }, + { + name: "exit in nested fields", + input: map[string]any{ + "author": map[string]any{ + "name": map[string]any{"_eq": "John"}, + "books": map[string]any{ + "title": map[string]any{"_eq": "Book 1"}, + "year": map[string]any{"_gt": 2000}, + }, + }, + }, + expectedCount: 1, + exitAfter: 1, + }, + { + name: "exit in array operator", + input: map[string]any{ + "_or": []any{ + map[string]any{ + "name": map[string]any{"_eq": "John"}, + }, + map[string]any{ + "age": map[string]any{"_gt": 30}, + }, + map[string]any{ + "city": map[string]any{"_eq": "Paris"}, + }, + }, + }, + expectedCount: 2, + exitAfter: 2, + }, + { + name: "exit in mixed operators", + input: map[string]any{ + "_and": []any{ + map[string]any{ + "name": map[string]any{"_eq": "John"}, + }, + map[string]any{ + "_or": []any{ + map[string]any{"age": map[string]any{"_gt": 30}}, + map[string]any{"city": map[string]any{"_eq": "Paris"}}, + }, + }, + }, + }, + expectedCount: 1, + exitAfter: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var actualPaths [][]string + var actualVals []any + + TraverseFields(tt.input, func(path []string, val any) bool { + pathCopy := make([]string, len(path)) + copy(pathCopy, path) + actualPaths = append(actualPaths, pathCopy) + actualVals = append(actualVals, val) + return len(actualPaths) < tt.exitAfter + }) + + assert.Equal(t, tt.expectedCount, len(actualPaths), + "should have stopped after %d fields", tt.expectedCount) + assert.Equal(t, tt.expectedCount, len(actualVals), + "should have stopped after %d values", tt.expectedCount) + }) + } +} + +func TestTraverseProperties(t *testing.T) { + tests := []struct { + name string + input map[connor.FilterKey]any + expectedProps []int + expectedValues map[int]any + }{ + { + name: "simple property", + input: map[connor.FilterKey]any{ + &mapper.PropertyIndex{Index: 1}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_eq"}: "John", + }, + }, + expectedProps: []int{1}, + expectedValues: map[int]any{1: "John"}, + }, + { + name: "multiple properties", + input: map[connor.FilterKey]any{ + &mapper.PropertyIndex{Index: 1}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_eq"}: "John", + }, + &mapper.PropertyIndex{Index: 2}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_gt"}: 25, + }, + }, + expectedProps: []int{1, 2}, + expectedValues: map[int]any{1: "John", 2: 25}, + }, + { + name: "nested in operator", + input: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_or"}: map[connor.FilterKey]any{ + &mapper.PropertyIndex{Index: 1}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_eq"}: "John", + }, + &mapper.PropertyIndex{Index: 2}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_gt"}: 25, + }, + }, + }, + expectedProps: []int{1, 2}, + expectedValues: map[int]any{1: "John", 2: 25}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var actualProps []int + actualValues := make(map[int]any) + + TraverseProperties(tt.input, func(prop *mapper.PropertyIndex, val map[connor.FilterKey]any) bool { + actualProps = append(actualProps, prop.Index) + // Extract the actual value from the operator map + for _, v := range val { + actualValues[prop.Index] = v + break // We only expect one operator per property in our test cases + } + return true + }) + + assert.ElementsMatch(t, tt.expectedProps, actualProps) + assert.Equal(t, tt.expectedValues, actualValues) + }) + } +} + +func TestTraverseProperties_EarlyExit(t *testing.T) { + input := map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_and"}: map[connor.FilterKey]any{ + &mapper.PropertyIndex{Index: 1}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_eq"}: "John", + }, + &mapper.PropertyIndex{Index: 2}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_gt"}: 25, + }, + &mapper.PropertyIndex{Index: 3}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_eq"}: "New York", + }, + }, + } + + var visitCount int + TraverseProperties(input, func(prop *mapper.PropertyIndex, val map[connor.FilterKey]any) bool { + visitCount++ + return visitCount < 2 // Stop after visiting 2 properties + }) + + assert.Equal(t, 2, visitCount, "should have stopped after visiting 2 properties") +} + +func TestTraversePropertiesWithIgnoreNodes(t *testing.T) { + tests := []struct { + name string + conditions map[connor.FilterKey]any + skipOps []string + expected []int + }{ + { + name: "ignore _not operator", + conditions: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_not"}: map[connor.FilterKey]any{ + &mapper.PropertyIndex{Index: 1}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_eq"}: "John", + }, + }, + &mapper.PropertyIndex{Index: 2}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_gt"}: 18, + }, + }, + skipOps: []string{"_not"}, + expected: []int{2}, + }, + { + name: "ignore multiple operators", + conditions: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_not"}: map[connor.FilterKey]any{ + &mapper.PropertyIndex{Index: 1}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_eq"}: "John", + }, + }, + &mapper.Operator{Operation: "_and"}: map[connor.FilterKey]any{ + &mapper.PropertyIndex{Index: 2}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_eq"}: true, + }, + }, + &mapper.Operator{Operation: "_or"}: map[connor.FilterKey]any{ + &mapper.PropertyIndex{Index: 3}: map[connor.FilterKey]any{ + &mapper.Operator{Operation: "_gt"}: 18, + }, + }, + }, + skipOps: []string{"_not", "_or"}, + expected: []int{2}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var visited []int + TraverseProperties(tt.conditions, func(p *mapper.PropertyIndex, conditions map[connor.FilterKey]any) bool { + visited = append(visited, p.Index) + return true + }, tt.skipOps...) + + assert.ElementsMatch(t, tt.expected, visited) + }) + } +} diff --git a/internal/planner/mapper/targetable.go b/internal/planner/mapper/targetable.go index e25c8b03f5..695dfede6d 100644 --- a/internal/planner/mapper/targetable.go +++ b/internal/planner/mapper/targetable.go @@ -30,11 +30,11 @@ type PropertyIndex struct { Index int } -func (k *PropertyIndex) PropertyAndOperator(data any, defaultOp string) (any, string, error) { +func (k *PropertyIndex) PropertyAndOperator(data any, defaultOp string) (connor.KeyResult, error) { if data == nil { - return nil, defaultOp, nil + return connor.KeyResult{Data: nil, Operator: defaultOp}, nil } - return data.(core.Doc).Fields[k.Index], defaultOp, nil + return connor.KeyResult{Data: data.(core.Doc).Fields[k.Index], Operator: defaultOp}, nil } func (k *PropertyIndex) Equal(other connor.FilterKey) bool { @@ -52,8 +52,8 @@ type Operator struct { Operation string } -func (k *Operator) PropertyAndOperator(data any, defaultOp string) (any, string, error) { - return data, k.Operation, nil +func (k *Operator) PropertyAndOperator(data any, defaultOp string) (connor.KeyResult, error) { + return connor.KeyResult{Data: data, Operator: k.Operation}, nil } func (k *Operator) Equal(other connor.FilterKey) bool { @@ -72,15 +72,16 @@ type ObjectProperty struct { Name string } -func (k *ObjectProperty) PropertyAndOperator(data any, defaultOp string) (any, string, error) { +func (k *ObjectProperty) PropertyAndOperator(data any, defaultOp string) (connor.KeyResult, error) { if data == nil { - return nil, defaultOp, nil + return connor.KeyResult{Operator: defaultOp}, nil } docMap, ok := data.(map[string]any) if !ok { - return nil, defaultOp, NewErrFieldOrAliasNotFound(k.Name) + return connor.KeyResult{Operator: defaultOp}, NewErrFieldOrAliasNotFound(k.Name) } - return docMap[k.Name], defaultOp, nil + prop, hasProp := docMap[k.Name] + return connor.KeyResult{Data: prop, MissProp: !hasProp, Operator: defaultOp}, nil } func (k *ObjectProperty) Equal(other connor.FilterKey) bool { diff --git a/internal/planner/planner.go b/internal/planner/planner.go index 8390c6d5a5..8d5c7cf052 100644 --- a/internal/planner/planner.go +++ b/internal/planner/planner.go @@ -309,11 +309,9 @@ func (p *Planner) tryOptimizeJoinDirection(node *invertibleTypeJoin, parentPlan if len(indexes) > 0 && !filter.IsComplex(parentPlan.selectNode.filter) { subInd := node.documentMapping.FirstIndexOfName(node.parentSide.relFieldDef.Value().Name) relatedField := mapper.Field{Name: node.parentSide.relFieldDef.Value().Name, Index: subInd} - fieldFilter := filter.UnwrapRelation(filter.CopyField( - parentPlan.selectNode.filter, - relatedField, - mapper.Field{Name: subFieldName, Index: subFieldInd}, - ), relatedField) + relevantFilter := filter.CopyField(parentPlan.selectNode.filter, relatedField, + mapper.Field{Name: subFieldName, Index: subFieldInd}) + fieldFilter := extractRelatedSubFilter(relevantFilter, node.parentSide.plan.DocumentMap(), relatedField) // At the moment we just take the first index, but later we want to run some kind of analysis to // determine which index is best to use. https://github.com/sourcenetwork/defradb/issues/2680 err := node.invertJoinDirectionWithIndex(fieldFilter, indexes[0]) @@ -327,6 +325,13 @@ func (p *Planner) tryOptimizeJoinDirection(node *invertibleTypeJoin, parentPlan return nil } +func extractRelatedSubFilter(f *mapper.Filter, docMap *core.DocumentMapping, relField mapper.Field) *mapper.Filter { + subInd := docMap.FirstIndexOfName(relField.Name) + relatedField := mapper.Field{Name: relField.Name, Index: subInd} + subFilter := filter.UnwrapRelation(f, relatedField) + return subFilter +} + // expandTypeJoin does a plan graph expansion and other optimizations on invertibleTypeJoin. func (p *Planner) expandTypeJoin(node *invertibleTypeJoin, parentPlan *selectTopNode) error { if parentPlan.selectNode.filter == nil { diff --git a/internal/planner/scan.go b/internal/planner/scan.go index bfca64b7bb..161a28f2f4 100644 --- a/internal/planner/scan.go +++ b/internal/planner/scan.go @@ -20,7 +20,6 @@ import ( "github.com/sourcenetwork/defradb/internal/db/fetcher" "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/lens" - "github.com/sourcenetwork/defradb/internal/planner/filter" "github.com/sourcenetwork/defradb/internal/planner/mapper" "github.com/sourcenetwork/defradb/internal/request/graphql/parser" ) @@ -51,6 +50,7 @@ type scanNode struct { filter *mapper.Filter slct *mapper.Select + index immutable.Option[client.IndexDescription] fetcher fetcher.Fetcher execInfo scanExecInfo @@ -67,6 +67,7 @@ func (n *scanNode) Init() error { n.p.identity, n.p.txn, n.p.acp, + n.index, n.col, n.fields, n.filter, @@ -152,46 +153,13 @@ func (n *scanNode) addField(field client.FieldDefinition) { } } -func (scan *scanNode) initFetcher( - cid immutable.Option[string], - index immutable.Option[client.IndexDescription], -) { +func (scan *scanNode) initFetcher(cid immutable.Option[string]) { var f fetcher.Fetcher if cid.HasValue() { f = new(fetcher.VersionedFetcher) } else { f = fetcher.NewDocumentFetcher() - if index.HasValue() { - fieldsToMove := make([]mapper.Field, 0, len(index.Value().Fields)) - fieldsToCopy := make([]mapper.Field, 0, len(index.Value().Fields)) - for _, field := range index.Value().Fields { - fieldName := field.Name - typeIndex := scan.documentMapping.FirstIndexOfName(fieldName) - indexField := mapper.Field{Index: typeIndex, Name: fieldName} - fd, _ := scan.col.Definition().Schema.GetFieldByName(fieldName) - // if the field is an array, we need to copy it instead of moving so that the - // top select node can do final filter check on the whole array of the document - // because indexes can not assert conditions like _any, _all, _none - // TODO: we don't have to do this for all json fields, only for those that filter - // on it's array fields. We should be able to optimize this. - // https://github.com/sourcenetwork/defradb/issues/3306 - if fd.Kind.IsArray() || fd.Kind == client.FieldKind_NILLABLE_JSON { - fieldsToCopy = append(fieldsToCopy, indexField) - } else { - fieldsToMove = append(fieldsToMove, indexField) - } - } - var indexFilter *mapper.Filter - scan.filter, indexFilter = filter.SplitByFields(scan.filter, fieldsToMove...) - for i := range fieldsToCopy { - indexFilter = filter.Merge(indexFilter, filter.CopyField(scan.filter, fieldsToCopy[i])) - } - if indexFilter != nil { - f = fetcher.NewIndexFetcher(f, index.Value(), indexFilter) - } - } - f = lens.NewFetcher(f, scan.p.db.LensRegistry()) } scan.fetcher = f diff --git a/internal/planner/select.go b/internal/planner/select.go index d3bcbb910d..8d41d1d251 100644 --- a/internal/planner/select.go +++ b/internal/planner/select.go @@ -11,6 +11,9 @@ package planner import ( + "slices" + "strings" + cid "github.com/ipfs/go-cid" "github.com/sourcenetwork/immutable" @@ -296,7 +299,8 @@ func (n *selectNode) initSource() ([]aggregateNode, error) { } if isScanNode { - origScan.initFetcher(n.selectReq.Cid, findIndexByFilteringField(origScan)) + origScan.index = findIndexByFilteringField(origScan) + origScan.initFetcher(n.selectReq.Cid) } return aggregates, nil @@ -308,17 +312,31 @@ func findIndexByFilteringField(scanNode *scanNode) immutable.Option[client.Index } colDesc := scanNode.col.Description() - for _, field := range scanNode.col.Schema().Fields { - if _, isFiltered := scanNode.filter.ExternalConditions[field.Name]; !isFiltered { - continue - } - indexes := colDesc.GetIndexesOnField(field.Name) - if len(indexes) > 0 { - // we return the first found index. We will optimize it later. - return immutable.Some(indexes[0]) + conditions := scanNode.filter.ExternalConditions + var indexCandidates []client.IndexDescription + filter.TraverseFields(conditions, func(path []string, val any) bool { + for _, field := range scanNode.col.Schema().Fields { + if field.Name != path[0] { + continue + } + indexes := colDesc.GetIndexesOnField(field.Name) + if len(indexes) > 0 { + indexCandidates = append(indexCandidates, indexes...) + return true + } } + return true + }) + if len(indexCandidates) == 0 { + return immutable.None[client.IndexDescription]() } - return immutable.None[client.IndexDescription]() + + slices.SortFunc(indexCandidates, func(a, b client.IndexDescription) int { + return strings.Compare(a.Name, b.Name) + }) + // we return the first found index. We will optimize it later. + // https://github.com/sourcenetwork/defradb/issues/2680 + return immutable.Some(indexCandidates[0]) } func findIndexByFieldName(col client.Collection, fieldName string) immutable.Option[client.IndexDescription] { diff --git a/internal/planner/type_join.go b/internal/planner/type_join.go index 5e7b83d237..5012d6f6a3 100644 --- a/internal/planner/type_join.go +++ b/internal/planner/type_join.go @@ -372,12 +372,16 @@ func (p *Planner) newInvertableTypeJoin( isParent: false, } - return invertibleTypeJoin{ + join := invertibleTypeJoin{ docMapper: docMapper{parent.documentMapping}, parentSide: parentSide, childSide: childSide, skipChild: skipChild, - }, nil + // we store child's own filter in case an index kicks in and replaces it with it's own filter + subFilter: getScanNode(childSide.plan).filter, + } + + return join, nil } type joinSide struct { @@ -437,11 +441,11 @@ func getForeignKey(node planNode, relFieldName string) string { return docIDStr } -// fetchDocWithID fetches a document with the given docID from the given planNode. -func fetchDocWithID(node planNode, docID string) (bool, error) { +// fetchDocWithIDAndItsSubDocs fetches a document with the given docID from the given planNode. +func fetchDocWithIDAndItsSubDocs(node planNode, docID string) (immutable.Option[core.Doc], error) { scan := getScanNode(node) if scan == nil { - return false, nil + return immutable.None[core.Doc](), nil } dsKey := base.MakeDataStoreKeyWithCollectionAndDocID(scan.col.Description(), docID) @@ -450,16 +454,16 @@ func fetchDocWithID(node planNode, docID string) (bool, error) { node.Prefixes(prefixes) if err := node.Init(); err != nil { - return false, NewErrSubTypeInit(err) + return immutable.None[core.Doc](), NewErrSubTypeInit(err) } hasValue, err := node.Next() if err != nil || !hasValue { - return false, err + return immutable.None[core.Doc](), err } - return true, nil + return immutable.Some(node.Value()), nil } type invertibleTypeJoin struct { @@ -470,6 +474,9 @@ type invertibleTypeJoin struct { parentSide joinSide childSide joinSide + // the filter of the subnode to store in case it's replaced by an index filter + subFilter *mapper.Filter + secondaryFetchLimit uint // docsToYield contains documents read and ready to be yielded by this node. @@ -514,22 +521,15 @@ type primaryObjectsRetriever struct { primarySide *joinSide secondarySide *joinSide + targetSecondaryDoc core.Doc + filter *mapper.Filter + primaryScan *scanNode resultPrimaryDocs []core.Doc resultSecondaryDoc core.Doc } -func newPrimaryObjectsRetriever( - primarySide, secondarySide *joinSide, -) primaryObjectsRetriever { - j := primaryObjectsRetriever{ - primarySide: primarySide, - secondarySide: secondarySide, - } - return j -} - func (r *primaryObjectsRetriever) retrievePrimaryDocsReferencingSecondaryDoc() error { relIDFieldDef, ok := r.primarySide.col.Definition().GetFieldByName( r.primarySide.relFieldDef.Value().Name + request.RelatedObjectID) @@ -547,7 +547,12 @@ func (r *primaryObjectsRetriever) retrievePrimaryDocsReferencingSecondaryDoc() e return err } - r.resultPrimaryDocs, r.resultSecondaryDoc = joinPrimaryDocs(primaryDocs, r.secondarySide, r.primarySide) + r.resultPrimaryDocs, r.resultSecondaryDoc = joinPrimaryDocs( + primaryDocs, + r.targetSecondaryDoc, + r.primarySide, + r.secondarySide, + ) return nil } @@ -585,13 +590,14 @@ func (r *primaryObjectsRetriever) collectDocs(numDocs int) ([]core.Doc, error) { func (r *primaryObjectsRetriever) retrievePrimaryDocs() ([]core.Doc, error) { r.primaryScan.addField(r.relIDFieldDef) - secondaryDoc := r.secondarySide.plan.Value() - addFilterOnIDField(r.primaryScan, r.primarySide.relIDFieldMapIndex.Value(), secondaryDoc.GetID()) + r.primaryScan.filter = addFilterOnIDField(r.filter, r.primarySide.relIDFieldMapIndex.Value(), + r.targetSecondaryDoc.GetID()) oldFetcher := r.primaryScan.fetcher + oldIndex := r.primaryScan.index - indexOnRelation := findIndexByFieldName(r.primaryScan.col, r.relIDFieldDef.Name) - r.primaryScan.initFetcher(immutable.None[string](), indexOnRelation) + r.primaryScan.index = findIndexByFieldName(r.primaryScan.col, r.relIDFieldDef.Name) + r.primaryScan.initFetcher(immutable.None[string]()) docs, err := r.collectDocs(0) if err != nil { @@ -604,6 +610,7 @@ func (r *primaryObjectsRetriever) retrievePrimaryDocs() ([]core.Doc, error) { } r.primaryScan.fetcher = oldFetcher + r.primaryScan.index = oldIndex return docs, nil } @@ -616,9 +623,11 @@ func docsToDocIDs(docs []core.Doc) []string { return docIDs } -func joinPrimaryDocs(primaryDocs []core.Doc, secondarySide, primarySide *joinSide) ([]core.Doc, core.Doc) { - secondaryDoc := secondarySide.plan.Value() - +func joinPrimaryDocs( + primaryDocs []core.Doc, + secondaryDoc core.Doc, + primarySide, secondarySide *joinSide, +) ([]core.Doc, core.Doc) { if secondarySide.relFieldMapIndex.HasValue() { if !secondarySide.relFieldDef.HasValue() || secondarySide.relFieldDef.Value().Kind.IsArray() { secondaryDoc.Fields[secondarySide.relFieldMapIndex.Value()] = primaryDocs @@ -650,8 +659,17 @@ func joinPrimaryDocs(primaryDocs []core.Doc, secondarySide, primarySide *joinSid return primaryDocs, secondaryDoc } -func (join *invertibleTypeJoin) fetchPrimaryDocsReferencingSecondaryDoc() ([]core.Doc, core.Doc, error) { - retriever := newPrimaryObjectsRetriever(join.getPrimarySide(), join.getSecondarySide()) +func fetchPrimaryDocsReferencingSecondaryDoc( + primarySide, secondarySide *joinSide, + secondaryDoc core.Doc, + filter *mapper.Filter, +) ([]core.Doc, core.Doc, error) { + retriever := primaryObjectsRetriever{ + primarySide: primarySide, + secondarySide: secondarySide, + targetSecondaryDoc: secondaryDoc, + filter: filter, + } err := retriever.retrievePrimaryDocsReferencingSecondaryDoc() return retriever.resultPrimaryDocs, retriever.resultSecondaryDoc, err } @@ -676,9 +694,10 @@ func (join *invertibleTypeJoin) Next() (bool, error) { } if firstSide.isPrimary() { - return join.nextJoinedSecondaryDoc() + return join.fetchRelatedSecondaryDocWithChildren(firstSide.plan.Value()) } else { - primaryDocs, secondaryDoc, err := join.fetchPrimaryDocsReferencingSecondaryDoc() + primaryDocs, secondaryDoc, err := fetchPrimaryDocsReferencingSecondaryDoc( + join.getPrimarySide(), join.getSecondarySide(), firstSide.plan.Value(), join.subFilter) if err != nil { return false, err } @@ -699,7 +718,7 @@ func (join *invertibleTypeJoin) Next() (bool, error) { return true, nil } -func (join *invertibleTypeJoin) nextJoinedSecondaryDoc() (bool, error) { +func (join *invertibleTypeJoin) fetchRelatedSecondaryDocWithChildren(primaryDoc core.Doc) (bool, error) { firstSide := join.getFirstSide() secondSide := join.getSecondSide() @@ -712,7 +731,9 @@ func (join *invertibleTypeJoin) nextJoinedSecondaryDoc() (bool, error) { return join.Next() } - if !firstSide.isParent { + if secondSide.isParent { + // child primary docs reference the same secondary parent doc. So if we already encountered + // the secondary parent doc, we continue to the next primary doc. for i := range join.encounteredDocIDs { if join.encounteredDocIDs[i] == secondaryDocID { return join.Next() @@ -721,12 +742,13 @@ func (join *invertibleTypeJoin) nextJoinedSecondaryDoc() (bool, error) { join.encounteredDocIDs = append(join.encounteredDocIDs, secondaryDocID) } - hasDoc, err := fetchDocWithID(secondSide.plan, secondaryDocID) + secondaryDocOpt, err := fetchDocWithIDAndItsSubDocs(secondSide.plan, secondaryDocID) + if err != nil { return false, err } - if !hasDoc { + if !secondaryDocOpt.HasValue() { if firstSide.isParent { join.docsToYield = append(join.docsToYield, firstSide.plan.Value()) return true, nil @@ -734,15 +756,18 @@ func (join *invertibleTypeJoin) nextJoinedSecondaryDoc() (bool, error) { return join.Next() } + secondaryDoc := secondaryDocOpt.Value() + if join.parentSide.relFieldDef.Value().Kind.IsArray() { var primaryDocs []core.Doc - var secondaryDoc core.Doc // if child is not requested as part of the response, we just add the existing one (fetched by the secondary index // on a filtered value) so that top select node that runs the filter again can yield it. if join.skipChild { - primaryDocs, secondaryDoc = joinPrimaryDocs([]core.Doc{firstSide.plan.Value()}, secondSide, firstSide) + primaryDocs, secondaryDoc = joinPrimaryDocs( + []core.Doc{firstSide.plan.Value()}, secondaryDoc, join.getPrimarySide(), join.getSecondSide()) } else { - primaryDocs, secondaryDoc, err = join.fetchPrimaryDocsReferencingSecondaryDoc() + primaryDocs, secondaryDoc, err = fetchPrimaryDocsReferencingSecondaryDoc( + join.getPrimarySide(), join.getSecondarySide(), secondaryDoc, join.subFilter) if err != nil { return false, err } @@ -751,8 +776,16 @@ func (join *invertibleTypeJoin) nextJoinedSecondaryDoc() (bool, error) { join.docsToYield = append(join.docsToYield, secondaryDoc) } else { - parentDoc := join.parentSide.plan.Value() - parentDoc.Fields[join.parentSide.relFieldMapIndex.Value()] = join.childSide.plan.Value() + var parentDoc core.Doc + var childDoc core.Doc + if join.getPrimarySide().isParent { + parentDoc = primaryDoc + childDoc = secondaryDoc + } else { + parentDoc = secondaryDoc + childDoc = primaryDoc + } + parentDoc.Fields[join.parentSide.relFieldMapIndex.Value()] = childDoc join.docsToYield = append(join.docsToYield, parentDoc) } return true, nil @@ -769,11 +802,13 @@ func (join *invertibleTypeJoin) invertJoinDirectionWithIndex( fieldFilter *mapper.Filter, index client.IndexDescription, ) error { - p := join.childSide.plan - s := getScanNode(p) - s.tryAddFieldWithName(join.childSide.relFieldDef.Value().Name + request.RelatedObjectID) - s.filter = fieldFilter - s.initFetcher(immutable.Option[string]{}, immutable.Some(index)) + childScan := getScanNode(join.childSide.plan) + childScan.tryAddFieldWithName(join.childSide.relFieldDef.Value().Name + request.RelatedObjectID) + // replace child's filter with the filter that utilizes the index + // the original child's filter is stored in join.subFilter + childScan.filter = fieldFilter + childScan.index = immutable.Some(index) + childScan.initFetcher(immutable.Option[string]{}) join.childSide.isFirst = join.parentSide.isFirst join.parentSide.isFirst = !join.parentSide.isFirst @@ -781,24 +816,21 @@ func (join *invertibleTypeJoin) invertJoinDirectionWithIndex( return nil } -func addFilterOnIDField(scan *scanNode, propIndex int, val any) { - if scan == nil { - return - } - - if scan.filter == nil { - scan.filter = mapper.NewFilter() +func addFilterOnIDField(f *mapper.Filter, propIndex int, docID string) *mapper.Filter { + if f == nil { + f = mapper.NewFilter() } propertyIndex := &mapper.PropertyIndex{Index: propIndex} filterConditions := map[connor.FilterKey]any{ propertyIndex: map[connor.FilterKey]any{ - mapper.FilterEqOp: val, + mapper.FilterEqOp: docID, }, } - filter.RemoveField(scan.filter, mapper.Field{Index: propIndex}) - scan.filter.Conditions = filter.MergeConditions(scan.filter.Conditions, filterConditions) + filter.RemoveField(f, mapper.Field{Index: propIndex}) + f.Conditions = filter.MergeConditions(f.Conditions, filterConditions) + return f } func getScanNode(plan planNode) *scanNode { diff --git a/tests/integration/explain/execute/create_test.go b/tests/integration/explain/execute/create_test.go index 29816b47c6..42ce15e334 100644 --- a/tests/integration/explain/execute/create_test.go +++ b/tests/integration/explain/execute/create_test.go @@ -48,7 +48,7 @@ func TestExecuteExplainMutationRequestWithCreate(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(2), "docFetches": uint64(1), - "fieldFetches": uint64(1), + "fieldFetches": uint64(3), "indexFetches": uint64(0), }, }, diff --git a/tests/integration/explain/execute/delete_test.go b/tests/integration/explain/execute/delete_test.go index 6e43b3dbbd..8b90fe83f1 100644 --- a/tests/integration/explain/execute/delete_test.go +++ b/tests/integration/explain/execute/delete_test.go @@ -51,7 +51,7 @@ func TestExecuteExplainMutationRequestWithDeleteUsingID(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(2), "docFetches": uint64(1), - "fieldFetches": uint64(1), + "fieldFetches": uint64(2), "indexFetches": uint64(0), }, }, @@ -103,7 +103,7 @@ func TestExecuteExplainMutationRequestWithDeleteUsingFilter(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(2), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, }, diff --git a/tests/integration/explain/execute/top_level_test.go b/tests/integration/explain/execute/top_level_test.go index 784d7fe8a9..8d64ad2cbc 100644 --- a/tests/integration/explain/execute/top_level_test.go +++ b/tests/integration/explain/execute/top_level_test.go @@ -70,7 +70,7 @@ func TestExecuteExplainTopLevelAverageRequest(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(4), "indexFetches": uint64(0), }, }, @@ -233,7 +233,7 @@ func TestExecuteExplainTopLevelSumRequest(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(4), "indexFetches": uint64(0), }, }, diff --git a/tests/integration/explain/execute/type_join_test.go b/tests/integration/explain/execute/type_join_test.go index 511c3498a9..be510237f8 100644 --- a/tests/integration/explain/execute/type_join_test.go +++ b/tests/integration/explain/execute/type_join_test.go @@ -54,13 +54,13 @@ func TestExecuteExplainRequestWithAOneToOneJoin(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(2), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(6), "indexFetches": uint64(0), }, }, @@ -120,13 +120,13 @@ func TestExecuteExplainWithMultipleOneToOneJoins(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(2), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(6), "indexFetches": uint64(0), }, }, @@ -137,13 +137,13 @@ func TestExecuteExplainWithMultipleOneToOneJoins(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(2), "docFetches": uint64(2), - "fieldFetches": uint64(4), + "fieldFetches": uint64(6), "indexFetches": uint64(0), }, }, @@ -203,13 +203,13 @@ func TestExecuteExplainWithTwoLevelDeepNestedJoins(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(4), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(2), "docFetches": uint64(2), - "fieldFetches": uint64(4), + "fieldFetches": uint64(6), "indexFetches": uint64(0), }, }, diff --git a/tests/integration/explain/execute/with_average_test.go b/tests/integration/explain/execute/with_average_test.go index fdadf6fcaa..6bfe343a3c 100644 --- a/tests/integration/explain/execute/with_average_test.go +++ b/tests/integration/explain/execute/with_average_test.go @@ -58,7 +58,7 @@ func TestExecuteExplainAverageRequestOnArrayField(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(4), "docFetches": uint64(3), - "fieldFetches": uint64(5), + "fieldFetches": uint64(11), "indexFetches": uint64(0), }, }, @@ -120,13 +120,13 @@ func TestExplainExplainAverageRequestOnJoinedField(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(5), "docFetches": uint64(6), - "fieldFetches": uint64(12), + "fieldFetches": uint64(22), "indexFetches": uint64(0), }, }, diff --git a/tests/integration/explain/execute/with_count_test.go b/tests/integration/explain/execute/with_count_test.go index 190a685592..cb623da565 100644 --- a/tests/integration/explain/execute/with_count_test.go +++ b/tests/integration/explain/execute/with_count_test.go @@ -56,13 +56,13 @@ func TestExecuteExplainRequestWithCountOnOneToManyRelation(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(5), "docFetches": uint64(6), - "fieldFetches": uint64(6), + "fieldFetches": uint64(22), "indexFetches": uint64(0), }, }, diff --git a/tests/integration/explain/execute/with_limit_test.go b/tests/integration/explain/execute/with_limit_test.go index ff2ca0b437..d4f1e5a846 100644 --- a/tests/integration/explain/execute/with_limit_test.go +++ b/tests/integration/explain/execute/with_limit_test.go @@ -53,7 +53,7 @@ func TestExecuteExplainRequestWithBothLimitAndOffsetOnParent(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(2), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(7), "indexFetches": uint64(0), }, }, @@ -111,13 +111,13 @@ func TestExecuteExplainRequestWithBothLimitAndOffsetOnParentAndLimitOnChild(t *t "scanNode": dataMap{ "iterations": uint64(2), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(2), "docFetches": uint64(3), - "fieldFetches": uint64(6), + "fieldFetches": uint64(9), "indexFetches": uint64(0), }, }, diff --git a/tests/integration/explain/execute/with_max_test.go b/tests/integration/explain/execute/with_max_test.go index 6fa390be7c..900d526c5b 100644 --- a/tests/integration/explain/execute/with_max_test.go +++ b/tests/integration/explain/execute/with_max_test.go @@ -54,7 +54,7 @@ func TestExecuteExplainRequest_WithMaxOfInlineArrayField_Succeeds(t *testing.T) "scanNode": dataMap{ "iterations": uint64(4), "docFetches": uint64(3), - "fieldFetches": uint64(5), + "fieldFetches": uint64(11), "indexFetches": uint64(0), }, }, @@ -113,13 +113,13 @@ func TestExecuteExplainRequest_MaxOfRelatedOneToManyField_Succeeds(t *testing.T) "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(5), "docFetches": uint64(6), - "fieldFetches": uint64(12), + "fieldFetches": uint64(18), "indexFetches": uint64(0), }, }, diff --git a/tests/integration/explain/execute/with_min_test.go b/tests/integration/explain/execute/with_min_test.go index 4626071d32..cad99db706 100644 --- a/tests/integration/explain/execute/with_min_test.go +++ b/tests/integration/explain/execute/with_min_test.go @@ -54,7 +54,7 @@ func TestExecuteExplainRequest_WithMinOfInlineArrayField_Succeeds(t *testing.T) "scanNode": dataMap{ "iterations": uint64(4), "docFetches": uint64(3), - "fieldFetches": uint64(5), + "fieldFetches": uint64(11), "indexFetches": uint64(0), }, }, @@ -113,13 +113,13 @@ func TestExecuteExplainRequest_MinOfRelatedOneToManyField_Succeeds(t *testing.T) "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(5), "docFetches": uint64(6), - "fieldFetches": uint64(12), + "fieldFetches": uint64(18), "indexFetches": uint64(0), }, }, diff --git a/tests/integration/explain/execute/with_order_test.go b/tests/integration/explain/execute/with_order_test.go index bbb2312c38..0ea9530445 100644 --- a/tests/integration/explain/execute/with_order_test.go +++ b/tests/integration/explain/execute/with_order_test.go @@ -53,7 +53,7 @@ func TestExecuteExplainRequestWithOrderFieldOnParent(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(4), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, }, @@ -195,13 +195,13 @@ func TestExecuteExplainRequestWithOrderFieldOnChild(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(5), "docFetches": uint64(6), - "fieldFetches": uint64(12), + "fieldFetches": uint64(18), "indexFetches": uint64(0), }, }, @@ -260,13 +260,13 @@ func TestExecuteExplainRequestWithOrderFieldOnBothParentAndChild(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(4), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(5), "docFetches": uint64(6), - "fieldFetches": uint64(12), + "fieldFetches": uint64(18), "indexFetches": uint64(0), }, }, diff --git a/tests/integration/explain/execute/with_sum_test.go b/tests/integration/explain/execute/with_sum_test.go index c7d614bf2f..736825c0da 100644 --- a/tests/integration/explain/execute/with_sum_test.go +++ b/tests/integration/explain/execute/with_sum_test.go @@ -54,7 +54,7 @@ func TestExecuteExplainRequestWithSumOfInlineArrayField(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(4), "docFetches": uint64(3), - "fieldFetches": uint64(5), + "fieldFetches": uint64(11), "indexFetches": uint64(0), }, }, @@ -113,13 +113,13 @@ func TestExecuteExplainRequestSumOfRelatedOneToManyField(t *testing.T) { "scanNode": dataMap{ "iterations": uint64(3), "docFetches": uint64(2), - "fieldFetches": uint64(2), + "fieldFetches": uint64(8), "indexFetches": uint64(0), }, "subTypeScanNode": dataMap{ "iterations": uint64(5), "docFetches": uint64(6), - "fieldFetches": uint64(12), + "fieldFetches": uint64(18), "indexFetches": uint64(0), }, }, diff --git a/tests/integration/index/array_test.go b/tests/integration/index/array_test.go index 096ecb87e1..f1ee1b56ef 100644 --- a/tests/integration/index/array_test.go +++ b/tests/integration/index/array_test.go @@ -122,7 +122,7 @@ func TestArrayIndex_WithFilterOnIndexedArrayUsingAll_ShouldUseIndex(t *testing.T testUtils.ExecuteTestCase(t, test) } -func TestArrayIndex_WithFilterOnIndexedArrayUsingNone_ShouldUseIndex(t *testing.T) { +func TestArrayIndex_WithFilterOnIndexedArrayUsingNone_ShouldNotUseIndex(t *testing.T) { req := `query { User(filter: {numbers: {_none: {_ge: 33}}}) { name @@ -166,8 +166,9 @@ func TestArrayIndex_WithFilterOnIndexedArrayUsingNone_ShouldUseIndex(t *testing. }, }, testUtils.Request{ - Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithIndexFetches(9), + Request: makeExplainQuery(req), + // index is not used for _none operator as it might be even less optimal than full scan + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(0), }, }, } diff --git a/tests/integration/index/json_composite_test.go b/tests/integration/index/json_composite_test.go index 187ed99334..9a0bfc867b 100644 --- a/tests/integration/index/json_composite_test.go +++ b/tests/integration/index/json_composite_test.go @@ -222,7 +222,7 @@ func TestJSONCompositeIndex_JSONWithScalarWithOtherFilters_ShouldFetchUsingIndex req: `query { User(filter: { age: {_le: 35}, - custom: {val: {_gt: 4}} + custom: {val: {_gt: 4}} }) { name } @@ -240,7 +240,7 @@ func TestJSONCompositeIndex_JSONWithScalarWithOtherFilters_ShouldFetchUsingIndex req: `query { User(filter: { age: {_lt: 100}, - custom: {val: {_eq: null}} + custom: {val: {_eq: null}} }) { name } @@ -267,7 +267,7 @@ func TestJSONCompositeIndex_JSONWithScalarWithOtherFilters_ShouldFetchUsingIndex {"name": "Chris"}, }, }, - indexFetches: 0, + indexFetches: 8, }, } diff --git a/tests/integration/index/json_test.go b/tests/integration/index/json_test.go index d154248501..749192a105 100644 --- a/tests/integration/index/json_test.go +++ b/tests/integration/index/json_test.go @@ -419,8 +419,10 @@ func TestJSONIndex_WithNeFilterOnNumberField_ShouldUseIndex(t *testing.T) { Request: req, Results: map[string]any{ "User": []map[string]any{ + {"name": "Bruno"}, {"name": "John"}, {"name": "Andy"}, + {"name": "Keenan"}, }, }, }, @@ -803,6 +805,8 @@ func TestJSONIndex_WithNeFilterOnBoolField_ShouldUseIndex(t *testing.T) { Request: req, Results: map[string]any{ "User": []map[string]any{ + {"name": "Bruno"}, + {"name": "Keenan"}, {"name": "Islam"}, {"name": "John"}, }, @@ -1301,12 +1305,239 @@ func TestJSONIndex_WithCompoundFilterCondition_ShouldUseIndex(t *testing.T) { }, }, testUtils.Request{ - Request: makeExplainQuery(req), - // TODO: this test doesn't utilize indexes. https://github.com/sourcenetwork/defradb/issues/3299 - Asserter: testUtils.NewExplainAsserter().WithIndexFetches(0), + Request: makeExplainQuery(req), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestJSONIndex_WithNeFilterAgainstNumberField_ShouldFetchNullValues(t *testing.T) { + req := `query { + User(filter: {custom: {age: {_ne: 48}}}) { + name + } + }` + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + custom: JSON @index + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "custom": map[string]any{ + "age": 48, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "custom": map[string]any{ + "age": nil, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "custom": map[string]any{ + "age": 42, + }, + }, + }, + testUtils.Request{ + Request: req, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Andy"}, + {"name": "Shahzad"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} + +func TestJSONIndex_WithNeFilterAgainstStringField_ShouldFetchNullValues(t *testing.T) { + req := `query { + User(filter: {custom: {city: {_ne: "Istanbul"}}}) { + name + } + }` + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + custom: JSON @index + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "custom": map[string]any{ + "city": "Istanbul", + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "custom": map[string]any{ + "city": nil, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "custom": map[string]any{ + "city": "Lucerne", + }, + }, + }, + testUtils.Request{ + Request: req, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Andy"}, + {"name": "Shahzad"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), }, }, } + testUtils.ExecuteTestCase(t, test) +} +func TestJSONIndex_WithNeFilterAgainstBoolField_ShouldFetchNullValues(t *testing.T) { + req := `query { + User(filter: {custom: {verified: {_ne: true}}}) { + name + } + }` + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + custom: JSON @index + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "custom": map[string]any{ + "verified": true, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "custom": map[string]any{ + "verified": nil, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "custom": map[string]any{ + "verified": false, + }, + }, + }, + testUtils.Request{ + Request: req, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Andy"}, + {"name": "Shahzad"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} + +func TestJSONIndex_WithNeFilterAgainstNullField_ShouldFetchNonNullValues(t *testing.T) { + req := `query { + User(filter: {custom: {age: {_ne: null}}}) { + name + } + }` + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + custom: JSON @index + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "custom": map[string]any{ + "age": 48, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "custom": map[string]any{ + "age": nil, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "custom": map[string]any{ + "age": 42, + }, + }, + }, + testUtils.Request{ + Request: req, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Shahzad"}, + {"name": "John"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + }, + } testUtils.ExecuteTestCase(t, test) } diff --git a/tests/integration/index/query_with_composite_index_only_filter_test.go b/tests/integration/index/query_with_composite_index_only_filter_test.go index 63e704cc78..c2dfcd898c 100644 --- a/tests/integration/index/query_with_composite_index_only_filter_test.go +++ b/tests/integration/index/query_with_composite_index_only_filter_test.go @@ -59,7 +59,7 @@ func TestQueryWithCompositeIndex_WithEqualFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req1), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(1), }, testUtils.Request{ Request: req2, @@ -71,7 +71,7 @@ func TestQueryWithCompositeIndex_WithEqualFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req2), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(1), }, testUtils.Request{ Request: req3, @@ -115,7 +115,7 @@ func TestQueryWithCompositeIndex_WithGreaterThanFilterOnFirstField_ShouldFetch(t }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -153,7 +153,7 @@ func TestQueryWithCompositeIndex_WithGreaterThanFilterOnSecondField_ShouldFetch( }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -192,7 +192,7 @@ func TestQueryWithCompositeIndex_WithGreaterOrEqualFilterOnFirstField_ShouldFetc }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -231,7 +231,7 @@ func TestQueryWithCompositeIndex_WithGreaterOrEqualFilterOnSecondField_ShouldFet }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -269,7 +269,7 @@ func TestQueryWithCompositeIndex_WithLessThanFilterOnFirstField_ShouldFetch(t *t }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -307,7 +307,7 @@ func TestQueryWithCompositeIndex_WithLessThanFilterOnSecondField_ShouldFetch(t * }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -346,7 +346,7 @@ func TestQueryWithCompositeIndex_WithLessOrEqualFilterOnFirstField_ShouldFetch(t }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -385,7 +385,7 @@ func TestQueryWithCompositeIndex_WithLessOrEqualFilterOnSecondField_ShouldFetch( }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -430,7 +430,7 @@ func TestQueryWithCompositeIndex_WithNotEqualFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -469,7 +469,7 @@ func TestQueryWithCompositeIndex_WithInFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(3), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), }, }, } @@ -509,7 +509,7 @@ func TestQueryWithCompositeIndex_WithNotInFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -576,7 +576,7 @@ func TestQueryWithCompositeIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req1), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req2, @@ -588,7 +588,7 @@ func TestQueryWithCompositeIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req2), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req3, @@ -600,7 +600,7 @@ func TestQueryWithCompositeIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req3), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req4, @@ -612,7 +612,7 @@ func TestQueryWithCompositeIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req4), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req5, @@ -624,7 +624,7 @@ func TestQueryWithCompositeIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req5), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req6, @@ -676,7 +676,7 @@ func TestQueryWithCompositeIndex_WithNotLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -705,7 +705,7 @@ func TestQueryWithCompositeIndex_IfFirstFieldIsNotInFilter_ShouldNotUseIndex(t * name } }`, - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(20).WithIndexFetches(0), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(0), }, }, } @@ -968,7 +968,7 @@ func TestQueryWithCompositeIndex_IfConsecutiveEqOps_ShouldUseAllToOptimizeQuery( }, testUtils.Request{ Request: makeExplainQuery(reqWithName), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(4).WithIndexFetches(4), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(4), }, testUtils.Request{ Request: reqWithNameAge, @@ -982,7 +982,7 @@ func TestQueryWithCompositeIndex_IfConsecutiveEqOps_ShouldUseAllToOptimizeQuery( }, testUtils.Request{ Request: makeExplainQuery(reqWithNameAge), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(3).WithIndexFetches(3), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), }, testUtils.Request{ Request: reqWithNameAgeNumChildren, @@ -995,7 +995,7 @@ func TestQueryWithCompositeIndex_IfConsecutiveEqOps_ShouldUseAllToOptimizeQuery( }, testUtils.Request{ Request: makeExplainQuery(reqWithNameAgeNumChildren), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, }, } diff --git a/tests/integration/index/query_with_index_combined_filter_test.go b/tests/integration/index/query_with_index_combined_filter_test.go index 0a6251db46..9d0572d2df 100644 --- a/tests/integration/index/query_with_index_combined_filter_test.go +++ b/tests/integration/index/query_with_index_combined_filter_test.go @@ -48,7 +48,7 @@ func TestQueryWithIndex_IfIndexFilterWithRegular_ShouldFilter(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(3).WithIndexFetches(3), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), }, }, } @@ -90,7 +90,7 @@ func TestQueryWithIndex_IfMultipleIndexFiltersWithRegular_ShouldFilter(t *testin }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(12), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -132,7 +132,7 @@ func TestQueryWithIndex_IfMultipleIndexFiltersWithRegularCaseInsensitive_ShouldF }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(6), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } diff --git a/tests/integration/index/query_with_index_on_datetime_test.go b/tests/integration/index/query_with_index_on_datetime_test.go index 6efb8d5644..8633c626d6 100644 --- a/tests/integration/index/query_with_index_on_datetime_test.go +++ b/tests/integration/index/query_with_index_on_datetime_test.go @@ -53,7 +53,7 @@ func TestQueryWithIndex_WithEqFilterOnDateTimeField_ShouldIndex(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(1), }, }, } diff --git a/tests/integration/index/query_with_index_only_filter_test.go b/tests/integration/index/query_with_index_only_filter_test.go index f0aab40546..8411ebaa2a 100644 --- a/tests/integration/index/query_with_index_only_filter_test.go +++ b/tests/integration/index/query_with_index_only_filter_test.go @@ -49,7 +49,7 @@ func TestQueryWithIndex_WithNonIndexedFields_ShouldFetchAllOfThem(t *testing.T) }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(1), }, }, } @@ -85,7 +85,7 @@ func TestQueryWithIndex_WithEqualFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(1), }, }, } @@ -130,7 +130,7 @@ func TestQueryWithIndex_IfSeveralDocsWithEqFilter_ShouldFetchAll(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, }, } @@ -167,7 +167,7 @@ func TestQueryWithIndex_WithGreaterThanFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -205,7 +205,7 @@ func TestQueryWithIndex_WithGreaterOrEqualFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -242,7 +242,7 @@ func TestQueryWithIndex_WithLessThanFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -280,7 +280,7 @@ func TestQueryWithIndex_WithLessOrEqualFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -325,7 +325,7 @@ func TestQueryWithIndex_WithNotEqualFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -363,7 +363,7 @@ func TestQueryWithIndex_WithInFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, }, } @@ -463,7 +463,7 @@ func TestQueryWithIndex_IfSeveralDocsWithInFilter_ShouldFetchAll(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, }, } @@ -503,7 +503,7 @@ func TestQueryWithIndex_WithNotInFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(4).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -566,7 +566,7 @@ func TestQueryWithIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req1), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req2, @@ -579,7 +579,7 @@ func TestQueryWithIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req2), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req3, @@ -592,7 +592,7 @@ func TestQueryWithIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req3), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req4, @@ -604,7 +604,7 @@ func TestQueryWithIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req4), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req5, @@ -617,7 +617,7 @@ func TestQueryWithIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req5), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req6, @@ -627,7 +627,7 @@ func TestQueryWithIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req6), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -670,7 +670,7 @@ func TestQueryWithIndex_WithNotLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -804,3 +804,348 @@ func TestQueryWithIndex_WithFilterOn2Relations_ShouldFilter(t *testing.T) { testUtils.ExecuteTestCase(t, test) } + +func TestQueryWithIndex_WithNeFilterAgainstIntField_ShouldFetchNilValues(t *testing.T) { + req1 := `query { + User(filter: {age: {_ne: 48}}) { + name + } + }` + req2 := `query { + User(filter: {age: {_ne: null}}) { + name + } + }` + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + age: Int @index + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "age": 48, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "age": nil, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "age": 42, + }, + }, + testUtils.Request{ + Request: req1, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Andy"}, + {"name": "Shahzad"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + testUtils.Request{ + Request: req2, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Shahzad"}, + {"name": "John"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} + +func TestQueryWithIndex_WithNeFilterAgainstFloatField_ShouldFetchNilValues(t *testing.T) { + req1 := `query { + User(filter: {rating: {_ne: 4.5}}) { + name + } + }` + req2 := `query { + User(filter: {rating: {_ne: null}}) { + name + } + }` + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + rating: Float @index + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "rating": 4.5, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "rating": nil, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "rating": 4.2, + }, + }, + testUtils.Request{ + Request: req1, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Andy"}, + {"name": "Shahzad"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + testUtils.Request{ + Request: req2, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Shahzad"}, + {"name": "John"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} + +func TestQueryWithIndex_WithNeFilterAgainstStringField_ShouldFetchNilValues(t *testing.T) { + req1 := `query { + User(filter: {city: {_ne: "Istanbul"}}) { + name + } + }` + req2 := `query { + User(filter: {city: {_ne: null}}) { + name + } + }` + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + city: String @index + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "city": "Istanbul", + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "city": nil, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "city": "Lucerne", + }, + }, + testUtils.Request{ + Request: req1, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Andy"}, + {"name": "Shahzad"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + testUtils.Request{ + Request: req2, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "John"}, + {"name": "Shahzad"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} + +func TestQueryWithIndex_WithNeFilterAgainstDateTimeField_ShouldFetchNilValues(t *testing.T) { + req1 := `query { + User(filter: {birthdate: {_ne: "2020-01-01T00:00:00Z"}}) { + name + } + }` + req2 := `query { + User(filter: {birthdate: {_ne: null}}) { + name + } + }` + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + birthdate: DateTime @index + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "birthdate": "2020-01-01T00:00:00Z", + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "birthdate": nil, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "birthdate": "2024-01-01T00:00:00Z", + }, + }, + testUtils.Request{ + Request: req1, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Andy"}, + {"name": "Shahzad"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + testUtils.Request{ + Request: req2, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "John"}, + {"name": "Shahzad"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} + +func TestQueryWithIndex_WithNeFilterAgainstBooleanField_ShouldFetchNilValues(t *testing.T) { + req1 := `query { + User(filter: {verified: {_ne: true}}) { + name + } + }` + req2 := `query { + User(filter: {verified: {_ne: null}}) { + name + } + }` + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + verified: Boolean @index + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "verified": true, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "verified": nil, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "verified": false, + }, + }, + testUtils.Request{ + Request: req1, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Andy"}, + {"name": "Shahzad"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + testUtils.Request{ + Request: req2, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Shahzad"}, + {"name": "John"}, + }, + }, + }, + testUtils.Request{ + Request: makeExplainQuery(req2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/index/query_with_relation_filter_test.go b/tests/integration/index/query_with_relation_filter_test.go index fa7fb6c443..ee1dd21e41 100644 --- a/tests/integration/index/query_with_relation_filter_test.go +++ b/tests/integration/index/query_with_relation_filter_test.go @@ -16,74 +16,6 @@ import ( testUtils "github.com/sourcenetwork/defradb/tests/integration" ) -func TestQueryWithIndexOnOneToManyRelation_IfFilterOnIndexedRelation_ShouldFilter2(t *testing.T) { - // 3 users have a MacBook Pro: Islam, Shahzad, Keenan - req1 := `query { - User(filter: { - devices: {model: {_eq: "MacBook Pro"}} - }) { - name - } - }` - // 1 user has an iPhone 10: Addo - req2 := `query { - User(filter: { - devices: {model: {_eq: "iPhone 10"}} - }) { - name - } - }` - test := testUtils.TestCase{ - Description: "Filter on indexed relation field in 1-N relation", - Actions: []any{ - testUtils.SchemaUpdate{ - Schema: ` - type User { - name: String - age: Int - devices: [Device] - } - - type Device { - model: String @index - owner: User - }`, - }, - testUtils.CreatePredefinedDocs{ - Docs: getUserDocs(), - }, - testUtils.Request{ - Request: req1, - Results: map[string]any{ - "User": []map[string]any{ - {"name": "Shahzad"}, - {"name": "Islam"}, - {"name": "Keenan"}, - }, - }, - }, - testUtils.Request{ - Request: makeExplainQuery(req1), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(6).WithIndexFetches(3), - }, - testUtils.Request{ - Request: req2, - Results: map[string]any{ - "User": []map[string]any{ - {"name": "Addo"}, - }, - }, - }, - testUtils.Request{ - Request: makeExplainQuery(req2), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(1), - }, - }, - } - - testUtils.ExecuteTestCase(t, test) -} - func TestQueryWithIndexOnOneToManyRelation_IfFilterOnIndexedRelation_ShouldFilter(t *testing.T) { // 3 users have a MacBook Pro: Islam, Shahzad, Keenan req1 := `query { @@ -132,7 +64,7 @@ func TestQueryWithIndexOnOneToManyRelation_IfFilterOnIndexedRelation_ShouldFilte }, testUtils.Request{ Request: makeExplainQuery(req1), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(6).WithIndexFetches(3), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), }, testUtils.Request{ Request: req2, @@ -144,7 +76,7 @@ func TestQueryWithIndexOnOneToManyRelation_IfFilterOnIndexedRelation_ShouldFilte }, testUtils.Request{ Request: makeExplainQuery(req2), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(1), }, }, } @@ -198,7 +130,7 @@ func TestQueryWithIndexOnOneToOnesSecondaryRelation_IfFilterOnIndexedRelation_Sh }, testUtils.Request{ Request: makeExplainQuery(req1), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(1), }, testUtils.Request{ Request: req2, @@ -212,7 +144,7 @@ func TestQueryWithIndexOnOneToOnesSecondaryRelation_IfFilterOnIndexedRelation_Sh }, testUtils.Request{ Request: makeExplainQuery(req2), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(6).WithIndexFetches(3), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), }, }, } @@ -269,8 +201,7 @@ func TestQueryWithIndexOnOneToOnePrimaryRelation_IfFilterOnIndexedFieldOfRelatio Request: makeExplainQuery(req1), // we make 2 index fetches: 1. to get the only address with city == "London" // and 2. to get the corresponding user - // then 1 field fetch to get the name of the user - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, testUtils.Request{ Request: req2, @@ -286,8 +217,7 @@ func TestQueryWithIndexOnOneToOnePrimaryRelation_IfFilterOnIndexedFieldOfRelatio Request: makeExplainQuery(req2), // we make 3 index fetches to get the 3 address with city == "Montreal" // and 3 more index fetches to get the corresponding users - // then 3 field fetches to get the name of each user - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(3).WithIndexFetches(6), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(6), }, }, } @@ -343,9 +273,10 @@ func TestQueryWithIndexOnOneToOnePrimaryRelation_IfFilterOnIndexedFieldOfRelatio testUtils.Request{ Request: makeExplainQuery(req1), // we make 1 index fetch to get the only address with city == "London" + // we fetch 2 fields for Address doc: "city" and "street" // then we scan all 10 users to find one with matching "address_id" - // after this we fetch the name of the user - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(20).WithIndexFetches(1), + // for each of User docs we fetch 3 fields: "name", "age" and "address_id" + Asserter: testUtils.NewExplainAsserter().WithFieldFetches(32).WithIndexFetches(1), }, testUtils.Request{ Request: req2, @@ -362,7 +293,7 @@ func TestQueryWithIndexOnOneToOnePrimaryRelation_IfFilterOnIndexedFieldOfRelatio // we make 3 index fetch to get the 3 address with city == "Montreal" // then we scan all 10 users to find one with matching "address_id" for each address // after this we fetch the name of each user - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(60).WithIndexFetches(3), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), }, }, } @@ -409,7 +340,7 @@ func TestQueryWithIndexOnOneToOnePrimaryRelation_IfFilterOnIndexedRelationWhileI }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, }, } @@ -417,7 +348,7 @@ func TestQueryWithIndexOnOneToOnePrimaryRelation_IfFilterOnIndexedRelationWhileI testUtils.ExecuteTestCase(t, test) } -func TestQueryWithIndexOnOneToMany_IfFilterOnIndexedRelation_ShouldFilter(t *testing.T) { +func TestQueryWithIndexOnOneToMany_IfFilterOnIndexedPrimaryDoc_ShouldFilter(t *testing.T) { test := testUtils.TestCase{ Description: "Filter on indexed relation field in 1-N relations", Actions: []any{ @@ -512,6 +443,96 @@ func TestQueryWithIndexOnOneToMany_IfFilterOnIndexedRelation_ShouldFilter(t *tes testUtils.ExecuteTestCase(t, test) } +func TestQueryWithIndexOnOneToMany_IfFilterOnIndexedPrimaryDocAndSubFilter_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Filter on indexed relation field in 1-N relations", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + devices: [Device] + } + + type Device { + model: String @index + manufacturer: String + owner: User + } + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "name": "Chris" + }`, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "name": "Addo" + }`, + }, + testUtils.CreateDoc{ + CollectionID: 1, + DocMap: map[string]any{ + "model": "Walkman", + "manufacturer": "Sony", + "owner": testUtils.NewDocIndex(0, 0), + }, + }, + testUtils.CreateDoc{ + CollectionID: 1, + DocMap: map[string]any{ + "model": "Walkman", + "manufacturer": "The Proclaimers", + "owner": testUtils.NewDocIndex(0, 0), + }, + }, + testUtils.CreateDoc{ + CollectionID: 1, + DocMap: map[string]any{ + "model": "Running Man", + "manufacturer": "Braveworld Productions", + "owner": testUtils.NewDocIndex(0, 0), + }, + }, + testUtils.Request{ + Request: `query { + User(filter: { + devices: {model: {_eq: "Walkman"}} + }) { + name + devices(filter: {manufacturer: {_ne: "Sony"}}) { + model + manufacturer + } + } + }`, + Results: map[string]any{ + "User": []map[string]any{ + { + "name": "Chris", + "devices": []map[string]any{ + { + "model": "Walkman", + "manufacturer": "The Proclaimers", + }, + { + "model": "Running Man", + "manufacturer": "Braveworld Productions", + }, + }, + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + func TestQueryWithIndexOnOneToMany_IfFilterOnIndexedRelation_ShouldFilterWithExplain(t *testing.T) { req := `query { User(filter: { @@ -597,7 +618,7 @@ func TestQueryWithIndexOnOneToMany_IfFilterOnIndexedRelation_ShouldFilterWithExp }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(14).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, }, } @@ -651,7 +672,7 @@ func TestQueryWithIndexOnOneToOne_IfFilterOnIndexedRelation_ShouldFilter(t *test }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(1), }, }, } @@ -720,8 +741,7 @@ func TestQueryWithIndexOnManyToOne_IfFilterOnIndexedField_ShouldFilterWithExplai testUtils.Request{ Request: makeExplainQuery(req), // we make 3 index fetches to get all 3 devices with year 2021 - // and 9 field fetches: for every device we fetch additionally "model", "owner_id" and owner's "name" - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(9).WithIndexFetches(3), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), }, }, } @@ -773,8 +793,7 @@ func TestQueryWithIndexOnManyToOne_IfFilterOnIndexedRelation_ShouldFilterWithExp Request: makeExplainQuery(req), // we make 1 index fetch to get the owner by it's name // and 3 index fetches to get all 3 devices of the owner - // and 3 field fetches to get 1 'model' field for every fetched device. - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(3).WithIndexFetches(4), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(4), }, }, } @@ -855,9 +874,7 @@ func TestQueryWithIndexOnOneToMany_IfIndexedRelationIsNil_NeNilFilterShouldUseIn testUtils.Request{ Request: makeExplainQuery(req), // we make 4 index fetches to find 2 devices with owner_id != null - // and 2 field fetches to get 1 'model' field for every fetched device - // plus 2 more field fetches to get related User docs - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(4).WithIndexFetches(4), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(4), }, }, } @@ -938,8 +955,7 @@ func TestQueryWithIndexOnOneToMany_IfIndexedRelationIsNil_EqNilFilterShouldUseIn testUtils.Request{ Request: makeExplainQuery(req), // we make 2 index fetches to get all 2 devices with owner_id == null - // and 2 field fetches to get 1 'model' field for every fetched device. - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, }, } diff --git a/tests/integration/index/query_with_unique_composite_index_filter_test.go b/tests/integration/index/query_with_unique_composite_index_filter_test.go index 9928cb684b..3d041a0d66 100644 --- a/tests/integration/index/query_with_unique_composite_index_filter_test.go +++ b/tests/integration/index/query_with_unique_composite_index_filter_test.go @@ -77,7 +77,7 @@ func TestQueryWithUniqueCompositeIndex_WithEqualFilter_ShouldFetch(t *testing.T) }, testUtils.Request{ Request: makeExplainQuery(req1), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(3), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(3), }, testUtils.Request{ Request: req2, @@ -89,7 +89,7 @@ func TestQueryWithUniqueCompositeIndex_WithEqualFilter_ShouldFetch(t *testing.T) }, testUtils.Request{ Request: makeExplainQuery(req2), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(1), }, testUtils.Request{ Request: req3, @@ -133,7 +133,7 @@ func TestQueryWithUniqueCompositeIndex_WithGreaterThanFilterOnFirstField_ShouldF }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -171,7 +171,7 @@ func TestQueryWithUniqueCompositeIndex_WithGreaterThanFilterOnSecondField_Should }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -210,7 +210,7 @@ func TestQueryWithUniqueCompositeIndex_WithGreaterOrEqualFilterOnFirstField_Shou }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -249,7 +249,7 @@ func TestQueryWithUniqueCompositeIndex_WithGreaterOrEqualFilterOnSecondField_Sho }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -287,7 +287,7 @@ func TestQueryWithUniqueCompositeIndex_WithLessThanFilterOnFirstField_ShouldFetc }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -325,7 +325,7 @@ func TestQueryWithUniqueCompositeIndex_WithLessThanFilterOnSecondField_ShouldFet }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -364,7 +364,7 @@ func TestQueryWithUniqueCompositeIndex_WithLessOrEqualFilterOnFirstField_ShouldF }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -403,7 +403,7 @@ func TestQueryWithUniqueCompositeIndex_WithLessOrEqualFilterOnSecondField_Should }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -448,7 +448,7 @@ func TestQueryWithUniqueCompositeIndex_WithNotEqualFilter_ShouldFetch(t *testing }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -525,7 +525,7 @@ func TestQueryWithUniqueCompositeIndex_WithInForFirstAndEqForRest_ShouldFetchEff }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, }, } @@ -580,7 +580,7 @@ func TestQueryWithUniqueCompositeIndex_WithInFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(5), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(5), }, }, } @@ -620,7 +620,7 @@ func TestQueryWithUniqueCompositeIndex_WithNotInFilter_ShouldFetch(t *testing.T) }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -687,7 +687,7 @@ func TestQueryWithUniqueCompositeIndex_WithLikeFilter_ShouldFetch(t *testing.T) }, testUtils.Request{ Request: makeExplainQuery(req1), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req2, @@ -699,7 +699,7 @@ func TestQueryWithUniqueCompositeIndex_WithLikeFilter_ShouldFetch(t *testing.T) }, testUtils.Request{ Request: makeExplainQuery(req2), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req3, @@ -711,7 +711,7 @@ func TestQueryWithUniqueCompositeIndex_WithLikeFilter_ShouldFetch(t *testing.T) }, testUtils.Request{ Request: makeExplainQuery(req3), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req4, @@ -723,7 +723,7 @@ func TestQueryWithUniqueCompositeIndex_WithLikeFilter_ShouldFetch(t *testing.T) }, testUtils.Request{ Request: makeExplainQuery(req4), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req5, @@ -735,7 +735,7 @@ func TestQueryWithUniqueCompositeIndex_WithLikeFilter_ShouldFetch(t *testing.T) }, testUtils.Request{ Request: makeExplainQuery(req5), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req6, @@ -787,7 +787,7 @@ func TestQueryWithUniqueCompositeIndex_WithNotLikeFilter_ShouldFetch(t *testing. }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -828,7 +828,7 @@ func TestQueryWithUniqueCompositeIndex_WithNotCaseInsensitiveLikeFilter_ShouldFe }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -857,7 +857,7 @@ func TestQueryWithUniqueCompositeIndex_IfFirstFieldIsNotInFilter_ShouldNotUseInd name } }`, - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(20).WithIndexFetches(0), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(0), }, }, } @@ -967,7 +967,7 @@ func TestQueryWithUniqueCompositeIndex_WithMultipleNilOnFirstFieldAndNilFilter_S }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, }, } @@ -1099,7 +1099,7 @@ func TestQueryWithUniqueCompositeIndex_WithMultipleNilOnSecondFieldsAndNilFilter }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, }, } diff --git a/tests/integration/index/query_with_unique_index_only_filter_test.go b/tests/integration/index/query_with_unique_index_only_filter_test.go index 4da1bb63ed..1876c3522d 100644 --- a/tests/integration/index/query_with_unique_index_only_filter_test.go +++ b/tests/integration/index/query_with_unique_index_only_filter_test.go @@ -44,7 +44,7 @@ func TestQueryWithUniqueIndex_WithEqualFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(1), }, }, } @@ -81,7 +81,7 @@ func TestQueryWithUniqueIndex_WithGreaterThanFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -119,7 +119,7 @@ func TestQueryWithUniqueIndex_WithGreaterOrEqualFilter_ShouldFetch(t *testing.T) }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -156,7 +156,7 @@ func TestQueryWithUniqueIndex_WithLessThanFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -194,7 +194,7 @@ func TestQueryWithUniqueIndex_WithLessOrEqualFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -239,7 +239,7 @@ func TestQueryWithUniqueIndex_WithNotEqualFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -277,7 +277,7 @@ func TestQueryWithUniqueIndex_WithInFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(2), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(2), }, }, } @@ -317,7 +317,7 @@ func TestQueryWithUniqueIndex_WithNotInFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(4).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -380,7 +380,7 @@ func TestQueryWithUniqueIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req1), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req2, @@ -393,7 +393,7 @@ func TestQueryWithUniqueIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req2), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req3, @@ -406,7 +406,7 @@ func TestQueryWithUniqueIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req3), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req4, @@ -418,7 +418,7 @@ func TestQueryWithUniqueIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req4), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req5, @@ -431,7 +431,7 @@ func TestQueryWithUniqueIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req5), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(2).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, testUtils.Request{ Request: req6, @@ -441,7 +441,7 @@ func TestQueryWithUniqueIndex_WithLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req6), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -484,7 +484,7 @@ func TestQueryWithUniqueIndex_WithNotLikeFilter_ShouldFetch(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -528,7 +528,7 @@ func TestQueryWithUniqueIndex_WithNotCaseInsensitiveLikeFilter_ShouldFetch(t *te }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(10), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(10), }, }, } @@ -818,7 +818,7 @@ func TestQueryWithUniqueIndex_WithDateTimeField_ShouldIndex(t *testing.T) { }, testUtils.Request{ Request: makeExplainQuery(req), - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithIndexFetches(1), }, }, } diff --git a/tests/integration/query/json/with_ne_test.go b/tests/integration/query/json/with_ne_test.go index 6a4d619552..dd55b60bf1 100644 --- a/tests/integration/query/json/with_ne_test.go +++ b/tests/integration/query/json/with_ne_test.go @@ -163,3 +163,211 @@ func TestQueryJSON_WithNotEqualFilterWithNullValue_ShouldFilter(t *testing.T) { testUtils.ExecuteTestCase(t, test) } + +func TestQueryJSON_WithNeFilterAgainstNumberField_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + custom: JSON + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "custom": map[string]any{ + "age": 48, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "custom": map[string]any{ + "age": nil, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "custom": map[string]any{ + "age": 42, + }, + }, + }, + testUtils.Request{ + Request: `query { + User(filter: {custom: {age: {_ne: 48}}}) { + name + } + }`, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Shahzad"}, + {"name": "Andy"}, + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} + +func TestQueryJSON_WithNeFilterAgainstStringField_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + custom: JSON + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "custom": map[string]any{ + "city": "Istanbul", + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "custom": map[string]any{ + "city": nil, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "custom": map[string]any{ + "city": "Lucerne", + }, + }, + }, + testUtils.Request{ + Request: `query { + User(filter: {custom: {city: {_ne: "Istanbul"}}}) { + name + } + }`, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Shahzad"}, + {"name": "Andy"}, + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} + +func TestQueryJSON_WithNeFilterAgainstBooleanField_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + custom: JSON + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "custom": map[string]any{ + "verified": true, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "custom": map[string]any{ + "verified": nil, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "custom": map[string]any{ + "verified": false, + }, + }, + }, + testUtils.Request{ + Request: `query { + User(filter: {custom: {verified: {_ne: true}}}) { + name + } + }`, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Shahzad"}, + {"name": "Andy"}, + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} + +func TestQueryJSON_WithNeFilterAgainstNullField_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + custom: JSON + }`, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "custom": map[string]any{ + "age": 48, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "custom": map[string]any{ + "age": nil, + }, + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Shahzad", + "custom": map[string]any{ + "age": 42, + }, + }, + }, + testUtils.Request{ + Request: `query { + User(filter: {custom: {age: {_ne: null}}}) { + name + } + }`, + Results: map[string]any{ + "User": []map[string]any{ + {"name": "Shahzad"}, + {"name": "John"}, + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/schema/updates/add/field/with_index_test.go b/tests/integration/schema/updates/add/field/with_index_test.go index 3c80f6cede..c0a94ec081 100644 --- a/tests/integration/schema/updates/add/field/with_index_test.go +++ b/tests/integration/schema/updates/add/field/with_index_test.go @@ -95,7 +95,7 @@ func TestSchemaUpdatesAddFieldSimple_WithExistingIndexDocsCreatedAfterPatch(t *t name } }`, - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(1), }, }, } @@ -180,7 +180,7 @@ func TestSchemaUpdatesAddFieldSimple_WithExistingIndexDocsCreatedBeforePatch(t * name } }`, - Asserter: testUtils.NewExplainAsserter().WithFieldFetches(0).WithIndexFetches(1), + Asserter: testUtils.NewExplainAsserter().WithFieldFetches(1).WithIndexFetches(1), }, }, }