From 6603e3aa32eceb91839b891d8fbce154a59ec97e Mon Sep 17 00:00:00 2001 From: sashayakovtseva Date: Wed, 13 Nov 2024 21:20:51 +0300 Subject: [PATCH] Do not update deps --- go.mod | 7 +- go.sum | 33 +- .../github.com/proullon/ramsql/driver/conn.go | 207 +- .../proullon/ramsql/driver/driver.go | 120 +- .../github.com/proullon/ramsql/driver/init.go | 39 + .../proullon/ramsql/driver/result.go | 9 + .../github.com/proullon/ramsql/driver/rows.go | 89 +- .../github.com/proullon/ramsql/driver/stmt.go | 119 +- .../github.com/proullon/ramsql/driver/tx.go | 24 +- .../ramsql/engine/agnostic/attribute.go | 220 -- .../proullon/ramsql/engine/agnostic/change.go | 76 - .../proullon/ramsql/engine/agnostic/engine.go | 97 - .../proullon/ramsql/engine/agnostic/index.go | 138 -- .../ramsql/engine/agnostic/predicate.go | 2192 ----------------- .../ramsql/engine/agnostic/relation.go | 143 -- .../ramsql/engine/agnostic/scanner.go | 73 - .../proullon/ramsql/engine/agnostic/schema.go | 56 - .../proullon/ramsql/engine/agnostic/source.go | 118 - .../ramsql/engine/agnostic/transaction.go | 768 ------ .../proullon/ramsql/engine/agnostic/tuple.go | 23 - .../proullon/ramsql/engine/attribute.go | 90 + .../proullon/ramsql/engine/condition.go | 29 + .../proullon/ramsql/engine/delete.go | 75 + .../proullon/ramsql/engine/distinct.go | 110 + .../github.com/proullon/ramsql/engine/drop.go | 30 + .../proullon/ramsql/engine/engine.go | 193 ++ .../ramsql/engine/executor/attribute.go | 77 - .../proullon/ramsql/engine/executor/engine.go | 768 ------ .../proullon/ramsql/engine/executor/tx.go | 527 ---- .../proullon/ramsql/engine/insert.go | 191 ++ .../github.com/proullon/ramsql/engine/join.go | 259 ++ .../proullon/ramsql/engine/limit.go | 102 + .../proullon/ramsql/engine/log/log.go | 136 +- .../proullon/ramsql/engine/operator.go | 218 ++ .../proullon/ramsql/engine/orderby.go | 301 +++ .../proullon/ramsql/engine/parser/create.go | 51 +- .../proullon/ramsql/engine/parser/delete.go | 9 +- .../proullon/ramsql/engine/parser/drop.go | 38 +- .../proullon/ramsql/engine/parser/insert.go | 156 -- .../proullon/ramsql/engine/parser/lexer.go | 511 ++-- .../proullon/ramsql/engine/parser/log.go | 9 + .../proullon/ramsql/engine/parser/parser.go | 328 ++- .../proullon/ramsql/engine/parser/select.go | 7 +- .../proullon/ramsql/engine/parser/where.go | 34 +- .../proullon/ramsql/engine/predicate.go | 141 ++ .../proullon/ramsql/engine/protocol/buffer.go | 81 + .../ramsql/engine/protocol/channel.go | 238 ++ .../proullon/ramsql/engine/protocol/public.go | 43 + .../proullon/ramsql/engine/relation.go | 30 + .../proullon/ramsql/engine/select.go | 633 +++++ .../proullon/ramsql/engine/table.go | 113 + .../proullon/ramsql/engine/truncate.go | 37 + .../proullon/ramsql/engine/tuple.go | 21 + .../proullon/ramsql/engine/update.go | 119 + .../testify/assert/assertion_compare.go | 64 +- .../assert/assertion_compare_can_convert.go | 16 + .../assert/assertion_compare_legacy.go | 16 + .../testify/assert/assertion_format.go | 244 +- .../testify/assert/assertion_forward.go | 483 ++-- .../testify/assert/assertion_order.go | 24 +- .../stretchr/testify/assert/assertions.go | 465 +--- .../github.com/stretchr/testify/assert/doc.go | 43 +- .../testify/assert/http_assertions.go | 39 +- .../stretchr/testify/require/doc.go | 23 +- .../stretchr/testify/require/require.go | 501 ++-- .../testify/require/require_forward.go | 483 ++-- vendor/golang.org/x/exp/LICENSE | 27 - vendor/golang.org/x/exp/PATENTS | 22 - .../x/exp/constraints/constraints.go | 50 - vendor/golang.org/x/exp/slices/slices.go | 282 --- vendor/golang.org/x/exp/slices/sort.go | 128 - vendor/golang.org/x/exp/slices/zsortfunc.go | 479 ---- .../golang.org/x/exp/slices/zsortordered.go | 481 ---- vendor/golang.org/x/exp/slog/attr.go | 102 - vendor/golang.org/x/exp/slog/doc.go | 316 --- vendor/golang.org/x/exp/slog/handler.go | 559 ----- .../x/exp/slog/internal/buffer/buffer.go | 84 - .../x/exp/slog/internal/ignorepc.go | 9 - vendor/golang.org/x/exp/slog/json_handler.go | 336 --- vendor/golang.org/x/exp/slog/level.go | 201 -- vendor/golang.org/x/exp/slog/logger.go | 343 --- vendor/golang.org/x/exp/slog/noplog.bench | 36 - vendor/golang.org/x/exp/slog/record.go | 207 -- vendor/golang.org/x/exp/slog/text_handler.go | 161 -- vendor/golang.org/x/exp/slog/value.go | 456 ---- vendor/golang.org/x/exp/slog/value_119.go | 53 - vendor/golang.org/x/exp/slog/value_120.go | 39 - vendor/golang.org/x/text/LICENSE | 4 +- vendor/modules.txt | 21 +- 89 files changed, 4932 insertions(+), 12121 deletions(-) create mode 100644 vendor/github.com/proullon/ramsql/driver/init.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/agnostic/attribute.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/agnostic/change.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/agnostic/engine.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/agnostic/index.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/agnostic/predicate.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/agnostic/relation.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/agnostic/scanner.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/agnostic/schema.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/agnostic/source.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/agnostic/transaction.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/agnostic/tuple.go create mode 100644 vendor/github.com/proullon/ramsql/engine/attribute.go create mode 100644 vendor/github.com/proullon/ramsql/engine/condition.go create mode 100644 vendor/github.com/proullon/ramsql/engine/delete.go create mode 100644 vendor/github.com/proullon/ramsql/engine/distinct.go create mode 100644 vendor/github.com/proullon/ramsql/engine/drop.go create mode 100644 vendor/github.com/proullon/ramsql/engine/engine.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/executor/attribute.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/executor/engine.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/executor/tx.go create mode 100644 vendor/github.com/proullon/ramsql/engine/insert.go create mode 100644 vendor/github.com/proullon/ramsql/engine/join.go create mode 100644 vendor/github.com/proullon/ramsql/engine/limit.go create mode 100644 vendor/github.com/proullon/ramsql/engine/operator.go create mode 100644 vendor/github.com/proullon/ramsql/engine/orderby.go delete mode 100644 vendor/github.com/proullon/ramsql/engine/parser/insert.go create mode 100644 vendor/github.com/proullon/ramsql/engine/parser/log.go create mode 100644 vendor/github.com/proullon/ramsql/engine/predicate.go create mode 100644 vendor/github.com/proullon/ramsql/engine/protocol/buffer.go create mode 100644 vendor/github.com/proullon/ramsql/engine/protocol/channel.go create mode 100644 vendor/github.com/proullon/ramsql/engine/protocol/public.go create mode 100644 vendor/github.com/proullon/ramsql/engine/relation.go create mode 100644 vendor/github.com/proullon/ramsql/engine/select.go create mode 100644 vendor/github.com/proullon/ramsql/engine/table.go create mode 100644 vendor/github.com/proullon/ramsql/engine/truncate.go create mode 100644 vendor/github.com/proullon/ramsql/engine/tuple.go create mode 100644 vendor/github.com/proullon/ramsql/engine/update.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go delete mode 100644 vendor/golang.org/x/exp/LICENSE delete mode 100644 vendor/golang.org/x/exp/PATENTS delete mode 100644 vendor/golang.org/x/exp/constraints/constraints.go delete mode 100644 vendor/golang.org/x/exp/slices/slices.go delete mode 100644 vendor/golang.org/x/exp/slices/sort.go delete mode 100644 vendor/golang.org/x/exp/slices/zsortfunc.go delete mode 100644 vendor/golang.org/x/exp/slices/zsortordered.go delete mode 100644 vendor/golang.org/x/exp/slog/attr.go delete mode 100644 vendor/golang.org/x/exp/slog/doc.go delete mode 100644 vendor/golang.org/x/exp/slog/handler.go delete mode 100644 vendor/golang.org/x/exp/slog/internal/buffer/buffer.go delete mode 100644 vendor/golang.org/x/exp/slog/internal/ignorepc.go delete mode 100644 vendor/golang.org/x/exp/slog/json_handler.go delete mode 100644 vendor/golang.org/x/exp/slog/level.go delete mode 100644 vendor/golang.org/x/exp/slog/logger.go delete mode 100644 vendor/golang.org/x/exp/slog/noplog.bench delete mode 100644 vendor/golang.org/x/exp/slog/record.go delete mode 100644 vendor/golang.org/x/exp/slog/text_handler.go delete mode 100644 vendor/golang.org/x/exp/slog/value.go delete mode 100644 vendor/golang.org/x/exp/slog/value_119.go delete mode 100644 vendor/golang.org/x/exp/slog/value_120.go diff --git a/go.mod b/go.mod index f39c80d..59b9613 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/blockloop/scan/v2 go 1.17 require ( - github.com/proullon/ramsql v0.1.4 - github.com/stretchr/testify v1.9.0 - golang.org/x/text v0.20.0 + github.com/proullon/ramsql v0.0.1 + github.com/stretchr/testify v1.8.2 + golang.org/x/text v0.14.0 ) require ( @@ -13,7 +13,6 @@ require ( github.com/kr/pretty v0.3.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.8.1 // indirect - golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 042545c..1413119 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,9 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +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/go-gorp/gorp v2.2.0+incompatible h1:xAUh4QgEeqPPhK3vxZN+bzrim1z5Av6q837gtjUlshc= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/go-gorp/gorp v2.0.0+incompatible h1:dIQPsBtl6/H1MjVseWuWPXa7ET4p6Dve4j3Hg+UjqYw= +github.com/go-gorp/gorp v2.0.0+incompatible/go.mod h1:7IfkAQnO7jfT/9IQ3R9wL1dFhukN6aQxzKTHnkxzA/E= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= @@ -15,27 +12,29 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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/proullon/ramsql v0.1.4 h1:yTFRTn46gFH/kPbzCx+mGjuFlyTBUeDr3h2ldwxddl0= -github.com/proullon/ramsql v0.1.4/go.mod h1:CFGqeQHQpdRfWqYmWD3yXqPTEaHkF4zgXy1C6qDWc9E= +github.com/proullon/ramsql v0.0.1 h1:tI7qN48Oj1LTmgdo4aWlvI9z45a4QlWaXlmdJ+IIfbU= +github.com/proullon/ramsql v0.0.1/go.mod h1:jG8oAQG0ZPHPyxg5QlMERS31airDC+ZuqiAe8DUvFVo= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +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/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 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= 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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= -gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho= diff --git a/vendor/github.com/proullon/ramsql/driver/conn.go b/vendor/github.com/proullon/ramsql/driver/conn.go index ecd4fd2..e9b8977 100644 --- a/vendor/github.com/proullon/ramsql/driver/conn.go +++ b/vendor/github.com/proullon/ramsql/driver/conn.go @@ -1,72 +1,33 @@ package ramsql import ( - "context" - "database/sql" "database/sql/driver" + "sync" - "github.com/proullon/ramsql/engine/executor" "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/protocol" ) // Conn implements sql/driver Conn interface -// -// All Conn implementations should implement the following interaces: Pinger, SessionResetter, and Validator. -// -// If a Conn does not implement QueryerContext, the sql package's DB.Query will fall back to Queryer; -// if the Conn does not implement Queryer either, DB.Query will first prepare a query, execute the statement, and then close the statement. -// -// If named parameters or context are supported, the driver's Conn should implement: ExecerContext, QueryerContext, ConnPrepareContext, and ConnBeginTx. -// -// The returned connection is only used by one goroutine at a time. -// -// https://pkg.go.dev/database/sql/driver#Conn -// -// https://pkg.go.dev/database/sql/driver#Pinger -// https://pkg.go.dev/database/sql/driver#SessionResetter -// https://pkg.go.dev/database/sql/driver#Validator -// https://pkg.go.dev/database/sql/driver#QueryerContext -// https://pkg.go.dev/database/sql/driver#ExecerContext -// https://pkg.go.dev/database/sql/driver#ConnPrepareContext -// https://pkg.go.dev/database/sql/driver#ConnBeginTx type Conn struct { - e *executor.Engine - tx *executor.Tx -} + // Mutex is locked when a Statement is created + // then released on Statement.Exec or Statement.Query + mutex sync.Mutex -func newConn(e *executor.Engine) *Conn { - return &Conn{e: e} -} + // Socket is the network connection to RamSQL engine + conn protocol.DriverConn + // socket net.Conn -// Ping -// -// If Conn.Ping returns ErrBadConn, DB.Ping and DB.PingContext will remove the Conn from pool. -// -// Implemented for Pinger interface -func (c *Conn) Ping(ctx context.Context) error { - return nil + // This conn belongs to this server + parent *Server } -// ResetSession is called prior to executing a query on the connection -// if the connection has been used before. If the driver returns ErrBadConn -// the connection is discarded. -// -// Implemented for SessionResetter interface -func (c *Conn) ResetSession(ctx context.Context) error { - return nil -} - -// IsValid is called prior to placing the connection into the -// connection pool. The connection will be discarded if false is returned. -// -// Implemented for Validator interface -func (c *Conn) IsValid() bool { - return true +func newConn(conn protocol.DriverConn, parent *Server) driver.Conn { + parent.openingConn() + return &Conn{conn: conn, parent: parent} } // Prepare returns a prepared statement, bound to this connection. -// -// Implemented for Conn interface func (c *Conn) Prepare(query string) (driver.Stmt, error) { stmt := prepareStatement(c, query) @@ -82,149 +43,23 @@ func (c *Conn) Prepare(query string) (driver.Stmt, error) { // connections and only calls Close when there's a surplus of // idle connections, it shouldn't be necessary for drivers to // do their own connection caching. -// -// Implemented for Conn interface func (c *Conn) Close() error { - if c.tx != nil { - _ = c.tx.Rollback() - c.tx = nil + log.Debug("Conn.Close") + c.conn.Close() + + if c.parent != nil { + c.parent.closingConn() } return nil } // Begin starts and returns a new transaction. -// -// Deprecated: Drivers should implement ConnBeginTx instead (or additionally). -// -// Implemented for Conn interface func (c *Conn) Begin() (driver.Tx, error) { - tx, err := executor.NewTx(context.Background(), c.e, sql.TxOptions{}) - if err != nil { - return nil, err - } - c.tx = tx - log.Debug("%p BEGIN", c.tx) - return c, nil -} - -// BeginTx starts and returns a new transaction. -// -// Implemented for ConnBeginTx interface -func (c *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { - o := sql.TxOptions{ - Isolation: sql.IsolationLevel(opts.Isolation), - ReadOnly: opts.ReadOnly, - } - tx, err := executor.NewTx(ctx, c.e, o) - if err != nil { - return nil, err - } - c.tx = tx - log.Debug("%p BEGIN", c.tx) - return c, nil -} - -func (c *Conn) Rollback() error { - if c.tx == nil { - return nil - } - log.Debug("%p ROLLBACK", c.tx) - err := c.tx.Rollback() - c.tx = nil - return err -} - -func (c *Conn) Commit() error { - if c.tx == nil { - return nil - } - log.Debug("%p COMMIT", c.tx) - err := c.tx.Commit() - c.tx = nil - return err -} - -// QueryContext is the sql package prefered way to run QUERY. -// -// Implemented for QueryerContext interface -func (c *Conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { - var err error - autocommit := false - - log.Debug("Conn.QueryContext: %s", query) - - tx := c.tx - - if tx == nil { - autocommit = true - tx, err = c.e.Begin() - if err != nil { - return nil, err - } - defer tx.Rollback() - } - - a := make([]executor.NamedValue, len(args)) - for i, arg := range args { - a[i].Name = arg.Name - a[i].Ordinal = arg.Ordinal - a[i].Value = arg.Value - } - - cols, tuples, err := tx.QueryContext(ctx, query, a) - if err != nil { - return nil, err - } - - if autocommit { - err = tx.Commit() - if err != nil { - return nil, err - } - } - - return newRows(cols, tuples), nil -} - -// ExecContext is the sql package prefered way to run Exec -// -// Implemented for ExecerContext interface -func (c *Conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { - var err error - autocommit := false - log.Info("Conn.ExecContext: %s", query) - - tx := c.tx - - if tx == nil { - autocommit = true - tx, err = c.e.Begin() - if err != nil { - return nil, err - } - defer tx.Rollback() - } - - a := make([]executor.NamedValue, len(args)) - for i, arg := range args { - a[i].Name = arg.Name - a[i].Ordinal = arg.Ordinal - a[i].Value = arg.Value - } - - r := &Result{} - r.lastInsertedID, r.rowsAffected, r.err = tx.ExecContext(ctx, query, a) - if r.err != nil { - return r, r.err - } - if autocommit { - err = tx.Commit() - if err != nil { - return r, r.err - } + tx := Tx{ + conn: c, } - return r, r.err + return &tx, nil } diff --git a/vendor/github.com/proullon/ramsql/driver/driver.go b/vendor/github.com/proullon/ramsql/driver/driver.go index b2074a6..549ad18 100644 --- a/vendor/github.com/proullon/ramsql/driver/driver.go +++ b/vendor/github.com/proullon/ramsql/driver/driver.go @@ -8,8 +8,9 @@ import ( "sync" "time" - "github.com/proullon/ramsql/engine/executor" + "github.com/proullon/ramsql/engine" "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/protocol" ) func init() { @@ -17,23 +18,32 @@ func init() { log.SetLevel(log.WarningLevel) } -// Driver is the driver entrypoint -// -// Drivers should implement Connector and DriverContext interaces. -// -// https://pkg.go.dev/database/sql/driver#Connector -// https://pkg.go.dev/database/sql/driver#DriverContext +// Server structs holds engine for each sql.DB instance. +// This way a sql.DB cann open as much connection to engine as wanted +// without colliding with another engine (during tests for example) +// with the unique constraint of providing a unique DataSourceName +type Server struct { + endpoint protocol.DriverEndpoint + server *engine.Engine + + // Kill server on last connection closing + sync.Mutex + connCount int64 +} + +// Driver is the driver entrypoint, +// implementing database/sql/driver interface type Driver struct { - // Mutex protect the map of engine + // Mutex protect the map of Server sync.Mutex // Holds all matching sql.DB instances of RamSQL engine - engines map[string]*executor.Engine + servers map[string]*Server } // NewDriver creates a driver object func NewDriver() *Driver { d := &Driver{} - d.engines = make(map[string]*executor.Engine) + d.servers = make(map[string]*Server) return d } @@ -47,55 +57,80 @@ type connConf struct { Timeout time.Duration } -// Open return an active connection so RamSQL engine -// If there is no connection in pool, start a new engine. -// After first instantiation of the engine, +// Open return an active connection so RamSQL server +// If there is no connection in pool, start a new server. +// After first instantiation of the server, func (rs *Driver) Open(dsn string) (conn driver.Conn, err error) { rs.Lock() - defer rs.Unlock() - _, err = parseConnectionURI(dsn) + connConf, err := parseConnectionURI(dsn) if err != nil { + rs.Unlock() return nil, err } - dsnengine, exist := rs.engines[dsn] + dsnServer, exist := rs.servers[dsn] if !exist { - e, err := executor.NewEngine() + driverEndpoint, engineEndpoint, err := endpoints(connConf) + if err != nil { + rs.Unlock() + return nil, err + } + + server, err := engine.New(engineEndpoint) + if err != nil { + rs.Unlock() + return nil, err + } + + driverConn, err := driverEndpoint.New(dsn) if err != nil { + rs.Unlock() return nil, err } - rs.engines[dsn] = e + s := &Server{ + endpoint: driverEndpoint, + server: server, + } + rs.servers[dsn] = s - return newConn(e), nil + rs.Unlock() + return newConn(driverConn, s), nil } - return newConn(dsnengine), err + rs.Unlock() + driverConn, err := dsnServer.endpoint.New(dsn) + return newConn(driverConn, dsnServer), err +} + +func endpoints(conf *connConf) (protocol.DriverEndpoint, protocol.EngineEndpoint, error) { + switch conf.Proto { + default: + driver, engine := protocol.NewChannelEndpoints() + return driver, engine, nil + } } // The uri need to have the following syntax: // -// [PROTOCOL_SPECFIIC*]DBNAME/USER/PASSWD +// [PROTOCOL_SPECFIIC*]DBNAME/USER/PASSWD // // where protocol spercific part may be empty (this means connection to -// local engine using default protocol). Currently possible forms: +// local server using default protocol). Currently possible forms: // -// DBNAME/USER/PASSWD -// unix:SOCKPATH*DBNAME/USER/PASSWD -// unix:SOCKPATH,OPTIONS*DBNAME/USER/PASSWD -// tcp:ADDR*DBNAME/USER/PASSWD -// tcp:ADDR,OPTIONS*DBNAME/USER/PASSWD -// cloudsql:INSTANCE*DBNAME/USER/PASSWD +// DBNAME/USER/PASSWD +// unix:SOCKPATH*DBNAME/USER/PASSWD +// unix:SOCKPATH,OPTIONS*DBNAME/USER/PASSWD +// tcp:ADDR*DBNAME/USER/PASSWD +// tcp:ADDR,OPTIONS*DBNAME/USER/PASSWD +// cloudsql:INSTANCE*DBNAME/USER/PASSWD // // OPTIONS can contain comma separated list of options in form: -// -// opt1=VAL1,opt2=VAL2,boolopt3,boolopt4 -// +// opt1=VAL1,opt2=VAL2,boolopt3,boolopt4 // Currently implemented options: -// -// laddr - local address/port (eg. 1.2.3.4:0) -// timeout - connect timeout in format accepted by time.ParseDuration +// laddr - local address/port (eg. 1.2.3.4:0) +// timeout - connect timeout in format accepted by time.ParseDuration func parseConnectionURI(uri string) (*connConf, error) { c := &connConf{} @@ -151,3 +186,20 @@ func parseConnectionURI(uri string) (*connConf, error) { c.Password = dup[2] return c, nil } + +func (s *Server) openingConn() { + + s.Lock() + defer s.Unlock() + s.connCount++ +} + +func (s *Server) closingConn() { + s.Lock() + defer s.Unlock() + s.connCount-- + + if s.connCount == 0 { + s.server.Stop() + } +} diff --git a/vendor/github.com/proullon/ramsql/driver/init.go b/vendor/github.com/proullon/ramsql/driver/init.go new file mode 100644 index 0000000..1519e4c --- /dev/null +++ b/vendor/github.com/proullon/ramsql/driver/init.go @@ -0,0 +1,39 @@ +package ramsql + +import ( + "database/sql" + "fmt" + "io/ioutil" + "os" + "path" + "strings" +) + +// InitSchemas execute each query in provided sql file +// Expected sql file path into $GOPATH/src +func InitSchemas(db *sql.DB, sqlfile string) error { + gopath := os.Getenv("GOPATH") + + content, err := ioutil.ReadFile(path.Join(gopath, "src", sqlfile)) + if err != nil { + return err + } + + queries := strings.Split(string(content), ";") + + for _, q := range queries { + q = strings.Trim(q, "\n") + + if q == "" { + continue + } + + _, err := db.Exec(q) + if err != nil { + return fmt.Errorf("Query '%s': %s", q, err) + } + + } + + return nil +} diff --git a/vendor/github.com/proullon/ramsql/driver/result.go b/vendor/github.com/proullon/ramsql/driver/result.go index 92c4f9d..afed9e7 100644 --- a/vendor/github.com/proullon/ramsql/driver/result.go +++ b/vendor/github.com/proullon/ramsql/driver/result.go @@ -7,6 +7,15 @@ type Result struct { rowsAffected int64 } +func newResult(lastInsertedID int64, rowsAffected int64) *Result { + r := &Result{ + lastInsertedID: lastInsertedID, + rowsAffected: rowsAffected, + } + + return r +} + // LastInsertId returns the database's auto-generated ID // after, for example, an INSERT into a table with primary // key. diff --git a/vendor/github.com/proullon/ramsql/driver/rows.go b/vendor/github.com/proullon/ramsql/driver/rows.go index fd0199c..fdf411d 100644 --- a/vendor/github.com/proullon/ramsql/driver/rows.go +++ b/vendor/github.com/proullon/ramsql/driver/rows.go @@ -2,28 +2,32 @@ package ramsql import ( "database/sql/driver" + "errors" "fmt" "io" + "sync" - "github.com/proullon/ramsql/engine/agnostic" + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/parser" ) // Rows implements the sql/driver Rows interface type Rows struct { - columns []string - tuples []*agnostic.Tuple - idx int - end int -} + rowsChannel chan []string + columns []string -func newRows(cols []string, tuples []*agnostic.Tuple) *Rows { + sync.Mutex +} - r := &Rows{ - tuples: tuples, - columns: cols, - end: len(tuples) - 1, +func newRows(channel chan []string) *Rows { + r := &Rows{rowsChannel: channel} + c, ok := <-channel + if !ok { + log.Critical("Cannot receive column names from channel") + return nil } + r.columns = c return r } @@ -37,6 +41,21 @@ func (r *Rows) Columns() []string { // Close closes the rows iterator. func (r *Rows) Close() error { + r.Lock() + defer r.Unlock() + + if r.rowsChannel == nil { + return nil + } + + _, ok := <-r.rowsChannel + if !ok { + return nil + } + + // Tels UnlimitedRowsChannel to close itself + //r.rowsChannel <- []string{} + r.rowsChannel = nil return nil } @@ -50,21 +69,53 @@ func (r *Rows) Close() error { // // Next should return io.EOF when there are no more rows. func (r *Rows) Next(dest []driver.Value) (err error) { - if r.idx > r.end { + r.Lock() + defer r.Unlock() + + if r.rowsChannel == nil { return io.EOF } - tuple := r.tuples[r.idx] - r.idx++ + value, ok := <-r.rowsChannel + if !ok { + r.rowsChannel = nil + return io.EOF + } - values := tuple.Values() - if len(dest) < len(values) { - return fmt.Errorf("slice too short (%d slots for %d values)", len(dest), len(values)) + if len(dest) < len(value) { + return fmt.Errorf("slice too short (%d slots for %d values)", len(dest), len(value)) } - for i, v := range values { - dest[i] = v + for i, v := range value { + if v == "" { + dest[i] = nil + continue + } + + // TODO: make rowsChannel send virtualRows, + // so we have the type and don't blindy try to parse date here + if t, err := parser.ParseDate(string(v)); err == nil { + dest[i] = *t + } else { + + dest[i] = []byte(v) + } + } + + return nil +} + +func (r *Rows) setColumns(columns []string) { + r.columns = columns +} + +func assignValue(s string, v driver.Value) error { + dest, ok := v.(*string) + if !ok { + err := errors.New("cannot assign value") + return err } + *dest = s return nil } diff --git a/vendor/github.com/proullon/ramsql/driver/stmt.go b/vendor/github.com/proullon/ramsql/driver/stmt.go index c233d8e..8bb4c8d 100644 --- a/vendor/github.com/proullon/ramsql/driver/stmt.go +++ b/vendor/github.com/proullon/ramsql/driver/stmt.go @@ -1,10 +1,13 @@ package ramsql import ( - "context" "database/sql/driver" "fmt" + "regexp" + "strconv" "strings" + + "github.com/proullon/ramsql/engine/log" ) // Stmt implements the Statement interface of sql/driver @@ -42,6 +45,7 @@ func prepareStatement(c *Conn, query string) *Stmt { numInput: numInput, } + stmt.conn.mutex.Lock() return stmt } @@ -50,7 +54,7 @@ func prepareStatement(c *Conn, query string) *Stmt { // As of Go 1.1, a Stmt will not be closed if it's in use // by any queries. func (s *Stmt) Close() error { - return nil + return fmt.Errorf("Not implemented.") } // NumInput returns the number of placeholder parameters. @@ -75,17 +79,33 @@ func (s *Stmt) Exec(args []driver.Value) (r driver.Result, err error) { return } }() + defer s.conn.mutex.Unlock() if s.query == "" { return nil, fmt.Errorf("empty statement") } - var cargs []driver.NamedValue - for i, arg := range args { - cargs = append(cargs, driver.NamedValue{Name: fmt.Sprintf("%d", i+1), Ordinal: i + 1, Value: arg}) + var finalQuery string + + // replace $* by arguments in query string + finalQuery = replaceArguments(s.query, args) + log.Info("Exec <%s>\n", finalQuery) + + // Send query to server + err = s.conn.conn.WriteExec(finalQuery) + if err != nil { + log.Warning("Exec: Cannot send query to server: %s", err) + return nil, fmt.Errorf("Cannot send query to server: %s", err) } - return s.conn.ExecContext(context.Background(), s.query, cargs) + // Get answer from server + lastInsertedID, rowsAffected, err := s.conn.conn.ReadResult() + if err != nil { + return nil, err + } + + // Create a driver.Result + return newResult(lastInsertedID, rowsAffected), nil } // Query executes a query that may return rows, such as a @@ -97,14 +117,93 @@ func (s *Stmt) Query(args []driver.Value) (r driver.Rows, err error) { return } }() + defer s.conn.mutex.Unlock() if s.query == "" { return nil, fmt.Errorf("empty statement") } - var cargs []driver.NamedValue - for i, arg := range args { - cargs = append(cargs, driver.NamedValue{Name: fmt.Sprintf("%d", i+1), Ordinal: i + 1, Value: arg}) + + finalQuery := replaceArguments(s.query, args) + log.Info("Query < %s >\n", finalQuery) + err = s.conn.conn.WriteQuery(finalQuery) + if err != nil { + return nil, err + } + + rowsChannel, err := s.conn.conn.ReadRows() + if err != nil { + return nil, err + } + + r = newRows(rowsChannel) + return r, nil +} + +// replace $* by arguments in query string +func replaceArguments(query string, args []driver.Value) string { + + holder := regexp.MustCompile(`[^\$]\$[0-9]+`) + replacedQuery := "" + + if strings.Count(query, "?") == len(args) { + return replaceArgumentsODBC(query, args) + } + + allloc := holder.FindAllIndex([]byte(query), -1) + queryB := []byte(query) + for i, loc := range allloc { + match := queryB[loc[0]+1 : loc[1]] + + index, err := strconv.Atoi(string(match[1:])) + if err != nil { + log.Warning("Matched %s as a placeholder but cannot get index: %s\n", match, err) + return query + } + + var v string + if args[index-1] == nil { + v = "null" + } else if b, ok := args[index-1].([]byte); ok { + v = fmt.Sprintf("$$%s$$", b) + } else { + v = fmt.Sprintf("$$%v$$", args[index-1]) + } + if i == 0 { + replacedQuery = fmt.Sprintf("%s%s%s", replacedQuery, string(queryB[:loc[0]+1]), v) + } else { + replacedQuery = fmt.Sprintf("%s%s%s", replacedQuery, string(queryB[allloc[i-1][1]:loc[0]+1]), v) + } + } + // add remaining query + replacedQuery = fmt.Sprintf("%s%s", replacedQuery, string(queryB[allloc[len(allloc)-1][1]:])) + + return replacedQuery +} + +func replaceArgumentsODBC(query string, args []driver.Value) string { + finalQuery := &strings.Builder{} + + queryParts := strings.Split(query, "?") + + finalQuery.WriteString(queryParts[0]) + + for i := range args { + var arg string + switch v := args[i].(type) { + case string: + if !strings.HasSuffix(query, "'") { + arg = fmt.Sprintf("$$%s$$", v) + } + case []byte: + if !strings.HasSuffix(query, "'") { + arg = fmt.Sprintf("$$%s$$", v) + } + default: + arg = fmt.Sprintf("%v", v) + } + finalQuery.WriteString(arg) + finalQuery.WriteString(queryParts[i+1]) } - return s.conn.QueryContext(context.Background(), s.query, cargs) + return finalQuery.String() } diff --git a/vendor/github.com/proullon/ramsql/driver/tx.go b/vendor/github.com/proullon/ramsql/driver/tx.go index 2ff1c7e..5b4073a 100644 --- a/vendor/github.com/proullon/ramsql/driver/tx.go +++ b/vendor/github.com/proullon/ramsql/driver/tx.go @@ -1,7 +1,21 @@ package ramsql -// -// Tx doesn't need to be in driver package. -// -// Implementation doesn't depend on any sql/driver type, and can live in executor package. -// +import ( + "fmt" +) + +// Tx implements SQL transaction method +type Tx struct { + conn *Conn +} + +// Commit the transaction on server +func (t *Tx) Commit() error { + // TODO: Not implemented + return nil +} + +// Rollback all changes +func (t *Tx) Rollback() error { + return fmt.Errorf("Not implemented") +} diff --git a/vendor/github.com/proullon/ramsql/engine/agnostic/attribute.go b/vendor/github.com/proullon/ramsql/engine/agnostic/attribute.go deleted file mode 100644 index 3d55861..0000000 --- a/vendor/github.com/proullon/ramsql/engine/agnostic/attribute.go +++ /dev/null @@ -1,220 +0,0 @@ -package agnostic - -import ( - "fmt" - "math/rand" - "reflect" - "strconv" - "strings" - "time" -) - -type Defaulter func() any - -type ForeignKey struct { - schema string - relation string - attribute string -} - -// Domain is the set of allowable values for an Attribute. -type Domain struct { -} - -// Attribute is a named column of a relation -// AKA Field -// AKA Column -type Attribute struct { - name string - typeName string - typeInstance reflect.Type - defaultValue Defaulter - domain Domain - autoIncrement bool - nextValue uint64 - unique bool - fk *ForeignKey -} - -func NewAttribute(name, typeName string) Attribute { - a := Attribute{ - name: name, - typeName: typeName, - typeInstance: typeInstanceFromName(typeName), - } - - return a -} - -func (a Attribute) WithAutoIncrement() Attribute { - a.autoIncrement = true - a.nextValue = 1 - return a -} - -func (a Attribute) HasAutoIncrement() bool { - return a.autoIncrement -} - -func (a Attribute) WithDefaultConst(defaultValue any) Attribute { - a.defaultValue = func() any { - if defaultValue == nil { - return nil - } - return reflect.ValueOf(defaultValue).Convert(a.typeInstance).Interface() - } - return a -} - -func (a Attribute) WithDefault(defaultValue Defaulter) Attribute { - a.defaultValue = defaultValue - return a -} - -func (a Attribute) WithDefaultNow() Attribute { - a.defaultValue = func() any { - return time.Now() - } - return a -} - -func (a Attribute) WithUnique() Attribute { - a.unique = true - return a -} - -func (a Attribute) Name() string { - return a.name -} - -func (a Attribute) String() string { - s := a.name + " (" + a.typeName - if a.autoIncrement { - s = s + " AutoInc" - } - if a.unique { - s = s + " unique" - } - s = s + ")" - return s -} - -func typeInstanceFromName(name string) reflect.Type { - switch strings.ToLower(name) { - case "serial", "bigserial", "int", "bigint": - var v int64 - return reflect.TypeOf(v) - case "bool", "boolean": - var v bool - return reflect.TypeOf(v) - case "decimal", "float": - var v float64 - return reflect.TypeOf(v) - case "timestamp", "timestamptz", "date": - var v time.Time - return reflect.TypeOf(v) - default: - var v string - return reflect.TypeOf(v) - } -} - -func ToInstance(value, typeName string) (any, error) { - if value == "now()" || value == "current_timestamp" { - return time.Now(), nil - } - if value == "null" { - return nil, nil - } - - switch strings.ToLower(typeName) { - case "serial", "bigserial": - var v uint64 - v, err := strconv.ParseUint(value, 10, 64) - if err != nil { - return nil, err - } - return v, nil - case "decimal", "float": - v, err := strconv.ParseFloat(value, 64) - if err != nil { - return nil, err - } - return v, nil - case "int", "bigint": - v, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return nil, err - } - return v, nil - case "bool", "boolean": - v, err := strconv.ParseBool(value) - if err != nil { - return nil, err - } - return v, nil - case "timestamp", "timestamptz", "date": - v, err := parseDate(value) - if err != nil { - return nil, err - } - return v, nil - case "json", "jsonb", "varchar": - return value, nil - default: // try everyting - if v, err := strconv.ParseUint(value, 10, 64); err == nil { - return v, nil - } - if v, err := parseDate(value); err == nil { - return v, nil - } - if v, err := strconv.ParseBool(value); err == nil { - return v, nil - } - return value, nil - } -} - -func parseDate(data string) (time.Time, error) { - DateLongFormat := "2006-01-02 15:04:05.999999999 -0700 MST" - DateShortFormat := "2006-Jan-02" - DateNumberFormat := "2006-01-02" - - t, err := time.Parse(DateLongFormat, data) - if err == nil { - return t, nil - } - - t, err = time.Parse(time.RFC3339, data) - if err == nil { - return t, nil - } - - t, err = time.Parse(DateShortFormat, data) - if err == nil { - return t, nil - } - - t, err = time.Parse(DateNumberFormat, data) - if err == nil { - return t, nil - } - - return time.Time{}, fmt.Errorf("cannot use '%s' as date", data) -} - -const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - -func NewRandString(n int) Defaulter { - - f := func() any { - sb := strings.Builder{} - sb.Grow(n) - for i := 0; i < n; i++ { - sb.WriteByte(charset[rand.Intn(len(charset))]) - } - return sb.String() - } - - return f -} diff --git a/vendor/github.com/proullon/ramsql/engine/agnostic/change.go b/vendor/github.com/proullon/ramsql/engine/agnostic/change.go deleted file mode 100644 index 9d1d036..0000000 --- a/vendor/github.com/proullon/ramsql/engine/agnostic/change.go +++ /dev/null @@ -1,76 +0,0 @@ -package agnostic - -import ( - "container/list" -) - -type ValueChange struct { - current *list.Element - old *list.Element - l *list.List -} - -type RelationChange struct { - schema *Schema - current *Relation - old *Relation -} - -type SchemaChange struct { - current *Schema - old *Schema - e *Engine -} - -func (t *Transaction) rollbackValueChange(c ValueChange) { - - // revert insert - if c.current != nil && c.old == nil { - c.l.Remove(c.current) - } - - // revert delete - if c.current == nil && c.old != nil { - old := c.old.Value.(*Tuple) - c.l.InsertAfter(old, c.old.Prev()) - } - - // revert update - if c.current != nil && c.old != nil { - cur := c.current.Value.(*Tuple) - old := c.old.Value.(*Tuple) - for i := range cur.values { - cur.values[i] = old.values[i] - } - } -} - -func (t *Transaction) rollbackRelationChange(c RelationChange) { - // revert relation creation - if c.current != nil && c.old == nil { - c.schema.Remove(c.current.name) - } - - // revert relation drop - if c.current == nil && c.old != nil { - c.schema.Add(c.old.name, c.old) - } - - // revert alter - if c.current != nil && c.old != nil { - c.schema.Remove(c.current.name) - c.schema.Add(c.old.name, c.old) - } -} - -func (t *Transaction) rollbackSchemaChange(c SchemaChange) { - // revert schema creation - if c.current != nil && c.old == nil { - delete(c.e.schemas, c.current.name) - } - - // revert schema drop - if c.current == nil && c.old != nil { - c.e.schemas[c.old.name] = c.old - } -} diff --git a/vendor/github.com/proullon/ramsql/engine/agnostic/engine.go b/vendor/github.com/proullon/ramsql/engine/agnostic/engine.go deleted file mode 100644 index 48d0661..0000000 --- a/vendor/github.com/proullon/ramsql/engine/agnostic/engine.go +++ /dev/null @@ -1,97 +0,0 @@ -package agnostic - -import ( - "fmt" - "sync" -) - -const ( - DefaultSchema = "public" -) - -type Engine struct { - schemas map[string]*Schema - - sync.Mutex -} - -func NewEngine() *Engine { - e := &Engine{} - - // create public schema - e.schemas = make(map[string]*Schema) - e.schemas[DefaultSchema] = NewSchema(DefaultSchema) - - return e -} - -func (e *Engine) Begin() (*Transaction, error) { - t, err := NewTransaction(e) - return t, err -} - -func (e *Engine) createRelation(schema, relation string, attributes []Attribute, pk []string) (*Schema, *Relation, error) { - - s, err := e.schema(schema) - if err != nil { - return nil, nil, err - } - - r, err := NewRelation(schema, relation, attributes, pk) - if err != nil { - return nil, nil, err - } - - s.Add(relation, r) - - return s, r, nil -} - -func (e *Engine) dropRelation(schema, relation string) (*Schema, *Relation, error) { - - s, err := e.schema(schema) - if err != nil { - return nil, nil, err - } - - r, err := s.Remove(relation) - if err != nil { - return nil, nil, err - } - - return s, r, nil -} - -func (e *Engine) schema(name string) (*Schema, error) { - if name == "" { - name = DefaultSchema - } - - s, ok := e.schemas[name] - if !ok { - return nil, fmt.Errorf("schema '%s' does not exist", name) - } - - return s, nil -} - -func (e *Engine) createSchema(name string) (*Schema, error) { - s, ok := e.schemas[name] - if ok { - return nil, fmt.Errorf("schema '%s' already exist", name) - } - - s = NewSchema(name) - e.schemas[name] = s - return s, nil -} - -func (e *Engine) dropSchema(name string) (*Schema, error) { - s, ok := e.schemas[name] - if !ok { - return nil, fmt.Errorf("schema '%s' does not exist", name) - } - - delete(e.schemas, name) - return s, nil -} diff --git a/vendor/github.com/proullon/ramsql/engine/agnostic/index.go b/vendor/github.com/proullon/ramsql/engine/agnostic/index.go deleted file mode 100644 index 06cc363..0000000 --- a/vendor/github.com/proullon/ramsql/engine/agnostic/index.go +++ /dev/null @@ -1,138 +0,0 @@ -package agnostic - -import ( - "container/list" - "fmt" - "hash/maphash" - "unsafe" -) - -type IndexType int - -const ( - HashIndexType IndexType = iota - BTreeIndexType -) - -type Index interface { - Truncate() - Add(*list.Element) - Remove(*list.Element) - Name() string - CanSourceWith(p Predicate) (bool, int64) - Get(values []any) (*list.Element, error) -} - -type HashIndex struct { - name string - relName string - relAttrs []string - attrs []int - attrsName []string - m map[uint64]uintptr - - maphash.Hash -} - -func NewHashIndex(name string, relName string, relAttrs []Attribute, attrsName []string, attrs []int) *HashIndex { - h := &HashIndex{ - name: name, - relName: relName, - attrs: attrs, - attrsName: attrsName, - m: make(map[uint64]uintptr), - } - h.SetSeed(maphash.MakeSeed()) - for _, a := range relAttrs { - h.relAttrs = append(h.relAttrs, a.name) - } - return h -} - -func (h *HashIndex) Name() string { - return h.name -} - -func (h *HashIndex) Add(e *list.Element) { - t := e.Value.(*Tuple) - for _, idx := range h.attrs { - if t.values[idx] == nil { - h.Write([]byte("nil")) - continue - } - h.Write([]byte(fmt.Sprintf("%v", t.values[idx]))) - } - sum := h.Sum64() - h.Reset() - h.m[sum] = uintptr(unsafe.Pointer(e)) -} - -func (h *HashIndex) Remove(e *list.Element) { - t := e.Value.(*Tuple) - for _, idx := range h.attrs { - if t.values[idx] == nil { - h.Write([]byte("nil")) - continue - } - h.Write([]byte(fmt.Sprintf("%v", t.values[idx]))) - } - sum := h.Sum64() - h.Reset() - delete(h.m, sum) -} - -func (h *HashIndex) Get(values []any) (*list.Element, error) { - for _, v := range values { - if v == nil { - h.Write([]byte("nil")) - continue - } - h.Write([]byte(fmt.Sprintf("%v", v))) - } - sum := h.Sum64() - h.Reset() - - var t *list.Element - ptr, ok := h.m[sum] - if !ok { - return nil, nil - // return nil, fmt.Errorf("could not find sum '%d' (%v) in index %s", sum, values, h) - } - - t = (*list.Element)(unsafe.Pointer(ptr)) - return t, nil -} - -func (h *HashIndex) Truncate() { - h.m = make(map[uint64]uintptr) -} - -func (h *HashIndex) String() string { - return h.Name() -} - -func (h *HashIndex) CanSourceWith(p Predicate) (bool, int64) { - if p.Relation() != h.relName { - return false, 0 - } - - if p.Type() != Eq { - return false, 0 - } - - var found bool - for _, l := range h.attrsName { - found = false - for _, r := range p.Attribute() { - if l == r || h.relName+"."+l == r { - found = true - break - } - } - if !found { - return false, 0 - } - } - - return true, 1 -} diff --git a/vendor/github.com/proullon/ramsql/engine/agnostic/predicate.go b/vendor/github.com/proullon/ramsql/engine/agnostic/predicate.go deleted file mode 100644 index 726e3d1..0000000 --- a/vendor/github.com/proullon/ramsql/engine/agnostic/predicate.go +++ /dev/null @@ -1,2192 +0,0 @@ -package agnostic - -import ( - "bytes" - "container/list" - "errors" - "fmt" - "hash/maphash" - "reflect" - "sort" - "strings" - "time" - - "github.com/proullon/ramsql/engine/log" -) - -type PredicateType int - -const ( - And PredicateType = iota - Or - Eq - Geq - Leq - Le - Ge - Neq - Like - In - Not - True - False -) - -var ( - NotImplemented = errors.New("not implemented") -) - -// Picker interface is used by query planner to define -// which relations and attributes are used in a query. -// -// Can be empty. -// -// Selector and Predicate implement Picker. -type Picker interface { - Relation() string - Attribute() []string -} - -// ValueFunctor is used by Predicate to compare values -// -// Possible ValueFunctor implementation: -// - ConstValueFunctor -// - AttributeValueFunctor -// - NowValueFunctor -type ValueFunctor interface { - Picker - Value(columns []string, tuple *Tuple) any -} - -// Selector defines values to be returned to user -// -// Possible Selector implementations: -// - Attribute -// - Star -// - Max -// - Min -// - Avg -// - ... -type Selector interface { - Picker - Alias() string - Select([]string, []*list.Element) ([]*Tuple, error) -} - -// Predicate defines filter to be applied on spcified relation row -type Predicate interface { - Picker - Type() PredicateType - Left() (Predicate, bool) - Right() (Predicate, bool) - Eval([]string, *Tuple) (bool, error) -} - -type Source interface { - HasNext() bool - Next() *list.Element - EstimateCardinal() int64 - Columns() []string -} - -// Node is an element of a quey plan -// -// Joiner, Sorter and Scanner implement Node. -type Node interface { - Exec() ([]string, []*list.Element, error) - EstimateCardinal() int64 - Children() []Node -} - -type SubqueryNode struct { - src Node -} - -func NewSubqueryNode(src Node) *SubqueryNode { - sn := &SubqueryNode{ - src: src, - } - return sn -} - -func (sn SubqueryNode) String() string { - buf := new(bytes.Buffer) - - PrintQueryPlan(sn.src, 1, func(format string, varargs ...any) { - fmt.Fprintf(buf, format, varargs...) - }) - - return buf.String() -} - -func (sn *SubqueryNode) Exec() ([]string, []*list.Element, error) { - return sn.src.Exec() -} - -func (sn *SubqueryNode) EstimateCardinal() int64 { - return sn.src.EstimateCardinal() -} -func (sn *SubqueryNode) Children() []Node { - return sn.src.Children() -} - -// Joiner joins two relation together. -// -// Should be able to estimate cardinality of join for cost optimization. -// -// Possible implementations: -// - NaturalJoiner -// - LeftOuterJoiner -// - RightOuterJoiner -// - FullOuterJoiner -type Joiner interface { - Node - Left() string - SetLeft(n Node) - Right() string - SetRight(n Node) -} - -type Joiners []Joiner - -func (js Joiners) Len() int { - return len(js) -} - -func (js Joiners) Less(i, j int) bool { - return js[i].EstimateCardinal() < js[j].EstimateCardinal() -} - -func (js Joiners) Swap(i, j int) { - js[i], js[j] = js[j], js[i] -} - -// Scanner produce results by scanning the relation. -// -// The query plan initialize a Scanner for each relation with: -// * The best source possible regarding cost (Hashmap, Btree, SeqScan) -// * A (possibly) recursive predicate to filter on -type Scanner interface { - Node - Append(Predicate) -} - -// Sorter produce a sorted result from single child node -// -// GroupBy (-10000) before Having (-5000) before Order (0) before Distinct (1000) before Offset (5000) before Limit (10000). -// -// # GroupBy must contains both selector node and last join to compute arithmetic on all groups -// -// Possible implementations: -// - OrderAscSort -// - OrderDescSort -// - HavingSort -// - DistinctSort -// - Limit -// - Offset -type Sorter interface { - Node - Priority() int - SetNode(Node) -} - -// Sorters sort the sorters \o/ -// -// Why ? I don't want to put on package caller the responsability to order them correctly. It's up to the query planner. -type Sorters []Sorter - -func (js Sorters) Len() int { - return len(js) -} - -func (js Sorters) Less(i, j int) bool { - return js[i].Priority() < js[j].Priority() -} - -func (js Sorters) Swap(i, j int) { - js[i], js[j] = js[j], js[i] -} - -type OffsetSorter struct { - o int - src Node -} - -func NewOffsetSorter(o int) *OffsetSorter { - return &OffsetSorter{o: o} -} - -func (s OffsetSorter) String() string { - return fmt.Sprintf("Offset %d on %s", s.o, s.src) -} - -func (s *OffsetSorter) Exec() ([]string, []*list.Element, error) { - cols, res, err := s.src.Exec() - if err != nil { - return nil, nil, err - } - - if len(res) > s.o { - res = res[s.o:] - } - return cols, res, nil -} - -func (s *OffsetSorter) EstimateCardinal() int64 { - if s.src != nil { - return int64(s.src.EstimateCardinal()/2) + 1 - } - return 0 -} - -func (s *OffsetSorter) Children() []Node { - return []Node{s.src} -} - -func (s *OffsetSorter) Priority() int { - return 5000 -} - -func (s *OffsetSorter) SetNode(n Node) { - s.src = n -} - -type GroupBySorter struct { - rel string - attrs []string - src Node - selector Node -} - -func NewGroupBySorter(rel string, attrs []string) *GroupBySorter { - return &GroupBySorter{rel: rel, attrs: attrs} -} - -func (s GroupBySorter) String() string { - return fmt.Sprintf("GroupBy %s.%v", s.rel, s.attrs) -} - -func (s *GroupBySorter) Exec() ([]string, []*list.Element, error) { - cols, res, err := s.src.Exec() - if err != nil { - return nil, nil, err - } - - return cols, res, nil -} - -func (s *GroupBySorter) EstimateCardinal() int64 { - if s.src != nil { - return int64(s.src.EstimateCardinal()/2) + 1 - } - return 0 -} - -func (s *GroupBySorter) Children() []Node { - return []Node{s.src} -} - -func (s *GroupBySorter) Priority() int { - return 0 -} - -func (s *GroupBySorter) SetNode(n Node) { - s.src = n -} - -func (s *GroupBySorter) SetSelector(n Node) { - s.selector = n -} - -type SortType int - -const ( - ASC SortType = iota - DESC -) - -type SortExpression struct { - attr string - direction SortType -} - -func NewSortExpression(attr string, direction SortType) SortExpression { - return SortExpression{attr: attr, direction: direction} -} - -type OrderBySorter struct { - rel string - attrs []SortExpression - src Node -} - -func NewOrderBySorter(rel string, attrs []SortExpression) *OrderBySorter { - s := &OrderBySorter{rel: rel, attrs: attrs} - - return s -} - -func (s OrderBySorter) String() string { - return fmt.Sprintf("OrderBy %s.%v", s.rel, s.attrs) -} - -func (s *OrderBySorter) Exec() ([]string, []*list.Element, error) { - cols, res, err := s.src.Exec() - if err != nil { - return nil, nil, err - } - - var idxs []int - for _, a := range s.attrs { - for i, c := range cols { - if c == a.attr || c == s.rel+"."+a.attr { - idxs = append(idxs, i) - } - } - } - - closure := func(t1idx, t2idx int) bool { - var comp bool - t1 := res[t1idx] - t2 := res[t2idx] - - for i, idx := range idxs { - v1 := t1.Value.(*Tuple).values[idx] - v2 := t2.Value.(*Tuple).values[idx] - - eq, err := equal(v1, v2) - if err != nil { - log.Warn("%s: %s", s, err) - return false - } - if eq { - continue - } - - if s.attrs[i].direction == ASC { - comp, err = greater(v2, v1) - } else { - comp, err = greater(v1, v2) - } - if err != nil { - log.Warn("%s: %s", s, err) - return false - } - return comp - } - return true - } - - sort.Slice(res, closure) - return cols, res, nil -} - -func (s *OrderBySorter) EstimateCardinal() int64 { - if s.src != nil { - return s.src.EstimateCardinal() - } - return 0 -} - -func (s *OrderBySorter) Children() []Node { - return []Node{s.src} -} - -func (s *OrderBySorter) Priority() int { - return 0 -} - -func (s *OrderBySorter) SetNode(n Node) { - s.src = n -} - -type LimitSorter struct { - limit int64 - src Node -} - -func NewLimitSorter(limit int64) *LimitSorter { - return &LimitSorter{limit: limit} -} - -func (s LimitSorter) String() string { - return fmt.Sprintf("Limit %d", s.limit) -} - -func (d *LimitSorter) Exec() ([]string, []*list.Element, error) { - - cols, res, err := d.src.Exec() - if err != nil { - return nil, nil, err - } - if len(res) > int(d.limit) { - res = res[:d.limit] - } - - return cols, res, nil -} - -func (d *LimitSorter) EstimateCardinal() int64 { - return d.limit -} - -func (d *LimitSorter) Children() []Node { - return []Node{d.src} -} - -func (d *LimitSorter) Priority() int { - return 10000 -} - -func (d *LimitSorter) SetNode(n Node) { - d.src = n -} - -type DistinctSorter struct { - rel string - attrs []string - src Node -} - -func NewDistinctSorter(rel string, attrs []string) *DistinctSorter { - return &DistinctSorter{rel: rel, attrs: attrs} -} - -func (s DistinctSorter) String() string { - return fmt.Sprintf("Distinct on %s.%v", s.rel, s.attrs) -} - -func (d *DistinctSorter) Exec() ([]string, []*list.Element, error) { - m := make(map[uint64]*list.Element) - var h maphash.Hash - var ok bool - - h.SetSeed(maphash.MakeSeed()) - - cols, in, err := d.src.Exec() - if err != nil { - return nil, nil, err - } - - var idxs []int - for _, a := range d.attrs { - for i, c := range cols { - if c == a || c == d.rel+"."+a { - idxs = append(idxs, i) - } - } - } - - for _, t := range in { - for _, idx := range idxs { - h.Write([]byte(fmt.Sprintf("%v", t.Value.(*Tuple).values[idx]))) - } - sum := h.Sum64() - h.Reset() - _, ok = m[sum] - if !ok { - m[sum] = t - } - } - - res := make([]*list.Element, len(m)) - var i int - for _, t := range m { - res[i] = t - i++ - } - return cols, res, nil -} - -func (d *DistinctSorter) EstimateCardinal() int64 { - if d.src != nil { - return int64(d.src.EstimateCardinal()/2) + 1 - } - return 0 -} - -func (d *DistinctSorter) Children() []Node { - return []Node{d.src} -} - -func (d *DistinctSorter) Priority() int { - return 1000 -} - -func (d *DistinctSorter) SetNode(n Node) { - d.src = n -} - -type AttributeSelector struct { - relation string - attributes []string - alias string -} - -func NewAttributeSelector(rel string, attrs []string, functors ...func(*AttributeSelector)) *AttributeSelector { - s := &AttributeSelector{ - relation: rel, - attributes: attrs, - } - - for _, f := range functors { - f(s) - } - - return s -} - -func WithAlias(alias string) func(*AttributeSelector) { - return func(s *AttributeSelector) { - s.alias = alias - attr := s.attributes - s.attributes = nil - for _, a := range attr { - s.attributes = append(s.attributes, s.alias+"."+a) - } - } -} - -func (s AttributeSelector) String() string { - return fmt.Sprintf("%s.%s", s.relation, s.attributes) -} - -func (s *AttributeSelector) Attribute() []string { - return s.attributes -} - -func (s *AttributeSelector) Relation() string { - return s.relation -} - -func (s *AttributeSelector) Alias() string { - return s.alias -} - -func (s *AttributeSelector) Select(cols []string, in []*list.Element) (out []*Tuple, err error) { - idx := make([]int, len(s.attributes)) - for attrIdx, attr := range s.attributes { - idx[attrIdx] = -1 - lattr := strings.ToLower(attr) - lrelation := strings.ToLower(s.relation) - for i, c := range cols { - lc := strings.ToLower(c) - if lc == lattr { - idx[attrIdx] = i - break - } - if lc == lrelation+"."+lattr { - idx[attrIdx] = i - break - } - if s.alias+"."+lc == lattr { - idx[attrIdx] = i - break - } - } - if idx[attrIdx] == -1 { - return nil, fmt.Errorf("AttributeSelector(%s) not found in %s", attr, cols) - } - } - - colsLen := len(cols) - for _, e := range in { - if e == nil { - return nil, fmt.Errorf("provided tuple is nil") - } - srct := e.Value.(*Tuple) - if srct == nil { - return nil, fmt.Errorf("provided tuple is nil") - } - if len(srct.values) != colsLen { - return nil, fmt.Errorf("provided tuple %v does not match anounced columns %s", srct.values, cols) - } - - t := NewTuple() - for _, id := range idx { - v := srct.values[id] - t.Append(v) - } - out = append(out, t) - } - - return -} - -type CountSelector struct { - relation string - attribute string - alias string - cols []string -} - -func NewCountSelector(rname string, attr string) *CountSelector { - s := &CountSelector{ - relation: rname, - attribute: attr, - } - return s -} - -func (s *CountSelector) Attribute() []string { - if s.cols != nil { - return s.cols - } - - if s.attribute == "*" { - return nil - } - - return []string{s.attribute} -} - -func (s *CountSelector) Relation() string { - return s.relation -} - -func (s *CountSelector) Alias() string { - return s.alias -} - -func (s *CountSelector) Select(cols []string, in []*list.Element) (out []*Tuple, err error) { - var idx int - idx = -1 - for i, c := range cols { - if s.attribute == "*" || c == s.attribute || c == s.relation+"."+s.attribute { - idx = i - break - } - } - if idx == -1 { - return nil, fmt.Errorf("%s.%s: columns not found in left node", s.relation, s.attribute) - } - - s.cols = []string{"COUNT(" + s.attribute + ")"} - t := NewTuple(int64(len(in))) - out = append(out, t) - return -} - -type StarSelector struct { - relation string - alias string - cols []string -} - -func NewStarSelector(rname string) *StarSelector { - s := &StarSelector{ - relation: rname, - } - return s -} - -func (s *StarSelector) Attribute() []string { - return s.cols -} - -func (s *StarSelector) Relation() string { - return s.relation -} - -func (s *StarSelector) Alias() string { - return s.alias -} - -func (s *StarSelector) Select(cols []string, in []*list.Element) (out []*Tuple, err error) { - var colIdx []int - - // if only 1 relation, can return directly - for i, c := range cols { - if !strings.Contains(c, ".") { - out = make([]*Tuple, len(in)) - for i, e := range in { - t, ok := e.Value.(*Tuple) - if !ok { - return nil, fmt.Errorf("provided element list does not contain Tuple") - } - out[i] = t - } - s.cols = cols - return - } - if strings.HasPrefix(c, s.relation) { - s.cols = append(s.cols, strings.Split(c, ".")[1]) - colIdx = append(colIdx, i) - } - } - // need to re-select table - for _, e := range in { - intup := e.Value.(*Tuple) - outtup := &Tuple{values: make([]any, len(colIdx))} - for i, idx := range colIdx { - outtup.values[i] = intup.values[idx] - } - out = append(out, outtup) - } - return -} - -func (s StarSelector) String() string { - return s.relation + ".*" -} - -type AvgSelector struct { -} - -type MaxSelector struct { -} - -func NewComparisonPredicate(left ValueFunctor, t PredicateType, right ValueFunctor) (Predicate, error) { - - switch t { - case Eq: - return NewEqPredicate(left, right), nil - case Geq: - return NewGeqPredicate(left, right), nil - case Leq: - return NewLeqPredicate(left, right), nil - case Le: - return NewLePredicate(left, right), nil - case Ge: - return NewGePredicate(left, right), nil - case Neq: - return NewNeqPredicate(left, right), nil - default: - return nil, fmt.Errorf("unknown predicate type %v", t) - } - -} - -type NotPredicate struct { - src Predicate -} - -func NewNotPredicate(src Predicate) *NotPredicate { - return &NotPredicate{src: src} -} - -func (p NotPredicate) String() string { - return fmt.Sprintf("NOT %s", p.src) -} - -func (p *NotPredicate) Type() PredicateType { - return Not -} - -func (p *NotPredicate) Eval(cols []string, t *Tuple) (bool, error) { - - e, err := p.src.Eval(cols, t) - if err != nil { - return false, err - } - - return !e, nil -} - -func (p *NotPredicate) Left() (Predicate, bool) { - return nil, false -} - -func (p *NotPredicate) Right() (Predicate, bool) { - return nil, false -} - -func (p *NotPredicate) Relation() string { - return p.src.Relation() -} - -func (p *NotPredicate) Attribute() []string { - return p.src.Attribute() -} - -type InPredicate struct { - v ValueFunctor - src Node - cols []string - res []*Tuple -} - -func NewInPredicate(v ValueFunctor, src Node) *InPredicate { - p := &InPredicate{v: v, src: src} - return p -} - -func (p InPredicate) String() string { - return fmt.Sprintf("%s IN %s", p.v, p.src) -} - -func (p *InPredicate) Type() PredicateType { - return In -} - -func (p *InPredicate) Eval(inCols []string, in *Tuple) (bool, error) { - - if p.res == nil { - cols, res, err := p.src.Exec() - if err != nil { - return false, err - } - p.cols = cols - for _, e := range res { - p.res = append(p.res, e.Value.(*Tuple)) - } - } - - lv := p.v.Value(inCols, in) - - for _, t := range p.res { - rv := t.values[0] - eq, err := equal(lv, rv) - if eq { - return true, nil - } - if err != nil { - return false, err - } - } - - return false, nil -} - -func (p *InPredicate) Left() (Predicate, bool) { - return nil, false -} - -func (p *InPredicate) Right() (Predicate, bool) { - return nil, false -} - -func (p *InPredicate) Relation() string { - return p.v.Relation() -} - -func (p *InPredicate) Attribute() []string { - return p.v.Attribute() -} - -type TruePredicate struct { -} - -func NewTruePredicate() *TruePredicate { - return &TruePredicate{} -} - -func (p TruePredicate) String() string { - return "TRUE" -} - -func (p *TruePredicate) Type() PredicateType { - return True -} - -func (p *TruePredicate) Eval([]string, *Tuple) (bool, error) { - return true, nil -} - -func (p *TruePredicate) Left() (Predicate, bool) { - return nil, false -} - -func (p *TruePredicate) Right() (Predicate, bool) { - return nil, false -} - -func (p *TruePredicate) Relation() string { - return "" -} - -func (p *TruePredicate) Attribute() []string { - return nil -} - -type FalsePredicate struct { -} - -func NewFalsePredicate() *FalsePredicate { - return &FalsePredicate{} -} - -func (p FalsePredicate) String() string { - return "FALSE" -} - -func (p *FalsePredicate) Type() PredicateType { - return False -} - -func (p *FalsePredicate) Eval([]string, *Tuple) (bool, error) { - return false, nil -} - -func (p *FalsePredicate) Left() (Predicate, bool) { - return nil, false -} - -func (p *FalsePredicate) Right() (Predicate, bool) { - return nil, false -} - -func (p *FalsePredicate) Relation() string { - return "" -} - -func (p *FalsePredicate) Attribute() []string { - return nil -} - -type AndPredicate struct { - left Predicate - right Predicate -} - -func NewAndPredicate(left, right Predicate) *AndPredicate { - p := &AndPredicate{ - left: left, - right: right, - } - - return p -} - -func (p AndPredicate) String() string { - return fmt.Sprintf("%s AND %s", p.left, p.right) -} - -func (p *AndPredicate) Type() PredicateType { - return And -} - -func (p *AndPredicate) Eval(cols []string, t *Tuple) (bool, error) { - - l, err := p.left.Eval(cols, t) - if err != nil { - return false, err - } - - r, err := p.right.Eval(cols, t) - if err != nil { - return false, err - } - - if l && r { - return true, nil - } - - return false, nil -} - -func (p *AndPredicate) Left() (Predicate, bool) { - return p.left, true -} - -func (p *AndPredicate) Right() (Predicate, bool) { - return p.right, true -} - -func (p *AndPredicate) Relation() string { - if p.left != nil && p.right != nil && p.left.Relation() == p.right.Relation() { - return p.left.Relation() - } - return "" -} - -func (p *AndPredicate) Attribute() []string { - return append(p.left.Attribute(), p.right.Attribute()...) -} - -type OrPredicate struct { - left Predicate - right Predicate -} - -func NewOrPredicate(left, right Predicate) *OrPredicate { - p := &OrPredicate{ - left: left, - right: right, - } - - return p -} - -func (p OrPredicate) String() string { - return fmt.Sprintf("%s OR %s", p.left, p.right) -} - -func (p *OrPredicate) Type() PredicateType { - return And -} - -func (p *OrPredicate) Eval(cols []string, t *Tuple) (bool, error) { - - l, err := p.left.Eval(cols, t) - if err != nil { - return false, err - } - - r, err := p.right.Eval(cols, t) - if err != nil { - return false, err - } - - if l || r { - return true, nil - } - - return false, nil -} - -func (p *OrPredicate) Left() (Predicate, bool) { - return p.left, true -} - -func (p *OrPredicate) Right() (Predicate, bool) { - return p.right, true -} - -func (p *OrPredicate) Relation() string { - if p.left != nil && p.right != nil && p.left.Relation() == p.right.Relation() { - return p.left.Relation() - } - return "" -} - -func (p *OrPredicate) Attribute() []string { - return append(p.left.Attribute(), p.right.Attribute()...) -} - -type EqPredicate struct { - left ValueFunctor - right ValueFunctor -} - -func NewEqPredicate(left, right ValueFunctor) *EqPredicate { - p := &EqPredicate{ - left: left, - right: right, - } - - return p -} - -func (p *EqPredicate) Type() PredicateType { - return Eq -} - -func (p EqPredicate) String() string { - return fmt.Sprintf("%s = %s", p.left, p.right) -} - -func (p *EqPredicate) Eval(cols []string, t *Tuple) (bool, error) { - - vl := p.left.Value(cols, t) - vr := p.right.Value(cols, t) - - return equal(vl, vr) -} - -func (p *EqPredicate) Left() (Predicate, bool) { - return nil, false -} - -func (p *EqPredicate) Right() (Predicate, bool) { - return nil, false -} - -func (p *EqPredicate) Relation() string { - if p.left.Relation() != "" { - return p.left.Relation() - } - - return p.right.Relation() -} - -func (p *EqPredicate) Attribute() []string { - return append(p.left.Attribute(), p.right.Attribute()...) -} - -type ListNode struct { - res []*list.Element -} - -func NewListNode(values ...any) *ListNode { - n := &ListNode{} - - list := list.New() - - for _, v := range values { - e := list.PushBack(NewTuple(v)) - n.res = append(n.res, e) - } - - return n -} - -func (ln ListNode) String() string { - return fmt.Sprintf("CONST_LIST (%d)", len(ln.res)) -} - -func (ln *ListNode) Exec() ([]string, []*list.Element, error) { - return []string{""}, ln.res, nil -} - -func (ln *ListNode) EstimateCardinal() int64 { - return int64(len(ln.res)) -} - -func (ln *ListNode) Children() []Node { - return nil -} - -type SelectorNode struct { - selectors []Selector - child Node - columns []string -} - -func NewSelectorNode(selectors []Selector, n Node) *SelectorNode { - sn := &SelectorNode{ - selectors: selectors, - child: n, - } - - for _, selector := range sn.selectors { - sn.columns = append(sn.columns, selector.Attribute()...) - } - - return sn -} - -func (sn SelectorNode) String() string { - return fmt.Sprintf("Select %s", sn.columns) -} - -func (sn *SelectorNode) Exec() ([]string, []*list.Element, error) { - cols, srcs, err := sn.child.Exec() - if err != nil { - return nil, nil, err - } - if len(sn.selectors) == 0 { - return cols, srcs, nil - } - - outs := make([][]*Tuple, len(sn.selectors)) - var resc []string - - var prevLen int - for i, selector := range sn.selectors { - out, err := selector.Select(cols, srcs) - if err != nil { - return nil, nil, err - } - outs[i] = out - if i != 0 && len(out) != prevLen { - return nil, nil, fmt.Errorf("selectors have different cardinals (%d and %d)", len(out), prevLen) - } - prevLen = len(out) - resc = append(resc, selector.Attribute()...) - } - - // We have prevLen rows with l columns to return - res := make([]*list.Element, prevLen) - l := len(resc) - rl := list.New() - // for each new tuple, concatenate values returned by all selectors - for i := 0; i < prevLen; i++ { - t := &Tuple{values: make([]any, l)} - var tidx int - // for each selector returned Tuple - for x := range outs { - // concatenate values to unified tuple - for y := range outs[x][i].values { - t.values[tidx] = outs[x][i].values[y] - tidx++ - } - } - - e := rl.PushBack(t) - res[i] = e - } - - return resc, res, nil -} - -func (sn *SelectorNode) Columns() []string { - return sn.columns -} - -func (sn *SelectorNode) EstimateCardinal() int64 { - return sn.child.EstimateCardinal() -} - -func (sn *SelectorNode) Children() []Node { - return []Node{sn.child} -} - -type NaturalJoin struct { - leftr string - lefta string - left Node - - rightr string - righta string - right Node -} - -func NewNaturalJoin(leftRel, leftAttr, rightRel, rightAttr string) *NaturalJoin { - j := &NaturalJoin{ - leftr: leftRel, - lefta: leftAttr, - rightr: rightRel, - righta: rightAttr, - } - return j -} - -func (j NaturalJoin) String() string { - return "JOIN " + j.leftr + "." + j.lefta + " >< " + j.rightr + "." + j.righta -} - -func (j *NaturalJoin) Left() string { - return j.leftr -} - -func (j *NaturalJoin) SetLeft(n Node) { - j.left = n -} - -func (j *NaturalJoin) Right() string { - return j.rightr -} - -func (j *NaturalJoin) SetRight(n Node) { - j.right = n -} - -func (j *NaturalJoin) EstimateCardinal() int64 { - if j.left == nil || j.right == nil { - return 0 - } - - return int64((j.left.EstimateCardinal() * j.right.EstimateCardinal()) / 2) -} - -func (j *NaturalJoin) Children() []Node { - return []Node{j.left, j.right} -} - -func (j *NaturalJoin) Exec() ([]string, []*list.Element, error) { - - lcols, lefts, err := j.left.Exec() - if err != nil { - return nil, nil, err - } - var lidx int - lidx = -1 - for i, c := range lcols { - if c == j.lefta || c == j.leftr+"."+j.lefta { - lidx = i - break - } - } - if lidx == -1 { - return nil, nil, fmt.Errorf("%s: columns not found in left node", j) - } - log.Debug("NaturalJoin.Exec: Found left (%s) %d in %v", j.lefta, lidx, lcols) - - rcols, rights, err := j.right.Exec() - if err != nil { - return nil, nil, err - } - var ridx int - ridx = -1 - for i, c := range rcols { - if c == j.righta || c == j.rightr+"."+j.righta { - ridx = i - break - } - } - if ridx == -1 { - return nil, nil, fmt.Errorf("%s: columns not found in right node", j) - } - log.Debug("NaturalJoin.Exec: Found right (%s) %d in %v", j.righta, ridx, rcols) - - cols := make([]string, len(lcols)+len(rcols)) - var idx int - for _, c := range lcols { - if strings.Contains(c, ".") { - cols[idx] = c - } else { - cols[idx] = j.leftr + "." + c - } - idx++ - } - for _, c := range rcols { - if strings.Contains(c, ".") { - cols[idx] = c - } else { - cols[idx] = j.rightr + "." + c - } - idx++ - } - - log.Debug("NaturalJoin.Exec: New cols: %v", cols) - - // prepare for worst case cross join - l := list.New() - for _, left := range lefts { - for _, right := range rights { - ok, err := equal(left.Value.(*Tuple).values[lidx], right.Value.(*Tuple).values[ridx]) - if err != nil { - return nil, nil, err - } - if ok { - t := NewTuple(left.Value.(*Tuple).values...) - t.Append(right.Value.(*Tuple).values...) - l.PushBack(t) - } - } - } - idx = 0 - res := make([]*list.Element, l.Len()) - for e := l.Front(); e != nil; e = e.Next() { - res[idx] = e - idx++ - } - - return cols, res, nil -} - -type ConstValueFunctor struct { - v any -} - -// NewConstValueFunctor creates a ValueFunctor returning v -func NewConstValueFunctor(v any) ValueFunctor { - f := &ConstValueFunctor{ - v: v, - } - return f -} - -func (f *ConstValueFunctor) Value([]string, *Tuple) any { - return f.v -} - -func (f *ConstValueFunctor) Relation() string { - return "" -} - -func (f *ConstValueFunctor) Attribute() []string { - return nil -} - -func (f ConstValueFunctor) String() string { - return fmt.Sprintf("const %v (%s)", f.v, reflect.TypeOf(f.v)) -} - -type AttributeValueFunctor struct { - rname string - aname string -} - -// NewAttributeValueFunctor creates a ValueFunctor returning attribute value in given tuple -func NewAttributeValueFunctor(rname, aname string) ValueFunctor { - f := &AttributeValueFunctor{ - rname: rname, - aname: aname, - } - - return f -} - -func (f *AttributeValueFunctor) Value(cols []string, t *Tuple) any { - var idx = -1 - for i, c := range cols { - if c == f.aname || c == f.rname+"."+f.aname { - idx = i - break - } - } - if idx == -1 { - return nil - } - return t.values[idx] -} - -func (f *AttributeValueFunctor) Relation() string { - return f.rname -} - -func (f *AttributeValueFunctor) Attribute() []string { - return []string{f.aname} -} - -func (f AttributeValueFunctor) String() string { - return f.rname + "." + f.aname -} - -type NowValueFunctor struct { -} - -// NewNowValueFunctor creates a ValueFunctor returning time.Now() -func NewNowValueFunctor() ValueFunctor { - f := &NowValueFunctor{} - return f -} - -func (f *NowValueFunctor) Value([]string, *Tuple) any { - return time.Now() -} - -func (f *NowValueFunctor) Relation() string { - return "" -} - -func (f *NowValueFunctor) Attribute() []string { - return nil -} - -func (f NowValueFunctor) String() string { - return "now()" -} - -type GeqPredicate struct { - left ValueFunctor - right ValueFunctor -} - -func NewGeqPredicate(left, right ValueFunctor) *GeqPredicate { - p := &GeqPredicate{ - left: left, - right: right, - } - - return p -} - -func (p *GeqPredicate) Type() PredicateType { - return Geq -} - -func (p GeqPredicate) String() string { - return fmt.Sprintf("%s >= %s", p.left, p.right) -} - -func (p *GeqPredicate) Eval(cols []string, t *Tuple) (bool, error) { - vl := p.left.Value(cols, t) - l := reflect.ValueOf(vl) - vr := p.right.Value(cols, t) - r := reflect.ValueOf(vr) - - if vl == nil && vr == nil { - return true, nil - } - if vl == nil || vr == nil { - return false, nil - } - - switch l.Kind() { - default: - return false, fmt.Errorf("%s not comparable", l) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if !r.CanInt() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Int() >= r.Int(), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - if !r.CanUint() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Uint() >= r.Uint(), nil - case reflect.Float32, reflect.Float64: - if !r.CanFloat() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Float() >= r.Float(), nil - case reflect.String: - return l.String() >= r.String(), nil - case reflect.Struct: // time.Time ? - switch vl.(type) { - case time.Time: - ltime := vl.(time.Time) - rtime, ok := vr.(time.Time) - if !ok { - return false, fmt.Errorf("%s not comparable", p) - } - return ltime.Unix() >= rtime.Unix(), nil - default: - return false, fmt.Errorf("%s not comparable", p) - } - } -} - -func (p *GeqPredicate) Left() (Predicate, bool) { - return nil, false -} - -func (p *GeqPredicate) Right() (Predicate, bool) { - return nil, false -} - -func (p *GeqPredicate) Relation() string { - if p.left.Relation() != "" { - return p.left.Relation() - } - - return p.right.Relation() -} - -func (p *GeqPredicate) Attribute() []string { - return append(p.left.Attribute(), p.right.Attribute()...) -} - -type LeqPredicate struct { - left ValueFunctor - right ValueFunctor -} - -func NewLeqPredicate(left, right ValueFunctor) *LeqPredicate { - p := &LeqPredicate{ - left: left, - right: right, - } - - return p -} - -func (p *LeqPredicate) Type() PredicateType { - return Leq -} - -func (p LeqPredicate) String() string { - return fmt.Sprintf("%s <= %s", p.left, p.right) -} - -func (p *LeqPredicate) Eval(cols []string, t *Tuple) (bool, error) { - vl := p.left.Value(cols, t) - l := reflect.ValueOf(vl) - vr := p.right.Value(cols, t) - r := reflect.ValueOf(vr) - - if vl == nil && vr == nil { - return true, nil - } - if vl == nil || vr == nil { - return false, nil - } - - switch l.Kind() { - default: - return false, fmt.Errorf("%s not comparable", l) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if !r.CanInt() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Int() <= r.Int(), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - if !r.CanUint() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Uint() <= r.Uint(), nil - case reflect.Float32, reflect.Float64: - if !r.CanFloat() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Float() <= r.Float(), nil - case reflect.String: - return l.String() <= r.String(), nil - case reflect.Struct: // time.Time ? - switch vl.(type) { - case time.Time: - ltime := vl.(time.Time) - rtime, ok := vr.(time.Time) - if !ok { - return false, fmt.Errorf("%s not comparable", p) - } - return ltime.Unix() <= rtime.Unix(), nil - default: - return false, fmt.Errorf("%s not comparable", p) - } - } -} - -func (p *LeqPredicate) Left() (Predicate, bool) { - return nil, false -} - -func (p *LeqPredicate) Right() (Predicate, bool) { - return nil, false -} - -func (p *LeqPredicate) Relation() string { - if p.left.Relation() != "" { - return p.left.Relation() - } - - return p.right.Relation() -} - -func (p *LeqPredicate) Attribute() []string { - return append(p.left.Attribute(), p.right.Attribute()...) -} - -type LePredicate struct { - left ValueFunctor - right ValueFunctor -} - -func NewLePredicate(left, right ValueFunctor) *LePredicate { - p := &LePredicate{ - left: left, - right: right, - } - - return p -} - -func (p *LePredicate) Type() PredicateType { - return Le -} - -func (p LePredicate) String() string { - return fmt.Sprintf("%s < %s", p.left, p.right) -} - -func (p *LePredicate) Eval(cols []string, t *Tuple) (bool, error) { - vl := p.left.Value(cols, t) - l := reflect.ValueOf(vl) - vr := p.right.Value(cols, t) - r := reflect.ValueOf(vr) - - if vl == nil && vr == nil { - return false, nil - } - if vl == nil || vr == nil { - return false, nil - } - - switch l.Kind() { - default: - return false, fmt.Errorf("%s not comparable", l) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if !r.CanInt() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Int() < r.Int(), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - if !r.CanUint() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Uint() < r.Uint(), nil - case reflect.Float32, reflect.Float64: - if !r.CanFloat() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Float() < r.Float(), nil - case reflect.String: - return l.String() < r.String(), nil - case reflect.Struct: // time.Time ? - switch vl.(type) { - case time.Time: - ltime := vl.(time.Time) - rtime, ok := vr.(time.Time) - if !ok { - return false, fmt.Errorf("%s not comparable", p) - } - return ltime.Before(rtime), nil - default: - return false, fmt.Errorf("%s not comparable", p) - } - } -} - -func (p *LePredicate) Left() (Predicate, bool) { - return nil, false -} - -func (p *LePredicate) Right() (Predicate, bool) { - return nil, false -} - -func (p *LePredicate) Relation() string { - if p.left.Relation() != "" { - return p.left.Relation() - } - - return p.right.Relation() -} - -func (p *LePredicate) Attribute() []string { - return append(p.left.Attribute(), p.right.Attribute()...) -} - -type GePredicate struct { - left ValueFunctor - right ValueFunctor -} - -func NewGePredicate(left, right ValueFunctor) *GePredicate { - p := &GePredicate{ - left: left, - right: right, - } - - return p -} - -func (p *GePredicate) Type() PredicateType { - return Ge -} - -func (p GePredicate) String() string { - return fmt.Sprintf("%s > %s", p.left, p.right) -} - -func (p *GePredicate) Eval(cols []string, t *Tuple) (bool, error) { - vl := p.left.Value(cols, t) - // l := reflect.ValueOf(vl) - vr := p.right.Value(cols, t) - // r := reflect.ValueOf(vr) - - return greater(vl, vr) -} - -/* - switch l.Kind() { - default: - return false, fmt.Errorf("%s not comparable", p) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if !r.CanInt() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Int() > r.Int(), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - if !r.CanUint() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Uint() > r.Uint(), nil - case reflect.Float32, reflect.Float64: - if !r.CanFloat() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Float() > r.Float(), nil - case reflect.String: - return l.String() > r.String(), nil - case reflect.Struct: // time.Time ? - switch vl.(type) { - case time.Time: - ltime := vl.(time.Time) - rtime, ok := vr.(time.Time) - if !ok { - return false, fmt.Errorf("%s not comparable", p) - } - return ltime.After(rtime), nil - default: - return false, fmt.Errorf("%s not comparable", p) - } - } -} -*/ - -func (p *GePredicate) Left() (Predicate, bool) { - return nil, false -} - -func (p *GePredicate) Right() (Predicate, bool) { - return nil, false -} - -func (p *GePredicate) Relation() string { - if p.left.Relation() != "" { - return p.left.Relation() - } - - return p.right.Relation() -} - -func (p *GePredicate) Attribute() []string { - return append(p.left.Attribute(), p.right.Attribute()...) -} - -type NeqPredicate struct { - left ValueFunctor - right ValueFunctor -} - -func NewNeqPredicate(left, right ValueFunctor) *NeqPredicate { - p := &NeqPredicate{ - left: left, - right: right, - } - - return p -} - -func (p *NeqPredicate) Type() PredicateType { - return Neq -} - -func (p NeqPredicate) String() string { - return fmt.Sprintf("%s != %s", p.left, p.right) -} - -func (p *NeqPredicate) Eval(cols []string, t *Tuple) (bool, error) { - vl := p.left.Value(cols, t) - l := reflect.ValueOf(vl) - vr := p.right.Value(cols, t) - r := reflect.ValueOf(vr) - - if vl == nil && vr == nil { - return false, nil - } - if vl == nil || vr == nil { - return true, nil - } - - if l.Kind() == r.Kind() { - return !l.Equal(r), nil - } - - switch l.Kind() { - default: - return false, fmt.Errorf("%s not comparable", l) - case reflect.Bool: - if r.Kind() != reflect.Bool { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Bool() != r.Bool(), nil - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if !r.CanInt() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Int() != r.Int(), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - if !r.CanUint() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Uint() != r.Uint(), nil - case reflect.Float32, reflect.Float64: - if !r.CanFloat() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Float() != r.Float(), nil - case reflect.Complex64, reflect.Complex128: - if !r.CanComplex() { - return false, fmt.Errorf("%s not comparable", p) - } - return l.Complex() != r.Complex(), nil - case reflect.String: - return l.String() != r.String(), nil - case reflect.Chan, reflect.Pointer, reflect.UnsafePointer: - return l.Pointer() != r.Pointer(), nil - case reflect.Struct: // time.Time ? - switch vl.(type) { - case time.Time: - ltime := vl.(time.Time) - rtime, ok := vr.(time.Time) - if !ok { - return false, fmt.Errorf("%s not comparable", p) - } - return ltime.Unix() != rtime.Unix(), nil - default: - return false, fmt.Errorf("%s not comparable", p) - } - } -} - -func (p *NeqPredicate) Left() (Predicate, bool) { - return nil, false -} - -func (p *NeqPredicate) Right() (Predicate, bool) { - return nil, false -} - -func (p *NeqPredicate) Relation() string { - if p.left.Relation() != "" { - return p.left.Relation() - } - - return p.right.Relation() -} - -func (p *NeqPredicate) Attribute() []string { - return append(p.left.Attribute(), p.right.Attribute()...) -} - -func equal(vl, vr any) (bool, error) { - l := reflect.ValueOf(vl) - r := reflect.ValueOf(vr) - - if vl == nil && vr == nil { - return true, nil - } - if vl == nil || vr == nil { - return false, nil - } - - if l.Kind() == r.Kind() { - return l.Equal(r), nil - } - - switch l.Kind() { - case reflect.Bool: - if r.Kind() == reflect.Bool { - return l.Bool() == r.Bool(), nil - } - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if r.CanInt() { - return l.Int() == r.Int(), nil - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - if r.CanUint() { - return l.Uint() == r.Uint(), nil - } - case reflect.Float32, reflect.Float64: - if r.CanFloat() { - return l.Float() == r.Float(), nil - } - case reflect.Complex64, reflect.Complex128: - if r.CanComplex() { - return l.Complex() == r.Complex(), nil - } - case reflect.String: - return l.String() == r.String(), nil - case reflect.Chan, reflect.Pointer, reflect.UnsafePointer: - return l.Pointer() == r.Pointer(), nil - case reflect.Struct: // time.Time ? - switch vl.(type) { - case time.Time: - ltime := vl.(time.Time) - rtime, ok := vr.(time.Time) - if ok { - return ltime.Unix() == rtime.Unix(), nil - } - } - } - - return false, fmt.Errorf("%v (%v) and %v (%v) not comparable", vl, reflect.TypeOf(vl), vr, reflect.TypeOf(vr)) -} - -func greater(vl, vr any) (bool, error) { - l := reflect.ValueOf(vl) - r := reflect.ValueOf(vr) - - if vl == nil && vr == nil { - return false, nil - } - if vl == nil { - return false, nil - } - if vr == nil { - return true, nil - } - - switch l.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if r.CanInt() { - return l.Int() > r.Int(), nil - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - if r.CanUint() { - return l.Uint() > r.Uint(), nil - } - case reflect.Float32, reflect.Float64: - if r.CanFloat() { - return l.Float() > r.Float(), nil - } - case reflect.String: - return l.String() > r.String(), nil - case reflect.Struct: // time.Time ? - switch vl.(type) { - case time.Time: - ltime := vl.(time.Time) - rtime, ok := vr.(time.Time) - if ok { - return ltime.After(rtime), nil - } - } - } - - return false, fmt.Errorf("%v (%v) and %v (%v) not comparable", vl, reflect.TypeOf(vl), vr, reflect.TypeOf(vr)) -} - -type Updater struct { - rel string - rows *list.List - changes *list.List - values map[string]any - attrs []string - child Node - attributes []Attribute - indexes []Index -} - -func NewUpdaterNode(relation *Relation, changes *list.List, values map[string]any) *Updater { - u := &Updater{ - rel: relation.name, - rows: relation.rows, - changes: changes, - values: values, - attributes: relation.attributes, - indexes: relation.indexes, - } - - for k := range values { - u.attrs = append(u.attrs, strings.ToLower(k)) - } - return u -} - -func (u Updater) String() string { - return fmt.Sprintf("UPDATE on %s values %s with %s", u.rel, u.values, u.child) -} - -func (u *Updater) Children() []Node { - return []Node{u.child} -} - -func (u *Updater) EstimateCardinal() int64 { - return u.child.EstimateCardinal() -} - -func (u *Updater) Exec() (cols []string, out []*list.Element, err error) { - var in []*list.Element - - cols, in, err = u.child.Exec() - if err != nil { - return nil, nil, err - } - - for _, e := range in { - t := e.Value.(*Tuple) - - newt := &Tuple{ - values: make([]any, len(t.values)), - } - - for i, v := range t.values { - nv := v - attr := u.attributes[i] - if val, ok := u.values[cols[i]]; ok { - if val == nil { - newt.values[i] = nil - delete(u.values, cols[i]) - continue - } - tof := reflect.TypeOf(val) - if !tof.ConvertibleTo(attr.typeInstance) { - return nil, nil, fmt.Errorf("cannot assign '%v' (type %s) to %s.%s (type %s)", val, tof, u.rel, attr.name, attr.typeInstance) - } - nv = reflect.ValueOf(val).Convert(attr.typeInstance).Interface() - log.Debug("Updating %s to %v", attr.name, nv) - } - - newt.values[i] = nv - delete(u.values, cols[i]) - } - - newe := u.rows.InsertAfter(newt, e) - if newe == nil { - return nil, nil, fmt.Errorf("cannot update rows %v with %v, element not in rows", e, newe) - } - u.rows.Remove(e) - for _, i := range u.indexes { - i.Remove(e) - } - for _, i := range u.indexes { - i.Add(newe) - } - out = append(out, newe) - - c := &ValueChange{ - current: newe, - old: e, - l: u.rows, - } - u.changes.PushBack(c) - } - - if len(u.values) > 0 { - return nil, nil, fmt.Errorf("attribute %s not existing in relation %s, %s", u.values, u.rel, u.attributes) - } - return cols, out, nil -} - -func (u *Updater) Relation() string { - return u.rel -} - -func (u *Updater) Attribute() []string { - return u.attrs -} - -type Deleter struct { - rel string - rows *list.List - changes *list.List - child Node - attributes []Attribute - indexes []Index -} - -func NewDeleterNode(relation *Relation, changes *list.List) *Deleter { - u := &Deleter{ - rel: relation.name, - rows: relation.rows, - changes: changes, - attributes: relation.attributes, - indexes: relation.indexes, - } - - return u -} - -func (u Deleter) String() string { - return fmt.Sprintf("DELETE on %s with %s", u.rel, u.child) -} - -func (u *Deleter) Children() []Node { - return []Node{u.child} -} - -func (u *Deleter) EstimateCardinal() int64 { - return u.child.EstimateCardinal() -} - -func (u *Deleter) Exec() (cols []string, out []*list.Element, err error) { - var in []*list.Element - - cols, in, err = u.child.Exec() - if err != nil { - return nil, nil, err - } - - for _, t := range in { - - u.rows.Remove(t) - for _, i := range u.indexes { - i.Remove(t) - } - - out = append(out, t) - - c := &ValueChange{ - current: nil, - old: t, - l: u.rows, - } - u.changes.PushBack(c) - } - - return cols, out, nil -} - -func (u *Deleter) Relation() string { - return u.rel -} - -func (u *Deleter) Attribute() []string { - // return u.child.Attribute() - return []string{} -} diff --git a/vendor/github.com/proullon/ramsql/engine/agnostic/relation.go b/vendor/github.com/proullon/ramsql/engine/agnostic/relation.go deleted file mode 100644 index 9a42f4a..0000000 --- a/vendor/github.com/proullon/ramsql/engine/agnostic/relation.go +++ /dev/null @@ -1,143 +0,0 @@ -package agnostic - -import ( - "container/list" - "fmt" - "strings" - "sync" -) - -type Relation struct { - name string - schema string - - attributes []Attribute - attrIndex map[string]int - // indexes of primary key attributes - pk []int - - // list of Tuple - rows *list.List - - indexes []Index - - sync.RWMutex -} - -func NewRelation(schema, name string, attributes []Attribute, pk []string) (*Relation, error) { - r := &Relation{ - name: name, - schema: schema, - attributes: attributes, - attrIndex: make(map[string]int), - rows: list.New(), - } - - // create utils to manage attributes - for i, a := range r.attributes { - r.attrIndex[a.name] = i - } - for _, k := range pk { - r.pk = append(r.pk, r.attrIndex[k]) - } - - // if primary key is specified, create Hash index - if len(r.pk) != 0 { - r.indexes = append(r.indexes, NewHashIndex("pk_"+schema+"_"+name, name, attributes, pk, r.pk)) - } - - // if unique is specified, create Hash index - for i, a := range r.attributes { - if a.unique { - r.indexes = append(r.indexes, NewHashIndex("unique_"+schema+"_"+name+"_"+a.name, name, attributes, []string{a.name}, []int{i})) - } - } - - return r, nil -} - -func (r *Relation) CheckPrimaryKey(tuple *Tuple) (bool, error) { - if len(r.pk) == 0 { - return true, nil - } - - var index Index - for i := range r.indexes { - if strings.HasPrefix(r.indexes[i].Name(), "pk") { - index = r.indexes[i] - break - } - } - if index == nil { - return false, fmt.Errorf("primary key index not found") - } - - var vals []any - for _, idx := range r.pk { - vals = append(vals, tuple.values[idx]) - } - - e, err := index.Get(vals) - if err != nil { - return false, err - } - if e == nil { - return true, nil - } - - return false, nil -} - -func (r *Relation) Attribute(name string) (int, Attribute, error) { - name = strings.ToLower(name) - index, ok := r.attrIndex[name] - if !ok { - return 0, Attribute{}, fmt.Errorf("attribute not defined: %s.%s", r.name, name) - } - return index, r.attributes[index], nil -} - -func (r *Relation) createIndex(name string, t IndexType, attrs []string) error { - - switch t { - case HashIndexType: - var attrsIdx []int - for _, a := range attrs { - for i, rela := range r.attributes { - if a == rela.name { - attrsIdx = append(attrsIdx, i) - break - } - } - } - i := NewHashIndex(name, r.name, r.attributes, attrs, attrsIdx) - r.indexes = append(r.indexes, i) - return nil - case BTreeIndexType: - return fmt.Errorf("BTree index are not implemented") - } - - return fmt.Errorf("unknown index type: %d", t) -} - -func (r *Relation) Truncate() int64 { - r.Lock() - defer r.Unlock() - - l := r.rows.Len() - - for _, i := range r.indexes { - i.Truncate() - } - - r.rows = list.New() - - return int64(l) -} - -func (r *Relation) String() string { - if r.schema != "" { - return r.schema + "." + r.name - } - return r.name -} diff --git a/vendor/github.com/proullon/ramsql/engine/agnostic/scanner.go b/vendor/github.com/proullon/ramsql/engine/agnostic/scanner.go deleted file mode 100644 index a2a841f..0000000 --- a/vendor/github.com/proullon/ramsql/engine/agnostic/scanner.go +++ /dev/null @@ -1,73 +0,0 @@ -package agnostic - -import ( - "container/list" - "fmt" -) - -type RelationScanner struct { - src Source - predicates []Predicate -} - -func NewRelationScanner(src Source, predicates []Predicate) *RelationScanner { - s := &RelationScanner{ - src: src, - predicates: predicates, - } - - return s -} - -func (s RelationScanner) String() string { - return fmt.Sprintf("scan %s with %s", s.src, s.predicates) -} - -func (s *RelationScanner) Append(p Predicate) { - s.predicates = append(s.predicates, p) -} - -func (s *RelationScanner) Exec() ([]string, []*list.Element, error) { - var ok bool - var err error - var res []*list.Element - var canAppend bool - - cols := s.src.Columns() - for s.src.HasNext() { - t := s.src.Next() - canAppend = true - for _, p := range s.predicates { - ok, err = p.Eval(cols, t.Value.(*Tuple)) - if err != nil { - return nil, nil, fmt.Errorf("RelationScanner.Exec: %s(%v) : %w", p, t, err) - } - if !ok { - canAppend = false - break - } - } - if canAppend { - res = append(res, t) - } - } - - return cols, res, nil -} - -// No idea on how to estimate cardinal of scanner given predicates -// -// min: 0 -// max: len(src) -// avg: len(src)/2 -func (s *RelationScanner) EstimateCardinal() int64 { - if len(s.predicates) == 0 { - return s.src.EstimateCardinal() - } - - return int64(s.src.EstimateCardinal()/2) + 1 -} - -func (s *RelationScanner) Children() []Node { - return nil -} diff --git a/vendor/github.com/proullon/ramsql/engine/agnostic/schema.go b/vendor/github.com/proullon/ramsql/engine/agnostic/schema.go deleted file mode 100644 index 45ad0a8..0000000 --- a/vendor/github.com/proullon/ramsql/engine/agnostic/schema.go +++ /dev/null @@ -1,56 +0,0 @@ -package agnostic - -import ( - "fmt" - "sync" -) - -type Schema struct { - name string - relations map[string]*Relation - - sync.RWMutex -} - -func NewSchema(name string) *Schema { - s := &Schema{ - name: name, - relations: make(map[string]*Relation), - } - - return s -} - -func (s *Schema) Relation(name string) (*Relation, error) { - s.RLock() - defer s.RUnlock() - - r, ok := s.relations[name] - if !ok { - // panic("lol") - return nil, fmt.Errorf("relation '%s'.'%s' does not exist", s.name, name) - } - - return r, nil -} - -func (s *Schema) Add(name string, r *Relation) { - s.Lock() - defer s.Unlock() - - s.relations[name] = r -} - -func (s *Schema) Remove(name string) (*Relation, error) { - s.Lock() - defer s.Unlock() - - r, ok := s.relations[name] - if !ok { - // panic("remove") - return nil, fmt.Errorf("relation '%s'.'%s' does not exist", s.name, name) - } - - delete(s.relations, name) - return r, nil -} diff --git a/vendor/github.com/proullon/ramsql/engine/agnostic/source.go b/vendor/github.com/proullon/ramsql/engine/agnostic/source.go deleted file mode 100644 index 13e0397..0000000 --- a/vendor/github.com/proullon/ramsql/engine/agnostic/source.go +++ /dev/null @@ -1,118 +0,0 @@ -package agnostic - -import ( - "container/list" - "fmt" -) - -type IndexSrc struct { - tuple *list.Element - hasNext bool - rname string - cols []string -} - -func NewHashIndexSource(index Index, alias string, p Predicate) (*IndexSrc, error) { - s := &IndexSrc{} - - i, ok := index.(*HashIndex) - if !ok { - return nil, fmt.Errorf("index %s is not a HashIndex", index) - } - s.rname = i.relName - s.cols = i.relAttrs - - if alias != "" { - s.rname = alias - } - - eq, ok := p.(*EqPredicate) - if !ok { - return nil, fmt.Errorf("predicate %s is not a Eq predicate", p) - } - - t, err := i.Get([]any{eq.right.Value(nil, nil)}) - if err != nil { - return nil, fmt.Errorf("cannot create NewHashIndexSource(%s,%s): %s", index, p, err) - } - - s.tuple = t - if t != nil { - s.hasNext = true - } - return s, nil -} - -func (s IndexSrc) String() string { - return "IndexScan on " + s.rname -} - -func (s *IndexSrc) HasNext() bool { - return s.hasNext -} - -func (s *IndexSrc) Next() *list.Element { - if !s.hasNext { - return nil - } - s.hasNext = false - return s.tuple -} - -func (s *IndexSrc) Columns() []string { - return s.cols -} - -func (s *IndexSrc) EstimateCardinal() int64 { - if s.tuple != nil { - return 1 - } - return 0 -} - -type SeqScanSrc struct { - e *list.Element - card int64 - rname string - cols []string -} - -func NewSeqScan(r *Relation, alias string) *SeqScanSrc { - s := &SeqScanSrc{ - e: r.rows.Front(), - card: int64(r.rows.Len()), - rname: r.name, - } - if alias != "" { - s.rname = alias - } - for _, a := range r.attributes { - s.cols = append(s.cols, a.name) - } - return s -} - -func (s SeqScanSrc) String() string { - return "SeqScan on " + s.rname -} - -func (s *SeqScanSrc) HasNext() bool { - return s.e != nil -} - -func (s *SeqScanSrc) Next() *list.Element { - if s.e == nil { - return nil - } - t := s.e - s.e = s.e.Next() - return t -} - -func (s *SeqScanSrc) EstimateCardinal() int64 { - return s.card -} - -func (s *SeqScanSrc) Columns() []string { - return s.cols -} diff --git a/vendor/github.com/proullon/ramsql/engine/agnostic/transaction.go b/vendor/github.com/proullon/ramsql/engine/agnostic/transaction.go deleted file mode 100644 index 997e9a4..0000000 --- a/vendor/github.com/proullon/ramsql/engine/agnostic/transaction.go +++ /dev/null @@ -1,768 +0,0 @@ -package agnostic - -import ( - "container/list" - "errors" - "fmt" - "reflect" - "sort" - - "github.com/proullon/ramsql/engine/log" -) - -type Transaction struct { - e *Engine - locks map[string]*Relation - - // list of Change - changes *list.List - - err error -} - -func NewTransaction(e *Engine) (*Transaction, error) { - t := Transaction{ - e: e, - locks: make(map[string]*Relation), - changes: list.New(), - } - - return &t, nil -} - -func (t *Transaction) Commit() (int, error) { - if err := t.aborted(); err != nil { - return 0, err - } - - changed := t.changes.Len() - - // Remove links to be GC'd faster - for { - b := t.changes.Back() - if b == nil { - break - } - t.changes.Remove(b) - } - - t.unlock() - t.err = fmt.Errorf("transaction committed") - return changed, nil -} - -func (t *Transaction) Rollback() { - if err := t.aborted(); err != nil { - return - } - - for { - b := t.changes.Back() - if b == nil { - break - } - switch b.Value.(type) { - case ValueChange: - c := b.Value.(ValueChange) - t.rollbackValueChange(c) - case RelationChange: - c := b.Value.(RelationChange) - t.rollbackRelationChange(c) - } - t.changes.Remove(b) - } - - t.unlock() -} - -func (t Transaction) Error() error { - return t.err -} - -func (t *Transaction) Truncate(schema, relation string) (int64, error) { - if err := t.aborted(); err != nil { - return 0, err - } - - s, err := t.e.schema(schema) - if err != nil { - return 0, err - } - - r, err := s.Relation(relation) - if err != nil { - return 0, err - } - - c := r.Truncate() - - return c, nil -} - -func (t *Transaction) RelationAttribute(schName, relName, attrName string) (int, Attribute, error) { - if err := t.aborted(); err != nil { - return 0, Attribute{}, err - } - - s, err := t.e.schema(schName) - if err != nil { - return 0, Attribute{}, err - } - - r, err := s.Relation(relName) - if err != nil { - return 0, Attribute{}, err - } - - return r.Attribute(attrName) -} - -func (t *Transaction) CheckRelation(schemaName, relName string) bool { - if err := t.aborted(); err != nil { - return false - } - - s, err := t.e.schema(schemaName) - if err != nil { - return false - } - - _, err = s.Relation(relName) - return err == nil -} - -func (t *Transaction) CreateRelation(schemaName, relName string, attributes []Attribute, pk []string) error { - if err := t.aborted(); err != nil { - return err - } - - s, r, err := t.e.createRelation(schemaName, relName, attributes, pk) - if err != nil { - return t.abort(err) - } - - c := RelationChange{ - schema: s, - current: r, - old: nil, - } - t.changes.PushBack(c) - log.Debug("CreateRelation(%s,%s,%s,%s)", schemaName, relName, attributes, pk) - - t.lock(r) - return nil -} - -func (t *Transaction) DropRelation(schemaName, relName string) error { - if err := t.aborted(); err != nil { - return err - } - - s, r, err := t.e.dropRelation(schemaName, relName) - if err != nil { - return t.abort(err) - } - - c := RelationChange{ - schema: s, - current: nil, - old: r, - } - t.changes.PushBack(c) - - return nil -} - -func (t *Transaction) CheckSchema(schemaName string) bool { - if err := t.aborted(); err != nil { - return false - } - - _, err := t.e.schema(schemaName) - return err == nil -} - -func (t *Transaction) CreateSchema(schemaName string) error { - if err := t.aborted(); err != nil { - return err - } - - s, err := t.e.createSchema(schemaName) - if err != nil { - return t.abort(err) - } - - c := SchemaChange{ - current: s, - old: nil, - e: t.e, - } - t.changes.PushBack(c) - log.Debug("CreateSchema(%s)", schemaName) - - return nil -} - -func (t *Transaction) DropSchema(schemaName string) error { - if err := t.aborted(); err != nil { - return err - } - - s, err := t.e.dropSchema(schemaName) - if err != nil { - return t.abort(err) - } - - c := SchemaChange{ - current: nil, - old: s, - e: t.e, - } - t.changes.PushBack(c) - - return nil -} - -func (t *Transaction) CreateIndex(schema, relation, index string, it IndexType, attrs []string) error { - if err := t.aborted(); err != nil { - return err - } - - s, err := t.e.schema(schema) - if err != nil { - return err - } - - r, err := s.Relation(relation) - if err != nil { - return err - } - - t.lock(r) - - err = r.createIndex(index, it, attrs) - if err != nil { - return err - } - log.Debug("CreateIndex(%s, %s, %s, %s)", schema, relation, index, attrs) - - return nil -} - -// Delete rows from relation. -// -// Delete node needs to be inserted right as child of selector node. -func (t *Transaction) Delete(schema, relation string, selectors []Selector, p Predicate) ([]string, []*Tuple, error) { - if err := t.aborted(); err != nil { - return nil, nil, err - } - - s, err := t.e.schema(schema) - if err != nil { - return nil, nil, err - } - - r, err := s.Relation(relation) - if err != nil { - return nil, nil, err - } - - n, err := t.Plan(schema, selectors, p, nil, nil) - if err != nil { - return nil, nil, err - } - - snode, ok := n.(*SelectorNode) - if !ok { - return nil, nil, fmt.Errorf("could not find selector node") - } - - un := NewDeleterNode(r, t.changes) - - snode.child, un.child = un, snode.child - - log.Debug("DELETE(%s, %s, %s, %s)", schema, relation, selectors, p) - PrintQueryPlan(n, 0, nil) - - // (4), (5), (6) - cols, eres, err := n.Exec() - if err != nil { - return nil, nil, t.abort(err) - } - - res := make([]*Tuple, len(eres)) - for i, e := range eres { - res[i] = e.Value.(*Tuple) - } - - return cols, res, nil -} - -// Update relation with given values. -// -// Update node needs to be inserted right as child of selector node. -func (t *Transaction) Update(schema, relation string, values map[string]any, selectors []Selector, p Predicate) ([]string, []*Tuple, error) { - if err := t.aborted(); err != nil { - return nil, nil, err - } - - s, err := t.e.schema(schema) - if err != nil { - return nil, nil, err - } - - r, err := s.Relation(relation) - if err != nil { - return nil, nil, err - } - - n, err := t.Plan(schema, selectors, p, nil, nil) - if err != nil { - return nil, nil, err - } - - snode, ok := n.(*SelectorNode) - if !ok { - return nil, nil, fmt.Errorf("could not find selector node") - } - - un := NewUpdaterNode(r, t.changes, values) - - snode.child, un.child = un, snode.child - - log.Debug("Update(%s, %s, %s, %s, %s)", schema, relation, values, selectors, p) - PrintQueryPlan(n, 0, nil) - - // (4), (5), (6) - cols, eres, err := n.Exec() - if err != nil { - return nil, nil, t.abort(err) - } - - res := make([]*Tuple, len(eres)) - for i, e := range eres { - res[i] = e.Value.(*Tuple) - } - - return cols, res, nil -} - -// Build tuple for given relation -// for each column: -// - if not specified, use default value if set -// - if specified: -// - check domain -// - check unique -// - check foreign key -// -// If tuple is valid, then -// - check primary key -// - insert into rows list -// - update index if any -func (t *Transaction) Insert(schema, relation string, values map[string]any) (*Tuple, error) { - if err := t.aborted(); err != nil { - return nil, err - } - - s, err := t.e.schema(schema) - if err != nil { - return nil, t.abort(err) - } - r, err := s.Relation(relation) - if err != nil { - return nil, t.abort(err) - } - - t.lock(r) - - log.Debug("Insert into %s.%s: %v", schema, relation, values) - - tuple := &Tuple{} - for i, attr := range r.attributes { - val, specified := values[attr.name] - if !specified { - if attr.defaultValue != nil { - tuple.Append(attr.defaultValue()) - continue - } - if attr.autoIncrement { - tuple.Append(reflect.ValueOf(attr.nextValue).Convert(attr.typeInstance).Interface()) - r.attributes[i].nextValue++ - continue - } - } - if specified { - if val == nil { - tuple.Append(val) - delete(values, attr.name) - continue - } - tof := reflect.TypeOf(val) - if !tof.ConvertibleTo(attr.typeInstance) { - return nil, t.abort(fmt.Errorf("cannot assign '%v' (type %s) to %s.%s (type %s)", val, tof, relation, attr.name, attr.typeInstance)) - } - if attr.unique { - f := NewAttributeValueFunctor(r.name, attr.name) - p := NewEqPredicate(f, f) - for _, index := range r.indexes { - if ok, _ := index.CanSourceWith(p); !ok { - continue - } - idx, ok := index.(*HashIndex) - if !ok { - return nil, t.abort(fmt.Errorf("cannot check unicity of %s", attr)) - } - tuple, err := idx.Get([]any{val}) - if err != nil { - return nil, t.abort(fmt.Errorf("cannot check unicity of %s", attr)) - } - if tuple != nil { - return nil, t.abort(fmt.Errorf("constraint violation: %s unicity", attr)) - } - } - } - if attr.fk != nil { - // TODO: predicate: equal - } - tuple.Append(reflect.ValueOf(val).Convert(attr.typeInstance).Interface()) - delete(values, attr.name) - continue - } - return nil, t.abort(fmt.Errorf("no value for %s.%s", relation, attr.name)) - } - - // if values map is not empty, then an non existing attribute was specified - for k := range values { - return nil, t.abort(fmt.Errorf("attribute %s does not exist in relation %s", k, relation)) - } - - // check primary key violation - ok, err := r.CheckPrimaryKey(tuple) - if err != nil { - return nil, t.abort(err) - } - if !ok { - return nil, t.abort(fmt.Errorf("primary key violation")) - } - - // insert into row list - log.Debug("Inserting %v", tuple.values) - e := r.rows.PushBack(tuple) - - // update indexes - for _, index := range r.indexes { - index.Add(e) - } - - // add change - c := ValueChange{ - current: e, - old: nil, - l: r.rows, - } - t.changes.PushBack(c) - - return tuple, nil -} - -// Query data from relations -// -// cf: https://en.wikipedia.org/wiki/Query_optimization -// -// cf: https://en.wikipedia.org/wiki/Relational_algebra -// -// * (1) Transaction safety : list all touched relations and lock them -// * (2) Sourcing : evaluate which indexes query can use for each relation. HashIndex > Btree > SeqScan -// * (3) Join ordering : estimate the cardinality (Join selection factor) of each relation after predicates filtering, then order the join by lower cardinality -// * (4) Selection : build filtered relations on each leaf (parallelisation possible) -// * (5) Join : join filtered relations on each node recursively -// * (6) Return result : return result to user with selectors -// -// TODO: foreign keys should have hashmap index -func (t *Transaction) Query(schema string, selectors []Selector, p Predicate, joiners []Joiner, sorters []Sorter) ([]string, []*Tuple, error) { - if err := t.aborted(); err != nil { - return nil, nil, err - } - - n, err := t.Plan(schema, selectors, p, joiners, sorters) - if err != nil { - return nil, nil, err - } - PrintQueryPlan(n, 0, nil) - - // (4), (5), (6) - columns, eres, err := n.Exec() - if err != nil { - return nil, nil, t.abort(err) - } - - res := make([]*Tuple, len(eres)) - for i, e := range eres { - res[i] = e.Value.(*Tuple) - } - - return columns, res, nil -} - -func recAppendPredicates(rname string, sc Scanner, p Predicate) { - if p.Relation() == rname { - sc.Append(p) - return - } - - if lp, ok := p.Left(); ok { - recAppendPredicates(rname, sc, lp) - } - if rp, ok := p.Right(); ok { - recAppendPredicates(rname, sc, rp) - } -} - -func (t *Transaction) Plan(schema string, selectors []Selector, p Predicate, joiners []Joiner, sorters []Sorter) (Node, error) { - if err := t.aborted(); err != nil { - return nil, err - } - - s, err := t.e.schema(schema) - if err != nil { - return nil, t.abort(err) - } - - if p == nil { - return nil, t.abort(errors.New("query requires 1 predicate")) - } - - aliases := make(map[string]string) - - // (1) - relations := make(map[string]*Relation) - err = t.recLock(schema, relations, p) - if err != nil { - return nil, t.abort(err) - } - for _, sel := range selectors { - rel := sel.Relation() - r, err := s.Relation(rel) - if err != nil { - return nil, t.abort(err) - } - if a := sel.Alias(); a != "" { - aliases[rel] = a - } - t.lock(r) - relations[rel] = r - } - - // (2) - sources := make(map[string]Source) - var sourceCost int64 - for _, r := range relations { - for _, index := range r.indexes { - cost, ok, p := recCanUseIndex(r.name, index, p) - if ok && (sourceCost == 0 || cost < sourceCost) { - log.Debug("choosing %s as source for relation %s", index, r) - newsrc, err := NewHashIndexSource(index, getAlias(r.name, aliases), p) - if err != nil { - continue - } - sources[r.name] = newsrc - sourceCost = cost - } - } - if _, ok := sources[r.name]; !ok { - log.Debug("could not find suitable index for relation %s, using seq scan", r) - sources[r.name] = NewSeqScan(r, getAlias(r.name, aliases)) - } - } - - // (3) - // build nodes for each relations - scanners := make(map[string]Scanner) - for _, r := range relations { - sc := NewRelationScanner(sources[r.name], nil) - recAppendPredicates(r.name, sc, p) - scanners[r.name] = sc - } - // assign scanner nodes to joiner nodes - for _, j := range joiners { - sc, ok := scanners[j.Left()] - if !ok { - return nil, t.abort(fmt.Errorf("cannot join %s, scanner for %s not found", j, j.Left())) - } - j.SetLeft(sc) - sc, ok = scanners[j.Right()] - if !ok { - return nil, t.abort(fmt.Errorf("cannot join %s, scanner for %s not found", j, j.Right())) - } - j.SetRight(sc) - } - // sort joins by estimated cardinal - sort.Sort(Joiners(joiners)) - // now we need to build tree by replacing gradually already joined relation in bigger join - seen := make(map[string]Node) - for _, n := range joiners { - child, ok := seen[n.Left()] - if !ok { - seen[n.Left()] = n - } else { - n.SetLeft(child) - } - child, ok = seen[n.Right()] - if !ok { - seen[n.Right()] = n - } else { - n.SetRight(child) - } - } - var headJoin Node - if len(joiners) > 0 { - headJoin = joiners[len(joiners)-1] - } else if len(scanners) == 1 { - // should have only on scanner then ? - for _, v := range scanners { - headJoin = v - } - } else { - return nil, t.abort(fmt.Errorf("no join, but got %d scan", len(scanners))) - } - - // append selectors - n := NewSelectorNode(selectors, headJoin) - - // append sorters - // GroupBy must contains both selector node and last join to compute arithmetic on all groups - if len(sorters) > 0 { - sort.Sort(Sorters(sorters)) - var src Node - for i, s := range sorters { - if i == 0 { - src = headJoin - } else { - src = sorters[i-1] - } - - switch s := s.(type) { - case *GroupBySorter: - s.SetNode(src) - s.SetSelector(n) - default: - s.SetNode(src) - } - } - n.child = sorters[len(sorters)-1] - } - - return n, nil -} - -func (t *Transaction) recLock(schema string, relations map[string]*Relation, p Predicate) error { - - s, err := t.e.schema(schema) - if err != nil { - return err - } - if rel := p.Relation(); rel != "" { - r, err := s.Relation(rel) - if err != nil { - return err - } - - relations[p.Relation()] = r - t.lock(r) - } - - if lp, ok := p.Left(); ok { - err = t.recLock(schema, relations, lp) - if err != nil { - return err - } - } - if rp, ok := p.Right(); ok { - err = t.recLock(schema, relations, rp) - if err != nil { - return err - } - } - - return nil -} - -func recCanUseIndex(relName string, index Index, p Predicate) (int64, bool, Predicate) { - if ok, cost := index.CanSourceWith(p); ok { - return cost, ok, p - } - - if lp, ok := p.Left(); ok { - cost, ok, cp := recCanUseIndex(relName, index, lp) - if ok { - return cost, ok, cp - } - } - - if rp, ok := p.Right(); ok { - cost, ok, cp := recCanUseIndex(relName, index, rp) - if ok { - return cost, ok, cp - } - } - - return 0, false, nil -} - -// Lock relations if not already done -func (t *Transaction) lock(r *Relation) { - _, done := t.locks[r.name] - if done { - return - } - - r.Lock() - t.locks[r.name] = r -} - -// Unlock all touched relations -func (t *Transaction) unlock() { - for _, r := range t.locks { - r.Unlock() - } - t.locks = make(map[string]*Relation) -} - -func (t *Transaction) aborted() error { - if t.err != nil { - return fmt.Errorf("transaction aborted due to previous error: %w", t.err) - } - return nil -} - -func (t *Transaction) abort(err error) error { - t.Rollback() - t.err = err - return err -} - -// PrintQueryPlan -func PrintQueryPlan(n Node, depth int, printer func(fmt string, varargs ...any)) { - - if printer == nil { - printer = log.Debug - } - - indent := "" - for i := 0; i < depth; i++ { - indent = fmt.Sprintf("%s ", indent) - } - - printer("%s|-> %s (|A| = %d)\n", indent, n, n.EstimateCardinal()) - for _, child := range n.Children() { - PrintQueryPlan(child, depth+1, printer) - } -} - -func getAlias(name string, alias map[string]string) string { - a, ok := alias[name] - if ok { - return a - } - return "" -} diff --git a/vendor/github.com/proullon/ramsql/engine/agnostic/tuple.go b/vendor/github.com/proullon/ramsql/engine/agnostic/tuple.go deleted file mode 100644 index ee93d0f..0000000 --- a/vendor/github.com/proullon/ramsql/engine/agnostic/tuple.go +++ /dev/null @@ -1,23 +0,0 @@ -package agnostic - -// Tuple is a row in a relation -type Tuple struct { - values []any -} - -// NewTuple should check that value are for the right Attribute and match domain -func NewTuple(values ...any) *Tuple { - t := &Tuple{} - - t.values = append(t.values, values...) - return t -} - -// Append add a value to the tuple -func (t *Tuple) Append(values ...any) { - t.values = append(t.values, values...) -} - -func (t *Tuple) Values() []any { - return t.values -} diff --git a/vendor/github.com/proullon/ramsql/engine/attribute.go b/vendor/github.com/proullon/ramsql/engine/attribute.go new file mode 100644 index 0000000..df01b29 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/attribute.go @@ -0,0 +1,90 @@ +package engine + +import ( + "fmt" + "strings" + "time" + + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/parser" +) + +// Domain is the set of allowable values for an Attribute. +type Domain struct { +} + +// Attribute is a named column of a relation +// AKA Field +// AKA Column +type Attribute struct { + name string + typeName string + typeInstance interface{} + defaultValue interface{} + domain Domain + autoIncrement bool + unique bool +} + +func parseAttribute(decl *parser.Decl) (Attribute, error) { + attr := Attribute{} + + // Attribute name + if decl.Token != parser.StringToken { + return attr, fmt.Errorf("engine: expected attribute name, got %v", decl.Token) + } + attr.name = decl.Lexeme + + // Attribute type + if len(decl.Decl) < 1 { + return attr, fmt.Errorf("Attribute %s has no type", decl.Lexeme) + } + if decl.Decl[0].Token != parser.StringToken { + return attr, fmt.Errorf("engine: expected attribute type, got %v:%v", decl.Decl[0].Token, decl.Decl[0].Lexeme) + } + attr.typeName = decl.Decl[0].Lexeme + + // Maybe domain and special thing like primary key + typeDecl := decl.Decl[1:] + for i := range typeDecl { + log.Debug("Got %v for %s %s", typeDecl[i], attr.name, attr.typeName) + if typeDecl[i].Token == parser.AutoincrementToken { + attr.autoIncrement = true + } + + if typeDecl[i].Token == parser.DefaultToken { + log.Debug("we get a default value for %s: %s!\n", attr.name, typeDecl[i].Decl[0].Lexeme) + switch typeDecl[i].Decl[0].Token { + case parser.LocalTimestampToken, parser.NowToken: + log.Debug("Setting default value to NOW() func !\n") + attr.defaultValue = func() interface{} { return time.Now().Format(parser.DateLongFormat) } + default: + log.Debug("Setting default value to '%v'\n", typeDecl[i].Decl[0].Lexeme) + attr.defaultValue = typeDecl[i].Decl[0].Lexeme + } + } + + // Check if attribute is unique + if typeDecl[i].Token == parser.UniqueToken { + attr.unique = true + } + + } + + if strings.ToLower(attr.typeName) == "bigserial" { + attr.autoIncrement = true + } + + return attr, nil +} + +// NewAttribute initialize a new Attribute struct +func NewAttribute(name string, typeName string, autoIncrement bool) Attribute { + a := Attribute{ + name: name, + typeName: typeName, + autoIncrement: autoIncrement, + } + + return a +} diff --git a/vendor/github.com/proullon/ramsql/engine/condition.go b/vendor/github.com/proullon/ramsql/engine/condition.go new file mode 100644 index 0000000..7609814 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/condition.go @@ -0,0 +1,29 @@ +package engine + +import ( + "fmt" + + "github.com/proullon/ramsql/engine/parser" + "github.com/proullon/ramsql/engine/protocol" +) + +func ifExecutor(e *Engine, ifDecl *parser.Decl, conn protocol.EngineConn) error { + + if len(ifDecl.Decl) == 0 { + return fmt.Errorf("malformed condition") + } + + if e.opsExecutors[ifDecl.Decl[0].Token] != nil { + return e.opsExecutors[ifDecl.Decl[0].Token](e, ifDecl.Decl[0], conn) + } + + return fmt.Errorf("error near %v, unknown keyword", ifDecl.Decl[0].Lexeme) +} + +func notExecutor(e *Engine, tableDecl *parser.Decl, conn protocol.EngineConn) error { + return nil +} + +func existsExecutor(e *Engine, tableDecl *parser.Decl, conn protocol.EngineConn) error { + return nil +} diff --git a/vendor/github.com/proullon/ramsql/engine/delete.go b/vendor/github.com/proullon/ramsql/engine/delete.go new file mode 100644 index 0000000..adccd23 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/delete.go @@ -0,0 +1,75 @@ +package engine + +import ( + // "errors" + "fmt" + + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/parser" + "github.com/proullon/ramsql/engine/protocol" +) + +func deleteExecutor(e *Engine, deleteDecl *parser.Decl, conn protocol.EngineConn) error { + log.Debug("deleteExecutor") + + // get tables to be deleted + tables := fromExecutor(deleteDecl.Decl[0]) + + // If len is 1, it means no predicates so truncate table + if len(deleteDecl.Decl) == 1 { + return truncateTable(e, tables[0], conn) + } + + // get WHERE declaration + predicates, err := whereExecutor(deleteDecl.Decl[1], tables[0].name) + if err != nil { + return err + } + + // and delete + return deleteRows(e, tables, conn, predicates) +} + +func deleteRows(e *Engine, tables []*Table, conn protocol.EngineConn, predicates []Predicate) error { + var rowsDeleted int64 + + r := e.relation(tables[0].name) + if r == nil { + return fmt.Errorf("Table %s not found", tables[0].name) + } + r.Lock() + defer r.Unlock() + + var ok, res bool + var err error + lenRows := len(r.rows) + for i := 0; i < lenRows; i++ { + ok = true + // If the row validate all predicates, write it + for _, predicate := range predicates { + if res, err = predicate.Evaluate(r.rows[i], r.table); err != nil { + return err + } + if res == false { + ok = false + continue + } + } + + if ok { + switch i { + case 0: + r.rows = r.rows[1:] + case lenRows - 1: + r.rows = r.rows[:lenRows-1] + default: + r.rows = append(r.rows[:i], r.rows[i+1:]...) + i-- + } + lenRows-- + rowsDeleted++ + } + } + + return conn.WriteResult(0, rowsDeleted) +} diff --git a/vendor/github.com/proullon/ramsql/engine/distinct.go b/vendor/github.com/proullon/ramsql/engine/distinct.go new file mode 100644 index 0000000..09b4c02 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/distinct.go @@ -0,0 +1,110 @@ +package engine + +import ( + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/protocol" +) + +type distinct struct { + realConn protocol.EngineConn + seen seen + len int +} + +func distinctedConn(conn protocol.EngineConn, len int) protocol.EngineConn { + return &distinct{ + realConn: conn, + len: len, + seen: make(seen), + } +} + +// Not needed +func (l *distinct) ReadStatement() (string, error) { + log.Debug("limit.ReadStatement: should not be used\n") + return "", nil +} + +// Not needed +func (l *distinct) WriteResult(last int64, ra int64) error { + log.Debug("limit.WriteResult: should not be used\n") + return nil +} + +func (l *distinct) WriteError(err error) error { + return l.realConn.WriteError(err) +} + +func (l *distinct) WriteRowHeader(header []string) error { + if l.len > 0 { + // Postgres returns only columns outside of DISTINCT ON + return l.realConn.WriteRowHeader(header[l.len:]) + } + return l.realConn.WriteRowHeader(header) +} + +func (l *distinct) WriteRow(row []string) error { + if l.len > 0 { + if l.seen.exists(row[:l.len]) { + return nil + } + // Postgres returns only columns outside of DISTINCT ON + return l.realConn.WriteRow(row[l.len:]) + } else { + if l.seen.exists(row) { + return nil + } + return l.realConn.WriteRow(row) + } +} + +func (l *distinct) WriteRowEnd() error { + return l.realConn.WriteRowEnd() +} + +func (l *distinct) equalRows(a, b []string) bool { + if l.len > 0 { + if len(a) < l.len || len(b) < l.len { + return false + } + + for idx := 0; idx < l.len; idx++ { + if a[idx] != b[idx] { + return false + } + } + + return true + } + + if len(a) != len(b) { + return false + } + for idx := range a { + if a[idx] != b[idx] { + return false + } + } + + return true +} + +type seen map[string]seen + +func (s seen) exists(r []string) bool { + if c, ok := s[r[0]]; ok { + if len(r) == 1 { + return true + } + + return c.exists(r[1:]) + } + + s[r[0]] = make(seen) + if len(r) == 1 { + return false + } + + // does not exists, but we want to populate the tree fully + return s[r[0]].exists(r[1:]) +} diff --git a/vendor/github.com/proullon/ramsql/engine/drop.go b/vendor/github.com/proullon/ramsql/engine/drop.go new file mode 100644 index 0000000..ac6802a --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/drop.go @@ -0,0 +1,30 @@ +package engine + +import ( + "fmt" + + "github.com/proullon/ramsql/engine/parser" + "github.com/proullon/ramsql/engine/protocol" +) + +func dropExecutor(e *Engine, dropDecl *parser.Decl, conn protocol.EngineConn) error { + + // Should have table token + if dropDecl.Decl == nil || + len(dropDecl.Decl) != 1 || + dropDecl.Decl[0].Token != parser.TableToken || + len(dropDecl.Decl[0].Decl) != 1 { + return fmt.Errorf("unexpected drop arguments") + } + + table := dropDecl.Decl[0].Decl[0].Lexeme + + r := e.relation(table) + if r == nil { + return fmt.Errorf("relation '%s' not found", table) + } + + e.drop(table) + + return conn.WriteResult(0, 1) +} diff --git a/vendor/github.com/proullon/ramsql/engine/engine.go b/vendor/github.com/proullon/ramsql/engine/engine.go new file mode 100644 index 0000000..27af5a5 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/engine.go @@ -0,0 +1,193 @@ +package engine + +import ( + "errors" + "fmt" + "io" + "sync" + + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/parser" + "github.com/proullon/ramsql/engine/protocol" +) + +type executor func(*Engine, *parser.Decl, protocol.EngineConn) error + +// Engine is the root struct of RamSQL server +type Engine struct { + endpoint protocol.EngineEndpoint + relations map[string]*Relation + opsExecutors map[int]executor + + // Any value send to this channel (through Engine.stop) + // Will stop the listening loop + stop chan bool + + sync.Mutex +} + +// New initialize a new RamSQL server +func New(endpoint protocol.EngineEndpoint) (e *Engine, err error) { + + e = &Engine{ + endpoint: endpoint, + } + + e.stop = make(chan bool) + + e.opsExecutors = map[int]executor{ + parser.CreateToken: createExecutor, + parser.TableToken: createTableExecutor, + parser.SelectToken: selectExecutor, + parser.InsertToken: insertIntoTableExecutor, + parser.DeleteToken: deleteExecutor, + parser.UpdateToken: updateExecutor, + parser.IfToken: ifExecutor, + parser.NotToken: notExecutor, + parser.ExistsToken: existsExecutor, + parser.TruncateToken: truncateExecutor, + parser.DropToken: dropExecutor, + parser.GrantToken: grantExecutor, + } + + e.relations = make(map[string]*Relation) + + err = e.start() + if err != nil { + return nil, err + } + + return +} + +func (e *Engine) start() (err error) { + go e.listen() + return nil +} + +// Stop shutdown the RamSQL server +func (e *Engine) Stop() { + if e.stop == nil { + // already stopped + return + } + go func() { + e.stop <- true + close(e.stop) + e.stop = nil + }() +} + +func (e *Engine) relation(name string) *Relation { + // Lock ? + r := e.relations[name] + // Unlock ? + + return r +} + +func (e *Engine) drop(name string) { + e.Lock() + delete(e.relations, name) + e.Unlock() +} + +func (e *Engine) listen() { + newConnectionChannel := make(chan protocol.EngineConn) + + go func() { + for { + conn, err := e.endpoint.Accept() + if err != nil { + e.Stop() + return + } + + newConnectionChannel <- conn + } + }() + + for { + select { + case conn := <-newConnectionChannel: + go e.handleConnection(conn) + break + + case <-e.stop: + e.endpoint.Close() + return + } + } + +} + +func (e *Engine) handleConnection(conn protocol.EngineConn) { + + for { + stmt, err := conn.ReadStatement() + if err == io.EOF { + // Todo: close engine if there is no conn left + return + } + if err != nil { + log.Warning("Enginge.handleConnection: cannot read : %s", err) + return + } + + instructions, err := parser.ParseInstruction(stmt) + if err != nil { + conn.WriteError(err) + continue + } + + err = e.executeQueries(instructions, conn) + if err != nil { + conn.WriteError(err) + continue + } + } +} + +func (e *Engine) executeQueries(instructions []parser.Instruction, conn protocol.EngineConn) (err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("fatal error: %s", r) + return + } + }() + + for _, i := range instructions { + err = e.executeQuery(i, conn) + if err != nil { + return err + } + } + + return nil +} + +func (e *Engine) executeQuery(i parser.Instruction, conn protocol.EngineConn) error { + + if e.opsExecutors[i.Decls[0].Token] != nil { + return e.opsExecutors[i.Decls[0].Token](e, i.Decls[0], conn) + } + + return errors.New("Not Implemented") +} + +func createExecutor(e *Engine, createDecl *parser.Decl, conn protocol.EngineConn) error { + + if len(createDecl.Decl) == 0 { + return errors.New("Parsing failed, no declaration after CREATE") + } + + if e.opsExecutors[createDecl.Decl[0].Token] != nil { + return e.opsExecutors[createDecl.Decl[0].Token](e, createDecl.Decl[0], conn) + } + + return errors.New("Parsing failed, unknown token " + createDecl.Decl[0].Lexeme) +} + +func grantExecutor(e *Engine, decl *parser.Decl, conn protocol.EngineConn) error { + return conn.WriteResult(0, 0) +} diff --git a/vendor/github.com/proullon/ramsql/engine/executor/attribute.go b/vendor/github.com/proullon/ramsql/engine/executor/attribute.go deleted file mode 100644 index 7464805..0000000 --- a/vendor/github.com/proullon/ramsql/engine/executor/attribute.go +++ /dev/null @@ -1,77 +0,0 @@ -package executor - -import ( - "fmt" - "strings" - "time" - - "github.com/proullon/ramsql/engine/agnostic" - "github.com/proullon/ramsql/engine/parser" -) - -func parseAttribute(decl *parser.Decl) (attr agnostic.Attribute, isPk bool, err error) { - var name, typeName string - - // Attribute name - if decl.Token != parser.StringToken { - return agnostic.Attribute{}, false, fmt.Errorf("engine: expected attribute name, got %v", decl.Token) - } - name = strings.ToLower(decl.Lexeme) - - // Attribute type - if len(decl.Decl) < 1 { - return attr, false, fmt.Errorf("Attribute %s has no type", decl.Lexeme) - } - switch decl.Decl[0].Token { - case parser.DecimalToken: - typeName = "float" - case parser.NumberToken: - typeName = "int" - case parser.DateToken: - typeName = "date" - case parser.StringToken: - typeName = decl.Decl[0].Lexeme - default: - return agnostic.Attribute{}, false, fmt.Errorf("engine: expected attribute type, got %v:%v", decl.Decl[0].Token, decl.Decl[0].Lexeme) - } - - attr = agnostic.NewAttribute(name, typeName) - - // Maybe domain and special thing like primary key - typeDecl := decl.Decl[1:] - for i := range typeDecl { - if typeDecl[i].Token == parser.AutoincrementToken { - attr = attr.WithAutoIncrement() - } - - if typeDecl[i].Token == parser.DefaultToken { - switch typeDecl[i].Decl[0].Token { - case parser.LocalTimestampToken, parser.NowToken: - attr = attr.WithDefault(func() any { return time.Now() }) - default: - v, err := agnostic.ToInstance(typeDecl[i].Decl[0].Lexeme, typeName) - if err != nil { - return agnostic.Attribute{}, false, err - } - attr = attr.WithDefaultConst(v) - } - } - - // Check if attribute is unique - if typeDecl[i].Token == parser.UniqueToken { - attr = attr.WithUnique() - } - if typeDecl[i].Token == parser.PrimaryToken { - if len(typeDecl[i].Decl) > 0 && typeDecl[i].Decl[0].Token == parser.KeyToken { - isPk = true - } - } - - } - - if strings.ToLower(typeName) == "bigserial" { - attr = attr.WithAutoIncrement() - } - - return attr, isPk, nil -} diff --git a/vendor/github.com/proullon/ramsql/engine/executor/engine.go b/vendor/github.com/proullon/ramsql/engine/executor/engine.go deleted file mode 100644 index d0fa559..0000000 --- a/vendor/github.com/proullon/ramsql/engine/executor/engine.go +++ /dev/null @@ -1,768 +0,0 @@ -package executor - -import ( - "context" - "database/sql" - "errors" - "fmt" - "reflect" - "strconv" - "strings" - - "github.com/proullon/ramsql/engine/agnostic" - "github.com/proullon/ramsql/engine/log" - "github.com/proullon/ramsql/engine/parser" -) - -// Engine is the root struct of RamSQL server -type Engine struct { - memstore *agnostic.Engine -} - -// New initialize a new RamSQL server -func NewEngine() (e *Engine, err error) { - - e = &Engine{ - memstore: agnostic.NewEngine(), - } - - return -} - -func (e *Engine) Begin() (*Tx, error) { - tx, err := NewTx(context.Background(), e, sql.TxOptions{}) - if err != nil { - return nil, err - } - - return tx, nil -} - -func (e *Engine) Stop() { -} - -func createExecutor(t *Tx, decl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - - if len(decl.Decl) == 0 { - return 0, 0, nil, nil, ParsingError - } - - if t.opsExecutors[decl.Decl[0].Token] != nil { - return t.opsExecutors[decl.Decl[0].Token](t, decl.Decl[0], args) - } - - return 0, 0, nil, nil, NotImplemented -} - -func dropExecutor(t *Tx, decl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - - if len(decl.Decl) == 0 { - return 0, 0, nil, nil, ParsingError - } - - if _, ok := decl.Has(parser.TableToken); ok { - return dropTable(t, decl.Decl[0], args) - } - if _, ok := decl.Has(parser.SchemaToken); ok { - return dropSchema(t, decl.Decl[0], args) - } - - return 0, 0, nil, nil, NotImplemented -} - -func dropTable(t *Tx, decl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - if len(decl.Decl) == 0 { - return 0, 1, nil, nil, ParsingError - } - - // Check if 'IF EXISTS' is present - ifExists := hasIfExists(decl) - - rDecl := decl.Decl[0] - if ifExists { - rDecl = decl.Decl[1] - } - - schema := agnostic.DefaultSchema - if d, ok := rDecl.Has(parser.SchemaToken); ok { - schema = d.Lexeme - } - relation := rDecl.Lexeme - - exists := t.tx.CheckRelation(schema, relation) - if !exists && ifExists { - return 0, 0, nil, nil, nil - } - if !exists { - return 0, 0, nil, nil, fmt.Errorf("relation %s.%s does not exist", schema, relation) - } - - err := t.tx.DropRelation(schema, relation) - if err != nil { - return 0, 0, nil, nil, err - } - - return 0, 1, nil, nil, nil -} - -func dropSchema(t *Tx, decl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - if len(decl.Decl) == 0 { - return 0, 1, nil, nil, ParsingError - } - // Check if 'IF EXISTS' is present - ifExists := hasIfExists(decl) - - rDecl := decl.Decl[0] - if ifExists { - rDecl = decl.Decl[1] - } - - schema := rDecl.Lexeme - - if ifExists && !t.tx.CheckSchema(schema) { - return 0, 0, nil, nil, nil - } - - err := t.tx.DropSchema(schema) - if err != nil { - return 0, 0, nil, nil, err - } - - return 0, 1, nil, nil, nil -} - -func grantExecutor(*Tx, *parser.Decl, []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - return 0, 1, nil, nil, nil -} - -func createSchemaExecutor(t *Tx, tableDecl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - if len(tableDecl.Decl) == 0 { - return 0, 0, nil, nil, ParsingError - } - - // Check if 'IF NOT EXISTS' is present - ifNotExists := hasIfNotExists(tableDecl) - - name := tableDecl.Decl[0].Lexeme - - if ifNotExists && t.tx.CheckSchema(name) { - return 0, 0, nil, nil, nil - } - - err := t.tx.CreateSchema(name) - if err != nil { - return 0, 0, nil, nil, err - } - - return 0, 0, nil, nil, nil -} - -func createTableExecutor(t *Tx, tableDecl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - var i int - var schemaName string - - if len(tableDecl.Decl) == 0 { - return 0, 0, nil, nil, ParsingError - } - - // Check for specific attribute - for i < len(tableDecl.Decl) { - if tableDecl.Decl[i].Token == parser.IfToken { - i++ - continue - } - - if t.opsExecutors[tableDecl.Decl[i].Token] == nil { - break - } - - _, _, _, _, err := t.opsExecutors[tableDecl.Decl[i].Token](t, tableDecl.Decl[i], args) - if err != nil { - return 0, 0, nil, nil, err - } - i++ - } - - if d, ok := tableDecl.Has(parser.SchemaToken); ok { - schemaName = d.Lexeme - } - - // Check if 'IF NOT EXISTS' is present - ifNotExists := hasIfNotExists(tableDecl) - - relationName := tableDecl.Decl[i].Lexeme - - exists := t.tx.CheckRelation(schemaName, relationName) - if exists && ifNotExists { - return 0, 0, nil, nil, nil - } - if exists { - return 0, 0, nil, nil, errors.New("relation already exists") - } - - var pk []string - var attributes []agnostic.Attribute - - // Fetch attributes - i++ - for i < len(tableDecl.Decl) { - if tableDecl.Decl[i].Token != parser.StringToken { - break - } - attr, isPk, err := parseAttribute(tableDecl.Decl[i]) - if err != nil { - return 0, 0, nil, nil, err - } - if isPk { - pk = append(pk, attr.Name()) - } - attributes = append(attributes, attr) - i++ - } - - if i < len(tableDecl.Decl) && tableDecl.Decl[i].Token == parser.PrimaryToken { - d := tableDecl.Decl[i].Decl[0] - for _, attr := range d.Decl { - pk = append(pk, attr.Lexeme) - } - } - - err := t.tx.CreateRelation(schemaName, relationName, attributes, pk) - if err != nil { - return 0, 0, nil, nil, err - } - return 0, 1, nil, nil, nil -} - -/* -|-> INSERT - - |-> INTO - |-> user - |-> last_name - |-> first_name - |-> email - |-> VALUES - |-> ( - |-> Roullon - |-> Pierre - |-> pierre.roullon@gmail.com - |-> RETURNING - |-> email -*/ -func insertIntoTableExecutor(t *Tx, insertDecl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - - var lastInsertedID int64 - var schemaName string - var returningAttrs []string - var returningIdx []int - relationName := insertDecl.Decl[0].Decl[0].Lexeme - - // Check for RETURNING clause - if len(insertDecl.Decl) > 2 { - for i := range insertDecl.Decl { - if insertDecl.Decl[i].Token == parser.ReturningToken { - returningDecl := insertDecl.Decl[i] - returningAttrs = append(returningAttrs, returningDecl.Decl[0].Lexeme) - idx, _, err := t.tx.RelationAttribute(schemaName, relationName, returningDecl.Decl[0].Lexeme) - if err != nil { - return 0, 0, nil, nil, fmt.Errorf("cannot return %s, doesn't exist in relation %s", returningDecl.Decl[0].Lexeme, relationName) - } - returningIdx = append(returningIdx, idx) - } - } - } - - var specifiedAttrs []string - for _, d := range insertDecl.Decl[0].Decl[0].Decl { - if d.Token == parser.SchemaToken { - schemaName = d.Lexeme - continue - } - specifiedAttrs = append(specifiedAttrs, d.Lexeme) - } - - var tuples []*agnostic.Tuple - valuesDecl := insertDecl.Decl[1] - for _, valueListDecl := range valuesDecl.Decl { - values, err := getValues(specifiedAttrs, valueListDecl, args) - if err != nil { - return 0, 0, nil, nil, err - } - tuple, err := t.tx.Insert(schemaName, relationName, values) - if err != nil { - return 0, 0, nil, nil, err - } - returningTuple := agnostic.NewTuple() - for _, idx := range returningIdx { - returningTuple.Append(tuple.Values()[idx]) - } - tuples = append(tuples, returningTuple) - - // guess lastInsertedID - if v := tuple.Values(); len(v) > 0 { - if reflect.TypeOf(v[0]).ConvertibleTo(reflect.TypeOf(lastInsertedID)) { - lastInsertedID = reflect.ValueOf(v[0]).Convert(reflect.TypeOf(lastInsertedID)).Int() - } - } - } - - if len(returningAttrs) == 0 { - return lastInsertedID, int64(len(tuples)), nil, nil, nil - } - - return lastInsertedID, int64(len(tuples)), returningAttrs, tuples, nil -} - -func getValues(specifiedAttrs []string, valuesDecl *parser.Decl, args []NamedValue) (map[string]any, error) { - var typeName string - var err error - values := make(map[string]any) - var odbcIdx int64 = 1 - - for i, d := range valuesDecl.Decl { - if d.Lexeme == "default" || d.Lexeme == "DEFAULT" { - continue - } - - switch d.Token { - case parser.IntToken, parser.NumberToken: - typeName = "bigint" - case parser.DateToken: - typeName = "timestamp" - case parser.TextToken: - typeName = "text" - case parser.FloatToken: - typeName = "float" - default: - typeName = "text" - if _, err := agnostic.ToInstance(d.Lexeme, "timestamp"); err == nil { - typeName = "timestamp" - } - } - - var v any - - switch d.Token { - case parser.ArgToken: - var idx int64 - if d.Lexeme == "?" { - idx = odbcIdx - odbcIdx++ - } else { - idx, err = strconv.ParseInt(d.Lexeme, 10, 64) - if err != nil { - return nil, err - } - } - if len(args) <= int(idx)-1 { - return nil, fmt.Errorf("reference to $%s, but only %d argument provided", d.Lexeme, len(args)) - } - v = args[idx-1].Value - case parser.NamedArgToken: - for _, arg := range args { - if arg.Name == d.Lexeme { - v = arg.Value - } - } - default: - v, err = agnostic.ToInstance(d.Lexeme, typeName) - if err != nil { - return nil, err - } - } - values[strings.ToLower(specifiedAttrs[i])] = v - } - - return values, nil -} - -func getSet(specifiedAttrs []string, values map[string]any, valuesDecl *parser.Decl, args []NamedValue) (map[string]any, error) { - var typeName string - var err error - var odbcIdx int64 = 1 - - nameDecl := valuesDecl - valueDecl := nameDecl.Decl[1] - - switch valueDecl.Token { - case parser.IntToken, parser.NumberToken: - typeName = "bigint" - case parser.DecimalToken: - typeName = "float" - case parser.DateToken: - typeName = "timestamp" - case parser.TextToken: - typeName = "text" - default: - typeName = "text" - if _, err := agnostic.ToInstance(valueDecl.Lexeme, "timestamp"); err == nil { - typeName = "timestamp" - } - } - - var v any - - switch valueDecl.Token { - case parser.ArgToken: - var idx int64 - if valueDecl.Lexeme == "?" { - idx = odbcIdx - odbcIdx++ - } else { - idx, err = strconv.ParseInt(valueDecl.Lexeme, 10, 64) - if err != nil { - return nil, err - } - } - if len(args) <= int(idx)-1 { - return nil, fmt.Errorf("reference to $%s, but only %d argument provided", valueDecl.Lexeme, len(args)) - } - v = args[idx-1].Value - default: - v, err = agnostic.ToInstance(valueDecl.Lexeme, typeName) - if err != nil { - return nil, err - } - } - values[nameDecl.Lexeme] = v - - return values, nil -} - -func hasIfNotExists(tableDecl *parser.Decl) bool { - for _, d := range tableDecl.Decl { - if d.Token == parser.IfToken { - if len(d.Decl) > 0 && d.Decl[0].Token == parser.NotToken { - not := d.Decl[0] - if len(not.Decl) > 0 && not.Decl[0].Token == parser.ExistsToken { - return true - } - } - } - } - - return false -} - -func hasIfExists(tableDecl *parser.Decl) bool { - for _, d := range tableDecl.Decl { - if d.Token == parser.IfToken { - if len(d.Decl) > 0 && d.Decl[0].Token == parser.ExistsToken { - return true - } - } - } - - return false -} - -/* -|-> SELECT - - |-> * - |-> FROM - |-> account - |-> WHERE - |-> email - |-> = - |-> foo@bar.com -*/ -func selectExecutor(t *Tx, selectDecl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - - var schema string - var selectors []agnostic.Selector - var predicate agnostic.Predicate - var joiners []agnostic.Joiner - var sorters []agnostic.Sorter - var tables []string - var err error - var aliases map[string]string - - for i := range selectDecl.Decl { - switch selectDecl.Decl[i].Token { - case parser.FromToken: - schema, tables, aliases = getSelectedTables(selectDecl.Decl[i]) - case parser.WhereToken: - predicate, err = t.getPredicates(selectDecl.Decl[i].Decl, schema, tables[0], args, aliases) - if err != nil { - return 0, 0, nil, nil, err - } - case parser.JoinToken: - j, err := t.getJoin(selectDecl.Decl[i], tables[0]) - if err != nil { - return 0, 0, nil, nil, err - } - joiners = append(joiners, j) - case parser.OffsetToken: - offset, err := strconv.Atoi(selectDecl.Decl[i].Decl[0].Lexeme) - if err != nil { - return 0, 0, nil, nil, fmt.Errorf("wrong offset value: %s", err) - } - s := agnostic.NewOffsetSorter(offset) - sorters = append(sorters, s) - case parser.DistinctToken: - s, err := t.getDistinctSorter("", selectDecl.Decl[i], selectDecl.Decl[i+1].Lexeme) - if err != nil { - return 0, 0, nil, nil, err - } - sorters = append(sorters, s) - case parser.OrderToken: - s, err := orderbyExecutor(selectDecl.Decl[i], tables) - if err != nil { - return 0, 0, nil, nil, err - } - sorters = append(sorters, s) - case parser.LimitToken: - limit, err := strconv.ParseInt(selectDecl.Decl[i].Decl[0].Lexeme, 10, 64) - if err != nil { - return 0, 0, nil, nil, fmt.Errorf("wrong limit value: %s", err) - } - s := agnostic.NewLimitSorter(limit) - sorters = append(sorters, s) - } - } - - if predicate == nil { - predicate = agnostic.NewTruePredicate() - } - - for i := 0; i < len(selectDecl.Decl); i++ { - if selectDecl.Decl[i].Token != parser.StringToken && - selectDecl.Decl[i].Token != parser.StarToken && - selectDecl.Decl[i].Token != parser.CountToken { - continue - } - // get attribute to select - selector, err := t.getSelector(selectDecl.Decl[i], schema, tables, aliases) - if err != nil { - return 0, 0, nil, nil, err - } - selectors = append(selectors, selector) - } - - log.Debug("executing '%s' with %s, joining with %s and sorting with %s", selectors, predicate, joiners, sorters) - cols, res, err := t.tx.Query(schema, selectors, predicate, joiners, sorters) - if err != nil { - return 0, 0, nil, nil, err - } - - return 0, 0, cols, res, nil -} - -func createIndexExecutor(t *Tx, indexDecl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - var i int - var schema, relation, index string - - if len(indexDecl.Decl) == 0 { - return 0, 0, nil, nil, ParsingError - } - - // Check if 'IF NOT EXISTS' is present - ifNotExists := hasIfNotExists(indexDecl) - - if ifNotExists { - i++ - } - - // Fetch index name - index = indexDecl.Decl[i].Lexeme - i++ - - if d, ok := indexDecl.Has(parser.TableToken); ok { - relation = d.Lexeme - i++ - } - - var attrs []string - for i < len(indexDecl.Decl) { - attrs = append(attrs, indexDecl.Decl[i].Lexeme) - i++ - } - - err := t.tx.CreateIndex(schema, relation, index, agnostic.HashIndexType, attrs) - if err != nil { - return 0, 0, nil, nil, err - } - - return 0, 0, nil, nil, nil -} - -func updateExecutor(t *Tx, updateDecl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - - var schema string - var selectors []agnostic.Selector - var predicate agnostic.Predicate - var err error - - if len(updateDecl.Decl) < 3 { - return 0, 0, nil, nil, ParsingError - } - - relationDecl := updateDecl.Decl[0] - setDecl := updateDecl.Decl[1] - whereDecl := updateDecl.Decl[2] - relation := relationDecl.Lexeme - - if d, ok := relationDecl.Has(parser.SchemaToken); ok { - schema = d.Lexeme - } - - // Check for RETURNING clause - if len(updateDecl.Decl) > 3 { - for i := range updateDecl.Decl { - if updateDecl.Decl[i].Token == parser.ReturningToken { - returningDecl := updateDecl.Decl[i] - _, _, err := t.tx.RelationAttribute(schema, relation, returningDecl.Decl[0].Lexeme) - if err != nil { - return 0, 0, nil, nil, fmt.Errorf("cannot return %s, doesn't exist in relation %s", returningDecl.Decl[0].Lexeme, relation) - } - } - } - } - - var specifiedAttrs []string - for _, d := range setDecl.Decl { - specifiedAttrs = append(specifiedAttrs, d.Lexeme) - } - - predicate, err = t.getPredicates(whereDecl.Decl, schema, relation, args, nil) - if err != nil { - return 0, 0, nil, nil, err - } - - if predicate == nil { - predicate = agnostic.NewTruePredicate() - } - - // var tuples []*agnostic.Tuple - values := make(map[string]any) - for _, s := range setDecl.Decl { - _, err = getSet(specifiedAttrs, values, s, args) - if err != nil { - return 0, 0, nil, nil, err - } - } - - log.Debug("executing update '%s' with values %v and predicate %s", selectors, values, predicate) - cols, res, err := t.tx.Update(schema, relation, values, selectors, predicate) - if err != nil { - return 0, 0, nil, nil, err - } - - return 0, int64(len(res)), cols, res, nil -} - -func deleteExecutor(t *Tx, decl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - var schema string - var selectors []agnostic.Selector - var predicate agnostic.Predicate - var err error - - if len(decl.Decl) < 2 { - return truncateExecutor(t, decl, args) - } - - fromDecl := decl.Decl[0] - relationDecl := fromDecl.Decl[0] - whereDecl := decl.Decl[1] - relation := relationDecl.Lexeme - - if d, ok := relationDecl.Has(parser.SchemaToken); ok { - schema = d.Lexeme - } - - // Check for RETURNING clause - if len(decl.Decl) > 3 { - for i := range decl.Decl { - if decl.Decl[i].Token == parser.ReturningToken { - returningDecl := decl.Decl[i] - _, _, err := t.tx.RelationAttribute(schema, relation, returningDecl.Decl[0].Lexeme) - if err != nil { - return 0, 0, nil, nil, fmt.Errorf("cannot return %s, doesn't exist in relation %s", returningDecl.Decl[0].Lexeme, relation) - } - } - } - } - - predicate, err = t.getPredicates(whereDecl.Decl, schema, relation, args, nil) - if err != nil { - return 0, 0, nil, nil, err - } - - if predicate == nil { - predicate = agnostic.NewTruePredicate() - } - - _, res, err := t.tx.Delete(schema, relation, selectors, predicate) - if err != nil { - return 0, 0, nil, nil, err - } - - return 0, int64(len(res)), nil, nil, nil -} - -func truncateExecutor(t *Tx, trDecl *parser.Decl, args []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) { - var schema string - - if len(trDecl.Decl) < 1 { - return 0, 0, nil, nil, ParsingError - } - - if d, ok := trDecl.Decl[0].Has(parser.SchemaToken); ok { - schema = d.Lexeme - } - relation := trDecl.Decl[0].Decl[0].Lexeme - - c, err := t.tx.Truncate(schema, relation) - if err != nil { - return 0, 0, nil, nil, err - } - - return 0, c, nil, nil, nil -} - -func orderbyExecutor(decl *parser.Decl, tables []string) (agnostic.Sorter, error) { - var orderingTk int - var valDecl *parser.Decl - var attrs []agnostic.SortExpression - - valDecl = decl - - relation := tables[0] - - for i := 0; i < len(valDecl.Decl); i++ { - attr := valDecl.Decl[i].Lexeme - attrDecl := valDecl.Decl[i] - if len(attrDecl.Decl) == 2 { - relationDecl := attrDecl.Decl[0] - orderingDecl := attrDecl.Decl[1] - relation = relationDecl.Lexeme - orderingTk = orderingDecl.Token - } else if len(attrDecl.Decl) == 1 { - switch attrDecl.Decl[0].Token { - case parser.StringToken: - orderingTk = parser.AscToken - relation = attrDecl.Decl[0].Lexeme - case parser.AscToken, parser.DescToken: - orderingTk = attrDecl.Decl[0].Token - relation = tables[0] - } - } else { - orderingTk = parser.AscToken - } - - switch orderingTk { - case parser.AscToken: - attrs = append(attrs, agnostic.NewSortExpression(attr, agnostic.ASC)) - case parser.DescToken: - attrs = append(attrs, agnostic.NewSortExpression(attr, agnostic.DESC)) - default: - attrs = append(attrs, agnostic.NewSortExpression(attr, agnostic.ASC)) - } - - } - - sorter := agnostic.NewOrderBySorter(relation, attrs) - return sorter, nil -} diff --git a/vendor/github.com/proullon/ramsql/engine/executor/tx.go b/vendor/github.com/proullon/ramsql/engine/executor/tx.go deleted file mode 100644 index 2902224..0000000 --- a/vendor/github.com/proullon/ramsql/engine/executor/tx.go +++ /dev/null @@ -1,527 +0,0 @@ -package executor - -import ( - "context" - "database/sql" - "errors" - "fmt" - "strconv" - "strings" - - "github.com/proullon/ramsql/engine/agnostic" - "github.com/proullon/ramsql/engine/log" - "github.com/proullon/ramsql/engine/parser" -) - -type executorFunc func(*Tx, *parser.Decl, []NamedValue) (int64, int64, []string, []*agnostic.Tuple, error) - -var ( - NotImplemented = errors.New("not implemented") - ParsingError = errors.New("parsing error") -) - -type NamedValue struct { - Name string - Ordinal int - Value any -} - -type Tx struct { - e *Engine - tx *agnostic.Transaction - opsExecutors map[int]executorFunc -} - -func NewTx(ctx context.Context, e *Engine, opts sql.TxOptions) (*Tx, error) { - tx, err := e.memstore.Begin() - if err != nil { - return nil, err - } - - t := &Tx{ - e: e, - tx: tx, - } - - t.opsExecutors = map[int]executorFunc{ - parser.CreateToken: createExecutor, - parser.TableToken: createTableExecutor, - parser.SchemaToken: createSchemaExecutor, - parser.IndexToken: createIndexExecutor, - parser.SelectToken: selectExecutor, - parser.InsertToken: insertIntoTableExecutor, - parser.DeleteToken: deleteExecutor, - parser.UpdateToken: updateExecutor, - parser.TruncateToken: truncateExecutor, - parser.DropToken: dropExecutor, - parser.GrantToken: grantExecutor, - } - - return t, nil -} - -func (t *Tx) QueryContext(ctx context.Context, query string, args []NamedValue) ([]string, []*agnostic.Tuple, error) { - - instructions, err := parser.ParseInstruction(query) - if err != nil { - return nil, nil, err - } - if len(instructions) != 1 { - return nil, nil, fmt.Errorf("expected 1 query, got %d", len(instructions)) - } - - inst := instructions[0] - if len(inst.Decls) == 0 { - return nil, nil, fmt.Errorf("expected 1 query") - } - - if t.opsExecutors[inst.Decls[0].Token] == nil { - return nil, nil, NotImplemented - } - - _, _, cols, res, err := t.opsExecutors[inst.Decls[0].Token](t, inst.Decls[0], args) - if err != nil { - return nil, nil, err - } - - return cols, res, nil -} - -// Commit the transaction on server -func (t *Tx) Commit() error { - _, err := t.tx.Commit() - return err -} - -// Rollback all changes -func (t *Tx) Rollback() error { - t.tx.Rollback() - return nil -} - -func (t *Tx) ExecContext(ctx context.Context, query string, args []NamedValue) (int64, int64, error) { - log.Info("ExecContext(%p, %s)", t.tx, query) - - instructions, err := parser.ParseInstruction(query) - if err != nil { - return 0, 0, err - } - - var lastInsertedID, rowsAffected, aff int64 - for _, instruct := range instructions { - lastInsertedID, aff, err = t.executeQuery(instruct, args) - if err != nil { - return 0, 0, err - } - rowsAffected += aff - } - - return lastInsertedID, rowsAffected, nil -} - -func (t *Tx) executeQuery(i parser.Instruction, args []NamedValue) (int64, int64, error) { - - if t.opsExecutors[i.Decls[0].Token] == nil { - return 0, 0, NotImplemented - } - - l, r, _, _, err := t.opsExecutors[i.Decls[0].Token](t, i.Decls[0], args) - if err != nil { - return 0, 0, err - } - - return l, r, nil -} - -func (t *Tx) getSelector(attr *parser.Decl, schema string, tables []string, aliases map[string]string) (agnostic.Selector, error) { - var err error - - switch attr.Token { - case parser.StarToken: - return agnostic.NewStarSelector(tables[0]), nil - case parser.CountToken: - for _, table := range tables { - if attr.Decl[0].Lexeme == "*" { - return agnostic.NewCountSelector(table, "*"), nil - } - _, _, err = t.tx.RelationAttribute(schema, getAlias(table, aliases), attr.Decl[0].Lexeme) - if err == nil { - return agnostic.NewCountSelector(table, attr.Decl[0].Lexeme), nil - } - } - return nil, err - case parser.StringToken: - attribute := attr.Lexeme - if len(attr.Decl) > 0 { - a := getAlias(attr.Decl[0].Lexeme, aliases) - _, _, err = t.tx.RelationAttribute(schema, a, attribute) - if err != nil { - return nil, err - } - - if attr.Decl[0].Lexeme != a { - return agnostic.NewAttributeSelector(a, []string{attribute}, agnostic.WithAlias(attr.Decl[0].Lexeme)), nil - } - return agnostic.NewAttributeSelector(attr.Decl[0].Lexeme, []string{attribute}), nil - } - for _, table := range tables { - _, _, err = t.tx.RelationAttribute(schema, getAlias(table, aliases), attribute) - if err == nil { - return agnostic.NewAttributeSelector(table, []string{attribute}), nil - } - } - return nil, err - } - - return nil, fmt.Errorf("cannot handle %s", attr.Lexeme) -} - -func getSelectedTables(fromDecl *parser.Decl) (string, []string, map[string]string) { - var tables []string - var schema string - - aliases := make(map[string]string) - - for _, t := range fromDecl.Decl { - schema = "" - if d, ok := t.Has(parser.SchemaToken); ok { - schema = d.Lexeme - } - if d, ok := t.Has(parser.AsToken); ok { - aliases[d.Decl[0].Lexeme] = t.Lexeme - } - tables = append(tables, t.Lexeme) - } - - return schema, tables, aliases -} - -func (t *Tx) getPredicates(decl []*parser.Decl, schema, fromTableName string, args []NamedValue, aliases map[string]string) (agnostic.Predicate, error) { - var odbcIdx int64 = 1 - - for i, cond := range decl { - - if cond.Token == parser.AndToken { - if i+1 == len(decl) { - return nil, fmt.Errorf("query error: AND not followed by any predicate") - } - - p, err := t.and(decl[:i], decl[i+1:], schema, fromTableName, args, aliases) - return p, err - } - - if cond.Token == parser.OrToken { - if i+1 == len(decl) { - return nil, fmt.Errorf("query error: OR not followd by any predicate") - } - p, err := t.or(decl[:i], decl[i+1:], schema, fromTableName, args, aliases) - return p, err - } - } - - var err error - cond := decl[0] - - // 1 PREDICATE - if cond.Lexeme == "1" { - log.Debug("Cond is %+v, returning TruePredicate", cond) - return agnostic.NewTruePredicate(), nil - } - - switch cond.Decl[0].Token { - case parser.IsToken, parser.InToken, parser.EqualityToken, parser.DistinctnessToken, parser.LeftDipleToken, parser.RightDipleToken, parser.LessOrEqualToken, parser.GreaterOrEqualToken: - break - default: - fromTableName = cond.Decl[0].Lexeme - cond.Decl = cond.Decl[1:] - } - - pLeftValue := strings.ToLower(cond.Lexeme) - - fromTableName = getAlias(fromTableName, aliases) - - _, _, err = t.tx.RelationAttribute(schema, fromTableName, pLeftValue) - if err != nil { - return nil, err - } - - // Handle IN keyword - if cond.Decl[0].Token == parser.InToken { - p, err := inExecutor(fromTableName, pLeftValue, cond.Decl[0]) - if err != nil { - return nil, err - } - return p, nil - } - - // Handle NOT IN keywords - if cond.Decl[0].Token == parser.NotToken && cond.Decl[0].Decl[0].Token == parser.InToken { - p, err := notInExecutor(fromTableName, pLeftValue, cond.Decl[0]) - if err != nil { - return nil, err - } - return p, nil - } - - // Handle IS NULL and IS NOT NULL - if cond.Decl[0].Token == parser.IsToken { - p, err := isExecutor(fromTableName, pLeftValue, cond.Decl[0]) - if err != nil { - return nil, err - } - return p, nil - } - - if len(cond.Decl) < 2 { - return nil, fmt.Errorf("Malformed predicate \"%s\"", cond.Lexeme) - } - - leftS := cond - op := cond.Decl[0] - rightS := cond.Decl[1] - - var left, right agnostic.ValueFunctor - - switch leftS.Token { - case parser.CurrentSchemaToken: - left = agnostic.NewConstValueFunctor(schema) - case parser.NamedArgToken: - for _, arg := range args { - if leftS.Lexeme == arg.Name { - left = agnostic.NewConstValueFunctor(arg.Value) - break - } - } - if left == nil { - return nil, fmt.Errorf("no named argument found for '%s'", leftS.Lexeme) - } - case parser.ArgToken: - var idx int64 - if rightS.Lexeme == "?" { - idx = odbcIdx - odbcIdx++ - } else { - idx, err = strconv.ParseInt(rightS.Lexeme, 10, 64) - if err != nil { - return nil, err - } - } - if len(args) <= int(idx)-1 { - return nil, fmt.Errorf("reference to $%s, but only %d argument provided", leftS.Lexeme, len(args)) - } - left = agnostic.NewConstValueFunctor(args[idx-1].Value) - default: - left = agnostic.NewAttributeValueFunctor(fromTableName, pLeftValue) - } - - switch rightS.Token { - case parser.CurrentSchemaToken: - left = agnostic.NewConstValueFunctor(schema) - case parser.NamedArgToken: - for _, arg := range args { - if rightS.Lexeme == arg.Name { - right = agnostic.NewConstValueFunctor(arg.Value) - break - } - } - if right == nil { - return nil, fmt.Errorf("no named argument found for '%s'", rightS.Lexeme) - } - case parser.ArgToken: - var idx int64 - if rightS.Lexeme == "?" { - idx = odbcIdx - odbcIdx++ - } else { - idx, err = strconv.ParseInt(rightS.Lexeme, 10, 64) - if err != nil { - return nil, err - } - } - if len(args) <= int(idx)-1 { - return nil, fmt.Errorf("reference to $%s, but only %d argument provided", rightS.Lexeme, len(args)) - } - right = agnostic.NewConstValueFunctor(args[idx-1].Value) - default: - v, err := agnostic.ToInstance(rightS.Lexeme, parser.TypeNameFromToken(rightS.Token)) - if err != nil { - return nil, err - } - right = agnostic.NewConstValueFunctor(v) - } - - var ptype agnostic.PredicateType - switch op.Token { - case parser.EqualityToken: - ptype = agnostic.Eq - case parser.LessOrEqualToken: - ptype = agnostic.Leq - case parser.GreaterOrEqualToken: - ptype = agnostic.Geq - case parser.DistinctnessToken: - ptype = agnostic.Neq - case parser.LeftDipleToken: - ptype = agnostic.Le - case parser.RightDipleToken: - ptype = agnostic.Ge - default: - return nil, fmt.Errorf("unknown comparison token %s", op.Lexeme) - } - - return agnostic.NewComparisonPredicate(left, ptype, right) -} - -func (t *Tx) and(left []*parser.Decl, right []*parser.Decl, schema, tableName string, args []NamedValue, aliases map[string]string) (agnostic.Predicate, error) { - - if len(left) == 0 { - return nil, fmt.Errorf("no predicate before AND") - } - if len(right) == 0 { - return nil, fmt.Errorf("no predicate after AND") - } - - lp, err := t.getPredicates(left, schema, tableName, args, aliases) - if err != nil { - return nil, err - } - - rp, err := t.getPredicates(right, schema, tableName, args, aliases) - if err != nil { - return nil, err - } - - return agnostic.NewAndPredicate(lp, rp), nil -} - -func (t *Tx) or(left []*parser.Decl, right []*parser.Decl, schema, tableName string, args []NamedValue, aliases map[string]string) (agnostic.Predicate, error) { - - if len(left) == 0 { - return nil, fmt.Errorf("no predicate before OR") - } - if len(right) == 0 { - return nil, fmt.Errorf("no predicate after OR") - } - - lp, err := t.getPredicates(left, schema, tableName, args, aliases) - if err != nil { - return nil, err - } - - rp, err := t.getPredicates(right, schema, tableName, args, aliases) - if err != nil { - return nil, err - } - - return agnostic.NewOrPredicate(lp, rp), nil -} - -func (t *Tx) getJoin(decl *parser.Decl, leftR string) (agnostic.Joiner, error) { - var leftA, rightA, rightR string - - if decl.Decl[0].Token != parser.StringToken { - return nil, fmt.Errorf("expected joined relation name, got %v", decl.Decl[0]) - } - rightR = decl.Decl[0].Lexeme - - if decl.Decl[1].Token != parser.OnToken { - return nil, fmt.Errorf("expected join ON information, got %v", decl.Decl[1]) - } - on := decl.Decl[1] - - if len(on.Decl) != 3 { - return nil, fmt.Errorf("expected JOIN ON to have pivot") - } - - if on.Decl[0].Decl[0].Lexeme == leftR { - leftA = on.Decl[0].Lexeme - if len(on.Decl[0].Decl) > 0 { - leftR = on.Decl[0].Decl[0].Lexeme - } - rightA = on.Decl[2].Lexeme - if len(on.Decl[2].Decl) > 0 { - rightR = on.Decl[2].Decl[0].Lexeme - } - } else { - leftA = on.Decl[2].Lexeme - if len(on.Decl[2].Decl) > 0 { - leftR = on.Decl[2].Decl[0].Lexeme - } - rightA = on.Decl[0].Lexeme - if len(on.Decl[0].Decl) > 0 { - rightR = on.Decl[0].Decl[0].Lexeme - } - } - - return agnostic.NewNaturalJoin(leftR, leftA, rightR, rightA), nil -} - -func (t *Tx) getDistinctSorter(rel string, decl *parser.Decl, nextAttr string) (agnostic.Sorter, error) { - var dattrs []string - - // if we have ON specified - if len(decl.Decl) > 0 { - for _, d := range decl.Decl { - dattrs = append(dattrs, d.Lexeme) - } - } else { - // otherwise use all selected attributes - dattrs = append(dattrs, nextAttr) - } - - return agnostic.NewDistinctSorter(rel, dattrs), nil -} - -func notInExecutor(rname string, aname string, inDecl *parser.Decl) (agnostic.Predicate, error) { - in, err := inExecutor(rname, aname, inDecl.Decl[0]) - if err != nil { - return nil, err - } - - return agnostic.NewNotPredicate(in), nil -} - -func inExecutor(rname string, aname string, inDecl *parser.Decl) (agnostic.Predicate, error) { - - if len(inDecl.Decl) == 0 { - return nil, ParsingError - } - - v := agnostic.NewAttributeValueFunctor(rname, aname) - - var n agnostic.Node - switch inDecl.Decl[0].Token { - case parser.SelectToken: - return nil, fmt.Errorf("IN subquery not implemented") - default: - var values []any - for _, d := range inDecl.Decl { - values = append(values, d.Lexeme) - } - n = agnostic.NewListNode(values...) - } - - p := agnostic.NewInPredicate(v, n) - return p, nil -} - -func isExecutor(rname string, aname string, isDecl *parser.Decl) (agnostic.Predicate, error) { - - if isDecl.Decl[0].Token == parser.NullToken { - p := agnostic.NewEqPredicate(agnostic.NewAttributeValueFunctor(rname, aname), agnostic.NewConstValueFunctor(nil)) - return p, nil - } - - if isDecl.Decl[0].Token == parser.NotToken && isDecl.Decl[1].Token == parser.NullToken { - p := agnostic.NewEqPredicate(agnostic.NewAttributeValueFunctor(rname, aname), agnostic.NewConstValueFunctor(nil)) - return agnostic.NewNotPredicate(p), nil - } - - return nil, ParsingError -} - -func getAlias(t string, aliases map[string]string) string { - if a, ok := aliases[t]; ok { - return a - } - return t -} diff --git a/vendor/github.com/proullon/ramsql/engine/insert.go b/vendor/github.com/proullon/ramsql/engine/insert.go new file mode 100644 index 0000000..91d110a --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/insert.go @@ -0,0 +1,191 @@ +package engine + +import ( + "errors" + "fmt" + "strconv" + "strings" + "time" + + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/parser" + "github.com/proullon/ramsql/engine/protocol" +) + +/* +|-> INSERT + |-> INTO + |-> user + |-> last_name + |-> first_name + |-> email + |-> VALUES + |-> ( + |-> Roullon + |-> Pierre + |-> pierre.roullon@gmail.com + |-> RETURNING + |-> email + +*/ +func insertIntoTableExecutor(e *Engine, insertDecl *parser.Decl, conn protocol.EngineConn) error { + // Get table and concerned attributes and write lock it + intoDecl := insertDecl.Decl[0] + r, attributes, err := getRelation(e, intoDecl) + if err != nil { + return err + } + r.Lock() + defer r.Unlock() + + // Check for RETURNING clause + var returnedID string + if len(insertDecl.Decl) > 2 { + for i := range insertDecl.Decl { + if insertDecl.Decl[i].Token == parser.ReturningToken { + returningDecl := insertDecl.Decl[i] + returnedID = returningDecl.Lexeme + break + } + } + } + + // Create a new tuple with values + ids := []int64{} + valuesDecl := insertDecl.Decl[1] + for _, valueListDecl := range valuesDecl.Decl { + // TODO handle all inserts atomically + id, err := insert(r, attributes, valueListDecl.Decl, returnedID) + if err != nil { + return err + } + + ids = append(ids, id) + } + + // if RETURNING decl is not present + if returnedID != "" { + conn.WriteRowHeader([]string{returnedID}) + for _, id := range ids { + conn.WriteRow([]string{fmt.Sprintf("%v", id)}) + } + conn.WriteRowEnd() + } else { + conn.WriteResult(ids[len(ids)-1], (int64)(len(ids))) + } + return nil +} + +/* +|-> INTO + |-> user + |-> last_name + |-> first_name + |-> email +*/ +func getRelation(e *Engine, intoDecl *parser.Decl) (*Relation, []*parser.Decl, error) { + + // Decl[0] is the table name + r := e.relation(intoDecl.Decl[0].Lexeme) + if r == nil { + return nil, nil, errors.New("table " + intoDecl.Decl[0].Lexeme + " does not exist") + } + + for i := range intoDecl.Decl[0].Decl { + err := attributeExistsInTable(e, intoDecl.Decl[0].Decl[i].Lexeme, intoDecl.Decl[0].Lexeme) + if err != nil { + return nil, nil, err + } + } + + return r, intoDecl.Decl[0].Decl, nil +} + +func insert(r *Relation, attributes []*parser.Decl, values []*parser.Decl, returnedID string) (int64, error) { + var assigned = false + var id int64 + var valuesindex int + + // Create tuple + t := NewTuple() + + + for attrindex, attr := range r.table.attributes { + assigned = false + + for x, decl := range attributes { + if attr.name == decl.Lexeme && attr.autoIncrement == false { + // Before adding value in tuple, check it's not a builtin func or arithmetic operation + switch values[x].Token { + case parser.NowToken: + t.Append(time.Now().Format(parser.DateLongFormat)) + default: + switch strings.ToLower(attr.typeName) { + case "int64", "int": + val, err := strconv.ParseInt(values[x].Lexeme, 10, 64) + if err != nil { + return 0, err + } + t.Append(val) + case "numeric", "decimal": + val, err := strconv.ParseFloat(values[x].Lexeme, 64) + if err != nil { + return 0, err + } + t.Append(val) + default: + t.Append(values[x].Lexeme) + } + } + valuesindex = x + assigned = true + if returnedID == attr.name { + var err error + id, err = strconv.ParseInt(values[x].Lexeme, 10, 64) + if err != nil { + return 0, err + } + } + } + } + + // If attribute is AUTO INCREMENT, compute it and assign it + if attr.autoIncrement { + assigned = true + id = int64(len(r.rows) + 1) + t.Append(id) + } + + // Do we have a UNIQUE attribute ? if so + if attr.unique { + for i := range r.rows { // check all value already in relation (yup, no index tree) + if r.rows[i].Values[attrindex].(string) == string(values[valuesindex].Lexeme) { + return 0, fmt.Errorf("UNIQUE constraint violation") + } + } + } + + // If values was not explicitly given, set default value + if assigned == false { + switch val := attr.defaultValue.(type) { + case func() interface{}: + v := (func() interface{})(val)() + log.Debug("Setting func value '%v' to %s\n", v, attr.name) + t.Append(v) + default: + log.Debug("Setting default value '%v' to %s\n", val, attr.name) + t.Append(attr.defaultValue) + } + } + } + + log.Info("New tuple : %v", t) + + // Insert tuple + err := r.Insert(t) + if err != nil { + return 0, err + } + + return id, nil +} diff --git a/vendor/github.com/proullon/ramsql/engine/join.go b/vendor/github.com/proullon/ramsql/engine/join.go new file mode 100644 index 0000000..3083c58 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/join.go @@ -0,0 +1,259 @@ +package engine + +import ( + "fmt" + "strings" + + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/parser" + "github.com/proullon/ramsql/engine/protocol" +) + +// virtualRow is the resultset after FROM and JOIN transformations +// The key of the map is the lexeme (table.attribute) of the value (i.e: user.name) +type virtualRow map[string]Value + +func (v virtualRow) String() string { + var l1, l2 string + l1 = "\n" + l2 = "\n" + for key, val := range v { + l1 = fmt.Sprintf("%s %25s", l1, key) + l2 = fmt.Sprintf("%s %25v", l2, val.v) + } + return l1 + l2 +} + +// 3 types of predicates +// INNER, LEFT, RIGHT, FULL +// with NATURAL option +type joiner interface { + Evaluate(virtualRow, *Relation, int) (bool, error) + On() string +} + +// default joiner implementation +type inner struct { + table string + t1Value Value + t2Value Value +} + +func (i *inner) On() string { + return i.table +} + +func (i *inner) Evaluate(row virtualRow, r *Relation, index int) (bool, error) { + var t1, t2 Value + + // I want t1 to be the attribute already in the virtual row + // So if t1 table is the current one...swap ! + if i.t1Value.table == r.table.name { + t1 = i.t2Value + i.t2Value = i.t1Value + i.t1Value = t1 + } + + // let's find t1Value + val, ok := row[i.t1Value.table+"."+i.t1Value.lexeme] + if !ok { + return false, fmt.Errorf("JOIN: joining on %s, not found", i.t1Value.table+"."+i.t1Value.lexeme) + } + t1 = val + + if r.table.name != i.t2Value.table { + return false, fmt.Errorf("JOIN: joining on table %s, got %s", i.t2Value.table, r.table.name) + } + for attrIndex, attr := range r.table.attributes { + if attr.name == i.t2Value.lexeme { + t2 = Value{ + v: r.rows[index].Values[attrIndex], + lexeme: attr.name, + table: r.table.name, + valid: true, + } + break + } + } + if t2.valid == false { + return false, fmt.Errorf("JOIN: joining on table %s, attribute %s not found", i.t2Value.table, i.t2Value.lexeme) + } + + // let's say for now the only operator is '=' + if fmt.Sprintf("%v", t1.v) == fmt.Sprintf("%v", t2.v) { + return true, nil + } + + return false, nil +} + +// The optional WHERE, GROUP BY, and HAVING clauses in the table expression specify a pipeline of successive transformations performed on the table derived in the FROM clause. +// All these transformations produce a virtual table that provides the rows that are passed to the select list to compute the output rows of the query. +func generateVirtualRows(e *Engine, attr []Attribute, conn protocol.EngineConn, t1Name string, joinPredicates []joiner, selectPredicates []PredicateLinker, functors []selectFunctor) error { + + // get t1 and lock it + t1 := e.relation(t1Name) + if t1 == nil { + return fmt.Errorf("table %s not found", t1Name) + } + t1.RLock() + defer t1.RUnlock() + + // all joined tables in a map of relation + relations := make(map[string]*Relation) + for _, j := range joinPredicates { + r := e.relation(j.On()) + if r == nil { + return fmt.Errorf("table %s not found", j.On()) + } + r.RLock() + defer r.RUnlock() + relations[j.On()] = r + } + + // Write header + var header []string + var alias []string + for _, a := range attr { + alias = append(alias, a.name) + if strings.Contains(a.name, ".") == false { + a.name = t1Name + "." + a.name + } + header = append(header, a.name) + } + + // Initialize functors here + for i := range functors { + if err := functors[i].Init(e, conn, header, alias); err != nil { + return err + } + } + + // for each row in t1 + for i := range t1.rows { + // create virtualrow + row := make(virtualRow) + for index := range t1.rows[i].Values { + v := Value{ + v: t1.rows[i].Values[index], + valid: true, + lexeme: t1.table.attributes[index].name, + table: t1Name, + } + row[v.table+"."+v.lexeme] = v + } + + // for first join predicates + err := join(row, relations, joinPredicates, 0, selectPredicates, functors) + if err != nil { + return err + } + + } + + for i := range functors { + err := functors[i].Done() + if err != nil { + return err + } + } + return nil +} + +// Recursive virtual row creation +func join(row virtualRow, relations map[string]*Relation, predicates []joiner, predicateIndex int, selectPredicates []PredicateLinker, functors []selectFunctor) error { + + // Skip directly to selectRows if there is no joiner to run + if len(predicates) == 0 { + return selectRows(row, selectPredicates, functors) + } + + // get current predicates + predicate := predicates[predicateIndex] + + // last := is it last join ? + last := false + if predicateIndex >= len(predicates)-1 { + last = true + } + + // for each row in relations[pred.Table()] + r := relations[predicate.On()] + for i := range r.rows { + ok, err := predicate.Evaluate(row, r, i) + if err != nil { + return err + } + // if predicate not ok + if !ok { + continue + } + + // combine columns to existing virtual row + for index := range r.rows[i].Values { + v := Value{ + v: r.rows[i].Values[index], + valid: true, + lexeme: r.table.attributes[index].name, + table: r.table.name, + } + row[v.table+"."+v.lexeme] = v + } + + // if last predicate + if last { + err = selectRows(row, selectPredicates, functors) + } else { + err = join(row, relations, predicates, predicateIndex+1, selectPredicates, functors) + } + if err != nil { + return err + } + } + + return nil +} + +/* +-> join + |-> user_project + |-> on + |-> project_id + |-> user_project + |-> = + |-> id + |-> project + +*/ +func joinExecutor(decl *parser.Decl) (joiner, error) { + decl.Stringy(0) + + j := &inner{} + + // Table name + if decl.Decl[0].Token != parser.StringToken { + return nil, fmt.Errorf("join: expected table name, got %v", decl.Decl[0]) + } + j.table = decl.Decl[0].Lexeme + + // Predicate should be ON + on := decl.Decl[1] + if on.Token != parser.OnToken { + return nil, fmt.Errorf("join: expected ON, got %v", on) + } + + // Set first value + j.t1Value.valid = true + j.t1Value.lexeme = on.Decl[0].Lexeme + j.t1Value.table = on.Decl[0].Decl[0].Lexeme + + // TODO: Skip operator here, expect '=' + + // Set second value + j.t2Value.valid = true + j.t2Value.lexeme = on.Decl[2].Lexeme + j.t2Value.table = on.Decl[2].Decl[0].Lexeme + + log.Debug("JOIN %s ON %s = %s !", j.table, j.t1Value.table+"."+j.t1Value.lexeme, j.t2Value.table+"."+j.t2Value.lexeme) + return j, nil +} diff --git a/vendor/github.com/proullon/ramsql/engine/limit.go b/vendor/github.com/proullon/ramsql/engine/limit.go new file mode 100644 index 0000000..3f46f7f --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/limit.go @@ -0,0 +1,102 @@ +package engine + +import ( + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/protocol" +) + +type limit struct { + realConn protocol.EngineConn + limit int + current int +} + +func limitedConn(conn protocol.EngineConn, l int) protocol.EngineConn { + c := &limit{ + realConn: conn, + limit: l, + current: 0, + } + return c +} + +// Not needed +func (l *limit) ReadStatement() (string, error) { + log.Debug("limit.ReadStatement: should not be used\n") + return "", nil +} + +// Not needed +func (l *limit) WriteResult(last int64, ra int64) error { + log.Debug("limit.WriteResult: should not be used\n") + return nil +} + +func (l *limit) WriteError(err error) error { + return l.realConn.WriteError(err) +} + +func (l *limit) WriteRowHeader(header []string) error { + return l.realConn.WriteRowHeader(header) +} + +func (l *limit) WriteRow(row []string) error { + if l.current == l.limit { + // We are done here + return nil + } + l.current++ + return l.realConn.WriteRow(row) +} + +func (l *limit) WriteRowEnd() error { + return l.realConn.WriteRowEnd() +} + +type offset struct { + realConn protocol.EngineConn + offset int + current int +} + +func offsetedConn(conn protocol.EngineConn, o int) protocol.EngineConn { + c := &offset{ + realConn: conn, + offset: o, + } + return c +} + +// Not needed +func (l *offset) ReadStatement() (string, error) { + log.Debug("limit.ReadStatement: should not be used\n") + return "", nil +} + +// Not needed +func (l *offset) WriteResult(last int64, ra int64) error { + log.Debug("limit.WriteResult: should not be used\n") + return nil +} + +func (l *offset) WriteError(err error) error { + return l.realConn.WriteError(err) +} + +func (l *offset) WriteRowHeader(header []string) error { + return l.realConn.WriteRowHeader(header) +} + +func (l *offset) WriteRow(row []string) error { + if l.current < l.offset { + // skip this line + l.current++ + return nil + } + + return l.realConn.WriteRow(row) +} + +func (l *offset) WriteRowEnd() error { + return l.realConn.WriteRowEnd() +} diff --git a/vendor/github.com/proullon/ramsql/engine/log/log.go b/vendor/github.com/proullon/ramsql/engine/log/log.go index e428a0a..3e2db98 100644 --- a/vendor/github.com/proullon/ramsql/engine/log/log.go +++ b/vendor/github.com/proullon/ramsql/engine/log/log.go @@ -1,33 +1,15 @@ package log import ( - "context" - "fmt" - "golang.org/x/exp/slog" - "os" - "path/filepath" - "runtime" - "time" -) - -var ( - logger *slog.Logger - level *slog.LevelVar + // TODO: add a file logger + "log" + "sync" + "testing" ) func init() { - replace := func(groups []string, a slog.Attr) slog.Attr { - // Remove the directory from the source's filename. - if a.Key == slog.SourceKey { - source := a.Value.Any().(*slog.Source) - source.File = filepath.Base(source.File) - } - return a - } - level = new(slog.LevelVar) - logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{AddSource: true, Level: level, ReplaceAttr: replace})) - slog.SetDefault(logger) - SetLevel(WarningLevel) + level = WarningLevel + logger = BaseLogger{} } // Level of logging trigger @@ -37,8 +19,15 @@ type Level int const ( DebugLevel Level = iota InfoLevel + NoticeLevel WarningLevel - ErrorLevel + CriticalLevel +) + +var ( + logger Logger + level Level + mu sync.Mutex ) // Logger defines the logs levels used by RamSQL engine @@ -48,54 +37,75 @@ type Logger interface { // SetLevel controls the categories of logs written func SetLevel(lvl Level) { - switch lvl { - case DebugLevel: - level.Set(slog.LevelDebug) - case WarningLevel: - level.Set(slog.LevelWarn) - case ErrorLevel: - level.Set(slog.LevelError) - default: - level.Set(slog.LevelInfo) - } + mu.Lock() + level = lvl + mu.Unlock() } -func Debug(format string, args ...any) { - if !logger.Enabled(context.Background(), slog.LevelDebug) { - return +func lvl() Level { + mu.Lock() + defer mu.Unlock() + return level +} + +// Debug prints debug log +func Debug(format string, values ...interface{}) { + if lvl() <= DebugLevel { + logger.Logf("[DEBUG] "+format, values...) } - var pcs [1]uintptr - runtime.Callers(2, pcs[:]) // skip [Callers, Infof] - r := slog.NewRecord(time.Now(), slog.LevelDebug, fmt.Sprintf(format, args...), pcs[0]) - _ = logger.Handler().Handle(context.Background(), r) } -func Info(format string, args ...any) { - if !logger.Enabled(context.Background(), slog.LevelInfo) { - return +// Info prints information log +func Info(format string, values ...interface{}) { + if lvl() <= InfoLevel { + logger.Logf("[INFO] "+format, values...) } - var pcs [1]uintptr - runtime.Callers(2, pcs[:]) // skip [Callers, Infof] - r := slog.NewRecord(time.Now(), slog.LevelInfo, fmt.Sprintf(format, args...), pcs[0]) - _ = logger.Handler().Handle(context.Background(), r) } -func Warn(format string, args ...any) { - if !logger.Enabled(context.Background(), slog.LevelWarn) { - return +// Notice prints information that should be seen +func Notice(format string, values ...interface{}) { + if lvl() <= NoticeLevel { + logger.Logf("[NOTICE] "+format, values...) } - var pcs [1]uintptr - runtime.Callers(2, pcs[:]) // skip [Callers, Infof] - r := slog.NewRecord(time.Now(), slog.LevelWarn, fmt.Sprintf(format, args...), pcs[0]) - _ = logger.Handler().Handle(context.Background(), r) } -func Error(format string, args ...any) { - if !logger.Enabled(context.Background(), slog.LevelError) { - return +// Warning prints warnings for user +func Warning(format string, values ...interface{}) { + if lvl() <= WarningLevel { + logger.Logf("[WARNING] "+format, values...) } - var pcs [1]uintptr - runtime.Callers(2, pcs[:]) // skip [Callers, Infof] - r := slog.NewRecord(time.Now(), slog.LevelError, fmt.Sprintf(format, args...), pcs[0]) - _ = logger.Handler().Handle(context.Background(), r) +} + +// Critical prints error informations +func Critical(format string, values ...interface{}) { + mu.Lock() + logger.Logf("[CRITICAL] "+format, values...) + mu.Unlock() +} + +// BaseLogger logs on stdout +type BaseLogger struct { +} + +// Logf logs on stdout +func (l BaseLogger) Logf(fmt string, values ...interface{}) { + log.Printf(fmt, values...) +} + +// TestLogger uses *testing.T as a backend for RamSQL logs +type TestLogger struct { + t *testing.T +} + +// Logf logs in testing log buffer +func (l TestLogger) Logf(fmt string, values ...interface{}) { + l.t.Logf(fmt, values...) +} + +// UseTestLogger should be used only by unit tests +func UseTestLogger(t testing.TB) { + mu.Lock() + logger = t + mu.Unlock() + SetLevel(WarningLevel) } diff --git a/vendor/github.com/proullon/ramsql/engine/operator.go b/vendor/github.com/proullon/ramsql/engine/operator.go new file mode 100644 index 0000000..1b5940e --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/operator.go @@ -0,0 +1,218 @@ +package engine + +import ( + "fmt" + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/parser" + "strconv" + "time" +) + +// Operator compares 2 values and return a boolean +type Operator func(leftValue Value, rightValue Value) bool + +// NewOperator initializes the operator matching the Token number +func NewOperator(token int, lexeme string) (Operator, error) { + switch token { + case parser.EqualityToken: + return equalityOperator, nil + case parser.DistinctnessToken: + return distinctnessOperator, nil + case parser.LeftDipleToken: + return lessThanOperator, nil + case parser.RightDipleToken: + return greaterThanOperator, nil + case parser.LessOrEqualToken: + return lessOrEqualOperator, nil + case parser.GreaterOrEqualToken: + return greaterOrEqualOperator, nil + } + + return nil, fmt.Errorf("Operator '%s' does not exist", lexeme) +} + +func convToDate(t interface{}) (time.Time, error) { + + switch t := t.(type) { + default: + log.Debug("convToDate> unexpected type %T\n", t) + return time.Time{}, fmt.Errorf("unexpected internal type %T", t) + case string: + d, err := parser.ParseDate(string(t)) + if err != nil { + return time.Time{}, fmt.Errorf("cannot parse date %v", t) + } + + return *d, nil + } + +} + +func convToFloat(t interface{}) (float64, error) { + + switch t := t.(type) { + default: + log.Debug("convToFloat> unexpected type %T\n", t) + return 0, fmt.Errorf("unexpected internal type %T", t) + case float64: + return float64(t), nil + case int64: + return float64(int64(t)), nil + case int: + return float64(int(t)), nil + case string: + return strconv.ParseFloat(string(t), 64) + } + +} + +func greaterThanOperator(leftValue Value, rightValue Value) bool { + log.Debug("GreaterThanOperator") + var left, right float64 + var err error + + var rvalue interface{} + if rightValue.v != nil { + rvalue = rightValue.v + } else { + rvalue = rightValue.lexeme + } + + var leftDate time.Time + var isDate bool + + left, err = convToFloat(leftValue.v) + if err != nil { + leftDate, err = convToDate(leftValue.v) + if err != nil { + log.Debug("GreaterThanOperator> %s\n", err) + return false + } + isDate = true + } + + if !isDate { + right, err = convToFloat(rvalue) + if err != nil { + log.Debug("GreaterThanOperator> %s\n", err) + return false + } + + return left > right + } + + rightDate, err := convToDate(rvalue) + if err != nil { + log.Debug("GreaterThanOperator> %s\n", err) + return false + } + + return leftDate.After(rightDate) +} + +func lessOrEqualOperator(leftValue Value, rightValue Value) bool { + return lessThanOperator(leftValue, rightValue) || equalityOperator(leftValue, rightValue) +} + +func greaterOrEqualOperator(leftValue Value, rightValue Value) bool { + return greaterThanOperator(leftValue, rightValue) || equalityOperator(leftValue, rightValue) +} + +func lessThanOperator(leftValue Value, rightValue Value) bool { + log.Debug("LessThanOperator") + var left, right float64 + var err error + + var rvalue interface{} + if rightValue.v != nil { + rvalue = rightValue.v + } else { + rvalue = rightValue.lexeme + } + + var leftDate time.Time + var isDate bool + + left, err = convToFloat(leftValue.v) + if err != nil { + leftDate, err = convToDate(leftValue.v) + if err != nil { + log.Debug("LessThanOperator> %s\n", err) + return false + } + isDate = true + } + + if !isDate { + right, err = convToFloat(rvalue) + if err != nil { + log.Debug("LessThanOperator> %s\n", err) + return false + } + + return left < right + } + + rightDate, err := convToDate(rvalue) + if err != nil { + log.Debug("LessThanOperator> %s\n", err) + return false + } + + return leftDate.Before(rightDate) +} + +// EqualityOperator checks if given value are equal +func equalityOperator(leftValue Value, rightValue Value) bool { + + if fmt.Sprintf("%v", leftValue.v) == rightValue.lexeme { + return true + } + + return false +} + +// DistinctnessOperator checks if given value are distinct +func distinctnessOperator(leftValue Value, rightValue Value) bool { + + if fmt.Sprintf("%v", leftValue.v) != rightValue.lexeme { + return true + } + + return false +} + +// TrueOperator always returns true +func TrueOperator(leftValue Value, rightValue Value) bool { + return true +} + +func inOperator(leftValue Value, rightValue Value) bool { + // Right value should be a slice of string + values, ok := rightValue.v.([]string) + if !ok { + log.Debug("InOperator: rightValue.v is not a []string !") + return false + } + + for i := range values { + log.Debug("InOperator: Testing %v against %s", leftValue.v, values[i]) + if fmt.Sprintf("%v", leftValue.v) == values[i] { + return true + } + } + + return false +} + +func notInOperator(leftValue Value, rightValue Value) bool { + return !inOperator(leftValue, rightValue) +} + +func isNullOperator(leftValue Value, rightValue Value) bool { + return leftValue.v == nil +} + +func isNotNullOperator(leftValue Value, rightValue Value) bool { + return leftValue.v != nil +} diff --git a/vendor/github.com/proullon/ramsql/engine/orderby.go b/vendor/github.com/proullon/ramsql/engine/orderby.go new file mode 100644 index 0000000..99b29d8 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/orderby.go @@ -0,0 +1,301 @@ +package engine + +import ( + "fmt" + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/parser" + "github.com/proullon/ramsql/engine/protocol" + "sort" +) + +// |-> order +// |-> age +// |-> desc +func orderbyExecutor(attr *parser.Decl, tables []*Table) (selectFunctor, error) { + f := &orderbyFunctor{} + + // first subdecl should be attribute + if len(attr.Decl) < 1 { + return nil, fmt.Errorf("ordering attribute not provided") + } + + // FIXME we should find for sure the table of the attribute + if len(tables) < 1 { + return nil, fmt.Errorf("cannot guess the table of attribute %s for order", attr.Decl[0].Lexeme) + } + + for _, d := range attr.Decl { + var desc bool + if len(d.Decl) >= 1 && d.Decl[0].Lexeme == "desc" { + desc = true + } + + f.orderBy = append(f.orderBy, &orderBy{ + column: tables[0].name + "." + d.Lexeme, + desc: desc, + }) + } + + return f, nil +} + +type orderBy struct { + column string + desc bool + comparator comparator +} + +// ok so our buffer is a map of INDEX -> slice of ROW +// let's say we can only order by integer values +// and yeah we can have multiple row with one value, order is then random +type orderbyFunctor struct { + e *Engine + conn protocol.EngineConn + attributes []string + alias []string + order orderer + orderBy []*orderBy +} + +func (f *orderbyFunctor) Init(e *Engine, conn protocol.EngineConn, attr []string, alias []string) error { + f.e = e + f.conn = conn + f.attributes = attr + f.alias = alias + + return f.conn.WriteRowHeader(f.alias) +} + +func (f *orderbyFunctor) FeedVirtualRow(vrow virtualRow) error { + if f.order == nil { // first time + o := &genericOrderer{orderBy: f.orderBy} + o.init(f.attributes) + + f.order = o + } + + return f.order.Feed(Value{}, vrow) +} + +func (f *orderbyFunctor) Done() error { + log.Debug("orderByFunctor.Done\n") + + // No row in result set, orderer hasn't been initialized + if f.order == nil { + return f.conn.WriteRowEnd() + } + + if err := f.order.Sort(); err != nil { + return err + } + + err := f.order.Write(f.conn) + if err != nil { + return err + } + + return f.conn.WriteRowEnd() +} + +type orderer interface { + Feed(key Value, vrow virtualRow) error + Sort() error + Write(conn protocol.EngineConn) error +} + +type genericOrderer struct { + buffer map[string][][]interface{} + attributes []string + keys []string + orderBy []*orderBy +} + +func (o *genericOrderer) init(attr []string) { + o.buffer = make(map[string][][]interface{}) + o.attributes = attr +} + +func (o *genericOrderer) Feed(_ Value, vrow virtualRow) error { + var row []interface{} + + var key string + for _, ob := range o.orderBy { + if key != "" { + key += "." + } + + key += fmt.Sprint(vrow[ob.column].v) + + if ob.comparator != nil { + continue + } + + // TODO: refactor using generics once possible + switch vrow[ob.column].v.(type) { + case string: + ob.comparator = func(desc bool) comparator { + return func(i interface{}, j interface{}) int { + if _, ok := i.(string); !ok { + panic(fmt.Sprintf("unsupported type, expected string but got %T", i)) + } + + a := i.(string) + b := j.(string) + if desc { + switch { + case a > b: + return 1 + case a < b: + return -1 + case a == b: + return 0 + } + } else { + switch { + case a < b: + return 1 + case a > b: + return -1 + case a == b: + return 0 + } + } + return 0 + } + }(ob.desc) + case int64: + ob.comparator = func(desc bool) comparator { + return func(i interface{}, j interface{}) int { + if _, ok := i.(int64); !ok { + panic(fmt.Sprintf("unsupported type, expected int64 but got %T %v", i, i)) + } + + a := i.(int64) + b := j.(int64) + if desc { + switch { + case a > b: + return 1 + case a < b: + return -1 + case a == b: + return 0 + } + } else { + switch { + case a < b: + return 1 + case a > b: + return -1 + case a == b: + return 0 + } + } + return 0 + } + }(ob.desc) + case float64: + ob.comparator = func(desc bool) comparator { + return func(i interface{}, j interface{}) int { + if _, ok := i.(float64); !ok { + panic(fmt.Sprintf("unsupported type, expected float64 but got %T %v", i, i)) + } + + a := i.(float64) + b := j.(float64) + if desc { + switch { + case a > b: + return 1 + case a < b: + return -1 + case a == b: + return 0 + } + } else { + switch { + case a < b: + return 1 + case a > b: + return -1 + case a == b: + return 0 + } + } + return 0 + } + }(ob.desc) + //default: + // panic(fmt.Sprintf("wrong type %T for column %s", vrow[ob.column].v, ob.column)) + } + } + + for _, attr := range o.attributes { + val, ok := vrow[attr] + if !ok { + return fmt.Errorf("could not select attribute %s", attr) + } + row = append(row, val.v) + } + + // now instead of writing row, we will find the ordering key and put in in our buffer + o.buffer[key] = append(o.buffer[key], row) + return nil +} + +func (o *genericOrderer) Sort() error { + o.keys = make([]string, len(o.buffer)) + var idx int + for k := range o.buffer { + o.keys[idx] = k + idx++ + } + + sort.Slice(o.keys, func(a, b int) bool { + for _, ob := range o.orderBy { + keyA := o.keys[a] + keyB := o.keys[b] + + var idx int + for i, attr := range o.attributes { + if attr == ob.column { + idx = i + } + } + + switch ob.comparator(o.buffer[keyA][0][idx], o.buffer[keyB][0][idx]) { + case 1: + return true + case 0: + continue + case -1: + return false + } + } + + return false + }) + + return nil +} + +func (o *genericOrderer) Write(conn protocol.EngineConn) error { + // now write ordered rows + for _, key := range o.keys { + rows := o.buffer[key] + for index := range rows { + var row []string + for _, elem := range rows[index] { + row = append(row, fmt.Sprint(elem)) + } + err := conn.WriteRow(row) + if err != nil { + return err + } + } + } + + return nil +} + +type comparator func(i interface{}, j interface{}) int diff --git a/vendor/github.com/proullon/ramsql/engine/parser/create.go b/vendor/github.com/proullon/ramsql/engine/parser/create.go index da3ffd5..8807465 100644 --- a/vendor/github.com/proullon/ramsql/engine/parser/create.go +++ b/vendor/github.com/proullon/ramsql/engine/parser/create.go @@ -28,18 +28,14 @@ func (p *parser) parseCreate(tokens []Token) (*Instruction, error) { return nil, err } createDecl.Add(d) + break case IndexToken: d, err := p.parseIndex(tokens) if err != nil { return nil, err } createDecl.Add(d) - case SchemaToken: - d, err := p.parseSchema(tokens) - if err != nil { - return nil, err - } - createDecl.Add(d) + break case UniqueToken: u, err := p.consumeToken(UniqueToken) if err != nil { @@ -55,6 +51,7 @@ func (p *parser) parseCreate(tokens []Token) (*Instruction, error) { } d.Add(u) createDecl.Add(d) + break default: return nil, fmt.Errorf("Parsing error near <%s>", tokens[p.index].Lexeme) @@ -108,11 +105,10 @@ func (p *parser) parseIndex(tokens []Token) (*Decl, error) { p.index++ // Now we should found table name - nameTable, err := p.parseTableName() + nameTable, err := p.parseAttribute() if err != nil { return nil, p.syntaxError() } - nameTable.Token = TableToken indexDecl.Add(nameTable) // Now we should found brackets @@ -132,10 +128,7 @@ func (p *parser) parseIndex(tokens []Token) (*Decl, error) { // Closing bracket ? if tokens[p.index].Token == BracketClosingToken { - _, err = p.consumeToken(BracketClosingToken) - if err != nil { - return nil, err - } + p.consumeToken(BracketClosingToken) break } @@ -206,7 +199,7 @@ func (p *parser) parseTable(tokens []Token) (*Decl, error) { } // Now we should found table name - nameTable, err := p.parseTableName() + nameTable, err := p.parseAttribute() if err != nil { return nil, p.syntaxError() } @@ -222,21 +215,17 @@ func (p *parser) parseTable(tokens []Token) (*Decl, error) { switch p.cur().Token { case PrimaryToken: - pkDecl, err := p.parsePrimaryKey() + _, err := p.parsePrimaryKey() if err != nil { return nil, err } - tableDecl.Add(pkDecl) continue default: } // Closing bracket ? if tokens[p.index].Token == BracketClosingToken { - _, err = p.consumeToken(BracketClosingToken) - if err != nil { - return nil, err - } + p.consumeToken(BracketClosingToken) break } @@ -257,11 +246,6 @@ func (p *parser) parseTable(tokens []Token) (*Decl, error) { // Column constraints can be listed in any order. for p.isNot(BracketClosingToken, CommaToken) { switch p.cur().Token { - case UnsignedToken: - _, err = p.consumeToken(UnsignedToken) - if err != nil { - return nil, err - } case UniqueToken: // UNIQUE uniqueDecl, err := p.consumeToken(UniqueToken) if err != nil { @@ -359,7 +343,7 @@ func (p *parser) parseDefaultClause() (*Decl, error) { if p.is(SimpleQuoteToken) || p.is(DoubleQuoteToken) { vDecl, err = p.parseStringLiteral() } else { - vDecl, err = p.consumeToken(NullToken, FloatToken, FalseToken, NumberToken, LocalTimestampToken, NowToken, ArgToken, NamedArgToken) + vDecl, err = p.consumeToken(FalseToken, NumberToken, LocalTimestampToken, NowToken) } if err != nil { @@ -391,13 +375,11 @@ func (p *parser) parsePrimaryKey() (*Decl, error) { if err != nil { return nil, err } - keyDecl.Add(d) d, err = p.consumeToken(CommaToken, BracketClosingToken) if err != nil { return nil, err } - if d.Token == BracketClosingToken { break } @@ -405,18 +387,3 @@ func (p *parser) parsePrimaryKey() (*Decl, error) { return primaryDecl, nil } - -func (p *parser) parseSchema(tokens []Token) (*Decl, error) { - var err error - schemaDecl := NewDecl(tokens[p.index]) - p.index++ - - // Now we should found name - name, err := p.parseAttribute() - if err != nil { - return nil, p.syntaxError() - } - schemaDecl.Add(name) - - return schemaDecl, nil -} diff --git a/vendor/github.com/proullon/ramsql/engine/parser/delete.go b/vendor/github.com/proullon/ramsql/engine/parser/delete.go index 80cf8e6..9d7bf04 100644 --- a/vendor/github.com/proullon/ramsql/engine/parser/delete.go +++ b/vendor/github.com/proullon/ramsql/engine/parser/delete.go @@ -1,8 +1,6 @@ package parser -import ( - "github.com/proullon/ramsql/engine/log" -) +import () func (p *parser) parseDelete() (*Instruction, error) { i := &Instruction{} @@ -22,13 +20,14 @@ func (p *parser) parseDelete() (*Instruction, error) { deleteDecl.Add(fromDecl) // Should be a table name - nameDecl, err := p.parseTableName() + nameDecl, err := p.parseQuotedToken() if err != nil { return nil, err } fromDecl.Add(nameDecl) - log.Debug("WHERE ? %v", p.tokens[p.index]) + // MAY be WHERE here + debug("WHERE ? %v", p.tokens[p.index]) if !p.hasNext() { return i, nil } diff --git a/vendor/github.com/proullon/ramsql/engine/parser/drop.go b/vendor/github.com/proullon/ramsql/engine/parser/drop.go index 565eccd..900abc3 100644 --- a/vendor/github.com/proullon/ramsql/engine/parser/drop.go +++ b/vendor/github.com/proullon/ramsql/engine/parser/drop.go @@ -1,41 +1,33 @@ package parser -func (p *parser) parseDrop(tokens []Token) (*Instruction, error) { - var err error +import ( + "github.com/proullon/ramsql/engine/log" +) + +func (p *parser) parseDrop() (*Instruction, error) { i := &Instruction{} trDecl, err := p.consumeToken(DropToken) if err != nil { + log.Debug("WTF\n") return nil, err } i.Decls = append(i.Decls, trDecl) - var d *Decl - switch tokens[p.index].Token { - case TableToken: - d, err = p.consumeToken(TableToken) - if err != nil { - return nil, err - } - case IndexToken: - d, err = p.consumeToken(SchemaToken) - if err != nil { - return nil, err - } - case SchemaToken: - d, err = p.consumeToken(SchemaToken) - if err != nil { - return nil, err - } + tableDecl, err := p.consumeToken(TableToken) + if err != nil { + log.Debug("Consume table !\n") + return nil, err } - trDecl.Add(d) + trDecl.Add(tableDecl) - // Should be a name attribute - nameDecl, err := p.parseAttribute() + // Should be a table name + nameDecl, err := p.parseQuotedToken() if err != nil { + log.Debug("UH ?\n") return nil, err } - d.Add(nameDecl) + tableDecl.Add(nameDecl) return i, nil } diff --git a/vendor/github.com/proullon/ramsql/engine/parser/insert.go b/vendor/github.com/proullon/ramsql/engine/parser/insert.go deleted file mode 100644 index e51509f..0000000 --- a/vendor/github.com/proullon/ramsql/engine/parser/insert.go +++ /dev/null @@ -1,156 +0,0 @@ -package parser - -// Parses an INSERT statement. -// -// The generated AST is as follows: -// -// |-> "INSERT" (InsertToken) -// |-> "INTO" (IntoToken) -// |-> table name -// |-> column name -// |-> (...) -// |-> "VALUES" (ValuesToken) -// |-> "(" (BracketOpeningToken) -// |-> value -// |-> (...) -// |-> (...) -// |-> "RETURNING" (ReturningToken) (optional) -// |-> column name -func (p *parser) parseInsert() (*Instruction, error) { - i := &Instruction{} - - // Set INSERT decl - insertDecl, err := p.consumeToken(InsertToken) - if err != nil { - return nil, err - } - i.Decls = append(i.Decls, insertDecl) - - // should be INTO - intoDecl, err := p.consumeToken(IntoToken) - if err != nil { - return nil, err - } - insertDecl.Add(intoDecl) - - // should be table Name - tableDecl, err := p.parseTableName() - if err != nil { - return nil, err - } - intoDecl.Add(tableDecl) - - _, err = p.consumeToken(BracketOpeningToken) - if err != nil { - return nil, err - } - - // concerned attribute - for { - decl, err := p.parseListElement() - if err != nil { - return nil, err - } - tableDecl.Add(decl) - - if p.is(BracketClosingToken) { - if _, err = p.consumeToken(BracketClosingToken); err != nil { - return nil, err - } - - break - } - - _, err = p.consumeToken(CommaToken) - if err != nil { - return nil, err - } - } - - // should be VALUES - valuesDecl, err := p.consumeToken(ValuesToken) - if err != nil { - return nil, err - } - insertDecl.Add(valuesDecl) - - for { - openingBracketDecl, err := p.consumeToken(BracketOpeningToken) - if err != nil { - return nil, err - } - valuesDecl.Add(openingBracketDecl) - - // should be a list of values for specified attributes - for { - decl, err := p.parseListElement() - if err != nil { - return nil, err - } - openingBracketDecl.Add(decl) - - if p.is(BracketClosingToken) { - p.consumeToken(BracketClosingToken) - break - } - - _, err = p.consumeToken(CommaToken) - if err != nil { - return nil, err - } - } - - if p.is(CommaToken) { - p.consumeToken(CommaToken) - continue - } - - break - } - - // we may have `returning "something"` here - if retDecl, err := p.consumeToken(ReturningToken); err == nil { - insertDecl.Add(retDecl) - - // returned attribute - attrDecl, err := p.parseAttribute() - if err != nil { - return nil, err - } - retDecl.Add(attrDecl) - } - - return i, nil -} - -func (p *parser) parseListElement() (*Decl, error) { - quoted := false - - // In case of INSERT, can be DEFAULT here - if p.is(DefaultToken) { - v, err := p.consumeToken(DefaultToken) - if err != nil { - return nil, err - } - return v, nil - } - - if p.is(SimpleQuoteToken) || p.is(DoubleQuoteToken) { - quoted = true - p.next() - } - - var valueDecl *Decl - valueDecl, err := p.consumeToken(FloatToken, StringToken, NumberToken, NullToken, DateToken, NowToken, ArgToken, NamedArgToken, FalseToken) - if err != nil { - return nil, err - } - - if quoted { - if _, err := p.consumeToken(SimpleQuoteToken, DoubleQuoteToken); err != nil { - return nil, err - } - } - - return valueDecl, nil -} diff --git a/vendor/github.com/proullon/ramsql/engine/parser/lexer.go b/vendor/github.com/proullon/ramsql/engine/parser/lexer.go index 8bdbc07..18e4d19 100644 --- a/vendor/github.com/proullon/ramsql/engine/parser/lexer.go +++ b/vendor/github.com/proullon/ramsql/engine/parser/lexer.go @@ -49,18 +49,14 @@ const ( FromToken WhereToken TableToken - SchemaToken - CurrentSchemaToken IntoToken ValuesToken JoinToken - AsToken OnToken IfToken NotToken ExistsToken NullToken - UnsignedToken AutoincrementToken CountToken SetToken @@ -95,13 +91,8 @@ const ( PrimaryToken KeyToken StringToken - DecimalToken NumberToken DateToken - FloatToken - - ArgToken - NamedArgToken ) // Token struct holds token id and it's lexeme @@ -128,86 +119,75 @@ func (l *lexer) lex(instruction []byte) ([]Token, error) { securityPos := 0 var matchers []Matcher - matchers = append(matchers, l.MatchArgTokenODBC) - matchers = append(matchers, l.MatchNamedArgToken) - matchers = append(matchers, l.MatchArgToken) - matchers = append(matchers, l.MatchFloatToken) // Punctuation Matcher matchers = append(matchers, l.MatchSpaceToken) - matchers = append(matchers, l.genericByteMatcher(';', SemicolonToken)) - matchers = append(matchers, l.genericByteMatcher(',', CommaToken)) - matchers = append(matchers, l.genericByteMatcher('(', BracketOpeningToken)) - matchers = append(matchers, l.genericByteMatcher(')', BracketClosingToken)) - matchers = append(matchers, l.genericByteMatcher('*', StarToken)) + matchers = append(matchers, l.MatchSemicolonToken) + matchers = append(matchers, l.MatchCommaToken) + matchers = append(matchers, l.MatchBracketOpeningToken) + matchers = append(matchers, l.MatchBracketClosingToken) + matchers = append(matchers, l.MatchStarToken) matchers = append(matchers, l.MatchSimpleQuoteToken) - matchers = append(matchers, l.genericByteMatcher('=', EqualityToken)) - matchers = append(matchers, l.genericStringMatcher("<>", DistinctnessToken)) - matchers = append(matchers, l.genericStringMatcher("!=", DistinctnessToken)) - matchers = append(matchers, l.genericByteMatcher('.', PeriodToken)) + matchers = append(matchers, l.MatchEqualityToken) + matchers = append(matchers, l.MatchDistinctnessToken) + matchers = append(matchers, l.MatchPeriodToken) matchers = append(matchers, l.MatchDoubleQuoteToken) - matchers = append(matchers, l.genericStringMatcher("<=", LessOrEqualToken)) - matchers = append(matchers, l.genericStringMatcher(">=", GreaterOrEqualToken)) - matchers = append(matchers, l.genericByteMatcher('<', LeftDipleToken)) - matchers = append(matchers, l.genericByteMatcher('>', RightDipleToken)) - matchers = append(matchers, l.genericByteMatcher('`', BacktickToken)) + matchers = append(matchers, l.MatchLessOrEqualToken) + matchers = append(matchers, l.MatchGreaterOrEqualToken) + matchers = append(matchers, l.MatchLeftDipleToken) + matchers = append(matchers, l.MatchRightDipleToken) + matchers = append(matchers, l.MatchBacktickToken) // First order Matcher - matchers = append(matchers, l.genericStringMatcher("create", CreateToken)) - matchers = append(matchers, l.genericStringMatcher("select", SelectToken)) - matchers = append(matchers, l.genericStringMatcher("insert", InsertToken)) - matchers = append(matchers, l.genericStringMatcher("update", UpdateToken)) - matchers = append(matchers, l.genericStringMatcher("delete", DeleteToken)) - matchers = append(matchers, l.genericStringMatcher("truncate", TruncateToken)) - matchers = append(matchers, l.genericStringMatcher("drop", DropToken)) - matchers = append(matchers, l.genericStringMatcher("grant", GrantToken)) - matchers = append(matchers, l.genericStringMatcher("distinct", DistinctToken)) + matchers = append(matchers, l.MatchCreateToken) + matchers = append(matchers, l.MatchSelectToken) + matchers = append(matchers, l.MatchInsertToken) + matchers = append(matchers, l.MatchUpdateToken) + matchers = append(matchers, l.MatchDeleteToken) + matchers = append(matchers, l.MatchTruncateToken) + matchers = append(matchers, l.MatchDropToken) + matchers = append(matchers, l.MatchGrantToken) + matchers = append(matchers, l.MatchDistinctToken) // Second order Matcher - matchers = append(matchers, l.genericStringMatcher("table", TableToken)) - matchers = append(matchers, l.genericStringMatcher("current_schema()", CurrentSchemaToken)) - matchers = append(matchers, l.genericStringMatcher("current_schema", CurrentSchemaToken)) - matchers = append(matchers, l.genericStringMatcher("schema", SchemaToken)) - matchers = append(matchers, l.genericStringMatcher("from", FromToken)) - matchers = append(matchers, l.genericStringMatcher("where", WhereToken)) - matchers = append(matchers, l.genericStringMatcher("into", IntoToken)) - matchers = append(matchers, l.genericStringMatcher("values", ValuesToken)) - matchers = append(matchers, l.genericStringMatcher("join", JoinToken)) - matchers = append(matchers, l.genericStringMatcher("as", AsToken)) - matchers = append(matchers, l.genericStringMatcher("on", OnToken)) - matchers = append(matchers, l.genericStringMatcher("if", IfToken)) - matchers = append(matchers, l.genericStringMatcher("not", NotToken)) - matchers = append(matchers, l.genericStringMatcher("exists", ExistsToken)) - matchers = append(matchers, l.genericStringMatcher("null", NullToken)) + matchers = append(matchers, l.MatchTableToken) + matchers = append(matchers, l.MatchFromToken) + matchers = append(matchers, l.MatchWhereToken) + matchers = append(matchers, l.MatchIntoToken) + matchers = append(matchers, l.MatchValuesToken) + matchers = append(matchers, l.MatchJoinToken) + matchers = append(matchers, l.MatchOnToken) + matchers = append(matchers, l.MatchIfToken) + matchers = append(matchers, l.MatchNotToken) + matchers = append(matchers, l.MatchExistsToken) + matchers = append(matchers, l.MatchNullToken) matchers = append(matchers, l.MatchAutoincrementToken) - matchers = append(matchers, l.genericStringMatcher("unsigned", UnsignedToken)) - matchers = append(matchers, l.genericStringMatcher("count", CountToken)) - matchers = append(matchers, l.genericStringMatcher("set", SetToken)) - matchers = append(matchers, l.genericStringMatcher("order", OrderToken)) - matchers = append(matchers, l.genericStringMatcher("by", ByToken)) - matchers = append(matchers, l.genericStringMatcher("with", WithToken)) - matchers = append(matchers, l.genericStringMatcher("time", TimeToken)) - matchers = append(matchers, l.genericStringMatcher("zone", ZoneToken)) - matchers = append(matchers, l.genericStringMatcher("returning", ReturningToken)) - matchers = append(matchers, l.genericStringMatcher("in", InToken)) - matchers = append(matchers, l.genericStringMatcher("and", AndToken)) - matchers = append(matchers, l.genericStringMatcher("or", OrToken)) - matchers = append(matchers, l.genericStringMatcher("asc", AscToken)) - matchers = append(matchers, l.genericStringMatcher("desc", DescToken)) - matchers = append(matchers, l.genericStringMatcher("limit", LimitToken)) - matchers = append(matchers, l.genericStringMatcher("is", IsToken)) - matchers = append(matchers, l.genericStringMatcher("for", ForToken)) - matchers = append(matchers, l.genericStringMatcher("default", DefaultToken)) - matchers = append(matchers, l.genericStringMatcher("localtimestamp", LocalTimestampToken)) - matchers = append(matchers, l.genericStringMatcher("false", FalseToken)) - matchers = append(matchers, l.genericStringMatcher("unique", UniqueToken)) - matchers = append(matchers, l.genericStringMatcher("now()", NowToken)) - matchers = append(matchers, l.genericStringMatcher("offset", OffsetToken)) - matchers = append(matchers, l.genericStringMatcher("index", IndexToken)) - matchers = append(matchers, l.genericStringMatcher("on", OnToken)) - matchers = append(matchers, l.genericStringMatcher("collate", CollateToken)) - matchers = append(matchers, l.genericStringMatcher("nocase", NocaseToken)) + matchers = append(matchers, l.MatchCountToken) + matchers = append(matchers, l.MatchSetToken) + matchers = append(matchers, l.MatchOrderToken) + matchers = append(matchers, l.MatchByToken) + matchers = append(matchers, l.MatchWithToken) + matchers = append(matchers, l.MatchTimeToken) + matchers = append(matchers, l.MatchZoneToken) + matchers = append(matchers, l.MatchReturningToken) + matchers = append(matchers, l.MatchInToken) + matchers = append(matchers, l.MatchAndToken) + matchers = append(matchers, l.MatchOrToken) + matchers = append(matchers, l.MatchAscToken) + matchers = append(matchers, l.MatchDescToken) + matchers = append(matchers, l.MatchLimitToken) + matchers = append(matchers, l.MatchIsToken) + matchers = append(matchers, l.MatchForToken) + matchers = append(matchers, l.MatchDefaultToken) + matchers = append(matchers, l.MatchLocalTimestampToken) + matchers = append(matchers, l.MatchFalseToken) + matchers = append(matchers, l.MatchUniqueToken) + matchers = append(matchers, l.MatchNowToken) + matchers = append(matchers, l.MatchOffsetToken) + matchers = append(matchers, l.MatchIndexToken) + matchers = append(matchers, l.MatchOnToken) + matchers = append(matchers, l.MatchCollateToken) + matchers = append(matchers, l.MatchNocaseToken) // Type Matcher - matchers = append(matchers, l.genericStringMatcher("decimal", DecimalToken)) - matchers = append(matchers, l.genericStringMatcher("primary", PrimaryToken)) - matchers = append(matchers, l.genericStringMatcher("key", KeyToken)) + matchers = append(matchers, l.MatchPrimaryToken) + matchers = append(matchers, l.MatchKeyToken) matchers = append(matchers, l.MatchEscapedStringToken) matchers = append(matchers, l.MatchDateToken) matchers = append(matchers, l.MatchNumberToken) @@ -217,7 +197,7 @@ func (l *lexer) lex(instruction []byte) ([]Token, error) { for l.pos < l.instructionLen { r = false for _, m := range matchers { - if r = m(); r { + if r = m(); r == true { securityPos = l.pos break } @@ -228,7 +208,7 @@ func (l *lexer) lex(instruction []byte) ([]Token, error) { } if l.pos == securityPos { - log.Warn("Cannot lex <%s>, stuck at pos %d -> [%c]", l.instruction, l.pos, l.instruction[l.pos]) + log.Warning("Cannot lex <%s>, stuck at pos %d -> [%c]", l.instruction, l.pos, l.instruction[l.pos]) return nil, fmt.Errorf("Cannot lex instruction. Syntax error near %s", instruction[l.pos:]) } securityPos = l.pos @@ -237,99 +217,167 @@ func (l *lexer) lex(instruction []byte) ([]Token, error) { return l.tokens, nil } -func (l *lexer) MatchArgTokenODBC() bool { - - i := l.pos - if l.instruction[i] != '?' { - return false - } - if len(l.tokens) < 1 { - return false - } - if l.tokens[len(l.tokens)-1].Token == SimpleQuoteToken || l.tokens[len(l.tokens)-1].Token == DoubleQuoteToken { - return false - } - i++ - t := Token{ - Token: ArgToken, - Lexeme: "?", - } - l.tokens = append(l.tokens, t) - l.pos = i - return true -} - -func (l *lexer) MatchNamedArgToken() bool { +func (l *lexer) MatchSpaceToken() bool { - i := l.pos - if l.instruction[i] != ':' { - return false - } - i++ - for i < l.instructionLen && unicode.IsLetter(rune(l.instruction[i])) { - i++ - } - if i > l.pos+1 { + if unicode.IsSpace(rune(l.instruction[l.pos])) { t := Token{ - Token: NamedArgToken, - Lexeme: string(l.instruction[l.pos+1 : i]), + Token: SpaceToken, + Lexeme: " ", } l.tokens = append(l.tokens, t) - l.pos = i + l.pos++ return true } return false } -func (l *lexer) MatchArgToken() bool { +func (l *lexer) MatchNowToken() bool { + return l.Match([]byte("now()"), NowToken) +} - i := l.pos - if l.instruction[i] != '$' { - return false - } - i++ - for i < l.instructionLen && unicode.IsDigit(rune(l.instruction[i])) { - i++ - } - if i > l.pos+1 { - t := Token{ - Token: ArgToken, - Lexeme: string(l.instruction[l.pos+1 : i]), - } - l.tokens = append(l.tokens, t) - l.pos = i - return true - } +func (l *lexer) MatchUniqueToken() bool { + return l.Match([]byte("unique"), UniqueToken) +} - return false +func (l *lexer) MatchLocalTimestampToken() bool { + return l.Match([]byte("localtimestamp"), LocalTimestampToken) } -func (l *lexer) MatchSpaceToken() bool { +func (l *lexer) MatchDefaultToken() bool { + return l.Match([]byte("default"), DefaultToken) +} - if unicode.IsSpace(rune(l.instruction[l.pos])) { - t := Token{ - Token: SpaceToken, - Lexeme: " ", - } - l.tokens = append(l.tokens, t) - l.pos++ - return true - } +func (l *lexer) MatchFalseToken() bool { + return l.Match([]byte("false"), FalseToken) +} - return false +func (l *lexer) MatchAscToken() bool { + return l.Match([]byte("asc"), AscToken) } -func (l *lexer) genericStringMatcher(str string, token int) Matcher { - return func() bool { - return l.Match([]byte(str), token) - } +func (l *lexer) MatchDescToken() bool { + return l.Match([]byte("desc"), DescToken) } -func (l *lexer) genericByteMatcher(r byte, token int) Matcher { - return func() bool { - return l.MatchSingle(r, token) - } +func (l *lexer) MatchAndToken() bool { + return l.Match([]byte("and"), AndToken) +} + +func (l *lexer) MatchOrToken() bool { + return l.Match([]byte("or"), OrToken) +} + +func (l *lexer) MatchInToken() bool { + return l.Match([]byte("in"), InToken) +} + +func (l *lexer) MatchReturningToken() bool { + return l.Match([]byte("returning"), ReturningToken) +} + +func (l *lexer) MatchTruncateToken() bool { + return l.Match([]byte("truncate"), TruncateToken) +} + +func (l *lexer) MatchDropToken() bool { + return l.Match([]byte("drop"), DropToken) +} + +func (l *lexer) MatchGrantToken() bool { + return l.Match([]byte("grant"), GrantToken) +} + +func (l *lexer) MatchWithToken() bool { + return l.Match([]byte("with"), WithToken) +} + +func (l *lexer) MatchTimeToken() bool { + return l.Match([]byte("time"), TimeToken) +} + +func (l *lexer) MatchZoneToken() bool { + return l.Match([]byte("zone"), ZoneToken) +} + +func (l *lexer) MatchIsToken() bool { + return l.Match([]byte("is"), IsToken) +} + +func (l *lexer) MatchForToken() bool { + return l.Match([]byte("for"), ForToken) +} + +func (l *lexer) MatchLimitToken() bool { + return l.Match([]byte("limit"), LimitToken) +} + +func (l *lexer) MatchOrderToken() bool { + return l.Match([]byte("order"), OrderToken) +} + +func (l *lexer) MatchByToken() bool { + return l.Match([]byte("by"), ByToken) +} + +func (l *lexer) MatchSetToken() bool { + return l.Match([]byte("set"), SetToken) +} + +func (l *lexer) MatchUpdateToken() bool { + return l.Match([]byte("update"), UpdateToken) +} + +func (l *lexer) MatchCreateToken() bool { + return l.Match([]byte("create"), CreateToken) +} + +func (l *lexer) MatchSelectToken() bool { + return l.Match([]byte("select"), SelectToken) +} + +func (l *lexer) MatchDistinctToken() bool { + return l.Match([]byte("distinct"), DistinctToken) +} + +func (l *lexer) MatchInsertToken() bool { + return l.Match([]byte("insert"), InsertToken) +} + +func (l *lexer) MatchWhereToken() bool { + return l.Match([]byte("where"), WhereToken) +} + +func (l *lexer) MatchFromToken() bool { + return l.Match([]byte("from"), FromToken) +} + +func (l *lexer) MatchTableToken() bool { + return l.Match([]byte("table"), TableToken) +} + +func (l *lexer) MatchNullToken() bool { + return l.Match([]byte("null"), NullToken) +} + +func (l *lexer) MatchIfToken() bool { + return l.Match([]byte("if"), IfToken) +} + +func (l *lexer) MatchNotToken() bool { + return l.Match([]byte("not"), NotToken) +} + +func (l *lexer) MatchExistsToken() bool { + return l.Match([]byte("exists"), ExistsToken) +} + +func (l *lexer) MatchCountToken() bool { + return l.Match([]byte("count"), CountToken) +} + +func (l *lexer) MatchDeleteToken() bool { + return l.Match([]byte("delete"), DeleteToken) } func (l *lexer) MatchAutoincrementToken() bool { @@ -340,6 +388,46 @@ func (l *lexer) MatchAutoincrementToken() bool { return l.Match([]byte("autoincrement"), AutoincrementToken) } +func (l *lexer) MatchPrimaryToken() bool { + return l.Match([]byte("primary"), PrimaryToken) +} + +func (l *lexer) MatchKeyToken() bool { + return l.Match([]byte("key"), KeyToken) +} + +func (l *lexer) MatchIntoToken() bool { + return l.Match([]byte("into"), IntoToken) +} + +func (l *lexer) MatchValuesToken() bool { + return l.Match([]byte("values"), ValuesToken) +} + +func (l *lexer) MatchJoinToken() bool { + return l.Match([]byte("join"), JoinToken) +} + +func (l *lexer) MatchOnToken() bool { + return l.Match([]byte("on"), OnToken) +} + +func (l *lexer) MatchOffsetToken() bool { + return l.Match([]byte("offset"), OffsetToken) +} + +func (l *lexer) MatchIndexToken() bool { + return l.Match([]byte("index"), IndexToken) +} + +func (l *lexer) MatchCollateToken() bool { + return l.Match([]byte("collate"), CollateToken) +} + +func (l *lexer) MatchNocaseToken() bool { + return l.Match([]byte("nocase"), NocaseToken) +} + func (l *lexer) MatchStringToken() bool { i := l.pos @@ -364,42 +452,22 @@ func (l *lexer) MatchStringToken() bool { return false } -func (l *lexer) MatchFloatToken() bool { +func (l *lexer) MatchNumberToken() bool { i := l.pos - for i < l.instructionLen && (unicode.IsDigit(rune(l.instruction[i])) || l.instruction[i] == '-') { - i++ - } - if i == l.pos || i >= l.instructionLen { - return false - } - - if l.instruction[i] != '.' && l.instruction[i] != 'e' { - return false - } - - if l.instruction[i] == '.' { + for i < l.instructionLen && unicode.IsDigit(rune(l.instruction[i])) { i++ } - - if l.instruction[i] == 'e' { + if i < l.instructionLen && l.instruction[i] == '.' { i++ - if i >= l.instructionLen { - return false + for i < l.instructionLen && unicode.IsDigit(rune(l.instruction[i])) { + i++ } - if l.instruction[i] != '+' && l.instruction[i] != '-' { - return false - } - i++ - } - - for i < l.instructionLen && (unicode.IsDigit(rune(l.instruction[i]))) { - i++ } if i != l.pos { t := Token{ - Token: FloatToken, + Token: NumberToken, Lexeme: string(l.instruction[l.pos:i]), } l.tokens = append(l.tokens, t) @@ -410,24 +478,56 @@ func (l *lexer) MatchFloatToken() bool { return false } -func (l *lexer) MatchNumberToken() bool { +func (l *lexer) MatchSemicolonToken() bool { + return l.MatchSingle(';', SemicolonToken) +} - i := l.pos - for i < l.instructionLen && (unicode.IsDigit(rune(l.instruction[i])) || l.instruction[i] == '-') { - i++ - } +func (l *lexer) MatchPeriodToken() bool { + return l.MatchSingle('.', PeriodToken) +} - if i != l.pos { - t := Token{ - Token: NumberToken, - Lexeme: string(l.instruction[l.pos:i]), - } - l.tokens = append(l.tokens, t) - l.pos = i - return true - } +func (l *lexer) MatchBracketOpeningToken() bool { + return l.MatchSingle('(', BracketOpeningToken) +} - return false +func (l *lexer) MatchBracketClosingToken() bool { + return l.MatchSingle(')', BracketClosingToken) +} + +func (l *lexer) MatchCommaToken() bool { + return l.MatchSingle(',', CommaToken) +} + +func (l *lexer) MatchStarToken() bool { + return l.MatchSingle('*', StarToken) +} + +func (l *lexer) MatchEqualityToken() bool { + return l.MatchSingle('=', EqualityToken) +} + +func (l *lexer) MatchDistinctnessToken() bool { + return l.Match([]byte("<>"), DistinctnessToken) +} + +func (l *lexer) MatchLeftDipleToken() bool { + return l.MatchSingle('<', LeftDipleToken) +} + +func (l *lexer) MatchRightDipleToken() bool { + return l.MatchSingle('>', RightDipleToken) +} + +func (l *lexer) MatchLessOrEqualToken() bool { + return l.Match([]byte("<="), LessOrEqualToken) +} + +func (l *lexer) MatchGreaterOrEqualToken() bool { + return l.Match([]byte(">="), GreaterOrEqualToken) +} + +func (l *lexer) MatchBacktickToken() bool { + return l.MatchSingle('`', BacktickToken) } // 2015-09-10 14:03:09.444695269 +0200 CEST); @@ -504,7 +604,7 @@ func (l *lexer) MatchEscapedStringToken() bool { escaped := l.instruction[l.pos+2 : i-1] for _, r := range escaped { - if !unicode.IsDigit(rune(r)) { + if unicode.IsDigit(rune(r)) == false { tok = StringToken } } @@ -634,18 +734,3 @@ func (l *lexer) Match(str []byte, token int) bool { l.pos += len(t.Lexeme) return true } - -func TypeNameFromToken(tk int) string { - switch tk { - case IntToken, NumberToken: - return "int" - case DateToken: - return "date" - case TextToken, StringToken: - return "text" - case FloatToken: - return "float" - default: - return "unknown" - } -} diff --git a/vendor/github.com/proullon/ramsql/engine/parser/log.go b/vendor/github.com/proullon/ramsql/engine/parser/log.go new file mode 100644 index 0000000..140b922 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/parser/log.go @@ -0,0 +1,9 @@ +package parser + +import ( +//"github.com/proullon/ramsql/engine/log" +) + +func debug(format string, v ...interface{}) { + //log.Debug(format, v...) +} diff --git a/vendor/github.com/proullon/ramsql/engine/parser/parser.go b/vendor/github.com/proullon/ramsql/engine/parser/parser.go index d3430ec..b551a83 100644 --- a/vendor/github.com/proullon/ramsql/engine/parser/parser.go +++ b/vendor/github.com/proullon/ramsql/engine/parser/parser.go @@ -25,44 +25,27 @@ type Decl struct { } // Stringy prints the declaration tree in console -func (d Decl) Stringy(depth int, printer func(fmt string, varargs ...any)) { - - if printer == nil { - printer = log.Debug - } - +func (d Decl) Stringy(depth int) { indent := "" for i := 0; i < depth; i++ { indent = fmt.Sprintf("%s ", indent) } - printer("%s|-> %s (%d)\n", indent, d.Lexeme, d.Token) + log.Debug("%s|-> %s\n", indent, d.Lexeme) for _, subD := range d.Decl { - subD.Stringy(depth+1, printer) + subD.Stringy(depth + 1) } } -func (d Decl) Has(t int) (*Decl, bool) { - for _, child := range d.Decl { - if child.Token == t { - return child, true - } - if cd, ok := child.Has(t); ok { - return cd, true - } - } - return nil, false -} - // Instruction define a valid SQL statement type Instruction struct { Decls []*Decl } // PrettyPrint prints instruction's declarations on console with indentation -func (i Instruction) PrettyPrint(printer func(fmt string, varargs ...interface{})) { +func (i Instruction) PrettyPrint() { for _, d := range i.Decls { - d.Stringy(0, printer) + d.Stringy(0) } } @@ -110,42 +93,50 @@ func (p *parser) parse(tokens []Token) ([]Instruction, error) { return nil, err } p.i = append(p.i, *i) + break case SelectToken: i, err := p.parseSelect(tokens) if err != nil { return nil, err } p.i = append(p.i, *i) + break case InsertToken: i, err := p.parseInsert() if err != nil { return nil, err } p.i = append(p.i, *i) + break case UpdateToken: i, err := p.parseUpdate() if err != nil { return nil, err } p.i = append(p.i, *i) + break case DeleteToken: i, err := p.parseDelete() if err != nil { return nil, err } p.i = append(p.i, *i) + break case TruncateToken: i, err := p.parseTruncate() if err != nil { return nil, err } p.i = append(p.i, *i) + break case DropToken: - i, err := p.parseDrop(tokens) + log.Debug("HEY DROP HERE !\n") + i, err := p.parseDrop() if err != nil { return nil, err } p.i = append(p.i, *i) + break case ExplainToken: break case GrantToken: @@ -212,8 +203,131 @@ func (p *parser) parseUpdate() (*Instruction, error) { return i, nil } +// Parses an INSERT statement. +// +// The generated AST is as follows: +// +// |-> "INSERT" (InsertToken) +// |-> "INTO" (IntoToken) +// |-> table name +// |-> column name +// |-> (...) +// |-> "VALUES" (ValuesToken) +// |-> "(" (BracketOpeningToken) +// |-> value +// |-> (...) +// |-> (...) +// |-> "RETURNING" (ReturningToken) (optional) +// |-> column name +func (p *parser) parseInsert() (*Instruction, error) { + i := &Instruction{} + + // Set INSERT decl + insertDecl, err := p.consumeToken(InsertToken) + if err != nil { + return nil, err + } + i.Decls = append(i.Decls, insertDecl) + + // should be INTO + intoDecl, err := p.consumeToken(IntoToken) + if err != nil { + return nil, err + } + insertDecl.Add(intoDecl) + + // should be table Name + tableDecl, err := p.parseQuotedToken() + if err != nil { + return nil, err + } + intoDecl.Add(tableDecl) + + _, err = p.consumeToken(BracketOpeningToken) + if err != nil { + return nil, err + } + + // concerned attribute + for { + decl, err := p.parseListElement() + if err != nil { + return nil, err + } + tableDecl.Add(decl) + + if p.is(BracketClosingToken) { + if _, err = p.consumeToken(BracketClosingToken); err != nil { + return nil, err + } + + break + } + + _, err = p.consumeToken(CommaToken) + if err != nil { + return nil, err + } + } + + // should be VALUES + valuesDecl, err := p.consumeToken(ValuesToken) + if err != nil { + return nil, err + } + insertDecl.Add(valuesDecl) + + for { + openingBracketDecl, err := p.consumeToken(BracketOpeningToken) + if err != nil { + return nil, err + } + valuesDecl.Add(openingBracketDecl) + + // should be a list of values for specified attributes + for { + decl, err := p.parseListElement() + if err != nil { + return nil, err + } + openingBracketDecl.Add(decl) + + if p.is(BracketClosingToken) { + p.consumeToken(BracketClosingToken) + break + } + + _, err = p.consumeToken(CommaToken) + if err != nil { + return nil, err + } + } + + if p.is(CommaToken) { + p.consumeToken(CommaToken) + continue + } + + break + } + + // we may have `returning "something"` here + if retDecl, err := p.consumeToken(ReturningToken); err == nil { + insertDecl.Add(retDecl) + + // returned attribute + attrDecl, err := p.parseAttribute() + if err != nil { + return nil, err + } + retDecl.Add(attrDecl) + } + + return i, nil +} + func (p *parser) parseType() (*Decl, error) { - typeDecl, err := p.consumeToken(FloatToken, DateToken, DecimalToken, NumberToken, StringToken) + typeDecl, err := p.consumeToken(StringToken) if err != nil { return nil, err } @@ -310,94 +424,6 @@ func (p *parser) parseBuiltinFunc() (*Decl, error) { return d, nil } -// parseTableName parse a table of the form -// schema.table -// "schema".table -// "schema"."table" -// table -func (p *parser) parseTableName() (*Decl, error) { - quoted := false - quoteToken := DoubleQuoteToken - - if p.is(DoubleQuoteToken) || p.is(BacktickToken) { - quoteToken = p.cur().Token - quoted = true - if err := p.next(); err != nil { - return nil, err - } - } - - // should be a StringToken here - // If there is a point after, it's a table name, - // if not, it's the attribute - if !p.is(StringToken, StarToken) { - return nil, p.syntaxError() - } - decl := NewDecl(p.cur()) - - if quoted { - // Check there is a closing quote - if _, err := p.mustHaveNext(quoteToken); err != nil { - return nil, err - } - } - quoted = false - - // If no next token, and not quoted, then is was the attribute name - if err := p.next(); err != nil { - return decl, nil - } - - // Now, is it a point ? - if p.is(PeriodToken) { - _, err := p.consumeToken(PeriodToken) - if err != nil { - return nil, err - } - - // mayby attribute is quoted as well (see #62) - if p.is(DoubleQuoteToken) || p.is(BacktickToken) { - quoteToken = p.cur().Token - quoted = true - if err := p.next(); err != nil { - return nil, err - } - } - // if so, next must be the attribute name or a star - attributeDecl, err := p.consumeToken(StringToken, StarToken) - if err != nil { - return nil, err - } - decl.Token = SchemaToken - attributeDecl.Add(decl) - - if quoted { - // Check there is a closing quote - if _, err := p.consumeToken(quoteToken); err != nil { - return nil, fmt.Errorf("expected closing quote: %s", err) - } - } - return attributeDecl, nil - } - - // AS SOMETHING ? - if p.is(AsToken) { - asDecl, err := p.consumeToken(AsToken) - if err != nil { - return nil, err - } - decl.Add(asDecl) - aliasDecl, err := p.consumeToken(StringToken) - if err != nil { - return nil, err - } - asDecl.Add(aliasDecl) - } - - // Then the first string token was the naked attribute name - return decl, nil -} - // parseAttribute parse an attribute of the form // table.foo // table.* @@ -427,6 +453,7 @@ func (p *parser) parseAttribute() (*Decl, error) { if quoted { // Check there is a closing quote if _, err := p.mustHaveNext(quoteToken); err != nil { + log.Debug("parseAttribute: Missing closing quote") return nil, err } } @@ -501,10 +528,7 @@ func (p *parser) parseQuotedToken() (*Decl, error) { } } - err := p.next() - if err != nil { - return nil, err - } + p.next() return decl, nil } @@ -527,6 +551,7 @@ func (p *parser) parseAttribution() (*Decl, error) { // Value if p.cur().Token == NullToken { + log.Debug("parseAttribution: NullToken\n") nullDecl, err := p.consumeToken(NullToken) if err != nil { return nil, err @@ -566,13 +591,10 @@ func (p *parser) parseIn() (*Decl, error) { gotList = true if p.is(BracketClosingToken) { - if !gotList { + if gotList == false { return nil, fmt.Errorf("IN clause: empty list of value") } - _, err = p.consumeToken(BracketClosingToken) - if err != nil { - return nil, err - } + p.consumeToken(BracketClosingToken) break } @@ -590,20 +612,25 @@ func (p *parser) parseValue() (*Decl, error) { if p.is(SimpleQuoteToken) || p.is(DoubleQuoteToken) { quoted = true + debug("value %v is quoted!", p.tokens[p.index]) _, err := p.consumeToken(SimpleQuoteToken, DoubleQuoteToken) if err != nil { return nil, err } } - valueDecl, err := p.consumeToken(FloatToken, StringToken, NumberToken, DateToken, NowToken, CurrentSchemaToken, ArgToken, NamedArgToken) + valueDecl, err := p.consumeToken(StringToken, NumberToken, DateToken, NowToken) if err != nil { + debug("parseValue: Wasn't expecting %v\n", p.tokens[p.index]) return nil, err } + log.Debug("Parsing value %v !\n", valueDecl) if quoted { + log.Debug("consume quote %v\n", p.tokens[p.index]) _, err := p.consumeToken(SimpleQuoteToken, DoubleQuoteToken) if err != nil { + debug("uuuh, wasn't a quote") return nil, err } } @@ -646,19 +673,6 @@ func (p *parser) parseJoin() (*Decl, error) { } joinDecl.Add(tableDecl) - // AS SOMETHING ? - if p.is(AsToken) { - _, err = p.consumeToken(AsToken) - if err != nil { - return nil, err - } - aliasDecl, err := p.consumeToken(StringToken) - if err != nil { - return nil, err - } - tableDecl.Add(aliasDecl) - } - // ON onDecl, err := p.consumeToken(OnToken) if err != nil { @@ -691,6 +705,38 @@ func (p *parser) parseJoin() (*Decl, error) { return joinDecl, nil } +func (p *parser) parseListElement() (*Decl, error) { + quoted := false + + // In case of INSERT, can be DEFAULT here + if p.is(DefaultToken) { + v, err := p.consumeToken(DefaultToken) + if err != nil { + return nil, err + } + return v, nil + } + + if p.is(SimpleQuoteToken) || p.is(DoubleQuoteToken) { + quoted = true + p.next() + } + + var valueDecl *Decl + valueDecl, err := p.consumeToken(StringToken, NumberToken, NullToken, DateToken, NowToken) + if err != nil { + return nil, err + } + + if quoted { + if _, err := p.consumeToken(SimpleQuoteToken, DoubleQuoteToken); err != nil { + return nil, err + } + } + + return valueDecl, nil +} + func (p *parser) next() error { if !p.hasNext() { return fmt.Errorf("Unexpected end") @@ -700,7 +746,10 @@ func (p *parser) next() error { } func (p *parser) hasNext() bool { - return p.index+1 < len(p.tokens) + if p.index+1 < len(p.tokens) { + return true + } + return false } func (p *parser) is(tokenTypes ...int) bool { @@ -721,34 +770,41 @@ func (p *parser) isNot(tokenTypes ...int) bool { func (p *parser) isNext(tokenTypes ...int) (t Token, err error) { if !p.hasNext() { + debug("parser.isNext: has no next") return t, p.syntaxError() } + debug("parser.isNext %v", tokenTypes) for _, tokenType := range tokenTypes { if p.tokens[p.index+1].Token == tokenType { return p.tokens[p.index+1], nil } } + debug("parser.isNext: Next (%v) is not among %v", p.cur(), tokenTypes) return t, p.syntaxError() } func (p *parser) mustHaveNext(tokenTypes ...int) (t Token, err error) { if !p.hasNext() { + debug("parser.mustHaveNext: has no next") return t, p.syntaxError() } if err = p.next(); err != nil { + debug("parser.mustHaveNext: error getting next") return t, err } + debug("parser.mustHaveNext %v", tokenTypes) for _, tokenType := range tokenTypes { if p.is(tokenType) { return p.tokens[p.index], nil } } + debug("parser.mustHaveNext: Next (%v) is not among %v", p.cur(), tokenTypes) return t, p.syntaxError() } diff --git a/vendor/github.com/proullon/ramsql/engine/parser/select.go b/vendor/github.com/proullon/ramsql/engine/parser/select.go index 445cc15..1e59617 100644 --- a/vendor/github.com/proullon/ramsql/engine/parser/select.go +++ b/vendor/github.com/proullon/ramsql/engine/parser/select.go @@ -61,9 +61,8 @@ func (p *parser) parseSelect(tokens []Token) (*Instruction, error) { } if distinctOpen { distinctDecl.Add(attrDecl) - } else { - selectDecl.Add(attrDecl) } + selectDecl.Add(attrDecl) } switch { @@ -96,7 +95,7 @@ func (p *parser) parseSelect(tokens []Token) (*Instruction, error) { if err = p.next(); err != nil { return nil, fmt.Errorf("Unexpected end. Syntax error near %v\n", tokens[p.index]) } - tableNameDecl, err := p.parseTableName() + tableNameDecl, err := p.parseAttribute() if err != nil { return nil, err } @@ -132,7 +131,7 @@ func (p *parser) parseSelect(tokens []Token) (*Instruction, error) { } hazWhereClause = true case OrderToken: - if !hazWhereClause { + if hazWhereClause == false { // WHERE clause is implicit addImplicitWhereAll(selectDecl) } diff --git a/vendor/github.com/proullon/ramsql/engine/parser/where.go b/vendor/github.com/proullon/ramsql/engine/parser/where.go index 5f0294e..232a028 100644 --- a/vendor/github.com/proullon/ramsql/engine/parser/where.go +++ b/vendor/github.com/proullon/ramsql/engine/parser/where.go @@ -2,6 +2,8 @@ package parser import ( "fmt" + + "github.com/proullon/ramsql/engine/log" ) func (p *parser) parseWhere(selectDecl *Decl) error { @@ -52,28 +54,13 @@ func (p *parser) parseCondition() (*Decl, error) { // We may have the WHERE 1 condition if t := p.cur(); t.Token == NumberToken && t.Lexeme == "1" { attributeDecl := NewDecl(t) - - // WHERE 1 - if !p.hasNext() { - return attributeDecl, nil - } - err := p.next() - if err != nil { - return nil, err - } - - // WHERE 1 = 1 + p.next() + // in case of 1 = 1 if p.cur().Token == EqualityToken { t, err := p.isNext(NumberToken) if err == nil && t.Lexeme == "1" { - _, err = p.consumeToken(EqualityToken) - if err != nil { - return nil, err - } - _, err = p.consumeToken(NumberToken) - if err != nil { - return nil, err - } + p.consumeToken(EqualityToken) + p.consumeToken(NumberToken) } } return attributeDecl, nil @@ -82,10 +69,7 @@ func (p *parser) parseCondition() (*Decl, error) { // do we have brackets ? hasBracket := false if p.is(BracketOpeningToken) { - _, err := p.consumeToken(BracketOpeningToken) - if err != nil { - return nil, err - } + p.consumeToken(BracketOpeningToken) hasBracket = true } @@ -102,6 +86,7 @@ func (p *parser) parseCondition() (*Decl, error) { return nil, err } attributeDecl.Add(decl) + break case InToken: inDecl, err := p.parseIn() if err != nil { @@ -128,12 +113,14 @@ func (p *parser) parseCondition() (*Decl, error) { attributeDecl.Add(notDecl) return attributeDecl, nil case IsToken: + log.Debug("parseCondition: IsToken\n") decl, err := p.consumeToken(IsToken) if err != nil { return nil, err } attributeDecl.Add(decl) if p.cur().Token == NotToken { + log.Debug("parseCondition: NotToken\n") notDecl, err := p.consumeToken(NotToken) if err != nil { return nil, err @@ -141,6 +128,7 @@ func (p *parser) parseCondition() (*Decl, error) { decl.Add(notDecl) } if p.cur().Token == NullToken { + log.Debug("parseCondition: NullToken\n") nullDecl, err := p.consumeToken(NullToken) if err != nil { return nil, err diff --git a/vendor/github.com/proullon/ramsql/engine/predicate.go b/vendor/github.com/proullon/ramsql/engine/predicate.go new file mode 100644 index 0000000..fd4f69b --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/predicate.go @@ -0,0 +1,141 @@ +package engine + +import ( + "fmt" +) + +// PredicateLinker referes to AND and OR operators. +type PredicateLinker interface { + Eval(v virtualRow) (bool, error) +} + +type andOperator struct { + pred []PredicateLinker +} + +func (o *andOperator) Add(p PredicateLinker) { + o.pred = append(o.pred, p) +} + +func (o *andOperator) Eval(v virtualRow) (bool, error) { + + for i := range o.pred { + ok, err := o.pred[i].Eval(v) + if err != nil { + return false, err + } + if !ok { + return false, nil + } + } + + return true, nil +} + +type orOperator struct { + pred []PredicateLinker +} + +func (o *orOperator) Add(p PredicateLinker) { + o.pred = append(o.pred, p) +} + +func (o *orOperator) Eval(v virtualRow) (bool, error) { + + for i := range o.pred { + ok, err := o.pred[i].Eval(v) + if err != nil { + return false, err + } + if ok { + return true, nil + } + } + + return false, nil +} + +// TruePredicate is a predicate which return always true +var TruePredicate = Predicate{ + True: true, +} + +// Value is a value given to predicates +type Value struct { + v interface{} + valid bool + lexeme string + constant bool + table string +} + +// Predicate evaluate if a condition is valid with 2 values and an operator on this 2 values +type Predicate struct { + LeftValue Value + Operator Operator + RightValue Value + True bool +} + +func (p Predicate) String() string { + var left, right string + + if p.True { + return "AlwaysTrue" + } + + left = "?" + right = "?" + + if p.LeftValue.valid { + left = p.LeftValue.lexeme + } + + if p.RightValue.valid { + right = p.RightValue.lexeme + } + + return fmt.Sprintf("[%s] vs [%s]", left, right) +} + +// Eval fetches operand from virtual row and run operator +func (p *Predicate) Eval(row virtualRow) (bool, error) { + + if p.True { + return true, nil + } + + // Find left attribute + left := p.LeftValue.table + "." + p.LeftValue.lexeme + val, ok := row[left] + if !ok { + return false, fmt.Errorf("Attribute [%s] not found in row", left) + } + p.LeftValue.v = val.v + + return p.Operator(p.LeftValue, p.RightValue), nil +} + +// Evaluate is deprecated (see Eval). It calls operators and use tuple as operand +// TODO: Delete that +func (p *Predicate) Evaluate(t *Tuple, table *Table) (bool, error) { + + if p.True { + return true, nil + } + + // Find left + var i = 0 + lenTable := len(table.attributes) + for i = 0; i < lenTable; i++ { + if table.attributes[i].name == p.LeftValue.lexeme { + break + } + } + if i == lenTable { + return false, fmt.Errorf("Attribute [%s] not found in table [%s]", p.LeftValue.lexeme, table.name) + } + + p.LeftValue.v = t.Values[i] + return p.Operator(p.LeftValue, p.RightValue), nil +} diff --git a/vendor/github.com/proullon/ramsql/engine/protocol/buffer.go b/vendor/github.com/proullon/ramsql/engine/protocol/buffer.go new file mode 100644 index 0000000..46a28ab --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/protocol/buffer.go @@ -0,0 +1,81 @@ +package protocol + +import ( + "container/list" + + "github.com/proullon/ramsql/engine/log" +) + +// UnlimitedRowsChannel buffers incomming message from bufferThis channel and forward them to +// returned channel. +// ONLY CREATED CHANNEL IS CLOSED HERE. +func UnlimitedRowsChannel(bufferThis chan message, firstMessage message) chan []string { + driverChannel := make(chan []string) + rowList := list.New() + + rowList.PushBack(firstMessage.Value) + + go func() { + for { + // If nothing comes in and nothing is going out... + if rowList.Len() == 0 && bufferThis == nil { + close(driverChannel) + return + } + + // Create a copy of driverChannel because if there is nothing to send + // We can disable the case in select with a nil channel and get a chance + // to fetch new data on bufferThis channel + driverChannelNullable := driverChannel + var nextRow []string + if rowList.Len() != 0 { + nextRow = rowList.Front().Value.([]string) + } else { + driverChannelNullable = nil + } + + select { + // In case a new row is sent to driver + case driverChannelNullable <- nextRow: + if nextRow != nil { + rowList.Remove(rowList.Front()) + } + // In case we receive a new value to buffer from engine channel + case newRow, ok := <-bufferThis: + if !ok || newRow.Type == rowEndMessage { + // Stop listening to bufferThis channel + bufferThis = nil + // If there is nothing more to listen and there is nothing in buffer, exit + // close driverChannel so *Rows knows there is nothing more to read + if rowList.Len() == 0 { + if driverChannel != nil { + close(driverChannel) + } + return + } + + if driverChannel == nil { + log.Critical("Unlimited: But there is nobody to read it, exiting") + return + } + } else if newRow.Type == errMessage { + log.Critical("Runtime error: %s", newRow.Value[0]) + if driverChannel != nil { + close(driverChannel) + } + return + } else { + // Everything is ok, buffering new value + rowList.PushBack(newRow.Value) + } + case exit := <-driverChannel: + // this means driverChannel is closed + // set driverChannel to nil so we don't try to close it again + driverChannel = nil + _ = exit + } + } + }() + + return driverChannel +} diff --git a/vendor/github.com/proullon/ramsql/engine/protocol/channel.go b/vendor/github.com/proullon/ramsql/engine/protocol/channel.go new file mode 100644 index 0000000..ccfd07c --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/protocol/channel.go @@ -0,0 +1,238 @@ +package protocol + +import ( + "errors" + "fmt" + "io" +) + +const ( + errMessage = "ERR" + queryMessage = "QUERY" + execMessage = "EXEC" + resultMessage = "RES" + rowHeaderMessage = "ROWHEAD" + rowValueMessage = "ROWVAL" + rowEndMessage = "ROWEND" +) + +type message struct { + Type string + Value []string +} + +// ChannelDriverConn implements DriverConn for channel backend +type ChannelDriverConn struct { + conn chan message +} + +// ChannelDriverEndpoint implements DriverEndpoint for channel backend +type ChannelDriverEndpoint struct { + newConnChannel chan<- chan message +} + +// Close method closes the connection to RamSQL server +func (cdc *ChannelDriverConn) Close() { + if cdc.conn == nil { + return + } + close(cdc.conn) + cdc.conn = nil +} + +// New method creates a new DriverConn from DriverEndpoint +func (cde *ChannelDriverEndpoint) New(uri string) (DriverConn, error) { + + if cde.newConnChannel == nil { + return nil, fmt.Errorf("connection closed") + } + + channel := make(chan message) + cdc := &ChannelDriverConn{conn: channel} + cde.newConnChannel <- channel + return cdc, nil +} + +// NewChannelDriverEndpoint initialize a DriverEndpoint with channel backend +func NewChannelDriverEndpoint(channel chan<- chan message) DriverEndpoint { + cde := &ChannelDriverEndpoint{ + newConnChannel: channel, + } + + return cde +} + +// ChannelEngineEndpoint implements EngineEndpoint for channel backend +type ChannelEngineEndpoint struct { + newConnChannel <-chan chan message +} + +// NewChannelEngineEndpoint initialize a EngineEndpoint with channel backend +func NewChannelEngineEndpoint(channel <-chan chan message) EngineEndpoint { + cee := &ChannelEngineEndpoint{ + newConnChannel: channel, + } + + return cee +} + +// Accept read from new channels channel and return an EngineConn +func (cee *ChannelEngineEndpoint) Accept() (EngineConn, error) { + newConn, ok := <-cee.newConnChannel + if !ok { + return nil, io.EOF + } + + return NewChannelEngineConn(newConn), nil +} + +// Close close the connection with client +func (cee *ChannelEngineEndpoint) Close() { +} + +// ChannelEngineConn implements EngineConn for channel backend +type ChannelEngineConn struct { + conn chan message +} + +// NewChannelEngineConn initializes a new EngineConn with channel backend +func NewChannelEngineConn(newConn chan message) EngineConn { + cec := &ChannelEngineConn{ + conn: newConn, + } + + return cec +} + +// ReadStatement get SQL statements from client +func (cec *ChannelEngineConn) ReadStatement() (string, error) { + message, ok := <-cec.conn + if !ok { + cec.conn = nil + return "", io.EOF + } + + return message.Value[0], nil +} + +// WriteResult is used to answer to statements other than SELECT +func (cec *ChannelEngineConn) WriteResult(lastInsertedID int64, rowsAffected int64) error { + m := message{ + Type: resultMessage, + Value: []string{fmt.Sprintf("%d %d", lastInsertedID, rowsAffected)}, + } + + cec.conn <- m + return nil +} + +// WriteError when error occurs +func (cec *ChannelEngineConn) WriteError(err error) error { + m := message{ + Type: errMessage, + Value: []string{err.Error()}, + } + + cec.conn <- m + return nil + +} + +// WriteRowHeader indicates that rows are coming next +func (cec *ChannelEngineConn) WriteRowHeader(header []string) error { + m := message{ + Type: rowHeaderMessage, + Value: header, + } + + cec.conn <- m + return nil + +} + +// WriteRow must be called after WriteRowHeader and before WriteRowEnd +func (cec *ChannelEngineConn) WriteRow(row []string) error { + m := message{ + Type: rowValueMessage, + Value: row, + } + + cec.conn <- m + return nil +} + +// WriteRowEnd indicates that query is done +func (cec *ChannelEngineConn) WriteRowEnd() error { + m := message{ + Type: rowEndMessage, + } + + cec.conn <- m + return nil +} + +// WriteQuery allows client to query the RamSQL server +func (cdc *ChannelDriverConn) WriteQuery(query string) error { + if cdc.conn == nil { + return fmt.Errorf("connection closed") + } + + m := message{ + Type: queryMessage, + Value: []string{query}, + } + + cdc.conn <- m + return nil +} + +// WriteExec allows client to manipulate the RamSQL server +func (cdc *ChannelDriverConn) WriteExec(statement string) error { + if cdc.conn == nil { + return fmt.Errorf("connection closed") + } + + m := message{ + Type: execMessage, + Value: []string{statement}, + } + + cdc.conn <- m + return nil +} + +// ReadResult when Exec has been used +func (cdc *ChannelDriverConn) ReadResult() (lastInsertedID int64, rowsAffected int64, err error) { + if cdc.conn == nil { + return 0, 0, fmt.Errorf("connection closed") + } + + m := <-cdc.conn + if m.Type != resultMessage { + if m.Type == errMessage { + return 0, 0, errors.New(m.Value[0]) + } + return 0, 0, fmt.Errorf("Protocol error: ReadResult received %v", m) + } + + _, err = fmt.Sscanf(m.Value[0], "%d %d", &lastInsertedID, &rowsAffected) + return lastInsertedID, rowsAffected, err +} + +// ReadRows when Query has been used +func (cdc *ChannelDriverConn) ReadRows() (chan []string, error) { + if cdc.conn == nil { + return nil, fmt.Errorf("connection closed") + } + + m := <-cdc.conn + if m.Type == errMessage { + return nil, errors.New(m.Value[0]) + } + + if m.Type != rowHeaderMessage { + return nil, errors.New("not a rows header") + } + + return UnlimitedRowsChannel(cdc.conn, m), nil +} diff --git a/vendor/github.com/proullon/ramsql/engine/protocol/public.go b/vendor/github.com/proullon/ramsql/engine/protocol/public.go new file mode 100644 index 0000000..c935a0d --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/protocol/public.go @@ -0,0 +1,43 @@ +package protocol + +// DriverConn is a networking helper hiding implementation +// either with channels or network sockets. +type DriverConn interface { + WriteQuery(query string) error + WriteExec(stmt string) error + ReadResult() (lastInsertedID int64, rowsAffected int64, err error) + ReadRows() (chan []string, error) + Close() +} + +// EngineConn is a networking helper hiding implementation +// either with channels or network sockets. +type EngineConn interface { + ReadStatement() (string, error) + WriteResult(lastInsertedID int64, rowsAffected int64) error + WriteError(err error) error + WriteRowHeader(header []string) error + WriteRow(row []string) error + WriteRowEnd() error +} + +// EngineEndpoint is the query entrypoint of RamSQL engine. +type EngineEndpoint interface { + Accept() (EngineConn, error) + Close() +} + +// DriverEndpoint instanciates either +// - an Engine and communication channels +// - a network socket to connect to an existing RamSQL engine +type DriverEndpoint interface { + New(string) (DriverConn, error) +} + +// NewChannelEndpoints instanciates a Driver and +// Engine channel endpoints +func NewChannelEndpoints() (DriverEndpoint, EngineEndpoint) { + channel := make(chan chan message) + + return NewChannelDriverEndpoint(channel), NewChannelEngineEndpoint(channel) +} diff --git a/vendor/github.com/proullon/ramsql/engine/relation.go b/vendor/github.com/proullon/ramsql/engine/relation.go new file mode 100644 index 0000000..1f87fb4 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/relation.go @@ -0,0 +1,30 @@ +package engine + +import ( + "sync" +) + +// Relation is a table with column and rows +// AKA File +type Relation struct { + sync.RWMutex + table *Table + rows []*Tuple +} + +// NewRelation initializes a new Relation struct +func NewRelation(t *Table) *Relation { + r := &Relation{ + table: t, + } + + return r +} + +// Insert a tuple in relation +func (r *Relation) Insert(t *Tuple) error { + // Maybe do somthing like lock read/write here + // Maybe index + r.rows = append(r.rows, t) + return nil +} diff --git a/vendor/github.com/proullon/ramsql/engine/select.go b/vendor/github.com/proullon/ramsql/engine/select.go new file mode 100644 index 0000000..bc91bb8 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/select.go @@ -0,0 +1,633 @@ +package engine + +import ( + "errors" + "fmt" + "strconv" + "strings" + + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/parser" + "github.com/proullon/ramsql/engine/protocol" +) + +func attributeExistsInTable(e *Engine, attr string, table string) error { + + r := e.relation(table) + if r == nil { + return fmt.Errorf("table \"%s\" does not exist", table) + } + + found := false + for _, tAttr := range r.table.attributes { + if tAttr.name == attr { + found = true + break + } + + } + + if !found { + return fmt.Errorf("attribute %s does not exist in table %s", attr, table) + } + + return nil +} + +func attributesExistInTables(e *Engine, attributes []Attribute, tables []string) error { + + for _, attr := range attributes { + if attr.name == "COUNT" { + continue + } + + if strings.Contains(attr.name, ".") { + t := strings.Split(attr.name, ".") + if err := attributeExistsInTable(e, t[1], t[0]); err != nil { + return err + } + continue + } + + found := 0 + for _, t := range tables { + + if err := attributeExistsInTable(e, attr.name, t); err == nil { + found++ + } + + if found == 0 { + return fmt.Errorf("attribute %s does not exist in tables %v", attr.name, tables) + } + if found > 1 { + return fmt.Errorf("ambiguous attribute %s", attr.name) + } + } + } + + return nil +} + +/* +|-> SELECT + |-> * + |-> FROM + |-> account + |-> WHERE + |-> email + |-> = + |-> foo@bar.com +*/ +func selectExecutor(e *Engine, selectDecl *parser.Decl, conn protocol.EngineConn) error { + var attributes []Attribute + var tables []*Table + var predicates []PredicateLinker + var functors []selectFunctor + var joiners []joiner + var err error + + selectDecl.Stringy(0) + for i := range selectDecl.Decl { + switch selectDecl.Decl[i].Token { + case parser.FromToken: + // get selected tables + tables = fromExecutor(selectDecl.Decl[i]) + case parser.WhereToken: + // get WHERE declaration + pred, err := whereExecutor2(e, selectDecl.Decl[i].Decl, tables[0].name) + if err != nil { + return err + } + predicates = []PredicateLinker{pred} + case parser.JoinToken: + j, err := joinExecutor(selectDecl.Decl[i]) + if err != nil { + return err + } + joiners = append(joiners, j) + case parser.OrderToken: + orderFunctor, err := orderbyExecutor(selectDecl.Decl[i], tables) + if err != nil { + return err + } + functors = append(functors, orderFunctor) + case parser.LimitToken: + limit, err := strconv.Atoi(selectDecl.Decl[i].Decl[0].Lexeme) + if err != nil { + return fmt.Errorf("wrong limit value: %s", err) + } + conn = limitedConn(conn, limit) + case parser.OffsetToken: + offset, err := strconv.Atoi(selectDecl.Decl[i].Decl[0].Lexeme) + if err != nil { + return fmt.Errorf("wrong offset value: %s", err) + } + conn = offsetedConn(conn, offset) + case parser.DistinctToken: + conn = distinctedConn(conn, len(selectDecl.Decl[i].Decl)) + } + } + + for i := range selectDecl.Decl { + if selectDecl.Decl[i].Token != parser.StringToken && + selectDecl.Decl[i].Token != parser.StarToken && + selectDecl.Decl[i].Token != parser.CountToken { + continue + } + + // get attribute to selected + attr, err := getSelectedAttribute(e, selectDecl.Decl[i], tables) + if err != nil { + return err + } + attributes = append(attributes, attr...) + + } + + if len(functors) == 0 { + // Instantiate a new select functor + functors, err = getSelectFunctors(selectDecl) + if err != nil { + return err + } + } + + err = generateVirtualRows(e, attributes, conn, tables[0].name, joiners, predicates, functors) + if err != nil { + return err + } + + return nil +} + +type selectFunctor interface { + Init(e *Engine, conn protocol.EngineConn, attr []string, alias []string) error + FeedVirtualRow(row virtualRow) error + Done() error +} + +// getSelectFunctors instantiate new functors for COUNT, MAX, MIN, AVG, ... and default select functor that return rows to client +// If a functor is specified, no attribute can be selected ? +func getSelectFunctors(attr *parser.Decl) ([]selectFunctor, error) { + var functors []selectFunctor + + for i := range attr.Decl { + + if attr.Decl[i].Token == parser.FromToken { + break + } + + if attr.Decl[i].Token == parser.CountToken { + f := &countSelectFunction{} + functors = append(functors, f) + } + } + + if len(functors) == 0 { + f := &defaultSelectFunction{} + functors = append(functors, f) + } + + return functors, nil + +} + +type defaultSelectFunction struct { + e *Engine + conn protocol.EngineConn + attributes []string + alias []string +} + +func (f *defaultSelectFunction) Init(e *Engine, conn protocol.EngineConn, attr []string, alias []string) error { + f.e = e + f.conn = conn + f.attributes = attr + f.alias = alias + + return f.conn.WriteRowHeader(f.alias) +} + +func (f *defaultSelectFunction) FeedVirtualRow(vrow virtualRow) error { + var row []string + + for _, attr := range f.attributes { + val, ok := vrow[attr] + if !ok { + return fmt.Errorf("could not select attribute %s", attr) + } + row = append(row, fmt.Sprintf("%v", val.v)) + } + + return f.conn.WriteRow(row) +} + +func (f *defaultSelectFunction) Done() error { + return f.conn.WriteRowEnd() +} + +type countSelectFunction struct { + e *Engine + conn protocol.EngineConn + attributes []string + alias []string + Count int64 +} + +func (f *countSelectFunction) Init(e *Engine, conn protocol.EngineConn, attr []string, alias []string) error { + f.e = e + f.conn = conn + f.attributes = attr + f.alias = alias + return nil +} + +func (f *countSelectFunction) FeedVirtualRow(row virtualRow) error { + f.Count++ + return nil +} + +func (f *countSelectFunction) Done() error { + err := f.conn.WriteRowHeader(f.alias) + if err != nil { + return err + } + + err = f.conn.WriteRow([]string{fmt.Sprintf("%d", f.Count)}) + if err != nil { + return err + } + + return f.conn.WriteRowEnd() +} + +func inExecutor(inDecl *parser.Decl, p *Predicate) error { + inDecl.Stringy(0) + + p.Operator = inOperator + + // Put everything in a []string + var values []string + for i := range inDecl.Decl { + log.Debug("inExecutor: Appending [%s]", inDecl.Decl[i].Lexeme) + values = append(values, inDecl.Decl[i].Lexeme) + } + p.RightValue.v = values + + return nil +} + +func notInExecutor(inDecl *parser.Decl, p *Predicate) error { + inDecl.Stringy(0) + + p.Operator = notInOperator + + // Put everything in a []string + var values []string + for i := range inDecl.Decl { + log.Debug("notIinExecutor: Appending [%s]", inDecl.Decl[i].Lexeme) + values = append(values, inDecl.Decl[i].Lexeme) + } + p.RightValue.v = values + + return nil +} + +func isExecutor(isDecl *parser.Decl, p *Predicate) error { + isDecl.Stringy(0) + + if isDecl.Decl[0].Token == parser.NullToken { + p.Operator = isNullOperator + } else { + p.Operator = isNotNullOperator + } + + return nil +} + +func or(e *Engine, left []*parser.Decl, right []*parser.Decl, tableName string) (PredicateLinker, error) { + p := &orOperator{} + + if len(left) > 0 { + lPred, err := whereExecutor2(e, left, tableName) + if err != nil { + return nil, err + } + p.Add(lPred) + } + + if len(right) > 0 { + rPred, err := whereExecutor2(e, right, tableName) + if err != nil { + return nil, err + } + p.Add(rPred) + } + + return p, nil +} + +func and(e *Engine, left []*parser.Decl, right []*parser.Decl, tableName string) (PredicateLinker, error) { + p := &andOperator{} + + if len(left) > 0 { + lPred, err := whereExecutor2(e, left, tableName) + if err != nil { + return nil, err + } + p.Add(lPred) + } + + if len(right) > 0 { + rPred, err := whereExecutor2(e, right, tableName) + if err != nil { + return nil, err + } + p.Add(rPred) + } + + return p, nil +} + +func whereExecutor2(e *Engine, decl []*parser.Decl, fromTableName string) (PredicateLinker, error) { + + for i, cond := range decl { + + if cond.Token == parser.AndToken { + if i+1 == len(decl) { + return nil, fmt.Errorf("query error: AND not followed by any predicate") + } + + p, err := and(e, decl[:i], decl[i+1:], fromTableName) + return p, err + } + + if cond.Token == parser.OrToken { + if i+1 == len(decl) { + return nil, fmt.Errorf("query error: OR not followd by any predicate") + } + p, err := or(e, decl[:i], decl[i+1:], fromTableName) + return p, err + } + } + + p := &Predicate{} + var err error + cond := decl[0] + + // 1 PREDICATE + if cond.Lexeme == "1" { + return &TruePredicate, nil + } + + switch cond.Decl[0].Token { + case parser.IsToken, parser.InToken, parser.EqualityToken, parser.DistinctnessToken, parser.LeftDipleToken, parser.RightDipleToken, parser.LessOrEqualToken, parser.GreaterOrEqualToken: + break + default: + fromTableName = cond.Decl[0].Lexeme + cond.Decl = cond.Decl[1:] + break + } + + p.LeftValue.lexeme = cond.Lexeme + + if err := attributeExistsInTable(e, p.LeftValue.lexeme, fromTableName); err != nil { + return nil, err + } + + // Handle IN keyword + if cond.Decl[0].Token == parser.InToken { + err := inExecutor(cond.Decl[0], p) + if err != nil { + return nil, err + } + p.LeftValue.table = fromTableName + return p, nil + } + + // Handle NOT IN keywords + if cond.Decl[0].Token == parser.NotToken && cond.Decl[0].Decl[0].Token == parser.InToken { + err := notInExecutor(cond.Decl[0].Decl[0], p) + if err != nil { + return nil, err + } + p.LeftValue.table = fromTableName + return p, nil + } + + // Handle IS NULL and IS NOT NULL + if cond.Decl[0].Token == parser.IsToken { + err := isExecutor(cond.Decl[0], p) + if err != nil { + return nil, err + } + p.LeftValue.table = fromTableName + return p, nil + } + + if len(cond.Decl) < 2 { + return nil, fmt.Errorf("Malformed predicate \"%s\"", cond.Lexeme) + } + + // The first element of the list is then the relation of the attribute + op := cond.Decl[0] + val := cond.Decl[1] + + p.Operator, err = NewOperator(op.Token, op.Lexeme) + if err != nil { + return nil, err + } + p.RightValue.lexeme = val.Lexeme + p.RightValue.valid = true + + p.LeftValue.table = fromTableName + return p, nil +} + +/* + |-> WHERE + |-> email + |-> = + |-> foo@bar.com +*/ +func whereExecutor(whereDecl *parser.Decl, fromTableName string) ([]Predicate, error) { + var predicates []Predicate + var err error + whereDecl.Stringy(0) + + for i := range whereDecl.Decl { + var p Predicate + tableName := fromTableName + cond := whereDecl.Decl[i] + + // 1 PREDICATE + if cond.Lexeme == "1" { + predicates = append(predicates, TruePredicate) + continue + } + + if len(cond.Decl) == 0 { + log.Debug("whereExecutor: HUm hum you must be AND or OR: %v", cond) + continue + } + + switch cond.Decl[0].Token { + case parser.EqualityToken, parser.DistinctnessToken, parser.LeftDipleToken, parser.RightDipleToken, parser.LessOrEqualToken, parser.GreaterOrEqualToken: + log.Debug("whereExecutor: it's = <> < > <= >=\n") + break + case parser.InToken: + log.Debug("whereExecutor: it's IN\n") + break + case parser.NotToken: + log.Debug("whereExecutor: it's NOT\n") + break + case parser.IsToken: + log.Debug("whereExecutor: it's IS token\n") + log.Debug("whereExecutor: %+v\n", cond.Decl[0]) + break + default: + log.Debug("it's the table name ! -> %s", cond.Decl[0].Lexeme) + tableName = cond.Decl[0].Lexeme + cond.Decl = cond.Decl[1:] + break + } + + p.LeftValue.lexeme = whereDecl.Decl[i].Lexeme + + // Handle IN keyword + if cond.Decl[0].Token == parser.InToken { + err := inExecutor(cond.Decl[0], &p) + if err != nil { + return nil, err + } + p.LeftValue.table = tableName + predicates = append(predicates, p) + continue + } + + // Handle NOT IN keywords + if cond.Decl[0].Token == parser.NotToken && cond.Decl[0].Decl[0].Token == parser.InToken { + err := notInExecutor(cond.Decl[0].Decl[0], &p) + if err != nil { + return nil, err + } + p.LeftValue.table = tableName + predicates = append(predicates, p) + continue + } + + // Handle IS NULL and IS NOT NULL + if cond.Decl[0].Token == parser.IsToken { + err := isExecutor(cond.Decl[0], &p) + if err != nil { + return nil, err + } + p.LeftValue.table = tableName + predicates = append(predicates, p) + continue + } + + if len(cond.Decl) < 2 { + return nil, fmt.Errorf("Malformed predicate \"%s\"", cond.Lexeme) + } + + // The first element of the list is then the relation of the attribute + op := cond.Decl[0] + val := cond.Decl[1] + + p.Operator, err = NewOperator(op.Token, op.Lexeme) + if err != nil { + return nil, err + } + p.RightValue.lexeme = val.Lexeme + p.RightValue.valid = true + + p.LeftValue.table = tableName + + predicates = append(predicates, p) + } + + if len(predicates) == 0 { + return nil, fmt.Errorf("No predicates provided") + } + + return predicates, nil +} + +/* +|-> FROM + |-> account +*/ +func fromExecutor(fromDecl *parser.Decl) []*Table { + var tables []*Table + for _, t := range fromDecl.Decl { + tables = append(tables, NewTable(t.Lexeme)) + } + + return tables +} + +func getSelectedAttribute(e *Engine, attr *parser.Decl, tables []*Table) ([]Attribute, error) { + var attributes []Attribute + var t []string + + for i := range tables { + t = append(t, tables[i].name) + } + + switch attr.Token { + case parser.StarToken: + for _, table := range tables { + r := e.relation(table.name) + if r == nil { + return nil, errors.New("Relation " + table.name + " not found") + } + attributes = append(attributes, r.table.attributes...) + } + case parser.CountToken: + err := attributesExistInTables(e, []Attribute{NewAttribute(attr.Decl[0].Lexeme, "", false)}, t) + if err != nil && attr.Decl[0].Lexeme != "*" { + return nil, err + } + attributes = append(attributes, NewAttribute("COUNT", "int", false)) + case parser.StringToken: + attribute := attr.Lexeme + if len(attr.Decl) > 0 { + if err := attributeExistsInTable(e, attr.Lexeme, attr.Decl[0].Lexeme); err != nil { + return nil, err + } + attribute = attr.Decl[0].Lexeme + "." + attribute + } + newAttr := NewAttribute(attribute, "text", false) + if err := attributesExistInTables(e, []Attribute{newAttr}, t); err != nil { + return nil, err + } + attributes = append(attributes, newAttr) + } + + return attributes, nil +} + +// Perform actual check of predicates present in virtualrow. +func selectRows(row virtualRow, predicates []PredicateLinker, functors []selectFunctor) error { + var res bool + var err error + + // If the row validate all predicates, write it + for _, predicate := range predicates { + if res, err = predicate.Eval(row); err != nil { + return err + } + if res == false { + return nil + } + } + + for i := range functors { + err := functors[i].FeedVirtualRow(row) + if err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/proullon/ramsql/engine/table.go b/vendor/github.com/proullon/ramsql/engine/table.go new file mode 100644 index 0000000..634bed1 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/table.go @@ -0,0 +1,113 @@ +package engine + +import ( + "fmt" + + "github.com/proullon/ramsql/engine/parser" + "github.com/proullon/ramsql/engine/protocol" +) + +// Table is defined by a name and attributes +// A table with data is called a Relation +type Table struct { + name string + attributes []Attribute +} + +// NewTable initializes a new Table +func NewTable(name string) *Table { + t := &Table{ + name: name, + } + + return t +} + +// AddAttribute is used by CREATE TABLE and ALTER TABLE +// Want to check that name isn't already taken +func (t *Table) AddAttribute(attr Attribute) error { + t.attributes = append(t.attributes, attr) + return nil +} + +// String returns a printable string with table name and attributes +func (t Table) String() string { + stringy := t.name + " (" + for i, a := range t.attributes { + if i != 0 { + stringy += " | " + } + stringy += a.name + " " + a.typeName + } + stringy += ")" + return stringy +} + +func createTableExecutor(e *Engine, tableDecl *parser.Decl, conn protocol.EngineConn) error { + var i int + + if len(tableDecl.Decl) == 0 { + return fmt.Errorf("parsing failed, malformed query") + } + + // Check for specific attribute + i = 0 + for i < len(tableDecl.Decl) { + + if e.opsExecutors[tableDecl.Decl[i].Token] != nil { + if err := e.opsExecutors[tableDecl.Decl[i].Token](e, tableDecl.Decl[i], conn); err != nil { + return err + } + } else { + break + } + + i++ + } + + // Check if 'IF NOT EXISTS' is present + ifNotExists := hasIfNotExists(tableDecl) + + // Check if table does not exists + r := e.relation(tableDecl.Decl[i].Lexeme) + if r != nil && !ifNotExists { + return fmt.Errorf("table %s already exists", tableDecl.Decl[i].Lexeme) + } + + // Fetch table name + t := NewTable(tableDecl.Decl[i].Lexeme) + + // Fetch attributes + i++ + for i < len(tableDecl.Decl) { + attr, err := parseAttribute(tableDecl.Decl[i]) + if err != nil { + return err + } + err = t.AddAttribute(attr) + if err != nil { + return err + } + + i++ + } + + e.relations[t.name] = NewRelation(t) + conn.WriteResult(0, 1) + return nil +} + +func hasIfNotExists(tableDecl *parser.Decl) bool { + for _, d := range tableDecl.Decl { + if d.Token == parser.IfToken { + if len(d.Decl) > 0 && d.Decl[0].Token == parser.NotToken { + not := d.Decl[0] + if len(not.Decl) > 0 && not.Decl[0].Token == parser.ExistsToken { + return true + } + } + } + } + + return false +} diff --git a/vendor/github.com/proullon/ramsql/engine/truncate.go b/vendor/github.com/proullon/ramsql/engine/truncate.go new file mode 100644 index 0000000..a5cd2e5 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/truncate.go @@ -0,0 +1,37 @@ +package engine + +import ( + "fmt" + + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/parser" + "github.com/proullon/ramsql/engine/protocol" +) + +func truncateExecutor(e *Engine, trDecl *parser.Decl, conn protocol.EngineConn) error { + log.Debug("truncateExecutor") + + // get tables to be deleted + table := NewTable(trDecl.Decl[0].Lexeme) + + return truncateTable(e, table, conn) +} + +func truncateTable(e *Engine, table *Table, conn protocol.EngineConn) error { + var rowsDeleted int64 + + // get relations and write lock them + r := e.relation(table.name) + if r == nil { + return fmt.Errorf("Table %v not found", table.name) + } + r.Lock() + defer r.Unlock() + + if r.rows != nil { + rowsDeleted = int64(len(r.rows)) + } + r.rows = make([]*Tuple, 0) + + return conn.WriteResult(0, rowsDeleted) +} diff --git a/vendor/github.com/proullon/ramsql/engine/tuple.go b/vendor/github.com/proullon/ramsql/engine/tuple.go new file mode 100644 index 0000000..4843be7 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/tuple.go @@ -0,0 +1,21 @@ +package engine + +// Tuple is a row in a relation +type Tuple struct { + Values []interface{} +} + +// NewTuple should check that value are for the right Attribute and match domain +func NewTuple(values ...interface{}) *Tuple { + t := &Tuple{} + + for _, v := range values { + t.Values = append(t.Values, v) + } + return t +} + +// Append add a value to the tuple +func (t *Tuple) Append(value interface{}) { + t.Values = append(t.Values, value) +} diff --git a/vendor/github.com/proullon/ramsql/engine/update.go b/vendor/github.com/proullon/ramsql/engine/update.go new file mode 100644 index 0000000..90a3386 --- /dev/null +++ b/vendor/github.com/proullon/ramsql/engine/update.go @@ -0,0 +1,119 @@ +package engine + +import ( + "fmt" + "strings" + "time" + + "github.com/proullon/ramsql/engine/log" + "github.com/proullon/ramsql/engine/parser" + "github.com/proullon/ramsql/engine/protocol" +) + +/* +|-> update + |-> account + |-> set + |-> email + |-> = + |-> roger@gmail.com + |-> where + |-> id + |-> = + |-> 2 +*/ +func updateExecutor(e *Engine, updateDecl *parser.Decl, conn protocol.EngineConn) error { + var num int64 + + updateDecl.Stringy(0) + + // Fetch table from name and write lock it + r := e.relation(updateDecl.Decl[0].Lexeme) + if r == nil { + return fmt.Errorf("Table %s does not exist", updateDecl.Decl[0].Lexeme) + } + r.Lock() + r.Unlock() + + // Set decl + values, err := setExecutor(updateDecl.Decl[1]) + if err != nil { + return err + } + + // Where decl + predicates, err := whereExecutor(updateDecl.Decl[2], r.table.name) + if err != nil { + return err + } + + var ok, res bool + for i := range r.rows { + ok = true + // If the row validate all predicates, write it + for _, predicate := range predicates { + if res, err = predicate.Evaluate(r.rows[i], r.table); err != nil { + return err + } + if res == false { + ok = false + continue + } + } + + if ok { + num++ + err = updateValues(r, i, values) + if err != nil { + return err + } + } + } + + return conn.WriteResult(0, num) +} + +/* + |-> set + |-> email + |-> = + |-> roger@gmail.com +*/ +func setExecutor(setDecl *parser.Decl) (map[string]interface{}, error) { + + values := make(map[string]interface{}) + + for _, attr := range setDecl.Decl { + if attr.Decl[1].Token == parser.NullToken { + values[attr.Lexeme] = nil + } else { + values[attr.Lexeme] = attr.Decl[1].Lexeme + } + } + + return values, nil +} + +func updateValues(r *Relation, row int, values map[string]interface{}) error { + for i := range r.table.attributes { + val, ok := values[r.table.attributes[i].name] + if !ok { + continue + } + log.Debug("Type of '%s' is '%s'\n", r.table.attributes[i].name, r.table.attributes[i].typeName) + switch strings.ToLower(r.table.attributes[i].typeName) { + case "timestamp", "localtimestamp": + s, ok := val.(string) + if ok && (s == "current_timestamp" || s == "now()") { + val = time.Now() + } + // format time.Time into parsable string + if t, ok := val.(time.Time); ok { + val = t.Format(parser.DateLongFormat) + } + } + r.rows[row].Values[i] = fmt.Sprintf("%v", val) + } + + return nil +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare.go b/vendor/github.com/stretchr/testify/assert/assertion_compare.go index 4d4b4aa..95d8e59 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_compare.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare.go @@ -28,8 +28,6 @@ var ( uint32Type = reflect.TypeOf(uint32(1)) uint64Type = reflect.TypeOf(uint64(1)) - uintptrType = reflect.TypeOf(uintptr(1)) - float32Type = reflect.TypeOf(float32(1)) float64Type = reflect.TypeOf(float64(1)) @@ -310,11 +308,11 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { case reflect.Struct: { // All structs enter here. We're not interested in most types. - if !obj1Value.CanConvert(timeType) { + if !canConvert(obj1Value, timeType) { break } - // time.Time can be compared! + // time.Time can compared! timeObj1, ok := obj1.(time.Time) if !ok { timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time) @@ -330,7 +328,7 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { case reflect.Slice: { // We only care about the []byte type. - if !obj1Value.CanConvert(bytesType) { + if !canConvert(obj1Value, bytesType) { break } @@ -347,26 +345,6 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { return CompareType(bytes.Compare(bytesObj1, bytesObj2)), true } - case reflect.Uintptr: - { - uintptrObj1, ok := obj1.(uintptr) - if !ok { - uintptrObj1 = obj1Value.Convert(uintptrType).Interface().(uintptr) - } - uintptrObj2, ok := obj2.(uintptr) - if !ok { - uintptrObj2 = obj2Value.Convert(uintptrType).Interface().(uintptr) - } - if uintptrObj1 > uintptrObj2 { - return compareGreater, true - } - if uintptrObj1 == uintptrObj2 { - return compareEqual, true - } - if uintptrObj1 < uintptrObj2 { - return compareLess, true - } - } } return compareEqual, false @@ -374,9 +352,9 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { // Greater asserts that the first element is greater than the second // -// assert.Greater(t, 2, 1) -// assert.Greater(t, float64(2), float64(1)) -// assert.Greater(t, "b", "a") +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -386,10 +364,10 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface // GreaterOrEqual asserts that the first element is greater than or equal to the second // -// assert.GreaterOrEqual(t, 2, 1) -// assert.GreaterOrEqual(t, 2, 2) -// assert.GreaterOrEqual(t, "b", "a") -// assert.GreaterOrEqual(t, "b", "b") +// assert.GreaterOrEqual(t, 2, 1) +// assert.GreaterOrEqual(t, 2, 2) +// assert.GreaterOrEqual(t, "b", "a") +// assert.GreaterOrEqual(t, "b", "b") func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -399,9 +377,9 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in // Less asserts that the first element is less than the second // -// assert.Less(t, 1, 2) -// assert.Less(t, float64(1), float64(2)) -// assert.Less(t, "a", "b") +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -411,10 +389,10 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) // LessOrEqual asserts that the first element is less than or equal to the second // -// assert.LessOrEqual(t, 1, 2) -// assert.LessOrEqual(t, 2, 2) -// assert.LessOrEqual(t, "a", "b") -// assert.LessOrEqual(t, "b", "b") +// assert.LessOrEqual(t, 1, 2) +// assert.LessOrEqual(t, 2, 2) +// assert.LessOrEqual(t, "a", "b") +// assert.LessOrEqual(t, "b", "b") func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -424,8 +402,8 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter // Positive asserts that the specified element is positive // -// assert.Positive(t, 1) -// assert.Positive(t, 1.23) +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -436,8 +414,8 @@ func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { // Negative asserts that the specified element is negative // -// assert.Negative(t, -1) -// assert.Negative(t, -1.23) +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go b/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go new file mode 100644 index 0000000..da86790 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go @@ -0,0 +1,16 @@ +//go:build go1.17 +// +build go1.17 + +// TODO: once support for Go 1.16 is dropped, this file can be +// merged/removed with assertion_compare_go1.17_test.go and +// assertion_compare_legacy.go + +package assert + +import "reflect" + +// Wrapper around reflect.Value.CanConvert, for compatibility +// reasons. +func canConvert(value reflect.Value, to reflect.Type) bool { + return value.CanConvert(to) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go b/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go new file mode 100644 index 0000000..1701af2 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go @@ -0,0 +1,16 @@ +//go:build !go1.17 +// +build !go1.17 + +// TODO: once support for Go 1.16 is dropped, this file can be +// merged/removed with assertion_compare_go1.17_test.go and +// assertion_compare_can_convert.go + +package assert + +import "reflect" + +// Older versions of Go does not have the reflect.Value.CanConvert +// method. +func canConvert(value reflect.Value, to reflect.Type) bool { + return false +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go index 3ddab10..7880b8f 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_format.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -1,4 +1,7 @@ -// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ package assert @@ -19,9 +22,9 @@ func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bo // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") -// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") -// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") +// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") +// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") +// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -53,7 +56,7 @@ func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string // Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// assert.Emptyf(t, obj, "error message %s", "formatted") +// assert.Emptyf(t, obj, "error message %s", "formatted") func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -63,7 +66,7 @@ func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) boo // Equalf asserts that two objects are equal. // -// assert.Equalf(t, 123, 123, "error message %s", "formatted") +// assert.Equalf(t, 123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -78,8 +81,8 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar // EqualErrorf asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -87,27 +90,10 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...) } -// EqualExportedValuesf asserts that the types of two objects are equal and their public -// fields are also equal. This is useful for comparing structs that have private fields -// that could potentially differ. -// -// type S struct { -// Exported int -// notExported int -// } -// assert.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true -// assert.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false -func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return EqualExportedValues(t, expected, actual, append([]interface{}{msg}, args...)...) -} - -// EqualValuesf asserts that two objects are equal or convertible to the same types +// EqualValuesf asserts that two objects are equal or convertable to the same types // and equal. // -// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") +// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -117,10 +103,10 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri // Errorf asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if assert.Errorf(t, err, "error message %s", "formatted") { -// assert.Equal(t, expectedErrorf, err) -// } +// actualObj, err := SomeFunction() +// if assert.Errorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } func Errorf(t TestingT, err error, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -140,8 +126,8 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -161,7 +147,7 @@ func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -169,34 +155,9 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) } -// EventuallyWithTf asserts that given condition will be met in waitFor time, -// periodically checking target function each tick. In contrast to Eventually, -// it supplies a CollectT to the condition function, so that the condition -// function can use the CollectT to call other assertions. -// The condition is considered "met" if no errors are raised in a tick. -// The supplied CollectT collects all errors from one tick (if there are any). -// If the condition is not met before waitFor, the collected errors of -// the last tick are copied to t. -// -// externalValue := false -// go func() { -// time.Sleep(8*time.Second) -// externalValue = true -// }() -// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") { -// // add assertions as needed; any assertion failure will fail the current tick -// assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") -func EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return EventuallyWithT(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) -} - // Exactlyf asserts that two objects are equal in value and type. // -// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") +// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -222,7 +183,7 @@ func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{} // Falsef asserts that the specified value is false. // -// assert.Falsef(t, myBool, "error message %s", "formatted") +// assert.Falsef(t, myBool, "error message %s", "formatted") func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -241,9 +202,9 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool // Greaterf asserts that the first element is greater than the second // -// assert.Greaterf(t, 2, 1, "error message %s", "formatted") -// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") -// assert.Greaterf(t, "b", "a", "error message %s", "formatted") +// assert.Greaterf(t, 2, 1, "error message %s", "formatted") +// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") +// assert.Greaterf(t, "b", "a", "error message %s", "formatted") func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -253,10 +214,10 @@ func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...in // GreaterOrEqualf asserts that the first element is greater than or equal to the second // -// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") -// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") -// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") -// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -267,7 +228,7 @@ func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, arg // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // -// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { @@ -280,7 +241,7 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // -// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { @@ -292,7 +253,7 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u // HTTPErrorf asserts that a specified handler returns an error status code. // -// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -304,7 +265,7 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, // HTTPRedirectf asserts that a specified handler returns a redirect status code. // -// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -316,7 +277,7 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri // HTTPStatusCodef asserts that a specified handler returns a specified status code. // -// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { @@ -328,7 +289,7 @@ func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url st // HTTPSuccessf asserts that a specified handler returns a success status code. // -// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -340,7 +301,7 @@ func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url strin // Implementsf asserts that an object is implemented by the specified interface. // -// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -350,7 +311,7 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms // InDeltaf asserts that the two numerals are within delta of each other. // -// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -392,9 +353,9 @@ func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsil // IsDecreasingf asserts that the collection is decreasing // -// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") -// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") -// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -404,9 +365,9 @@ func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface // IsIncreasingf asserts that the collection is increasing // -// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") -// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") -// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -416,9 +377,9 @@ func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface // IsNonDecreasingf asserts that the collection is not decreasing // -// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") -// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") -// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -428,9 +389,9 @@ func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interf // IsNonIncreasingf asserts that the collection is not increasing // -// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") -// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") -// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -448,7 +409,7 @@ func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg strin // JSONEqf asserts that two JSON strings are equivalent. // -// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -459,7 +420,7 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // -// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") +// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -469,9 +430,9 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf // Lessf asserts that the first element is less than the second // -// assert.Lessf(t, 1, 2, "error message %s", "formatted") -// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") -// assert.Lessf(t, "a", "b", "error message %s", "formatted") +// assert.Lessf(t, 1, 2, "error message %s", "formatted") +// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") +// assert.Lessf(t, "a", "b", "error message %s", "formatted") func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -481,10 +442,10 @@ func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...inter // LessOrEqualf asserts that the first element is less than or equal to the second // -// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") -// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") -// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") -// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -494,8 +455,8 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args . // Negativef asserts that the specified element is negative // -// assert.Negativef(t, -1, "error message %s", "formatted") -// assert.Negativef(t, -1.23, "error message %s", "formatted") +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -506,7 +467,7 @@ func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -516,7 +477,7 @@ func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time. // Nilf asserts that the specified object is nil. // -// assert.Nilf(t, err, "error message %s", "formatted") +// assert.Nilf(t, err, "error message %s", "formatted") func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -535,10 +496,10 @@ func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool // NoErrorf asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if assert.NoErrorf(t, err, "error message %s", "formatted") { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if assert.NoErrorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -558,9 +519,9 @@ func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) boo // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") -// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") -// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -571,9 +532,9 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { -// assert.Equal(t, "two", obj[1]) -// } +// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -583,7 +544,7 @@ func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) // NotEqualf asserts that the specified values are NOT equal. // -// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") +// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -596,7 +557,7 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // -// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") +// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -613,19 +574,9 @@ func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interf return NotErrorIs(t, err, target, append([]interface{}{msg}, args...)...) } -// NotImplementsf asserts that an object does not implement the specified interface. -// -// assert.NotImplementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") -func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotImplements(t, interfaceObject, object, append([]interface{}{msg}, args...)...) -} - // NotNilf asserts that the specified object is not nil. // -// assert.NotNilf(t, err, "error message %s", "formatted") +// assert.NotNilf(t, err, "error message %s", "formatted") func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -635,7 +586,7 @@ func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bo // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // -// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") +// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -645,8 +596,8 @@ func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bo // NotRegexpf asserts that a specified regexp does not match a string. // -// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") -// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") +// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -656,7 +607,7 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args .. // NotSamef asserts that two pointers do not reference the same object. // -// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") +// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -667,12 +618,10 @@ func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...) } -// NotSubsetf asserts that the specified list(array, slice...) or map does NOT -// contain all elements given in the specified subset list(array, slice...) or -// map. +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). // -// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted") -// assert.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") +// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -690,7 +639,7 @@ func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool { // Panicsf asserts that the code inside the specified PanicTestFunc panics. // -// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") +// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -702,7 +651,7 @@ func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -713,7 +662,7 @@ func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -723,8 +672,8 @@ func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg str // Positivef asserts that the specified element is positive // -// assert.Positivef(t, 1, "error message %s", "formatted") -// assert.Positivef(t, 1.23, "error message %s", "formatted") +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -734,8 +683,8 @@ func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool // Regexpf asserts that a specified regexp matches a string. // -// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") -// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") +// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -745,7 +694,7 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in // Samef asserts that two pointers reference the same object. // -// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") +// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -756,11 +705,10 @@ func Samef(t TestingT, expected interface{}, actual interface{}, msg string, arg return Same(t, expected, actual, append([]interface{}{msg}, args...)...) } -// Subsetf asserts that the specified list(array, slice...) or map contains all -// elements given in the specified subset list(array, slice...) or map. +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). // -// assert.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted") -// assert.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") +// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -770,7 +718,7 @@ func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args // Truef asserts that the specified value is true. // -// assert.Truef(t, myBool, "error message %s", "formatted") +// assert.Truef(t, myBool, "error message %s", "formatted") func Truef(t TestingT, value bool, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -780,7 +728,7 @@ func Truef(t TestingT, value bool, msg string, args ...interface{}) bool { // WithinDurationf asserts that the two times are within duration delta of each other. // -// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -790,7 +738,7 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim // WithinRangef asserts that a time is within a time range (inclusive). // -// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go index a84e09b..339515b 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -1,4 +1,7 @@ -// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ package assert @@ -27,9 +30,9 @@ func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{} // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// a.Contains("Hello World", "World") -// a.Contains(["Hello", "World"], "World") -// a.Contains({"Hello": "World"}, "Hello") +// a.Contains("Hello World", "World") +// a.Contains(["Hello", "World"], "World") +// a.Contains({"Hello": "World"}, "Hello") func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -40,9 +43,9 @@ func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs .. // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// a.Containsf("Hello World", "World", "error message %s", "formatted") -// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") -// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") +// a.Containsf("Hello World", "World", "error message %s", "formatted") +// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") +// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -95,7 +98,7 @@ func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg st // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// a.Empty(obj) +// a.Empty(obj) func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -106,7 +109,7 @@ func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool { // Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// a.Emptyf(obj, "error message %s", "formatted") +// a.Emptyf(obj, "error message %s", "formatted") func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -116,7 +119,7 @@ func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) // Equal asserts that two objects are equal. // -// a.Equal(123, 123) +// a.Equal(123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -131,8 +134,8 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs // EqualError asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// a.EqualError(err, expectedErrorString) +// actualObj, err := SomeFunction() +// a.EqualError(err, expectedErrorString) func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -143,8 +146,8 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ... // EqualErrorf asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -152,44 +155,10 @@ func (a *Assertions) EqualErrorf(theError error, errString string, msg string, a return EqualErrorf(a.t, theError, errString, msg, args...) } -// EqualExportedValues asserts that the types of two objects are equal and their public -// fields are also equal. This is useful for comparing structs that have private fields -// that could potentially differ. -// -// type S struct { -// Exported int -// notExported int -// } -// a.EqualExportedValues(S{1, 2}, S{1, 3}) => true -// a.EqualExportedValues(S{1, 2}, S{2, 3}) => false -func (a *Assertions) EqualExportedValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return EqualExportedValues(a.t, expected, actual, msgAndArgs...) -} - -// EqualExportedValuesf asserts that the types of two objects are equal and their public -// fields are also equal. This is useful for comparing structs that have private fields -// that could potentially differ. -// -// type S struct { -// Exported int -// notExported int -// } -// a.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true -// a.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false -func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return EqualExportedValuesf(a.t, expected, actual, msg, args...) -} - -// EqualValues asserts that two objects are equal or convertible to the same types +// EqualValues asserts that two objects are equal or convertable to the same types // and equal. // -// a.EqualValues(uint32(123), int32(123)) +// a.EqualValues(uint32(123), int32(123)) func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -197,10 +166,10 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn return EqualValues(a.t, expected, actual, msgAndArgs...) } -// EqualValuesf asserts that two objects are equal or convertible to the same types +// EqualValuesf asserts that two objects are equal or convertable to the same types // and equal. // -// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") +// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -210,7 +179,7 @@ func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg // Equalf asserts that two objects are equal. // -// a.Equalf(123, 123, "error message %s", "formatted") +// a.Equalf(123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -224,10 +193,10 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string // Error asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if a.Error(err) { -// assert.Equal(t, expectedError, err) -// } +// actualObj, err := SomeFunction() +// if a.Error(err) { +// assert.Equal(t, expectedError, err) +// } func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -256,8 +225,8 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args .. // ErrorContains asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// a.ErrorContains(err, expectedErrorSubString) +// actualObj, err := SomeFunction() +// a.ErrorContains(err, expectedErrorSubString) func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -268,8 +237,8 @@ func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs . // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -297,10 +266,10 @@ func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...inter // Errorf asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if a.Errorf(err, "error message %s", "formatted") { -// assert.Equal(t, expectedErrorf, err) -// } +// actualObj, err := SomeFunction() +// if a.Errorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -311,7 +280,7 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool { // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) +// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -319,60 +288,10 @@ func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, ti return Eventually(a.t, condition, waitFor, tick, msgAndArgs...) } -// EventuallyWithT asserts that given condition will be met in waitFor time, -// periodically checking target function each tick. In contrast to Eventually, -// it supplies a CollectT to the condition function, so that the condition -// function can use the CollectT to call other assertions. -// The condition is considered "met" if no errors are raised in a tick. -// The supplied CollectT collects all errors from one tick (if there are any). -// If the condition is not met before waitFor, the collected errors of -// the last tick are copied to t. -// -// externalValue := false -// go func() { -// time.Sleep(8*time.Second) -// externalValue = true -// }() -// a.EventuallyWithT(func(c *assert.CollectT) { -// // add assertions as needed; any assertion failure will fail the current tick -// assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") -func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...) -} - -// EventuallyWithTf asserts that given condition will be met in waitFor time, -// periodically checking target function each tick. In contrast to Eventually, -// it supplies a CollectT to the condition function, so that the condition -// function can use the CollectT to call other assertions. -// The condition is considered "met" if no errors are raised in a tick. -// The supplied CollectT collects all errors from one tick (if there are any). -// If the condition is not met before waitFor, the collected errors of -// the last tick are copied to t. -// -// externalValue := false -// go func() { -// time.Sleep(8*time.Second) -// externalValue = true -// }() -// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { -// // add assertions as needed; any assertion failure will fail the current tick -// assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") -func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...) -} - // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -382,7 +301,7 @@ func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, t // Exactly asserts that two objects are equal in value and type. // -// a.Exactly(int32(123), int64(123)) +// a.Exactly(int32(123), int64(123)) func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -392,7 +311,7 @@ func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArg // Exactlyf asserts that two objects are equal in value and type. // -// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") +// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -434,7 +353,7 @@ func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{ // False asserts that the specified value is false. // -// a.False(myBool) +// a.False(myBool) func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -444,7 +363,7 @@ func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool { // Falsef asserts that the specified value is false. // -// a.Falsef(myBool, "error message %s", "formatted") +// a.Falsef(myBool, "error message %s", "formatted") func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -472,9 +391,9 @@ func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) b // Greater asserts that the first element is greater than the second // -// a.Greater(2, 1) -// a.Greater(float64(2), float64(1)) -// a.Greater("b", "a") +// a.Greater(2, 1) +// a.Greater(float64(2), float64(1)) +// a.Greater("b", "a") func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -484,10 +403,10 @@ func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...inter // GreaterOrEqual asserts that the first element is greater than or equal to the second // -// a.GreaterOrEqual(2, 1) -// a.GreaterOrEqual(2, 2) -// a.GreaterOrEqual("b", "a") -// a.GreaterOrEqual("b", "b") +// a.GreaterOrEqual(2, 1) +// a.GreaterOrEqual(2, 2) +// a.GreaterOrEqual("b", "a") +// a.GreaterOrEqual("b", "b") func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -497,10 +416,10 @@ func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs . // GreaterOrEqualf asserts that the first element is greater than or equal to the second // -// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") -// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") -// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") -// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") +// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") +// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") +// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") +// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -510,9 +429,9 @@ func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, // Greaterf asserts that the first element is greater than the second // -// a.Greaterf(2, 1, "error message %s", "formatted") -// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") -// a.Greaterf("b", "a", "error message %s", "formatted") +// a.Greaterf(2, 1, "error message %s", "formatted") +// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") +// a.Greaterf("b", "a", "error message %s", "formatted") func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -523,7 +442,7 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args . // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // -// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { @@ -536,7 +455,7 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // -// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { @@ -549,7 +468,7 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // -// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { @@ -562,7 +481,7 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // -// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { @@ -574,7 +493,7 @@ func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method strin // HTTPError asserts that a specified handler returns an error status code. // -// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -586,7 +505,7 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri // HTTPErrorf asserts that a specified handler returns an error status code. // -// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -598,7 +517,7 @@ func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url str // HTTPRedirect asserts that a specified handler returns a redirect status code. // -// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -610,7 +529,7 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s // HTTPRedirectf asserts that a specified handler returns a redirect status code. // -// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -622,7 +541,7 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url // HTTPStatusCode asserts that a specified handler returns a specified status code. // -// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { @@ -634,7 +553,7 @@ func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url // HTTPStatusCodef asserts that a specified handler returns a specified status code. // -// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { @@ -646,7 +565,7 @@ func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, ur // HTTPSuccess asserts that a specified handler returns a success status code. // -// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) +// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -658,7 +577,7 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url st // HTTPSuccessf asserts that a specified handler returns a success status code. // -// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -670,7 +589,7 @@ func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url s // Implements asserts that an object is implemented by the specified interface. // -// a.Implements((*MyInterface)(nil), new(MyObject)) +// a.Implements((*MyInterface)(nil), new(MyObject)) func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -680,7 +599,7 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, // Implementsf asserts that an object is implemented by the specified interface. // -// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -690,7 +609,7 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{} // InDelta asserts that the two numerals are within delta of each other. // -// a.InDelta(math.Pi, 22/7.0, 0.01) +// a.InDelta(math.Pi, 22/7.0, 0.01) func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -732,7 +651,7 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del // InDeltaf asserts that the two numerals are within delta of each other. // -// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -774,9 +693,9 @@ func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilo // IsDecreasing asserts that the collection is decreasing // -// a.IsDecreasing([]int{2, 1, 0}) -// a.IsDecreasing([]float{2, 1}) -// a.IsDecreasing([]string{"b", "a"}) +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -786,9 +705,9 @@ func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) // IsDecreasingf asserts that the collection is decreasing // -// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") -// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") -// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -798,9 +717,9 @@ func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...inter // IsIncreasing asserts that the collection is increasing // -// a.IsIncreasing([]int{1, 2, 3}) -// a.IsIncreasing([]float{1, 2}) -// a.IsIncreasing([]string{"a", "b"}) +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -810,9 +729,9 @@ func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) // IsIncreasingf asserts that the collection is increasing // -// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") -// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") -// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -822,9 +741,9 @@ func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...inter // IsNonDecreasing asserts that the collection is not decreasing // -// a.IsNonDecreasing([]int{1, 1, 2}) -// a.IsNonDecreasing([]float{1, 2}) -// a.IsNonDecreasing([]string{"a", "b"}) +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -834,9 +753,9 @@ func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface // IsNonDecreasingf asserts that the collection is not decreasing // -// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") -// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") -// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -846,9 +765,9 @@ func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...in // IsNonIncreasing asserts that the collection is not increasing // -// a.IsNonIncreasing([]int{2, 1, 1}) -// a.IsNonIncreasing([]float{2, 1}) -// a.IsNonIncreasing([]string{"b", "a"}) +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -858,9 +777,9 @@ func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface // IsNonIncreasingf asserts that the collection is not increasing // -// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") -// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") -// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -886,7 +805,7 @@ func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg s // JSONEq asserts that two JSON strings are equivalent. // -// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -896,7 +815,7 @@ func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interf // JSONEqf asserts that two JSON strings are equivalent. // -// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -907,7 +826,7 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args .. // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // -// a.Len(mySlice, 3) +// a.Len(mySlice, 3) func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -918,7 +837,7 @@ func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // -// a.Lenf(mySlice, 3, "error message %s", "formatted") +// a.Lenf(mySlice, 3, "error message %s", "formatted") func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -928,9 +847,9 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in // Less asserts that the first element is less than the second // -// a.Less(1, 2) -// a.Less(float64(1), float64(2)) -// a.Less("a", "b") +// a.Less(1, 2) +// a.Less(float64(1), float64(2)) +// a.Less("a", "b") func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -940,10 +859,10 @@ func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interfac // LessOrEqual asserts that the first element is less than or equal to the second // -// a.LessOrEqual(1, 2) -// a.LessOrEqual(2, 2) -// a.LessOrEqual("a", "b") -// a.LessOrEqual("b", "b") +// a.LessOrEqual(1, 2) +// a.LessOrEqual(2, 2) +// a.LessOrEqual("a", "b") +// a.LessOrEqual("b", "b") func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -953,10 +872,10 @@ func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...i // LessOrEqualf asserts that the first element is less than or equal to the second // -// a.LessOrEqualf(1, 2, "error message %s", "formatted") -// a.LessOrEqualf(2, 2, "error message %s", "formatted") -// a.LessOrEqualf("a", "b", "error message %s", "formatted") -// a.LessOrEqualf("b", "b", "error message %s", "formatted") +// a.LessOrEqualf(1, 2, "error message %s", "formatted") +// a.LessOrEqualf(2, 2, "error message %s", "formatted") +// a.LessOrEqualf("a", "b", "error message %s", "formatted") +// a.LessOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -966,9 +885,9 @@ func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, ar // Lessf asserts that the first element is less than the second // -// a.Lessf(1, 2, "error message %s", "formatted") -// a.Lessf(float64(1), float64(2), "error message %s", "formatted") -// a.Lessf("a", "b", "error message %s", "formatted") +// a.Lessf(1, 2, "error message %s", "formatted") +// a.Lessf(float64(1), float64(2), "error message %s", "formatted") +// a.Lessf("a", "b", "error message %s", "formatted") func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -978,8 +897,8 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i // Negative asserts that the specified element is negative // -// a.Negative(-1) -// a.Negative(-1.23) +// a.Negative(-1) +// a.Negative(-1.23) func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -989,8 +908,8 @@ func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) bool { // Negativef asserts that the specified element is negative // -// a.Negativef(-1, "error message %s", "formatted") -// a.Negativef(-1.23, "error message %s", "formatted") +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1001,7 +920,7 @@ func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) b // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1012,7 +931,7 @@ func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick ti // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1022,7 +941,7 @@ func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick t // Nil asserts that the specified object is nil. // -// a.Nil(err) +// a.Nil(err) func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1032,7 +951,7 @@ func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool { // Nilf asserts that the specified object is nil. // -// a.Nilf(err, "error message %s", "formatted") +// a.Nilf(err, "error message %s", "formatted") func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1060,10 +979,10 @@ func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) // NoError asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if a.NoError(err) { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if a.NoError(err) { +// assert.Equal(t, expectedObj, actualObj) +// } func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1073,10 +992,10 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { // NoErrorf asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if a.NoErrorf(err, "error message %s", "formatted") { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if a.NoErrorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1105,9 +1024,9 @@ func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// a.NotContains("Hello World", "Earth") -// a.NotContains(["Hello", "World"], "Earth") -// a.NotContains({"Hello": "World"}, "Earth") +// a.NotContains("Hello World", "Earth") +// a.NotContains(["Hello", "World"], "Earth") +// a.NotContains({"Hello": "World"}, "Earth") func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1118,9 +1037,9 @@ func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") -// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") -// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") +// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") +// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") +// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1131,9 +1050,9 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if a.NotEmpty(obj) { -// assert.Equal(t, "two", obj[1]) -// } +// if a.NotEmpty(obj) { +// assert.Equal(t, "two", obj[1]) +// } func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1144,9 +1063,9 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) boo // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if a.NotEmptyf(obj, "error message %s", "formatted") { -// assert.Equal(t, "two", obj[1]) -// } +// if a.NotEmptyf(obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1156,7 +1075,7 @@ func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface // NotEqual asserts that the specified values are NOT equal. // -// a.NotEqual(obj1, obj2) +// a.NotEqual(obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1169,7 +1088,7 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr // NotEqualValues asserts that two objects are not equal even when converted to the same type // -// a.NotEqualValues(obj1, obj2) +// a.NotEqualValues(obj1, obj2) func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1179,7 +1098,7 @@ func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, ms // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // -// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") +// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1189,7 +1108,7 @@ func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, m // NotEqualf asserts that the specified values are NOT equal. // -// a.NotEqualf(obj1, obj2, "error message %s", "formatted") +// a.NotEqualf(obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1218,29 +1137,9 @@ func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...in return NotErrorIsf(a.t, err, target, msg, args...) } -// NotImplements asserts that an object does not implement the specified interface. -// -// a.NotImplements((*MyInterface)(nil), new(MyObject)) -func (a *Assertions) NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return NotImplements(a.t, interfaceObject, object, msgAndArgs...) -} - -// NotImplementsf asserts that an object does not implement the specified interface. -// -// a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") -func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return NotImplementsf(a.t, interfaceObject, object, msg, args...) -} - // NotNil asserts that the specified object is not nil. // -// a.NotNil(err) +// a.NotNil(err) func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1250,7 +1149,7 @@ func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool // NotNilf asserts that the specified object is not nil. // -// a.NotNilf(err, "error message %s", "formatted") +// a.NotNilf(err, "error message %s", "formatted") func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1260,7 +1159,7 @@ func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{} // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // -// a.NotPanics(func(){ RemainCalm() }) +// a.NotPanics(func(){ RemainCalm() }) func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1270,7 +1169,7 @@ func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // -// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") +// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1280,8 +1179,8 @@ func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{} // NotRegexp asserts that a specified regexp does not match a string. // -// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") -// a.NotRegexp("^start", "it's not starting") +// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") +// a.NotRegexp("^start", "it's not starting") func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1291,8 +1190,8 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in // NotRegexpf asserts that a specified regexp does not match a string. // -// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") -// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") +// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1302,7 +1201,7 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg // NotSame asserts that two pointers do not reference the same object. // -// a.NotSame(ptr1, ptr2) +// a.NotSame(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1315,7 +1214,7 @@ func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArg // NotSamef asserts that two pointers do not reference the same object. // -// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1326,12 +1225,10 @@ func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg stri return NotSamef(a.t, expected, actual, msg, args...) } -// NotSubset asserts that the specified list(array, slice...) or map does NOT -// contain all elements given in the specified subset list(array, slice...) or -// map. +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). // -// a.NotSubset([1, 3, 4], [1, 2]) -// a.NotSubset({"x": 1, "y": 2}, {"z": 3}) +// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1339,12 +1236,10 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs return NotSubset(a.t, list, subset, msgAndArgs...) } -// NotSubsetf asserts that the specified list(array, slice...) or map does NOT -// contain all elements given in the specified subset list(array, slice...) or -// map. +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). // -// a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted") -// a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") +// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1370,7 +1265,7 @@ func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bo // Panics asserts that the code inside the specified PanicTestFunc panics. // -// a.Panics(func(){ GoCrazy() }) +// a.Panics(func(){ GoCrazy() }) func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1382,7 +1277,7 @@ func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// a.PanicsWithError("crazy error", func(){ GoCrazy() }) +// a.PanicsWithError("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1394,7 +1289,7 @@ func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndAr // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1405,7 +1300,7 @@ func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg str // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) +// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1416,7 +1311,7 @@ func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgA // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1426,7 +1321,7 @@ func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg // Panicsf asserts that the code inside the specified PanicTestFunc panics. // -// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") +// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1436,8 +1331,8 @@ func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) b // Positive asserts that the specified element is positive // -// a.Positive(1) -// a.Positive(1.23) +// a.Positive(1) +// a.Positive(1.23) func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1447,8 +1342,8 @@ func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) bool { // Positivef asserts that the specified element is positive // -// a.Positivef(1, "error message %s", "formatted") -// a.Positivef(1.23, "error message %s", "formatted") +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1458,8 +1353,8 @@ func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) b // Regexp asserts that a specified regexp matches a string. // -// a.Regexp(regexp.MustCompile("start"), "it's starting") -// a.Regexp("start...$", "it's not starting") +// a.Regexp(regexp.MustCompile("start"), "it's starting") +// a.Regexp("start...$", "it's not starting") func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1469,8 +1364,8 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter // Regexpf asserts that a specified regexp matches a string. // -// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") -// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") +// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1480,7 +1375,7 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args . // Same asserts that two pointers reference the same object. // -// a.Same(ptr1, ptr2) +// a.Same(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1493,7 +1388,7 @@ func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs . // Samef asserts that two pointers reference the same object. // -// a.Samef(ptr1, ptr2, "error message %s", "formatted") +// a.Samef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1504,11 +1399,10 @@ func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, return Samef(a.t, expected, actual, msg, args...) } -// Subset asserts that the specified list(array, slice...) or map contains all -// elements given in the specified subset list(array, slice...) or map. +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). // -// a.Subset([1, 2, 3], [1, 2]) -// a.Subset({"x": 1, "y": 2}, {"x": 1}) +// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1516,11 +1410,10 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ... return Subset(a.t, list, subset, msgAndArgs...) } -// Subsetf asserts that the specified list(array, slice...) or map contains all -// elements given in the specified subset list(array, slice...) or map. +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). // -// a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted") -// a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") +// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1530,7 +1423,7 @@ func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, a // True asserts that the specified value is true. // -// a.True(myBool) +// a.True(myBool) func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1540,7 +1433,7 @@ func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool { // Truef asserts that the specified value is true. // -// a.Truef(myBool, "error message %s", "formatted") +// a.Truef(myBool, "error message %s", "formatted") func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1550,7 +1443,7 @@ func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool { // WithinDuration asserts that the two times are within duration delta of each other. // -// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) +// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1560,7 +1453,7 @@ func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta // WithinDurationf asserts that the two times are within duration delta of each other. // -// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1570,7 +1463,7 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta // WithinRange asserts that a time is within a time range (inclusive). // -// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1580,7 +1473,7 @@ func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Tim // WithinRangef asserts that a time is within a time range (inclusive). // -// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go index 00df62a..7594487 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_order.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go @@ -46,36 +46,36 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT // IsIncreasing asserts that the collection is increasing // -// assert.IsIncreasing(t, []int{1, 2, 3}) -// assert.IsIncreasing(t, []float{1, 2}) -// assert.IsIncreasing(t, []string{"a", "b"}) +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) } // IsNonIncreasing asserts that the collection is not increasing // -// assert.IsNonIncreasing(t, []int{2, 1, 1}) -// assert.IsNonIncreasing(t, []float{2, 1}) -// assert.IsNonIncreasing(t, []string{"b", "a"}) +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) } // IsDecreasing asserts that the collection is decreasing // -// assert.IsDecreasing(t, []int{2, 1, 0}) -// assert.IsDecreasing(t, []float{2, 1}) -// assert.IsDecreasing(t, []string{"b", "a"}) +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) } // IsNonDecreasing asserts that the collection is not decreasing // -// assert.IsNonDecreasing(t, []int{1, 1, 2}) -// assert.IsNonDecreasing(t, []float{1, 2}) -// assert.IsNonDecreasing(t, []string{"a", "b"}) +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) } diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go index 0b7570f..2924cf3 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -19,7 +19,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/pmezard/go-difflib/difflib" - "gopkg.in/yaml.v3" + yaml "gopkg.in/yaml.v3" ) //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" @@ -75,84 +75,6 @@ func ObjectsAreEqual(expected, actual interface{}) bool { return bytes.Equal(exp, act) } -// copyExportedFields iterates downward through nested data structures and creates a copy -// that only contains the exported struct fields. -func copyExportedFields(expected interface{}) interface{} { - if isNil(expected) { - return expected - } - - expectedType := reflect.TypeOf(expected) - expectedKind := expectedType.Kind() - expectedValue := reflect.ValueOf(expected) - - switch expectedKind { - case reflect.Struct: - result := reflect.New(expectedType).Elem() - for i := 0; i < expectedType.NumField(); i++ { - field := expectedType.Field(i) - isExported := field.IsExported() - if isExported { - fieldValue := expectedValue.Field(i) - if isNil(fieldValue) || isNil(fieldValue.Interface()) { - continue - } - newValue := copyExportedFields(fieldValue.Interface()) - result.Field(i).Set(reflect.ValueOf(newValue)) - } - } - return result.Interface() - - case reflect.Ptr: - result := reflect.New(expectedType.Elem()) - unexportedRemoved := copyExportedFields(expectedValue.Elem().Interface()) - result.Elem().Set(reflect.ValueOf(unexportedRemoved)) - return result.Interface() - - case reflect.Array, reflect.Slice: - var result reflect.Value - if expectedKind == reflect.Array { - result = reflect.New(reflect.ArrayOf(expectedValue.Len(), expectedType.Elem())).Elem() - } else { - result = reflect.MakeSlice(expectedType, expectedValue.Len(), expectedValue.Len()) - } - for i := 0; i < expectedValue.Len(); i++ { - index := expectedValue.Index(i) - if isNil(index) { - continue - } - unexportedRemoved := copyExportedFields(index.Interface()) - result.Index(i).Set(reflect.ValueOf(unexportedRemoved)) - } - return result.Interface() - - case reflect.Map: - result := reflect.MakeMap(expectedType) - for _, k := range expectedValue.MapKeys() { - index := expectedValue.MapIndex(k) - unexportedRemoved := copyExportedFields(index.Interface()) - result.SetMapIndex(k, reflect.ValueOf(unexportedRemoved)) - } - return result.Interface() - - default: - return expected - } -} - -// ObjectsExportedFieldsAreEqual determines if the exported (public) fields of two objects are -// considered equal. This comparison of only exported fields is applied recursively to nested data -// structures. -// -// This function does no assertion of any kind. -// -// Deprecated: Use [EqualExportedValues] instead. -func ObjectsExportedFieldsAreEqual(expected, actual interface{}) bool { - expectedCleaned := copyExportedFields(expected) - actualCleaned := copyExportedFields(actual) - return ObjectsAreEqualValues(expectedCleaned, actualCleaned) -} - // ObjectsAreEqualValues gets whether two objects are equal, or if their // values are equal. func ObjectsAreEqualValues(expected, actual interface{}) bool { @@ -160,40 +82,17 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool { return true } - expectedValue := reflect.ValueOf(expected) - actualValue := reflect.ValueOf(actual) - if !expectedValue.IsValid() || !actualValue.IsValid() { - return false - } - - expectedType := expectedValue.Type() - actualType := actualValue.Type() - if !expectedType.ConvertibleTo(actualType) { + actualType := reflect.TypeOf(actual) + if actualType == nil { return false } - - if !isNumericType(expectedType) || !isNumericType(actualType) { + expectedValue := reflect.ValueOf(expected) + if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { // Attempt comparison after type conversion - return reflect.DeepEqual( - expectedValue.Convert(actualType).Interface(), actual, - ) + return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) } - // If BOTH values are numeric, there are chances of false positives due - // to overflow or underflow. So, we need to make sure to always convert - // the smaller type to a larger type before comparing. - if expectedType.Size() >= actualType.Size() { - return actualValue.Convert(expectedType).Interface() == expected - } - - return expectedValue.Convert(actualType).Interface() == actual -} - -// isNumericType returns true if the type is one of: -// int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, -// float32, float64, complex64, complex128 -func isNumericType(t reflect.Type) bool { - return t.Kind() >= reflect.Int && t.Kind() <= reflect.Complex128 + return false } /* CallerInfo is necessary because the assert functions use the testing object @@ -296,7 +195,7 @@ func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { // Aligns the provided message so that all lines after the first line start at the same location as the first line. // Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab). -// The longestLabelLen parameter specifies the length of the longest label in the output (required because this is the +// The longestLabelLen parameter specifies the length of the longest label in the output (required becaues this is the // basis on which the alignment occurs). func indentMessageLines(message string, longestLabelLen int) string { outBuf := new(bytes.Buffer) @@ -372,7 +271,7 @@ type labeledContent struct { // labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner: // -// \t{{label}}:{{align_spaces}}\t{{content}}\n +// \t{{label}}:{{align_spaces}}\t{{content}}\n // // The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label. // If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this @@ -395,7 +294,7 @@ func labeledOutput(content ...labeledContent) string { // Implements asserts that an object is implemented by the specified interface. // -// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -412,25 +311,6 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg return true } -// NotImplements asserts that an object does not implement the specified interface. -// -// assert.NotImplements(t, (*MyInterface)(nil), new(MyObject)) -func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - interfaceType := reflect.TypeOf(interfaceObject).Elem() - - if object == nil { - return Fail(t, fmt.Sprintf("Cannot check if nil does not implement %v", interfaceType), msgAndArgs...) - } - if reflect.TypeOf(object).Implements(interfaceType) { - return Fail(t, fmt.Sprintf("%T implements %v", object, interfaceType), msgAndArgs...) - } - - return true -} - // IsType asserts that the specified objects are of the same type. func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { @@ -446,7 +326,7 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs // Equal asserts that two objects are equal. // -// assert.Equal(t, 123, 123) +// assert.Equal(t, 123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -487,7 +367,7 @@ func validateEqualArgs(expected, actual interface{}) error { // Same asserts that two pointers reference the same object. // -// assert.Same(t, ptr1, ptr2) +// assert.Same(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -507,7 +387,7 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b // NotSame asserts that two pointers do not reference the same object. // -// assert.NotSame(t, ptr1, ptr2) +// assert.NotSame(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -545,7 +425,7 @@ func samePointers(first, second interface{}) bool { // representations appropriate to be presented to the user. // // If the values are not of like type, the returned strings will be prefixed -// with the type name, and the value will be enclosed in parentheses similar +// with the type name, and the value will be enclosed in parenthesis similar // to a type conversion in the Go grammar. func formatUnequalValues(expected, actual interface{}) (e string, a string) { if reflect.TypeOf(expected) != reflect.TypeOf(actual) { @@ -572,10 +452,10 @@ func truncatingFormat(data interface{}) string { return value } -// EqualValues asserts that two objects are equal or convertible to the same types +// EqualValues asserts that two objects are equal or convertable to the same types // and equal. // -// assert.EqualValues(t, uint32(123), int32(123)) +// assert.EqualValues(t, uint32(123), int32(123)) func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -593,60 +473,9 @@ func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interfa } -// EqualExportedValues asserts that the types of two objects are equal and their public -// fields are also equal. This is useful for comparing structs that have private fields -// that could potentially differ. -// -// type S struct { -// Exported int -// notExported int -// } -// assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true -// assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false -func EqualExportedValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - - aType := reflect.TypeOf(expected) - bType := reflect.TypeOf(actual) - - if aType != bType { - return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...) - } - - if aType.Kind() == reflect.Ptr { - aType = aType.Elem() - } - if bType.Kind() == reflect.Ptr { - bType = bType.Elem() - } - - if aType.Kind() != reflect.Struct { - return Fail(t, fmt.Sprintf("Types expected to both be struct or pointer to struct \n\t%v != %v", aType.Kind(), reflect.Struct), msgAndArgs...) - } - - if bType.Kind() != reflect.Struct { - return Fail(t, fmt.Sprintf("Types expected to both be struct or pointer to struct \n\t%v != %v", bType.Kind(), reflect.Struct), msgAndArgs...) - } - - expected = copyExportedFields(expected) - actual = copyExportedFields(actual) - - if !ObjectsAreEqualValues(expected, actual) { - diff := diff(expected, actual) - expected, actual = formatUnequalValues(expected, actual) - return Fail(t, fmt.Sprintf("Not equal (comparing only exported fields): \n"+ - "expected: %s\n"+ - "actual : %s%s", expected, actual, diff), msgAndArgs...) - } - - return true -} - // Exactly asserts that two objects are equal in value and type. // -// assert.Exactly(t, int32(123), int64(123)) +// assert.Exactly(t, int32(123), int64(123)) func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -665,7 +494,7 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{} // NotNil asserts that the specified object is not nil. // -// assert.NotNil(t, err) +// assert.NotNil(t, err) func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if !isNil(object) { return true @@ -676,6 +505,17 @@ func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { return Fail(t, "Expected value not to be nil.", msgAndArgs...) } +// containsKind checks if a specified kind in the slice of kinds. +func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool { + for i := 0; i < len(kinds); i++ { + if kind == kinds[i] { + return true + } + } + + return false +} + // isNil checks if a specified object is nil or not, without Failing. func isNil(object interface{}) bool { if object == nil { @@ -683,13 +523,16 @@ func isNil(object interface{}) bool { } value := reflect.ValueOf(object) - switch value.Kind() { - case - reflect.Chan, reflect.Func, - reflect.Interface, reflect.Map, - reflect.Ptr, reflect.Slice, reflect.UnsafePointer: - - return value.IsNil() + kind := value.Kind() + isNilableKind := containsKind( + []reflect.Kind{ + reflect.Chan, reflect.Func, + reflect.Interface, reflect.Map, + reflect.Ptr, reflect.Slice, reflect.UnsafePointer}, + kind) + + if isNilableKind && value.IsNil() { + return true } return false @@ -697,7 +540,7 @@ func isNil(object interface{}) bool { // Nil asserts that the specified object is nil. // -// assert.Nil(t, err) +// assert.Nil(t, err) func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if isNil(object) { return true @@ -740,7 +583,7 @@ func isEmpty(object interface{}) bool { // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// assert.Empty(t, obj) +// assert.Empty(t, obj) func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { pass := isEmpty(object) if !pass { @@ -757,9 +600,9 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if assert.NotEmpty(t, obj) { -// assert.Equal(t, "two", obj[1]) -// } +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { pass := !isEmpty(object) if !pass { @@ -773,38 +616,40 @@ func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { } -// getLen tries to get the length of an object. -// It returns (0, false) if impossible. -func getLen(x interface{}) (length int, ok bool) { +// getLen try to get length of object. +// return (false, 0) if impossible. +func getLen(x interface{}) (ok bool, length int) { v := reflect.ValueOf(x) defer func() { - ok = recover() == nil + if e := recover(); e != nil { + ok = false + } }() - return v.Len(), true + return true, v.Len() } // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // -// assert.Len(t, mySlice, 3) +// assert.Len(t, mySlice, 3) func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } - l, ok := getLen(object) + ok, l := getLen(object) if !ok { - return Fail(t, fmt.Sprintf("\"%v\" could not be applied builtin len()", object), msgAndArgs...) + return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...) } if l != length { - return Fail(t, fmt.Sprintf("\"%v\" should have %d item(s), but has %d", object, length, l), msgAndArgs...) + return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...) } return true } // True asserts that the specified value is true. // -// assert.True(t, myBool) +// assert.True(t, myBool) func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { if !value { if h, ok := t.(tHelper); ok { @@ -819,7 +664,7 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { // False asserts that the specified value is false. // -// assert.False(t, myBool) +// assert.False(t, myBool) func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { if value { if h, ok := t.(tHelper); ok { @@ -834,7 +679,7 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { // NotEqual asserts that the specified values are NOT equal. // -// assert.NotEqual(t, obj1, obj2) +// assert.NotEqual(t, obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -857,7 +702,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{ // NotEqualValues asserts that two objects are not equal even when converted to the same type // -// assert.NotEqualValues(t, obj1, obj2) +// assert.NotEqualValues(t, obj1, obj2) func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -916,9 +761,9 @@ func containsElement(list interface{}, element interface{}) (ok, found bool) { // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// assert.Contains(t, "Hello World", "World") -// assert.Contains(t, ["Hello", "World"], "World") -// assert.Contains(t, {"Hello": "World"}, "Hello") +// assert.Contains(t, "Hello World", "World") +// assert.Contains(t, ["Hello", "World"], "World") +// assert.Contains(t, {"Hello": "World"}, "Hello") func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -939,9 +784,9 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// assert.NotContains(t, "Hello World", "Earth") -// assert.NotContains(t, ["Hello", "World"], "Earth") -// assert.NotContains(t, {"Hello": "World"}, "Earth") +// assert.NotContains(t, "Hello World", "Earth") +// assert.NotContains(t, ["Hello", "World"], "Earth") +// assert.NotContains(t, {"Hello": "World"}, "Earth") func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -949,21 +794,20 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) ok, found := containsElement(s, contains) if !ok { - return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) + return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) } if found { - return Fail(t, fmt.Sprintf("%#v should not contain %#v", s, contains), msgAndArgs...) + return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...) } return true } -// Subset asserts that the specified list(array, slice...) or map contains all -// elements given in the specified subset list(array, slice...) or map. +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). // -// assert.Subset(t, [1, 2, 3], [1, 2]) -// assert.Subset(t, {"x": 1, "y": 2}, {"x": 1}) +// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1016,12 +860,10 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok return true } -// NotSubset asserts that the specified list(array, slice...) or map does NOT -// contain all elements given in the specified subset list(array, slice...) or -// map. +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). // -// assert.NotSubset(t, [1, 3, 4], [1, 2]) -// assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3}) +// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1206,7 +1048,7 @@ func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string // Panics asserts that the code inside the specified PanicTestFunc panics. // -// assert.Panics(t, func(){ GoCrazy() }) +// assert.Panics(t, func(){ GoCrazy() }) func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1222,7 +1064,7 @@ func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) +// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1243,7 +1085,7 @@ func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndAr // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1263,7 +1105,7 @@ func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs . // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // -// assert.NotPanics(t, func(){ RemainCalm() }) +// assert.NotPanics(t, func(){ RemainCalm() }) func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1278,7 +1120,7 @@ func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { // WithinDuration asserts that the two times are within duration delta of each other. // -// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) +// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1294,7 +1136,7 @@ func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, // WithinRange asserts that a time is within a time range (inclusive). // -// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func WithinRange(t TestingT, actual, start, end time.Time, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1353,7 +1195,7 @@ func toFloat(x interface{}) (float64, bool) { // InDelta asserts that the two numerals are within delta of each other. // -// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1482,7 +1324,7 @@ func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAnd h.Helper() } if math.IsNaN(epsilon) { - return Fail(t, "epsilon must not be NaN", msgAndArgs...) + return Fail(t, "epsilon must not be NaN") } actualEpsilon, err := calcRelativeError(expected, actual) if err != nil { @@ -1501,26 +1343,19 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m if h, ok := t.(tHelper); ok { h.Helper() } - - if expected == nil || actual == nil { + if expected == nil || actual == nil || + reflect.TypeOf(actual).Kind() != reflect.Slice || + reflect.TypeOf(expected).Kind() != reflect.Slice { return Fail(t, "Parameters must be slice", msgAndArgs...) } - expectedSlice := reflect.ValueOf(expected) actualSlice := reflect.ValueOf(actual) + expectedSlice := reflect.ValueOf(expected) - if expectedSlice.Type().Kind() != reflect.Slice { - return Fail(t, "Expected value must be slice", msgAndArgs...) - } - - expectedLen := expectedSlice.Len() - if !IsType(t, expected, actual) || !Len(t, actual, expectedLen) { - return false - } - - for i := 0; i < expectedLen; i++ { - if !InEpsilon(t, expectedSlice.Index(i).Interface(), actualSlice.Index(i).Interface(), epsilon, "at index %d", i) { - return false + for i := 0; i < actualSlice.Len(); i++ { + result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon) + if !result { + return result } } @@ -1533,10 +1368,10 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m // NoError asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if assert.NoError(t, err) { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { if err != nil { if h, ok := t.(tHelper); ok { @@ -1550,10 +1385,10 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { // Error asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if assert.Error(t, err) { -// assert.Equal(t, expectedError, err) -// } +// actualObj, err := SomeFunction() +// if assert.Error(t, err) { +// assert.Equal(t, expectedError, err) +// } func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { if err == nil { if h, ok := t.(tHelper); ok { @@ -1568,8 +1403,8 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { // EqualError asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// assert.EqualError(t, err, expectedErrorString) +// actualObj, err := SomeFunction() +// assert.EqualError(t, err, expectedErrorString) func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1591,8 +1426,8 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte // ErrorContains asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// assert.ErrorContains(t, err, expectedErrorSubString) +// actualObj, err := SomeFunction() +// assert.ErrorContains(t, err, expectedErrorSubString) func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1625,8 +1460,8 @@ func matchRegexp(rx interface{}, str interface{}) bool { // Regexp asserts that a specified regexp matches a string. // -// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") -// assert.Regexp(t, "start...$", "it's not starting") +// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") +// assert.Regexp(t, "start...$", "it's not starting") func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1643,8 +1478,8 @@ func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface // NotRegexp asserts that a specified regexp does not match a string. // -// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") -// assert.NotRegexp(t, "^start", "it's not starting") +// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// assert.NotRegexp(t, "^start", "it's not starting") func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1756,7 +1591,7 @@ func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { // JSONEq asserts that two JSON strings are equivalent. // -// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1879,7 +1714,7 @@ type tHelper interface { // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) +// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1909,94 +1744,10 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t } } -// CollectT implements the TestingT interface and collects all errors. -type CollectT struct { - errors []error -} - -// Errorf collects the error. -func (c *CollectT) Errorf(format string, args ...interface{}) { - c.errors = append(c.errors, fmt.Errorf(format, args...)) -} - -// FailNow panics. -func (*CollectT) FailNow() { - panic("Assertion failed") -} - -// Deprecated: That was a method for internal usage that should not have been published. Now just panics. -func (*CollectT) Reset() { - panic("Reset() is deprecated") -} - -// Deprecated: That was a method for internal usage that should not have been published. Now just panics. -func (*CollectT) Copy(TestingT) { - panic("Copy() is deprecated") -} - -// EventuallyWithT asserts that given condition will be met in waitFor time, -// periodically checking target function each tick. In contrast to Eventually, -// it supplies a CollectT to the condition function, so that the condition -// function can use the CollectT to call other assertions. -// The condition is considered "met" if no errors are raised in a tick. -// The supplied CollectT collects all errors from one tick (if there are any). -// If the condition is not met before waitFor, the collected errors of -// the last tick are copied to t. -// -// externalValue := false -// go func() { -// time.Sleep(8*time.Second) -// externalValue = true -// }() -// assert.EventuallyWithT(t, func(c *assert.CollectT) { -// // add assertions as needed; any assertion failure will fail the current tick -// assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") -func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - - var lastFinishedTickErrs []error - ch := make(chan []error, 1) - - timer := time.NewTimer(waitFor) - defer timer.Stop() - - ticker := time.NewTicker(tick) - defer ticker.Stop() - - for tick := ticker.C; ; { - select { - case <-timer.C: - for _, err := range lastFinishedTickErrs { - t.Errorf("%v", err) - } - return Fail(t, "Condition never satisfied", msgAndArgs...) - case <-tick: - tick = nil - go func() { - collect := new(CollectT) - defer func() { - ch <- collect.errors - }() - condition(collect) - }() - case errs := <-ch: - if len(errs) == 0 { - return true - } - // Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached. - lastFinishedTickErrs = errs - tick = ticker.C - } - } -} - // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) +// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/doc.go b/vendor/github.com/stretchr/testify/assert/doc.go index 4953981..c9dccc4 100644 --- a/vendor/github.com/stretchr/testify/assert/doc.go +++ b/vendor/github.com/stretchr/testify/assert/doc.go @@ -1,40 +1,39 @@ // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. // -// # Example Usage +// Example Usage // // The following is a complete example using assert in a standard test function: +// import ( +// "testing" +// "github.com/stretchr/testify/assert" +// ) // -// import ( -// "testing" -// "github.com/stretchr/testify/assert" -// ) +// func TestSomething(t *testing.T) { // -// func TestSomething(t *testing.T) { +// var a string = "Hello" +// var b string = "Hello" // -// var a string = "Hello" -// var b string = "Hello" +// assert.Equal(t, a, b, "The two words should be the same.") // -// assert.Equal(t, a, b, "The two words should be the same.") -// -// } +// } // // if you assert many times, use the format below: // -// import ( -// "testing" -// "github.com/stretchr/testify/assert" -// ) +// import ( +// "testing" +// "github.com/stretchr/testify/assert" +// ) // -// func TestSomething(t *testing.T) { -// assert := assert.New(t) +// func TestSomething(t *testing.T) { +// assert := assert.New(t) // -// var a string = "Hello" -// var b string = "Hello" +// var a string = "Hello" +// var b string = "Hello" // -// assert.Equal(a, b, "The two words should be the same.") -// } +// assert.Equal(a, b, "The two words should be the same.") +// } // -// # Assertions +// Assertions // // Assertions allow you to easily write test code, and are global funcs in the `assert` package. // All assertion functions take, as the first argument, the `*testing.T` object provided by the diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/stretchr/testify/assert/http_assertions.go index 861ed4b..4ed341d 100644 --- a/vendor/github.com/stretchr/testify/assert/http_assertions.go +++ b/vendor/github.com/stretchr/testify/assert/http_assertions.go @@ -12,7 +12,7 @@ import ( // an error if building a new request fails. func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { w := httptest.NewRecorder() - req, err := http.NewRequest(method, url, http.NoBody) + req, err := http.NewRequest(method, url, nil) if err != nil { return -1, err } @@ -23,7 +23,7 @@ func httpCode(handler http.HandlerFunc, method, url string, values url.Values) ( // HTTPSuccess asserts that a specified handler returns a success status code. // -// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) +// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) // // Returns whether the assertion was successful (true) or not (false). func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -32,12 +32,12 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value } code, err := httpCode(handler, method, url, values) if err != nil { - Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) } isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent if !isSuccessCode { - Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) + Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code)) } return isSuccessCode @@ -45,7 +45,7 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value // HTTPRedirect asserts that a specified handler returns a redirect status code. // -// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -54,12 +54,12 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu } code, err := httpCode(handler, method, url, values) if err != nil { - Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) } isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect if !isRedirectCode { - Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) + Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code)) } return isRedirectCode @@ -67,7 +67,7 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu // HTTPError asserts that a specified handler returns an error status code. // -// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -76,12 +76,12 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values } code, err := httpCode(handler, method, url, values) if err != nil { - Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) } isErrorCode := code >= http.StatusBadRequest if !isErrorCode { - Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) + Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code)) } return isErrorCode @@ -89,7 +89,7 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values // HTTPStatusCode asserts that a specified handler returns a specified status code. // -// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) +// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) // // Returns whether the assertion was successful (true) or not (false). func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { @@ -98,12 +98,12 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, va } code, err := httpCode(handler, method, url, values) if err != nil { - Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) } successful := code == statuscode if !successful { - Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code), msgAndArgs...) + Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code)) } return successful @@ -113,10 +113,7 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, va // empty string if building a new request fails. func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { w := httptest.NewRecorder() - if len(values) > 0 { - url += "?" + values.Encode() - } - req, err := http.NewRequest(method, url, http.NoBody) + req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) if err != nil { return "" } @@ -127,7 +124,7 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) s // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // -// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { @@ -138,7 +135,7 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, contains := strings.Contains(body, fmt.Sprint(str)) if !contains { - Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body), msgAndArgs...) + Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) } return contains @@ -147,7 +144,7 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // -// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { @@ -158,7 +155,7 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url strin contains := strings.Contains(body, fmt.Sprint(str)) if contains { - Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body), msgAndArgs...) + Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) } return !contains diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go index 9684347..169de39 100644 --- a/vendor/github.com/stretchr/testify/require/doc.go +++ b/vendor/github.com/stretchr/testify/require/doc.go @@ -1,25 +1,24 @@ // Package require implements the same assertions as the `assert` package but // stops test execution when a test fails. // -// # Example Usage +// Example Usage // // The following is a complete example using require in a standard test function: +// import ( +// "testing" +// "github.com/stretchr/testify/require" +// ) // -// import ( -// "testing" -// "github.com/stretchr/testify/require" -// ) +// func TestSomething(t *testing.T) { // -// func TestSomething(t *testing.T) { +// var a string = "Hello" +// var b string = "Hello" // -// var a string = "Hello" -// var b string = "Hello" +// require.Equal(t, a, b, "The two words should be the same.") // -// require.Equal(t, a, b, "The two words should be the same.") +// } // -// } -// -// # Assertions +// Assertions // // The `require` package have same global functions as in the `assert` package, // but instead of returning a boolean result they call `t.FailNow()`. diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go index 506a82f..880853f 100644 --- a/vendor/github.com/stretchr/testify/require/require.go +++ b/vendor/github.com/stretchr/testify/require/require.go @@ -1,4 +1,7 @@ -// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ package require @@ -34,9 +37,9 @@ func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interfac // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// assert.Contains(t, "Hello World", "World") -// assert.Contains(t, ["Hello", "World"], "World") -// assert.Contains(t, {"Hello": "World"}, "Hello") +// assert.Contains(t, "Hello World", "World") +// assert.Contains(t, ["Hello", "World"], "World") +// assert.Contains(t, {"Hello": "World"}, "Hello") func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -50,9 +53,9 @@ func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...int // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") -// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") -// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") +// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") +// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") +// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -120,7 +123,7 @@ func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// assert.Empty(t, obj) +// assert.Empty(t, obj) func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -134,7 +137,7 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) { // Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// assert.Emptyf(t, obj, "error message %s", "formatted") +// assert.Emptyf(t, obj, "error message %s", "formatted") func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -147,7 +150,7 @@ func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) { // Equal asserts that two objects are equal. // -// assert.Equal(t, 123, 123) +// assert.Equal(t, 123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -165,8 +168,8 @@ func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...i // EqualError asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// assert.EqualError(t, err, expectedErrorString) +// actualObj, err := SomeFunction() +// assert.EqualError(t, err, expectedErrorString) func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -180,8 +183,8 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte // EqualErrorf asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -192,50 +195,10 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args t.FailNow() } -// EqualExportedValues asserts that the types of two objects are equal and their public -// fields are also equal. This is useful for comparing structs that have private fields -// that could potentially differ. -// -// type S struct { -// Exported int -// notExported int -// } -// assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true -// assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false -func EqualExportedValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.EqualExportedValues(t, expected, actual, msgAndArgs...) { - return - } - t.FailNow() -} - -// EqualExportedValuesf asserts that the types of two objects are equal and their public -// fields are also equal. This is useful for comparing structs that have private fields -// that could potentially differ. -// -// type S struct { -// Exported int -// notExported int -// } -// assert.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true -// assert.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false -func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.EqualExportedValuesf(t, expected, actual, msg, args...) { - return - } - t.FailNow() -} - -// EqualValues asserts that two objects are equal or convertible to the same types +// EqualValues asserts that two objects are equal or convertable to the same types // and equal. // -// assert.EqualValues(t, uint32(123), int32(123)) +// assert.EqualValues(t, uint32(123), int32(123)) func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -246,10 +209,10 @@ func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArg t.FailNow() } -// EqualValuesf asserts that two objects are equal or convertible to the same types +// EqualValuesf asserts that two objects are equal or convertable to the same types // and equal. // -// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") +// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -262,7 +225,7 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri // Equalf asserts that two objects are equal. // -// assert.Equalf(t, 123, 123, "error message %s", "formatted") +// assert.Equalf(t, 123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -279,10 +242,10 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar // Error asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if assert.Error(t, err) { -// assert.Equal(t, expectedError, err) -// } +// actualObj, err := SomeFunction() +// if assert.Error(t, err) { +// assert.Equal(t, expectedError, err) +// } func Error(t TestingT, err error, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -320,8 +283,8 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int // ErrorContains asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// assert.ErrorContains(t, err, expectedErrorSubString) +// actualObj, err := SomeFunction() +// assert.ErrorContains(t, err, expectedErrorSubString) func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -335,8 +298,8 @@ func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...in // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -373,10 +336,10 @@ func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface // Errorf asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if assert.Errorf(t, err, "error message %s", "formatted") { -// assert.Equal(t, expectedErrorf, err) -// } +// actualObj, err := SomeFunction() +// if assert.Errorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } func Errorf(t TestingT, err error, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -390,7 +353,7 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) { // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) +// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -401,66 +364,10 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t t.FailNow() } -// EventuallyWithT asserts that given condition will be met in waitFor time, -// periodically checking target function each tick. In contrast to Eventually, -// it supplies a CollectT to the condition function, so that the condition -// function can use the CollectT to call other assertions. -// The condition is considered "met" if no errors are raised in a tick. -// The supplied CollectT collects all errors from one tick (if there are any). -// If the condition is not met before waitFor, the collected errors of -// the last tick are copied to t. -// -// externalValue := false -// go func() { -// time.Sleep(8*time.Second) -// externalValue = true -// }() -// assert.EventuallyWithT(t, func(c *assert.CollectT) { -// // add assertions as needed; any assertion failure will fail the current tick -// assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") -func EventuallyWithT(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.EventuallyWithT(t, condition, waitFor, tick, msgAndArgs...) { - return - } - t.FailNow() -} - -// EventuallyWithTf asserts that given condition will be met in waitFor time, -// periodically checking target function each tick. In contrast to Eventually, -// it supplies a CollectT to the condition function, so that the condition -// function can use the CollectT to call other assertions. -// The condition is considered "met" if no errors are raised in a tick. -// The supplied CollectT collects all errors from one tick (if there are any). -// If the condition is not met before waitFor, the collected errors of -// the last tick are copied to t. -// -// externalValue := false -// go func() { -// time.Sleep(8*time.Second) -// externalValue = true -// }() -// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") { -// // add assertions as needed; any assertion failure will fail the current tick -// assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") -func EventuallyWithTf(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.EventuallyWithTf(t, condition, waitFor, tick, msg, args...) { - return - } - t.FailNow() -} - // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -473,7 +380,7 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick // Exactly asserts that two objects are equal in value and type. // -// assert.Exactly(t, int32(123), int64(123)) +// assert.Exactly(t, int32(123), int64(123)) func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -486,7 +393,7 @@ func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs .. // Exactlyf asserts that two objects are equal in value and type. // -// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") +// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -543,7 +450,7 @@ func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) { // False asserts that the specified value is false. // -// assert.False(t, myBool) +// assert.False(t, myBool) func False(t TestingT, value bool, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -556,7 +463,7 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) { // Falsef asserts that the specified value is false. // -// assert.Falsef(t, myBool, "error message %s", "formatted") +// assert.Falsef(t, myBool, "error message %s", "formatted") func Falsef(t TestingT, value bool, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -593,9 +500,9 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) { // Greater asserts that the first element is greater than the second // -// assert.Greater(t, 2, 1) -// assert.Greater(t, float64(2), float64(1)) -// assert.Greater(t, "b", "a") +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -608,10 +515,10 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface // GreaterOrEqual asserts that the first element is greater than or equal to the second // -// assert.GreaterOrEqual(t, 2, 1) -// assert.GreaterOrEqual(t, 2, 2) -// assert.GreaterOrEqual(t, "b", "a") -// assert.GreaterOrEqual(t, "b", "b") +// assert.GreaterOrEqual(t, 2, 1) +// assert.GreaterOrEqual(t, 2, 2) +// assert.GreaterOrEqual(t, "b", "a") +// assert.GreaterOrEqual(t, "b", "b") func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -624,10 +531,10 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in // GreaterOrEqualf asserts that the first element is greater than or equal to the second // -// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") -// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") -// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") -// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -640,9 +547,9 @@ func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, arg // Greaterf asserts that the first element is greater than the second // -// assert.Greaterf(t, 2, 1, "error message %s", "formatted") -// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") -// assert.Greaterf(t, "b", "a", "error message %s", "formatted") +// assert.Greaterf(t, 2, 1, "error message %s", "formatted") +// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") +// assert.Greaterf(t, "b", "a", "error message %s", "formatted") func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -656,7 +563,7 @@ func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...in // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // -// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { @@ -672,7 +579,7 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url s // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // -// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { @@ -688,7 +595,7 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // -// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { @@ -704,7 +611,7 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, ur // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // -// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { @@ -719,7 +626,7 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u // HTTPError asserts that a specified handler returns an error status code. // -// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -734,7 +641,7 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, // HTTPErrorf asserts that a specified handler returns an error status code. // -// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -749,7 +656,7 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, // HTTPRedirect asserts that a specified handler returns a redirect status code. // -// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -764,7 +671,7 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url strin // HTTPRedirectf asserts that a specified handler returns a redirect status code. // -// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -779,7 +686,7 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri // HTTPStatusCode asserts that a specified handler returns a specified status code. // -// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) +// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) // // Returns whether the assertion was successful (true) or not (false). func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { @@ -794,7 +701,7 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url str // HTTPStatusCodef asserts that a specified handler returns a specified status code. // -// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { @@ -809,7 +716,7 @@ func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url st // HTTPSuccess asserts that a specified handler returns a success status code. // -// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) +// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) // // Returns whether the assertion was successful (true) or not (false). func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -824,7 +731,7 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string // HTTPSuccessf asserts that a specified handler returns a success status code. // -// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -839,7 +746,7 @@ func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url strin // Implements asserts that an object is implemented by the specified interface. // -// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -852,7 +759,7 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg // Implementsf asserts that an object is implemented by the specified interface. // -// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -865,7 +772,7 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms // InDelta asserts that the two numerals are within delta of each other. // -// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -922,7 +829,7 @@ func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta f // InDeltaf asserts that the two numerals are within delta of each other. // -// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -979,9 +886,9 @@ func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon fl // IsDecreasing asserts that the collection is decreasing // -// assert.IsDecreasing(t, []int{2, 1, 0}) -// assert.IsDecreasing(t, []float{2, 1}) -// assert.IsDecreasing(t, []string{"b", "a"}) +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -994,9 +901,9 @@ func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { // IsDecreasingf asserts that the collection is decreasing // -// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") -// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") -// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1009,9 +916,9 @@ func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface // IsIncreasing asserts that the collection is increasing // -// assert.IsIncreasing(t, []int{1, 2, 3}) -// assert.IsIncreasing(t, []float{1, 2}) -// assert.IsIncreasing(t, []string{"a", "b"}) +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1024,9 +931,9 @@ func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { // IsIncreasingf asserts that the collection is increasing // -// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") -// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") -// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1039,9 +946,9 @@ func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface // IsNonDecreasing asserts that the collection is not decreasing // -// assert.IsNonDecreasing(t, []int{1, 1, 2}) -// assert.IsNonDecreasing(t, []float{1, 2}) -// assert.IsNonDecreasing(t, []string{"a", "b"}) +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1054,9 +961,9 @@ func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) // IsNonDecreasingf asserts that the collection is not decreasing // -// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") -// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") -// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1069,9 +976,9 @@ func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interf // IsNonIncreasing asserts that the collection is not increasing // -// assert.IsNonIncreasing(t, []int{2, 1, 1}) -// assert.IsNonIncreasing(t, []float{2, 1}) -// assert.IsNonIncreasing(t, []string{"b", "a"}) +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1084,9 +991,9 @@ func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) // IsNonIncreasingf asserts that the collection is not increasing // -// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") -// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") -// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1121,7 +1028,7 @@ func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg strin // JSONEq asserts that two JSON strings are equivalent. // -// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1134,7 +1041,7 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{ // JSONEqf asserts that two JSON strings are equivalent. // -// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1148,7 +1055,7 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // -// assert.Len(t, mySlice, 3) +// assert.Len(t, mySlice, 3) func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1162,7 +1069,7 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // -// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") +// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1175,9 +1082,9 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf // Less asserts that the first element is less than the second // -// assert.Less(t, 1, 2) -// assert.Less(t, float64(1), float64(2)) -// assert.Less(t, "a", "b") +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1190,10 +1097,10 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) // LessOrEqual asserts that the first element is less than or equal to the second // -// assert.LessOrEqual(t, 1, 2) -// assert.LessOrEqual(t, 2, 2) -// assert.LessOrEqual(t, "a", "b") -// assert.LessOrEqual(t, "b", "b") +// assert.LessOrEqual(t, 1, 2) +// assert.LessOrEqual(t, 2, 2) +// assert.LessOrEqual(t, "a", "b") +// assert.LessOrEqual(t, "b", "b") func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1206,10 +1113,10 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter // LessOrEqualf asserts that the first element is less than or equal to the second // -// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") -// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") -// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") -// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1222,9 +1129,9 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args . // Lessf asserts that the first element is less than the second // -// assert.Lessf(t, 1, 2, "error message %s", "formatted") -// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") -// assert.Lessf(t, "a", "b", "error message %s", "formatted") +// assert.Lessf(t, 1, 2, "error message %s", "formatted") +// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") +// assert.Lessf(t, "a", "b", "error message %s", "formatted") func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1237,8 +1144,8 @@ func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...inter // Negative asserts that the specified element is negative // -// assert.Negative(t, -1) -// assert.Negative(t, -1.23) +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1251,8 +1158,8 @@ func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) { // Negativef asserts that the specified element is negative // -// assert.Negativef(t, -1, "error message %s", "formatted") -// assert.Negativef(t, -1.23, "error message %s", "formatted") +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1266,7 +1173,7 @@ func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) { // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) +// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1280,7 +1187,7 @@ func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.D // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1293,7 +1200,7 @@ func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time. // Nil asserts that the specified object is nil. // -// assert.Nil(t, err) +// assert.Nil(t, err) func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1306,7 +1213,7 @@ func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) { // Nilf asserts that the specified object is nil. // -// assert.Nilf(t, err, "error message %s", "formatted") +// assert.Nilf(t, err, "error message %s", "formatted") func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1343,10 +1250,10 @@ func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) { // NoError asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if assert.NoError(t, err) { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } func NoError(t TestingT, err error, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1359,10 +1266,10 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) { // NoErrorf asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if assert.NoErrorf(t, err, "error message %s", "formatted") { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if assert.NoErrorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } func NoErrorf(t TestingT, err error, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1400,9 +1307,9 @@ func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) { // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// assert.NotContains(t, "Hello World", "Earth") -// assert.NotContains(t, ["Hello", "World"], "Earth") -// assert.NotContains(t, {"Hello": "World"}, "Earth") +// assert.NotContains(t, "Hello World", "Earth") +// assert.NotContains(t, ["Hello", "World"], "Earth") +// assert.NotContains(t, {"Hello": "World"}, "Earth") func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1416,9 +1323,9 @@ func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ... // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") -// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") -// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1432,9 +1339,9 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if assert.NotEmpty(t, obj) { -// assert.Equal(t, "two", obj[1]) -// } +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1448,9 +1355,9 @@ func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { -// assert.Equal(t, "two", obj[1]) -// } +// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1463,7 +1370,7 @@ func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) // NotEqual asserts that the specified values are NOT equal. // -// assert.NotEqual(t, obj1, obj2) +// assert.NotEqual(t, obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1479,7 +1386,7 @@ func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs . // NotEqualValues asserts that two objects are not equal even when converted to the same type // -// assert.NotEqualValues(t, obj1, obj2) +// assert.NotEqualValues(t, obj1, obj2) func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1492,7 +1399,7 @@ func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAnd // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // -// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") +// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1505,7 +1412,7 @@ func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg s // NotEqualf asserts that the specified values are NOT equal. // -// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") +// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1543,35 +1450,9 @@ func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interf t.FailNow() } -// NotImplements asserts that an object does not implement the specified interface. -// -// assert.NotImplements(t, (*MyInterface)(nil), new(MyObject)) -func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.NotImplements(t, interfaceObject, object, msgAndArgs...) { - return - } - t.FailNow() -} - -// NotImplementsf asserts that an object does not implement the specified interface. -// -// assert.NotImplementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") -func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.NotImplementsf(t, interfaceObject, object, msg, args...) { - return - } - t.FailNow() -} - // NotNil asserts that the specified object is not nil. // -// assert.NotNil(t, err) +// assert.NotNil(t, err) func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1584,7 +1465,7 @@ func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) { // NotNilf asserts that the specified object is not nil. // -// assert.NotNilf(t, err, "error message %s", "formatted") +// assert.NotNilf(t, err, "error message %s", "formatted") func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1597,7 +1478,7 @@ func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) { // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // -// assert.NotPanics(t, func(){ RemainCalm() }) +// assert.NotPanics(t, func(){ RemainCalm() }) func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1610,7 +1491,7 @@ func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // -// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") +// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1623,8 +1504,8 @@ func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interfac // NotRegexp asserts that a specified regexp does not match a string. // -// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") -// assert.NotRegexp(t, "^start", "it's not starting") +// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// assert.NotRegexp(t, "^start", "it's not starting") func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1637,8 +1518,8 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf // NotRegexpf asserts that a specified regexp does not match a string. // -// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") -// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") +// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1651,7 +1532,7 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args .. // NotSame asserts that two pointers do not reference the same object. // -// assert.NotSame(t, ptr1, ptr2) +// assert.NotSame(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1667,7 +1548,7 @@ func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs .. // NotSamef asserts that two pointers do not reference the same object. // -// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") +// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1681,12 +1562,10 @@ func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, t.FailNow() } -// NotSubset asserts that the specified list(array, slice...) or map does NOT -// contain all elements given in the specified subset list(array, slice...) or -// map. +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). // -// assert.NotSubset(t, [1, 3, 4], [1, 2]) -// assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3}) +// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1697,12 +1576,10 @@ func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...i t.FailNow() } -// NotSubsetf asserts that the specified list(array, slice...) or map does NOT -// contain all elements given in the specified subset list(array, slice...) or -// map. +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). // -// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted") -// assert.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") +// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1737,7 +1614,7 @@ func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) { // Panics asserts that the code inside the specified PanicTestFunc panics. // -// assert.Panics(t, func(){ GoCrazy() }) +// assert.Panics(t, func(){ GoCrazy() }) func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1752,7 +1629,7 @@ func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1767,7 +1644,7 @@ func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAn // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1781,7 +1658,7 @@ func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) +// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1795,7 +1672,7 @@ func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, m // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1808,7 +1685,7 @@ func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, // Panicsf asserts that the code inside the specified PanicTestFunc panics. // -// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") +// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1821,8 +1698,8 @@ func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{} // Positive asserts that the specified element is positive // -// assert.Positive(t, 1) -// assert.Positive(t, 1.23) +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1835,8 +1712,8 @@ func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) { // Positivef asserts that the specified element is positive // -// assert.Positivef(t, 1, "error message %s", "formatted") -// assert.Positivef(t, 1.23, "error message %s", "formatted") +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1849,8 +1726,8 @@ func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) { // Regexp asserts that a specified regexp matches a string. // -// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") -// assert.Regexp(t, "start...$", "it's not starting") +// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") +// assert.Regexp(t, "start...$", "it's not starting") func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1863,8 +1740,8 @@ func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface // Regexpf asserts that a specified regexp matches a string. // -// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") -// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") +// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1877,7 +1754,7 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in // Same asserts that two pointers reference the same object. // -// assert.Same(t, ptr1, ptr2) +// assert.Same(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1893,7 +1770,7 @@ func Same(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...in // Samef asserts that two pointers reference the same object. // -// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") +// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1907,11 +1784,10 @@ func Samef(t TestingT, expected interface{}, actual interface{}, msg string, arg t.FailNow() } -// Subset asserts that the specified list(array, slice...) or map contains all -// elements given in the specified subset list(array, slice...) or map. +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). // -// assert.Subset(t, [1, 2, 3], [1, 2]) -// assert.Subset(t, {"x": 1, "y": 2}, {"x": 1}) +// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1922,11 +1798,10 @@ func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...inte t.FailNow() } -// Subsetf asserts that the specified list(array, slice...) or map contains all -// elements given in the specified subset list(array, slice...) or map. +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). // -// assert.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted") -// assert.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") +// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1939,7 +1814,7 @@ func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args // True asserts that the specified value is true. // -// assert.True(t, myBool) +// assert.True(t, myBool) func True(t TestingT, value bool, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1952,7 +1827,7 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) { // Truef asserts that the specified value is true. // -// assert.Truef(t, myBool, "error message %s", "formatted") +// assert.Truef(t, myBool, "error message %s", "formatted") func Truef(t TestingT, value bool, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1965,7 +1840,7 @@ func Truef(t TestingT, value bool, msg string, args ...interface{}) { // WithinDuration asserts that the two times are within duration delta of each other. // -// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) +// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1978,7 +1853,7 @@ func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time // WithinDurationf asserts that the two times are within duration delta of each other. // -// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1991,7 +1866,7 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim // WithinRange asserts that a time is within a time range (inclusive). // -// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func WithinRange(t TestingT, actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -2004,7 +1879,7 @@ func WithinRange(t TestingT, actual time.Time, start time.Time, end time.Time, m // WithinRangef asserts that a time is within a time range (inclusive). // -// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go index eee8310..960bf6f 100644 --- a/vendor/github.com/stretchr/testify/require/require_forward.go +++ b/vendor/github.com/stretchr/testify/require/require_forward.go @@ -1,4 +1,7 @@ -// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ package require @@ -28,9 +31,9 @@ func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...inte // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// a.Contains("Hello World", "World") -// a.Contains(["Hello", "World"], "World") -// a.Contains({"Hello": "World"}, "Hello") +// a.Contains("Hello World", "World") +// a.Contains(["Hello", "World"], "World") +// a.Contains({"Hello": "World"}, "Hello") func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -41,9 +44,9 @@ func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs .. // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// a.Containsf("Hello World", "World", "error message %s", "formatted") -// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") -// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") +// a.Containsf("Hello World", "World", "error message %s", "formatted") +// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") +// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -96,7 +99,7 @@ func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg st // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// a.Empty(obj) +// a.Empty(obj) func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -107,7 +110,7 @@ func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { // Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// a.Emptyf(obj, "error message %s", "formatted") +// a.Emptyf(obj, "error message %s", "formatted") func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -117,7 +120,7 @@ func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) // Equal asserts that two objects are equal. // -// a.Equal(123, 123) +// a.Equal(123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -132,8 +135,8 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs // EqualError asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// a.EqualError(err, expectedErrorString) +// actualObj, err := SomeFunction() +// a.EqualError(err, expectedErrorString) func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -144,8 +147,8 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ... // EqualErrorf asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -153,44 +156,10 @@ func (a *Assertions) EqualErrorf(theError error, errString string, msg string, a EqualErrorf(a.t, theError, errString, msg, args...) } -// EqualExportedValues asserts that the types of two objects are equal and their public -// fields are also equal. This is useful for comparing structs that have private fields -// that could potentially differ. -// -// type S struct { -// Exported int -// notExported int -// } -// a.EqualExportedValues(S{1, 2}, S{1, 3}) => true -// a.EqualExportedValues(S{1, 2}, S{2, 3}) => false -func (a *Assertions) EqualExportedValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - EqualExportedValues(a.t, expected, actual, msgAndArgs...) -} - -// EqualExportedValuesf asserts that the types of two objects are equal and their public -// fields are also equal. This is useful for comparing structs that have private fields -// that could potentially differ. -// -// type S struct { -// Exported int -// notExported int -// } -// a.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true -// a.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false -func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - EqualExportedValuesf(a.t, expected, actual, msg, args...) -} - -// EqualValues asserts that two objects are equal or convertible to the same types +// EqualValues asserts that two objects are equal or convertable to the same types // and equal. // -// a.EqualValues(uint32(123), int32(123)) +// a.EqualValues(uint32(123), int32(123)) func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -198,10 +167,10 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn EqualValues(a.t, expected, actual, msgAndArgs...) } -// EqualValuesf asserts that two objects are equal or convertible to the same types +// EqualValuesf asserts that two objects are equal or convertable to the same types // and equal. // -// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") +// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -211,7 +180,7 @@ func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg // Equalf asserts that two objects are equal. // -// a.Equalf(123, 123, "error message %s", "formatted") +// a.Equalf(123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -225,10 +194,10 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string // Error asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if a.Error(err) { -// assert.Equal(t, expectedError, err) -// } +// actualObj, err := SomeFunction() +// if a.Error(err) { +// assert.Equal(t, expectedError, err) +// } func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -257,8 +226,8 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args .. // ErrorContains asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// a.ErrorContains(err, expectedErrorSubString) +// actualObj, err := SomeFunction() +// a.ErrorContains(err, expectedErrorSubString) func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -269,8 +238,8 @@ func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs . // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -298,10 +267,10 @@ func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...inter // Errorf asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if a.Errorf(err, "error message %s", "formatted") { -// assert.Equal(t, expectedErrorf, err) -// } +// actualObj, err := SomeFunction() +// if a.Errorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } func (a *Assertions) Errorf(err error, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -312,7 +281,7 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) { // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) +// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -320,60 +289,10 @@ func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, ti Eventually(a.t, condition, waitFor, tick, msgAndArgs...) } -// EventuallyWithT asserts that given condition will be met in waitFor time, -// periodically checking target function each tick. In contrast to Eventually, -// it supplies a CollectT to the condition function, so that the condition -// function can use the CollectT to call other assertions. -// The condition is considered "met" if no errors are raised in a tick. -// The supplied CollectT collects all errors from one tick (if there are any). -// If the condition is not met before waitFor, the collected errors of -// the last tick are copied to t. -// -// externalValue := false -// go func() { -// time.Sleep(8*time.Second) -// externalValue = true -// }() -// a.EventuallyWithT(func(c *assert.CollectT) { -// // add assertions as needed; any assertion failure will fail the current tick -// assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") -func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...) -} - -// EventuallyWithTf asserts that given condition will be met in waitFor time, -// periodically checking target function each tick. In contrast to Eventually, -// it supplies a CollectT to the condition function, so that the condition -// function can use the CollectT to call other assertions. -// The condition is considered "met" if no errors are raised in a tick. -// The supplied CollectT collects all errors from one tick (if there are any). -// If the condition is not met before waitFor, the collected errors of -// the last tick are copied to t. -// -// externalValue := false -// go func() { -// time.Sleep(8*time.Second) -// externalValue = true -// }() -// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { -// // add assertions as needed; any assertion failure will fail the current tick -// assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") -func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...) -} - // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -383,7 +302,7 @@ func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, t // Exactly asserts that two objects are equal in value and type. // -// a.Exactly(int32(123), int64(123)) +// a.Exactly(int32(123), int64(123)) func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -393,7 +312,7 @@ func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArg // Exactlyf asserts that two objects are equal in value and type. // -// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") +// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -435,7 +354,7 @@ func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{ // False asserts that the specified value is false. // -// a.False(myBool) +// a.False(myBool) func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -445,7 +364,7 @@ func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { // Falsef asserts that the specified value is false. // -// a.Falsef(myBool, "error message %s", "formatted") +// a.Falsef(myBool, "error message %s", "formatted") func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -473,9 +392,9 @@ func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) { // Greater asserts that the first element is greater than the second // -// a.Greater(2, 1) -// a.Greater(float64(2), float64(1)) -// a.Greater("b", "a") +// a.Greater(2, 1) +// a.Greater(float64(2), float64(1)) +// a.Greater("b", "a") func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -485,10 +404,10 @@ func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...inter // GreaterOrEqual asserts that the first element is greater than or equal to the second // -// a.GreaterOrEqual(2, 1) -// a.GreaterOrEqual(2, 2) -// a.GreaterOrEqual("b", "a") -// a.GreaterOrEqual("b", "b") +// a.GreaterOrEqual(2, 1) +// a.GreaterOrEqual(2, 2) +// a.GreaterOrEqual("b", "a") +// a.GreaterOrEqual("b", "b") func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -498,10 +417,10 @@ func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs . // GreaterOrEqualf asserts that the first element is greater than or equal to the second // -// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") -// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") -// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") -// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") +// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") +// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") +// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") +// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -511,9 +430,9 @@ func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, // Greaterf asserts that the first element is greater than the second // -// a.Greaterf(2, 1, "error message %s", "formatted") -// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") -// a.Greaterf("b", "a", "error message %s", "formatted") +// a.Greaterf(2, 1, "error message %s", "formatted") +// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") +// a.Greaterf("b", "a", "error message %s", "formatted") func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -524,7 +443,7 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args . // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // -// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { @@ -537,7 +456,7 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // -// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { @@ -550,7 +469,7 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // -// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { @@ -563,7 +482,7 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // -// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { @@ -575,7 +494,7 @@ func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method strin // HTTPError asserts that a specified handler returns an error status code. // -// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -587,7 +506,7 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri // HTTPErrorf asserts that a specified handler returns an error status code. // -// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -599,7 +518,7 @@ func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url str // HTTPRedirect asserts that a specified handler returns a redirect status code. // -// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -611,7 +530,7 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s // HTTPRedirectf asserts that a specified handler returns a redirect status code. // -// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -623,7 +542,7 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url // HTTPStatusCode asserts that a specified handler returns a specified status code. // -// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { @@ -635,7 +554,7 @@ func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url // HTTPStatusCodef asserts that a specified handler returns a specified status code. // -// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { @@ -647,7 +566,7 @@ func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, ur // HTTPSuccess asserts that a specified handler returns a success status code. // -// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) +// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -659,7 +578,7 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url st // HTTPSuccessf asserts that a specified handler returns a success status code. // -// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -671,7 +590,7 @@ func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url s // Implements asserts that an object is implemented by the specified interface. // -// a.Implements((*MyInterface)(nil), new(MyObject)) +// a.Implements((*MyInterface)(nil), new(MyObject)) func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -681,7 +600,7 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, // Implementsf asserts that an object is implemented by the specified interface. // -// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -691,7 +610,7 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{} // InDelta asserts that the two numerals are within delta of each other. // -// a.InDelta(math.Pi, 22/7.0, 0.01) +// a.InDelta(math.Pi, 22/7.0, 0.01) func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -733,7 +652,7 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del // InDeltaf asserts that the two numerals are within delta of each other. // -// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -775,9 +694,9 @@ func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilo // IsDecreasing asserts that the collection is decreasing // -// a.IsDecreasing([]int{2, 1, 0}) -// a.IsDecreasing([]float{2, 1}) -// a.IsDecreasing([]string{"b", "a"}) +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -787,9 +706,9 @@ func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) // IsDecreasingf asserts that the collection is decreasing // -// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") -// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") -// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -799,9 +718,9 @@ func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...inter // IsIncreasing asserts that the collection is increasing // -// a.IsIncreasing([]int{1, 2, 3}) -// a.IsIncreasing([]float{1, 2}) -// a.IsIncreasing([]string{"a", "b"}) +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -811,9 +730,9 @@ func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) // IsIncreasingf asserts that the collection is increasing // -// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") -// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") -// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -823,9 +742,9 @@ func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...inter // IsNonDecreasing asserts that the collection is not decreasing // -// a.IsNonDecreasing([]int{1, 1, 2}) -// a.IsNonDecreasing([]float{1, 2}) -// a.IsNonDecreasing([]string{"a", "b"}) +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -835,9 +754,9 @@ func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface // IsNonDecreasingf asserts that the collection is not decreasing // -// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") -// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") -// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -847,9 +766,9 @@ func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...in // IsNonIncreasing asserts that the collection is not increasing // -// a.IsNonIncreasing([]int{2, 1, 1}) -// a.IsNonIncreasing([]float{2, 1}) -// a.IsNonIncreasing([]string{"b", "a"}) +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -859,9 +778,9 @@ func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface // IsNonIncreasingf asserts that the collection is not increasing // -// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") -// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") -// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -887,7 +806,7 @@ func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg s // JSONEq asserts that two JSON strings are equivalent. // -// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -897,7 +816,7 @@ func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interf // JSONEqf asserts that two JSON strings are equivalent. // -// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -908,7 +827,7 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args .. // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // -// a.Len(mySlice, 3) +// a.Len(mySlice, 3) func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -919,7 +838,7 @@ func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // -// a.Lenf(mySlice, 3, "error message %s", "formatted") +// a.Lenf(mySlice, 3, "error message %s", "formatted") func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -929,9 +848,9 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in // Less asserts that the first element is less than the second // -// a.Less(1, 2) -// a.Less(float64(1), float64(2)) -// a.Less("a", "b") +// a.Less(1, 2) +// a.Less(float64(1), float64(2)) +// a.Less("a", "b") func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -941,10 +860,10 @@ func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interfac // LessOrEqual asserts that the first element is less than or equal to the second // -// a.LessOrEqual(1, 2) -// a.LessOrEqual(2, 2) -// a.LessOrEqual("a", "b") -// a.LessOrEqual("b", "b") +// a.LessOrEqual(1, 2) +// a.LessOrEqual(2, 2) +// a.LessOrEqual("a", "b") +// a.LessOrEqual("b", "b") func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -954,10 +873,10 @@ func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...i // LessOrEqualf asserts that the first element is less than or equal to the second // -// a.LessOrEqualf(1, 2, "error message %s", "formatted") -// a.LessOrEqualf(2, 2, "error message %s", "formatted") -// a.LessOrEqualf("a", "b", "error message %s", "formatted") -// a.LessOrEqualf("b", "b", "error message %s", "formatted") +// a.LessOrEqualf(1, 2, "error message %s", "formatted") +// a.LessOrEqualf(2, 2, "error message %s", "formatted") +// a.LessOrEqualf("a", "b", "error message %s", "formatted") +// a.LessOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -967,9 +886,9 @@ func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, ar // Lessf asserts that the first element is less than the second // -// a.Lessf(1, 2, "error message %s", "formatted") -// a.Lessf(float64(1), float64(2), "error message %s", "formatted") -// a.Lessf("a", "b", "error message %s", "formatted") +// a.Lessf(1, 2, "error message %s", "formatted") +// a.Lessf(float64(1), float64(2), "error message %s", "formatted") +// a.Lessf("a", "b", "error message %s", "formatted") func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -979,8 +898,8 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i // Negative asserts that the specified element is negative // -// a.Negative(-1) -// a.Negative(-1.23) +// a.Negative(-1) +// a.Negative(-1.23) func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -990,8 +909,8 @@ func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) { // Negativef asserts that the specified element is negative // -// a.Negativef(-1, "error message %s", "formatted") -// a.Negativef(-1.23, "error message %s", "formatted") +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1002,7 +921,7 @@ func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) { // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1013,7 +932,7 @@ func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick ti // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1023,7 +942,7 @@ func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick t // Nil asserts that the specified object is nil. // -// a.Nil(err) +// a.Nil(err) func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1033,7 +952,7 @@ func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { // Nilf asserts that the specified object is nil. // -// a.Nilf(err, "error message %s", "formatted") +// a.Nilf(err, "error message %s", "formatted") func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1061,10 +980,10 @@ func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) // NoError asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if a.NoError(err) { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if a.NoError(err) { +// assert.Equal(t, expectedObj, actualObj) +// } func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1074,10 +993,10 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { // NoErrorf asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if a.NoErrorf(err, "error message %s", "formatted") { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if a.NoErrorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1106,9 +1025,9 @@ func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// a.NotContains("Hello World", "Earth") -// a.NotContains(["Hello", "World"], "Earth") -// a.NotContains({"Hello": "World"}, "Earth") +// a.NotContains("Hello World", "Earth") +// a.NotContains(["Hello", "World"], "Earth") +// a.NotContains({"Hello": "World"}, "Earth") func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1119,9 +1038,9 @@ func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") -// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") -// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") +// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") +// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") +// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1132,9 +1051,9 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if a.NotEmpty(obj) { -// assert.Equal(t, "two", obj[1]) -// } +// if a.NotEmpty(obj) { +// assert.Equal(t, "two", obj[1]) +// } func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1145,9 +1064,9 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if a.NotEmptyf(obj, "error message %s", "formatted") { -// assert.Equal(t, "two", obj[1]) -// } +// if a.NotEmptyf(obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1157,7 +1076,7 @@ func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface // NotEqual asserts that the specified values are NOT equal. // -// a.NotEqual(obj1, obj2) +// a.NotEqual(obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1170,7 +1089,7 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr // NotEqualValues asserts that two objects are not equal even when converted to the same type // -// a.NotEqualValues(obj1, obj2) +// a.NotEqualValues(obj1, obj2) func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1180,7 +1099,7 @@ func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, ms // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // -// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") +// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1190,7 +1109,7 @@ func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, m // NotEqualf asserts that the specified values are NOT equal. // -// a.NotEqualf(obj1, obj2, "error message %s", "formatted") +// a.NotEqualf(obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1219,29 +1138,9 @@ func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...in NotErrorIsf(a.t, err, target, msg, args...) } -// NotImplements asserts that an object does not implement the specified interface. -// -// a.NotImplements((*MyInterface)(nil), new(MyObject)) -func (a *Assertions) NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - NotImplements(a.t, interfaceObject, object, msgAndArgs...) -} - -// NotImplementsf asserts that an object does not implement the specified interface. -// -// a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") -func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - NotImplementsf(a.t, interfaceObject, object, msg, args...) -} - // NotNil asserts that the specified object is not nil. // -// a.NotNil(err) +// a.NotNil(err) func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1251,7 +1150,7 @@ func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { // NotNilf asserts that the specified object is not nil. // -// a.NotNilf(err, "error message %s", "formatted") +// a.NotNilf(err, "error message %s", "formatted") func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1261,7 +1160,7 @@ func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{} // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // -// a.NotPanics(func(){ RemainCalm() }) +// a.NotPanics(func(){ RemainCalm() }) func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1271,7 +1170,7 @@ func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{} // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // -// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") +// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1281,8 +1180,8 @@ func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...inte // NotRegexp asserts that a specified regexp does not match a string. // -// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") -// a.NotRegexp("^start", "it's not starting") +// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") +// a.NotRegexp("^start", "it's not starting") func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1292,8 +1191,8 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in // NotRegexpf asserts that a specified regexp does not match a string. // -// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") -// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") +// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1303,7 +1202,7 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg // NotSame asserts that two pointers do not reference the same object. // -// a.NotSame(ptr1, ptr2) +// a.NotSame(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1316,7 +1215,7 @@ func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArg // NotSamef asserts that two pointers do not reference the same object. // -// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1327,12 +1226,10 @@ func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg stri NotSamef(a.t, expected, actual, msg, args...) } -// NotSubset asserts that the specified list(array, slice...) or map does NOT -// contain all elements given in the specified subset list(array, slice...) or -// map. +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). // -// a.NotSubset([1, 3, 4], [1, 2]) -// a.NotSubset({"x": 1, "y": 2}, {"z": 3}) +// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1340,12 +1237,10 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs NotSubset(a.t, list, subset, msgAndArgs...) } -// NotSubsetf asserts that the specified list(array, slice...) or map does NOT -// contain all elements given in the specified subset list(array, slice...) or -// map. +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). // -// a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted") -// a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") +// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1371,7 +1266,7 @@ func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) { // Panics asserts that the code inside the specified PanicTestFunc panics. // -// a.Panics(func(){ GoCrazy() }) +// a.Panics(func(){ GoCrazy() }) func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1383,7 +1278,7 @@ func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// a.PanicsWithError("crazy error", func(){ GoCrazy() }) +// a.PanicsWithError("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1395,7 +1290,7 @@ func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, m // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1406,7 +1301,7 @@ func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) +// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1417,7 +1312,7 @@ func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFun // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1427,7 +1322,7 @@ func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFu // Panicsf asserts that the code inside the specified PanicTestFunc panics. // -// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") +// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1437,8 +1332,8 @@ func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interfa // Positive asserts that the specified element is positive // -// a.Positive(1) -// a.Positive(1.23) +// a.Positive(1) +// a.Positive(1.23) func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1448,8 +1343,8 @@ func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) { // Positivef asserts that the specified element is positive // -// a.Positivef(1, "error message %s", "formatted") -// a.Positivef(1.23, "error message %s", "formatted") +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1459,8 +1354,8 @@ func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) { // Regexp asserts that a specified regexp matches a string. // -// a.Regexp(regexp.MustCompile("start"), "it's starting") -// a.Regexp("start...$", "it's not starting") +// a.Regexp(regexp.MustCompile("start"), "it's starting") +// a.Regexp("start...$", "it's not starting") func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1470,8 +1365,8 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter // Regexpf asserts that a specified regexp matches a string. // -// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") -// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") +// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1481,7 +1376,7 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args . // Same asserts that two pointers reference the same object. // -// a.Same(ptr1, ptr2) +// a.Same(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1494,7 +1389,7 @@ func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs . // Samef asserts that two pointers reference the same object. // -// a.Samef(ptr1, ptr2, "error message %s", "formatted") +// a.Samef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1505,11 +1400,10 @@ func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, Samef(a.t, expected, actual, msg, args...) } -// Subset asserts that the specified list(array, slice...) or map contains all -// elements given in the specified subset list(array, slice...) or map. +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). // -// a.Subset([1, 2, 3], [1, 2]) -// a.Subset({"x": 1, "y": 2}, {"x": 1}) +// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1517,11 +1411,10 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ... Subset(a.t, list, subset, msgAndArgs...) } -// Subsetf asserts that the specified list(array, slice...) or map contains all -// elements given in the specified subset list(array, slice...) or map. +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). // -// a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted") -// a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") +// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1531,7 +1424,7 @@ func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, a // True asserts that the specified value is true. // -// a.True(myBool) +// a.True(myBool) func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1541,7 +1434,7 @@ func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { // Truef asserts that the specified value is true. // -// a.Truef(myBool, "error message %s", "formatted") +// a.Truef(myBool, "error message %s", "formatted") func (a *Assertions) Truef(value bool, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1551,7 +1444,7 @@ func (a *Assertions) Truef(value bool, msg string, args ...interface{}) { // WithinDuration asserts that the two times are within duration delta of each other. // -// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) +// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1561,7 +1454,7 @@ func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta // WithinDurationf asserts that the two times are within duration delta of each other. // -// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1571,7 +1464,7 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta // WithinRange asserts that a time is within a time range (inclusive). // -// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1581,7 +1474,7 @@ func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Tim // WithinRangef asserts that a time is within a time range (inclusive). // -// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() diff --git a/vendor/golang.org/x/exp/LICENSE b/vendor/golang.org/x/exp/LICENSE deleted file mode 100644 index 6a66aea..0000000 --- a/vendor/golang.org/x/exp/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/exp/PATENTS b/vendor/golang.org/x/exp/PATENTS deleted file mode 100644 index 7330990..0000000 --- a/vendor/golang.org/x/exp/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/exp/constraints/constraints.go b/vendor/golang.org/x/exp/constraints/constraints.go deleted file mode 100644 index 2c033df..0000000 --- a/vendor/golang.org/x/exp/constraints/constraints.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package constraints defines a set of useful constraints to be used -// with type parameters. -package constraints - -// Signed is a constraint that permits any signed integer type. -// If future releases of Go add new predeclared signed integer types, -// this constraint will be modified to include them. -type Signed interface { - ~int | ~int8 | ~int16 | ~int32 | ~int64 -} - -// Unsigned is a constraint that permits any unsigned integer type. -// If future releases of Go add new predeclared unsigned integer types, -// this constraint will be modified to include them. -type Unsigned interface { - ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr -} - -// Integer is a constraint that permits any integer type. -// If future releases of Go add new predeclared integer types, -// this constraint will be modified to include them. -type Integer interface { - Signed | Unsigned -} - -// Float is a constraint that permits any floating-point type. -// If future releases of Go add new predeclared floating-point types, -// this constraint will be modified to include them. -type Float interface { - ~float32 | ~float64 -} - -// Complex is a constraint that permits any complex numeric type. -// If future releases of Go add new predeclared complex numeric types, -// this constraint will be modified to include them. -type Complex interface { - ~complex64 | ~complex128 -} - -// Ordered is a constraint that permits any ordered type: any type -// that supports the operators < <= >= >. -// If future releases of Go add new ordered types, -// this constraint will be modified to include them. -type Ordered interface { - Integer | Float | ~string -} diff --git a/vendor/golang.org/x/exp/slices/slices.go b/vendor/golang.org/x/exp/slices/slices.go deleted file mode 100644 index 8a7cf20..0000000 --- a/vendor/golang.org/x/exp/slices/slices.go +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package slices defines various functions useful with slices of any type. -// Unless otherwise specified, these functions all apply to the elements -// of a slice at index 0 <= i < len(s). -// -// Note that the less function in IsSortedFunc, SortFunc, SortStableFunc requires a -// strict weak ordering (https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings), -// or the sorting may fail to sort correctly. A common case is when sorting slices of -// floating-point numbers containing NaN values. -package slices - -import "golang.org/x/exp/constraints" - -// Equal reports whether two slices are equal: the same length and all -// elements equal. If the lengths are different, Equal returns false. -// Otherwise, the elements are compared in increasing index order, and the -// comparison stops at the first unequal pair. -// Floating point NaNs are not considered equal. -func Equal[E comparable](s1, s2 []E) bool { - if len(s1) != len(s2) { - return false - } - for i := range s1 { - if s1[i] != s2[i] { - return false - } - } - return true -} - -// EqualFunc reports whether two slices are equal using a comparison -// function on each pair of elements. If the lengths are different, -// EqualFunc returns false. Otherwise, the elements are compared in -// increasing index order, and the comparison stops at the first index -// for which eq returns false. -func EqualFunc[E1, E2 any](s1 []E1, s2 []E2, eq func(E1, E2) bool) bool { - if len(s1) != len(s2) { - return false - } - for i, v1 := range s1 { - v2 := s2[i] - if !eq(v1, v2) { - return false - } - } - return true -} - -// Compare compares the elements of s1 and s2. -// The elements are compared sequentially, starting at index 0, -// until one element is not equal to the other. -// The result of comparing the first non-matching elements is returned. -// If both slices are equal until one of them ends, the shorter slice is -// considered less than the longer one. -// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2. -// Comparisons involving floating point NaNs are ignored. -func Compare[E constraints.Ordered](s1, s2 []E) int { - s2len := len(s2) - for i, v1 := range s1 { - if i >= s2len { - return +1 - } - v2 := s2[i] - switch { - case v1 < v2: - return -1 - case v1 > v2: - return +1 - } - } - if len(s1) < s2len { - return -1 - } - return 0 -} - -// CompareFunc is like Compare but uses a comparison function -// on each pair of elements. The elements are compared in increasing -// index order, and the comparisons stop after the first time cmp -// returns non-zero. -// The result is the first non-zero result of cmp; if cmp always -// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2), -// and +1 if len(s1) > len(s2). -func CompareFunc[E1, E2 any](s1 []E1, s2 []E2, cmp func(E1, E2) int) int { - s2len := len(s2) - for i, v1 := range s1 { - if i >= s2len { - return +1 - } - v2 := s2[i] - if c := cmp(v1, v2); c != 0 { - return c - } - } - if len(s1) < s2len { - return -1 - } - return 0 -} - -// Index returns the index of the first occurrence of v in s, -// or -1 if not present. -func Index[E comparable](s []E, v E) int { - for i := range s { - if v == s[i] { - return i - } - } - return -1 -} - -// IndexFunc returns the first index i satisfying f(s[i]), -// or -1 if none do. -func IndexFunc[E any](s []E, f func(E) bool) int { - for i := range s { - if f(s[i]) { - return i - } - } - return -1 -} - -// Contains reports whether v is present in s. -func Contains[E comparable](s []E, v E) bool { - return Index(s, v) >= 0 -} - -// ContainsFunc reports whether at least one -// element e of s satisfies f(e). -func ContainsFunc[E any](s []E, f func(E) bool) bool { - return IndexFunc(s, f) >= 0 -} - -// Insert inserts the values v... into s at index i, -// returning the modified slice. -// In the returned slice r, r[i] == v[0]. -// Insert panics if i is out of range. -// This function is O(len(s) + len(v)). -func Insert[S ~[]E, E any](s S, i int, v ...E) S { - tot := len(s) + len(v) - if tot <= cap(s) { - s2 := s[:tot] - copy(s2[i+len(v):], s[i:]) - copy(s2[i:], v) - return s2 - } - s2 := make(S, tot) - copy(s2, s[:i]) - copy(s2[i:], v) - copy(s2[i+len(v):], s[i:]) - return s2 -} - -// Delete removes the elements s[i:j] from s, returning the modified slice. -// Delete panics if s[i:j] is not a valid slice of s. -// Delete modifies the contents of the slice s; it does not create a new slice. -// Delete is O(len(s)-j), so if many items must be deleted, it is better to -// make a single call deleting them all together than to delete one at a time. -// Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those -// elements contain pointers you might consider zeroing those elements so that -// objects they reference can be garbage collected. -func Delete[S ~[]E, E any](s S, i, j int) S { - _ = s[i:j] // bounds check - - return append(s[:i], s[j:]...) -} - -// DeleteFunc removes any elements from s for which del returns true, -// returning the modified slice. -// When DeleteFunc removes m elements, it might not modify the elements -// s[len(s)-m:len(s)]. If those elements contain pointers you might consider -// zeroing those elements so that objects they reference can be garbage -// collected. -func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S { - // Don't start copying elements until we find one to delete. - for i, v := range s { - if del(v) { - j := i - for i++; i < len(s); i++ { - v = s[i] - if !del(v) { - s[j] = v - j++ - } - } - return s[:j] - } - } - return s -} - -// Replace replaces the elements s[i:j] by the given v, and returns the -// modified slice. Replace panics if s[i:j] is not a valid slice of s. -func Replace[S ~[]E, E any](s S, i, j int, v ...E) S { - _ = s[i:j] // verify that i:j is a valid subslice - tot := len(s[:i]) + len(v) + len(s[j:]) - if tot <= cap(s) { - s2 := s[:tot] - copy(s2[i+len(v):], s[j:]) - copy(s2[i:], v) - return s2 - } - s2 := make(S, tot) - copy(s2, s[:i]) - copy(s2[i:], v) - copy(s2[i+len(v):], s[j:]) - return s2 -} - -// Clone returns a copy of the slice. -// The elements are copied using assignment, so this is a shallow clone. -func Clone[S ~[]E, E any](s S) S { - // Preserve nil in case it matters. - if s == nil { - return nil - } - return append(S([]E{}), s...) -} - -// Compact replaces consecutive runs of equal elements with a single copy. -// This is like the uniq command found on Unix. -// Compact modifies the contents of the slice s; it does not create a new slice. -// When Compact discards m elements in total, it might not modify the elements -// s[len(s)-m:len(s)]. If those elements contain pointers you might consider -// zeroing those elements so that objects they reference can be garbage collected. -func Compact[S ~[]E, E comparable](s S) S { - if len(s) < 2 { - return s - } - i := 1 - for k := 1; k < len(s); k++ { - if s[k] != s[k-1] { - if i != k { - s[i] = s[k] - } - i++ - } - } - return s[:i] -} - -// CompactFunc is like Compact but uses a comparison function. -func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { - if len(s) < 2 { - return s - } - i := 1 - for k := 1; k < len(s); k++ { - if !eq(s[k], s[k-1]) { - if i != k { - s[i] = s[k] - } - i++ - } - } - return s[:i] -} - -// Grow increases the slice's capacity, if necessary, to guarantee space for -// another n elements. After Grow(n), at least n elements can be appended -// to the slice without another allocation. If n is negative or too large to -// allocate the memory, Grow panics. -func Grow[S ~[]E, E any](s S, n int) S { - if n < 0 { - panic("cannot be negative") - } - if n -= cap(s) - len(s); n > 0 { - // TODO(https://go.dev/issue/53888): Make using []E instead of S - // to workaround a compiler bug where the runtime.growslice optimization - // does not take effect. Revert when the compiler is fixed. - s = append([]E(s)[:cap(s)], make([]E, n)...)[:len(s)] - } - return s -} - -// Clip removes unused capacity from the slice, returning s[:len(s):len(s)]. -func Clip[S ~[]E, E any](s S) S { - return s[:len(s):len(s)] -} diff --git a/vendor/golang.org/x/exp/slices/sort.go b/vendor/golang.org/x/exp/slices/sort.go deleted file mode 100644 index 231b644..0000000 --- a/vendor/golang.org/x/exp/slices/sort.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slices - -import ( - "math/bits" - - "golang.org/x/exp/constraints" -) - -// Sort sorts a slice of any ordered type in ascending order. -// Sort may fail to sort correctly when sorting slices of floating-point -// numbers containing Not-a-number (NaN) values. -// Use slices.SortFunc(x, func(a, b float64) bool {return a < b || (math.IsNaN(a) && !math.IsNaN(b))}) -// instead if the input may contain NaNs. -func Sort[E constraints.Ordered](x []E) { - n := len(x) - pdqsortOrdered(x, 0, n, bits.Len(uint(n))) -} - -// SortFunc sorts the slice x in ascending order as determined by the less function. -// This sort is not guaranteed to be stable. -// -// SortFunc requires that less is a strict weak ordering. -// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings. -func SortFunc[E any](x []E, less func(a, b E) bool) { - n := len(x) - pdqsortLessFunc(x, 0, n, bits.Len(uint(n)), less) -} - -// SortStableFunc sorts the slice x while keeping the original order of equal -// elements, using less to compare elements. -func SortStableFunc[E any](x []E, less func(a, b E) bool) { - stableLessFunc(x, len(x), less) -} - -// IsSorted reports whether x is sorted in ascending order. -func IsSorted[E constraints.Ordered](x []E) bool { - for i := len(x) - 1; i > 0; i-- { - if x[i] < x[i-1] { - return false - } - } - return true -} - -// IsSortedFunc reports whether x is sorted in ascending order, with less as the -// comparison function. -func IsSortedFunc[E any](x []E, less func(a, b E) bool) bool { - for i := len(x) - 1; i > 0; i-- { - if less(x[i], x[i-1]) { - return false - } - } - return true -} - -// BinarySearch searches for target in a sorted slice and returns the position -// where target is found, or the position where target would appear in the -// sort order; it also returns a bool saying whether the target is really found -// in the slice. The slice must be sorted in increasing order. -func BinarySearch[E constraints.Ordered](x []E, target E) (int, bool) { - // Inlining is faster than calling BinarySearchFunc with a lambda. - n := len(x) - // Define x[-1] < target and x[n] >= target. - // Invariant: x[i-1] < target, x[j] >= target. - i, j := 0, n - for i < j { - h := int(uint(i+j) >> 1) // avoid overflow when computing h - // i ≤ h < j - if x[h] < target { - i = h + 1 // preserves x[i-1] < target - } else { - j = h // preserves x[j] >= target - } - } - // i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i. - return i, i < n && x[i] == target -} - -// BinarySearchFunc works like BinarySearch, but uses a custom comparison -// function. The slice must be sorted in increasing order, where "increasing" -// is defined by cmp. cmp should return 0 if the slice element matches -// the target, a negative number if the slice element precedes the target, -// or a positive number if the slice element follows the target. -// cmp must implement the same ordering as the slice, such that if -// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice. -func BinarySearchFunc[E, T any](x []E, target T, cmp func(E, T) int) (int, bool) { - n := len(x) - // Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 . - // Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0. - i, j := 0, n - for i < j { - h := int(uint(i+j) >> 1) // avoid overflow when computing h - // i ≤ h < j - if cmp(x[h], target) < 0 { - i = h + 1 // preserves cmp(x[i - 1], target) < 0 - } else { - j = h // preserves cmp(x[j], target) >= 0 - } - } - // i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i. - return i, i < n && cmp(x[i], target) == 0 -} - -type sortedHint int // hint for pdqsort when choosing the pivot - -const ( - unknownHint sortedHint = iota - increasingHint - decreasingHint -) - -// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf -type xorshift uint64 - -func (r *xorshift) Next() uint64 { - *r ^= *r << 13 - *r ^= *r >> 17 - *r ^= *r << 5 - return uint64(*r) -} - -func nextPowerOfTwo(length int) uint { - return 1 << bits.Len(uint(length)) -} diff --git a/vendor/golang.org/x/exp/slices/zsortfunc.go b/vendor/golang.org/x/exp/slices/zsortfunc.go deleted file mode 100644 index 2a63247..0000000 --- a/vendor/golang.org/x/exp/slices/zsortfunc.go +++ /dev/null @@ -1,479 +0,0 @@ -// Code generated by gen_sort_variants.go; DO NOT EDIT. - -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slices - -// insertionSortLessFunc sorts data[a:b] using insertion sort. -func insertionSortLessFunc[E any](data []E, a, b int, less func(a, b E) bool) { - for i := a + 1; i < b; i++ { - for j := i; j > a && less(data[j], data[j-1]); j-- { - data[j], data[j-1] = data[j-1], data[j] - } - } -} - -// siftDownLessFunc implements the heap property on data[lo:hi]. -// first is an offset into the array where the root of the heap lies. -func siftDownLessFunc[E any](data []E, lo, hi, first int, less func(a, b E) bool) { - root := lo - for { - child := 2*root + 1 - if child >= hi { - break - } - if child+1 < hi && less(data[first+child], data[first+child+1]) { - child++ - } - if !less(data[first+root], data[first+child]) { - return - } - data[first+root], data[first+child] = data[first+child], data[first+root] - root = child - } -} - -func heapSortLessFunc[E any](data []E, a, b int, less func(a, b E) bool) { - first := a - lo := 0 - hi := b - a - - // Build heap with greatest element at top. - for i := (hi - 1) / 2; i >= 0; i-- { - siftDownLessFunc(data, i, hi, first, less) - } - - // Pop elements, largest first, into end of data. - for i := hi - 1; i >= 0; i-- { - data[first], data[first+i] = data[first+i], data[first] - siftDownLessFunc(data, lo, i, first, less) - } -} - -// pdqsortLessFunc sorts data[a:b]. -// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort. -// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf -// C++ implementation: https://github.com/orlp/pdqsort -// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/ -// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort. -func pdqsortLessFunc[E any](data []E, a, b, limit int, less func(a, b E) bool) { - const maxInsertion = 12 - - var ( - wasBalanced = true // whether the last partitioning was reasonably balanced - wasPartitioned = true // whether the slice was already partitioned - ) - - for { - length := b - a - - if length <= maxInsertion { - insertionSortLessFunc(data, a, b, less) - return - } - - // Fall back to heapsort if too many bad choices were made. - if limit == 0 { - heapSortLessFunc(data, a, b, less) - return - } - - // If the last partitioning was imbalanced, we need to breaking patterns. - if !wasBalanced { - breakPatternsLessFunc(data, a, b, less) - limit-- - } - - pivot, hint := choosePivotLessFunc(data, a, b, less) - if hint == decreasingHint { - reverseRangeLessFunc(data, a, b, less) - // The chosen pivot was pivot-a elements after the start of the array. - // After reversing it is pivot-a elements before the end of the array. - // The idea came from Rust's implementation. - pivot = (b - 1) - (pivot - a) - hint = increasingHint - } - - // The slice is likely already sorted. - if wasBalanced && wasPartitioned && hint == increasingHint { - if partialInsertionSortLessFunc(data, a, b, less) { - return - } - } - - // Probably the slice contains many duplicate elements, partition the slice into - // elements equal to and elements greater than the pivot. - if a > 0 && !less(data[a-1], data[pivot]) { - mid := partitionEqualLessFunc(data, a, b, pivot, less) - a = mid - continue - } - - mid, alreadyPartitioned := partitionLessFunc(data, a, b, pivot, less) - wasPartitioned = alreadyPartitioned - - leftLen, rightLen := mid-a, b-mid - balanceThreshold := length / 8 - if leftLen < rightLen { - wasBalanced = leftLen >= balanceThreshold - pdqsortLessFunc(data, a, mid, limit, less) - a = mid + 1 - } else { - wasBalanced = rightLen >= balanceThreshold - pdqsortLessFunc(data, mid+1, b, limit, less) - b = mid - } - } -} - -// partitionLessFunc does one quicksort partition. -// Let p = data[pivot] -// Moves elements in data[a:b] around, so that data[i]

=p for inewpivot. -// On return, data[newpivot] = p -func partitionLessFunc[E any](data []E, a, b, pivot int, less func(a, b E) bool) (newpivot int, alreadyPartitioned bool) { - data[a], data[pivot] = data[pivot], data[a] - i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned - - for i <= j && less(data[i], data[a]) { - i++ - } - for i <= j && !less(data[j], data[a]) { - j-- - } - if i > j { - data[j], data[a] = data[a], data[j] - return j, true - } - data[i], data[j] = data[j], data[i] - i++ - j-- - - for { - for i <= j && less(data[i], data[a]) { - i++ - } - for i <= j && !less(data[j], data[a]) { - j-- - } - if i > j { - break - } - data[i], data[j] = data[j], data[i] - i++ - j-- - } - data[j], data[a] = data[a], data[j] - return j, false -} - -// partitionEqualLessFunc partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot]. -// It assumed that data[a:b] does not contain elements smaller than the data[pivot]. -func partitionEqualLessFunc[E any](data []E, a, b, pivot int, less func(a, b E) bool) (newpivot int) { - data[a], data[pivot] = data[pivot], data[a] - i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned - - for { - for i <= j && !less(data[a], data[i]) { - i++ - } - for i <= j && less(data[a], data[j]) { - j-- - } - if i > j { - break - } - data[i], data[j] = data[j], data[i] - i++ - j-- - } - return i -} - -// partialInsertionSortLessFunc partially sorts a slice, returns true if the slice is sorted at the end. -func partialInsertionSortLessFunc[E any](data []E, a, b int, less func(a, b E) bool) bool { - const ( - maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted - shortestShifting = 50 // don't shift any elements on short arrays - ) - i := a + 1 - for j := 0; j < maxSteps; j++ { - for i < b && !less(data[i], data[i-1]) { - i++ - } - - if i == b { - return true - } - - if b-a < shortestShifting { - return false - } - - data[i], data[i-1] = data[i-1], data[i] - - // Shift the smaller one to the left. - if i-a >= 2 { - for j := i - 1; j >= 1; j-- { - if !less(data[j], data[j-1]) { - break - } - data[j], data[j-1] = data[j-1], data[j] - } - } - // Shift the greater one to the right. - if b-i >= 2 { - for j := i + 1; j < b; j++ { - if !less(data[j], data[j-1]) { - break - } - data[j], data[j-1] = data[j-1], data[j] - } - } - } - return false -} - -// breakPatternsLessFunc scatters some elements around in an attempt to break some patterns -// that might cause imbalanced partitions in quicksort. -func breakPatternsLessFunc[E any](data []E, a, b int, less func(a, b E) bool) { - length := b - a - if length >= 8 { - random := xorshift(length) - modulus := nextPowerOfTwo(length) - - for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ { - other := int(uint(random.Next()) & (modulus - 1)) - if other >= length { - other -= length - } - data[idx], data[a+other] = data[a+other], data[idx] - } - } -} - -// choosePivotLessFunc chooses a pivot in data[a:b]. -// -// [0,8): chooses a static pivot. -// [8,shortestNinther): uses the simple median-of-three method. -// [shortestNinther,∞): uses the Tukey ninther method. -func choosePivotLessFunc[E any](data []E, a, b int, less func(a, b E) bool) (pivot int, hint sortedHint) { - const ( - shortestNinther = 50 - maxSwaps = 4 * 3 - ) - - l := b - a - - var ( - swaps int - i = a + l/4*1 - j = a + l/4*2 - k = a + l/4*3 - ) - - if l >= 8 { - if l >= shortestNinther { - // Tukey ninther method, the idea came from Rust's implementation. - i = medianAdjacentLessFunc(data, i, &swaps, less) - j = medianAdjacentLessFunc(data, j, &swaps, less) - k = medianAdjacentLessFunc(data, k, &swaps, less) - } - // Find the median among i, j, k and stores it into j. - j = medianLessFunc(data, i, j, k, &swaps, less) - } - - switch swaps { - case 0: - return j, increasingHint - case maxSwaps: - return j, decreasingHint - default: - return j, unknownHint - } -} - -// order2LessFunc returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a. -func order2LessFunc[E any](data []E, a, b int, swaps *int, less func(a, b E) bool) (int, int) { - if less(data[b], data[a]) { - *swaps++ - return b, a - } - return a, b -} - -// medianLessFunc returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c. -func medianLessFunc[E any](data []E, a, b, c int, swaps *int, less func(a, b E) bool) int { - a, b = order2LessFunc(data, a, b, swaps, less) - b, c = order2LessFunc(data, b, c, swaps, less) - a, b = order2LessFunc(data, a, b, swaps, less) - return b -} - -// medianAdjacentLessFunc finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a. -func medianAdjacentLessFunc[E any](data []E, a int, swaps *int, less func(a, b E) bool) int { - return medianLessFunc(data, a-1, a, a+1, swaps, less) -} - -func reverseRangeLessFunc[E any](data []E, a, b int, less func(a, b E) bool) { - i := a - j := b - 1 - for i < j { - data[i], data[j] = data[j], data[i] - i++ - j-- - } -} - -func swapRangeLessFunc[E any](data []E, a, b, n int, less func(a, b E) bool) { - for i := 0; i < n; i++ { - data[a+i], data[b+i] = data[b+i], data[a+i] - } -} - -func stableLessFunc[E any](data []E, n int, less func(a, b E) bool) { - blockSize := 20 // must be > 0 - a, b := 0, blockSize - for b <= n { - insertionSortLessFunc(data, a, b, less) - a = b - b += blockSize - } - insertionSortLessFunc(data, a, n, less) - - for blockSize < n { - a, b = 0, 2*blockSize - for b <= n { - symMergeLessFunc(data, a, a+blockSize, b, less) - a = b - b += 2 * blockSize - } - if m := a + blockSize; m < n { - symMergeLessFunc(data, a, m, n, less) - } - blockSize *= 2 - } -} - -// symMergeLessFunc merges the two sorted subsequences data[a:m] and data[m:b] using -// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum -// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz -// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in -// Computer Science, pages 714-723. Springer, 2004. -// -// Let M = m-a and N = b-n. Wolog M < N. -// The recursion depth is bound by ceil(log(N+M)). -// The algorithm needs O(M*log(N/M + 1)) calls to data.Less. -// The algorithm needs O((M+N)*log(M)) calls to data.Swap. -// -// The paper gives O((M+N)*log(M)) as the number of assignments assuming a -// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation -// in the paper carries through for Swap operations, especially as the block -// swapping rotate uses only O(M+N) Swaps. -// -// symMerge assumes non-degenerate arguments: a < m && m < b. -// Having the caller check this condition eliminates many leaf recursion calls, -// which improves performance. -func symMergeLessFunc[E any](data []E, a, m, b int, less func(a, b E) bool) { - // Avoid unnecessary recursions of symMerge - // by direct insertion of data[a] into data[m:b] - // if data[a:m] only contains one element. - if m-a == 1 { - // Use binary search to find the lowest index i - // such that data[i] >= data[a] for m <= i < b. - // Exit the search loop with i == b in case no such index exists. - i := m - j := b - for i < j { - h := int(uint(i+j) >> 1) - if less(data[h], data[a]) { - i = h + 1 - } else { - j = h - } - } - // Swap values until data[a] reaches the position before i. - for k := a; k < i-1; k++ { - data[k], data[k+1] = data[k+1], data[k] - } - return - } - - // Avoid unnecessary recursions of symMerge - // by direct insertion of data[m] into data[a:m] - // if data[m:b] only contains one element. - if b-m == 1 { - // Use binary search to find the lowest index i - // such that data[i] > data[m] for a <= i < m. - // Exit the search loop with i == m in case no such index exists. - i := a - j := m - for i < j { - h := int(uint(i+j) >> 1) - if !less(data[m], data[h]) { - i = h + 1 - } else { - j = h - } - } - // Swap values until data[m] reaches the position i. - for k := m; k > i; k-- { - data[k], data[k-1] = data[k-1], data[k] - } - return - } - - mid := int(uint(a+b) >> 1) - n := mid + m - var start, r int - if m > mid { - start = n - b - r = mid - } else { - start = a - r = m - } - p := n - 1 - - for start < r { - c := int(uint(start+r) >> 1) - if !less(data[p-c], data[c]) { - start = c + 1 - } else { - r = c - } - } - - end := n - start - if start < m && m < end { - rotateLessFunc(data, start, m, end, less) - } - if a < start && start < mid { - symMergeLessFunc(data, a, start, mid, less) - } - if mid < end && end < b { - symMergeLessFunc(data, mid, end, b, less) - } -} - -// rotateLessFunc rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data: -// Data of the form 'x u v y' is changed to 'x v u y'. -// rotate performs at most b-a many calls to data.Swap, -// and it assumes non-degenerate arguments: a < m && m < b. -func rotateLessFunc[E any](data []E, a, m, b int, less func(a, b E) bool) { - i := m - a - j := b - m - - for i != j { - if i > j { - swapRangeLessFunc(data, m-i, m, j, less) - i -= j - } else { - swapRangeLessFunc(data, m-i, m+j-i, i, less) - j -= i - } - } - // i == j - swapRangeLessFunc(data, m-i, m, i, less) -} diff --git a/vendor/golang.org/x/exp/slices/zsortordered.go b/vendor/golang.org/x/exp/slices/zsortordered.go deleted file mode 100644 index efaa1c8..0000000 --- a/vendor/golang.org/x/exp/slices/zsortordered.go +++ /dev/null @@ -1,481 +0,0 @@ -// Code generated by gen_sort_variants.go; DO NOT EDIT. - -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slices - -import "golang.org/x/exp/constraints" - -// insertionSortOrdered sorts data[a:b] using insertion sort. -func insertionSortOrdered[E constraints.Ordered](data []E, a, b int) { - for i := a + 1; i < b; i++ { - for j := i; j > a && (data[j] < data[j-1]); j-- { - data[j], data[j-1] = data[j-1], data[j] - } - } -} - -// siftDownOrdered implements the heap property on data[lo:hi]. -// first is an offset into the array where the root of the heap lies. -func siftDownOrdered[E constraints.Ordered](data []E, lo, hi, first int) { - root := lo - for { - child := 2*root + 1 - if child >= hi { - break - } - if child+1 < hi && (data[first+child] < data[first+child+1]) { - child++ - } - if !(data[first+root] < data[first+child]) { - return - } - data[first+root], data[first+child] = data[first+child], data[first+root] - root = child - } -} - -func heapSortOrdered[E constraints.Ordered](data []E, a, b int) { - first := a - lo := 0 - hi := b - a - - // Build heap with greatest element at top. - for i := (hi - 1) / 2; i >= 0; i-- { - siftDownOrdered(data, i, hi, first) - } - - // Pop elements, largest first, into end of data. - for i := hi - 1; i >= 0; i-- { - data[first], data[first+i] = data[first+i], data[first] - siftDownOrdered(data, lo, i, first) - } -} - -// pdqsortOrdered sorts data[a:b]. -// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort. -// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf -// C++ implementation: https://github.com/orlp/pdqsort -// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/ -// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort. -func pdqsortOrdered[E constraints.Ordered](data []E, a, b, limit int) { - const maxInsertion = 12 - - var ( - wasBalanced = true // whether the last partitioning was reasonably balanced - wasPartitioned = true // whether the slice was already partitioned - ) - - for { - length := b - a - - if length <= maxInsertion { - insertionSortOrdered(data, a, b) - return - } - - // Fall back to heapsort if too many bad choices were made. - if limit == 0 { - heapSortOrdered(data, a, b) - return - } - - // If the last partitioning was imbalanced, we need to breaking patterns. - if !wasBalanced { - breakPatternsOrdered(data, a, b) - limit-- - } - - pivot, hint := choosePivotOrdered(data, a, b) - if hint == decreasingHint { - reverseRangeOrdered(data, a, b) - // The chosen pivot was pivot-a elements after the start of the array. - // After reversing it is pivot-a elements before the end of the array. - // The idea came from Rust's implementation. - pivot = (b - 1) - (pivot - a) - hint = increasingHint - } - - // The slice is likely already sorted. - if wasBalanced && wasPartitioned && hint == increasingHint { - if partialInsertionSortOrdered(data, a, b) { - return - } - } - - // Probably the slice contains many duplicate elements, partition the slice into - // elements equal to and elements greater than the pivot. - if a > 0 && !(data[a-1] < data[pivot]) { - mid := partitionEqualOrdered(data, a, b, pivot) - a = mid - continue - } - - mid, alreadyPartitioned := partitionOrdered(data, a, b, pivot) - wasPartitioned = alreadyPartitioned - - leftLen, rightLen := mid-a, b-mid - balanceThreshold := length / 8 - if leftLen < rightLen { - wasBalanced = leftLen >= balanceThreshold - pdqsortOrdered(data, a, mid, limit) - a = mid + 1 - } else { - wasBalanced = rightLen >= balanceThreshold - pdqsortOrdered(data, mid+1, b, limit) - b = mid - } - } -} - -// partitionOrdered does one quicksort partition. -// Let p = data[pivot] -// Moves elements in data[a:b] around, so that data[i]

=p for inewpivot. -// On return, data[newpivot] = p -func partitionOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int, alreadyPartitioned bool) { - data[a], data[pivot] = data[pivot], data[a] - i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned - - for i <= j && (data[i] < data[a]) { - i++ - } - for i <= j && !(data[j] < data[a]) { - j-- - } - if i > j { - data[j], data[a] = data[a], data[j] - return j, true - } - data[i], data[j] = data[j], data[i] - i++ - j-- - - for { - for i <= j && (data[i] < data[a]) { - i++ - } - for i <= j && !(data[j] < data[a]) { - j-- - } - if i > j { - break - } - data[i], data[j] = data[j], data[i] - i++ - j-- - } - data[j], data[a] = data[a], data[j] - return j, false -} - -// partitionEqualOrdered partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot]. -// It assumed that data[a:b] does not contain elements smaller than the data[pivot]. -func partitionEqualOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int) { - data[a], data[pivot] = data[pivot], data[a] - i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned - - for { - for i <= j && !(data[a] < data[i]) { - i++ - } - for i <= j && (data[a] < data[j]) { - j-- - } - if i > j { - break - } - data[i], data[j] = data[j], data[i] - i++ - j-- - } - return i -} - -// partialInsertionSortOrdered partially sorts a slice, returns true if the slice is sorted at the end. -func partialInsertionSortOrdered[E constraints.Ordered](data []E, a, b int) bool { - const ( - maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted - shortestShifting = 50 // don't shift any elements on short arrays - ) - i := a + 1 - for j := 0; j < maxSteps; j++ { - for i < b && !(data[i] < data[i-1]) { - i++ - } - - if i == b { - return true - } - - if b-a < shortestShifting { - return false - } - - data[i], data[i-1] = data[i-1], data[i] - - // Shift the smaller one to the left. - if i-a >= 2 { - for j := i - 1; j >= 1; j-- { - if !(data[j] < data[j-1]) { - break - } - data[j], data[j-1] = data[j-1], data[j] - } - } - // Shift the greater one to the right. - if b-i >= 2 { - for j := i + 1; j < b; j++ { - if !(data[j] < data[j-1]) { - break - } - data[j], data[j-1] = data[j-1], data[j] - } - } - } - return false -} - -// breakPatternsOrdered scatters some elements around in an attempt to break some patterns -// that might cause imbalanced partitions in quicksort. -func breakPatternsOrdered[E constraints.Ordered](data []E, a, b int) { - length := b - a - if length >= 8 { - random := xorshift(length) - modulus := nextPowerOfTwo(length) - - for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ { - other := int(uint(random.Next()) & (modulus - 1)) - if other >= length { - other -= length - } - data[idx], data[a+other] = data[a+other], data[idx] - } - } -} - -// choosePivotOrdered chooses a pivot in data[a:b]. -// -// [0,8): chooses a static pivot. -// [8,shortestNinther): uses the simple median-of-three method. -// [shortestNinther,∞): uses the Tukey ninther method. -func choosePivotOrdered[E constraints.Ordered](data []E, a, b int) (pivot int, hint sortedHint) { - const ( - shortestNinther = 50 - maxSwaps = 4 * 3 - ) - - l := b - a - - var ( - swaps int - i = a + l/4*1 - j = a + l/4*2 - k = a + l/4*3 - ) - - if l >= 8 { - if l >= shortestNinther { - // Tukey ninther method, the idea came from Rust's implementation. - i = medianAdjacentOrdered(data, i, &swaps) - j = medianAdjacentOrdered(data, j, &swaps) - k = medianAdjacentOrdered(data, k, &swaps) - } - // Find the median among i, j, k and stores it into j. - j = medianOrdered(data, i, j, k, &swaps) - } - - switch swaps { - case 0: - return j, increasingHint - case maxSwaps: - return j, decreasingHint - default: - return j, unknownHint - } -} - -// order2Ordered returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a. -func order2Ordered[E constraints.Ordered](data []E, a, b int, swaps *int) (int, int) { - if data[b] < data[a] { - *swaps++ - return b, a - } - return a, b -} - -// medianOrdered returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c. -func medianOrdered[E constraints.Ordered](data []E, a, b, c int, swaps *int) int { - a, b = order2Ordered(data, a, b, swaps) - b, c = order2Ordered(data, b, c, swaps) - a, b = order2Ordered(data, a, b, swaps) - return b -} - -// medianAdjacentOrdered finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a. -func medianAdjacentOrdered[E constraints.Ordered](data []E, a int, swaps *int) int { - return medianOrdered(data, a-1, a, a+1, swaps) -} - -func reverseRangeOrdered[E constraints.Ordered](data []E, a, b int) { - i := a - j := b - 1 - for i < j { - data[i], data[j] = data[j], data[i] - i++ - j-- - } -} - -func swapRangeOrdered[E constraints.Ordered](data []E, a, b, n int) { - for i := 0; i < n; i++ { - data[a+i], data[b+i] = data[b+i], data[a+i] - } -} - -func stableOrdered[E constraints.Ordered](data []E, n int) { - blockSize := 20 // must be > 0 - a, b := 0, blockSize - for b <= n { - insertionSortOrdered(data, a, b) - a = b - b += blockSize - } - insertionSortOrdered(data, a, n) - - for blockSize < n { - a, b = 0, 2*blockSize - for b <= n { - symMergeOrdered(data, a, a+blockSize, b) - a = b - b += 2 * blockSize - } - if m := a + blockSize; m < n { - symMergeOrdered(data, a, m, n) - } - blockSize *= 2 - } -} - -// symMergeOrdered merges the two sorted subsequences data[a:m] and data[m:b] using -// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum -// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz -// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in -// Computer Science, pages 714-723. Springer, 2004. -// -// Let M = m-a and N = b-n. Wolog M < N. -// The recursion depth is bound by ceil(log(N+M)). -// The algorithm needs O(M*log(N/M + 1)) calls to data.Less. -// The algorithm needs O((M+N)*log(M)) calls to data.Swap. -// -// The paper gives O((M+N)*log(M)) as the number of assignments assuming a -// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation -// in the paper carries through for Swap operations, especially as the block -// swapping rotate uses only O(M+N) Swaps. -// -// symMerge assumes non-degenerate arguments: a < m && m < b. -// Having the caller check this condition eliminates many leaf recursion calls, -// which improves performance. -func symMergeOrdered[E constraints.Ordered](data []E, a, m, b int) { - // Avoid unnecessary recursions of symMerge - // by direct insertion of data[a] into data[m:b] - // if data[a:m] only contains one element. - if m-a == 1 { - // Use binary search to find the lowest index i - // such that data[i] >= data[a] for m <= i < b. - // Exit the search loop with i == b in case no such index exists. - i := m - j := b - for i < j { - h := int(uint(i+j) >> 1) - if data[h] < data[a] { - i = h + 1 - } else { - j = h - } - } - // Swap values until data[a] reaches the position before i. - for k := a; k < i-1; k++ { - data[k], data[k+1] = data[k+1], data[k] - } - return - } - - // Avoid unnecessary recursions of symMerge - // by direct insertion of data[m] into data[a:m] - // if data[m:b] only contains one element. - if b-m == 1 { - // Use binary search to find the lowest index i - // such that data[i] > data[m] for a <= i < m. - // Exit the search loop with i == m in case no such index exists. - i := a - j := m - for i < j { - h := int(uint(i+j) >> 1) - if !(data[m] < data[h]) { - i = h + 1 - } else { - j = h - } - } - // Swap values until data[m] reaches the position i. - for k := m; k > i; k-- { - data[k], data[k-1] = data[k-1], data[k] - } - return - } - - mid := int(uint(a+b) >> 1) - n := mid + m - var start, r int - if m > mid { - start = n - b - r = mid - } else { - start = a - r = m - } - p := n - 1 - - for start < r { - c := int(uint(start+r) >> 1) - if !(data[p-c] < data[c]) { - start = c + 1 - } else { - r = c - } - } - - end := n - start - if start < m && m < end { - rotateOrdered(data, start, m, end) - } - if a < start && start < mid { - symMergeOrdered(data, a, start, mid) - } - if mid < end && end < b { - symMergeOrdered(data, mid, end, b) - } -} - -// rotateOrdered rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data: -// Data of the form 'x u v y' is changed to 'x v u y'. -// rotate performs at most b-a many calls to data.Swap, -// and it assumes non-degenerate arguments: a < m && m < b. -func rotateOrdered[E constraints.Ordered](data []E, a, m, b int) { - i := m - a - j := b - m - - for i != j { - if i > j { - swapRangeOrdered(data, m-i, m, j) - i -= j - } else { - swapRangeOrdered(data, m-i, m+j-i, i) - j -= i - } - } - // i == j - swapRangeOrdered(data, m-i, m, i) -} diff --git a/vendor/golang.org/x/exp/slog/attr.go b/vendor/golang.org/x/exp/slog/attr.go deleted file mode 100644 index a180d0e..0000000 --- a/vendor/golang.org/x/exp/slog/attr.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slog - -import ( - "fmt" - "time" -) - -// An Attr is a key-value pair. -type Attr struct { - Key string - Value Value -} - -// String returns an Attr for a string value. -func String(key, value string) Attr { - return Attr{key, StringValue(value)} -} - -// Int64 returns an Attr for an int64. -func Int64(key string, value int64) Attr { - return Attr{key, Int64Value(value)} -} - -// Int converts an int to an int64 and returns -// an Attr with that value. -func Int(key string, value int) Attr { - return Int64(key, int64(value)) -} - -// Uint64 returns an Attr for a uint64. -func Uint64(key string, v uint64) Attr { - return Attr{key, Uint64Value(v)} -} - -// Float64 returns an Attr for a floating-point number. -func Float64(key string, v float64) Attr { - return Attr{key, Float64Value(v)} -} - -// Bool returns an Attr for a bool. -func Bool(key string, v bool) Attr { - return Attr{key, BoolValue(v)} -} - -// Time returns an Attr for a time.Time. -// It discards the monotonic portion. -func Time(key string, v time.Time) Attr { - return Attr{key, TimeValue(v)} -} - -// Duration returns an Attr for a time.Duration. -func Duration(key string, v time.Duration) Attr { - return Attr{key, DurationValue(v)} -} - -// Group returns an Attr for a Group Value. -// The first argument is the key; the remaining arguments -// are converted to Attrs as in [Logger.Log]. -// -// Use Group to collect several key-value pairs under a single -// key on a log line, or as the result of LogValue -// in order to log a single value as multiple Attrs. -func Group(key string, args ...any) Attr { - return Attr{key, GroupValue(argsToAttrSlice(args)...)} -} - -func argsToAttrSlice(args []any) []Attr { - var ( - attr Attr - attrs []Attr - ) - for len(args) > 0 { - attr, args = argsToAttr(args) - attrs = append(attrs, attr) - } - return attrs -} - -// Any returns an Attr for the supplied value. -// See [Value.AnyValue] for how values are treated. -func Any(key string, value any) Attr { - return Attr{key, AnyValue(value)} -} - -// Equal reports whether a and b have equal keys and values. -func (a Attr) Equal(b Attr) bool { - return a.Key == b.Key && a.Value.Equal(b.Value) -} - -func (a Attr) String() string { - return fmt.Sprintf("%s=%s", a.Key, a.Value) -} - -// isEmpty reports whether a has an empty key and a nil value. -// That can be written as Attr{} or Any("", nil). -func (a Attr) isEmpty() bool { - return a.Key == "" && a.Value.num == 0 && a.Value.any == nil -} diff --git a/vendor/golang.org/x/exp/slog/doc.go b/vendor/golang.org/x/exp/slog/doc.go deleted file mode 100644 index 4beaf86..0000000 --- a/vendor/golang.org/x/exp/slog/doc.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package slog provides structured logging, -in which log records include a message, -a severity level, and various other attributes -expressed as key-value pairs. - -It defines a type, [Logger], -which provides several methods (such as [Logger.Info] and [Logger.Error]) -for reporting events of interest. - -Each Logger is associated with a [Handler]. -A Logger output method creates a [Record] from the method arguments -and passes it to the Handler, which decides how to handle it. -There is a default Logger accessible through top-level functions -(such as [Info] and [Error]) that call the corresponding Logger methods. - -A log record consists of a time, a level, a message, and a set of key-value -pairs, where the keys are strings and the values may be of any type. -As an example, - - slog.Info("hello", "count", 3) - -creates a record containing the time of the call, -a level of Info, the message "hello", and a single -pair with key "count" and value 3. - -The [Info] top-level function calls the [Logger.Info] method on the default Logger. -In addition to [Logger.Info], there are methods for Debug, Warn and Error levels. -Besides these convenience methods for common levels, -there is also a [Logger.Log] method which takes the level as an argument. -Each of these methods has a corresponding top-level function that uses the -default logger. - -The default handler formats the log record's message, time, level, and attributes -as a string and passes it to the [log] package. - - 2022/11/08 15:28:26 INFO hello count=3 - -For more control over the output format, create a logger with a different handler. -This statement uses [New] to create a new logger with a TextHandler -that writes structured records in text form to standard error: - - logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) - -[TextHandler] output is a sequence of key=value pairs, easily and unambiguously -parsed by machine. This statement: - - logger.Info("hello", "count", 3) - -produces this output: - - time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3 - -The package also provides [JSONHandler], whose output is line-delimited JSON: - - logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) - logger.Info("hello", "count", 3) - -produces this output: - - {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3} - -Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions]. -There are options for setting the minimum level (see Levels, below), -displaying the source file and line of the log call, and -modifying attributes before they are logged. - -Setting a logger as the default with - - slog.SetDefault(logger) - -will cause the top-level functions like [Info] to use it. -[SetDefault] also updates the default logger used by the [log] package, -so that existing applications that use [log.Printf] and related functions -will send log records to the logger's handler without needing to be rewritten. - -Some attributes are common to many log calls. -For example, you may wish to include the URL or trace identifier of a server request -with all log events arising from the request. -Rather than repeat the attribute with every log call, you can use [Logger.With] -to construct a new Logger containing the attributes: - - logger2 := logger.With("url", r.URL) - -The arguments to With are the same key-value pairs used in [Logger.Info]. -The result is a new Logger with the same handler as the original, but additional -attributes that will appear in the output of every call. - -# Levels - -A [Level] is an integer representing the importance or severity of a log event. -The higher the level, the more severe the event. -This package defines constants for the most common levels, -but any int can be used as a level. - -In an application, you may wish to log messages only at a certain level or greater. -One common configuration is to log messages at Info or higher levels, -suppressing debug logging until it is needed. -The built-in handlers can be configured with the minimum level to output by -setting [HandlerOptions.Level]. -The program's `main` function typically does this. -The default value is LevelInfo. - -Setting the [HandlerOptions.Level] field to a [Level] value -fixes the handler's minimum level throughout its lifetime. -Setting it to a [LevelVar] allows the level to be varied dynamically. -A LevelVar holds a Level and is safe to read or write from multiple -goroutines. -To vary the level dynamically for an entire program, first initialize -a global LevelVar: - - var programLevel = new(slog.LevelVar) // Info by default - -Then use the LevelVar to construct a handler, and make it the default: - - h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) - slog.SetDefault(slog.New(h)) - -Now the program can change its logging level with a single statement: - - programLevel.Set(slog.LevelDebug) - -# Groups - -Attributes can be collected into groups. -A group has a name that is used to qualify the names of its attributes. -How this qualification is displayed depends on the handler. -[TextHandler] separates the group and attribute names with a dot. -[JSONHandler] treats each group as a separate JSON object, with the group name as the key. - -Use [Group] to create a Group attribute from a name and a list of key-value pairs: - - slog.Group("request", - "method", r.Method, - "url", r.URL) - -TextHandler would display this group as - - request.method=GET request.url=http://example.com - -JSONHandler would display it as - - "request":{"method":"GET","url":"http://example.com"} - -Use [Logger.WithGroup] to qualify all of a Logger's output -with a group name. Calling WithGroup on a Logger results in a -new Logger with the same Handler as the original, but with all -its attributes qualified by the group name. - -This can help prevent duplicate attribute keys in large systems, -where subsystems might use the same keys. -Pass each subsystem a different Logger with its own group name so that -potential duplicates are qualified: - - logger := slog.Default().With("id", systemID) - parserLogger := logger.WithGroup("parser") - parseInput(input, parserLogger) - -When parseInput logs with parserLogger, its keys will be qualified with "parser", -so even if it uses the common key "id", the log line will have distinct keys. - -# Contexts - -Some handlers may wish to include information from the [context.Context] that is -available at the call site. One example of such information -is the identifier for the current span when tracing is enabled. - -The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first -argument, as do their corresponding top-level functions. - -Although the convenience methods on Logger (Info and so on) and the -corresponding top-level functions do not take a context, the alternatives ending -in "Context" do. For example, - - slog.InfoContext(ctx, "message") - -It is recommended to pass a context to an output method if one is available. - -# Attrs and Values - -An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as -alternating keys and values. The statement - - slog.Info("hello", slog.Int("count", 3)) - -behaves the same as - - slog.Info("hello", "count", 3) - -There are convenience constructors for [Attr] such as [Int], [String], and [Bool] -for common types, as well as the function [Any] for constructing Attrs of any -type. - -The value part of an Attr is a type called [Value]. -Like an [any], a Value can hold any Go value, -but it can represent typical values, including all numbers and strings, -without an allocation. - -For the most efficient log output, use [Logger.LogAttrs]. -It is similar to [Logger.Log] but accepts only Attrs, not alternating -keys and values; this allows it, too, to avoid allocation. - -The call - - logger.LogAttrs(nil, slog.LevelInfo, "hello", slog.Int("count", 3)) - -is the most efficient way to achieve the same output as - - slog.Info("hello", "count", 3) - -# Customizing a type's logging behavior - -If a type implements the [LogValuer] interface, the [Value] returned from its LogValue -method is used for logging. You can use this to control how values of the type -appear in logs. For example, you can redact secret information like passwords, -or gather a struct's fields in a Group. See the examples under [LogValuer] for -details. - -A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve] -method handles these cases carefully, avoiding infinite loops and unbounded recursion. -Handler authors and others may wish to use Value.Resolve instead of calling LogValue directly. - -# Wrapping output methods - -The logger functions use reflection over the call stack to find the file name -and line number of the logging call within the application. This can produce -incorrect source information for functions that wrap slog. For instance, if you -define this function in file mylog.go: - - func Infof(format string, args ...any) { - slog.Default().Info(fmt.Sprintf(format, args...)) - } - -and you call it like this in main.go: - - Infof(slog.Default(), "hello, %s", "world") - -then slog will report the source file as mylog.go, not main.go. - -A correct implementation of Infof will obtain the source location -(pc) and pass it to NewRecord. -The Infof function in the package-level example called "wrapping" -demonstrates how to do this. - -# Working with Records - -Sometimes a Handler will need to modify a Record -before passing it on to another Handler or backend. -A Record contains a mixture of simple public fields (e.g. Time, Level, Message) -and hidden fields that refer to state (such as attributes) indirectly. This -means that modifying a simple copy of a Record (e.g. by calling -[Record.Add] or [Record.AddAttrs] to add attributes) -may have unexpected effects on the original. -Before modifying a Record, use [Clone] to -create a copy that shares no state with the original, -or create a new Record with [NewRecord] -and build up its Attrs by traversing the old ones with [Record.Attrs]. - -# Performance considerations - -If profiling your application demonstrates that logging is taking significant time, -the following suggestions may help. - -If many log lines have a common attribute, use [Logger.With] to create a Logger with -that attribute. The built-in handlers will format that attribute only once, at the -call to [Logger.With]. The [Handler] interface is designed to allow that optimization, -and a well-written Handler should take advantage of it. - -The arguments to a log call are always evaluated, even if the log event is discarded. -If possible, defer computation so that it happens only if the value is actually logged. -For example, consider the call - - slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily - -The URL.String method will be called even if the logger discards Info-level events. -Instead, pass the URL directly: - - slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed - -The built-in [TextHandler] will call its String method, but only -if the log event is enabled. -Avoiding the call to String also preserves the structure of the underlying value. -For example [JSONHandler] emits the components of the parsed URL as a JSON object. -If you want to avoid eagerly paying the cost of the String call -without causing the handler to potentially inspect the structure of the value, -wrap the value in a fmt.Stringer implementation that hides its Marshal methods. - -You can also use the [LogValuer] interface to avoid unnecessary work in disabled log -calls. Say you need to log some expensive value: - - slog.Debug("frobbing", "value", computeExpensiveValue(arg)) - -Even if this line is disabled, computeExpensiveValue will be called. -To avoid that, define a type implementing LogValuer: - - type expensive struct { arg int } - - func (e expensive) LogValue() slog.Value { - return slog.AnyValue(computeExpensiveValue(e.arg)) - } - -Then use a value of that type in log calls: - - slog.Debug("frobbing", "value", expensive{arg}) - -Now computeExpensiveValue will only be called when the line is enabled. - -The built-in handlers acquire a lock before calling [io.Writer.Write] -to ensure that each record is written in one piece. User-defined -handlers are responsible for their own locking. -*/ -package slog diff --git a/vendor/golang.org/x/exp/slog/handler.go b/vendor/golang.org/x/exp/slog/handler.go deleted file mode 100644 index 74f8873..0000000 --- a/vendor/golang.org/x/exp/slog/handler.go +++ /dev/null @@ -1,559 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slog - -import ( - "context" - "fmt" - "io" - "strconv" - "sync" - "time" - - "golang.org/x/exp/slices" - "golang.org/x/exp/slog/internal/buffer" -) - -// A Handler handles log records produced by a Logger.. -// -// A typical handler may print log records to standard error, -// or write them to a file or database, or perhaps augment them -// with additional attributes and pass them on to another handler. -// -// Any of the Handler's methods may be called concurrently with itself -// or with other methods. It is the responsibility of the Handler to -// manage this concurrency. -// -// Users of the slog package should not invoke Handler methods directly. -// They should use the methods of [Logger] instead. -type Handler interface { - // Enabled reports whether the handler handles records at the given level. - // The handler ignores records whose level is lower. - // It is called early, before any arguments are processed, - // to save effort if the log event should be discarded. - // If called from a Logger method, the first argument is the context - // passed to that method, or context.Background() if nil was passed - // or the method does not take a context. - // The context is passed so Enabled can use its values - // to make a decision. - Enabled(context.Context, Level) bool - - // Handle handles the Record. - // It will only be called when Enabled returns true. - // The Context argument is as for Enabled. - // It is present solely to provide Handlers access to the context's values. - // Canceling the context should not affect record processing. - // (Among other things, log messages may be necessary to debug a - // cancellation-related problem.) - // - // Handle methods that produce output should observe the following rules: - // - If r.Time is the zero time, ignore the time. - // - If r.PC is zero, ignore it. - // - Attr's values should be resolved. - // - If an Attr's key and value are both the zero value, ignore the Attr. - // This can be tested with attr.Equal(Attr{}). - // - If a group's key is empty, inline the group's Attrs. - // - If a group has no Attrs (even if it has a non-empty key), - // ignore it. - Handle(context.Context, Record) error - - // WithAttrs returns a new Handler whose attributes consist of - // both the receiver's attributes and the arguments. - // The Handler owns the slice: it may retain, modify or discard it. - WithAttrs(attrs []Attr) Handler - - // WithGroup returns a new Handler with the given group appended to - // the receiver's existing groups. - // The keys of all subsequent attributes, whether added by With or in a - // Record, should be qualified by the sequence of group names. - // - // How this qualification happens is up to the Handler, so long as - // this Handler's attribute keys differ from those of another Handler - // with a different sequence of group names. - // - // A Handler should treat WithGroup as starting a Group of Attrs that ends - // at the end of the log event. That is, - // - // logger.WithGroup("s").LogAttrs(level, msg, slog.Int("a", 1), slog.Int("b", 2)) - // - // should behave like - // - // logger.LogAttrs(level, msg, slog.Group("s", slog.Int("a", 1), slog.Int("b", 2))) - // - // If the name is empty, WithGroup returns the receiver. - WithGroup(name string) Handler -} - -type defaultHandler struct { - ch *commonHandler - // log.Output, except for testing - output func(calldepth int, message string) error -} - -func newDefaultHandler(output func(int, string) error) *defaultHandler { - return &defaultHandler{ - ch: &commonHandler{json: false}, - output: output, - } -} - -func (*defaultHandler) Enabled(_ context.Context, l Level) bool { - return l >= LevelInfo -} - -// Collect the level, attributes and message in a string and -// write it with the default log.Logger. -// Let the log.Logger handle time and file/line. -func (h *defaultHandler) Handle(ctx context.Context, r Record) error { - buf := buffer.New() - buf.WriteString(r.Level.String()) - buf.WriteByte(' ') - buf.WriteString(r.Message) - state := h.ch.newHandleState(buf, true, " ", nil) - defer state.free() - state.appendNonBuiltIns(r) - - // skip [h.output, defaultHandler.Handle, handlerWriter.Write, log.Output] - return h.output(4, buf.String()) -} - -func (h *defaultHandler) WithAttrs(as []Attr) Handler { - return &defaultHandler{h.ch.withAttrs(as), h.output} -} - -func (h *defaultHandler) WithGroup(name string) Handler { - return &defaultHandler{h.ch.withGroup(name), h.output} -} - -// HandlerOptions are options for a TextHandler or JSONHandler. -// A zero HandlerOptions consists entirely of default values. -type HandlerOptions struct { - // AddSource causes the handler to compute the source code position - // of the log statement and add a SourceKey attribute to the output. - AddSource bool - - // Level reports the minimum record level that will be logged. - // The handler discards records with lower levels. - // If Level is nil, the handler assumes LevelInfo. - // The handler calls Level.Level for each record processed; - // to adjust the minimum level dynamically, use a LevelVar. - Level Leveler - - // ReplaceAttr is called to rewrite each non-group attribute before it is logged. - // The attribute's value has been resolved (see [Value.Resolve]). - // If ReplaceAttr returns an Attr with Key == "", the attribute is discarded. - // - // The built-in attributes with keys "time", "level", "source", and "msg" - // are passed to this function, except that time is omitted - // if zero, and source is omitted if AddSource is false. - // - // The first argument is a list of currently open groups that contain the - // Attr. It must not be retained or modified. ReplaceAttr is never called - // for Group attributes, only their contents. For example, the attribute - // list - // - // Int("a", 1), Group("g", Int("b", 2)), Int("c", 3) - // - // results in consecutive calls to ReplaceAttr with the following arguments: - // - // nil, Int("a", 1) - // []string{"g"}, Int("b", 2) - // nil, Int("c", 3) - // - // ReplaceAttr can be used to change the default keys of the built-in - // attributes, convert types (for example, to replace a `time.Time` with the - // integer seconds since the Unix epoch), sanitize personal information, or - // remove attributes from the output. - ReplaceAttr func(groups []string, a Attr) Attr -} - -// Keys for "built-in" attributes. -const ( - // TimeKey is the key used by the built-in handlers for the time - // when the log method is called. The associated Value is a [time.Time]. - TimeKey = "time" - // LevelKey is the key used by the built-in handlers for the level - // of the log call. The associated value is a [Level]. - LevelKey = "level" - // MessageKey is the key used by the built-in handlers for the - // message of the log call. The associated value is a string. - MessageKey = "msg" - // SourceKey is the key used by the built-in handlers for the source file - // and line of the log call. The associated value is a string. - SourceKey = "source" -) - -type commonHandler struct { - json bool // true => output JSON; false => output text - opts HandlerOptions - preformattedAttrs []byte - groupPrefix string // for text: prefix of groups opened in preformatting - groups []string // all groups started from WithGroup - nOpenGroups int // the number of groups opened in preformattedAttrs - mu sync.Mutex - w io.Writer -} - -func (h *commonHandler) clone() *commonHandler { - // We can't use assignment because we can't copy the mutex. - return &commonHandler{ - json: h.json, - opts: h.opts, - preformattedAttrs: slices.Clip(h.preformattedAttrs), - groupPrefix: h.groupPrefix, - groups: slices.Clip(h.groups), - nOpenGroups: h.nOpenGroups, - w: h.w, - } -} - -// enabled reports whether l is greater than or equal to the -// minimum level. -func (h *commonHandler) enabled(l Level) bool { - minLevel := LevelInfo - if h.opts.Level != nil { - minLevel = h.opts.Level.Level() - } - return l >= minLevel -} - -func (h *commonHandler) withAttrs(as []Attr) *commonHandler { - h2 := h.clone() - // Pre-format the attributes as an optimization. - prefix := buffer.New() - defer prefix.Free() - prefix.WriteString(h.groupPrefix) - state := h2.newHandleState((*buffer.Buffer)(&h2.preformattedAttrs), false, "", prefix) - defer state.free() - if len(h2.preformattedAttrs) > 0 { - state.sep = h.attrSep() - } - state.openGroups() - for _, a := range as { - state.appendAttr(a) - } - // Remember the new prefix for later keys. - h2.groupPrefix = state.prefix.String() - // Remember how many opened groups are in preformattedAttrs, - // so we don't open them again when we handle a Record. - h2.nOpenGroups = len(h2.groups) - return h2 -} - -func (h *commonHandler) withGroup(name string) *commonHandler { - if name == "" { - return h - } - h2 := h.clone() - h2.groups = append(h2.groups, name) - return h2 -} - -func (h *commonHandler) handle(r Record) error { - state := h.newHandleState(buffer.New(), true, "", nil) - defer state.free() - if h.json { - state.buf.WriteByte('{') - } - // Built-in attributes. They are not in a group. - stateGroups := state.groups - state.groups = nil // So ReplaceAttrs sees no groups instead of the pre groups. - rep := h.opts.ReplaceAttr - // time - if !r.Time.IsZero() { - key := TimeKey - val := r.Time.Round(0) // strip monotonic to match Attr behavior - if rep == nil { - state.appendKey(key) - state.appendTime(val) - } else { - state.appendAttr(Time(key, val)) - } - } - // level - key := LevelKey - val := r.Level - if rep == nil { - state.appendKey(key) - state.appendString(val.String()) - } else { - state.appendAttr(Any(key, val)) - } - // source - if h.opts.AddSource { - state.appendAttr(Any(SourceKey, r.source())) - } - key = MessageKey - msg := r.Message - if rep == nil { - state.appendKey(key) - state.appendString(msg) - } else { - state.appendAttr(String(key, msg)) - } - state.groups = stateGroups // Restore groups passed to ReplaceAttrs. - state.appendNonBuiltIns(r) - state.buf.WriteByte('\n') - - h.mu.Lock() - defer h.mu.Unlock() - _, err := h.w.Write(*state.buf) - return err -} - -func (s *handleState) appendNonBuiltIns(r Record) { - // preformatted Attrs - if len(s.h.preformattedAttrs) > 0 { - s.buf.WriteString(s.sep) - s.buf.Write(s.h.preformattedAttrs) - s.sep = s.h.attrSep() - } - // Attrs in Record -- unlike the built-in ones, they are in groups started - // from WithGroup. - s.prefix = buffer.New() - defer s.prefix.Free() - s.prefix.WriteString(s.h.groupPrefix) - s.openGroups() - r.Attrs(func(a Attr) bool { - s.appendAttr(a) - return true - }) - if s.h.json { - // Close all open groups. - for range s.h.groups { - s.buf.WriteByte('}') - } - // Close the top-level object. - s.buf.WriteByte('}') - } -} - -// attrSep returns the separator between attributes. -func (h *commonHandler) attrSep() string { - if h.json { - return "," - } - return " " -} - -// handleState holds state for a single call to commonHandler.handle. -// The initial value of sep determines whether to emit a separator -// before the next key, after which it stays true. -type handleState struct { - h *commonHandler - buf *buffer.Buffer - freeBuf bool // should buf be freed? - sep string // separator to write before next key - prefix *buffer.Buffer // for text: key prefix - groups *[]string // pool-allocated slice of active groups, for ReplaceAttr -} - -var groupPool = sync.Pool{New: func() any { - s := make([]string, 0, 10) - return &s -}} - -func (h *commonHandler) newHandleState(buf *buffer.Buffer, freeBuf bool, sep string, prefix *buffer.Buffer) handleState { - s := handleState{ - h: h, - buf: buf, - freeBuf: freeBuf, - sep: sep, - prefix: prefix, - } - if h.opts.ReplaceAttr != nil { - s.groups = groupPool.Get().(*[]string) - *s.groups = append(*s.groups, h.groups[:h.nOpenGroups]...) - } - return s -} - -func (s *handleState) free() { - if s.freeBuf { - s.buf.Free() - } - if gs := s.groups; gs != nil { - *gs = (*gs)[:0] - groupPool.Put(gs) - } -} - -func (s *handleState) openGroups() { - for _, n := range s.h.groups[s.h.nOpenGroups:] { - s.openGroup(n) - } -} - -// Separator for group names and keys. -const keyComponentSep = '.' - -// openGroup starts a new group of attributes -// with the given name. -func (s *handleState) openGroup(name string) { - if s.h.json { - s.appendKey(name) - s.buf.WriteByte('{') - s.sep = "" - } else { - s.prefix.WriteString(name) - s.prefix.WriteByte(keyComponentSep) - } - // Collect group names for ReplaceAttr. - if s.groups != nil { - *s.groups = append(*s.groups, name) - } -} - -// closeGroup ends the group with the given name. -func (s *handleState) closeGroup(name string) { - if s.h.json { - s.buf.WriteByte('}') - } else { - (*s.prefix) = (*s.prefix)[:len(*s.prefix)-len(name)-1 /* for keyComponentSep */] - } - s.sep = s.h.attrSep() - if s.groups != nil { - *s.groups = (*s.groups)[:len(*s.groups)-1] - } -} - -// appendAttr appends the Attr's key and value using app. -// It handles replacement and checking for an empty key. -// after replacement). -func (s *handleState) appendAttr(a Attr) { - if rep := s.h.opts.ReplaceAttr; rep != nil && a.Value.Kind() != KindGroup { - var gs []string - if s.groups != nil { - gs = *s.groups - } - // Resolve before calling ReplaceAttr, so the user doesn't have to. - a.Value = a.Value.Resolve() - a = rep(gs, a) - } - a.Value = a.Value.Resolve() - // Elide empty Attrs. - if a.isEmpty() { - return - } - // Special case: Source. - if v := a.Value; v.Kind() == KindAny { - if src, ok := v.Any().(*Source); ok { - if s.h.json { - a.Value = src.group() - } else { - a.Value = StringValue(fmt.Sprintf("%s:%d", src.File, src.Line)) - } - } - } - if a.Value.Kind() == KindGroup { - attrs := a.Value.Group() - // Output only non-empty groups. - if len(attrs) > 0 { - // Inline a group with an empty key. - if a.Key != "" { - s.openGroup(a.Key) - } - for _, aa := range attrs { - s.appendAttr(aa) - } - if a.Key != "" { - s.closeGroup(a.Key) - } - } - } else { - s.appendKey(a.Key) - s.appendValue(a.Value) - } -} - -func (s *handleState) appendError(err error) { - s.appendString(fmt.Sprintf("!ERROR:%v", err)) -} - -func (s *handleState) appendKey(key string) { - s.buf.WriteString(s.sep) - if s.prefix != nil { - // TODO: optimize by avoiding allocation. - s.appendString(string(*s.prefix) + key) - } else { - s.appendString(key) - } - if s.h.json { - s.buf.WriteByte(':') - } else { - s.buf.WriteByte('=') - } - s.sep = s.h.attrSep() -} - -func (s *handleState) appendString(str string) { - if s.h.json { - s.buf.WriteByte('"') - *s.buf = appendEscapedJSONString(*s.buf, str) - s.buf.WriteByte('"') - } else { - // text - if needsQuoting(str) { - *s.buf = strconv.AppendQuote(*s.buf, str) - } else { - s.buf.WriteString(str) - } - } -} - -func (s *handleState) appendValue(v Value) { - var err error - if s.h.json { - err = appendJSONValue(s, v) - } else { - err = appendTextValue(s, v) - } - if err != nil { - s.appendError(err) - } -} - -func (s *handleState) appendTime(t time.Time) { - if s.h.json { - appendJSONTime(s, t) - } else { - writeTimeRFC3339Millis(s.buf, t) - } -} - -// This takes half the time of Time.AppendFormat. -func writeTimeRFC3339Millis(buf *buffer.Buffer, t time.Time) { - year, month, day := t.Date() - buf.WritePosIntWidth(year, 4) - buf.WriteByte('-') - buf.WritePosIntWidth(int(month), 2) - buf.WriteByte('-') - buf.WritePosIntWidth(day, 2) - buf.WriteByte('T') - hour, min, sec := t.Clock() - buf.WritePosIntWidth(hour, 2) - buf.WriteByte(':') - buf.WritePosIntWidth(min, 2) - buf.WriteByte(':') - buf.WritePosIntWidth(sec, 2) - ns := t.Nanosecond() - buf.WriteByte('.') - buf.WritePosIntWidth(ns/1e6, 3) - _, offsetSeconds := t.Zone() - if offsetSeconds == 0 { - buf.WriteByte('Z') - } else { - offsetMinutes := offsetSeconds / 60 - if offsetMinutes < 0 { - buf.WriteByte('-') - offsetMinutes = -offsetMinutes - } else { - buf.WriteByte('+') - } - buf.WritePosIntWidth(offsetMinutes/60, 2) - buf.WriteByte(':') - buf.WritePosIntWidth(offsetMinutes%60, 2) - } -} diff --git a/vendor/golang.org/x/exp/slog/internal/buffer/buffer.go b/vendor/golang.org/x/exp/slog/internal/buffer/buffer.go deleted file mode 100644 index 7786c16..0000000 --- a/vendor/golang.org/x/exp/slog/internal/buffer/buffer.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package buffer provides a pool-allocated byte buffer. -package buffer - -import ( - "sync" -) - -// Buffer adapted from go/src/fmt/print.go -type Buffer []byte - -// Having an initial size gives a dramatic speedup. -var bufPool = sync.Pool{ - New: func() any { - b := make([]byte, 0, 1024) - return (*Buffer)(&b) - }, -} - -func New() *Buffer { - return bufPool.Get().(*Buffer) -} - -func (b *Buffer) Free() { - // To reduce peak allocation, return only smaller buffers to the pool. - const maxBufferSize = 16 << 10 - if cap(*b) <= maxBufferSize { - *b = (*b)[:0] - bufPool.Put(b) - } -} - -func (b *Buffer) Reset() { - *b = (*b)[:0] -} - -func (b *Buffer) Write(p []byte) (int, error) { - *b = append(*b, p...) - return len(p), nil -} - -func (b *Buffer) WriteString(s string) { - *b = append(*b, s...) -} - -func (b *Buffer) WriteByte(c byte) { - *b = append(*b, c) -} - -func (b *Buffer) WritePosInt(i int) { - b.WritePosIntWidth(i, 0) -} - -// WritePosIntWidth writes non-negative integer i to the buffer, padded on the left -// by zeroes to the given width. Use a width of 0 to omit padding. -func (b *Buffer) WritePosIntWidth(i, width int) { - // Cheap integer to fixed-width decimal ASCII. - // Copied from log/log.go. - - if i < 0 { - panic("negative int") - } - - // Assemble decimal in reverse order. - var bb [20]byte - bp := len(bb) - 1 - for i >= 10 || width > 1 { - width-- - q := i / 10 - bb[bp] = byte('0' + i - q*10) - bp-- - i = q - } - // i < 10 - bb[bp] = byte('0' + i) - b.Write(bb[bp:]) -} - -func (b *Buffer) String() string { - return string(*b) -} diff --git a/vendor/golang.org/x/exp/slog/internal/ignorepc.go b/vendor/golang.org/x/exp/slog/internal/ignorepc.go deleted file mode 100644 index d125642..0000000 --- a/vendor/golang.org/x/exp/slog/internal/ignorepc.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package internal - -// If IgnorePC is true, do not invoke runtime.Callers to get the pc. -// This is solely for benchmarking the slowdown from runtime.Callers. -var IgnorePC = false diff --git a/vendor/golang.org/x/exp/slog/json_handler.go b/vendor/golang.org/x/exp/slog/json_handler.go deleted file mode 100644 index 157ada8..0000000 --- a/vendor/golang.org/x/exp/slog/json_handler.go +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slog - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "strconv" - "time" - "unicode/utf8" - - "golang.org/x/exp/slog/internal/buffer" -) - -// JSONHandler is a Handler that writes Records to an io.Writer as -// line-delimited JSON objects. -type JSONHandler struct { - *commonHandler -} - -// NewJSONHandler creates a JSONHandler that writes to w, -// using the given options. -// If opts is nil, the default options are used. -func NewJSONHandler(w io.Writer, opts *HandlerOptions) *JSONHandler { - if opts == nil { - opts = &HandlerOptions{} - } - return &JSONHandler{ - &commonHandler{ - json: true, - w: w, - opts: *opts, - }, - } -} - -// Enabled reports whether the handler handles records at the given level. -// The handler ignores records whose level is lower. -func (h *JSONHandler) Enabled(_ context.Context, level Level) bool { - return h.commonHandler.enabled(level) -} - -// WithAttrs returns a new JSONHandler whose attributes consists -// of h's attributes followed by attrs. -func (h *JSONHandler) WithAttrs(attrs []Attr) Handler { - return &JSONHandler{commonHandler: h.commonHandler.withAttrs(attrs)} -} - -func (h *JSONHandler) WithGroup(name string) Handler { - return &JSONHandler{commonHandler: h.commonHandler.withGroup(name)} -} - -// Handle formats its argument Record as a JSON object on a single line. -// -// If the Record's time is zero, the time is omitted. -// Otherwise, the key is "time" -// and the value is output as with json.Marshal. -// -// If the Record's level is zero, the level is omitted. -// Otherwise, the key is "level" -// and the value of [Level.String] is output. -// -// If the AddSource option is set and source information is available, -// the key is "source" -// and the value is output as "FILE:LINE". -// -// The message's key is "msg". -// -// To modify these or other attributes, or remove them from the output, use -// [HandlerOptions.ReplaceAttr]. -// -// Values are formatted as with an [encoding/json.Encoder] with SetEscapeHTML(false), -// with two exceptions. -// -// First, an Attr whose Value is of type error is formatted as a string, by -// calling its Error method. Only errors in Attrs receive this special treatment, -// not errors embedded in structs, slices, maps or other data structures that -// are processed by the encoding/json package. -// -// Second, an encoding failure does not cause Handle to return an error. -// Instead, the error message is formatted as a string. -// -// Each call to Handle results in a single serialized call to io.Writer.Write. -func (h *JSONHandler) Handle(_ context.Context, r Record) error { - return h.commonHandler.handle(r) -} - -// Adapted from time.Time.MarshalJSON to avoid allocation. -func appendJSONTime(s *handleState, t time.Time) { - if y := t.Year(); y < 0 || y >= 10000 { - // RFC 3339 is clear that years are 4 digits exactly. - // See golang.org/issue/4556#c15 for more discussion. - s.appendError(errors.New("time.Time year outside of range [0,9999]")) - } - s.buf.WriteByte('"') - *s.buf = t.AppendFormat(*s.buf, time.RFC3339Nano) - s.buf.WriteByte('"') -} - -func appendJSONValue(s *handleState, v Value) error { - switch v.Kind() { - case KindString: - s.appendString(v.str()) - case KindInt64: - *s.buf = strconv.AppendInt(*s.buf, v.Int64(), 10) - case KindUint64: - *s.buf = strconv.AppendUint(*s.buf, v.Uint64(), 10) - case KindFloat64: - // json.Marshal is funny about floats; it doesn't - // always match strconv.AppendFloat. So just call it. - // That's expensive, but floats are rare. - if err := appendJSONMarshal(s.buf, v.Float64()); err != nil { - return err - } - case KindBool: - *s.buf = strconv.AppendBool(*s.buf, v.Bool()) - case KindDuration: - // Do what json.Marshal does. - *s.buf = strconv.AppendInt(*s.buf, int64(v.Duration()), 10) - case KindTime: - s.appendTime(v.Time()) - case KindAny: - a := v.Any() - _, jm := a.(json.Marshaler) - if err, ok := a.(error); ok && !jm { - s.appendString(err.Error()) - } else { - return appendJSONMarshal(s.buf, a) - } - default: - panic(fmt.Sprintf("bad kind: %s", v.Kind())) - } - return nil -} - -func appendJSONMarshal(buf *buffer.Buffer, v any) error { - // Use a json.Encoder to avoid escaping HTML. - var bb bytes.Buffer - enc := json.NewEncoder(&bb) - enc.SetEscapeHTML(false) - if err := enc.Encode(v); err != nil { - return err - } - bs := bb.Bytes() - buf.Write(bs[:len(bs)-1]) // remove final newline - return nil -} - -// appendEscapedJSONString escapes s for JSON and appends it to buf. -// It does not surround the string in quotation marks. -// -// Modified from encoding/json/encode.go:encodeState.string, -// with escapeHTML set to false. -func appendEscapedJSONString(buf []byte, s string) []byte { - char := func(b byte) { buf = append(buf, b) } - str := func(s string) { buf = append(buf, s...) } - - start := 0 - for i := 0; i < len(s); { - if b := s[i]; b < utf8.RuneSelf { - if safeSet[b] { - i++ - continue - } - if start < i { - str(s[start:i]) - } - char('\\') - switch b { - case '\\', '"': - char(b) - case '\n': - char('n') - case '\r': - char('r') - case '\t': - char('t') - default: - // This encodes bytes < 0x20 except for \t, \n and \r. - str(`u00`) - char(hex[b>>4]) - char(hex[b&0xF]) - } - i++ - start = i - continue - } - c, size := utf8.DecodeRuneInString(s[i:]) - if c == utf8.RuneError && size == 1 { - if start < i { - str(s[start:i]) - } - str(`\ufffd`) - i += size - start = i - continue - } - // U+2028 is LINE SEPARATOR. - // U+2029 is PARAGRAPH SEPARATOR. - // They are both technically valid characters in JSON strings, - // but don't work in JSONP, which has to be evaluated as JavaScript, - // and can lead to security holes there. It is valid JSON to - // escape them, so we do so unconditionally. - // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. - if c == '\u2028' || c == '\u2029' { - if start < i { - str(s[start:i]) - } - str(`\u202`) - char(hex[c&0xF]) - i += size - start = i - continue - } - i += size - } - if start < len(s) { - str(s[start:]) - } - return buf -} - -var hex = "0123456789abcdef" - -// Copied from encoding/json/tables.go. -// -// safeSet holds the value true if the ASCII character with the given array -// position can be represented inside a JSON string without any further -// escaping. -// -// All values are true except for the ASCII control characters (0-31), the -// double quote ("), and the backslash character ("\"). -var safeSet = [utf8.RuneSelf]bool{ - ' ': true, - '!': true, - '"': false, - '#': true, - '$': true, - '%': true, - '&': true, - '\'': true, - '(': true, - ')': true, - '*': true, - '+': true, - ',': true, - '-': true, - '.': true, - '/': true, - '0': true, - '1': true, - '2': true, - '3': true, - '4': true, - '5': true, - '6': true, - '7': true, - '8': true, - '9': true, - ':': true, - ';': true, - '<': true, - '=': true, - '>': true, - '?': true, - '@': true, - 'A': true, - 'B': true, - 'C': true, - 'D': true, - 'E': true, - 'F': true, - 'G': true, - 'H': true, - 'I': true, - 'J': true, - 'K': true, - 'L': true, - 'M': true, - 'N': true, - 'O': true, - 'P': true, - 'Q': true, - 'R': true, - 'S': true, - 'T': true, - 'U': true, - 'V': true, - 'W': true, - 'X': true, - 'Y': true, - 'Z': true, - '[': true, - '\\': false, - ']': true, - '^': true, - '_': true, - '`': true, - 'a': true, - 'b': true, - 'c': true, - 'd': true, - 'e': true, - 'f': true, - 'g': true, - 'h': true, - 'i': true, - 'j': true, - 'k': true, - 'l': true, - 'm': true, - 'n': true, - 'o': true, - 'p': true, - 'q': true, - 'r': true, - 's': true, - 't': true, - 'u': true, - 'v': true, - 'w': true, - 'x': true, - 'y': true, - 'z': true, - '{': true, - '|': true, - '}': true, - '~': true, - '\u007f': true, -} diff --git a/vendor/golang.org/x/exp/slog/level.go b/vendor/golang.org/x/exp/slog/level.go deleted file mode 100644 index b2365f0..0000000 --- a/vendor/golang.org/x/exp/slog/level.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slog - -import ( - "errors" - "fmt" - "strconv" - "strings" - "sync/atomic" -) - -// A Level is the importance or severity of a log event. -// The higher the level, the more important or severe the event. -type Level int - -// Level numbers are inherently arbitrary, -// but we picked them to satisfy three constraints. -// Any system can map them to another numbering scheme if it wishes. -// -// First, we wanted the default level to be Info, Since Levels are ints, Info is -// the default value for int, zero. -// - -// Second, we wanted to make it easy to use levels to specify logger verbosity. -// Since a larger level means a more severe event, a logger that accepts events -// with smaller (or more negative) level means a more verbose logger. Logger -// verbosity is thus the negation of event severity, and the default verbosity -// of 0 accepts all events at least as severe as INFO. -// -// Third, we wanted some room between levels to accommodate schemes with named -// levels between ours. For example, Google Cloud Logging defines a Notice level -// between Info and Warn. Since there are only a few of these intermediate -// levels, the gap between the numbers need not be large. Our gap of 4 matches -// OpenTelemetry's mapping. Subtracting 9 from an OpenTelemetry level in the -// DEBUG, INFO, WARN and ERROR ranges converts it to the corresponding slog -// Level range. OpenTelemetry also has the names TRACE and FATAL, which slog -// does not. But those OpenTelemetry levels can still be represented as slog -// Levels by using the appropriate integers. -// -// Names for common levels. -const ( - LevelDebug Level = -4 - LevelInfo Level = 0 - LevelWarn Level = 4 - LevelError Level = 8 -) - -// String returns a name for the level. -// If the level has a name, then that name -// in uppercase is returned. -// If the level is between named values, then -// an integer is appended to the uppercased name. -// Examples: -// -// LevelWarn.String() => "WARN" -// (LevelInfo+2).String() => "INFO+2" -func (l Level) String() string { - str := func(base string, val Level) string { - if val == 0 { - return base - } - return fmt.Sprintf("%s%+d", base, val) - } - - switch { - case l < LevelInfo: - return str("DEBUG", l-LevelDebug) - case l < LevelWarn: - return str("INFO", l-LevelInfo) - case l < LevelError: - return str("WARN", l-LevelWarn) - default: - return str("ERROR", l-LevelError) - } -} - -// MarshalJSON implements [encoding/json.Marshaler] -// by quoting the output of [Level.String]. -func (l Level) MarshalJSON() ([]byte, error) { - // AppendQuote is sufficient for JSON-encoding all Level strings. - // They don't contain any runes that would produce invalid JSON - // when escaped. - return strconv.AppendQuote(nil, l.String()), nil -} - -// UnmarshalJSON implements [encoding/json.Unmarshaler] -// It accepts any string produced by [Level.MarshalJSON], -// ignoring case. -// It also accepts numeric offsets that would result in a different string on -// output. For example, "Error-8" would marshal as "INFO". -func (l *Level) UnmarshalJSON(data []byte) error { - s, err := strconv.Unquote(string(data)) - if err != nil { - return err - } - return l.parse(s) -} - -// MarshalText implements [encoding.TextMarshaler] -// by calling [Level.String]. -func (l Level) MarshalText() ([]byte, error) { - return []byte(l.String()), nil -} - -// UnmarshalText implements [encoding.TextUnmarshaler]. -// It accepts any string produced by [Level.MarshalText], -// ignoring case. -// It also accepts numeric offsets that would result in a different string on -// output. For example, "Error-8" would marshal as "INFO". -func (l *Level) UnmarshalText(data []byte) error { - return l.parse(string(data)) -} - -func (l *Level) parse(s string) (err error) { - defer func() { - if err != nil { - err = fmt.Errorf("slog: level string %q: %w", s, err) - } - }() - - name := s - offset := 0 - if i := strings.IndexAny(s, "+-"); i >= 0 { - name = s[:i] - offset, err = strconv.Atoi(s[i:]) - if err != nil { - return err - } - } - switch strings.ToUpper(name) { - case "DEBUG": - *l = LevelDebug - case "INFO": - *l = LevelInfo - case "WARN": - *l = LevelWarn - case "ERROR": - *l = LevelError - default: - return errors.New("unknown name") - } - *l += Level(offset) - return nil -} - -// Level returns the receiver. -// It implements Leveler. -func (l Level) Level() Level { return l } - -// A LevelVar is a Level variable, to allow a Handler level to change -// dynamically. -// It implements Leveler as well as a Set method, -// and it is safe for use by multiple goroutines. -// The zero LevelVar corresponds to LevelInfo. -type LevelVar struct { - val atomic.Int64 -} - -// Level returns v's level. -func (v *LevelVar) Level() Level { - return Level(int(v.val.Load())) -} - -// Set sets v's level to l. -func (v *LevelVar) Set(l Level) { - v.val.Store(int64(l)) -} - -func (v *LevelVar) String() string { - return fmt.Sprintf("LevelVar(%s)", v.Level()) -} - -// MarshalText implements [encoding.TextMarshaler] -// by calling [Level.MarshalText]. -func (v *LevelVar) MarshalText() ([]byte, error) { - return v.Level().MarshalText() -} - -// UnmarshalText implements [encoding.TextUnmarshaler] -// by calling [Level.UnmarshalText]. -func (v *LevelVar) UnmarshalText(data []byte) error { - var l Level - if err := l.UnmarshalText(data); err != nil { - return err - } - v.Set(l) - return nil -} - -// A Leveler provides a Level value. -// -// As Level itself implements Leveler, clients typically supply -// a Level value wherever a Leveler is needed, such as in HandlerOptions. -// Clients who need to vary the level dynamically can provide a more complex -// Leveler implementation such as *LevelVar. -type Leveler interface { - Level() Level -} diff --git a/vendor/golang.org/x/exp/slog/logger.go b/vendor/golang.org/x/exp/slog/logger.go deleted file mode 100644 index e87ec99..0000000 --- a/vendor/golang.org/x/exp/slog/logger.go +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slog - -import ( - "context" - "log" - "runtime" - "sync/atomic" - "time" - - "golang.org/x/exp/slog/internal" -) - -var defaultLogger atomic.Value - -func init() { - defaultLogger.Store(New(newDefaultHandler(log.Output))) -} - -// Default returns the default Logger. -func Default() *Logger { return defaultLogger.Load().(*Logger) } - -// SetDefault makes l the default Logger. -// After this call, output from the log package's default Logger -// (as with [log.Print], etc.) will be logged at LevelInfo using l's Handler. -func SetDefault(l *Logger) { - defaultLogger.Store(l) - // If the default's handler is a defaultHandler, then don't use a handleWriter, - // or we'll deadlock as they both try to acquire the log default mutex. - // The defaultHandler will use whatever the log default writer is currently - // set to, which is correct. - // This can occur with SetDefault(Default()). - // See TestSetDefault. - if _, ok := l.Handler().(*defaultHandler); !ok { - capturePC := log.Flags()&(log.Lshortfile|log.Llongfile) != 0 - log.SetOutput(&handlerWriter{l.Handler(), LevelInfo, capturePC}) - log.SetFlags(0) // we want just the log message, no time or location - } -} - -// handlerWriter is an io.Writer that calls a Handler. -// It is used to link the default log.Logger to the default slog.Logger. -type handlerWriter struct { - h Handler - level Level - capturePC bool -} - -func (w *handlerWriter) Write(buf []byte) (int, error) { - if !w.h.Enabled(context.Background(), w.level) { - return 0, nil - } - var pc uintptr - if !internal.IgnorePC && w.capturePC { - // skip [runtime.Callers, w.Write, Logger.Output, log.Print] - var pcs [1]uintptr - runtime.Callers(4, pcs[:]) - pc = pcs[0] - } - - // Remove final newline. - origLen := len(buf) // Report that the entire buf was written. - if len(buf) > 0 && buf[len(buf)-1] == '\n' { - buf = buf[:len(buf)-1] - } - r := NewRecord(time.Now(), w.level, string(buf), pc) - return origLen, w.h.Handle(context.Background(), r) -} - -// A Logger records structured information about each call to its -// Log, Debug, Info, Warn, and Error methods. -// For each call, it creates a Record and passes it to a Handler. -// -// To create a new Logger, call [New] or a Logger method -// that begins "With". -type Logger struct { - handler Handler // for structured logging -} - -func (l *Logger) clone() *Logger { - c := *l - return &c -} - -// Handler returns l's Handler. -func (l *Logger) Handler() Handler { return l.handler } - -// With returns a new Logger that includes the given arguments, converted to -// Attrs as in [Logger.Log]. -// The Attrs will be added to each output from the Logger. -// The new Logger shares the old Logger's context. -// The new Logger's handler is the result of calling WithAttrs on the receiver's -// handler. -func (l *Logger) With(args ...any) *Logger { - c := l.clone() - c.handler = l.handler.WithAttrs(argsToAttrSlice(args)) - return c -} - -// WithGroup returns a new Logger that starts a group. The keys of all -// attributes added to the Logger will be qualified by the given name. -// (How that qualification happens depends on the [Handler.WithGroup] -// method of the Logger's Handler.) -// The new Logger shares the old Logger's context. -// -// The new Logger's handler is the result of calling WithGroup on the receiver's -// handler. -func (l *Logger) WithGroup(name string) *Logger { - c := l.clone() - c.handler = l.handler.WithGroup(name) - return c - -} - -// New creates a new Logger with the given non-nil Handler and a nil context. -func New(h Handler) *Logger { - if h == nil { - panic("nil Handler") - } - return &Logger{handler: h} -} - -// With calls Logger.With on the default logger. -func With(args ...any) *Logger { - return Default().With(args...) -} - -// Enabled reports whether l emits log records at the given context and level. -func (l *Logger) Enabled(ctx context.Context, level Level) bool { - if ctx == nil { - ctx = context.Background() - } - return l.Handler().Enabled(ctx, level) -} - -// NewLogLogger returns a new log.Logger such that each call to its Output method -// dispatches a Record to the specified handler. The logger acts as a bridge from -// the older log API to newer structured logging handlers. -func NewLogLogger(h Handler, level Level) *log.Logger { - return log.New(&handlerWriter{h, level, true}, "", 0) -} - -// Log emits a log record with the current time and the given level and message. -// The Record's Attrs consist of the Logger's attributes followed by -// the Attrs specified by args. -// -// The attribute arguments are processed as follows: -// - If an argument is an Attr, it is used as is. -// - If an argument is a string and this is not the last argument, -// the following argument is treated as the value and the two are combined -// into an Attr. -// - Otherwise, the argument is treated as a value with key "!BADKEY". -func (l *Logger) Log(ctx context.Context, level Level, msg string, args ...any) { - l.log(ctx, level, msg, args...) -} - -// LogAttrs is a more efficient version of [Logger.Log] that accepts only Attrs. -func (l *Logger) LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) { - l.logAttrs(ctx, level, msg, attrs...) -} - -// Debug logs at LevelDebug. -func (l *Logger) Debug(msg string, args ...any) { - l.log(nil, LevelDebug, msg, args...) -} - -// DebugContext logs at LevelDebug with the given context. -func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any) { - l.log(ctx, LevelDebug, msg, args...) -} - -// DebugCtx logs at LevelDebug with the given context. -// Deprecated: Use Logger.DebugContext. -func (l *Logger) DebugCtx(ctx context.Context, msg string, args ...any) { - l.log(ctx, LevelDebug, msg, args...) -} - -// Info logs at LevelInfo. -func (l *Logger) Info(msg string, args ...any) { - l.log(nil, LevelInfo, msg, args...) -} - -// InfoContext logs at LevelInfo with the given context. -func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any) { - l.log(ctx, LevelInfo, msg, args...) -} - -// InfoCtx logs at LevelInfo with the given context. -// Deprecated: Use Logger.InfoContext. -func (l *Logger) InfoCtx(ctx context.Context, msg string, args ...any) { - l.log(ctx, LevelInfo, msg, args...) -} - -// Warn logs at LevelWarn. -func (l *Logger) Warn(msg string, args ...any) { - l.log(nil, LevelWarn, msg, args...) -} - -// WarnContext logs at LevelWarn with the given context. -func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any) { - l.log(ctx, LevelWarn, msg, args...) -} - -// WarnCtx logs at LevelWarn with the given context. -// Deprecated: Use Logger.WarnContext. -func (l *Logger) WarnCtx(ctx context.Context, msg string, args ...any) { - l.log(ctx, LevelWarn, msg, args...) -} - -// Error logs at LevelError. -func (l *Logger) Error(msg string, args ...any) { - l.log(nil, LevelError, msg, args...) -} - -// ErrorContext logs at LevelError with the given context. -func (l *Logger) ErrorContext(ctx context.Context, msg string, args ...any) { - l.log(ctx, LevelError, msg, args...) -} - -// ErrorCtx logs at LevelError with the given context. -// Deprecated: Use Logger.ErrorContext. -func (l *Logger) ErrorCtx(ctx context.Context, msg string, args ...any) { - l.log(ctx, LevelError, msg, args...) -} - -// log is the low-level logging method for methods that take ...any. -// It must always be called directly by an exported logging method -// or function, because it uses a fixed call depth to obtain the pc. -func (l *Logger) log(ctx context.Context, level Level, msg string, args ...any) { - if !l.Enabled(ctx, level) { - return - } - var pc uintptr - if !internal.IgnorePC { - var pcs [1]uintptr - // skip [runtime.Callers, this function, this function's caller] - runtime.Callers(3, pcs[:]) - pc = pcs[0] - } - r := NewRecord(time.Now(), level, msg, pc) - r.Add(args...) - if ctx == nil { - ctx = context.Background() - } - _ = l.Handler().Handle(ctx, r) -} - -// logAttrs is like [Logger.log], but for methods that take ...Attr. -func (l *Logger) logAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) { - if !l.Enabled(ctx, level) { - return - } - var pc uintptr - if !internal.IgnorePC { - var pcs [1]uintptr - // skip [runtime.Callers, this function, this function's caller] - runtime.Callers(3, pcs[:]) - pc = pcs[0] - } - r := NewRecord(time.Now(), level, msg, pc) - r.AddAttrs(attrs...) - if ctx == nil { - ctx = context.Background() - } - _ = l.Handler().Handle(ctx, r) -} - -// Debug calls Logger.Debug on the default logger. -func Debug(msg string, args ...any) { - Default().log(nil, LevelDebug, msg, args...) -} - -// DebugContext calls Logger.DebugContext on the default logger. -func DebugContext(ctx context.Context, msg string, args ...any) { - Default().log(ctx, LevelDebug, msg, args...) -} - -// Info calls Logger.Info on the default logger. -func Info(msg string, args ...any) { - Default().log(nil, LevelInfo, msg, args...) -} - -// InfoContext calls Logger.InfoContext on the default logger. -func InfoContext(ctx context.Context, msg string, args ...any) { - Default().log(ctx, LevelInfo, msg, args...) -} - -// Warn calls Logger.Warn on the default logger. -func Warn(msg string, args ...any) { - Default().log(nil, LevelWarn, msg, args...) -} - -// WarnContext calls Logger.WarnContext on the default logger. -func WarnContext(ctx context.Context, msg string, args ...any) { - Default().log(ctx, LevelWarn, msg, args...) -} - -// Error calls Logger.Error on the default logger. -func Error(msg string, args ...any) { - Default().log(nil, LevelError, msg, args...) -} - -// ErrorContext calls Logger.ErrorContext on the default logger. -func ErrorContext(ctx context.Context, msg string, args ...any) { - Default().log(ctx, LevelError, msg, args...) -} - -// DebugCtx calls Logger.DebugContext on the default logger. -// Deprecated: call DebugContext. -func DebugCtx(ctx context.Context, msg string, args ...any) { - Default().log(ctx, LevelDebug, msg, args...) -} - -// InfoCtx calls Logger.InfoContext on the default logger. -// Deprecated: call InfoContext. -func InfoCtx(ctx context.Context, msg string, args ...any) { - Default().log(ctx, LevelInfo, msg, args...) -} - -// WarnCtx calls Logger.WarnContext on the default logger. -// Deprecated: call WarnContext. -func WarnCtx(ctx context.Context, msg string, args ...any) { - Default().log(ctx, LevelWarn, msg, args...) -} - -// ErrorCtx calls Logger.ErrorContext on the default logger. -// Deprecated: call ErrorContext. -func ErrorCtx(ctx context.Context, msg string, args ...any) { - Default().log(ctx, LevelError, msg, args...) -} - -// Log calls Logger.Log on the default logger. -func Log(ctx context.Context, level Level, msg string, args ...any) { - Default().log(ctx, level, msg, args...) -} - -// LogAttrs calls Logger.LogAttrs on the default logger. -func LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) { - Default().logAttrs(ctx, level, msg, attrs...) -} diff --git a/vendor/golang.org/x/exp/slog/noplog.bench b/vendor/golang.org/x/exp/slog/noplog.bench deleted file mode 100644 index ed9296f..0000000 --- a/vendor/golang.org/x/exp/slog/noplog.bench +++ /dev/null @@ -1,36 +0,0 @@ -goos: linux -goarch: amd64 -pkg: golang.org/x/exp/slog -cpu: Intel(R) Xeon(R) CPU @ 2.20GHz -BenchmarkNopLog/attrs-8 1000000 1090 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/attrs-8 1000000 1097 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/attrs-8 1000000 1078 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/attrs-8 1000000 1095 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/attrs-8 1000000 1096 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/attrs-parallel-8 4007268 308.2 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/attrs-parallel-8 4016138 299.7 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/attrs-parallel-8 4020529 305.9 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/attrs-parallel-8 3977829 303.4 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/attrs-parallel-8 3225438 318.5 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/keys-values-8 1179256 994.2 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/keys-values-8 1000000 1002 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/keys-values-8 1216710 993.2 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/keys-values-8 1000000 1013 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/keys-values-8 1000000 1016 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/WithContext-8 989066 1163 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/WithContext-8 994116 1163 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/WithContext-8 1000000 1152 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/WithContext-8 991675 1165 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/WithContext-8 965268 1166 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/WithContext-parallel-8 3955503 303.3 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/WithContext-parallel-8 3861188 307.8 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/WithContext-parallel-8 3967752 303.9 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/WithContext-parallel-8 3955203 302.7 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/WithContext-parallel-8 3948278 301.1 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/Ctx-8 940622 1247 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/Ctx-8 936381 1257 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/Ctx-8 959730 1266 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/Ctx-8 943473 1290 ns/op 0 B/op 0 allocs/op -BenchmarkNopLog/Ctx-8 919414 1259 ns/op 0 B/op 0 allocs/op -PASS -ok golang.org/x/exp/slog 40.566s diff --git a/vendor/golang.org/x/exp/slog/record.go b/vendor/golang.org/x/exp/slog/record.go deleted file mode 100644 index 38b3440..0000000 --- a/vendor/golang.org/x/exp/slog/record.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slog - -import ( - "runtime" - "time" - - "golang.org/x/exp/slices" -) - -const nAttrsInline = 5 - -// A Record holds information about a log event. -// Copies of a Record share state. -// Do not modify a Record after handing out a copy to it. -// Use [Record.Clone] to create a copy with no shared state. -type Record struct { - // The time at which the output method (Log, Info, etc.) was called. - Time time.Time - - // The log message. - Message string - - // The level of the event. - Level Level - - // The program counter at the time the record was constructed, as determined - // by runtime.Callers. If zero, no program counter is available. - // - // The only valid use for this value is as an argument to - // [runtime.CallersFrames]. In particular, it must not be passed to - // [runtime.FuncForPC]. - PC uintptr - - // Allocation optimization: an inline array sized to hold - // the majority of log calls (based on examination of open-source - // code). It holds the start of the list of Attrs. - front [nAttrsInline]Attr - - // The number of Attrs in front. - nFront int - - // The list of Attrs except for those in front. - // Invariants: - // - len(back) > 0 iff nFront == len(front) - // - Unused array elements are zero. Used to detect mistakes. - back []Attr -} - -// NewRecord creates a Record from the given arguments. -// Use [Record.AddAttrs] to add attributes to the Record. -// -// NewRecord is intended for logging APIs that want to support a [Handler] as -// a backend. -func NewRecord(t time.Time, level Level, msg string, pc uintptr) Record { - return Record{ - Time: t, - Message: msg, - Level: level, - PC: pc, - } -} - -// Clone returns a copy of the record with no shared state. -// The original record and the clone can both be modified -// without interfering with each other. -func (r Record) Clone() Record { - r.back = slices.Clip(r.back) // prevent append from mutating shared array - return r -} - -// NumAttrs returns the number of attributes in the Record. -func (r Record) NumAttrs() int { - return r.nFront + len(r.back) -} - -// Attrs calls f on each Attr in the Record. -// Iteration stops if f returns false. -func (r Record) Attrs(f func(Attr) bool) { - for i := 0; i < r.nFront; i++ { - if !f(r.front[i]) { - return - } - } - for _, a := range r.back { - if !f(a) { - return - } - } -} - -// AddAttrs appends the given Attrs to the Record's list of Attrs. -func (r *Record) AddAttrs(attrs ...Attr) { - n := copy(r.front[r.nFront:], attrs) - r.nFront += n - // Check if a copy was modified by slicing past the end - // and seeing if the Attr there is non-zero. - if cap(r.back) > len(r.back) { - end := r.back[:len(r.back)+1][len(r.back)] - if !end.isEmpty() { - panic("copies of a slog.Record were both modified") - } - } - r.back = append(r.back, attrs[n:]...) -} - -// Add converts the args to Attrs as described in [Logger.Log], -// then appends the Attrs to the Record's list of Attrs. -func (r *Record) Add(args ...any) { - var a Attr - for len(args) > 0 { - a, args = argsToAttr(args) - if r.nFront < len(r.front) { - r.front[r.nFront] = a - r.nFront++ - } else { - if r.back == nil { - r.back = make([]Attr, 0, countAttrs(args)) - } - r.back = append(r.back, a) - } - } - -} - -// countAttrs returns the number of Attrs that would be created from args. -func countAttrs(args []any) int { - n := 0 - for i := 0; i < len(args); i++ { - n++ - if _, ok := args[i].(string); ok { - i++ - } - } - return n -} - -const badKey = "!BADKEY" - -// argsToAttr turns a prefix of the nonempty args slice into an Attr -// and returns the unconsumed portion of the slice. -// If args[0] is an Attr, it returns it. -// If args[0] is a string, it treats the first two elements as -// a key-value pair. -// Otherwise, it treats args[0] as a value with a missing key. -func argsToAttr(args []any) (Attr, []any) { - switch x := args[0].(type) { - case string: - if len(args) == 1 { - return String(badKey, x), nil - } - return Any(x, args[1]), args[2:] - - case Attr: - return x, args[1:] - - default: - return Any(badKey, x), args[1:] - } -} - -// Source describes the location of a line of source code. -type Source struct { - // Function is the package path-qualified function name containing the - // source line. If non-empty, this string uniquely identifies a single - // function in the program. This may be the empty string if not known. - Function string `json:"function"` - // File and Line are the file name and line number (1-based) of the source - // line. These may be the empty string and zero, respectively, if not known. - File string `json:"file"` - Line int `json:"line"` -} - -// attrs returns the non-zero fields of s as a slice of attrs. -// It is similar to a LogValue method, but we don't want Source -// to implement LogValuer because it would be resolved before -// the ReplaceAttr function was called. -func (s *Source) group() Value { - var as []Attr - if s.Function != "" { - as = append(as, String("function", s.Function)) - } - if s.File != "" { - as = append(as, String("file", s.File)) - } - if s.Line != 0 { - as = append(as, Int("line", s.Line)) - } - return GroupValue(as...) -} - -// source returns a Source for the log event. -// If the Record was created without the necessary information, -// or if the location is unavailable, it returns a non-nil *Source -// with zero fields. -func (r Record) source() *Source { - fs := runtime.CallersFrames([]uintptr{r.PC}) - f, _ := fs.Next() - return &Source{ - Function: f.Function, - File: f.File, - Line: f.Line, - } -} diff --git a/vendor/golang.org/x/exp/slog/text_handler.go b/vendor/golang.org/x/exp/slog/text_handler.go deleted file mode 100644 index 75b66b7..0000000 --- a/vendor/golang.org/x/exp/slog/text_handler.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slog - -import ( - "context" - "encoding" - "fmt" - "io" - "reflect" - "strconv" - "unicode" - "unicode/utf8" -) - -// TextHandler is a Handler that writes Records to an io.Writer as a -// sequence of key=value pairs separated by spaces and followed by a newline. -type TextHandler struct { - *commonHandler -} - -// NewTextHandler creates a TextHandler that writes to w, -// using the given options. -// If opts is nil, the default options are used. -func NewTextHandler(w io.Writer, opts *HandlerOptions) *TextHandler { - if opts == nil { - opts = &HandlerOptions{} - } - return &TextHandler{ - &commonHandler{ - json: false, - w: w, - opts: *opts, - }, - } -} - -// Enabled reports whether the handler handles records at the given level. -// The handler ignores records whose level is lower. -func (h *TextHandler) Enabled(_ context.Context, level Level) bool { - return h.commonHandler.enabled(level) -} - -// WithAttrs returns a new TextHandler whose attributes consists -// of h's attributes followed by attrs. -func (h *TextHandler) WithAttrs(attrs []Attr) Handler { - return &TextHandler{commonHandler: h.commonHandler.withAttrs(attrs)} -} - -func (h *TextHandler) WithGroup(name string) Handler { - return &TextHandler{commonHandler: h.commonHandler.withGroup(name)} -} - -// Handle formats its argument Record as a single line of space-separated -// key=value items. -// -// If the Record's time is zero, the time is omitted. -// Otherwise, the key is "time" -// and the value is output in RFC3339 format with millisecond precision. -// -// If the Record's level is zero, the level is omitted. -// Otherwise, the key is "level" -// and the value of [Level.String] is output. -// -// If the AddSource option is set and source information is available, -// the key is "source" and the value is output as FILE:LINE. -// -// The message's key is "msg". -// -// To modify these or other attributes, or remove them from the output, use -// [HandlerOptions.ReplaceAttr]. -// -// If a value implements [encoding.TextMarshaler], the result of MarshalText is -// written. Otherwise, the result of fmt.Sprint is written. -// -// Keys and values are quoted with [strconv.Quote] if they contain Unicode space -// characters, non-printing characters, '"' or '='. -// -// Keys inside groups consist of components (keys or group names) separated by -// dots. No further escaping is performed. -// Thus there is no way to determine from the key "a.b.c" whether there -// are two groups "a" and "b" and a key "c", or a single group "a.b" and a key "c", -// or single group "a" and a key "b.c". -// If it is necessary to reconstruct the group structure of a key -// even in the presence of dots inside components, use -// [HandlerOptions.ReplaceAttr] to encode that information in the key. -// -// Each call to Handle results in a single serialized call to -// io.Writer.Write. -func (h *TextHandler) Handle(_ context.Context, r Record) error { - return h.commonHandler.handle(r) -} - -func appendTextValue(s *handleState, v Value) error { - switch v.Kind() { - case KindString: - s.appendString(v.str()) - case KindTime: - s.appendTime(v.time()) - case KindAny: - if tm, ok := v.any.(encoding.TextMarshaler); ok { - data, err := tm.MarshalText() - if err != nil { - return err - } - // TODO: avoid the conversion to string. - s.appendString(string(data)) - return nil - } - if bs, ok := byteSlice(v.any); ok { - // As of Go 1.19, this only allocates for strings longer than 32 bytes. - s.buf.WriteString(strconv.Quote(string(bs))) - return nil - } - s.appendString(fmt.Sprintf("%+v", v.Any())) - default: - *s.buf = v.append(*s.buf) - } - return nil -} - -// byteSlice returns its argument as a []byte if the argument's -// underlying type is []byte, along with a second return value of true. -// Otherwise it returns nil, false. -func byteSlice(a any) ([]byte, bool) { - if bs, ok := a.([]byte); ok { - return bs, true - } - // Like Printf's %s, we allow both the slice type and the byte element type to be named. - t := reflect.TypeOf(a) - if t != nil && t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 { - return reflect.ValueOf(a).Bytes(), true - } - return nil, false -} - -func needsQuoting(s string) bool { - if len(s) == 0 { - return true - } - for i := 0; i < len(s); { - b := s[i] - if b < utf8.RuneSelf { - // Quote anything except a backslash that would need quoting in a - // JSON string, as well as space and '=' - if b != '\\' && (b == ' ' || b == '=' || !safeSet[b]) { - return true - } - i++ - continue - } - r, size := utf8.DecodeRuneInString(s[i:]) - if r == utf8.RuneError || unicode.IsSpace(r) || !unicode.IsPrint(r) { - return true - } - i += size - } - return false -} diff --git a/vendor/golang.org/x/exp/slog/value.go b/vendor/golang.org/x/exp/slog/value.go deleted file mode 100644 index df9b047..0000000 --- a/vendor/golang.org/x/exp/slog/value.go +++ /dev/null @@ -1,456 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package slog - -import ( - "fmt" - "math" - "runtime" - "strconv" - "strings" - "time" - "unsafe" - - "golang.org/x/exp/slices" -) - -// A Value can represent any Go value, but unlike type any, -// it can represent most small values without an allocation. -// The zero Value corresponds to nil. -type Value struct { - _ [0]func() // disallow == - // num holds the value for Kinds Int64, Uint64, Float64, Bool and Duration, - // the string length for KindString, and nanoseconds since the epoch for KindTime. - num uint64 - // If any is of type Kind, then the value is in num as described above. - // If any is of type *time.Location, then the Kind is Time and time.Time value - // can be constructed from the Unix nanos in num and the location (monotonic time - // is not preserved). - // If any is of type stringptr, then the Kind is String and the string value - // consists of the length in num and the pointer in any. - // Otherwise, the Kind is Any and any is the value. - // (This implies that Attrs cannot store values of type Kind, *time.Location - // or stringptr.) - any any -} - -// Kind is the kind of a Value. -type Kind int - -// The following list is sorted alphabetically, but it's also important that -// KindAny is 0 so that a zero Value represents nil. - -const ( - KindAny Kind = iota - KindBool - KindDuration - KindFloat64 - KindInt64 - KindString - KindTime - KindUint64 - KindGroup - KindLogValuer -) - -var kindStrings = []string{ - "Any", - "Bool", - "Duration", - "Float64", - "Int64", - "String", - "Time", - "Uint64", - "Group", - "LogValuer", -} - -func (k Kind) String() string { - if k >= 0 && int(k) < len(kindStrings) { - return kindStrings[k] - } - return "" -} - -// Unexported version of Kind, just so we can store Kinds in Values. -// (No user-provided value has this type.) -type kind Kind - -// Kind returns v's Kind. -func (v Value) Kind() Kind { - switch x := v.any.(type) { - case Kind: - return x - case stringptr: - return KindString - case timeLocation: - return KindTime - case groupptr: - return KindGroup - case LogValuer: - return KindLogValuer - case kind: // a kind is just a wrapper for a Kind - return KindAny - default: - return KindAny - } -} - -//////////////// Constructors - -// IntValue returns a Value for an int. -func IntValue(v int) Value { - return Int64Value(int64(v)) -} - -// Int64Value returns a Value for an int64. -func Int64Value(v int64) Value { - return Value{num: uint64(v), any: KindInt64} -} - -// Uint64Value returns a Value for a uint64. -func Uint64Value(v uint64) Value { - return Value{num: v, any: KindUint64} -} - -// Float64Value returns a Value for a floating-point number. -func Float64Value(v float64) Value { - return Value{num: math.Float64bits(v), any: KindFloat64} -} - -// BoolValue returns a Value for a bool. -func BoolValue(v bool) Value { - u := uint64(0) - if v { - u = 1 - } - return Value{num: u, any: KindBool} -} - -// Unexported version of *time.Location, just so we can store *time.Locations in -// Values. (No user-provided value has this type.) -type timeLocation *time.Location - -// TimeValue returns a Value for a time.Time. -// It discards the monotonic portion. -func TimeValue(v time.Time) Value { - if v.IsZero() { - // UnixNano on the zero time is undefined, so represent the zero time - // with a nil *time.Location instead. time.Time.Location method never - // returns nil, so a Value with any == timeLocation(nil) cannot be - // mistaken for any other Value, time.Time or otherwise. - return Value{any: timeLocation(nil)} - } - return Value{num: uint64(v.UnixNano()), any: timeLocation(v.Location())} -} - -// DurationValue returns a Value for a time.Duration. -func DurationValue(v time.Duration) Value { - return Value{num: uint64(v.Nanoseconds()), any: KindDuration} -} - -// AnyValue returns a Value for the supplied value. -// -// If the supplied value is of type Value, it is returned -// unmodified. -// -// Given a value of one of Go's predeclared string, bool, or -// (non-complex) numeric types, AnyValue returns a Value of kind -// String, Bool, Uint64, Int64, or Float64. The width of the -// original numeric type is not preserved. -// -// Given a time.Time or time.Duration value, AnyValue returns a Value of kind -// KindTime or KindDuration. The monotonic time is not preserved. -// -// For nil, or values of all other types, including named types whose -// underlying type is numeric, AnyValue returns a value of kind KindAny. -func AnyValue(v any) Value { - switch v := v.(type) { - case string: - return StringValue(v) - case int: - return Int64Value(int64(v)) - case uint: - return Uint64Value(uint64(v)) - case int64: - return Int64Value(v) - case uint64: - return Uint64Value(v) - case bool: - return BoolValue(v) - case time.Duration: - return DurationValue(v) - case time.Time: - return TimeValue(v) - case uint8: - return Uint64Value(uint64(v)) - case uint16: - return Uint64Value(uint64(v)) - case uint32: - return Uint64Value(uint64(v)) - case uintptr: - return Uint64Value(uint64(v)) - case int8: - return Int64Value(int64(v)) - case int16: - return Int64Value(int64(v)) - case int32: - return Int64Value(int64(v)) - case float64: - return Float64Value(v) - case float32: - return Float64Value(float64(v)) - case []Attr: - return GroupValue(v...) - case Kind: - return Value{any: kind(v)} - case Value: - return v - default: - return Value{any: v} - } -} - -//////////////// Accessors - -// Any returns v's value as an any. -func (v Value) Any() any { - switch v.Kind() { - case KindAny: - if k, ok := v.any.(kind); ok { - return Kind(k) - } - return v.any - case KindLogValuer: - return v.any - case KindGroup: - return v.group() - case KindInt64: - return int64(v.num) - case KindUint64: - return v.num - case KindFloat64: - return v.float() - case KindString: - return v.str() - case KindBool: - return v.bool() - case KindDuration: - return v.duration() - case KindTime: - return v.time() - default: - panic(fmt.Sprintf("bad kind: %s", v.Kind())) - } -} - -// Int64 returns v's value as an int64. It panics -// if v is not a signed integer. -func (v Value) Int64() int64 { - if g, w := v.Kind(), KindInt64; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - return int64(v.num) -} - -// Uint64 returns v's value as a uint64. It panics -// if v is not an unsigned integer. -func (v Value) Uint64() uint64 { - if g, w := v.Kind(), KindUint64; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - return v.num -} - -// Bool returns v's value as a bool. It panics -// if v is not a bool. -func (v Value) Bool() bool { - if g, w := v.Kind(), KindBool; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - return v.bool() -} - -func (a Value) bool() bool { - return a.num == 1 -} - -// Duration returns v's value as a time.Duration. It panics -// if v is not a time.Duration. -func (a Value) Duration() time.Duration { - if g, w := a.Kind(), KindDuration; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - - return a.duration() -} - -func (a Value) duration() time.Duration { - return time.Duration(int64(a.num)) -} - -// Float64 returns v's value as a float64. It panics -// if v is not a float64. -func (v Value) Float64() float64 { - if g, w := v.Kind(), KindFloat64; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - - return v.float() -} - -func (a Value) float() float64 { - return math.Float64frombits(a.num) -} - -// Time returns v's value as a time.Time. It panics -// if v is not a time.Time. -func (v Value) Time() time.Time { - if g, w := v.Kind(), KindTime; g != w { - panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) - } - return v.time() -} - -func (v Value) time() time.Time { - loc := v.any.(timeLocation) - if loc == nil { - return time.Time{} - } - return time.Unix(0, int64(v.num)).In(loc) -} - -// LogValuer returns v's value as a LogValuer. It panics -// if v is not a LogValuer. -func (v Value) LogValuer() LogValuer { - return v.any.(LogValuer) -} - -// Group returns v's value as a []Attr. -// It panics if v's Kind is not KindGroup. -func (v Value) Group() []Attr { - if sp, ok := v.any.(groupptr); ok { - return unsafe.Slice((*Attr)(sp), v.num) - } - panic("Group: bad kind") -} - -func (v Value) group() []Attr { - return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num) -} - -//////////////// Other - -// Equal reports whether v and w represent the same Go value. -func (v Value) Equal(w Value) bool { - k1 := v.Kind() - k2 := w.Kind() - if k1 != k2 { - return false - } - switch k1 { - case KindInt64, KindUint64, KindBool, KindDuration: - return v.num == w.num - case KindString: - return v.str() == w.str() - case KindFloat64: - return v.float() == w.float() - case KindTime: - return v.time().Equal(w.time()) - case KindAny, KindLogValuer: - return v.any == w.any // may panic if non-comparable - case KindGroup: - return slices.EqualFunc(v.group(), w.group(), Attr.Equal) - default: - panic(fmt.Sprintf("bad kind: %s", k1)) - } -} - -// append appends a text representation of v to dst. -// v is formatted as with fmt.Sprint. -func (v Value) append(dst []byte) []byte { - switch v.Kind() { - case KindString: - return append(dst, v.str()...) - case KindInt64: - return strconv.AppendInt(dst, int64(v.num), 10) - case KindUint64: - return strconv.AppendUint(dst, v.num, 10) - case KindFloat64: - return strconv.AppendFloat(dst, v.float(), 'g', -1, 64) - case KindBool: - return strconv.AppendBool(dst, v.bool()) - case KindDuration: - return append(dst, v.duration().String()...) - case KindTime: - return append(dst, v.time().String()...) - case KindGroup: - return fmt.Append(dst, v.group()) - case KindAny, KindLogValuer: - return fmt.Append(dst, v.any) - default: - panic(fmt.Sprintf("bad kind: %s", v.Kind())) - } -} - -// A LogValuer is any Go value that can convert itself into a Value for logging. -// -// This mechanism may be used to defer expensive operations until they are -// needed, or to expand a single value into a sequence of components. -type LogValuer interface { - LogValue() Value -} - -const maxLogValues = 100 - -// Resolve repeatedly calls LogValue on v while it implements LogValuer, -// and returns the result. -// If v resolves to a group, the group's attributes' values are not recursively -// resolved. -// If the number of LogValue calls exceeds a threshold, a Value containing an -// error is returned. -// Resolve's return value is guaranteed not to be of Kind KindLogValuer. -func (v Value) Resolve() (rv Value) { - orig := v - defer func() { - if r := recover(); r != nil { - rv = AnyValue(fmt.Errorf("LogValue panicked\n%s", stack(3, 5))) - } - }() - - for i := 0; i < maxLogValues; i++ { - if v.Kind() != KindLogValuer { - return v - } - v = v.LogValuer().LogValue() - } - err := fmt.Errorf("LogValue called too many times on Value of type %T", orig.Any()) - return AnyValue(err) -} - -func stack(skip, nFrames int) string { - pcs := make([]uintptr, nFrames+1) - n := runtime.Callers(skip+1, pcs) - if n == 0 { - return "(no stack)" - } - frames := runtime.CallersFrames(pcs[:n]) - var b strings.Builder - i := 0 - for { - frame, more := frames.Next() - fmt.Fprintf(&b, "called from %s (%s:%d)\n", frame.Function, frame.File, frame.Line) - if !more { - break - } - i++ - if i >= nFrames { - fmt.Fprintf(&b, "(rest of stack elided)\n") - break - } - } - return b.String() -} diff --git a/vendor/golang.org/x/exp/slog/value_119.go b/vendor/golang.org/x/exp/slog/value_119.go deleted file mode 100644 index 29b0d73..0000000 --- a/vendor/golang.org/x/exp/slog/value_119.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.19 && !go1.20 - -package slog - -import ( - "reflect" - "unsafe" -) - -type ( - stringptr unsafe.Pointer // used in Value.any when the Value is a string - groupptr unsafe.Pointer // used in Value.any when the Value is a []Attr -) - -// StringValue returns a new Value for a string. -func StringValue(value string) Value { - hdr := (*reflect.StringHeader)(unsafe.Pointer(&value)) - return Value{num: uint64(hdr.Len), any: stringptr(hdr.Data)} -} - -func (v Value) str() string { - var s string - hdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) - hdr.Data = uintptr(v.any.(stringptr)) - hdr.Len = int(v.num) - return s -} - -// String returns Value's value as a string, formatted like fmt.Sprint. Unlike -// the methods Int64, Float64, and so on, which panic if v is of the -// wrong kind, String never panics. -func (v Value) String() string { - if sp, ok := v.any.(stringptr); ok { - // Inlining this code makes a huge difference. - var s string - hdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) - hdr.Data = uintptr(sp) - hdr.Len = int(v.num) - return s - } - return string(v.append(nil)) -} - -// GroupValue returns a new Value for a list of Attrs. -// The caller must not subsequently mutate the argument slice. -func GroupValue(as ...Attr) Value { - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&as)) - return Value{num: uint64(hdr.Len), any: groupptr(hdr.Data)} -} diff --git a/vendor/golang.org/x/exp/slog/value_120.go b/vendor/golang.org/x/exp/slog/value_120.go deleted file mode 100644 index f7d4c09..0000000 --- a/vendor/golang.org/x/exp/slog/value_120.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.20 - -package slog - -import "unsafe" - -type ( - stringptr *byte // used in Value.any when the Value is a string - groupptr *Attr // used in Value.any when the Value is a []Attr -) - -// StringValue returns a new Value for a string. -func StringValue(value string) Value { - return Value{num: uint64(len(value)), any: stringptr(unsafe.StringData(value))} -} - -// GroupValue returns a new Value for a list of Attrs. -// The caller must not subsequently mutate the argument slice. -func GroupValue(as ...Attr) Value { - return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))} -} - -// String returns Value's value as a string, formatted like fmt.Sprint. Unlike -// the methods Int64, Float64, and so on, which panic if v is of the -// wrong kind, String never panics. -func (v Value) String() string { - if sp, ok := v.any.(stringptr); ok { - return unsafe.String(sp, v.num) - } - return string(v.append(nil)) -} - -func (v Value) str() string { - return unsafe.String(v.any.(stringptr), v.num) -} diff --git a/vendor/golang.org/x/text/LICENSE b/vendor/golang.org/x/text/LICENSE index 2a7cf70..6a66aea 100644 --- a/vendor/golang.org/x/text/LICENSE +++ b/vendor/golang.org/x/text/LICENSE @@ -1,4 +1,4 @@ -Copyright 2009 The Go Authors. +Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer. copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Google LLC nor the names of its + * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/vendor/modules.txt b/vendor/modules.txt index 9f68592..2f51cfe 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -6,27 +6,20 @@ github.com/davecgh/go-spew/spew # github.com/pmezard/go-difflib v1.0.0 ## explicit github.com/pmezard/go-difflib/difflib -# github.com/proullon/ramsql v0.1.4 -## explicit; go 1.20 +# github.com/proullon/ramsql v0.0.1 +## explicit github.com/proullon/ramsql/driver -github.com/proullon/ramsql/engine/agnostic -github.com/proullon/ramsql/engine/executor +github.com/proullon/ramsql/engine github.com/proullon/ramsql/engine/log github.com/proullon/ramsql/engine/parser +github.com/proullon/ramsql/engine/protocol # github.com/rogpeppe/go-internal v1.8.1 ## explicit; go 1.16 -# github.com/stretchr/testify v1.9.0 -## explicit; go 1.17 +# github.com/stretchr/testify v1.8.2 +## explicit; go 1.13 github.com/stretchr/testify/assert github.com/stretchr/testify/require -# golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 -## explicit; go 1.20 -golang.org/x/exp/constraints -golang.org/x/exp/slices -golang.org/x/exp/slog -golang.org/x/exp/slog/internal -golang.org/x/exp/slog/internal/buffer -# golang.org/x/text v0.20.0 +# golang.org/x/text v0.14.0 ## explicit; go 1.18 golang.org/x/text/cases golang.org/x/text/internal