From 733e59ec9551a7ac7e9106b84dffc52da257a394 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Fri, 17 Feb 2023 09:17:22 +1100 Subject: [PATCH] Issue 47: Query expression planner now recognises GSIs (#48) The query expression planner now recognises GSIs, and will use them if the expression can be executed as a query over an index. --- go.mod | 9 +- go.sum | 104 ++---------------- .../controllers/tableread_test.go | 19 ++++ internal/dynamo-browse/models/query.go | 4 + .../dynamo-browse/models/queryexpr/ast.go | 50 ++++++--- .../dynamo-browse/models/queryexpr/comp.go | 8 +- .../dynamo-browse/models/queryexpr/conj.go | 18 +-- .../models/queryexpr/equality.go | 18 +-- .../dynamo-browse/models/queryexpr/expr.go | 13 ++- .../models/queryexpr/expr_test.go | 45 +++++++- internal/dynamo-browse/models/queryexpr/ir.go | 8 +- .../providers/dynamo/provider.go | 26 ++++- .../dynamo-browse/services/tables/iface.go | 1 + .../dynamo-browse/services/tables/service.go | 4 +- test/testdynamo/client.go | 26 ++++- 15 files changed, 190 insertions(+), 163 deletions(-) diff --git a/go.mod b/go.mod index ada9d15..4562fef 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/charmbracelet/bubbles v0.14.0 github.com/charmbracelet/bubbletea v0.22.1 github.com/charmbracelet/lipgloss v0.6.0 - github.com/google/uuid v1.3.0 + github.com/cloudcmds/tamarin v1.0.0 github.com/lmika/events v0.0.0-20200906102219-a2269cd4394e github.com/lmika/go-bubble-table v0.2.2-0.20220616114432-6bbb2995e538 github.com/lmika/gopkgs v0.0.0-20211210041137-0dc91e939890 @@ -29,10 +29,10 @@ require ( github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.1 golang.design/x/clipboard v0.6.2 + golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a ) require ( - atomicgo.dev/keyboard v0.2.8 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/Sereal/Sereal v0.0.0-20220220040404-e0d1e550e879 // indirect github.com/atotto/clipboard v0.1.4 // indirect @@ -48,10 +48,8 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect github.com/aws/smithy-go v1.13.5 // indirect github.com/aymanbagabas/go-osc52 v1.0.3 // indirect - github.com/cloudcmds/tamarin v1.0.0 // indirect github.com/containerd/console v1.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fatih/color v1.13.0 // indirect github.com/gofrs/uuid v4.3.1+incompatible // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -64,7 +62,6 @@ require ( github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lunixbochs/vtclean v1.0.0 // indirect - github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/muesli/cancelreader v0.2.2 // indirect @@ -80,7 +77,7 @@ require ( github.com/wI2L/jsondiff v0.3.0 // indirect go.etcd.io/bbolt v1.3.6 // indirect golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect - golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a // indirect + golang.org/x/exp/shiny v0.0.0-20230213192124-5e25df0256eb // indirect golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554 // indirect golang.org/x/sys v0.1.0 // indirect diff --git a/go.sum b/go.sum index 30ff8b7..ce47c1b 100644 --- a/go.sum +++ b/go.sum @@ -1,78 +1,46 @@ -atomicgo.dev/keyboard v0.2.8 h1:Di09BitwZgdTV1hPyX/b9Cqxi8HVuJQwWivnZUEqlj4= -atomicgo.dev/keyboard v0.2.8/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= -github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= -github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= -github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= -github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= -github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= -github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= github.com/Sereal/Sereal v0.0.0-20220220040404-e0d1e550e879 h1:M5ptEKnqKqpFTKbe+p5zEf3ro1deJ6opUz5j3g3/ErQ= github.com/Sereal/Sereal v0.0.0-20220220040404-e0d1e550e879/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM= -github.com/alecthomas/participle v0.7.1 h1:2bN7reTw//5f0cugJcTOnY/NYZcWQOaajW+BwZB5xWs= -github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= -github.com/alecthomas/participle/v2 v2.0.0-alpha7/go.mod h1:NumScqsC42o9x+dGj8/YqsIfhrIQjFEOFovxotbBirA= +github.com/alecthomas/assert/v2 v2.0.3 h1:WKqJODfOiQG0nEJKFKzDIG3E29CN2/4zR9XGJzKIkbg= github.com/alecthomas/participle/v2 v2.0.0-beta.5 h1:y6dsSYVb1G5eK6mgmy+BgI3Mw35a3WghArZ/Hbebrjo= github.com/alecthomas/participle/v2 v2.0.0-beta.5/go.mod h1:RC764t6n4L8D8ITAJv0qdokritYSNR3wV5cVwmIEaMM= -github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1 h1:GDQdwm/gAcJcLAKQQZGOJ4knlw+7rfEQQcmwTbt4p5E= -github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE= github.com/asdine/storm v2.1.2+incompatible h1:dczuIkyqwY2LrtXPz8ixMrU/OFgZp71kbKTHGrXYt/Q= github.com/asdine/storm v2.1.2+incompatible/go.mod h1:RarYDc9hq1UPLImuiXK3BIWPJLdIygvV3PsInK0FbVQ= -github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aws/aws-sdk-go-v2 v1.13.0/go.mod h1:L6+ZpqHaLbAaxsqV0L4cvxZY7QupWJB4fhkf8LXvC7w= github.com/aws/aws-sdk-go-v2 v1.16.1/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU= -github.com/aws/aws-sdk-go-v2 v1.16.5 h1:Ah9h1TZD9E2S1LzHpViBO3Jz9FPL5+rmflmb8hXirtI= -github.com/aws/aws-sdk-go-v2 v1.16.5/go.mod h1:Wh7MEsmEApyL5hrWzpDkba4gwAPc5/piwLVLFnCxp48= github.com/aws/aws-sdk-go-v2 v1.17.4 h1:wyC6p9Yfq6V2y98wfDsj6OnNQa4w2BLGCLIxzNhwOGY= github.com/aws/aws-sdk-go-v2 v1.17.4/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/config v1.13.1 h1:yLv8bfNoT4r+UvUKQKqRtdnvuWGMK5a82l4ru9Jvnuo= github.com/aws/aws-sdk-go-v2/config v1.13.1/go.mod h1:Ba5Z4yL/UGbjQUzsiaN378YobhFo0MLfueXGiOsYtEs= github.com/aws/aws-sdk-go-v2/credentials v1.8.0 h1:8Ow0WcyDesGNL0No11jcgb1JAtE+WtubqXjgxau+S0o= github.com/aws/aws-sdk-go-v2/credentials v1.8.0/go.mod h1:gnMo58Vwx3Mu7hj1wpcG8DI0s57c9o42UQ6wgTQT5to= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.9.4 h1:EoyeSOfbSuKh+bQIDoZaVJjON6PF+dsSn5w1RhIpMD0= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.9.4/go.mod h1:bfCL7OwZS6owS06pahfGxhcgpLWj2W1sQASoYRuenag= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.12 h1:ama2cD4WaH6+8Gq/M/g+ZumPmmqCyanr+6Sm+iJVxfA= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.12/go.mod h1:tPnUO5mS3JThpwfq4Q8iPd745s7yh6fGPqDUEBw+Wv4= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.4.10 h1:IBIZfpnWCTTQhH/bMvDcCMw10BtLBPYO30Ev8MLXMTY= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.4.10/go.mod h1:RL7aJOwlWj2N6wkE4nKR1S5M4iGph+xSu7JovwNYpyU= github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.4.39 h1:PhgfvgqwMFQKwOcxLV7V3lNDVnR3ZUWzoB6T9oCFpR4= github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.4.39/go.mod h1:/GkvC7uHpK50ilKkKx9I2gZiI/ieZbKjS2aah1rT9uE= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 h1:NITDuUZO34mqtOwFWZiXo7yAHj7kf+XPE+EiKuCBNUI= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0/go.mod h1:I6/fHT/fH460v09eg2gVrd8B/IqskhNdpcLH0WNO3QI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4/go.mod h1:XHgQ7Hz2WY2GAn//UXHofLfPXWh+s62MbMOijrg12Lw= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.8/go.mod h1:LnTQMTqbKsbtt+UI5+wPsB7jedW+2ZgozoPG8k6cMxg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12 h1:Zt7DDk5V7SyQULUUwIKzsROtVzp/kVvcz15uQx/Tkow= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12/go.mod h1:Afj/U8svX6sJ77Q+FPWMzabJ9QjbwP32YlopgKALUpg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28 h1:r+XwaCLpIvCKjBIYy/HVZujQS9tsz5ohHG3ZIe0wKoE= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28/go.mod h1:3lwChorpIM/BhImY/hy+Z6jekmN92cXGPI1QJasVPYY= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0/go.mod h1:BsCSJHx5DnDXIrOcqB8KN1/B+hXLG/bi4Y6Vjcx/x9E= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.2/go.mod h1:1x4ZP3Z8odssdhuLI+/1Tqw6Pt/VAaP4Tr8EUxHvPXE= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6 h1:eeXdGVtXEe+2Jc49+/vAzna3FAQnUD4AagAw8tzbmfc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6/go.mod h1:FwpAKI+FBPIELJIdmQzlLtRe8LQSOreMcM2wBsPMvvc= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 h1:7AwGYXDdqRQYsluvKFmWoqpcOQJ4bH634SkYf3FNj/A= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22/go.mod h1:EqK7gVrIGAHyZItrD1D8B0ilgwMD1GiWAmbU4u/JHNk= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5 h1:ixotxbfTCFpqbuwFv/RcZwyzhkxPSYDYEMcj4niB5Uk= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5/go.mod h1:R3sWUqPcfXSiF/LSFJhjyJmpg9uV6yP2yv3YZZjldVI= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.15.7 h1:Ls6kDGWNr3wxE8JypXgTTonHpQ1eRVCGNqaFHY2UASw= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.15.7/go.mod h1:+v2jeT4/39fCXUQ0ZfHQHMMiJljnmiuj16F03uAd9DY= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.18.3 h1:MxOpCZ+o9+AIeQHi2ocW7H4D7p0LhEkmetETVvDnkvg= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.18.3/go.mod h1:nkpC9xkh+3vdxmhqN8Ac10pgV14DsJDLzUsV2CcS+44= -github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.7 h1:o2HKntJx3vr3y11NK58RA6tYKZKQo5PWWt/bs0rWR0U= -github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.7/go.mod h1:FAVtDKEl/8WxRDQ33e2fz16RO1t4zeEwWIU5kR29xXs= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.14.3 h1:B+bkmCnNJi194pu9aTtYUe8f4EPXafC+xfU+zciVxdg= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.14.3/go.mod h1:bRphLmXQD9Ux4jLcFEwyrWdmuPTj2Lh8VGl9wILuJII= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.2 h1:T/ywkX1ed+TsZVQccu/8rRJGxKZF/t0Ivgrb4MHTSeo= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.2/go.mod h1:RnloUnyZ4KN9JStGY1LuQ7Wzqh7V0f8FinmRdHYtuaA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= -github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.6 h1:JGrc3+kkyr848/wpG2+kWuzHK3H4Fyxj2jnXj8ijQ/Y= -github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.6/go.mod h1:zwvTysbXES8GDwFcwCPB8NkC+bCdio1abH+E+BRe/xg= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.22 h1:6zEryIiJOSk5/OcVHzkPDwzNBQ2atYCTShyA7TqkuxA= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.22/go.mod h1:moeOz5SKfY0p6pNIChdPIQdfaUfWI67+OVe0/r6+aGY= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 h1:4QAOB3KrvI1ApJK14sliGr3Ie2pjyvNypn/lfzDHfUw= @@ -87,8 +55,6 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 h1:ksiDXhvNYg0D2/UFkLejsaz3LqpW github.com/aws/aws-sdk-go-v2/service/sts v1.14.0/go.mod h1:u0xMJKDvvfocRjiozsoZglVNXRG19043xzp3r2ivLIk= github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= -github.com/aws/smithy-go v1.11.3 h1:DQixirEFM9IaKxX1olZ3ke3nvxRS2xMDteKIDWxozW8= -github.com/aws/smithy-go v1.11.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aymanbagabas/go-osc52 v1.0.3 h1:DTwqENW7X9arYimJrPeGZcV0ln14sGMt3pHZspWD+Mg= @@ -97,23 +63,15 @@ github.com/brianvoe/gofakeit/v6 v6.15.0 h1:lJPGJZ2/07TRGDazyTzD5b18N3y4tmmJpdhCU github.com/brianvoe/gofakeit/v6 v6.15.0/go.mod h1:Ow6qC71xtwm79anlwKRlWZW6zVq9D2XHE4QSSMP/rU8= github.com/calyptia/go-bubble-table v0.2.1 h1:NWcVRyGCLuP7QIA29uUFSY+IjmWcmUWHjy5J/CPb0Rk= github.com/calyptia/go-bubble-table v0.2.1/go.mod h1:gJvzUOUzfQeA9JmgLumyJYWJMtuRQ7WxxTwc9tjEiGw= -github.com/charmbracelet/bubbles v0.11.0 h1:fBLyY0PvJnd56Vlu5L84JJH6f4axhgIJ9P3NET78f0Q= -github.com/charmbracelet/bubbles v0.11.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWoiNibae+1yCMtcc= github.com/charmbracelet/bubbles v0.14.0 h1:DJfCwnARfWjZLvMglhSQzo76UZ2gucuHPy9jLWX45Og= github.com/charmbracelet/bubbles v0.14.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWoiNibae+1yCMtcc= -github.com/charmbracelet/bubbletea v0.21.0 h1:f3y+kanzgev5PA916qxmDybSHU3N804uOnKnhRPXTcI= github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4= github.com/charmbracelet/bubbletea v0.22.1 h1:z66q0LWdJNOWEH9zadiAIXp2GN1AWrwNXU8obVY9X24= github.com/charmbracelet/bubbletea v0.22.1/go.mod h1:8/7hVvbPN6ZZPkczLiB8YpLkLJ0n7DMho5Wvfd2X1C0= github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= -github.com/charmbracelet/lipgloss v0.5.0 h1:lulQHuVeodSgDez+3rGiuxlPVXSnhth442DATR2/8t8= github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs= github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY= github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= -github.com/cloudcmds/tamarin v0.0.12 h1:xigMcfala5I81fh+6FSaJpjiKyWTOqzdf/GIQnsk/oc= -github.com/cloudcmds/tamarin v0.0.12/go.mod h1:U1aHBoAFtJbI9jzgaj8TUo9C6vfzUKzn1OhWKIdigVM= -github.com/cloudcmds/tamarin v0.0.14 h1:LNHz/CplhiM9u4SVy/9dGjyXpMTvKMmWcuO0+f0t5Ls= -github.com/cloudcmds/tamarin v0.0.14/go.mod h1:U1aHBoAFtJbI9jzgaj8TUo9C6vfzUKzn1OhWKIdigVM= github.com/cloudcmds/tamarin v1.0.0 h1:PhrJ74FCUJo24/nIPXnQe9E3WVEIYo4aG58pICOMDBE= github.com/cloudcmds/tamarin v1.0.0/go.mod h1:U1aHBoAFtJbI9jzgaj8TUo9C6vfzUKzn1OhWKIdigVM= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= @@ -121,8 +79,6 @@ github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkX github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -137,14 +93,11 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= -github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= @@ -157,15 +110,11 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc h1:ZQrgZFsLzkw7o3CoDzsfBhx0bf/1rVBXrLy8dXKRe8o= github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc/go.mod h1:PyXUpnI3olx3bsPcHt98FGPX/KCFZ1Fi+hw1XLI6384= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lmika/events v0.0.0-20200906102219-a2269cd4394e h1:0QkUe2ejnT/i+xbgGylMU1b+XnZponQKiPVNi+C/xgA= @@ -180,12 +129,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.10/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -193,14 +138,12 @@ github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2J github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 h1:kMlmsLSbjkikxQJ1IPwaM+7LJ9ltFu/fi8CRzvSnQmA= github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= -github.com/muesli/cancelreader v0.2.0 h1:SOpr+CfyVNce341kKqvbhhzQhBPyJRXQaCtn03Pae1Q= github.com/muesli/cancelreader v0.2.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= @@ -209,41 +152,26 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= -github.com/muesli/termenv v0.12.0 h1:KuQRUE3PgxRFWhq4gHvZtPSLCGDqM5q/cYr1pZ39ytc= -github.com/muesli/termenv v0.12.0/go.mod h1:WCCv32tusQ/EEZ5S8oUIIrC/nIuBcxCVqlN4Xfkv+7A= github.com/muesli/termenv v0.13.0 h1:wK20DRpJdDX8b7Ek2QfhvqhRQFZ237RGRO0RQ/Iqdy0= github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= -github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= -github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= -github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= -github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= -github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= -github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -258,7 +186,6 @@ github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaU github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/wI2L/jsondiff v0.3.0 h1:iTzQ9u/d86GE9RsBzVHX88f2EA1vQUboHwLhSQFc1s4= github.com/wI2L/jsondiff v0.3.0/go.mod h1:y1IMzNNjlSsk3IUoJdRJO7VRBtzMvRgyo4Vu0LdHpTc= -github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= @@ -269,10 +196,11 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU= golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a h1:tlXy25amD5A7gOfbXdqCGN5k8ESEed/Ee1E5RcrYnqU= golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp/shiny v0.0.0-20230213192124-5e25df0256eb h1:gdeQX7xJSkTNF+Sw7++XNIOo4pGL0CjQv3N2Vm1Erxk= +golang.org/x/exp/shiny v0.0.0-20230213192124-5e25df0256eb/go.mod h1:UH99kUObWAZkDnWqppdQe5ZhPYESUw8I0zVV1uWBR+0= 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/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ= @@ -284,10 +212,10 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -301,31 +229,19 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI= -golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220919170432-7a66f970e087 h1:tPwmk4vmvVCMdr98VgL4JH+qZxPL8fqlUOHnyOM8N3w= golang.org/x/term v0.0.0-20220919170432-7a66f970e087/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= @@ -343,15 +259,11 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/dynamo-browse/controllers/tableread_test.go b/internal/dynamo-browse/controllers/tableread_test.go index 153b06e..6a86a85 100644 --- a/internal/dynamo-browse/controllers/tableread_test.go +++ b/internal/dynamo-browse/controllers/tableread_test.go @@ -100,6 +100,24 @@ func TestTableReadController_Query(t *testing.T) { }, "")) }) + t.Run("should run query on index with filter based on user query", func(t *testing.T) { + srv := newService(t, serviceConfig{tableName: "bravo-table"}) + + tempFile := tempFile(t) + + invokeCommand(t, srv.readController.Init()) + invokeCommandWithPrompts(t, srv.readController.PromptForQuery(), `alpha = "This is some value"`) + invokeCommand(t, srv.exportController.ExportCSV(tempFile)) + + bts, err := os.ReadFile(tempFile) + assert.NoError(t, err) + + assert.Equal(t, string(bts), strings.Join([]string{ + "pk,sk,alpha\n", + "foo,bar,This is some value\n", + }, "")) + }) + t.Run("should return error if result set is not set", func(t *testing.T) { srv := newService(t, serviceConfig{tableName: "non-existant-table"}) @@ -250,6 +268,7 @@ var testData = []testdynamo.TestData{ }, { TableName: "bravo-table", + Index: []string{"alpha"}, Data: []map[string]interface{}{ { "pk": "foo", diff --git a/internal/dynamo-browse/models/query.go b/internal/dynamo-browse/models/query.go index c3f6704..65d1451 100644 --- a/internal/dynamo-browse/models/query.go +++ b/internal/dynamo-browse/models/query.go @@ -8,6 +8,7 @@ import ( type QueryExecutionPlan struct { CanQuery bool + IndexName string Expression expression.Expression } @@ -18,6 +19,9 @@ func (qep QueryExecutionPlan) Describe(dp DescribingPrinter) { dp.Println(" execute as: scan") } + if qep.IndexName != "" { + dp.Printf(" index: %v", qep.IndexName) + } if keyCond := aws.ToString(qep.Expression.KeyCondition()); keyCond != "" { dp.Printf(" key condition: %v", keyCond) } diff --git a/internal/dynamo-browse/models/queryexpr/ast.go b/internal/dynamo-browse/models/queryexpr/ast.go index 28c49ea..7e8cf81 100644 --- a/internal/dynamo-browse/models/queryexpr/ast.go +++ b/internal/dynamo-browse/models/queryexpr/ast.go @@ -5,6 +5,7 @@ import ( "github.com/alecthomas/participle/v2/lexer" "github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression" "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/lmika/audax/internal/common/sliceutils" "github.com/lmika/audax/internal/dynamo-browse/models" "github.com/pkg/errors" ) @@ -121,30 +122,43 @@ func Parse(expr string) (*QueryExpr, error) { } func (a *astExpr) calcQuery(ctx *evalContext, info *models.TableInfo) (*models.QueryExecutionPlan, error) { + type queryTestAttempt struct { + index string + keysUnderTest models.KeyAttribute + } + queryTestAttempts := append( + []queryTestAttempt{{keysUnderTest: info.Keys}}, + sliceutils.Map(info.GSIs, func(gsi models.TableGSI) queryTestAttempt { + return queryTestAttempt{index: gsi.Name, keysUnderTest: gsi.Keys} + })...) + ir, err := a.evalToIR(ctx, info) if err != nil { return nil, err } - var qci queryCalcInfo - if canExecuteAsQuery(ir, info, &qci) { - ke, err := ir.(queryableIRAtom).calcQueryForQuery(info) - if err != nil { - return nil, err + for _, attempt := range queryTestAttempts { + var qci = queryCalcInfo{keysUnderTest: attempt.keysUnderTest} + if canExecuteAsQuery(ir, &qci) { + ke, err := ir.(queryableIRAtom).calcQueryForQuery() + if err != nil { + return nil, err + } + + builder := expression.NewBuilder() + builder = builder.WithKeyCondition(ke) + + expr, err := builder.Build() + if err != nil { + return nil, err + } + + return &models.QueryExecutionPlan{ + CanQuery: true, + IndexName: attempt.index, + Expression: expr, + }, nil } - - builder := expression.NewBuilder() - builder = builder.WithKeyCondition(ke) - - expr, err := builder.Build() - if err != nil { - return nil, err - } - - return &models.QueryExecutionPlan{ - CanQuery: true, - Expression: expr, - }, nil } cb, err := ir.calcQueryForScan(info) diff --git a/internal/dynamo-browse/models/queryexpr/comp.go b/internal/dynamo-browse/models/queryexpr/comp.go index efc6176..31e9e4d 100644 --- a/internal/dynamo-browse/models/queryexpr/comp.go +++ b/internal/dynamo-browse/models/queryexpr/comp.go @@ -128,14 +128,14 @@ type irKeyFieldCmp struct { cmpType int } -func (a irKeyFieldCmp) canBeExecutedAsQuery(info *models.TableInfo, qci *queryCalcInfo) bool { +func (a irKeyFieldCmp) canBeExecutedAsQuery(qci *queryCalcInfo) bool { keyName := a.name.keyName() if keyName == "" { return false } - if keyName == info.Keys.SortKey { - return qci.addKey(info, keyName) + if keyName == qci.keysUnderTest.SortKey { + return qci.addKey(keyName) } return false @@ -158,7 +158,7 @@ func (a irKeyFieldCmp) calcQueryForScan(info *models.TableInfo) (expression.Cond return expression.ConditionBuilder{}, errors.New("unsupported cmp type") } -func (a irKeyFieldCmp) calcQueryForQuery(info *models.TableInfo) (expression.KeyConditionBuilder, error) { +func (a irKeyFieldCmp) calcQueryForQuery() (expression.KeyConditionBuilder, error) { keyName := a.name.keyName() vb := a.value.goValue() diff --git a/internal/dynamo-browse/models/queryexpr/conj.go b/internal/dynamo-browse/models/queryexpr/conj.go index 7f23135..dd7f4a2 100644 --- a/internal/dynamo-browse/models/queryexpr/conj.go +++ b/internal/dynamo-browse/models/queryexpr/conj.go @@ -100,31 +100,31 @@ type irDualConjunction struct { leftIsPK bool } -func (i *irDualConjunction) canBeExecutedAsQuery(info *models.TableInfo, qci *queryCalcInfo) bool { +func (i *irDualConjunction) canBeExecutedAsQuery(qci *queryCalcInfo) bool { qciCopy := qci.clone() - leftCanExecuteAsQuery := canExecuteAsQuery(i.left, info, qci) + leftCanExecuteAsQuery := canExecuteAsQuery(i.left, qci) if leftCanExecuteAsQuery { - i.leftIsPK = qci.hasSeenPrimaryKey(info) - return canExecuteAsQuery(i.right, info, qci) + i.leftIsPK = qci.hasSeenPrimaryKey() + return canExecuteAsQuery(i.right, qci) } // Might be that the right is the partition key, so test again with them swapped - rightCanExecuteAsQuery := canExecuteAsQuery(i.right, info, qciCopy) + rightCanExecuteAsQuery := canExecuteAsQuery(i.right, qciCopy) if rightCanExecuteAsQuery { - return canExecuteAsQuery(i.left, info, qciCopy) + return canExecuteAsQuery(i.left, qciCopy) } return false } -func (i *irDualConjunction) calcQueryForQuery(info *models.TableInfo) (expression.KeyConditionBuilder, error) { - left, err := i.left.(queryableIRAtom).calcQueryForQuery(info) +func (i *irDualConjunction) calcQueryForQuery() (expression.KeyConditionBuilder, error) { + left, err := i.left.(queryableIRAtom).calcQueryForQuery() if err != nil { return expression.KeyConditionBuilder{}, err } - right, err := i.right.(queryableIRAtom).calcQueryForQuery(info) + right, err := i.right.(queryableIRAtom).calcQueryForQuery() if err != nil { return expression.KeyConditionBuilder{}, err } diff --git a/internal/dynamo-browse/models/queryexpr/equality.go b/internal/dynamo-browse/models/queryexpr/equality.go index 4d3118e..702754b 100644 --- a/internal/dynamo-browse/models/queryexpr/equality.go +++ b/internal/dynamo-browse/models/queryexpr/equality.go @@ -136,15 +136,15 @@ type irKeyFieldEq struct { value valueIRAtom } -func (a irKeyFieldEq) canBeExecutedAsQuery(info *models.TableInfo, qci *queryCalcInfo) bool { +func (a irKeyFieldEq) canBeExecutedAsQuery(qci *queryCalcInfo) bool { keyName := a.name.keyName() if keyName == "" { return false } - if keyName == info.Keys.PartitionKey || - (keyName == info.Keys.SortKey && qci.hasSeenPrimaryKey(info)) { - return qci.addKey(info, keyName) + if keyName == qci.keysUnderTest.PartitionKey || + (keyName == qci.keysUnderTest.SortKey && qci.hasSeenPrimaryKey()) { + return qci.addKey(keyName) } return false @@ -156,7 +156,7 @@ func (a irKeyFieldEq) calcQueryForScan(info *models.TableInfo) (expression.Condi return nb.Equal(vb), nil } -func (a irKeyFieldEq) calcQueryForQuery(info *models.TableInfo) (expression.KeyConditionBuilder, error) { +func (a irKeyFieldEq) calcQueryForQuery() (expression.KeyConditionBuilder, error) { vb := a.value.goValue() return expression.Key(a.name.keyName()).Equal(expression.Value(vb)), nil } @@ -188,14 +188,14 @@ type irFieldBeginsWith struct { value irValue } -func (a irFieldBeginsWith) canBeExecutedAsQuery(info *models.TableInfo, qci *queryCalcInfo) bool { +func (a irFieldBeginsWith) canBeExecutedAsQuery(qci *queryCalcInfo) bool { keyName := a.name.keyName() if keyName == "" { return false } - if keyName == info.Keys.SortKey && qci.hasSeenPrimaryKey(info) { - return qci.addKey(info, a.name.keyName()) + if keyName == qci.keysUnderTest.SortKey && qci.hasSeenPrimaryKey() { + return qci.addKey(a.name.keyName()) } return false @@ -212,7 +212,7 @@ func (a irFieldBeginsWith) calcQueryForScan(info *models.TableInfo) (expression. return nb.BeginsWith(strValue), nil } -func (a irFieldBeginsWith) calcQueryForQuery(info *models.TableInfo) (expression.KeyConditionBuilder, error) { +func (a irFieldBeginsWith) calcQueryForQuery() (expression.KeyConditionBuilder, error) { vb := a.value.goValue() strValue, isStrValue := vb.(string) if !isStrValue { diff --git a/internal/dynamo-browse/models/queryexpr/expr.go b/internal/dynamo-browse/models/queryexpr/expr.go index f4055b9..aed149f 100644 --- a/internal/dynamo-browse/models/queryexpr/expr.go +++ b/internal/dynamo-browse/models/queryexpr/expr.go @@ -199,7 +199,8 @@ func (a *astExpr) String() string { } type queryCalcInfo struct { - seenKeys map[string]struct{} + keysUnderTest models.KeyAttribute + seenKeys map[string]struct{} } func (qc *queryCalcInfo) clone() *queryCalcInfo { @@ -207,16 +208,16 @@ func (qc *queryCalcInfo) clone() *queryCalcInfo { for k, v := range qc.seenKeys { newKeys[k] = v } - return &queryCalcInfo{seenKeys: newKeys} + return &queryCalcInfo{keysUnderTest: qc.keysUnderTest, seenKeys: newKeys} } -func (qc *queryCalcInfo) hasSeenPrimaryKey(tableInfo *models.TableInfo) bool { - _, hasKey := qc.seenKeys[tableInfo.Keys.PartitionKey] +func (qc *queryCalcInfo) hasSeenPrimaryKey() bool { + _, hasKey := qc.seenKeys[qc.keysUnderTest.PartitionKey] return hasKey } -func (qc *queryCalcInfo) addKey(tableInfo *models.TableInfo, key string) bool { - if tableInfo.Keys.PartitionKey != key && tableInfo.Keys.SortKey != key { +func (qc *queryCalcInfo) addKey(key string) bool { + if qc.keysUnderTest.PartitionKey != key && qc.keysUnderTest.SortKey != key { return false } diff --git a/internal/dynamo-browse/models/queryexpr/expr_test.go b/internal/dynamo-browse/models/queryexpr/expr_test.go index e035664..5575f14 100644 --- a/internal/dynamo-browse/models/queryexpr/expr_test.go +++ b/internal/dynamo-browse/models/queryexpr/expr_test.go @@ -19,6 +19,22 @@ func TestModExpr_Query(t *testing.T) { PartitionKey: "pk", SortKey: "sk", }, + GSIs: []models.TableGSI{ + { + Name: "with-color", + Keys: models.KeyAttribute{ + PartitionKey: "color", + SortKey: "shade", + }, + }, + { + Name: "with-apples", + Keys: models.KeyAttribute{ + PartitionKey: "apples", + SortKey: "sk", + }, + }, + }, } t.Run("as queries", func(t *testing.T) { @@ -113,10 +129,25 @@ func TestModExpr_Query(t *testing.T) { ), // Querying the index - scanCase("when request pk is fixed", - `pk="prefix"`, + scanCase("querying the index with the index pk", + `color="blue"`, `#0 = :0`, - exprNameIsString(0, 0, "pk", "prefix"), + indexName("with-color"), + exprNameIsString(0, 0, "color", "blue"), + ), + scanCase("querying the index with the index pk and index sk", + `color="red" and shade="gray"`, + `(#0 = :0) AND (#1 = :1)`, + indexName("with-color"), + exprNameIsString(0, 0, "color", "red"), + exprNameIsString(1, 1, "shade", "gray"), + ), + scanCase("querying the index with the index pk and begins with index sk", + `color="yellow" and shade ^= "dark"`, + `(#0 = :0) AND (begins_with (#1, :1))`, + indexName("with-color"), + exprNameIsString(0, 0, "color", "yellow"), + exprNameIsString(1, 1, "shade", "dark"), ), } @@ -131,6 +162,7 @@ func TestModExpr_Query(t *testing.T) { assert.NoError(t, err) assert.True(t, plan.CanQuery) + assert.Equal(t, scenario.indexName, plan.IndexName) assert.Equal(t, scenario.expectedFilter, aws.ToString(plan.Expression.KeyCondition())) for k, v := range scenario.expectedNames { assert.Equal(t, v, plan.Expression.Names()[k]) @@ -824,6 +856,7 @@ type scanScenario struct { description string expression string expectedFilter string + indexName string expectedNames map[string]string expectedValues map[string]types.AttributeValue placeholderNames map[string]string @@ -844,6 +877,12 @@ func scanCase(description, expression, expectedFilter string, options ...func(ss return ss } +func indexName(indexName string) func(ss *scanScenario) { + return func(ss *scanScenario) { + ss.indexName = indexName + } +} + func placeholderNames(placeholderNames map[string]string) func(ss *scanScenario) { return func(ss *scanScenario) { ss.placeholderNames = placeholderNames diff --git a/internal/dynamo-browse/models/queryexpr/ir.go b/internal/dynamo-browse/models/queryexpr/ir.go index 335314e..db9c218 100644 --- a/internal/dynamo-browse/models/queryexpr/ir.go +++ b/internal/dynamo-browse/models/queryexpr/ir.go @@ -16,10 +16,10 @@ type queryableIRAtom interface { irAtom // canBeExecutedAsQuery returns true if the atom is capable of being executed as a query - canBeExecutedAsQuery(info *models.TableInfo, qci *queryCalcInfo) bool + canBeExecutedAsQuery(qci *queryCalcInfo) bool // calcQueryForQuery returns a key condition builder for this atom to include in a query - calcQueryForQuery(info *models.TableInfo) (expression.KeyConditionBuilder, error) + calcQueryForQuery() (expression.KeyConditionBuilder, error) } type oprIRAtom interface { @@ -43,10 +43,10 @@ type multiValueIRAtom interface { calcGoValues(info *models.TableInfo) ([]any, error) } -func canExecuteAsQuery(ir irAtom, info *models.TableInfo, qci *queryCalcInfo) bool { +func canExecuteAsQuery(ir irAtom, qci *queryCalcInfo) bool { queryable, isQuearyable := ir.(queryableIRAtom) if !isQuearyable { return false } - return queryable.canBeExecutedAsQuery(info, qci) + return queryable.canBeExecutedAsQuery(qci) } diff --git a/internal/dynamo-browse/providers/dynamo/provider.go b/internal/dynamo-browse/providers/dynamo/provider.go index f6958b1..66e8d1c 100644 --- a/internal/dynamo-browse/providers/dynamo/provider.go +++ b/internal/dynamo-browse/providers/dynamo/provider.go @@ -41,12 +41,13 @@ func (p *Provider) DescribeTable(ctx context.Context, tableName string) (*models var tableInfo models.TableInfo tableInfo.Name = aws.ToString(out.Table.TableName) + tableInfo.Keys = p.keySchemaToKeyAttributes(out.Table.KeySchema) - for _, keySchema := range out.Table.KeySchema { - if keySchema.KeyType == types.KeyTypeHash { - tableInfo.Keys.PartitionKey = aws.ToString(keySchema.AttributeName) - } else if keySchema.KeyType == types.KeyTypeRange { - tableInfo.Keys.SortKey = aws.ToString(keySchema.AttributeName) + tableInfo.GSIs = make([]models.TableGSI, len(out.Table.GlobalSecondaryIndexes)) + for i, gsiIndex := range out.Table.GlobalSecondaryIndexes { + tableInfo.GSIs[i] = models.TableGSI{ + Name: aws.ToString(gsiIndex.IndexName), + Keys: p.keySchemaToKeyAttributes(gsiIndex.KeySchema), } } @@ -57,6 +58,17 @@ func (p *Provider) DescribeTable(ctx context.Context, tableName string) (*models return &tableInfo, nil } +func (p *Provider) keySchemaToKeyAttributes(keySchemaElements []types.KeySchemaElement) (keyAttribute models.KeyAttribute) { + for _, keySchema := range keySchemaElements { + if keySchema.KeyType == types.KeyTypeHash { + keyAttribute.PartitionKey = aws.ToString(keySchema.AttributeName) + } else if keySchema.KeyType == types.KeyTypeRange { + keyAttribute.SortKey = aws.ToString(keySchema.AttributeName) + } + } + return keyAttribute +} + func (p *Provider) PutItem(ctx context.Context, name string, item models.Item) error { _, err := p.client.PutItem(ctx, &dynamodb.PutItemInput{ TableName: aws.String(name), @@ -170,6 +182,7 @@ func (p *Provider) ScanItems( func (p *Provider) QueryItems( ctx context.Context, tableName string, + indexName string, filterExpr *expression.Expression, exclusiveStartKey map[string]types.AttributeValue, maxItems int, @@ -179,6 +192,9 @@ func (p *Provider) QueryItems( input := &dynamodb.QueryInput{ TableName: aws.String(tableName), } + if indexName != "" { + input.IndexName = aws.String(indexName) + } if filterExpr != nil { input.KeyConditionExpression = filterExpr.KeyCondition() input.FilterExpression = filterExpr.Filter() diff --git a/internal/dynamo-browse/services/tables/iface.go b/internal/dynamo-browse/services/tables/iface.go index 0f28797..75aca24 100644 --- a/internal/dynamo-browse/services/tables/iface.go +++ b/internal/dynamo-browse/services/tables/iface.go @@ -17,6 +17,7 @@ type TableProvider interface { QueryItems( ctx context.Context, tableName string, + indexName string, filterExpr *expression.Expression, exclusiveStartKey map[string]types.AttributeValue, maxItems int, diff --git a/internal/dynamo-browse/services/tables/service.go b/internal/dynamo-browse/services/tables/service.go index 7cf6612..fb2bad3 100644 --- a/internal/dynamo-browse/services/tables/service.go +++ b/internal/dynamo-browse/services/tables/service.go @@ -49,6 +49,7 @@ func (s *Service) doScan( var ( filterExpr *expression.Expression runAsQuery bool + index string err error ) if expr != nil { @@ -58,6 +59,7 @@ func (s *Service) doScan( } runAsQuery = plan.CanQuery + index = plan.IndexName filterExpr = &plan.Expression log.Printf("Running query over '%v'", tableInfo.Name) @@ -69,7 +71,7 @@ func (s *Service) doScan( var results []models.Item var lastEvalKey map[string]types.AttributeValue if runAsQuery { - results, lastEvalKey, err = s.provider.QueryItems(ctx, tableInfo.Name, filterExpr, exclusiveStartKey, limit) + results, lastEvalKey, err = s.provider.QueryItems(ctx, tableInfo.Name, index, filterExpr, exclusiveStartKey, limit) } else { results, lastEvalKey, err = s.provider.ScanItems(ctx, tableInfo.Name, filterExpr, exclusiveStartKey, limit) } diff --git a/test/testdynamo/client.go b/test/testdynamo/client.go index 9f61ecc..68c9065 100644 --- a/test/testdynamo/client.go +++ b/test/testdynamo/client.go @@ -15,6 +15,7 @@ import ( type TestData struct { TableName string + Index []string Data []map[string]interface{} } @@ -31,7 +32,7 @@ func SetupTestTable(t *testing.T, testData []TestData) *dynamodb.Client { dynamodb.WithEndpointResolver(dynamodb.EndpointResolverFromURL("http://localhost:4566"))) for _, table := range testData { - _, err = dynamoClient.CreateTable(ctx, &dynamodb.CreateTableInput{ + tableInput := &dynamodb.CreateTableInput{ TableName: aws.String(table.TableName), KeySchema: []types.KeySchemaElement{ {AttributeName: aws.String("pk"), KeyType: types.KeyTypeHash}, @@ -45,7 +46,28 @@ func SetupTestTable(t *testing.T, testData []TestData) *dynamodb.Client { ReadCapacityUnits: aws.Int64(100), WriteCapacityUnits: aws.Int64(100), }, - }) + } + for _, index := range table.Index { + tableInput.AttributeDefinitions = append(tableInput.AttributeDefinitions, types.AttributeDefinition{ + AttributeName: aws.String(index), + AttributeType: types.ScalarAttributeTypeS, + }) + tableInput.GlobalSecondaryIndexes = append(tableInput.GlobalSecondaryIndexes, types.GlobalSecondaryIndex{ + IndexName: aws.String(index + "-index"), + KeySchema: []types.KeySchemaElement{ + {AttributeName: aws.String(index), KeyType: types.KeyTypeHash}, + }, + Projection: &types.Projection{ + ProjectionType: types.ProjectionTypeAll, + }, + ProvisionedThroughput: &types.ProvisionedThroughput{ + ReadCapacityUnits: aws.Int64(100), + WriteCapacityUnits: aws.Int64(100), + }, + }) + } + + _, err = dynamoClient.CreateTable(ctx, tableInput) assert.NoError(t, err) for _, item := range table.Data {