diff --git a/cmd/meroxa/root/apps/list_test.go b/cmd/meroxa/root/apps/list_test.go index 4c367d2af..6e7653346 100644 --- a/cmd/meroxa/root/apps/list_test.go +++ b/cmd/meroxa/root/apps/list_test.go @@ -24,6 +24,8 @@ import ( "testing" "github.com/golang/mock/gomock" + "github.com/volatiletech/null/v8" + "github.com/meroxa/cli/log" "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" @@ -42,8 +44,8 @@ func TestListAppsExecution(t *testing.T) { Language: GoLang, Status: meroxa.ApplicationStatus{State: meroxa.ApplicationStateReady}, Functions: []meroxa.FunctionIdentifier{ - {Name: "one"}, - {Name: "two"}, + {Name: null.StringFrom("one")}, + {Name: null.StringFrom("two")}, }, } diff --git a/cmd/meroxa/root/functions/create.go b/cmd/meroxa/root/functions/create.go index dc2ea3931..97dd2eccf 100644 --- a/cmd/meroxa/root/functions/create.go +++ b/cmd/meroxa/root/functions/create.go @@ -6,6 +6,8 @@ import ( "strings" "github.com/mattn/go-shellwords" + "github.com/volatiletech/null/v8" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" "github.com/meroxa/meroxa-go/pkg/meroxa" @@ -39,6 +41,7 @@ type Create struct { Args string `long:"args" usage:"Arguments to the entrypoint"` EnvVars []string `long:"env" usage:"List of environment variables to set in the function"` Pipeline string `long:"pipeline" usage:"pipeline name to attach function to" required:"true"` + Application string `long:"app" usage:"application name or UUID to which this function belongs" required:"true"` } } @@ -49,10 +52,10 @@ func (c *Create) Usage() string { func (c *Create) Docs() builder.Docs { return builder.Docs{ Short: "Create a function", - Long: "Use `functions create` to create a function to process records from an input steram (--input-stream)", + Long: "Use `functions create` to create a function to process records from an input stream (--input-stream)", Example: ` -meroxa functions create [NAME] --input-stream connector-output-stream --image myimage --pipeline my-pipeline -meroxa functions create [NAME] --input-stream connector-output-stream --image myimage --pipeline my-pipeline --env FOO=BAR --env BAR=BAZ +meroxa functions create [NAME] --input-stream connector-output-stream --image myimage --app my-app +meroxa functions create [NAME] --input-stream connector-output-stream --image myimage --app my-app --env FOO=BAR --env BAR=BAZ `, } } @@ -86,7 +89,10 @@ func (c *Create) Execute(ctx context.Context) error { Name: c.args.Name, InputStream: c.flags.InputStream, Pipeline: meroxa.PipelineIdentifier{ - Name: c.flags.Pipeline, + Name: null.StringFrom(c.flags.Pipeline), + }, + Application: meroxa.ApplicationIdentifier{ + Name: null.StringFrom(c.flags.Application), }, Image: c.flags.Image, Command: command, diff --git a/cmd/meroxa/root/functions/describe.go b/cmd/meroxa/root/functions/describe.go index d0c201bd3..6504e4eef 100644 --- a/cmd/meroxa/root/functions/describe.go +++ b/cmd/meroxa/root/functions/describe.go @@ -19,7 +19,7 @@ var ( ) type describeFunctionClient interface { - GetFunction(ctx context.Context, nameOrUUID string) (*meroxa.Function, error) + GetFunction(ctx context.Context, appNameOrUUID, nameOrUUID string) (*meroxa.Function, error) } type Describe struct { @@ -29,6 +29,10 @@ type Describe struct { args struct { NameOrUUID string } + + flags struct { + Application string `long:"app" usage:"application name or UUID to which this function belongs" required:"true"` + } } func (d *Describe) Usage() string { @@ -42,7 +46,7 @@ func (d *Describe) Docs() builder.Docs { } func (d *Describe) Execute(ctx context.Context) error { - fun, err := d.client.GetFunction(ctx, d.args.NameOrUUID) + fun, err := d.client.GetFunction(ctx, d.flags.Application, d.args.NameOrUUID) if err != nil { return err } diff --git a/cmd/meroxa/root/functions/functions.go b/cmd/meroxa/root/functions/functions.go index 36d7a52bf..47bffca3f 100644 --- a/cmd/meroxa/root/functions/functions.go +++ b/cmd/meroxa/root/functions/functions.go @@ -14,7 +14,7 @@ var ( _ builder.CommandWithDocs = (*Functions)(nil) _ builder.CommandWithFeatureFlag = (*Functions)(nil) _ builder.CommandWithSubCommands = (*Functions)(nil) - _ builder.CommandWithHidden = (*Functions)(nil) + _ builder.CommandWithHidden = (*Functions)(nil) // for internal use only, will always be hidden ) func (*Functions) Usage() string { @@ -26,7 +26,7 @@ func (*Functions) Hidden() bool { } func (*Functions) FeatureFlag() (string, error) { - return "functions", fmt.Errorf(`no access to the Meroxa functions feature`) + return "turbine", fmt.Errorf(`no access to the Meroxa Data applications feature`) } func (*Functions) Docs() builder.Docs { diff --git a/cmd/meroxa/root/functions/list.go b/cmd/meroxa/root/functions/list.go index 835010f97..edb9ce402 100644 --- a/cmd/meroxa/root/functions/list.go +++ b/cmd/meroxa/root/functions/list.go @@ -19,19 +19,40 @@ var ( ) type listFunctionClient interface { - ListFunctions(ctx context.Context) ([]*meroxa.Function, error) + ListApplications(ctx context.Context) ([]*meroxa.Application, error) + ListFunctions(ctx context.Context, appNameOrUUID string) ([]*meroxa.Function, error) } type List struct { client listFunctionClient logger log.Logger hideHeaders bool + + flags struct { + Application string `long:"app" usage:"application name or UUID to which this function belongs"` + } } func (l *List) Execute(ctx context.Context) error { - funs, err := l.client.ListFunctions(ctx) - if err != nil { - return err + var err error + funs := make([]*meroxa.Function, 0) + if l.flags.Application != "" { + funs, err = l.client.ListFunctions(ctx, l.flags.Application) + if err != nil { + return err + } + } else { + apps, err := l.client.ListApplications(ctx) + if err != nil { + return err + } + for _, app := range apps { + fs, err := l.client.ListFunctions(ctx, app.UUID) + if err != nil { + return err + } + funs = append(funs, fs...) + } } l.logger.JSON(ctx, funs) diff --git a/cmd/meroxa/root/functions/logs.go b/cmd/meroxa/root/functions/logs.go index 7ae6c09e3..4ab91958b 100644 --- a/cmd/meroxa/root/functions/logs.go +++ b/cmd/meroxa/root/functions/logs.go @@ -20,7 +20,7 @@ var ( ) type functionLogsClient interface { - GetFunctionLogs(ctx context.Context, nameOrUUID string) (*http.Response, error) + GetFunctionLogs(ctx context.Context, appNameOrUUID, nameOrUUID string) (*http.Response, error) } type Logs struct { @@ -30,6 +30,10 @@ type Logs struct { args struct { NameOrUUID string } + + flags struct { + Application string `long:"app" usage:"application name or UUID to which this function belongs" required:"true"` + } } func (l *Logs) Usage() string { @@ -43,7 +47,7 @@ func (l *Logs) Docs() builder.Docs { } func (l *Logs) Execute(ctx context.Context) error { - resp, err := l.client.GetFunctionLogs(ctx, l.args.NameOrUUID) + resp, err := l.client.GetFunctionLogs(ctx, l.flags.Application, l.args.NameOrUUID) if err != nil { return err diff --git a/cmd/meroxa/root/functions/remove.go b/cmd/meroxa/root/functions/remove.go index c402004b6..26d8180c2 100644 --- a/cmd/meroxa/root/functions/remove.go +++ b/cmd/meroxa/root/functions/remove.go @@ -20,7 +20,7 @@ var ( ) type removeFunctionClient interface { - DeleteFunction(ctx context.Context, nameOrUUID string) (*meroxa.Function, error) + DeleteFunction(ctx context.Context, appNameOrUUID, nameOrUUID string) (*meroxa.Function, error) } type Remove struct { @@ -30,6 +30,10 @@ type Remove struct { args struct { NameOrUUID string } + + flags struct { + Application string `long:"app" usage:"application name or UUID to which this function belongs" required:"true"` + } } func (r *Remove) Usage() string { @@ -49,7 +53,7 @@ func (r *Remove) ValueToConfirm(_ context.Context) (wantInput string) { func (r *Remove) Execute(ctx context.Context) error { r.logger.Infof(ctx, "Function %q is being removed...", r.args.NameOrUUID) - e, err := r.client.DeleteFunction(ctx, r.args.NameOrUUID) + e, err := r.client.DeleteFunction(ctx, r.flags.Application, r.args.NameOrUUID) if err != nil { return err } diff --git a/go.mod b/go.mod index 1f064cd44..69df5584a 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,9 @@ require ( github.com/docker/distribution v2.8.0+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect + github.com/friendsofgo/errors v0.9.2 // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/gofrs/uuid v4.2.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.2 // indirect @@ -69,6 +71,10 @@ require ( github.com/spf13/cast v1.3.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect + github.com/volatiletech/inflect v0.0.1 // indirect + github.com/volatiletech/null/v8 v8.1.2 // indirect + github.com/volatiletech/randomize v0.0.1 // indirect + github.com/volatiletech/strmangle v0.0.2 // indirect go.opencensus.io v0.23.0 // indirect golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect @@ -82,3 +88,5 @@ require ( gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) + +replace github.com/meroxa/meroxa-go => ../meroxa-go diff --git a/go.sum b/go.sum index f53e8d165..a19841223 100644 --- a/go.sum +++ b/go.sum @@ -318,6 +318,8 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/friendsofgo/errors v0.9.2 h1:X6NYxef4efCBdwI7BgS820zFaN7Cphrmb+Pljdzjtgk= +github.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4Pn44IGoTOI= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -356,6 +358,9 @@ github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6 github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -569,9 +574,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/meroxa/funtime v0.0.0-20220113012133-85e6e898fc73/go.mod h1:K2y2GvcA4Cg3dJtckcwYWnwnJzF63FDdtAQI0fToU0Q= -github.com/meroxa/meroxa-go v0.0.0-20220208195203-71ddc3133fab/go.mod h1:HDFszURCM1cOpKE699o5Hs0T2tEIXqY+vFcsur3RiwY= -github.com/meroxa/meroxa-go v0.0.0-20220302153558-e3b3dc31559c h1:Xgq1zRKeonrGZc0NATJVDYyXniuZJftpJ2dOi6SpHB4= -github.com/meroxa/meroxa-go v0.0.0-20220302153558-e3b3dc31559c/go.mod h1:ab2rHsqdQ25tYbIohjRGNujKHu6yGhV5ALAi4GE0Ehw= github.com/meroxa/turbine v0.0.0-20220301211444-5662995ad65f h1:fWCA+cO4aPIzePOuz4drdOQAgUTM6UG7lRYgtbWLHv0= github.com/meroxa/turbine v0.0.0-20220301211444-5662995ad65f/go.mod h1:4A2E9icHDi3x4Flp9CunWyRBvNkZy6h8MS8zLvWUlmw= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -805,6 +807,15 @@ github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:tw github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/volatiletech/inflect v0.0.1 h1:2a6FcMQyhmPZcLa+uet3VJ8gLn/9svWhJxJYwvE8KsU= +github.com/volatiletech/inflect v0.0.1/go.mod h1:IBti31tG6phkHitLlr5j7shC5SOo//x0AjDzaJU1PLA= +github.com/volatiletech/null/v8 v8.1.2 h1:kiTiX1PpwvuugKwfvUNX/SU/5A2KGZMXfGD0DUHdKEI= +github.com/volatiletech/null/v8 v8.1.2/go.mod h1:98DbwNoKEpRrYtGjWFctievIfm4n4MxG0A6EBUcoS5g= +github.com/volatiletech/randomize v0.0.1 h1:eE5yajattWqTB2/eN8df4dw+8jwAzBtbdo5sbWC4nMk= +github.com/volatiletech/randomize v0.0.1/go.mod h1:GN3U0QYqfZ9FOJ67bzax1cqZ5q2xuj2mXrXBjWaRTlY= +github.com/volatiletech/strmangle v0.0.1/go.mod h1:F6RA6IkB5vq0yTG4GQ0UsbbRcl3ni9P76i+JrTBKFFg= +github.com/volatiletech/strmangle v0.0.2 h1:amhpV9ATyq1DtkQ2D8WF94uqGpkYYmSmx7X2QIner/A= +github.com/volatiletech/strmangle v0.0.2/go.mod h1:F6RA6IkB5vq0yTG4GQ0UsbbRcl3ni9P76i+JrTBKFFg= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= diff --git a/utils/display.go b/utils/display.go index 8fb7edde5..5408273fc 100644 --- a/utils/display.go +++ b/utils/display.go @@ -509,6 +509,7 @@ func FunctionsTable(funs []*meroxa.Function, hideHeaders bool) string { {Align: simpletable.AlignCenter, Text: "OUTPUT STREAM"}, {Align: simpletable.AlignCenter, Text: "STATE"}, {Align: simpletable.AlignCenter, Text: "PIPELINE"}, + {Align: simpletable.AlignCenter, Text: "APPLICATION"}, }, } } @@ -520,7 +521,8 @@ func FunctionsTable(funs []*meroxa.Function, hideHeaders bool) string { {Align: simpletable.AlignCenter, Text: p.InputStream}, {Align: simpletable.AlignCenter, Text: p.OutputStream}, {Align: simpletable.AlignCenter, Text: p.Status.State}, - {Align: simpletable.AlignCenter, Text: p.Pipeline.Name}, + {Align: simpletable.AlignCenter, Text: p.Pipeline.Name.String}, + {Align: simpletable.AlignCenter, Text: p.Application.Name.String}, } table.Body.Cells = append(table.Body.Cells, r) @@ -572,7 +574,11 @@ func FunctionTable(fun *meroxa.Function) string { }, { {Align: simpletable.AlignRight, Text: "Pipeline:"}, - {Text: fun.Pipeline.Name}, + {Text: fun.Pipeline.Name.String}, + }, + { + {Align: simpletable.AlignRight, Text: "Application:"}, + {Text: fun.Application.Name.String}, }, { {Align: simpletable.AlignRight, Text: "State:"}, @@ -827,7 +833,7 @@ func AppsTable(apps []*meroxa.Application, hideHeaders bool) string { for _, app := range apps { names := make([]string, 0) for _, f := range app.Functions { - names = append(names, f.Name) + names = append(names, f.Name.String) } r := []*simpletable.Cell{ {Align: simpletable.AlignRight, Text: app.UUID}, diff --git a/vendor/github.com/friendsofgo/errors/.gitignore b/vendor/github.com/friendsofgo/errors/.gitignore new file mode 100644 index 000000000..daf913b1b --- /dev/null +++ b/vendor/github.com/friendsofgo/errors/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/friendsofgo/errors/LICENSE b/vendor/github.com/friendsofgo/errors/LICENSE new file mode 100644 index 000000000..d40eb8a66 --- /dev/null +++ b/vendor/github.com/friendsofgo/errors/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 friendsofgo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/friendsofgo/errors/LICENSE_THIRD_PARTY b/vendor/github.com/friendsofgo/errors/LICENSE_THIRD_PARTY new file mode 100644 index 000000000..ab070c198 --- /dev/null +++ b/vendor/github.com/friendsofgo/errors/LICENSE_THIRD_PARTY @@ -0,0 +1,27 @@ +Certain parts of this library are inspired by (or entirely copied from) various third party libraries. +This file contains their licenses. + +github.com/pkg/errors: +Copyright (c) 2015, Dave Cheney +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. + +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 HOLDER 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. \ No newline at end of file diff --git a/vendor/github.com/friendsofgo/errors/Makefile b/vendor/github.com/friendsofgo/errors/Makefile new file mode 100644 index 000000000..226c4f903 --- /dev/null +++ b/vendor/github.com/friendsofgo/errors/Makefile @@ -0,0 +1,21 @@ +# general +WORKDIR = $(PWD) + +# coverage +COVERAGE_REPORT = coverage.txt +COVERAGE_PROFILE = profile.out +COVERAGE_MODE = atomic + +coverage: + @cd $(WORKDIR); \ + echo "" > $(COVERAGE_REPORT); \ + for dir in `find . -name "*.go" | grep -o '.*/' | sort | uniq`; do \ + go test -v -race $$dir -coverprofile=$(COVERAGE_PROFILE) -covermode=$(COVERAGE_MODE); \ + if [ $$? != 0 ]; then \ + exit 2; \ + fi; \ + if [ -f $(COVERAGE_PROFILE) ]; then \ + cat $(COVERAGE_PROFILE) >> $(COVERAGE_REPORT); \ + rm $(COVERAGE_PROFILE); \ + fi; \ + done; \ \ No newline at end of file diff --git a/vendor/github.com/friendsofgo/errors/README.md b/vendor/github.com/friendsofgo/errors/README.md new file mode 100644 index 000000000..c0de9cd9c --- /dev/null +++ b/vendor/github.com/friendsofgo/errors/README.md @@ -0,0 +1,102 @@ +[![FriendsOfGo](https://img.shields.io/badge/powered%20by-Friends%20of%20Go-73D7E2.svg)](https://friendsofgo.tech) +[![CircleCI](https://circleci.com/gh/friendsofgo/errors.svg?style=svg)](https://circleci.com/gh/friendsofgo/errors) +[![Build status](https://ci.appveyor.com/api/projects/status/phjkr6de4mnb19kq?svg=true)](https://ci.appveyor.com/project/aperezg/errors) +[![Version](https://img.shields.io/github/release/friendsofgo/errors.svg?style=flat-square)](https://github.com/friendsofgo/errors/releases/latest) +[![Go Report Card](https://goreportcard.com/badge/github.com/friendsofgo/errors)](https://goreportcard.com/report/github.com/friendsofgo/errors) +[![GoDoc](https://godoc.org/github.com/friendsofgo/errors?status.svg)](https://godoc.org/github.com/friendsofgo/errors) + +# errors + +This package is a fork from [github.com/pkg/errors](https://github.com/pkg/errors) package created by +[Dave Cheney](https://github.com/davecheney). The original package has no longer accepting proposals for new functionality. + +With the new errors on [go 1.13](https://godoc.org/errors), the way to using the errors on Go has some +changes that can be applied into Dave Cheney library. We want to offer one way to migrate your code to new +errors, but with the minimum refactor, for that we've created this package. + +This package provide the same interface that the original library have, but using new [go 1.13](https://godoc.org/errors) +errors, or in previous version [golang.org/x/xerrors](https://golang.org/x/xerrors) package. + +## How to start using friendsofgo/errors + +If you previously was using the package [github.com/pkg/errors](https://github.com/pkg/errors), you only need +change your imports for **github.com/friendsofgo/errors**, with this simple change now you're capable to use +[go 1.13](https://godoc.org/errors) in your code, and use the new methods `As` and `Is` if you want. + +Furthermore the method `Wrap` `Wrapf become compatible with `Unwrap` interface of new [go 1.13](https://godoc.org/errors) errors. + +## Adding context to an error + +With the original package [go 1.13](https://godoc.org/errors) if you want add context, ergo wrap your error you need to create +a new error and using the new verb `"%w" like that: + +```go +_, err := ioutil.ReadAll(r) +if err != nil { + return fmt.Errorf("read failed: %w", err) +} +``` + +Using our library you can do that forgetting to the new verb: + +```go +_, err := ioutil.ReadAll(r) +if err != nil { + return errors.Wrap(err, "read failed") +} +``` + +## Retrieving the cause of an error + +We want to keep the compatibility with the [github.com/pkg/errors](https://github.com/pkg/errors) package, for that +our package provides a `Cause` method, but this method is not longer needed, because we can use the new methods `Is` or `As` +that provides the official package. + +So previously if you needed to check an error cause, your error must be implemented the `causer` inteface: + +```go +type causer interface { + Cause() error +} +``` + +`errors.Cause` will recursively retrieve the topmost error which does not implement causer, which is assumed to be the original cause. For example: + +```go +switch err := errors.Cause(err).(type) { +case *MyError: + // handle specifically +default: + // unknown error +} +``` + +But now you can do: + +```go +var target *MyError +if errors.As(err, &target) { + // handle specifically +} else { + // unknown error +} +``` + +Or if you uses a sentinel error: + +```go +var ErrMyError = errors.New("my sentinel error") +if errors.Is(err, ErrMyError) { + // handle specifically +} else { + // unknown error +} +``` + +## Disclaimer +This package was created to using with go 1.13 version however if you uses this package with a previous version, the methods +`As`, `Is`, `Wrap` and `Wrapf` will be using [golang.org/x/xerrors](https://golang.org/x/xerrors) package. + +## Contributing + +[Contributions](https://github.com/friendsofgo/errors/issues?q=is%3Aissue+is%3Aopen) are more than welcome, if you are interested please fork this repo and send your Pull Request. diff --git a/vendor/github.com/friendsofgo/errors/appveyor.yml b/vendor/github.com/friendsofgo/errors/appveyor.yml new file mode 100644 index 000000000..251f3f7e4 --- /dev/null +++ b/vendor/github.com/friendsofgo/errors/appveyor.yml @@ -0,0 +1,33 @@ +version: build-{build}.{branch} + +clone_folder: C:\gopath\src\github.com\friendsofgo\errors +shallow_clone: true # for startup speed + +environment: + GOPATH: C:\gopath + GO111MODULE: on + +stack: go 1.13 + +platform: + - x64 + +# http://www.appveyor.com/docs/installed-software +install: + - go version + - go env + - set PATH=C:\msys64\mingw64\bin;%GOPATH%\bin;c:\go\bin;%PATH% + - go mod tidy + - gcc --version + - g++ --version + +build_script: + - go install -v ./... + +test_script: + - set PATH=C:\gopath\bin;%PATH% + - go test -v ./... + +#artifacts: +# - path: '%GOPATH%\bin\*.exe' +deploy: off diff --git a/vendor/github.com/friendsofgo/errors/errors.go b/vendor/github.com/friendsofgo/errors/errors.go new file mode 100644 index 000000000..0c08f9af6 --- /dev/null +++ b/vendor/github.com/friendsofgo/errors/errors.go @@ -0,0 +1,341 @@ +// +build go1.13 + +// Original package created by Dave Cheney +// Copyright (c) 2015, Dave Cheney +// +// Modifications of the original package by Friends of Go +// Copyright (c) 2019, Friends of Go +// +// Package errors provides simple error handling primitives. +// +// The traditional error handling idiom in Go is roughly akin to +// +// if err != nil { +// return err +// } +// +// which when applied recursively up the call stack results in error reports +// without context or debugging information. The errors package allows +// programmers to add context to the failure path in their code in a way +// that does not destroy the original value of the error. +// +// Adding context to an error +// +// The errors.Wrap function returns a new error that adds context to the +// original error by recording a stack trace at the point Wrap is called, +// together with the supplied message. For example +// +// _, err := ioutil.ReadAll(r) +// if err != nil { +// return errors.Wrap(err, "read failed") +// } +// +// If additional control is required, the errors.WithStack and +// errors.WithMessage functions destructure errors.Wrap into its component +// operations: annotating an error with a stack trace and with a message, +// respectively. +// +// Retrieving the cause of an error +// +// Using errors.Wrap constructs a stack of errors, adding context to the +// preceding error. Depending on the nature of the error it may be necessary +// to reverse the operation of errors.Wrap to retrieve the original error +// for inspection. Any error value which implements this interface +// +// type causer interface { +// Cause() error +// } +// +// can be inspected by errors.Cause. errors.Cause will recursively retrieve +// the topmost error that does not implement causer, which is assumed to be +// the original cause. For example: +// +// switch err := errors.Cause(err).(type) { +// case *MyError: +// // handle specifically +// default: +// // unknown error +// } +// +// Although the causer interface is not exported by this package, it is +// considered a part of its stable public interface. +// +// With the new standard package error we have two new ways to figure what is the cause of +// our error: +// +// var target *MyError +// if errors.As(err, &target) { +// // handle specifically +// } else { +// // unknown error +// } +// +// or even with sentinel errors: +// +// var ErrMyError = errors.New("my sentinel error") +// if errors.Is(err, ErrMyError) { +// // handle specifically +// } else { +// // unknown error +// } +// +// Formatted printing of errors +// +// All error values returned from this package implement fmt.Formatter and can +// be formatted by the fmt package. The following verbs are supported: +// +// %s print the error. If the error has a Cause it will be +// printed recursively. +// %v see %s +// %+v extended format. Each Frame of the error's StackTrace will +// be printed in detail. +// +// Retrieving the stack trace of an error or wrapper +// +// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are +// invoked. This information can be retrieved with the following interface: +// +// type stackTracer interface { +// StackTrace() errors.StackTrace +// } +// +// The returned errors.StackTrace type is defined as +// +// type StackTrace []Frame +// +// The Frame type represents a call site in the stack trace. Frame supports +// the fmt.Formatter interface that can be used for printing information about +// the stack trace of this error. For example: +// +// if err, ok := err.(stackTracer); ok { +// for _, f := range err.StackTrace() { +// fmt.Printf("%+s:%d\n", f, f) +// } +// } +// +// Although the stackTracer interface is not exported by this package, it is +// considered a part of its stable public interface. +// +// See the documentation for Frame.Format for more details. +package errors + +import ( + "errors" + "fmt" + "io" +) + +// New returns an error with the supplied message. +// New also records the stack trace at the point it was called. +func New(message string) error { + return &fundamental{ + msg: message, + stack: callers(), + } +} + +// Errorf formats according to a format specifier and returns the string +// as a value that satisfies error. +// Errorf also records the stack trace at the point it was called. +func Errorf(format string, args ...interface{}) error { + return &fundamental{ + msg: fmt.Sprintf(format, args...), + stack: callers(), + } +} + +// fundamental is an error that has a message and a stack, but no caller. +type fundamental struct { + msg string + *stack +} + +func (f *fundamental) Error() string { return f.msg } + +func (f *fundamental) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + io.WriteString(s, f.msg) + f.stack.Format(s, verb) + return + } + fallthrough + case 's': + io.WriteString(s, f.msg) + case 'q': + fmt.Fprintf(s, "%q", f.msg) + } +} + +// WithStack annotates err with a stack trace at the point WithStack was called. +// If err is nil, WithStack returns nil. +func WithStack(err error) error { + if err == nil { + return nil + } + return &withStack{ + err, + callers(), + } +} + +type withStack struct { + error + *stack +} + +func (w *withStack) Cause() error { return w.error } +func (w *withStack) Unwrap() error { return w.error } + +func (w *withStack) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + fmt.Fprintf(s, "%+v", w.Cause()) + w.stack.Format(s, verb) + return + } + fallthrough + case 's': + io.WriteString(s, w.Error()) + case 'q': + fmt.Fprintf(s, "%q", w.Error()) + } +} + +// Wrap returns an error annotating err with a stack trace +// at the point Wrap is called, and the supplied message. +// If err is nil, Wrap returns nil. +func Wrap(err error, message string) error { + if err == nil { + return nil + } + err = &withMessage{ + cause: err, + msg: message, + } + return &withStack{ + err, + callers(), + } +} + +// Wrapf returns an error annotating err with a stack trace +// at the point Wrapf is called, and the format specifier. +// If err is nil, Wrapf returns nil. +func Wrapf(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + err = &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } + return &withStack{ + err, + callers(), + } +} + +// Is reports whether any error in err's chain matches target. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error is considered to match a target if it is equal to that target or if +// it implements a method Is(error) bool such that Is(target) returns true. +func Is(err error, target error) bool { + return errors.Is(err, target) +} + +// As finds the first error in err's chain that matches target, and if so, sets +// target to that error value and returns true. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error matches target if the error's concrete value is assignable to the value +// pointed to by target, or if the error has a method As(interface{}) bool such that +// As(target) returns true. In the latter case, the As method is responsible for +// setting target. +// +// As will panic if target is not a non-nil pointer to either a type that implements +// error, or to any interface type. As returns false if err is nil. +func As(err error, target interface{}) bool { + return errors.As(err, target) +} + +// WithMessage annotates err with a new message. +// If err is nil, WithMessage returns nil. +func WithMessage(err error, message string) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: message, + } +} + +// WithMessagef annotates err with the format specifier. +// If err is nil, WithMessagef returns nil. +func WithMessagef(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } +} + +type withMessage struct { + cause error + msg string +} + +func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } +func (w *withMessage) Cause() error { return w.cause } +func (w *withMessage) Unwrap() error { return w.cause } + + +func (w *withMessage) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + fmt.Fprintf(s, "%+v\n", w.Cause()) + io.WriteString(s, w.msg) + return + } + fallthrough + case 's', 'q': + io.WriteString(s, w.Error()) + } +} + +// Cause returns the underlying cause of the error, if possible. +// An error value has a cause if it implements the following +// interface: +// +// type causer interface { +// Cause() error +// } +// +// If the error does not implement Cause, the original error will +// be returned. If the error is nil, nil will be returned without further +// investigation. +func Cause(err error) error { + type causer interface { + Cause() error + } + + for err != nil { + var c causer + if !As(err, &c) { + break + } + err = c.Cause() + } + return err +} diff --git a/vendor/github.com/friendsofgo/errors/stack.go b/vendor/github.com/friendsofgo/errors/stack.go new file mode 100644 index 000000000..779a8348f --- /dev/null +++ b/vendor/github.com/friendsofgo/errors/stack.go @@ -0,0 +1,177 @@ +package errors + +import ( + "fmt" + "io" + "path" + "runtime" + "strconv" + "strings" +) + +// Frame represents a program counter inside a stack frame. +// For historical reasons if Frame is interpreted as a uintptr +// its value represents the program counter + 1. +type Frame uintptr + +// pc returns the program counter for this frame; +// multiple frames may have the same PC value. +func (f Frame) pc() uintptr { return uintptr(f) - 1 } + +// file returns the full path to the file that contains the +// function for this Frame's pc. +func (f Frame) file() string { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return "unknown" + } + file, _ := fn.FileLine(f.pc()) + return file +} + +// line returns the line number of source code of the +// function for this Frame's pc. +func (f Frame) line() int { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return 0 + } + _, line := fn.FileLine(f.pc()) + return line +} + +// name returns the name of this function, if known. +func (f Frame) name() string { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return "unknown" + } + return fn.Name() +} + +// Format formats the frame according to the fmt.Formatter interface. +// +// %s source file +// %d source line +// %n function name +// %v equivalent to %s:%d +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+s function name and path of source file relative to the compile time +// GOPATH separated by \n\t (\n\t) +// %+v equivalent to %+s:%d +func (f Frame) Format(s fmt.State, verb rune) { + switch verb { + case 's': + switch { + case s.Flag('+'): + io.WriteString(s, f.name()) + io.WriteString(s, "\n\t") + io.WriteString(s, f.file()) + default: + io.WriteString(s, path.Base(f.file())) + } + case 'd': + io.WriteString(s, strconv.Itoa(f.line())) + case 'n': + io.WriteString(s, funcname(f.name())) + case 'v': + f.Format(s, 's') + io.WriteString(s, ":") + f.Format(s, 'd') + } +} + +// MarshalText formats a stacktrace Frame as a text string. The output is the +// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs. +func (f Frame) MarshalText() ([]byte, error) { + name := f.name() + if name == "unknown" { + return []byte(name), nil + } + return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil +} + +// StackTrace is stack of Frames from innermost (newest) to outermost (oldest). +type StackTrace []Frame + +// Format formats the stack of Frames according to the fmt.Formatter interface. +// +// %s lists source files for each Frame in the stack +// %v lists the source file and line number for each Frame in the stack +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+v Prints filename, function, and line number for each Frame in the stack. +func (st StackTrace) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + switch { + case s.Flag('+'): + for _, f := range st { + io.WriteString(s, "\n") + f.Format(s, verb) + } + case s.Flag('#'): + fmt.Fprintf(s, "%#v", []Frame(st)) + default: + st.formatSlice(s, verb) + } + case 's': + st.formatSlice(s, verb) + } +} + +// formatSlice will format this StackTrace into the given buffer as a slice of +// Frame, only valid when called with '%s' or '%v'. +func (st StackTrace) formatSlice(s fmt.State, verb rune) { + io.WriteString(s, "[") + for i, f := range st { + if i > 0 { + io.WriteString(s, " ") + } + f.Format(s, verb) + } + io.WriteString(s, "]") +} + +// stack represents a stack of program counters. +type stack []uintptr + +func (s *stack) Format(st fmt.State, verb rune) { + switch verb { + case 'v': + switch { + case st.Flag('+'): + for _, pc := range *s { + f := Frame(pc) + fmt.Fprintf(st, "\n%+v", f) + } + } + } +} + +func (s *stack) StackTrace() StackTrace { + f := make([]Frame, len(*s)) + for i := 0; i < len(f); i++ { + f[i] = Frame((*s)[i]) + } + return f +} + +func callers() *stack { + const depth = 32 + var pcs [depth]uintptr + n := runtime.Callers(3, pcs[:]) + var st stack = pcs[0:n] + return &st +} + +// funcname removes the path prefix component of a function's name reported by func.Name(). +func funcname(name string) string { + i := strings.LastIndex(name, "/") + name = name[i+1:] + i = strings.Index(name, ".") + return name[i+1:] +} diff --git a/vendor/github.com/friendsofgo/errors/xerrors.go b/vendor/github.com/friendsofgo/errors/xerrors.go new file mode 100644 index 000000000..302334188 --- /dev/null +++ b/vendor/github.com/friendsofgo/errors/xerrors.go @@ -0,0 +1,333 @@ +// +build !go1.13 + +// Original package created by Dave Cheney +// Copyright (c) 2015, Dave Cheney +// +// Modifications of the original package by Friends of Go +// Copyright (c) 2019, Friends of Go +// +// Package errors provides simple error handling primitives. +// +// The traditional error handling idiom in Go is roughly akin to +// +// if err != nil { +// return err +// } +// +// which when applied recursively up the call stack results in error reports +// without context or debugging information. The errors package allows +// programmers to add context to the failure path in their code in a way +// that does not destroy the original value of the error. +// +// Adding context to an error +// +// The errors.Wrap function returns a new error that adds context to the +// original error by recording a stack trace at the point Wrap is called, +// together with the supplied message. For example +// +// _, err := ioutil.ReadAll(r) +// if err != nil { +// return errors.Wrap(err, "read failed") +// } +// +// If additional control is required, the errors.WithStack and +// errors.WithMessage functions destructure errors.Wrap into its component +// operations: annotating an error with a stack trace and with a message, +// respectively. +// +// Retrieving the cause of an error +// +// Using errors.Wrap constructs a stack of errors, adding context to the +// preceding error. Depending on the nature of the error it may be necessary +// to reverse the operation of errors.Wrap to retrieve the original error +// for inspection. Any error value which implements this interface +// +// type causer interface { +// Cause() error +// } +// +// can be inspected by errors.Cause. errors.Cause will recursively retrieve +// the topmost error that does not implement causer, which is assumed to be +// the original cause. For example: +// +// switch err := errors.Cause(err).(type) { +// case *MyError: +// // handle specifically +// default: +// // unknown error +// } +// +// Although the causer interface is not exported by this package, it is +// considered a part of its stable public interface. +// +// With the new standard package error we have two new ways to figure what is the cause of +// our error. +// +// var target *MyError +// if errors.As(err, &target) { +// // handle specifically +// } else { +// // unknown error +// } +// +// or even with sentinel errors: +// +// var ErrMyError = errors.New("my sentinel error") +// if errors.Is(err, ErrMyError) { +// // handle specifically +// } else { +// // unknown error +// } +// +// Formatted printing of errors +// +// All error values returned from this package implement fmt.Formatter and can +// be formatted by the fmt package. The following verbs are supported: +// +// %s print the error. If the error has a Cause it will be +// printed recursively. +// %v see %s +// %+v extended format. Each Frame of the error's StackTrace will +// be printed in detail. +// +// Retrieving the stack trace of an error or wrapper +// +// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are +// invoked. This information can be retrieved with the following interface: +// +// type stackTracer interface { +// StackTrace() errors.StackTrace +// } +// +// The returned errors.StackTrace type is defined as +// +// type StackTrace []Frame +// +// The Frame type represents a call site in the stack trace. Frame supports +// the fmt.Formatter interface that can be used for printing information about +// the stack trace of this error. For example: +// +// if err, ok := err.(stackTracer); ok { +// for _, f := range err.StackTrace() { +// fmt.Printf("%+s:%d\n", f, f) +// } +// } +// +// Although the stackTracer interface is not exported by this package, it is +// considered a part of its stable public interface. +// +// See the documentation for Frame.Format for more details. +package errors + +import ( + "fmt" + "io" + + "golang.org/x/xerrors" +) + +// New returns an error with the supplied message. +// New also records the stack trace at the point it was called. +func New(message string) error { + return &fundamental{ + msg: message, + stack: callers(), + } +} + +// Errorf formats according to a format specifier and returns the string +// as a value that satisfies error. +// Errorf also records the stack trace at the point it was called. +func Errorf(format string, args ...interface{}) error { + return &fundamental{ + msg: fmt.Sprintf(format, args...), + stack: callers(), + } +} + +// fundamental is an error that has a message and a stack, but no caller. +type fundamental struct { + msg string + *stack +} + +func (f *fundamental) Error() string { return f.msg } + +func (f *fundamental) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + io.WriteString(s, f.msg) + f.stack.Format(s, verb) + return + } + fallthrough + case 's': + io.WriteString(s, f.msg) + case 'q': + fmt.Fprintf(s, "%q", f.msg) + } +} + +// WithStack annotates err with a stack trace at the point WithStack was called. +// If err is nil, WithStack returns nil. +func WithStack(err error) error { + if err == nil { + return nil + } + return &withStack{ + err, + callers(), + } +} + +type withStack struct { + error + *stack +} + +func (w *withStack) Cause() error { return w.error } +func (w *withStack) Unwrap() error { return w.error } + +func (w *withStack) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + fmt.Fprintf(s, "%+v", w.Cause()) + w.stack.Format(s, verb) + return + } + fallthrough + case 's': + io.WriteString(s, w.Error()) + case 'q': + fmt.Fprintf(s, "%q", w.Error()) + } +} + +// Wrap returns an error annotating err with a stack trace +// at the point Wrap is called, and the supplied message. +// If err is nil, Wrap returns nil. +func Wrap(err error, message string) error { + if err == nil { + return nil + } + err = &withMessage{ + cause: err, + msg: message, + } + return &withStack{ + err, + callers(), + } +} + +// Wrapf returns an error annotating err with a stack trace +// at the point Wrapf is called, and the format specifier. +// If err is nil, Wrapf returns nil. +func Wrapf(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + err = &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } + return &withStack{ + err, + callers(), + } +} + +// Is reports whether any error in err's chain matches target. +// +// An error is considered to match a target if it is equal to that target or if +// it implements a method Is(error) bool such that Is(target) returns true. +func Is(err error, target error) bool { + return xerrors.Is(err, target) +} + +// As finds the first error in err's chain that matches the type to which target +// points, and if so, sets the target to its value and returns true. An error +// matches a type if it is assignable to the target type, or if it has a method +// As(interface{}) bool such that As(target) returns true. As will panic if target +// is not a non-nil pointer to a type which implements error or is of interface type. +// +// The As method should set the target to its value and return true if err +// matches the type to which target points. +func As(err error, target interface{}) bool { + return xerrors.As(err, target) +} + +// WithMessage annotates err with a new message. +// If err is nil, WithMessage returns nil. +func WithMessage(err error, message string) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: message, + } +} + +// WithMessagef annotates err with the format specifier. +// If err is nil, WithMessagef returns nil. +func WithMessagef(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } +} + +type withMessage struct { + cause error + msg string +} + +func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } +func (w *withMessage) Cause() error { return w.cause } +func (w *withMessage) Unwrap() error { return w.cause } + +func (w *withMessage) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + fmt.Fprintf(s, "%+v\n", w.Cause()) + io.WriteString(s, w.msg) + return + } + fallthrough + case 's', 'q': + io.WriteString(s, w.Error()) + } +} + +// Cause returns the underlying cause of the error, if possible. +// An error value has a cause if it implements the following +// interface: +// +// type causer interface { +// Cause() error +// } +// +// If the error does not implement Cause, the original error will +// be returned. If the error is nil, nil will be returned without further +// investigation. +func Cause(err error) error { + type causer interface { + Cause() error + } + + for err != nil { + var c causer + if !As(err, &c) { + break + } + err = c.Cause() + } + return err +} diff --git a/vendor/github.com/gofrs/uuid/.gitignore b/vendor/github.com/gofrs/uuid/.gitignore new file mode 100644 index 000000000..666dbbb5b --- /dev/null +++ b/vendor/github.com/gofrs/uuid/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# binary bundle generated by go-fuzz +uuid-fuzz.zip diff --git a/vendor/github.com/gofrs/uuid/LICENSE b/vendor/github.com/gofrs/uuid/LICENSE new file mode 100644 index 000000000..926d54987 --- /dev/null +++ b/vendor/github.com/gofrs/uuid/LICENSE @@ -0,0 +1,20 @@ +Copyright (C) 2013-2018 by Maxim Bublis + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/gofrs/uuid/README.md b/vendor/github.com/gofrs/uuid/README.md new file mode 100644 index 000000000..48303001b --- /dev/null +++ b/vendor/github.com/gofrs/uuid/README.md @@ -0,0 +1,109 @@ +# UUID + +[![License](https://img.shields.io/github/license/gofrs/uuid.svg)](https://github.com/gofrs/uuid/blob/master/LICENSE) +[![Build Status](https://travis-ci.org/gofrs/uuid.svg?branch=master)](https://travis-ci.org/gofrs/uuid) +[![GoDoc](http://godoc.org/github.com/gofrs/uuid?status.svg)](http://godoc.org/github.com/gofrs/uuid) +[![Coverage Status](https://codecov.io/gh/gofrs/uuid/branch/master/graphs/badge.svg?branch=master)](https://codecov.io/gh/gofrs/uuid/) +[![Go Report Card](https://goreportcard.com/badge/github.com/gofrs/uuid)](https://goreportcard.com/report/github.com/gofrs/uuid) + +Package uuid provides a pure Go implementation of Universally Unique Identifiers +(UUID) variant as defined in RFC-4122. This package supports both the creation +and parsing of UUIDs in different formats. + +This package supports the following UUID versions: +* Version 1, based on timestamp and MAC address (RFC-4122) +* Version 3, based on MD5 hashing of a named value (RFC-4122) +* Version 4, based on random numbers (RFC-4122) +* Version 5, based on SHA-1 hashing of a named value (RFC-4122) + +## Project History + +This project was originally forked from the +[github.com/satori/go.uuid](https://github.com/satori/go.uuid) repository after +it appeared to be no longer maintained, while exhibiting [critical +flaws](https://github.com/satori/go.uuid/issues/73). We have decided to take +over this project to ensure it receives regular maintenance for the benefit of +the larger Go community. + +We'd like to thank Maxim Bublis for his hard work on the original iteration of +the package. + +## License + +This source code of this package is released under the MIT License. Please see +the [LICENSE](https://github.com/gofrs/uuid/blob/master/LICENSE) for the full +content of the license. + +## Recommended Package Version + +We recommend using v2.0.0+ of this package, as versions prior to 2.0.0 were +created before our fork of the original package and have some known +deficiencies. + +## Installation + +It is recommended to use a package manager like `dep` that understands tagged +releases of a package, as well as semantic versioning. + +If you are unable to make use of a dependency manager with your project, you can +use the `go get` command to download it directly: + +```Shell +$ go get github.com/gofrs/uuid +``` + +## Requirements + +Due to subtests not being supported in older versions of Go, this package is +only regularly tested against Go 1.7+. This package may work perfectly fine with +Go 1.2+, but support for these older versions is not actively maintained. + +## Go 1.11 Modules + +As of v3.2.0, this repository no longer adopts Go modules, and v3.2.0 no longer has a `go.mod` file. As a result, v3.2.0 also drops support for the `github.com/gofrs/uuid/v3` import path. Only module-based consumers are impacted. With the v3.2.0 release, _all_ gofrs/uuid consumers should use the `github.com/gofrs/uuid` import path. + +An existing module-based consumer will continue to be able to build using the `github.com/gofrs/uuid/v3` import path using any valid consumer `go.mod` that worked prior to the publishing of v3.2.0, but any module-based consumer should start using the `github.com/gofrs/uuid` import path when possible and _must_ use the `github.com/gofrs/uuid` import path prior to upgrading to v3.2.0. + +Please refer to [Issue #61](https://github.com/gofrs/uuid/issues/61) and [Issue #66](https://github.com/gofrs/uuid/issues/66) for more details. + +## Usage + +Here is a quick overview of how to use this package. For more detailed +documentation, please see the [GoDoc Page](http://godoc.org/github.com/gofrs/uuid). + +```go +package main + +import ( + "log" + + "github.com/gofrs/uuid" +) + +// Create a Version 4 UUID, panicking on error. +// Use this form to initialize package-level variables. +var u1 = uuid.Must(uuid.NewV4()) + +func main() { + // Create a Version 4 UUID. + u2, err := uuid.NewV4() + if err != nil { + log.Fatalf("failed to generate UUID: %v", err) + } + log.Printf("generated Version 4 UUID %v", u2) + + // Parse a UUID from a string. + s := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + u3, err := uuid.FromString(s) + if err != nil { + log.Fatalf("failed to parse UUID %q: %v", s, err) + } + log.Printf("successfully parsed UUID %v", u3) +} +``` + +## References + +* [RFC-4122](https://tools.ietf.org/html/rfc4122) +* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01) +* [New UUID Formats RFC Draft (Peabody) Rev 02](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-02) diff --git a/vendor/github.com/gofrs/uuid/codec.go b/vendor/github.com/gofrs/uuid/codec.go new file mode 100644 index 000000000..e3014c68c --- /dev/null +++ b/vendor/github.com/gofrs/uuid/codec.go @@ -0,0 +1,212 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package uuid + +import ( + "bytes" + "encoding/hex" + "fmt" +) + +// FromBytes returns a UUID generated from the raw byte slice input. +// It will return an error if the slice isn't 16 bytes long. +func FromBytes(input []byte) (UUID, error) { + u := UUID{} + err := u.UnmarshalBinary(input) + return u, err +} + +// FromBytesOrNil returns a UUID generated from the raw byte slice input. +// Same behavior as FromBytes(), but returns uuid.Nil instead of an error. +func FromBytesOrNil(input []byte) UUID { + uuid, err := FromBytes(input) + if err != nil { + return Nil + } + return uuid +} + +// FromString returns a UUID parsed from the input string. +// Input is expected in a form accepted by UnmarshalText. +func FromString(input string) (UUID, error) { + u := UUID{} + err := u.UnmarshalText([]byte(input)) + return u, err +} + +// FromStringOrNil returns a UUID parsed from the input string. +// Same behavior as FromString(), but returns uuid.Nil instead of an error. +func FromStringOrNil(input string) UUID { + uuid, err := FromString(input) + if err != nil { + return Nil + } + return uuid +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The encoding is the same as returned by the String() method. +func (u UUID) MarshalText() ([]byte, error) { + return []byte(u.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// Following formats are supported: +// +// "6ba7b810-9dad-11d1-80b4-00c04fd430c8", +// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", +// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" +// "6ba7b8109dad11d180b400c04fd430c8" +// "{6ba7b8109dad11d180b400c04fd430c8}", +// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8" +// +// ABNF for supported UUID text representation follows: +// +// URN := 'urn' +// UUID-NID := 'uuid' +// +// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | +// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | +// 'A' | 'B' | 'C' | 'D' | 'E' | 'F' +// +// hexoct := hexdig hexdig +// 2hexoct := hexoct hexoct +// 4hexoct := 2hexoct 2hexoct +// 6hexoct := 4hexoct 2hexoct +// 12hexoct := 6hexoct 6hexoct +// +// hashlike := 12hexoct +// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct +// +// plain := canonical | hashlike +// uuid := canonical | hashlike | braced | urn +// +// braced := '{' plain '}' | '{' hashlike '}' +// urn := URN ':' UUID-NID ':' plain +// +func (u *UUID) UnmarshalText(text []byte) error { + switch len(text) { + case 32: + return u.decodeHashLike(text) + case 34, 38: + return u.decodeBraced(text) + case 36: + return u.decodeCanonical(text) + case 41, 45: + return u.decodeURN(text) + default: + return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(text), text) + } +} + +// decodeCanonical decodes UUID strings that are formatted as defined in RFC-4122 (section 3): +// "6ba7b810-9dad-11d1-80b4-00c04fd430c8". +func (u *UUID) decodeCanonical(t []byte) error { + if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' { + return fmt.Errorf("uuid: incorrect UUID format in string %q", t) + } + + src := t + dst := u[:] + + for i, byteGroup := range byteGroups { + if i > 0 { + src = src[1:] // skip dash + } + _, err := hex.Decode(dst[:byteGroup/2], src[:byteGroup]) + if err != nil { + return err + } + src = src[byteGroup:] + dst = dst[byteGroup/2:] + } + + return nil +} + +// decodeHashLike decodes UUID strings that are using the following format: +// "6ba7b8109dad11d180b400c04fd430c8". +func (u *UUID) decodeHashLike(t []byte) error { + src := t[:] + dst := u[:] + + _, err := hex.Decode(dst, src) + return err +} + +// decodeBraced decodes UUID strings that are using the following formats: +// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" +// "{6ba7b8109dad11d180b400c04fd430c8}". +func (u *UUID) decodeBraced(t []byte) error { + l := len(t) + + if t[0] != '{' || t[l-1] != '}' { + return fmt.Errorf("uuid: incorrect UUID format in string %q", t) + } + + return u.decodePlain(t[1 : l-1]) +} + +// decodeURN decodes UUID strings that are using the following formats: +// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" +// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8". +func (u *UUID) decodeURN(t []byte) error { + total := len(t) + + urnUUIDPrefix := t[:9] + + if !bytes.Equal(urnUUIDPrefix, urnPrefix) { + return fmt.Errorf("uuid: incorrect UUID format in string %q", t) + } + + return u.decodePlain(t[9:total]) +} + +// decodePlain decodes UUID strings that are using the following formats: +// "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format +// "6ba7b8109dad11d180b400c04fd430c8". +func (u *UUID) decodePlain(t []byte) error { + switch len(t) { + case 32: + return u.decodeHashLike(t) + case 36: + return u.decodeCanonical(t) + default: + return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(t), t) + } +} + +// MarshalBinary implements the encoding.BinaryMarshaler interface. +func (u UUID) MarshalBinary() ([]byte, error) { + return u.Bytes(), nil +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. +// It will return an error if the slice isn't 16 bytes long. +func (u *UUID) UnmarshalBinary(data []byte) error { + if len(data) != Size { + return fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data)) + } + copy(u[:], data) + + return nil +} diff --git a/vendor/github.com/gofrs/uuid/fuzz.go b/vendor/github.com/gofrs/uuid/fuzz.go new file mode 100644 index 000000000..afaefbc8e --- /dev/null +++ b/vendor/github.com/gofrs/uuid/fuzz.go @@ -0,0 +1,47 @@ +// Copyright (c) 2018 Andrei Tudor Călin +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// +build gofuzz + +package uuid + +// Fuzz implements a simple fuzz test for FromString / UnmarshalText. +// +// To run: +// +// $ go get github.com/dvyukov/go-fuzz/... +// $ cd $GOPATH/src/github.com/gofrs/uuid +// $ go-fuzz-build github.com/gofrs/uuid +// $ go-fuzz -bin=uuid-fuzz.zip -workdir=./testdata +// +// If you make significant changes to FromString / UnmarshalText and add +// new cases to fromStringTests (in codec_test.go), please run +// +// $ go test -seed_fuzz_corpus +// +// to seed the corpus with the new interesting inputs, then run the fuzzer. +func Fuzz(data []byte) int { + _, err := FromString(string(data)) + if err != nil { + return 0 + } + return 1 +} diff --git a/vendor/github.com/gofrs/uuid/generator.go b/vendor/github.com/gofrs/uuid/generator.go new file mode 100644 index 000000000..38bf68502 --- /dev/null +++ b/vendor/github.com/gofrs/uuid/generator.go @@ -0,0 +1,573 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package uuid + +import ( + "crypto/md5" + "crypto/rand" + "crypto/sha1" + "encoding/binary" + "errors" + "fmt" + "hash" + "io" + "net" + "sync" + "time" +) + +// Difference in 100-nanosecond intervals between +// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970). +const epochStart = 122192928000000000 + +type epochFunc func() time.Time + +// HWAddrFunc is the function type used to provide hardware (MAC) addresses. +type HWAddrFunc func() (net.HardwareAddr, error) + +// DefaultGenerator is the default UUID Generator used by this package. +var DefaultGenerator Generator = NewGen() + +// NewV1 returns a UUID based on the current timestamp and MAC address. +func NewV1() (UUID, error) { + return DefaultGenerator.NewV1() +} + +// NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name. +func NewV3(ns UUID, name string) UUID { + return DefaultGenerator.NewV3(ns, name) +} + +// NewV4 returns a randomly generated UUID. +func NewV4() (UUID, error) { + return DefaultGenerator.NewV4() +} + +// NewV5 returns a UUID based on SHA-1 hash of the namespace UUID and name. +func NewV5(ns UUID, name string) UUID { + return DefaultGenerator.NewV5(ns, name) +} + +// NewV6 returns a k-sortable UUID based on a timestamp and 48 bits of +// pseudorandom data. The timestamp in a V6 UUID is the same as V1, with the bit +// order being adjusted to allow the UUID to be k-sortable. +// +// This is implemented based on revision 02 of the Peabody UUID draft, and may +// be subject to change pending further revisions. Until the final specification +// revision is finished, changes required to implement updates to the spec will +// not be considered a breaking change. They will happen as a minor version +// releases until the spec is final. +func NewV6() (UUID, error) { + return DefaultGenerator.NewV6() +} + +// NewV7 returns a k-sortable UUID based on the current UNIX epoch, with the +// ability to configure the timestamp's precision from millisecond all the way +// to nanosecond. The additional precision is supported by reducing the amount +// of pseudorandom data that makes up the rest of the UUID. +// +// If an unknown Precision argument is passed to this method it will panic. As +// such it's strongly encouraged to use the package-provided constants for this +// value. +// +// This is implemented based on revision 02 of the Peabody UUID draft, and may +// be subject to change pending further revisions. Until the final specification +// revision is finished, changes required to implement updates to the spec will +// not be considered a breaking change. They will happen as a minor version +// releases until the spec is final. +func NewV7(p Precision) (UUID, error) { + return DefaultGenerator.NewV7(p) +} + +// Generator provides an interface for generating UUIDs. +type Generator interface { + NewV1() (UUID, error) + NewV3(ns UUID, name string) UUID + NewV4() (UUID, error) + NewV5(ns UUID, name string) UUID + NewV6() (UUID, error) + NewV7(Precision) (UUID, error) +} + +// Gen is a reference UUID generator based on the specifications laid out in +// RFC-4122 and DCE 1.1: Authentication and Security Services. This type +// satisfies the Generator interface as defined in this package. +// +// For consumers who are generating V1 UUIDs, but don't want to expose the MAC +// address of the node generating the UUIDs, the NewGenWithHWAF() function has been +// provided as a convenience. See the function's documentation for more info. +// +// The authors of this package do not feel that the majority of users will need +// to obfuscate their MAC address, and so we recommend using NewGen() to create +// a new generator. +type Gen struct { + clockSequenceOnce sync.Once + hardwareAddrOnce sync.Once + storageMutex sync.Mutex + + rand io.Reader + + epochFunc epochFunc + hwAddrFunc HWAddrFunc + lastTime uint64 + clockSequence uint16 + hardwareAddr [6]byte + + v7LastTime uint64 + v7LastSubsec uint64 + v7ClockSequence uint16 +} + +// interface check -- build will fail if *Gen doesn't satisfy Generator +var _ Generator = (*Gen)(nil) + +// NewGen returns a new instance of Gen with some default values set. Most +// people should use this. +func NewGen() *Gen { + return NewGenWithHWAF(defaultHWAddrFunc) +} + +// NewGenWithHWAF builds a new UUID generator with the HWAddrFunc provided. Most +// consumers should use NewGen() instead. +// +// This is used so that consumers can generate their own MAC addresses, for use +// in the generated UUIDs, if there is some concern about exposing the physical +// address of the machine generating the UUID. +// +// The Gen generator will only invoke the HWAddrFunc once, and cache that MAC +// address for all the future UUIDs generated by it. If you'd like to switch the +// MAC address being used, you'll need to create a new generator using this +// function. +func NewGenWithHWAF(hwaf HWAddrFunc) *Gen { + return &Gen{ + epochFunc: time.Now, + hwAddrFunc: hwaf, + rand: rand.Reader, + } +} + +// NewV1 returns a UUID based on the current timestamp and MAC address. +func (g *Gen) NewV1() (UUID, error) { + u := UUID{} + + timeNow, clockSeq, err := g.getClockSequence() + if err != nil { + return Nil, err + } + binary.BigEndian.PutUint32(u[0:], uint32(timeNow)) + binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) + binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) + binary.BigEndian.PutUint16(u[8:], clockSeq) + + hardwareAddr, err := g.getHardwareAddr() + if err != nil { + return Nil, err + } + copy(u[10:], hardwareAddr) + + u.SetVersion(V1) + u.SetVariant(VariantRFC4122) + + return u, nil +} + +// NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name. +func (g *Gen) NewV3(ns UUID, name string) UUID { + u := newFromHash(md5.New(), ns, name) + u.SetVersion(V3) + u.SetVariant(VariantRFC4122) + + return u +} + +// NewV4 returns a randomly generated UUID. +func (g *Gen) NewV4() (UUID, error) { + u := UUID{} + if _, err := io.ReadFull(g.rand, u[:]); err != nil { + return Nil, err + } + u.SetVersion(V4) + u.SetVariant(VariantRFC4122) + + return u, nil +} + +// NewV5 returns a UUID based on SHA-1 hash of the namespace UUID and name. +func (g *Gen) NewV5(ns UUID, name string) UUID { + u := newFromHash(sha1.New(), ns, name) + u.SetVersion(V5) + u.SetVariant(VariantRFC4122) + + return u +} + +// NewV6 returns a k-sortable UUID based on a timestamp and 48 bits of +// pseudorandom data. The timestamp in a V6 UUID is the same as V1, with the bit +// order being adjusted to allow the UUID to be k-sortable. +// +// This is implemented based on revision 02 of the Peabody UUID draft, and may +// be subject to change pending further revisions. Until the final specification +// revision is finished, changes required to implement updates to the spec will +// not be considered a breaking change. They will happen as a minor version +// releases until the spec is final. +func (g *Gen) NewV6() (UUID, error) { + var u UUID + + if _, err := io.ReadFull(g.rand, u[10:]); err != nil { + return Nil, err + } + + timeNow, clockSeq, err := g.getClockSequence() + if err != nil { + return Nil, err + } + + binary.BigEndian.PutUint32(u[0:], uint32(timeNow>>28)) // set time_high + binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>12)) // set time_mid + binary.BigEndian.PutUint16(u[6:], uint16(timeNow&0xfff)) // set time_low (minus four version bits) + binary.BigEndian.PutUint16(u[8:], clockSeq&0x3fff) // set clk_seq_hi_res (minus two variant bits) + + u.SetVersion(V6) + u.SetVariant(VariantRFC4122) + + return u, nil +} + +// getClockSequence returns the epoch and clock sequence for V1 and V6 UUIDs. +func (g *Gen) getClockSequence() (uint64, uint16, error) { + var err error + g.clockSequenceOnce.Do(func() { + buf := make([]byte, 2) + if _, err = io.ReadFull(g.rand, buf); err != nil { + return + } + g.clockSequence = binary.BigEndian.Uint16(buf) + }) + if err != nil { + return 0, 0, err + } + + g.storageMutex.Lock() + defer g.storageMutex.Unlock() + + timeNow := g.getEpoch() + // Clock didn't change since last UUID generation. + // Should increase clock sequence. + if timeNow <= g.lastTime { + g.clockSequence++ + } + g.lastTime = timeNow + + return timeNow, g.clockSequence, nil +} + +// Precision is used to configure the V7 generator, to specify how precise the +// timestamp within the UUID should be. +type Precision byte + +const ( + NanosecondPrecision Precision = iota + MicrosecondPrecision + MillisecondPrecision +) + +func (p Precision) String() string { + switch p { + case NanosecondPrecision: + return "nanosecond" + + case MicrosecondPrecision: + return "microsecond" + + case MillisecondPrecision: + return "millisecond" + + default: + return "unknown" + } +} + +// Duration returns the time.Duration for a specific precision. If the Precision +// value is not known, this returns 0. +func (p Precision) Duration() time.Duration { + switch p { + case NanosecondPrecision: + return time.Nanosecond + + case MicrosecondPrecision: + return time.Microsecond + + case MillisecondPrecision: + return time.Millisecond + + default: + return 0 + } +} + +// NewV7 returns a k-sortable UUID based on the current UNIX epoch, with the +// ability to configure the timestamp's precision from millisecond all the way +// to nanosecond. The additional precision is supported by reducing the amount +// of pseudorandom data that makes up the rest of the UUID. +// +// If an unknown Precision argument is passed to this method it will panic. As +// such it's strongly encouraged to use the package-provided constants for this +// value. +// +// This is implemented based on revision 02 of the Peabody UUID draft, and may +// be subject to change pending further revisions. Until the final specification +// revision is finished, changes required to implement updates to the spec will +// not be considered a breaking change. They will happen as a minor version +// releases until the spec is final. +func (g *Gen) NewV7(p Precision) (UUID, error) { + var u UUID + var err error + + switch p { + case NanosecondPrecision: + u, err = g.newV7Nano() + + case MicrosecondPrecision: + u, err = g.newV7Micro() + + case MillisecondPrecision: + u, err = g.newV7Milli() + + default: + panic(fmt.Sprintf("unknown precision value %d", p)) + } + + if err != nil { + return Nil, err + } + + u.SetVersion(V7) + u.SetVariant(VariantRFC4122) + + return u, nil +} + +func (g *Gen) newV7Milli() (UUID, error) { + var u UUID + + if _, err := io.ReadFull(g.rand, u[8:]); err != nil { + return Nil, err + } + + sec, nano, seq, err := g.getV7ClockSequence(MillisecondPrecision) + if err != nil { + return Nil, err + } + + msec := (nano / 1000000) & 0xfff + + d := (sec << 28) // set unixts field + d |= (msec << 16) // set msec field + d |= (uint64(seq) & 0xfff) // set seq field + + binary.BigEndian.PutUint64(u[:], d) + + return u, nil +} + +func (g *Gen) newV7Micro() (UUID, error) { + var u UUID + + if _, err := io.ReadFull(g.rand, u[10:]); err != nil { + return Nil, err + } + + sec, nano, seq, err := g.getV7ClockSequence(MicrosecondPrecision) + if err != nil { + return Nil, err + } + + usec := nano / 1000 + usech := (usec << 4) & 0xfff0000 + usecl := usec & 0xfff + + d := (sec << 28) // set unixts field + d |= usech | usecl // set usec fields + + binary.BigEndian.PutUint64(u[:], d) + binary.BigEndian.PutUint16(u[8:], seq) + + return u, nil +} + +func (g *Gen) newV7Nano() (UUID, error) { + var u UUID + + if _, err := io.ReadFull(g.rand, u[11:]); err != nil { + return Nil, err + } + + sec, nano, seq, err := g.getV7ClockSequence(NanosecondPrecision) + if err != nil { + return Nil, err + } + + nano &= 0x3fffffffff + nanoh := nano >> 26 + nanom := (nano >> 14) & 0xfff + nanol := uint16(nano & 0x3fff) + + d := (sec << 28) // set unixts field + d |= (nanoh << 16) | nanom // set nsec high and med fields + + binary.BigEndian.PutUint64(u[:], d) + binary.BigEndian.PutUint16(u[8:], nanol) // set nsec low field + + u[10] = byte(seq) // set seq field + + return u, nil +} + +const ( + maxSeq14 = (1 << 14) - 1 + maxSeq12 = (1 << 12) - 1 + maxSeq8 = (1 << 8) - 1 +) + +// getV7ClockSequence returns the unix epoch, nanoseconds of current second, and +// the sequence for V7 UUIDs. +func (g *Gen) getV7ClockSequence(p Precision) (epoch uint64, nano uint64, seq uint16, err error) { + g.storageMutex.Lock() + defer g.storageMutex.Unlock() + + tn := g.epochFunc() + unix := uint64(tn.Unix()) + nsec := uint64(tn.Nanosecond()) + + // V7 UUIDs have more precise requirements around how the clock sequence + // value is generated and used. Specifically they require that the sequence + // be zero, unless we've already generated a UUID within this unit of time + // (millisecond, microsecond, or nanosecond) at which point you should + // increment the sequence. Likewise if time has warped backwards for some reason (NTP + // adjustment?), we also increment the clock sequence to reduce the risk of a + // collision. + switch { + case unix < g.v7LastTime: + g.v7ClockSequence++ + + case unix > g.v7LastTime: + g.v7ClockSequence = 0 + + case unix == g.v7LastTime: + switch p { + case NanosecondPrecision: + if nsec <= g.v7LastSubsec { + if g.v7ClockSequence >= maxSeq8 { + return 0, 0, 0, errors.New("generating nanosecond precision UUIDv7s too fast: internal clock sequence would roll over") + } + + g.v7ClockSequence++ + } else { + g.v7ClockSequence = 0 + } + + case MicrosecondPrecision: + if nsec/1000 <= g.v7LastSubsec/1000 { + if g.v7ClockSequence >= maxSeq14 { + return 0, 0, 0, errors.New("generating microsecond precision UUIDv7s too fast: internal clock sequence would roll over") + } + + g.v7ClockSequence++ + } else { + g.v7ClockSequence = 0 + } + + case MillisecondPrecision: + if nsec/1000000 <= g.v7LastSubsec/1000000 { + if g.v7ClockSequence >= maxSeq12 { + return 0, 0, 0, errors.New("generating millisecond precision UUIDv7s too fast: internal clock sequence would roll over") + } + + g.v7ClockSequence++ + } else { + g.v7ClockSequence = 0 + } + + default: + panic(fmt.Sprintf("unknown precision value %d", p)) + } + } + + g.v7LastTime = unix + g.v7LastSubsec = nsec + + return unix, nsec, g.v7ClockSequence, nil +} + +// Returns the hardware address. +func (g *Gen) getHardwareAddr() ([]byte, error) { + var err error + g.hardwareAddrOnce.Do(func() { + var hwAddr net.HardwareAddr + if hwAddr, err = g.hwAddrFunc(); err == nil { + copy(g.hardwareAddr[:], hwAddr) + return + } + + // Initialize hardwareAddr randomly in case + // of real network interfaces absence. + if _, err = io.ReadFull(g.rand, g.hardwareAddr[:]); err != nil { + return + } + // Set multicast bit as recommended by RFC-4122 + g.hardwareAddr[0] |= 0x01 + }) + if err != nil { + return []byte{}, err + } + return g.hardwareAddr[:], nil +} + +// Returns the difference between UUID epoch (October 15, 1582) +// and current time in 100-nanosecond intervals. +func (g *Gen) getEpoch() uint64 { + return epochStart + uint64(g.epochFunc().UnixNano()/100) +} + +// Returns the UUID based on the hashing of the namespace UUID and name. +func newFromHash(h hash.Hash, ns UUID, name string) UUID { + u := UUID{} + h.Write(ns[:]) + h.Write([]byte(name)) + copy(u[:], h.Sum(nil)) + + return u +} + +// Returns the hardware address. +func defaultHWAddrFunc() (net.HardwareAddr, error) { + ifaces, err := net.Interfaces() + if err != nil { + return []byte{}, err + } + for _, iface := range ifaces { + if len(iface.HardwareAddr) >= 6 { + return iface.HardwareAddr, nil + } + } + return []byte{}, fmt.Errorf("uuid: no HW address found") +} diff --git a/vendor/github.com/gofrs/uuid/sql.go b/vendor/github.com/gofrs/uuid/sql.go new file mode 100644 index 000000000..6f254a4fd --- /dev/null +++ b/vendor/github.com/gofrs/uuid/sql.go @@ -0,0 +1,109 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package uuid + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "fmt" +) + +// Value implements the driver.Valuer interface. +func (u UUID) Value() (driver.Value, error) { + return u.String(), nil +} + +// Scan implements the sql.Scanner interface. +// A 16-byte slice will be handled by UnmarshalBinary, while +// a longer byte slice or a string will be handled by UnmarshalText. +func (u *UUID) Scan(src interface{}) error { + switch src := src.(type) { + case UUID: // support gorm convert from UUID to NullUUID + *u = src + return nil + + case []byte: + if len(src) == Size { + return u.UnmarshalBinary(src) + } + return u.UnmarshalText(src) + + case string: + return u.UnmarshalText([]byte(src)) + } + + return fmt.Errorf("uuid: cannot convert %T to UUID", src) +} + +// NullUUID can be used with the standard sql package to represent a +// UUID value that can be NULL in the database. +type NullUUID struct { + UUID UUID + Valid bool +} + +// Value implements the driver.Valuer interface. +func (u NullUUID) Value() (driver.Value, error) { + if !u.Valid { + return nil, nil + } + // Delegate to UUID Value function + return u.UUID.Value() +} + +// Scan implements the sql.Scanner interface. +func (u *NullUUID) Scan(src interface{}) error { + if src == nil { + u.UUID, u.Valid = Nil, false + return nil + } + + // Delegate to UUID Scan function + u.Valid = true + return u.UUID.Scan(src) +} + +// MarshalJSON marshals the NullUUID as null or the nested UUID +func (u NullUUID) MarshalJSON() ([]byte, error) { + if !u.Valid { + return json.Marshal(nil) + } + + return json.Marshal(u.UUID) +} + +// UnmarshalJSON unmarshals a NullUUID +func (u *NullUUID) UnmarshalJSON(b []byte) error { + if bytes.Equal(b, []byte("null")) { + u.UUID, u.Valid = Nil, false + return nil + } + + if err := json.Unmarshal(b, &u.UUID); err != nil { + return err + } + + u.Valid = true + + return nil +} diff --git a/vendor/github.com/gofrs/uuid/uuid.go b/vendor/github.com/gofrs/uuid/uuid.go new file mode 100644 index 000000000..f314b8457 --- /dev/null +++ b/vendor/github.com/gofrs/uuid/uuid.go @@ -0,0 +1,292 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Package uuid provides implementations of the Universally Unique Identifier +// (UUID), as specified in RFC-4122 and the Peabody RFC Draft (revision 02). +// +// RFC-4122[1] provides the specification for versions 1, 3, 4, and 5. The +// Peabody UUID RFC Draft[2] provides the specification for the new k-sortable +// UUIDs, versions 6 and 7. +// +// DCE 1.1[3] provides the specification for version 2, but version 2 support +// was removed from this package in v4 due to some concerns with the +// specification itself. Reading the spec, it seems that it would result in +// generating UUIDs that aren't very unique. In having read the spec it seemed +// that our implementation did not meet the spec. It also seems to be at-odds +// with RFC 4122, meaning we would need quite a bit of special code to support +// it. Lastly, there were no Version 2 implementations that we could find to +// ensure we were understanding the specification correctly. +// +// [1] https://tools.ietf.org/html/rfc4122 +// [2] https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-02 +// [3] http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01 +package uuid + +import ( + "encoding/binary" + "encoding/hex" + "fmt" + "io" + "strings" + "time" +) + +// Size of a UUID in bytes. +const Size = 16 + +// UUID is an array type to represent the value of a UUID, as defined in RFC-4122. +type UUID [Size]byte + +// UUID versions. +const ( + _ byte = iota + V1 // Version 1 (date-time and MAC address) + _ // Version 2 (date-time and MAC address, DCE security version) [removed] + V3 // Version 3 (namespace name-based) + V4 // Version 4 (random) + V5 // Version 5 (namespace name-based) + V6 // Version 6 (k-sortable timestamp and random data) [peabody draft] + V7 // Version 7 (k-sortable timestamp, with configurable precision, and random data) [peabody draft] + _ // Version 8 (k-sortable timestamp, meant for custom implementations) [peabody draft] [not implemented] +) + +// UUID layout variants. +const ( + VariantNCS byte = iota + VariantRFC4122 + VariantMicrosoft + VariantFuture +) + +// UUID DCE domains. +const ( + DomainPerson = iota + DomainGroup + DomainOrg +) + +// Timestamp is the count of 100-nanosecond intervals since 00:00:00.00, +// 15 October 1582 within a V1 UUID. This type has no meaning for other +// UUID versions since they don't have an embedded timestamp. +type Timestamp uint64 + +const _100nsPerSecond = 10000000 + +// Time returns the UTC time.Time representation of a Timestamp +func (t Timestamp) Time() (time.Time, error) { + secs := uint64(t) / _100nsPerSecond + nsecs := 100 * (uint64(t) % _100nsPerSecond) + + return time.Unix(int64(secs)-(epochStart/_100nsPerSecond), int64(nsecs)), nil +} + +// TimestampFromV1 returns the Timestamp embedded within a V1 UUID. +// Returns an error if the UUID is any version other than 1. +func TimestampFromV1(u UUID) (Timestamp, error) { + if u.Version() != 1 { + err := fmt.Errorf("uuid: %s is version %d, not version 1", u, u.Version()) + return 0, err + } + + low := binary.BigEndian.Uint32(u[0:4]) + mid := binary.BigEndian.Uint16(u[4:6]) + hi := binary.BigEndian.Uint16(u[6:8]) & 0xfff + + return Timestamp(uint64(low) + (uint64(mid) << 32) + (uint64(hi) << 48)), nil +} + +// TimestampFromV6 returns the Timestamp embedded within a V6 UUID. This +// function returns an error if the UUID is any version other than 6. +// +// This is implemented based on revision 01 of the Peabody UUID draft, and may +// be subject to change pending further revisions. Until the final specification +// revision is finished, changes required to implement updates to the spec will +// not be considered a breaking change. They will happen as a minor version +// releases until the spec is final. +func TimestampFromV6(u UUID) (Timestamp, error) { + if u.Version() != 6 { + return 0, fmt.Errorf("uuid: %s is version %d, not version 6", u, u.Version()) + } + + hi := binary.BigEndian.Uint32(u[0:4]) + mid := binary.BigEndian.Uint16(u[4:6]) + low := binary.BigEndian.Uint16(u[6:8]) & 0xfff + + return Timestamp(uint64(low) + (uint64(mid) << 12) + (uint64(hi) << 28)), nil +} + +// String parse helpers. +var ( + urnPrefix = []byte("urn:uuid:") + byteGroups = []int{8, 4, 4, 4, 12} +) + +// Nil is the nil UUID, as specified in RFC-4122, that has all 128 bits set to +// zero. +var Nil = UUID{} + +// Predefined namespace UUIDs. +var ( + NamespaceDNS = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) + NamespaceURL = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) + NamespaceOID = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) + NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) +) + +// IsNil returns if the UUID is equal to the nil UUID +func (u UUID) IsNil() bool { + return u == Nil +} + +// Version returns the algorithm version used to generate the UUID. +func (u UUID) Version() byte { + return u[6] >> 4 +} + +// Variant returns the UUID layout variant. +func (u UUID) Variant() byte { + switch { + case (u[8] >> 7) == 0x00: + return VariantNCS + case (u[8] >> 6) == 0x02: + return VariantRFC4122 + case (u[8] >> 5) == 0x06: + return VariantMicrosoft + case (u[8] >> 5) == 0x07: + fallthrough + default: + return VariantFuture + } +} + +// Bytes returns a byte slice representation of the UUID. +func (u UUID) Bytes() []byte { + return u[:] +} + +// String returns a canonical RFC-4122 string representation of the UUID: +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. +func (u UUID) String() string { + buf := make([]byte, 36) + + hex.Encode(buf[0:8], u[0:4]) + buf[8] = '-' + hex.Encode(buf[9:13], u[4:6]) + buf[13] = '-' + hex.Encode(buf[14:18], u[6:8]) + buf[18] = '-' + hex.Encode(buf[19:23], u[8:10]) + buf[23] = '-' + hex.Encode(buf[24:], u[10:]) + + return string(buf) +} + +// Format implements fmt.Formatter for UUID values. +// +// The behavior is as follows: +// The 'x' and 'X' verbs output only the hex digits of the UUID, using a-f for 'x' and A-F for 'X'. +// The 'v', '+v', 's' and 'q' verbs return the canonical RFC-4122 string representation. +// The 'S' verb returns the RFC-4122 format, but with capital hex digits. +// The '#v' verb returns the "Go syntax" representation, which is a 16 byte array initializer. +// All other verbs not handled directly by the fmt package (like '%p') are unsupported and will return +// "%!verb(uuid.UUID=value)" as recommended by the fmt package. +func (u UUID) Format(f fmt.State, c rune) { + switch c { + case 'x', 'X': + s := hex.EncodeToString(u.Bytes()) + if c == 'X' { + s = strings.Map(toCapitalHexDigits, s) + } + _, _ = io.WriteString(f, s) + case 'v': + var s string + if f.Flag('#') { + s = fmt.Sprintf("%#v", [Size]byte(u)) + } else { + s = u.String() + } + _, _ = io.WriteString(f, s) + case 's', 'S': + s := u.String() + if c == 'S' { + s = strings.Map(toCapitalHexDigits, s) + } + _, _ = io.WriteString(f, s) + case 'q': + _, _ = io.WriteString(f, `"`+u.String()+`"`) + default: + // invalid/unsupported format verb + fmt.Fprintf(f, "%%!%c(uuid.UUID=%s)", c, u.String()) + } +} + +func toCapitalHexDigits(ch rune) rune { + // convert a-f hex digits to A-F + switch ch { + case 'a': + return 'A' + case 'b': + return 'B' + case 'c': + return 'C' + case 'd': + return 'D' + case 'e': + return 'E' + case 'f': + return 'F' + default: + return ch + } +} + +// SetVersion sets the version bits. +func (u *UUID) SetVersion(v byte) { + u[6] = (u[6] & 0x0f) | (v << 4) +} + +// SetVariant sets the variant bits. +func (u *UUID) SetVariant(v byte) { + switch v { + case VariantNCS: + u[8] = (u[8]&(0xff>>1) | (0x00 << 7)) + case VariantRFC4122: + u[8] = (u[8]&(0xff>>2) | (0x02 << 6)) + case VariantMicrosoft: + u[8] = (u[8]&(0xff>>3) | (0x06 << 5)) + case VariantFuture: + fallthrough + default: + u[8] = (u[8]&(0xff>>3) | (0x07 << 5)) + } +} + +// Must is a helper that wraps a call to a function returning (UUID, error) +// and panics if the error is non-nil. It is intended for use in variable +// initializations such as +// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000")) +func Must(u UUID, err error) UUID { + if err != nil { + panic(err) + } + return u +} diff --git a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/application.go b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/application.go index ae29be498..24258a611 100644 --- a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/application.go +++ b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/application.go @@ -6,6 +6,8 @@ import ( "fmt" "net/http" "time" + + "github.com/volatiletech/null/v8" ) type ApplicationState string @@ -29,8 +31,8 @@ type Application struct { } type ApplicationIdentifier struct { - UUID string `json:"uuid"` - Name string `json:"name"` + UUID null.String `json:"uuid,omitempty"` + Name null.String `json:"name,omitempty"` } // CreateApplicationInput represents the input for a Meroxa Application create operation in the API diff --git a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/function.go b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/function.go index 7f4dd6467..2bcb4dee8 100644 --- a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/function.go +++ b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/function.go @@ -5,9 +5,11 @@ import ( "encoding/json" "fmt" "net/http" + + "github.com/volatiletech/null/v8" ) -const functionsBasePath = "/v1/functions" +const functionsSubPath = "functions" type Function struct { UUID string `json:"uuid"` @@ -29,8 +31,8 @@ type FunctionStatus struct { } type FunctionIdentifier struct { - Name string `json:"name"` - UUID string `json:"uuid"` + Name null.String `json:"name,omitempty"` + UUID null.String `json:"uuid,omitempty"` } type CreateFunctionInput struct { @@ -38,7 +40,7 @@ type CreateFunctionInput struct { InputStream string `json:"input_stream"` OutputStream string `json:"output_stream"` Pipeline PipelineIdentifier `json:"pipeline"` - Application ApplicationIdentifier `json:"application,omitempty"` + Application ApplicationIdentifier `json:"application"` Image string `json:"image"` Command []string `json:"command"` Args []string `json:"args"` @@ -46,7 +48,14 @@ type CreateFunctionInput struct { } func (c *client) CreateFunction(ctx context.Context, input *CreateFunctionInput) (*Function, error) { - resp, err := c.MakeRequest(ctx, http.MethodPost, functionsBasePath, input, nil) + var appID string + if input.Application.Name.Valid && input.Application.Name.String != "" { + appID = input.Application.Name.String + } else { + appID = input.Application.UUID.String + } + path := fmt.Sprintf("%s/%s/%s", applicationsBasePath, appID, functionsSubPath) + resp, err := c.MakeRequest(ctx, http.MethodPost, path, input, nil) if err != nil { return nil, err } @@ -63,8 +72,8 @@ func (c *client) CreateFunction(ctx context.Context, input *CreateFunctionInput) return &fun, nil } -func (c *client) GetFunction(ctx context.Context, nameOrUUID string) (*Function, error) { - path := fmt.Sprintf("%s/%s", functionsBasePath, nameOrUUID) +func (c *client) GetFunction(ctx context.Context, appNameOrUUID, nameOrUUID string) (*Function, error) { + path := fmt.Sprintf("%s/%s/%s/%s", applicationsBasePath, appNameOrUUID, functionsSubPath, nameOrUUID) resp, err := c.MakeRequest(ctx, http.MethodGet, path, nil, nil) if err != nil { @@ -85,8 +94,9 @@ func (c *client) GetFunction(ctx context.Context, nameOrUUID string) (*Function, return &fun, nil } -func (c *client) ListFunctions(ctx context.Context) ([]*Function, error) { - resp, err := c.MakeRequest(ctx, http.MethodGet, functionsBasePath, nil, nil) +func (c *client) ListFunctions(ctx context.Context, appNameOrUUID string) ([]*Function, error) { + path := fmt.Sprintf("%s/%s/%s", applicationsBasePath, appNameOrUUID, functionsSubPath) + resp, err := c.MakeRequest(ctx, http.MethodGet, path, nil, nil) if err != nil { return nil, err } @@ -105,8 +115,8 @@ func (c *client) ListFunctions(ctx context.Context) ([]*Function, error) { return funs, nil } -func (c *client) DeleteFunction(ctx context.Context, nameOrUUID string) (*Function, error) { - path := fmt.Sprintf("%s/%s", functionsBasePath, nameOrUUID) +func (c *client) DeleteFunction(ctx context.Context, appNameOrUUID, nameOrUUID string) (*Function, error) { + path := fmt.Sprintf("%s/%s/%s/%s", applicationsBasePath, appNameOrUUID, functionsSubPath, nameOrUUID) resp, err := c.MakeRequest(ctx, http.MethodDelete, path, nil, nil) if err != nil { diff --git a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/log.go b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/log.go index d3db2673d..e0f2cd60c 100644 --- a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/log.go +++ b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/log.go @@ -8,7 +8,6 @@ import ( const ( connectorLogsBasePath = "/v1/connectors" - functionLogsBasePath = "/v1/functions" ) func (c *client) GetConnectorLogs(ctx context.Context, nameOrID string) (*http.Response, error) { @@ -26,8 +25,8 @@ func (c *client) GetConnectorLogs(ctx context.Context, nameOrID string) (*http.R return c.httpClient.Do(req) } -func (c *client) GetFunctionLogs(ctx context.Context, nameOrUUID string) (*http.Response, error) { - path := fmt.Sprintf("%s/%s/logs", functionLogsBasePath, nameOrUUID) +func (c *client) GetFunctionLogs(ctx context.Context, appNameOrUUID, nameOrUUID string) (*http.Response, error) { + path := fmt.Sprintf("%s/%s/functions/%s/logs", applicationsBasePath, appNameOrUUID, nameOrUUID) req, err := c.newRequest(ctx, http.MethodGet, path, nil, nil) if err != nil { diff --git a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/meroxa.go b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/meroxa.go index cc3d288a8..b2702d207 100644 --- a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/meroxa.go +++ b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/meroxa.go @@ -47,10 +47,10 @@ type Client interface { UpdateConnectorStatus(ctx context.Context, nameOrID string, state Action) (*Connector, error) CreateFunction(ctx context.Context, input *CreateFunctionInput) (*Function, error) - GetFunction(ctx context.Context, nameOrUUID string) (*Function, error) - GetFunctionLogs(ctx context.Context, nameOrUUID string) (*http.Response, error) - ListFunctions(ctx context.Context) ([]*Function, error) - DeleteFunction(ctx context.Context, nameOrUUID string) (*Function, error) + GetFunction(ctx context.Context, appNameOrUUID, nameOrUUID string) (*Function, error) + GetFunctionLogs(ctx context.Context, appNameOrUUID, nameOrUUID string) (*http.Response, error) + ListFunctions(ctx context.Context, appNameOrUUID string) ([]*Function, error) + DeleteFunction(ctx context.Context, appNameOrUUID, nameOrUUID string) (*Function, error) CreateEndpoint(ctx context.Context, input *CreateEndpointInput) error DeleteEndpoint(ctx context.Context, name string) error diff --git a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/pipeline.go b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/pipeline.go index 9f037779d..92e6ee01d 100644 --- a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/pipeline.go +++ b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/pipeline.go @@ -6,6 +6,8 @@ import ( "fmt" "net/http" "time" + + "github.com/volatiletech/null/v8" ) const pipelinesBasePath = "/v1/pipelines" @@ -18,8 +20,8 @@ const ( ) type PipelineIdentifier struct { - UUID string `json:"uuid"` - Name string `json:"name"` + UUID null.String `json:"uuid"` + Name null.String `json:"name"` } // Pipeline represents the Meroxa Pipeline type within the Meroxa API diff --git a/vendor/github.com/meroxa/meroxa-go/pkg/mock/mock_client.go b/vendor/github.com/meroxa/meroxa-go/pkg/mock/mock_client.go index d4c963af3..568e5efa9 100644 --- a/vendor/github.com/meroxa/meroxa-go/pkg/mock/mock_client.go +++ b/vendor/github.com/meroxa/meroxa-go/pkg/mock/mock_client.go @@ -199,18 +199,18 @@ func (mr *MockClientMockRecorder) DeleteEnvironment(ctx, nameOrUUID interface{}) } // DeleteFunction mocks base method. -func (m *MockClient) DeleteFunction(ctx context.Context, nameOrUUID string) (*meroxa.Function, error) { +func (m *MockClient) DeleteFunction(ctx context.Context, appNameOrUUID, nameOrUUID string) (*meroxa.Function, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteFunction", ctx, nameOrUUID) + ret := m.ctrl.Call(m, "DeleteFunction", ctx, appNameOrUUID, nameOrUUID) ret0, _ := ret[0].(*meroxa.Function) ret1, _ := ret[1].(error) return ret0, ret1 } // DeleteFunction indicates an expected call of DeleteFunction. -func (mr *MockClientMockRecorder) DeleteFunction(ctx, nameOrUUID interface{}) *gomock.Call { +func (mr *MockClientMockRecorder) DeleteFunction(ctx, appNameOrUUID, nameOrUUID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFunction", reflect.TypeOf((*MockClient)(nil).DeleteFunction), ctx, nameOrUUID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFunction", reflect.TypeOf((*MockClient)(nil).DeleteFunction), ctx, appNameOrUUID, nameOrUUID) } // DeletePipeline mocks base method. @@ -317,33 +317,33 @@ func (mr *MockClientMockRecorder) GetEnvironment(ctx, nameOrUUID interface{}) *g } // GetFunction mocks base method. -func (m *MockClient) GetFunction(ctx context.Context, nameOrUUID string) (*meroxa.Function, error) { +func (m *MockClient) GetFunction(ctx context.Context, appNameOrUUID, nameOrUUID string) (*meroxa.Function, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFunction", ctx, nameOrUUID) + ret := m.ctrl.Call(m, "GetFunction", ctx, appNameOrUUID, nameOrUUID) ret0, _ := ret[0].(*meroxa.Function) ret1, _ := ret[1].(error) return ret0, ret1 } // GetFunction indicates an expected call of GetFunction. -func (mr *MockClientMockRecorder) GetFunction(ctx, nameOrUUID interface{}) *gomock.Call { +func (mr *MockClientMockRecorder) GetFunction(ctx, appNameOrUUID, nameOrUUID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFunction", reflect.TypeOf((*MockClient)(nil).GetFunction), ctx, nameOrUUID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFunction", reflect.TypeOf((*MockClient)(nil).GetFunction), ctx, appNameOrUUID, nameOrUUID) } // GetFunctionLogs mocks base method. -func (m *MockClient) GetFunctionLogs(ctx context.Context, nameOrUUID string) (*http.Response, error) { +func (m *MockClient) GetFunctionLogs(ctx context.Context, appNameOrUUID, nameOrUUID string) (*http.Response, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFunctionLogs", ctx, nameOrUUID) + ret := m.ctrl.Call(m, "GetFunctionLogs", ctx, appNameOrUUID, nameOrUUID) ret0, _ := ret[0].(*http.Response) ret1, _ := ret[1].(error) return ret0, ret1 } // GetFunctionLogs indicates an expected call of GetFunctionLogs. -func (mr *MockClientMockRecorder) GetFunctionLogs(ctx, nameOrUUID interface{}) *gomock.Call { +func (mr *MockClientMockRecorder) GetFunctionLogs(ctx, appNameOrUUID, nameOrUUID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFunctionLogs", reflect.TypeOf((*MockClient)(nil).GetFunctionLogs), ctx, nameOrUUID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFunctionLogs", reflect.TypeOf((*MockClient)(nil).GetFunctionLogs), ctx, appNameOrUUID, nameOrUUID) } // GetPipeline mocks base method. @@ -467,18 +467,18 @@ func (mr *MockClientMockRecorder) ListEnvironments(ctx interface{}) *gomock.Call } // ListFunctions mocks base method. -func (m *MockClient) ListFunctions(ctx context.Context) ([]*meroxa.Function, error) { +func (m *MockClient) ListFunctions(ctx context.Context, appNameOrUUID string) ([]*meroxa.Function, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListFunctions", ctx) + ret := m.ctrl.Call(m, "ListFunctions", ctx, appNameOrUUID) ret0, _ := ret[0].([]*meroxa.Function) ret1, _ := ret[1].(error) return ret0, ret1 } // ListFunctions indicates an expected call of ListFunctions. -func (mr *MockClientMockRecorder) ListFunctions(ctx interface{}) *gomock.Call { +func (mr *MockClientMockRecorder) ListFunctions(ctx, appNameOrUUID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListFunctions", reflect.TypeOf((*MockClient)(nil).ListFunctions), ctx) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListFunctions", reflect.TypeOf((*MockClient)(nil).ListFunctions), ctx, appNameOrUUID) } // ListPipelineConnectors mocks base method. diff --git a/vendor/github.com/volatiletech/inflect/LICENCE b/vendor/github.com/volatiletech/inflect/LICENCE new file mode 100644 index 000000000..8a36b944a --- /dev/null +++ b/vendor/github.com/volatiletech/inflect/LICENCE @@ -0,0 +1,7 @@ +Copyright (c) 2011 Chris Farmiloe + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/volatiletech/inflect/README.md b/vendor/github.com/volatiletech/inflect/README.md new file mode 100644 index 000000000..f1a043d7d --- /dev/null +++ b/vendor/github.com/volatiletech/inflect/README.md @@ -0,0 +1,170 @@ +Fork of bitbucket.org/pkg/inflect + +INSTALLATION + +`go get -u github.com/volatiletech/inflect` + +PACKAGE + +package inflect + + +FUNCTIONS + +func AddAcronym(word string) + +func AddHuman(suffix, replacement string) + +func AddIrregular(singular, plural string) + +func AddPlural(suffix, replacement string) + +func AddSingular(suffix, replacement string) + +func AddUncountable(word string) + +func Asciify(word string) string + +func Camelize(word string) string + +func CamelizeDownFirst(word string) string + +func Capitalize(word string) string + +func Dasherize(word string) string + +func ForeignKey(word string) string + +func ForeignKeyCondensed(word string) string + +func Humanize(word string) string + +func Ordinalize(word string) string + +func Parameterize(word string) string + +func ParameterizeJoin(word, sep string) string + +func Pluralize(word string) string + +func Singularize(word string) string + +func Tableize(word string) string + +func Titleize(word string) string + +func Typeify(word string) string + +func Uncountables() map[string]bool + +func Underscore(word string) string + + +TYPES + +type Rule struct { + // contains filtered or unexported fields +} +used by rulesets + +type Ruleset struct { + // contains filtered or unexported fields +} +a Ruleset is the config of pluralization rules +you can extend the rules with the Add* methods + +func NewDefaultRuleset() *Ruleset +create a new ruleset and load it with the default +set of common English pluralization rules + +func NewRuleset() *Ruleset +create a blank ruleset. Unless you are going to +build your own rules from scratch you probably +won't need this and can just use the defaultRuleset +via the global inflect.* methods + +func (rs *Ruleset) AddAcronym(word string) +if you use acronym you may need to add them to the ruleset +to prevent Underscored words of things like "HTML" coming out +as "h_t_m_l" + +func (rs *Ruleset) AddHuman(suffix, replacement string) +Human rules are applied by humanize to show more friendly +versions of words + +func (rs *Ruleset) AddIrregular(singular, plural string) +Add any inconsistant pluralizing/sinularizing rules +to the set here. + +func (rs *Ruleset) AddPlural(suffix, replacement string) +add a pluralization rule + +func (rs *Ruleset) AddPluralExact(suffix, replacement string, exact bool) +add a pluralization rule with full string match + +func (rs *Ruleset) AddSingular(suffix, replacement string) +add a singular rule + +func (rs *Ruleset) AddSingularExact(suffix, replacement string, exact bool) +same as AddSingular but you can set `exact` to force +a full string match + +func (rs *Ruleset) AddUncountable(word string) +add a word to this ruleset that has the same singular and plural form +for example: "rice" + +func (rs *Ruleset) Asciify(word string) string +transforms latin characters like é -> e + +func (rs *Ruleset) Camelize(word string) string +"dino_party" -> "DinoParty" + +func (rs *Ruleset) CamelizeDownFirst(word string) string +same as Camelcase but with first letter downcased + +func (rs *Ruleset) Capitalize(word string) string +uppercase first character + +func (rs *Ruleset) Dasherize(word string) string +"SomeText" -> "some-text" + +func (rs *Ruleset) ForeignKey(word string) string +an underscored foreign key name "Person" -> "person_id" + +func (rs *Ruleset) ForeignKeyCondensed(word string) string +a foreign key (with an underscore) "Person" -> "personid" + +func (rs *Ruleset) Humanize(word string) string +First letter of sentance captitilized +Uses custom friendly replacements via AddHuman() + +func (rs *Ruleset) Ordinalize(str string) string +"1031" -> "1031st" + +func (rs *Ruleset) Parameterize(word string) string +param safe dasherized names like "my-param" + +func (rs *Ruleset) ParameterizeJoin(word, sep string) string +param safe dasherized names with custom seperator + +func (rs *Ruleset) Pluralize(word string) string +returns the plural form of a singular word + +func (rs *Ruleset) Singularize(word string) string +returns the singular form of a plural word + +func (rs *Ruleset) Tableize(word string) string +Rails style pluralized table names: "SuperPerson" -> "super_people" + +func (rs *Ruleset) Titleize(word string) string +Captitilize every word in sentance "hello there" -> "Hello There" + +func (rs *Ruleset) Typeify(word string) string +"something_like_this" -> "SomethingLikeThis" + +func (rs *Ruleset) Uncountables() map[string]bool + +func (rs *Ruleset) Underscore(word string) string +lowercase underscore version "BigBen" -> "big_ben" + + diff --git a/vendor/github.com/volatiletech/inflect/inflect.go b/vendor/github.com/volatiletech/inflect/inflect.go new file mode 100644 index 000000000..18ff411e3 --- /dev/null +++ b/vendor/github.com/volatiletech/inflect/inflect.go @@ -0,0 +1,753 @@ +package inflect + +import ( + "fmt" + "regexp" + "strconv" + "strings" + "unicode" + "unicode/utf8" +) + +// Rule is used by rulesets +type Rule struct { + suffix string + replacement string + exact bool +} + +// Ruleset is the config of pluralization rules +// you can extend the rules with the Add* methods +type Ruleset struct { + uncountables map[string]bool + plurals []*Rule + singulars []*Rule + humans []*Rule + acronyms []*Rule + acronymMatcher *regexp.Regexp +} + +// NewRuleset creates a blank ruleset. Unless you are going to +// build your own rules from scratch you probably +// won't need this and can just use the defaultRuleset +// via the global inflect.* methods +func NewRuleset() *Ruleset { + rs := new(Ruleset) + rs.uncountables = make(map[string]bool) + rs.plurals = make([]*Rule, 0) + rs.singulars = make([]*Rule, 0) + rs.humans = make([]*Rule, 0) + rs.acronyms = make([]*Rule, 0) + return rs +} + +// NewDefaultRuleset creates a new ruleset and load it with the default +// set of common English pluralization rules +func NewDefaultRuleset() *Ruleset { + rs := NewRuleset() + rs.AddPlural("s", "s") + rs.AddPlural("testis", "testes") + rs.AddPlural("axis", "axes") + rs.AddPlural("octopus", "octopi") + rs.AddPlural("virus", "viri") + rs.AddPlural("octopi", "octopi") + rs.AddPlural("viri", "viri") + rs.AddPlural("alias", "aliases") + rs.AddPlural("status", "statuses") + rs.AddPlural("bus", "buses") + rs.AddPlural("buffalo", "buffaloes") + rs.AddPlural("tomato", "tomatoes") + rs.AddPlural("tum", "ta") + rs.AddPlural("ium", "ia") + rs.AddPlural("ta", "ta") + rs.AddPlural("ia", "ia") + rs.AddPlural("sis", "ses") + rs.AddPlural("lf", "lves") + rs.AddPlural("rf", "rves") + rs.AddPlural("afe", "aves") + rs.AddPlural("bfe", "bves") + rs.AddPlural("cfe", "cves") + rs.AddPlural("dfe", "dves") + rs.AddPlural("efe", "eves") + rs.AddPlural("gfe", "gves") + rs.AddPlural("hfe", "hves") + rs.AddPlural("ife", "ives") + rs.AddPlural("jfe", "jves") + rs.AddPlural("kfe", "kves") + rs.AddPlural("lfe", "lves") + rs.AddPlural("mfe", "mves") + rs.AddPlural("nfe", "nves") + rs.AddPlural("ofe", "oves") + rs.AddPlural("pfe", "pves") + rs.AddPlural("qfe", "qves") + rs.AddPlural("rfe", "rves") + rs.AddPlural("sfe", "sves") + rs.AddPlural("tfe", "tves") + rs.AddPlural("ufe", "uves") + rs.AddPlural("vfe", "vves") + rs.AddPlural("wfe", "wves") + rs.AddPlural("xfe", "xves") + rs.AddPlural("yfe", "yves") + rs.AddPlural("zfe", "zves") + rs.AddPlural("hive", "hives") + rs.AddPlural("quy", "quies") + rs.AddPlural("by", "bies") + rs.AddPlural("cy", "cies") + rs.AddPlural("dy", "dies") + rs.AddPlural("fy", "fies") + rs.AddPlural("gy", "gies") + rs.AddPlural("hy", "hies") + rs.AddPlural("jy", "jies") + rs.AddPlural("ky", "kies") + rs.AddPlural("ly", "lies") + rs.AddPlural("my", "mies") + rs.AddPlural("ny", "nies") + rs.AddPlural("py", "pies") + rs.AddPlural("qy", "qies") + rs.AddPlural("ry", "ries") + rs.AddPlural("sy", "sies") + rs.AddPlural("ty", "ties") + rs.AddPlural("vy", "vies") + rs.AddPlural("wy", "wies") + rs.AddPlural("xy", "xies") + rs.AddPlural("zy", "zies") + rs.AddPlural("x", "xes") + rs.AddPlural("ch", "ches") + rs.AddPlural("ss", "sses") + rs.AddPlural("sh", "shes") + rs.AddPlural("matrix", "matrices") + rs.AddPlural("vertix", "vertices") + rs.AddPlural("indix", "indices") + rs.AddPlural("matrex", "matrices") + rs.AddPlural("vertex", "vertices") + rs.AddPlural("index", "indices") + rs.AddPlural("mouse", "mice") + rs.AddPlural("louse", "lice") + rs.AddPlural("mice", "mice") + rs.AddPlural("lice", "lice") + rs.AddPluralExact("ox", "oxen", true) + rs.AddPluralExact("oxen", "oxen", true) + rs.AddPluralExact("quiz", "quizzes", true) + rs.AddSingular("s", "") + rs.AddSingular("ss", "ss") + rs.AddSingular("as", "as") + rs.AddSingular("us", "us") + rs.AddSingular("is", "is") + rs.AddSingular("news", "news") + rs.AddSingular("ta", "tum") + rs.AddSingular("ia", "ium") + rs.AddSingular("analyses", "analysis") + rs.AddSingular("bases", "basis") + rs.AddSingular("diagnoses", "diagnosis") + rs.AddSingular("parentheses", "parenthesis") + rs.AddSingular("prognoses", "prognosis") + rs.AddSingular("synopses", "synopsis") + rs.AddSingular("theses", "thesis") + rs.AddSingular("analyses", "analysis") + rs.AddSingular("aves", "afe") + rs.AddSingular("bves", "bfe") + rs.AddSingular("cves", "cfe") + rs.AddSingular("dves", "dfe") + rs.AddSingular("eves", "efe") + rs.AddSingular("gves", "gfe") + rs.AddSingular("hves", "hfe") + rs.AddSingular("ives", "ife") + rs.AddSingular("jves", "jfe") + rs.AddSingular("kves", "kfe") + rs.AddSingular("lves", "lfe") + rs.AddSingular("mves", "mfe") + rs.AddSingular("nves", "nfe") + rs.AddSingular("oves", "ofe") + rs.AddSingular("pves", "pfe") + rs.AddSingular("qves", "qfe") + rs.AddSingular("rves", "rfe") + rs.AddSingular("sves", "sfe") + rs.AddSingular("tves", "tfe") + rs.AddSingular("uves", "ufe") + rs.AddSingular("vves", "vfe") + rs.AddSingular("wves", "wfe") + rs.AddSingular("xves", "xfe") + rs.AddSingular("yves", "yfe") + rs.AddSingular("zves", "zfe") + rs.AddSingular("hives", "hive") + rs.AddSingular("tives", "tive") + rs.AddSingular("lves", "lf") + rs.AddSingular("rves", "rf") + rs.AddSingular("quies", "quy") + rs.AddSingular("bies", "by") + rs.AddSingular("cies", "cy") + rs.AddSingular("dies", "dy") + rs.AddSingular("fies", "fy") + rs.AddSingular("gies", "gy") + rs.AddSingular("hies", "hy") + rs.AddSingular("jies", "jy") + rs.AddSingular("kies", "ky") + rs.AddSingular("lies", "ly") + rs.AddSingular("mies", "my") + rs.AddSingular("nies", "ny") + rs.AddSingular("pies", "py") + rs.AddSingular("qies", "qy") + rs.AddSingular("ries", "ry") + rs.AddSingular("sies", "sy") + rs.AddSingular("ties", "ty") + rs.AddSingular("vies", "vy") + rs.AddSingular("wies", "wy") + rs.AddSingular("xies", "xy") + rs.AddSingular("zies", "zy") + rs.AddSingular("series", "series") + rs.AddSingular("movies", "movie") + rs.AddSingular("xes", "x") + rs.AddSingular("ches", "ch") + rs.AddSingular("sses", "ss") + rs.AddSingular("shes", "sh") + rs.AddSingular("mice", "mouse") + rs.AddSingular("lice", "louse") + rs.AddSingular("buses", "bus") + rs.AddSingular("oes", "o") + rs.AddSingular("shoes", "shoe") + rs.AddSingular("crises", "crisis") + rs.AddSingular("axes", "axis") + rs.AddSingular("testes", "testis") + rs.AddSingular("octopi", "octopus") + rs.AddSingular("viri", "virus") + rs.AddSingular("statuses", "status") + rs.AddSingular("aliases", "alias") + rs.AddSingularExact("oxen", "ox", true) + rs.AddSingular("vertices", "vertex") + rs.AddSingular("indices", "index") + rs.AddSingular("matrices", "matrix") + rs.AddSingularExact("quizzes", "quiz", true) + rs.AddSingular("databases", "database") + rs.AddIrregular("person", "people") + rs.AddIrregular("man", "men") + rs.AddIrregular("child", "children") + rs.AddIrregular("sex", "sexes") + rs.AddIrregular("move", "moves") + rs.AddIrregular("zombie", "zombies") + rs.AddSingularExact("a", "a", true) + rs.AddSingularExact("i", "i", true) + rs.AddSingularExact("is", "is", true) + rs.AddSingularExact("us", "us", true) + rs.AddSingularExact("as", "as", true) + rs.AddPluralExact("a", "a", true) + rs.AddPluralExact("i", "i", true) + rs.AddPluralExact("is", "is", true) + rs.AddPluralExact("us", "us", true) + rs.AddPluralExact("as", "as", true) + rs.AddUncountable("fu") + rs.AddUncountable("equipment") + rs.AddUncountable("information") + rs.AddUncountable("rice") + rs.AddUncountable("money") + rs.AddUncountable("species") + rs.AddUncountable("series") + rs.AddUncountable("fish") + rs.AddUncountable("sheep") + rs.AddUncountable("jeans") + rs.AddUncountable("police") + return rs +} + +// Uncountables returns the uncountables ruleset +func (rs *Ruleset) Uncountables() map[string]bool { + return rs.uncountables +} + +// AddPlural adds a pluralization rule +func (rs *Ruleset) AddPlural(suffix, replacement string) { + rs.AddPluralExact(suffix, replacement, false) +} + +// AddPluralExact adds a pluralization rule with full string match +func (rs *Ruleset) AddPluralExact(suffix, replacement string, exact bool) { + // remove uncountable + delete(rs.uncountables, suffix) + // create rule + r := new(Rule) + r.suffix = suffix + r.replacement = replacement + r.exact = exact + // prepend + rs.plurals = append([]*Rule{r}, rs.plurals...) +} + +// AddSingular adds a singular rule +func (rs *Ruleset) AddSingular(suffix, replacement string) { + rs.AddSingularExact(suffix, replacement, false) +} + +// AddSingularExact is the same as AddSingular but you can set `exact` to force +// a full string match +func (rs *Ruleset) AddSingularExact(suffix, replacement string, exact bool) { + // remove from uncountable + delete(rs.uncountables, suffix) + // create rule + r := new(Rule) + r.suffix = suffix + r.replacement = replacement + r.exact = exact + rs.singulars = append([]*Rule{r}, rs.singulars...) +} + +// AddHuman added rules are applied by humanize to show more friendly +// versions of words +func (rs *Ruleset) AddHuman(suffix, replacement string) { + r := new(Rule) + r.suffix = suffix + r.replacement = replacement + rs.humans = append([]*Rule{r}, rs.humans...) +} + +// AddIrregular adds any inconsistant pluralizing/sinularizing rules +// to the set here. +func (rs *Ruleset) AddIrregular(singular, plural string) { + delete(rs.uncountables, singular) + delete(rs.uncountables, plural) + rs.AddPlural(singular, plural) + rs.AddPlural(plural, plural) + rs.AddSingular(plural, singular) +} + +// AddAcronym - if you use acronym you may need to add them to the ruleset +// to prevent Underscored words of things like "HTML" coming out +// as "h_t_m_l" +func (rs *Ruleset) AddAcronym(word string) { + r := new(Rule) + r.suffix = word + r.replacement = rs.Titleize(strings.ToLower(word)) + rs.acronyms = append(rs.acronyms, r) +} + +// AddUncountable adds a word to this ruleset that has the same singular and plural form +// for example: "rice" +func (rs *Ruleset) AddUncountable(word string) { + rs.uncountables[strings.ToLower(word)] = true +} + +func (rs *Ruleset) isUncountable(word string) bool { + // handle multiple words by using the last one + words := strings.Split(word, " ") + if _, exists := rs.uncountables[strings.ToLower(words[len(words)-1])]; exists { + return true + } + return false +} + +// Pluralize returns the plural form of a singular word +func (rs *Ruleset) Pluralize(word string) string { + if len(word) == 0 { + return word + } + if rs.isUncountable(word) { + return word + } + for _, rule := range rs.plurals { + if rule.exact { + if word == rule.suffix { + return rule.replacement + } + } else { + if strings.HasSuffix(word, rule.suffix) { + return replaceLast(word, rule.suffix, rule.replacement) + } + } + } + return word + "s" +} + +// Singularize returns the singular form of a plural word +func (rs *Ruleset) Singularize(word string) string { + if len(word) == 0 { + return word + } + if rs.isUncountable(word) { + return word + } + for _, rule := range rs.singulars { + if rule.exact { + if word == rule.suffix { + return rule.replacement + } + } else { + if strings.HasSuffix(word, rule.suffix) { + return replaceLast(word, rule.suffix, rule.replacement) + } + } + } + return word +} + +// Capitalize will uppercase first character +func (rs *Ruleset) Capitalize(word string) string { + return strings.ToUpper(word[:1]) + word[1:] +} + +// Camelize "dino_party" -> "DinoParty" +func (rs *Ruleset) Camelize(word string) string { + words := splitAtCaseChangeWithTitlecase(word) + return strings.Join(words, "") +} + +// CamelizeDownFirst is the same as Camelcase but with first letter downcased +func (rs *Ruleset) CamelizeDownFirst(word string) string { + word = Camelize(word) + return strings.ToLower(word[:1]) + word[1:] +} + +// Titleize captitilizes every word in sentance "hello there" -> "Hello There" +func (rs *Ruleset) Titleize(word string) string { + words := splitAtCaseChangeWithTitlecase(word) + return strings.Join(words, " ") +} + +func (rs *Ruleset) safeCaseAcronyms(word string) string { + // convert an acroymn like HTML into Html + for _, rule := range rs.acronyms { + word = strings.Replace(word, rule.suffix, rule.replacement, -1) + } + return word +} + +func (rs *Ruleset) seperatedWords(word, sep string) string { + word = rs.safeCaseAcronyms(word) + words := splitAtCaseChange(word) + return strings.Join(words, sep) +} + +// Underscore returns the lowercase underscore version "BigBen" -> "big_ben" +func (rs *Ruleset) Underscore(word string) string { + return rs.seperatedWords(word, "_") +} + +// Humanize converts the first letter of sentence captitilized +// Uses custom friendly replacements via AddHuman() +func (rs *Ruleset) Humanize(word string) string { + word = replaceLast(word, "_id", "") // strip foreign key kinds + // replace and strings in humans list + for _, rule := range rs.humans { + word = strings.Replace(word, rule.suffix, rule.replacement, -1) + } + sentance := rs.seperatedWords(word, " ") + return strings.ToUpper(sentance[:1]) + sentance[1:] +} + +// ForeignKey returns an underscored foreign key name "Person" -> "person_id" +func (rs *Ruleset) ForeignKey(word string) string { + return rs.Underscore(rs.Singularize(word)) + "_id" +} + +// ForeignKeyCondensed returns a foreign key (with an underscore) "Person" -> "personid" +func (rs *Ruleset) ForeignKeyCondensed(word string) string { + return rs.Underscore(word) + "id" +} + +// Tableize returns a rails style pluralized table names: "SuperPerson" -> "super_people" +func (rs *Ruleset) Tableize(word string) string { + return rs.Pluralize(rs.Underscore(rs.Typeify(word))) +} + +var notURLSafe = regexp.MustCompile(`[^\w\d\-_ ]`) + +// Parameterize returns a param safe dasherized names like "my-param" +func (rs *Ruleset) Parameterize(word string) string { + return ParameterizeJoin(word, "-") +} + +// ParameterizeJoin returns a param safe dasherized names with custom seperator +func (rs *Ruleset) ParameterizeJoin(word, sep string) string { + word = strings.ToLower(word) + word = rs.Asciify(word) + word = notURLSafe.ReplaceAllString(word, "") + word = strings.Replace(word, " ", sep, -1) + if len(sep) > 0 { + squash, err := regexp.Compile(sep + "+") + if err == nil { + word = squash.ReplaceAllString(word, sep) + } + } + word = strings.Trim(word, sep+" ") + return word +} + +var lookalikes = map[string]*regexp.Regexp{ + "A": regexp.MustCompile(`À|Á|Â|Ã|Ä|Å`), + "AE": regexp.MustCompile(`Æ`), + "C": regexp.MustCompile(`Ç`), + "E": regexp.MustCompile(`È|É|Ê|Ë`), + "G": regexp.MustCompile(`Ğ`), + "I": regexp.MustCompile(`Ì|Í|Î|Ï|İ`), + "N": regexp.MustCompile(`Ñ`), + "O": regexp.MustCompile(`Ò|Ó|Ô|Õ|Ö|Ø`), + "S": regexp.MustCompile(`Ş`), + "U": regexp.MustCompile(`Ù|Ú|Û|Ü`), + "Y": regexp.MustCompile(`Ý`), + "ss": regexp.MustCompile(`ß`), + "a": regexp.MustCompile(`à|á|â|ã|ä|å`), + "ae": regexp.MustCompile(`æ`), + "c": regexp.MustCompile(`ç`), + "e": regexp.MustCompile(`è|é|ê|ë`), + "g": regexp.MustCompile(`ğ`), + "i": regexp.MustCompile(`ì|í|î|ï|ı`), + "n": regexp.MustCompile(`ñ`), + "o": regexp.MustCompile(`ò|ó|ô|õ|ö|ø`), + "s": regexp.MustCompile(`ş`), + "u": regexp.MustCompile(`ù|ú|û|ü|ũ|ū|ŭ|ů|ű|ų`), + "y": regexp.MustCompile(`ý|ÿ`), +} + +// Asciify transforms latin characters like é -> e +func (rs *Ruleset) Asciify(word string) string { + for repl, regex := range lookalikes { + word = regex.ReplaceAllString(word, repl) + } + return word +} + +var tablePrefix = regexp.MustCompile(`^[^.]*\.`) + +// Typeify converts "something_like_this" -> "SomethingLikeThis" +func (rs *Ruleset) Typeify(word string) string { + word = tablePrefix.ReplaceAllString(word, "") + return rs.Camelize(rs.Singularize(word)) +} + +// Dasherize converts "SomeText" -> "some-text" +func (rs *Ruleset) Dasherize(word string) string { + return rs.seperatedWords(word, "-") +} + +// Ordinalize converts "1031" -> "1031st" +func (rs *Ruleset) Ordinalize(str string) string { + number, err := strconv.Atoi(str) + if err != nil { + return str + } + switch abs(number) % 100 { + case 11, 12, 13: + return fmt.Sprintf("%dth", number) + default: + switch abs(number) % 10 { + case 1: + return fmt.Sprintf("%dst", number) + case 2: + return fmt.Sprintf("%dnd", number) + case 3: + return fmt.Sprintf("%drd", number) + } + } + return fmt.Sprintf("%dth", number) +} + +///////////////////////////////////////// +// the default global ruleset +////////////////////////////////////////// + +var defaultRuleset *Ruleset + +func init() { + defaultRuleset = NewDefaultRuleset() +} + +// Uncountables returns the uncountable ruleset +func Uncountables() map[string]bool { + return defaultRuleset.Uncountables() +} + +// AddPlural to the default ruleset +func AddPlural(suffix, replacement string) { + defaultRuleset.AddPlural(suffix, replacement) +} + +// AddSingular to the default ruleset +func AddSingular(suffix, replacement string) { + defaultRuleset.AddSingular(suffix, replacement) +} + +// AddHuman to the default ruleset +func AddHuman(suffix, replacement string) { + defaultRuleset.AddHuman(suffix, replacement) +} + +// AddIrregular to the default ruleset +func AddIrregular(singular, plural string) { + defaultRuleset.AddIrregular(singular, plural) +} + +// AddAcronym to the default ruleset +func AddAcronym(word string) { + defaultRuleset.AddAcronym(word) +} + +// AddUncountable to the default ruleset +func AddUncountable(word string) { + defaultRuleset.AddUncountable(word) +} + +// Pluralize word +func Pluralize(word string) string { + return defaultRuleset.Pluralize(word) +} + +// Singularize word +func Singularize(word string) string { + return defaultRuleset.Singularize(word) +} + +// Capitalize word +func Capitalize(word string) string { + return defaultRuleset.Capitalize(word) +} + +// Camelize word +func Camelize(word string) string { + return defaultRuleset.Camelize(word) +} + +// CamelizeDownFirst word +func CamelizeDownFirst(word string) string { + return defaultRuleset.CamelizeDownFirst(word) +} + +// Titleize word +func Titleize(word string) string { + return defaultRuleset.Titleize(word) +} + +// Underscore word +func Underscore(word string) string { + return defaultRuleset.Underscore(word) +} + +// Humanize word +func Humanize(word string) string { + return defaultRuleset.Humanize(word) +} + +// ForeignKey word +func ForeignKey(word string) string { + return defaultRuleset.ForeignKey(word) +} + +// ForeignKeyCondensed word +func ForeignKeyCondensed(word string) string { + return defaultRuleset.ForeignKeyCondensed(word) +} + +// Tableize word +func Tableize(word string) string { + return defaultRuleset.Tableize(word) +} + +// Parameterize word +func Parameterize(word string) string { + return defaultRuleset.Parameterize(word) +} + +// ParameterizeJoin word using sep +func ParameterizeJoin(word, sep string) string { + return defaultRuleset.ParameterizeJoin(word, sep) +} + +// Typeify word +func Typeify(word string) string { + return defaultRuleset.Typeify(word) +} + +// Dasherize word +func Dasherize(word string) string { + return defaultRuleset.Dasherize(word) +} + +// Ordinalize word +func Ordinalize(word string) string { + return defaultRuleset.Ordinalize(word) +} + +// Asciify word +func Asciify(word string) string { + return defaultRuleset.Asciify(word) +} + +// helper funcs + +func reverse(s string) string { + o := make([]rune, utf8.RuneCountInString(s)) + i := len(o) + for _, c := range s { + i-- + o[i] = c + } + return string(o) +} + +func isSpacerChar(c rune) bool { + switch { + case c == rune("_"[0]): + return true + case c == rune(" "[0]): + return true + case c == rune(":"[0]): + return true + case c == rune("-"[0]): + return true + } + return false +} + +func splitAtCaseChange(s string) []string { + words := make([]string, 0) + word := make([]rune, 0) + for _, c := range s { + spacer := isSpacerChar(c) + if len(word) > 0 { + if unicode.IsUpper(c) || spacer { + words = append(words, string(word)) + word = make([]rune, 0) + } + } + if !spacer { + word = append(word, unicode.ToLower(c)) + } + } + words = append(words, string(word)) + return words +} + +func splitAtCaseChangeWithTitlecase(s string) []string { + words := make([]string, 0) + word := make([]rune, 0) + for _, c := range s { + spacer := isSpacerChar(c) + if len(word) > 0 { + if unicode.IsUpper(c) || spacer { + words = append(words, string(word)) + word = make([]rune, 0) + } + } + if !spacer { + if len(word) > 0 { + word = append(word, unicode.ToLower(c)) + } else { + word = append(word, unicode.ToUpper(c)) + } + } + } + words = append(words, string(word)) + return words +} + +func replaceLast(s, match, repl string) string { + // reverse strings + srev := reverse(s) + mrev := reverse(match) + rrev := reverse(repl) + // match first and reverse back + return reverse(strings.Replace(srev, mrev, rrev, 1)) +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x +} diff --git a/vendor/github.com/volatiletech/null/v8/.gitignore b/vendor/github.com/volatiletech/null/v8/.gitignore new file mode 100644 index 000000000..1b3ac108d --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/.gitignore @@ -0,0 +1 @@ +coverage.out \ No newline at end of file diff --git a/vendor/github.com/volatiletech/null/v8/CHANGELOG.md b/vendor/github.com/volatiletech/null/v8/CHANGELOG.md new file mode 100644 index 000000000..8f8ec875a --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [v8.0.0] + +### Changed + +- Update code for new randomizer interface +- Start versioning with semantic versions +- Add tags for older versions (back to 7.1.0) diff --git a/vendor/github.com/volatiletech/null/v8/LICENSE b/vendor/github.com/volatiletech/null/v8/LICENSE new file mode 100644 index 000000000..fe95b731e --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/LICENSE @@ -0,0 +1,11 @@ +Copyright for portions of project null-extended are held by *Greg Roseberry, 2014* as part of project null. +All other copyright for project null-extended are held by *Patrick O'Brien, 2016*. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. 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. + +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 HOLDER 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/github.com/volatiletech/null/v8/README.md b/vendor/github.com/volatiletech/null/v8/README.md new file mode 100644 index 000000000..a75e5fc8b --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/README.md @@ -0,0 +1,61 @@ +## null [![GoDoc](https://godoc.org/github.com/volatiletech/null?status.svg)](https://godoc.org/github.com/volatiletech/null) [![Coverage](http://gocover.io/_badge/github.com/volatiletech/null)](http://gocover.io/github.com/volatiletech/null) + +`null` is a library with reasonable options for dealing with nullable SQL and +JSON values. + +Types in `null` will only be considered null on null input, and will JSON +encode to `null`. + +All types implement `sql.Scanner` and `driver.Valuer`, so you can use this +library in place of `sql.NullXXX`. All types also implement: +`encoding.TextMarshaler`, `encoding.TextUnmarshaler`, `json.Marshaler`, +`json.Unmarshaler` and `sql.Scanner`. + +--- + +### Installation + +Null used to be versioned with gopkg.in, so once you upgrade to v8 and beyond +please stop using gopkg.in and ensure you're using `vgo`, `dep` or vendoring to +version null. + +``` +go get -u "github.com/volatiletech/null" +``` + +### Usage + +The following are all types supported in this package. All types will marshal +to JSON null if Invalid or SQL source data is null. + +| Type | Description | Notes | +|------|-------------|-------| +| `null.JSON` | Nullable `[]byte` | Will marshal to JSON null if Invalid. `[]byte{}` input will not produce an Invalid JSON, but `[]byte(nil)` will. This should be used for storing raw JSON in the database. Also has `null.JSON.Marshal` and `null.JSON.Unmarshal` helpers to marshal and unmarshal foreign objects. | +| `null.Bytes` | Nullable `[]byte` | `[]byte{}` input will not produce an Invalid Bytes, but `[]byte(nil)` will. This should be used for storing binary data (bytes in PSQL for example) in the database. | +| `null.String` | Nullable `string` | | +| `null.Byte` | Nullable `byte` | | +| `null.Bool` | Nullable `bool` | | +| `null.Time` | Nullable `time.Time | Marshals to JSON null if SQL source data is null. Uses `time.Time`'s marshaler. | +| `null.Float32` | Nullable `float32` | | +| `null.Float64` | Nullable `float64` | | +| `null.Int` | Nullable `int` | | +| `null.Int8` | Nullable `int8` | | +| `null.Int16` | Nullable `int16` | | +| `null.Int32` | Nullable `int32` | | +| `null.Int64` | Nullable `int64` | | +| `null.Uint` | Nullable `uint` | | +| `null.Uint8` | Nullable `uint8` | | +| `null.Uint16` | Nullable `uint16` | | +| `null.Uint32` | Nullable `int32` | | +| `null.Int64` | Nullable `uint64` | | | + +### Bugs + +`json`'s `",omitempty"` struct tag does not work correctly right now. It will +never omit a null or empty String. This might be [fixed +eventually](https://github.com/golang/go/issues/4357). + + +### License + +BSD diff --git a/vendor/github.com/volatiletech/null/v8/bool.go b/vendor/github.com/volatiletech/null/v8/bool.go new file mode 100644 index 000000000..a757d0971 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/bool.go @@ -0,0 +1,144 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "errors" + + "github.com/volatiletech/null/v8/convert" +) + +// Bool is a nullable bool. +type Bool struct { + Bool bool + Valid bool +} + +// NewBool creates a new Bool +func NewBool(b bool, valid bool) Bool { + return Bool{ + Bool: b, + Valid: valid, + } +} + +// BoolFrom creates a new Bool that will always be valid. +func BoolFrom(b bool) Bool { + return NewBool(b, true) +} + +// BoolFromPtr creates a new Bool that will be null if f is nil. +func BoolFromPtr(b *bool) Bool { + if b == nil { + return NewBool(false, false) + } + return NewBool(*b, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (b *Bool) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + b.Bool = false + b.Valid = false + return nil + } + + if err := json.Unmarshal(data, &b.Bool); err != nil { + return err + } + + b.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (b *Bool) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + b.Valid = false + return nil + } + + str := string(text) + switch str { + case "true": + b.Bool = true + case "false": + b.Bool = false + default: + b.Valid = false + return errors.New("invalid input:" + str) + } + b.Valid = true + return nil +} + +// MarshalJSON implements json.Marshaler. +func (b Bool) MarshalJSON() ([]byte, error) { + if !b.Valid { + return NullBytes, nil + } + if !b.Bool { + return []byte("false"), nil + } + return []byte("true"), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (b Bool) MarshalText() ([]byte, error) { + if !b.Valid { + return []byte{}, nil + } + if !b.Bool { + return []byte("false"), nil + } + return []byte("true"), nil +} + +// SetValid changes this Bool's value and also sets it to be non-null. +func (b *Bool) SetValid(v bool) { + b.Bool = v + b.Valid = true +} + +// Ptr returns a pointer to this Bool's value, or a nil pointer if this Bool is null. +func (b Bool) Ptr() *bool { + if !b.Valid { + return nil + } + return &b.Bool +} + +// IsZero returns true for invalid Bools, for future omitempty support (Go 1.4?) +func (b Bool) IsZero() bool { + return !b.Valid +} + +// Scan implements the Scanner interface. +func (b *Bool) Scan(value interface{}) error { + if value == nil { + b.Bool, b.Valid = false, false + return nil + } + b.Valid = true + return convert.ConvertAssign(&b.Bool, value) +} + +// Value implements the driver Valuer interface. +func (b Bool) Value() (driver.Value, error) { + if !b.Valid { + return nil, nil + } + return b.Bool, nil +} + +// Randomize for sqlboiler +func (b *Bool) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + b.Bool = false + b.Valid = false + } else { + b.Bool = nextInt()%2 == 1 + b.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/byte.go b/vendor/github.com/volatiletech/null/v8/byte.go new file mode 100644 index 000000000..9a4cd2c2b --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/byte.go @@ -0,0 +1,146 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "errors" +) + +// Byte is an nullable int. +type Byte struct { + Byte byte + Valid bool +} + +// NewByte creates a new Byte +func NewByte(b byte, valid bool) Byte { + return Byte{ + Byte: b, + Valid: valid, + } +} + +// ByteFrom creates a new Byte that will always be valid. +func ByteFrom(b byte) Byte { + return NewByte(b, true) +} + +// ByteFromPtr creates a new Byte that be null if i is nil. +func ByteFromPtr(b *byte) Byte { + if b == nil { + return NewByte(0, false) + } + return NewByte(*b, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (b *Byte) UnmarshalJSON(data []byte) error { + if len(data) == 0 || bytes.Equal(data, NullBytes) { + b.Valid = false + b.Byte = 0 + return nil + } + + var x string + if err := json.Unmarshal(data, &x); err != nil { + return err + } + + if len(x) > 1 { + return errors.New("json: cannot convert to byte, text len is greater than one") + } + + b.Byte = x[0] + b.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (b *Byte) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + b.Valid = false + return nil + } + + if len(text) > 1 { + return errors.New("text: cannot convert to byte, text len is greater than one") + } + + b.Valid = true + b.Byte = text[0] + return nil +} + +// MarshalJSON implements json.Marshaler. +func (b Byte) MarshalJSON() ([]byte, error) { + if !b.Valid { + return NullBytes, nil + } + return []byte{'"', b.Byte, '"'}, nil +} + +// MarshalText implements encoding.TextMarshaler. +func (b Byte) MarshalText() ([]byte, error) { + if !b.Valid { + return []byte{}, nil + } + return []byte{b.Byte}, nil +} + +// SetValid changes this Byte's value and also sets it to be non-null. +func (b *Byte) SetValid(n byte) { + b.Byte = n + b.Valid = true +} + +// Ptr returns a pointer to this Byte's value, or a nil pointer if this Byte is null. +func (b Byte) Ptr() *byte { + if !b.Valid { + return nil + } + return &b.Byte +} + +// IsZero returns true for invalid Bytes, for future omitempty support (Go 1.4?) +func (b Byte) IsZero() bool { + return !b.Valid +} + +// Scan implements the Scanner interface. +func (b *Byte) Scan(value interface{}) error { + if value == nil { + b.Byte, b.Valid = 0, false + return nil + } + + val := value.(string) + if len(val) == 0 { + b.Valid = false + b.Byte = 0 + return nil + } + + b.Valid = true + b.Byte = byte(val[0]) + return nil +} + +// Value implements the driver Valuer interface. +func (b Byte) Value() (driver.Value, error) { + if !b.Valid { + return nil, nil + } + return []byte{b.Byte}, nil +} + +// Randomize for sqlboiler +func (b *Byte) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + b.Byte = byte(0) + b.Valid = false + } else { + b.Byte = byte(nextInt()%60 + 65) // Ascii range + b.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/bytes.go b/vendor/github.com/volatiletech/null/v8/bytes.go new file mode 100644 index 000000000..2f58b45a1 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/bytes.go @@ -0,0 +1,135 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + + "github.com/volatiletech/null/v8/convert" +) + +// NullBytes is a global byte slice of JSON null +var NullBytes = []byte("null") + +// Bytes is a nullable []byte. +type Bytes struct { + Bytes []byte + Valid bool +} + +// NewBytes creates a new Bytes +func NewBytes(b []byte, valid bool) Bytes { + return Bytes{ + Bytes: b, + Valid: valid, + } +} + +// BytesFrom creates a new Bytes that will be invalid if nil. +func BytesFrom(b []byte) Bytes { + return NewBytes(b, b != nil) +} + +// BytesFromPtr creates a new Bytes that will be invalid if nil. +func BytesFromPtr(b *[]byte) Bytes { + if b == nil { + return NewBytes(nil, false) + } + n := NewBytes(*b, true) + return n +} + +// UnmarshalJSON implements json.Unmarshaler. +func (b *Bytes) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + b.Valid = false + b.Bytes = nil + return nil + } + + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + + b.Bytes = []byte(s) + b.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (b *Bytes) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + b.Bytes = nil + b.Valid = false + } else { + b.Bytes = append(b.Bytes[0:0], text...) + b.Valid = true + } + + return nil +} + +// MarshalJSON implements json.Marshaler. +func (b Bytes) MarshalJSON() ([]byte, error) { + if len(b.Bytes) == 0 || b.Bytes == nil { + return NullBytes, nil + } + return b.Bytes, nil +} + +// MarshalText implements encoding.TextMarshaler. +func (b Bytes) MarshalText() ([]byte, error) { + if !b.Valid { + return nil, nil + } + return b.Bytes, nil +} + +// SetValid changes this Bytes's value and also sets it to be non-null. +func (b *Bytes) SetValid(n []byte) { + b.Bytes = n + b.Valid = true +} + +// Ptr returns a pointer to this Bytes's value, or a nil pointer if this Bytes is null. +func (b Bytes) Ptr() *[]byte { + if !b.Valid { + return nil + } + return &b.Bytes +} + +// IsZero returns true for null or zero Bytes's, for future omitempty support (Go 1.4?) +func (b Bytes) IsZero() bool { + return !b.Valid +} + +// Scan implements the Scanner interface. +func (b *Bytes) Scan(value interface{}) error { + if value == nil { + b.Bytes, b.Valid = []byte{}, false + return nil + } + b.Valid = true + return convert.ConvertAssign(&b.Bytes, value) +} + +// Value implements the driver Valuer interface. +func (b Bytes) Value() (driver.Value, error) { + if !b.Valid { + return nil, nil + } + return b.Bytes, nil +} + +// Randomize for sqlboiler +func (b *Bytes) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + b.Bytes = nil + b.Valid = false + } else { + b.Bytes = []byte{byte(nextInt() % 256)} + b.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/convert/convert.go b/vendor/github.com/volatiletech/null/v8/convert/convert.go new file mode 100644 index 000000000..b231ebf8e --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/convert/convert.go @@ -0,0 +1,266 @@ +package convert + +// Copyright 2011 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. + +// Type conversions for Scan. +// These functions are copied from database/sql/convert.go build 1.6.2 + +import ( + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "reflect" + "strconv" + "time" +) + +var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error + +// ConvertAssign copies to dest the value in src, converting it if possible. +// An error is returned if the copy would result in loss of information. +// dest should be a pointer type. +func ConvertAssign(dest, src interface{}) error { + // Common cases, without reflect. + switch s := src.(type) { + case string: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = s + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s) + return nil + } + case []byte: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = string(s) + return nil + case *interface{}: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = s + return nil + } + case time.Time: + switch d := dest.(type) { + case *string: + *d = s.Format(time.RFC3339Nano) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s.Format(time.RFC3339Nano)) + return nil + } + case nil: + switch d := dest.(type) { + case *interface{}: + if d == nil { + return errNilPtr + } + *d = nil + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = nil + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = nil + return nil + } + } + + var sv reflect.Value + + switch d := dest.(type) { + case *string: + sv = reflect.ValueOf(src) + switch sv.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + *d = asString(src) + return nil + } + case *[]byte: + sv = reflect.ValueOf(src) + if b, ok := asBytes(nil, sv); ok { + *d = b + return nil + } + case *sql.RawBytes: + sv = reflect.ValueOf(src) + if b, ok := asBytes([]byte(*d)[:0], sv); ok { + *d = sql.RawBytes(b) + return nil + } + case *bool: + bv, err := driver.Bool.ConvertValue(src) + if err == nil { + *d = bv.(bool) + } + return err + case *interface{}: + *d = src + return nil + } + + if scanner, ok := dest.(sql.Scanner); ok { + return scanner.Scan(src) + } + + dpv := reflect.ValueOf(dest) + if dpv.Kind() != reflect.Ptr { + return errors.New("destination not a pointer") + } + if dpv.IsNil() { + return errNilPtr + } + + if !sv.IsValid() { + sv = reflect.ValueOf(src) + } + + dv := reflect.Indirect(dpv) + if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { + dv.Set(sv) + return nil + } + + if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { + dv.Set(sv.Convert(dv.Type())) + return nil + } + + switch dv.Kind() { + case reflect.Ptr: + if src == nil { + dv.Set(reflect.Zero(dv.Type())) + return nil + } else { + dv.Set(reflect.New(dv.Type().Elem())) + return ConvertAssign(dv.Interface(), src) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := asString(src) + i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetInt(i64) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + s := asString(src) + u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetUint(u64) + return nil + case reflect.Float32, reflect.Float64: + s := asString(src) + f64, err := strconv.ParseFloat(s, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetFloat(f64) + return nil + } + + return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) +} + +func strconvErr(err error) error { + if ne, ok := err.(*strconv.NumError); ok { + return ne.Err + } + return err +} + +func cloneBytes(b []byte) []byte { + if b == nil { + return nil + } else { + c := make([]byte, len(b)) + copy(c, b) + return c + } +} + +func asString(src interface{}) string { + switch v := src.(type) { + case string: + return v + case []byte: + return string(v) + } + rv := reflect.ValueOf(src) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.FormatInt(rv.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.FormatUint(rv.Uint(), 10) + case reflect.Float64: + return strconv.FormatFloat(rv.Float(), 'g', -1, 64) + case reflect.Float32: + return strconv.FormatFloat(rv.Float(), 'g', -1, 32) + case reflect.Bool: + return strconv.FormatBool(rv.Bool()) + } + return fmt.Sprintf("%v", src) +} + +func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) { + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.AppendInt(buf, rv.Int(), 10), true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.AppendUint(buf, rv.Uint(), 10), true + case reflect.Float32: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true + case reflect.Float64: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true + case reflect.Bool: + return strconv.AppendBool(buf, rv.Bool()), true + case reflect.String: + s := rv.String() + return append(buf, s...), true + } + return +} diff --git a/vendor/github.com/volatiletech/null/v8/float32.go b/vendor/github.com/volatiletech/null/v8/float32.go new file mode 100644 index 000000000..b74e260e7 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/float32.go @@ -0,0 +1,134 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "strconv" + + "github.com/volatiletech/null/v8/convert" +) + +// Float32 is a nullable float32. +type Float32 struct { + Float32 float32 + Valid bool +} + +// NewFloat32 creates a new Float32 +func NewFloat32(f float32, valid bool) Float32 { + return Float32{ + Float32: f, + Valid: valid, + } +} + +// Float32From creates a new Float32 that will always be valid. +func Float32From(f float32) Float32 { + return NewFloat32(f, true) +} + +// Float32FromPtr creates a new Float32 that be null if f is nil. +func Float32FromPtr(f *float32) Float32 { + if f == nil { + return NewFloat32(0, false) + } + return NewFloat32(*f, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (f *Float32) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + f.Valid = false + f.Float32 = 0 + return nil + } + + var x float64 + if err := json.Unmarshal(data, &x); err != nil { + return err + } + + f.Float32 = float32(x) + f.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (f *Float32) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + f.Valid = false + return nil + } + var err error + res, err := strconv.ParseFloat(string(text), 32) + f.Valid = err == nil + if f.Valid { + f.Float32 = float32(res) + } + return err +} + +// MarshalJSON implements json.Marshaler. +func (f Float32) MarshalJSON() ([]byte, error) { + if !f.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatFloat(float64(f.Float32), 'f', -1, 32)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (f Float32) MarshalText() ([]byte, error) { + if !f.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatFloat(float64(f.Float32), 'f', -1, 32)), nil +} + +// SetValid changes this Float32's value and also sets it to be non-null. +func (f *Float32) SetValid(n float32) { + f.Float32 = n + f.Valid = true +} + +// Ptr returns a pointer to this Float32's value, or a nil pointer if this Float32 is null. +func (f Float32) Ptr() *float32 { + if !f.Valid { + return nil + } + return &f.Float32 +} + +// IsZero returns true for invalid Float32s, for future omitempty support (Go 1.4?) +func (f Float32) IsZero() bool { + return !f.Valid +} + +// Scan implements the Scanner interface. +func (f *Float32) Scan(value interface{}) error { + if value == nil { + f.Float32, f.Valid = 0, false + return nil + } + f.Valid = true + return convert.ConvertAssign(&f.Float32, value) +} + +// Value implements the driver Valuer interface. +func (f Float32) Value() (driver.Value, error) { + if !f.Valid { + return nil, nil + } + return float64(f.Float32), nil +} + +// Randomize for sqlboiler +func (f *Float32) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + f.Float32 = 0 + f.Valid = false + } else { + f.Float32 = float32(nextInt()%10)/10.0 + float32(nextInt()%10) + f.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/float64.go b/vendor/github.com/volatiletech/null/v8/float64.go new file mode 100644 index 000000000..dea1eb423 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/float64.go @@ -0,0 +1,129 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "strconv" + + "github.com/volatiletech/null/v8/convert" +) + +// Float64 is a nullable float64. +type Float64 struct { + Float64 float64 + Valid bool +} + +// NewFloat64 creates a new Float64 +func NewFloat64(f float64, valid bool) Float64 { + return Float64{ + Float64: f, + Valid: valid, + } +} + +// Float64From creates a new Float64 that will always be valid. +func Float64From(f float64) Float64 { + return NewFloat64(f, true) +} + +// Float64FromPtr creates a new Float64 that be null if f is nil. +func Float64FromPtr(f *float64) Float64 { + if f == nil { + return NewFloat64(0, false) + } + return NewFloat64(*f, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (f *Float64) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + f.Float64 = 0 + f.Valid = false + return nil + } + + if err := json.Unmarshal(data, &f.Float64); err != nil { + return err + } + + f.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (f *Float64) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + f.Valid = false + return nil + } + var err error + f.Float64, err = strconv.ParseFloat(string(text), 64) + f.Valid = err == nil + return err +} + +// MarshalJSON implements json.Marshaler. +func (f Float64) MarshalJSON() ([]byte, error) { + if !f.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatFloat(f.Float64, 'f', -1, 64)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (f Float64) MarshalText() ([]byte, error) { + if !f.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatFloat(f.Float64, 'f', -1, 64)), nil +} + +// SetValid changes this Float64's value and also sets it to be non-null. +func (f *Float64) SetValid(n float64) { + f.Float64 = n + f.Valid = true +} + +// Ptr returns a pointer to this Float64's value, or a nil pointer if this Float64 is null. +func (f Float64) Ptr() *float64 { + if !f.Valid { + return nil + } + return &f.Float64 +} + +// IsZero returns true for invalid Float64s, for future omitempty support (Go 1.4?) +func (f Float64) IsZero() bool { + return !f.Valid +} + +// Scan implements the Scanner interface. +func (f *Float64) Scan(value interface{}) error { + if value == nil { + f.Float64, f.Valid = 0, false + return nil + } + f.Valid = true + return convert.ConvertAssign(&f.Float64, value) +} + +// Value implements the driver Valuer interface. +func (f Float64) Value() (driver.Value, error) { + if !f.Valid { + return nil, nil + } + return f.Float64, nil +} + +// Randomize for sqlboiler +func (f *Float64) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + f.Float64 = 0 + f.Valid = false + } else { + f.Float64 = float64(nextInt()%10)/10.0 + float64(nextInt()%10) + f.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/int.go b/vendor/github.com/volatiletech/null/v8/int.go new file mode 100644 index 000000000..62e7f9fbd --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/int.go @@ -0,0 +1,135 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "math" + "strconv" + + "github.com/volatiletech/null/v8/convert" +) + +// Int is an nullable int. +type Int struct { + Int int + Valid bool +} + +// NewInt creates a new Int +func NewInt(i int, valid bool) Int { + return Int{ + Int: i, + Valid: valid, + } +} + +// IntFrom creates a new Int that will always be valid. +func IntFrom(i int) Int { + return NewInt(i, true) +} + +// IntFromPtr creates a new Int that be null if i is nil. +func IntFromPtr(i *int) Int { + if i == nil { + return NewInt(0, false) + } + return NewInt(*i, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (i *Int) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + i.Valid = false + i.Int = 0 + return nil + } + + var x int64 + if err := json.Unmarshal(data, &x); err != nil { + return err + } + + i.Int = int(x) + i.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (i *Int) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + i.Valid = false + return nil + } + var err error + res, err := strconv.ParseInt(string(text), 10, 0) + i.Valid = err == nil + if i.Valid { + i.Int = int(res) + } + return err +} + +// MarshalJSON implements json.Marshaler. +func (i Int) MarshalJSON() ([]byte, error) { + if !i.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatInt(int64(i.Int), 10)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (i Int) MarshalText() ([]byte, error) { + if !i.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatInt(int64(i.Int), 10)), nil +} + +// SetValid changes this Int's value and also sets it to be non-null. +func (i *Int) SetValid(n int) { + i.Int = n + i.Valid = true +} + +// Ptr returns a pointer to this Int's value, or a nil pointer if this Int is null. +func (i Int) Ptr() *int { + if !i.Valid { + return nil + } + return &i.Int +} + +// IsZero returns true for invalid Ints, for future omitempty support (Go 1.4?) +func (i Int) IsZero() bool { + return !i.Valid +} + +// Scan implements the Scanner interface. +func (i *Int) Scan(value interface{}) error { + if value == nil { + i.Int, i.Valid = 0, false + return nil + } + i.Valid = true + return convert.ConvertAssign(&i.Int, value) +} + +// Value implements the driver Valuer interface. +func (i Int) Value() (driver.Value, error) { + if !i.Valid { + return nil, nil + } + return int64(i.Int), nil +} + +// Randomize for sqlboiler +func (i *Int) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + i.Int = 0 + i.Valid = false + } else { + i.Int = int(int32(nextInt() % math.MaxInt32)) + i.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/int16.go b/vendor/github.com/volatiletech/null/v8/int16.go new file mode 100644 index 000000000..48cd0415e --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/int16.go @@ -0,0 +1,140 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "fmt" + "math" + "strconv" + + "github.com/volatiletech/null/v8/convert" +) + +// Int16 is an nullable int16. +type Int16 struct { + Int16 int16 + Valid bool +} + +// NewInt16 creates a new Int16 +func NewInt16(i int16, valid bool) Int16 { + return Int16{ + Int16: i, + Valid: valid, + } +} + +// Int16From creates a new Int16 that will always be valid. +func Int16From(i int16) Int16 { + return NewInt16(i, true) +} + +// Int16FromPtr creates a new Int16 that be null if i is nil. +func Int16FromPtr(i *int16) Int16 { + if i == nil { + return NewInt16(0, false) + } + return NewInt16(*i, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (i *Int16) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + i.Valid = false + i.Int16 = 0 + return nil + } + + var x int64 + if err := json.Unmarshal(data, &x); err != nil { + return err + } + + if x > math.MaxInt16 { + return fmt.Errorf("json: %d overflows max int16 value", x) + } + + i.Int16 = int16(x) + i.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (i *Int16) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + i.Valid = false + return nil + } + var err error + res, err := strconv.ParseInt(string(text), 10, 16) + i.Valid = err == nil + if i.Valid { + i.Int16 = int16(res) + } + return err +} + +// MarshalJSON implements json.Marshaler. +func (i Int16) MarshalJSON() ([]byte, error) { + if !i.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatInt(int64(i.Int16), 10)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (i Int16) MarshalText() ([]byte, error) { + if !i.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatInt(int64(i.Int16), 10)), nil +} + +// SetValid changes this Int16's value and also sets it to be non-null. +func (i *Int16) SetValid(n int16) { + i.Int16 = n + i.Valid = true +} + +// Ptr returns a pointer to this Int16's value, or a nil pointer if this Int16 is null. +func (i Int16) Ptr() *int16 { + if !i.Valid { + return nil + } + return &i.Int16 +} + +// IsZero returns true for invalid Int16's, for future omitempty support (Go 1.4?) +func (i Int16) IsZero() bool { + return !i.Valid +} + +// Scan implements the Scanner interface. +func (i *Int16) Scan(value interface{}) error { + if value == nil { + i.Int16, i.Valid = 0, false + return nil + } + i.Valid = true + return convert.ConvertAssign(&i.Int16, value) +} + +// Value implements the driver Valuer interface. +func (i Int16) Value() (driver.Value, error) { + if !i.Valid { + return nil, nil + } + return int64(i.Int16), nil +} + +// Randomize for sqlboiler +func (i *Int16) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + i.Int16 = 0 + i.Valid = false + } else { + i.Int16 = int16(nextInt() % math.MaxInt16) + i.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/int32.go b/vendor/github.com/volatiletech/null/v8/int32.go new file mode 100644 index 000000000..5de9fc02c --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/int32.go @@ -0,0 +1,147 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "fmt" + "math" + "strconv" + + "github.com/volatiletech/null/v8/convert" + "github.com/volatiletech/randomize" +) + +// Int32 is an nullable int32. +type Int32 struct { + Int32 int32 + Valid bool +} + +// NewInt32 creates a new Int32 +func NewInt32(i int32, valid bool) Int32 { + return Int32{ + Int32: i, + Valid: valid, + } +} + +// Int32From creates a new Int32 that will always be valid. +func Int32From(i int32) Int32 { + return NewInt32(i, true) +} + +// Int32FromPtr creates a new Int32 that be null if i is nil. +func Int32FromPtr(i *int32) Int32 { + if i == nil { + return NewInt32(0, false) + } + return NewInt32(*i, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (i *Int32) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + i.Valid = false + i.Int32 = 0 + return nil + } + + var x int64 + if err := json.Unmarshal(data, &x); err != nil { + return err + } + + if x > math.MaxInt32 { + return fmt.Errorf("json: %d overflows max int32 value", x) + } + + i.Int32 = int32(x) + i.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (i *Int32) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + i.Valid = false + return nil + } + var err error + res, err := strconv.ParseInt(string(text), 10, 32) + i.Valid = err == nil + if i.Valid { + i.Int32 = int32(res) + } + return err +} + +// MarshalJSON implements json.Marshaler. +func (i Int32) MarshalJSON() ([]byte, error) { + if !i.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatInt(int64(i.Int32), 10)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (i Int32) MarshalText() ([]byte, error) { + if !i.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatInt(int64(i.Int32), 10)), nil +} + +// SetValid changes this Int32's value and also sets it to be non-null. +func (i *Int32) SetValid(n int32) { + i.Int32 = n + i.Valid = true +} + +// Ptr returns a pointer to this Int32's value, or a nil pointer if this Int32 is null. +func (i Int32) Ptr() *int32 { + if !i.Valid { + return nil + } + return &i.Int32 +} + +// IsZero returns true for invalid Int32's, for future omitempty support (Go 1.4?) +func (i Int32) IsZero() bool { + return !i.Valid +} + +// Scan implements the Scanner interface. +func (i *Int32) Scan(value interface{}) error { + if value == nil { + i.Int32, i.Valid = 0, false + return nil + } + i.Valid = true + return convert.ConvertAssign(&i.Int32, value) +} + +// Value implements the driver Valuer interface. +func (i Int32) Value() (driver.Value, error) { + if !i.Valid { + return nil, nil + } + return int64(i.Int32), nil +} + +// Randomize for sqlboiler +func (i *Int32) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + i.Int32 = 0 + i.Valid = false + } else { + val, ok := randomize.MediumInt(nextInt, fieldType) + if ok { + i.Int32 = val + } else { + i.Int32 = int32(nextInt() % math.MaxInt32) + } + + i.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/int64.go b/vendor/github.com/volatiletech/null/v8/int64.go new file mode 100644 index 000000000..01a602851 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/int64.go @@ -0,0 +1,129 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "strconv" + + "github.com/volatiletech/null/v8/convert" +) + +// Int64 is an nullable int64. +type Int64 struct { + Int64 int64 + Valid bool +} + +// NewInt64 creates a new Int64 +func NewInt64(i int64, valid bool) Int64 { + return Int64{ + Int64: i, + Valid: valid, + } +} + +// Int64From creates a new Int64 that will always be valid. +func Int64From(i int64) Int64 { + return NewInt64(i, true) +} + +// Int64FromPtr creates a new Int64 that be null if i is nil. +func Int64FromPtr(i *int64) Int64 { + if i == nil { + return NewInt64(0, false) + } + return NewInt64(*i, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (i *Int64) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + i.Valid = false + i.Int64 = 0 + return nil + } + + if err := json.Unmarshal(data, &i.Int64); err != nil { + return err + } + + i.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (i *Int64) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + i.Valid = false + return nil + } + var err error + i.Int64, err = strconv.ParseInt(string(text), 10, 64) + i.Valid = err == nil + return err +} + +// MarshalJSON implements json.Marshaler. +func (i Int64) MarshalJSON() ([]byte, error) { + if !i.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatInt(i.Int64, 10)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (i Int64) MarshalText() ([]byte, error) { + if !i.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatInt(i.Int64, 10)), nil +} + +// SetValid changes this Int64's value and also sets it to be non-null. +func (i *Int64) SetValid(n int64) { + i.Int64 = n + i.Valid = true +} + +// Ptr returns a pointer to this Int64's value, or a nil pointer if this Int64 is null. +func (i Int64) Ptr() *int64 { + if !i.Valid { + return nil + } + return &i.Int64 +} + +// IsZero returns true for invalid Int64's, for future omitempty support (Go 1.4?) +func (i Int64) IsZero() bool { + return !i.Valid +} + +// Scan implements the Scanner interface. +func (i *Int64) Scan(value interface{}) error { + if value == nil { + i.Int64, i.Valid = 0, false + return nil + } + i.Valid = true + return convert.ConvertAssign(&i.Int64, value) +} + +// Value implements the driver Valuer interface. +func (i Int64) Value() (driver.Value, error) { + if !i.Valid { + return nil, nil + } + return i.Int64, nil +} + +// Randomize for sqlboiler +func (i *Int64) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + i.Int64 = 0 + i.Valid = false + } else { + i.Int64 = int64(nextInt()) + i.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/int8.go b/vendor/github.com/volatiletech/null/v8/int8.go new file mode 100644 index 000000000..899f35834 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/int8.go @@ -0,0 +1,140 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "fmt" + "math" + "strconv" + + "github.com/volatiletech/null/v8/convert" +) + +// Int8 is an nullable int8. +type Int8 struct { + Int8 int8 + Valid bool +} + +// NewInt8 creates a new Int8 +func NewInt8(i int8, valid bool) Int8 { + return Int8{ + Int8: i, + Valid: valid, + } +} + +// Int8From creates a new Int8 that will always be valid. +func Int8From(i int8) Int8 { + return NewInt8(i, true) +} + +// Int8FromPtr creates a new Int8 that be null if i is nil. +func Int8FromPtr(i *int8) Int8 { + if i == nil { + return NewInt8(0, false) + } + return NewInt8(*i, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (i *Int8) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + i.Valid = false + i.Int8 = 0 + return nil + } + + var x int64 + if err := json.Unmarshal(data, &x); err != nil { + return err + } + + if x > math.MaxInt8 { + return fmt.Errorf("json: %d overflows max int8 value", x) + } + + i.Int8 = int8(x) + i.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (i *Int8) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + i.Valid = false + return nil + } + var err error + res, err := strconv.ParseInt(string(text), 10, 8) + i.Valid = err == nil + if i.Valid { + i.Int8 = int8(res) + } + return err +} + +// MarshalJSON implements json.Marshaler. +func (i Int8) MarshalJSON() ([]byte, error) { + if !i.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatInt(int64(i.Int8), 10)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (i Int8) MarshalText() ([]byte, error) { + if !i.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatInt(int64(i.Int8), 10)), nil +} + +// SetValid changes this Int8's value and also sets it to be non-null. +func (i *Int8) SetValid(n int8) { + i.Int8 = n + i.Valid = true +} + +// Ptr returns a pointer to this Int8's value, or a nil pointer if this Int8 is null. +func (i Int8) Ptr() *int8 { + if !i.Valid { + return nil + } + return &i.Int8 +} + +// IsZero returns true for invalid Int8's, for future omitempty support (Go 1.4?) +func (i Int8) IsZero() bool { + return !i.Valid +} + +// Scan implements the Scanner interface. +func (i *Int8) Scan(value interface{}) error { + if value == nil { + i.Int8, i.Valid = 0, false + return nil + } + i.Valid = true + return convert.ConvertAssign(&i.Int8, value) +} + +// Value implements the driver Valuer interface. +func (i Int8) Value() (driver.Value, error) { + if !i.Valid { + return nil, nil + } + return int64(i.Int8), nil +} + +// Randomize for sqlboiler +func (i *Int8) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + i.Int8 = 0 + i.Valid = false + } else { + i.Int8 = int8(nextInt() % math.MaxInt8) + i.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/json.go b/vendor/github.com/volatiletech/null/v8/json.go new file mode 100644 index 000000000..550ed4648 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/json.go @@ -0,0 +1,164 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "errors" + "fmt" + + "github.com/volatiletech/null/v8/convert" + "github.com/volatiletech/randomize" +) + +// JSON is a nullable []byte. +type JSON struct { + JSON []byte + Valid bool +} + +// NewJSON creates a new JSON +func NewJSON(b []byte, valid bool) JSON { + return JSON{ + JSON: b, + Valid: valid, + } +} + +// JSONFrom creates a new JSON that will be invalid if nil. +func JSONFrom(b []byte) JSON { + return NewJSON(b, b != nil) +} + +// JSONFromPtr creates a new JSON that will be invalid if nil. +func JSONFromPtr(b *[]byte) JSON { + if b == nil { + return NewJSON(nil, false) + } + n := NewJSON(*b, true) + return n +} + +// Unmarshal will unmarshal your JSON stored in +// your JSON object and store the result in the +// value pointed to by dest. +func (j JSON) Unmarshal(dest interface{}) error { + if dest == nil { + return errors.New("destination is nil, not a valid pointer to an object") + } + + // Call our implementation of + // JSON MarshalJSON through json.Marshal + // to get the value of the JSON object + res, err := json.Marshal(j) + if err != nil { + return err + } + + return json.Unmarshal(res, dest) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (j *JSON) UnmarshalJSON(data []byte) error { + if data == nil { + return fmt.Errorf("json: cannot unmarshal nil into Go value of type null.JSON") + } + + if bytes.Equal(data, NullBytes) { + j.JSON = NullBytes + j.Valid = false + return nil + } + + j.Valid = true + j.JSON = make([]byte, len(data)) + copy(j.JSON, data) + + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (j *JSON) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + j.JSON = nil + j.Valid = false + } else { + j.JSON = append(j.JSON[0:0], text...) + j.Valid = true + } + + return nil +} + +// Marshal will marshal the passed in object, +// and store it in the JSON member on the JSON object. +func (j *JSON) Marshal(obj interface{}) error { + res, err := json.Marshal(obj) + if err != nil { + return err + } + + // Call our implementation of + // JSON UnmarshalJSON through json.Unmarshal + // to set the result to the JSON object + return json.Unmarshal(res, j) +} + +// MarshalJSON implements json.Marshaler. +func (j JSON) MarshalJSON() ([]byte, error) { + if len(j.JSON) == 0 || j.JSON == nil { + return NullBytes, nil + } + return j.JSON, nil +} + +// MarshalText implements encoding.TextMarshaler. +func (j JSON) MarshalText() ([]byte, error) { + if !j.Valid { + return nil, nil + } + return j.JSON, nil +} + +// SetValid changes this JSON's value and also sets it to be non-null. +func (j *JSON) SetValid(n []byte) { + j.JSON = n + j.Valid = true +} + +// Ptr returns a pointer to this JSON's value, or a nil pointer if this JSON is null. +func (j JSON) Ptr() *[]byte { + if !j.Valid { + return nil + } + return &j.JSON +} + +// IsZero returns true for null or zero JSON's, for future omitempty support (Go 1.4?) +func (j JSON) IsZero() bool { + return !j.Valid +} + +// Scan implements the Scanner interface. +func (j *JSON) Scan(value interface{}) error { + if value == nil { + j.JSON, j.Valid = []byte{}, false + return nil + } + j.Valid = true + return convert.ConvertAssign(&j.JSON, value) +} + +// Value implements the driver Valuer interface. +func (j JSON) Value() (driver.Value, error) { + if !j.Valid { + return nil, nil + } + return j.JSON, nil +} + +// Randomize for sqlboiler +func (j *JSON) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + j.JSON = []byte(`"` + randomize.Str(nextInt, 1) + `"`) + j.Valid = true +} diff --git a/vendor/github.com/volatiletech/null/v8/string.go b/vendor/github.com/volatiletech/null/v8/string.go new file mode 100644 index 000000000..5a48ea990 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/string.go @@ -0,0 +1,136 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + + "github.com/volatiletech/null/v8/convert" + "github.com/volatiletech/randomize" +) + +// String is a nullable string. It supports SQL and JSON serialization. +type String struct { + String string + Valid bool +} + +// StringFrom creates a new String that will never be blank. +func StringFrom(s string) String { + return NewString(s, true) +} + +// StringFromPtr creates a new String that be null if s is nil. +func StringFromPtr(s *string) String { + if s == nil { + return NewString("", false) + } + return NewString(*s, true) +} + +// NewString creates a new String +func NewString(s string, valid bool) String { + return String{ + String: s, + Valid: valid, + } +} + +// UnmarshalJSON implements json.Unmarshaler. +func (s *String) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + s.String = "" + s.Valid = false + return nil + } + + if err := json.Unmarshal(data, &s.String); err != nil { + return err + } + + s.Valid = true + return nil +} + +// MarshalJSON implements json.Marshaler. +func (s String) MarshalJSON() ([]byte, error) { + if !s.Valid { + return NullBytes, nil + } + return json.Marshal(s.String) +} + +// MarshalText implements encoding.TextMarshaler. +func (s String) MarshalText() ([]byte, error) { + if !s.Valid { + return []byte{}, nil + } + return []byte(s.String), nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (s *String) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + s.Valid = false + return nil + } + + s.String = string(text) + s.Valid = true + return nil +} + +// SetValid changes this String's value and also sets it to be non-null. +func (s *String) SetValid(v string) { + s.String = v + s.Valid = true +} + +// Ptr returns a pointer to this String's value, or a nil pointer if this String is null. +func (s String) Ptr() *string { + if !s.Valid { + return nil + } + return &s.String +} + +// IsZero returns true for null strings, for potential future omitempty support. +func (s String) IsZero() bool { + return !s.Valid +} + +// Scan implements the Scanner interface. +func (s *String) Scan(value interface{}) error { + if value == nil { + s.String, s.Valid = "", false + return nil + } + s.Valid = true + return convert.ConvertAssign(&s.String, value) +} + +// Value implements the driver Valuer interface. +func (s String) Value() (driver.Value, error) { + if !s.Valid { + return nil, nil + } + return s.String, nil +} + +// Randomize for sqlboiler +func (s *String) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + str, ok := randomize.FormattedString(nextInt, fieldType) + if ok { + s.String = str + s.Valid = true + return + } + + if shouldBeNull { + s.String = "" + s.Valid = false + } else { + s.String = randomize.Str(nextInt, 1) + s.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/time.go b/vendor/github.com/volatiletech/null/v8/time.go new file mode 100644 index 000000000..34be1dc95 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/time.go @@ -0,0 +1,136 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "fmt" + "time" + + "github.com/volatiletech/randomize" +) + +// Time is a nullable time.Time. It supports SQL and JSON serialization. +type Time struct { + Time time.Time + Valid bool +} + +// NewTime creates a new Time. +func NewTime(t time.Time, valid bool) Time { + return Time{ + Time: t, + Valid: valid, + } +} + +// TimeFrom creates a new Time that will always be valid. +func TimeFrom(t time.Time) Time { + return NewTime(t, true) +} + +// TimeFromPtr creates a new Time that will be null if t is nil. +func TimeFromPtr(t *time.Time) Time { + if t == nil { + return NewTime(time.Time{}, false) + } + return NewTime(*t, true) +} + +// MarshalJSON implements json.Marshaler. +func (t Time) MarshalJSON() ([]byte, error) { + if !t.Valid { + return NullBytes, nil + } + return t.Time.MarshalJSON() +} + +// UnmarshalJSON implements json.Unmarshaler. +func (t *Time) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + t.Valid = false + t.Time = time.Time{} + return nil + } + + if err := t.Time.UnmarshalJSON(data); err != nil { + return err + } + + t.Valid = true + return nil +} + +// MarshalText implements encoding.TextMarshaler. +func (t Time) MarshalText() ([]byte, error) { + if !t.Valid { + return NullBytes, nil + } + return t.Time.MarshalText() +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (t *Time) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + t.Valid = false + return nil + } + if err := t.Time.UnmarshalText(text); err != nil { + return err + } + t.Valid = true + return nil +} + +// SetValid changes this Time's value and sets it to be non-null. +func (t *Time) SetValid(v time.Time) { + t.Time = v + t.Valid = true +} + +// Ptr returns a pointer to this Time's value, or a nil pointer if this Time is null. +func (t Time) Ptr() *time.Time { + if !t.Valid { + return nil + } + return &t.Time +} + +// IsZero returns true for an invalid Time's value, for potential future omitempty support. +func (t Time) IsZero() bool { + return !t.Valid +} + +// Scan implements the Scanner interface. +func (t *Time) Scan(value interface{}) error { + var err error + switch x := value.(type) { + case time.Time: + t.Time = x + case nil: + t.Valid = false + return nil + default: + err = fmt.Errorf("null: cannot scan type %T into null.Time: %v", value, value) + } + t.Valid = err == nil + return err +} + +// Value implements the driver Valuer interface. +func (t Time) Value() (driver.Value, error) { + if !t.Valid { + return nil, nil + } + return t.Time, nil +} + +// Randomize for sqlboiler +func (t *Time) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + t.Time = time.Time{} + t.Valid = false + } else { + t.Time = randomize.Date(nextInt) + t.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/uint.go b/vendor/github.com/volatiletech/null/v8/uint.go new file mode 100644 index 000000000..ee17fadb4 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/uint.go @@ -0,0 +1,134 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "strconv" + + "github.com/volatiletech/null/v8/convert" +) + +// Uint is an nullable uint. +type Uint struct { + Uint uint + Valid bool +} + +// NewUint creates a new Uint +func NewUint(i uint, valid bool) Uint { + return Uint{ + Uint: i, + Valid: valid, + } +} + +// UintFrom creates a new Uint that will always be valid. +func UintFrom(i uint) Uint { + return NewUint(i, true) +} + +// UintFromPtr creates a new Uint that be null if i is nil. +func UintFromPtr(i *uint) Uint { + if i == nil { + return NewUint(0, false) + } + return NewUint(*i, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (u *Uint) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + u.Valid = false + u.Uint = 0 + return nil + } + + var x uint64 + if err := json.Unmarshal(data, &x); err != nil { + return err + } + + u.Uint = uint(x) + u.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (u *Uint) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + u.Valid = false + return nil + } + var err error + res, err := strconv.ParseUint(string(text), 10, 0) + u.Valid = err == nil + if u.Valid { + u.Uint = uint(res) + } + return err +} + +// MarshalJSON implements json.Marshaler. +func (u Uint) MarshalJSON() ([]byte, error) { + if !u.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatUint(uint64(u.Uint), 10)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (u Uint) MarshalText() ([]byte, error) { + if !u.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatUint(uint64(u.Uint), 10)), nil +} + +// SetValid changes this Uint's value and also sets it to be non-null. +func (u *Uint) SetValid(n uint) { + u.Uint = n + u.Valid = true +} + +// Ptr returns a pointer to this Uint's value, or a nil pointer if this Uint is null. +func (u Uint) Ptr() *uint { + if !u.Valid { + return nil + } + return &u.Uint +} + +// IsZero returns true for invalid Uints, for future omitempty support (Go 1.4?) +func (u Uint) IsZero() bool { + return !u.Valid +} + +// Scan implements the Scanner interface. +func (u *Uint) Scan(value interface{}) error { + if value == nil { + u.Uint, u.Valid = 0, false + return nil + } + u.Valid = true + return convert.ConvertAssign(&u.Uint, value) +} + +// Value implements the driver Valuer interface. +func (u Uint) Value() (driver.Value, error) { + if !u.Valid { + return nil, nil + } + return int64(u.Uint), nil +} + +// Randomize for sqlboiler +func (u *Uint) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + u.Uint = 0 + u.Valid = false + } else { + u.Uint = uint(nextInt()) + u.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/uint16.go b/vendor/github.com/volatiletech/null/v8/uint16.go new file mode 100644 index 000000000..d213be43d --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/uint16.go @@ -0,0 +1,140 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "fmt" + "math" + "strconv" + + "github.com/volatiletech/null/v8/convert" +) + +// Uint16 is an nullable uint16. +type Uint16 struct { + Uint16 uint16 + Valid bool +} + +// NewUint16 creates a new Uint16 +func NewUint16(i uint16, valid bool) Uint16 { + return Uint16{ + Uint16: i, + Valid: valid, + } +} + +// Uint16From creates a new Uint16 that will always be valid. +func Uint16From(i uint16) Uint16 { + return NewUint16(i, true) +} + +// Uint16FromPtr creates a new Uint16 that be null if i is nil. +func Uint16FromPtr(i *uint16) Uint16 { + if i == nil { + return NewUint16(0, false) + } + return NewUint16(*i, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (u *Uint16) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + u.Valid = false + u.Uint16 = 0 + return nil + } + + var x uint64 + if err := json.Unmarshal(data, &x); err != nil { + return err + } + + if x > math.MaxUint16 { + return fmt.Errorf("json: %d overflows max uint8 value", x) + } + + u.Uint16 = uint16(x) + u.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (u *Uint16) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + u.Valid = false + return nil + } + var err error + res, err := strconv.ParseUint(string(text), 10, 16) + u.Valid = err == nil + if u.Valid { + u.Uint16 = uint16(res) + } + return err +} + +// MarshalJSON implements json.Marshaler. +func (u Uint16) MarshalJSON() ([]byte, error) { + if !u.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatUint(uint64(u.Uint16), 10)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (u Uint16) MarshalText() ([]byte, error) { + if !u.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatUint(uint64(u.Uint16), 10)), nil +} + +// SetValid changes this Uint16's value and also sets it to be non-null. +func (u *Uint16) SetValid(n uint16) { + u.Uint16 = n + u.Valid = true +} + +// Ptr returns a pointer to this Uint16's value, or a nil pointer if this Uint16 is null. +func (u Uint16) Ptr() *uint16 { + if !u.Valid { + return nil + } + return &u.Uint16 +} + +// IsZero returns true for invalid Uint16's, for future omitempty support (Go 1.4?) +func (u Uint16) IsZero() bool { + return !u.Valid +} + +// Scan implements the Scanner interface. +func (u *Uint16) Scan(value interface{}) error { + if value == nil { + u.Uint16, u.Valid = 0, false + return nil + } + u.Valid = true + return convert.ConvertAssign(&u.Uint16, value) +} + +// Value implements the driver Valuer interface. +func (u Uint16) Value() (driver.Value, error) { + if !u.Valid { + return nil, nil + } + return int64(u.Uint16), nil +} + +// Randomize for sqlboiler +func (u *Uint16) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + u.Uint16 = 0 + u.Valid = false + } else { + u.Uint16 = uint16(nextInt() % math.MaxUint16) + u.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/uint32.go b/vendor/github.com/volatiletech/null/v8/uint32.go new file mode 100644 index 000000000..0cc2a96d4 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/uint32.go @@ -0,0 +1,140 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "fmt" + "math" + "strconv" + + "github.com/volatiletech/null/v8/convert" +) + +// Uint32 is an nullable uint32. +type Uint32 struct { + Uint32 uint32 + Valid bool +} + +// NewUint32 creates a new Uint32 +func NewUint32(i uint32, valid bool) Uint32 { + return Uint32{ + Uint32: i, + Valid: valid, + } +} + +// Uint32From creates a new Uint32 that will always be valid. +func Uint32From(i uint32) Uint32 { + return NewUint32(i, true) +} + +// Uint32FromPtr creates a new Uint32 that be null if i is nil. +func Uint32FromPtr(i *uint32) Uint32 { + if i == nil { + return NewUint32(0, false) + } + return NewUint32(*i, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (u *Uint32) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + u.Valid = false + u.Uint32 = 0 + return nil + } + + var x uint64 + if err := json.Unmarshal(data, &x); err != nil { + return err + } + + if x > math.MaxUint32 { + return fmt.Errorf("json: %d overflows max uint32 value", x) + } + + u.Uint32 = uint32(x) + u.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (u *Uint32) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + u.Valid = false + return nil + } + var err error + res, err := strconv.ParseUint(string(text), 10, 32) + u.Valid = err == nil + if u.Valid { + u.Uint32 = uint32(res) + } + return err +} + +// MarshalJSON implements json.Marshaler. +func (u Uint32) MarshalJSON() ([]byte, error) { + if !u.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatUint(uint64(u.Uint32), 10)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (u Uint32) MarshalText() ([]byte, error) { + if !u.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatUint(uint64(u.Uint32), 10)), nil +} + +// SetValid changes this Uint32's value and also sets it to be non-null. +func (u *Uint32) SetValid(n uint32) { + u.Uint32 = n + u.Valid = true +} + +// Ptr returns a pointer to this Uint32's value, or a nil pointer if this Uint32 is null. +func (u Uint32) Ptr() *uint32 { + if !u.Valid { + return nil + } + return &u.Uint32 +} + +// IsZero returns true for invalid Uint32's, for future omitempty support (Go 1.4?) +func (u Uint32) IsZero() bool { + return !u.Valid +} + +// Scan implements the Scanner interface. +func (u *Uint32) Scan(value interface{}) error { + if value == nil { + u.Uint32, u.Valid = 0, false + return nil + } + u.Valid = true + return convert.ConvertAssign(&u.Uint32, value) +} + +// Value implements the driver Valuer interface. +func (u Uint32) Value() (driver.Value, error) { + if !u.Valid { + return nil, nil + } + return int64(u.Uint32), nil +} + +// Randomize for sqlboiler +func (u *Uint32) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + u.Uint32 = 0 + u.Valid = false + } else { + u.Uint32 = uint32(nextInt() % math.MaxUint32) + u.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/uint64.go b/vendor/github.com/volatiletech/null/v8/uint64.go new file mode 100644 index 000000000..a9ff8cfc7 --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/uint64.go @@ -0,0 +1,144 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "strconv" + + "github.com/volatiletech/null/v8/convert" +) + +// Uint64 is an nullable uint64. +type Uint64 struct { + Uint64 uint64 + Valid bool +} + +// NewUint64 creates a new Uint64 +func NewUint64(i uint64, valid bool) Uint64 { + return Uint64{ + Uint64: i, + Valid: valid, + } +} + +// Uint64From creates a new Uint64 that will always be valid. +func Uint64From(i uint64) Uint64 { + return NewUint64(i, true) +} + +// Uint64FromPtr creates a new Uint64 that be null if i is nil. +func Uint64FromPtr(i *uint64) Uint64 { + if i == nil { + return NewUint64(0, false) + } + return NewUint64(*i, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (u *Uint64) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + u.Uint64 = 0 + u.Valid = false + return nil + } + + if err := json.Unmarshal(data, &u.Uint64); err != nil { + return err + } + + u.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (u *Uint64) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + u.Valid = false + return nil + } + var err error + res, err := strconv.ParseUint(string(text), 10, 64) + u.Valid = err == nil + if u.Valid { + u.Uint64 = uint64(res) + } + return err +} + +// MarshalJSON implements json.Marshaler. +func (u Uint64) MarshalJSON() ([]byte, error) { + if !u.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatUint(u.Uint64, 10)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (u Uint64) MarshalText() ([]byte, error) { + if !u.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatUint(u.Uint64, 10)), nil +} + +// SetValid changes this Uint64's value and also sets it to be non-null. +func (u *Uint64) SetValid(n uint64) { + u.Uint64 = n + u.Valid = true +} + +// Ptr returns a pointer to this Uint64's value, or a nil pointer if this Uint64 is null. +func (u Uint64) Ptr() *uint64 { + if !u.Valid { + return nil + } + return &u.Uint64 +} + +// IsZero returns true for invalid Uint64's, for future omitempty support (Go 1.4?) +func (u Uint64) IsZero() bool { + return !u.Valid +} + +// Scan implements the Scanner interface. +func (u *Uint64) Scan(value interface{}) error { + if value == nil { + u.Uint64, u.Valid = 0, false + return nil + } + u.Valid = true + + // If value is negative int64, convert it to uint64 + if i, ok := value.(int64); ok && i < 0 { + return convert.ConvertAssign(&u.Uint64, uint64(i)) + } + + return convert.ConvertAssign(&u.Uint64, value) +} + +// Value implements the driver Valuer interface. +func (u Uint64) Value() (driver.Value, error) { + if !u.Valid { + return nil, nil + } + + // If u.Uint64 overflows the range of int64, convert it to string + if u.Uint64 >= 1<<63 { + return strconv.FormatUint(u.Uint64, 10), nil + } + + return int64(u.Uint64), nil +} + +// Randomize for sqlboiler +func (u *Uint64) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + u.Uint64 = 0 + u.Valid = false + } else { + u.Uint64 = uint64(nextInt()) + u.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/null/v8/uint8.go b/vendor/github.com/volatiletech/null/v8/uint8.go new file mode 100644 index 000000000..0d46c477c --- /dev/null +++ b/vendor/github.com/volatiletech/null/v8/uint8.go @@ -0,0 +1,140 @@ +package null + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "fmt" + "math" + "strconv" + + "github.com/volatiletech/null/v8/convert" +) + +// Uint8 is an nullable uint8. +type Uint8 struct { + Uint8 uint8 + Valid bool +} + +// NewUint8 creates a new Uint8 +func NewUint8(i uint8, valid bool) Uint8 { + return Uint8{ + Uint8: i, + Valid: valid, + } +} + +// Uint8From creates a new Uint8 that will always be valid. +func Uint8From(i uint8) Uint8 { + return NewUint8(i, true) +} + +// Uint8FromPtr creates a new Uint8 that be null if i is nil. +func Uint8FromPtr(i *uint8) Uint8 { + if i == nil { + return NewUint8(0, false) + } + return NewUint8(*i, true) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (u *Uint8) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, NullBytes) { + u.Valid = false + u.Uint8 = 0 + return nil + } + + var x uint64 + if err := json.Unmarshal(data, &x); err != nil { + return err + } + + if x > math.MaxUint8 { + return fmt.Errorf("json: %d overflows max uint8 value", x) + } + + u.Uint8 = uint8(x) + u.Valid = true + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (u *Uint8) UnmarshalText(text []byte) error { + if text == nil || len(text) == 0 { + u.Valid = false + return nil + } + var err error + res, err := strconv.ParseUint(string(text), 10, 8) + u.Valid = err == nil + if u.Valid { + u.Uint8 = uint8(res) + } + return err +} + +// MarshalJSON implements json.Marshaler. +func (u Uint8) MarshalJSON() ([]byte, error) { + if !u.Valid { + return NullBytes, nil + } + return []byte(strconv.FormatUint(uint64(u.Uint8), 10)), nil +} + +// MarshalText implements encoding.TextMarshaler. +func (u Uint8) MarshalText() ([]byte, error) { + if !u.Valid { + return []byte{}, nil + } + return []byte(strconv.FormatUint(uint64(u.Uint8), 10)), nil +} + +// SetValid changes this Uint8's value and also sets it to be non-null. +func (u *Uint8) SetValid(n uint8) { + u.Uint8 = n + u.Valid = true +} + +// Ptr returns a pointer to this Uint8's value, or a nil pointer if this Uint8 is null. +func (u Uint8) Ptr() *uint8 { + if !u.Valid { + return nil + } + return &u.Uint8 +} + +// IsZero returns true for invalid Uint8's, for future omitempty support (Go 1.4?) +func (u Uint8) IsZero() bool { + return !u.Valid +} + +// Scan implements the Scanner interface. +func (u *Uint8) Scan(value interface{}) error { + if value == nil { + u.Uint8, u.Valid = 0, false + return nil + } + u.Valid = true + return convert.ConvertAssign(&u.Uint8, value) +} + +// Value implements the driver Valuer interface. +func (u Uint8) Value() (driver.Value, error) { + if !u.Valid { + return nil, nil + } + return int64(u.Uint8), nil +} + +// Randomize for sqlboiler +func (u *Uint8) Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) { + if shouldBeNull { + u.Uint8 = 0 + u.Valid = false + } else { + u.Uint8 = uint8(nextInt() % math.MaxUint8) + u.Valid = true + } +} diff --git a/vendor/github.com/volatiletech/randomize/LICENSE b/vendor/github.com/volatiletech/randomize/LICENSE new file mode 100644 index 000000000..99344d84f --- /dev/null +++ b/vendor/github.com/volatiletech/randomize/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2020 Volatile Technologies Inc. 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 Vattle or Volatile Technologies 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/github.com/volatiletech/randomize/random.go b/vendor/github.com/volatiletech/randomize/random.go new file mode 100644 index 000000000..119e19e2a --- /dev/null +++ b/vendor/github.com/volatiletech/randomize/random.go @@ -0,0 +1,203 @@ +package randomize + +import ( + "crypto/md5" + "fmt" + "math/rand" + "strconv" + "strings" + "time" + + "github.com/gofrs/uuid" + "github.com/volatiletech/strmangle" +) + +const alphabetAll = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +const alphabetLowerAlpha = "abcdefghijklmnopqrstuvwxyz" + +// Str creates a randomized string from printable characters in the alphabet +func Str(nextInt func() int64, ln int) string { + str := make([]byte, ln) + for i := 0; i < ln; i++ { + str[i] = byte(alphabetAll[nextInt()%int64(len(alphabetAll))]) + } + + return string(str) +} + +// FormattedString checks a field type to see if it's in a range of special +// values and if so returns a randomized string for it. +func FormattedString(nextInt func() int64, fieldType string) (string, bool) { + if strings.HasPrefix(fieldType, "enum") { + enum, err := EnumValue(nextInt, fieldType) + if err != nil { + panic(err) + } + + return enum, true + } + + switch fieldType { + case "json", "jsonb": + return `"` + Str(nextInt, 1) + `"`, true + case "interval": + return strconv.Itoa((int(nextInt())%26)+2) + " days", true + case "uuid": + randomUUID, err := uuid.NewV4() + if err != nil { + panic(err) + } + return randomUUID.String(), true + case "cidr", "inet": + return randNetAddr(nextInt), true + case "macaddr": + return randMacAddr(nextInt), true + case "pg_lsn": + return randLsn(nextInt), true + case "txid_snapshot": + return randTxID(nextInt), true + case "money": + return randMoney(nextInt), true + case "time": + return randTime(nextInt), true + } + + return "", false +} + +// MediumInt is a special case in mysql (thanks for that -_-) +// this function checks if the fieldtype matches and if so returns +// a random value in the proper range. +func MediumInt(nextInt func() int64, fieldType string) (int32, bool) { + if fieldType == "mediumint" { + return int32(nextInt()) % 8388607, true + } + + return 0, false +} + +// MediumUint is the unsigned version of MediumInt +func MediumUint(nextInt func() int64, fieldType string) (uint32, bool) { + fmt.Println(fieldType) + if fieldType == "mediumint" { + return uint32(nextInt()) % 16777215, true + } + + return 0, false +} + +// Date generates a random time.Time between 1850 and 2050. +// Only the Day/Month/Year columns are set so that Dates and DateTimes do +// not cause mismatches in the test data comparisons. +func Date(nextInt func() int64) time.Time { + t := time.Date( + int(1972+nextInt()%60), + time.Month(1+(nextInt()%12)), + int(1+(nextInt()%25)), + 0, + 0, + 0, + 0, + time.UTC, + ) + + return t +} + +// EnumValue takes an enum field type, parses it's definition +// to figure out valid values, and selects a random one from within them. +func EnumValue(nextInt func() int64, enum string) (string, error) { + vals := strmangle.ParseEnumVals(enum) + if vals == nil || len(vals) == 0 { + return "", fmt.Errorf("unable to parse enum string: %s", enum) + } + + return vals[int(nextInt())%len(vals)], nil +} + +// ByteSlice creates a random set of bytes (non-printables included) +func ByteSlice(nextInt func() int64, ln int) []byte { + str := make([]byte, ln) + for i := 0; i < ln; i++ { + str[i] = byte(nextInt() % 256) + } + + return str +} + +func randNetAddr(nextInt func() int64) string { + return fmt.Sprintf( + "%d.%d.%d.%d", + nextInt()%254+1, + nextInt()%254+1, + nextInt()%254+1, + nextInt()%254+1, + ) +} + +func randMacAddr(nextInt func() int64) string { + buf := make([]byte, 6) + for i := range buf { + buf[i] = byte(nextInt()) + } + + // Set the local bit + buf[0] |= 2 + return fmt.Sprintf( + "%02x:%02x:%02x:%02x:%02x:%02x", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + ) +} + +func randLsn(nextInt func() int64) string { + a := nextInt() % 9000000 + b := nextInt() % 9000000 + return fmt.Sprintf("%d/%d", a, b) +} + +func randTxID(nextInt func() int64) string { + // Order of integers is relevant + a := nextInt()%200 + 100 + b := a + 100 + c := a + d := a + 50 + return fmt.Sprintf("%d:%d:%d,%d", a, b, c, d) +} + +func randMoney(nextInt func() int64) string { + return fmt.Sprintf("%d.00", nextInt()%100000) +} + +func randTime(nextInt func() int64) string { + return fmt.Sprintf("%d:%d:%d", nextInt()%24, nextInt()%60, nextInt()%60) +} + +// StableDBName takes a database name in, and generates +// a random string using the database name as the rand Seed. +// getDBNameHash is used to generate unique test database names. +func StableDBName(input string) string { + return randStrFromSource(stableSource(input), 40) +} + +// stableSource takes an input value, and produces a random +// seed from it that will produce very few collisions in +// a 40 character random string made from a different alphabet. +func stableSource(input string) *rand.Rand { + sum := md5.Sum([]byte(input)) + var seed int64 + for i, byt := range sum { + seed ^= int64(byt) << uint((i*4)%64) + } + return rand.New(rand.NewSource(seed)) +} + +func randStrFromSource(r *rand.Rand, length int) string { + ln := len(alphabetLowerAlpha) + + output := make([]rune, length) + for i := 0; i < length; i++ { + output[i] = rune(alphabetLowerAlpha[r.Intn(ln)]) + } + + return string(output) +} diff --git a/vendor/github.com/volatiletech/randomize/randomize.go b/vendor/github.com/volatiletech/randomize/randomize.go new file mode 100644 index 000000000..f5b3be58c --- /dev/null +++ b/vendor/github.com/volatiletech/randomize/randomize.go @@ -0,0 +1,292 @@ +// Package randomize has helpers for randomization of structs and fields +package randomize + +import ( + "math" + "reflect" + "regexp" + "sort" + "sync/atomic" + "time" + + "github.com/friendsofgo/errors" + "github.com/volatiletech/strmangle" +) + +// Randomizer allows a field to be randomized +type Randomizer interface { + // Randomize should panic if there's no ability to randomize with the current parameters. + // + // nextInt can be called to create "random" sequential integers. This is done to avoid collisions in unique columns + // for the tests. + // + // fieldType is used in the cases where the actual type (string, null string etc.) can actually be multiple + // types of things that have specific randomization requirements, like a uuid for example is a normal null.String + // but when randomizing that null string it must create a valid uuid or the database will reject it. + // + // shouldBeNull is a suggestion that a field should be null in this instance. The randomize implementation + // can ignore this if the field cannot be null either because the type doesn't support it or there + // is no ability for a field of this type to be null. + Randomize(nextInt func() int64, fieldType string, shouldBeNull bool) +} + +var ( + typeTime = reflect.TypeOf(time.Time{}) + rgxValidTime = regexp.MustCompile(`[2-9]+`) +) + +// Seed is an atomic counter for pseudo-randomization structs. Using full +// randomization leads to collisions in a domain where uniqueness is an +// important factor. +type Seed int64 + +// NewSeed creates a new seed for pseudo-randomization. +func NewSeed() *Seed { + s := new(int64) + *s = time.Now().Unix() + return (*Seed)(s) +} + +// NextInt retrives an integer in order +func (s *Seed) NextInt() int64 { + return atomic.AddInt64((*int64)(s), 1) +} + +// Struct gets its fields filled with random data based on the seed. +// It will ignore the fields in the blacklist. +// It will ignore fields that have the struct tag boil:"-" +func Struct(s *Seed, str interface{}, colTypes map[string]string, canBeNull bool, blacklist ...string) error { + // Don't modify blacklist + copyBlacklist := make([]string, len(blacklist)) + copy(copyBlacklist, blacklist) + blacklist = copyBlacklist + blacklist = append(blacklist, "deleted_at") + + sort.Strings(blacklist) + + // Check if it's pointer + value := reflect.ValueOf(str) + kind := value.Kind() + if kind != reflect.Ptr { + return errors.Errorf("Outer element should be a pointer, given a non-pointer: %T", str) + } + + // Check if it's a struct + value = value.Elem() + kind = value.Kind() + if kind != reflect.Struct { + return errors.Errorf("Inner element should be a struct, given a non-struct: %T", str) + } + + typ := value.Type() + nFields := value.NumField() + + // Iterate through fields, randomizing + for i := 0; i < nFields; i++ { + fieldVal := value.Field(i) + fieldTyp := typ.Field(i) + + var found bool + for _, v := range blacklist { + if strmangle.TitleCase(v) == fieldTyp.Name || v == fieldTyp.Tag.Get("boil") { + found = true + break + } + } + + if found { + continue + } + + if fieldTyp.Tag.Get("boil") == "-" { + continue + } + + fieldDBType := colTypes[fieldTyp.Name] + if err := randomizeField(s, fieldVal, fieldDBType, canBeNull); err != nil { + return err + } + } + + return nil +} + +// randomizeField changes the value at field to a "randomized" value. +// +// If canBeNull is false: +// The value will always be a non-null and non-zero value. +// +// If canBeNull is true: +// The value has the possibility of being null or a non-zero value at random. +func randomizeField(s *Seed, field reflect.Value, fieldType string, canBeNull bool) error { + kind := field.Kind() + typ := field.Type() + + var shouldBeNull bool + // Check the regular columns, these can be set or not set + // depending on the canBeNull flag. + // if canBeNull is false, then never return null values. + if canBeNull { + // 1 in 3 chance of being null or zero value + shouldBeNull = s.NextInt()%3 == 0 + } + + // The struct and it's fields should always be addressable + ptrToField := field.Addr() + if r, ok := ptrToField.Interface().(Randomizer); ok { + r.Randomize(s.NextInt, fieldType, shouldBeNull) + return nil + } + + var value interface{} + + if kind == reflect.Struct { + if shouldBeNull { + value = getStructNullValue(s, fieldType, typ) + } else { + value = getStructRandValue(s, fieldType, typ) + } + } else { + // only get zero values for non byte slices + // to stop mysql from being a jerk + if shouldBeNull && kind != reflect.Slice { + value = getVariableZeroValue(s, fieldType, kind, typ) + } else { + value = getVariableRandValue(s, fieldType, kind, typ) + } + } + + if value == nil { + return errors.Errorf("unsupported type: %s", typ.String()) + } + + newValue := reflect.ValueOf(value) + if reflect.TypeOf(value) != typ { + newValue = newValue.Convert(typ) + } + + field.Set(newValue) + + return nil +} + +// getStructNullValue for the matching type. +func getStructNullValue(s *Seed, fieldType string, typ reflect.Type) interface{} { + if typ == typeTime { + // MySQL does not support 0 value time.Time, so use rand + return Date(s.NextInt) + } + + return nil +} + +// getStructRandValue returns a "random" value for the matching type. +// The randomness is really an incrementation of the global seed, +// this is done to avoid duplicate key violations. +func getStructRandValue(s *Seed, fieldType string, typ reflect.Type) interface{} { + if typ == typeTime { + return Date(s.NextInt) + } + + return nil +} + +// getVariableZeroValue for the matching type. +func getVariableZeroValue(s *Seed, fieldType string, kind reflect.Kind, typ reflect.Type) interface{} { + switch kind { + case reflect.Float32: + return float32(0) + case reflect.Float64: + return float64(0) + case reflect.Int: + return int(0) + case reflect.Int8: + return int8(0) + case reflect.Int16: + return int16(0) + case reflect.Int32: + return int32(0) + case reflect.Int64: + return int64(0) + case reflect.Uint: + return uint(0) + case reflect.Uint8: + return uint8(0) + case reflect.Uint16: + return uint16(0) + case reflect.Uint32: + return uint32(0) + case reflect.Uint64: + return uint64(0) + case reflect.Bool: + return false + case reflect.String: + // Some of these formatted strings cannot tolerate 0 values, so + // we ignore the request for a null value. + str, ok := FormattedString(s.NextInt, fieldType) + if ok { + return str + } + return "" + case reflect.Slice: + return []byte{} + } + + return nil +} + +// getVariableRandValue returns a "random" value for the matching kind. +// The randomness is really an incrementation of the global seed, +// this is done to avoid duplicate key violations. +func getVariableRandValue(s *Seed, fieldType string, kind reflect.Kind, typ reflect.Type) interface{} { + switch kind { + case reflect.Float32: + return float32(float32(s.NextInt()%10)/10.0 + float32(s.NextInt()%10)) + case reflect.Float64: + return float64(float64(s.NextInt()%10)/10.0 + float64(s.NextInt()%10)) + case reflect.Int: + return int(s.NextInt()) + case reflect.Int8: + return int8(s.NextInt() % math.MaxInt8) + case reflect.Int16: + return int16(s.NextInt() % math.MaxInt16) + case reflect.Int32: + val, ok := MediumInt(s.NextInt, fieldType) + if ok { + return val + } + return int32(s.NextInt() % math.MaxInt32) + case reflect.Int64: + return int64(s.NextInt()) + case reflect.Uint: + return uint(s.NextInt()) + case reflect.Uint8: + return uint8(s.NextInt() % math.MaxUint8) + case reflect.Uint16: + return uint16(s.NextInt() % math.MaxUint16) + case reflect.Uint32: + val, ok := MediumUint(s.NextInt, fieldType) + if ok { + return val + } + return uint32(s.NextInt() % math.MaxUint32) + case reflect.Uint64: + return uint64(s.NextInt()) + case reflect.Bool: + return true + case reflect.String: + str, ok := FormattedString(s.NextInt, fieldType) + if ok { + return str + } + return Str(s.NextInt, 1) + case reflect.Slice: + sliceVal := typ.Elem() + if sliceVal.Kind() != reflect.Uint8 { + return errors.Errorf("unsupported slice type: %T, was expecting byte slice.", typ.String()) + } + return ByteSlice(s.NextInt, 1) + } + + return nil +} diff --git a/vendor/github.com/volatiletech/strmangle/LICENSE b/vendor/github.com/volatiletech/strmangle/LICENSE new file mode 100644 index 000000000..99344d84f --- /dev/null +++ b/vendor/github.com/volatiletech/strmangle/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2020 Volatile Technologies Inc. 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 Vattle or Volatile Technologies 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/github.com/volatiletech/strmangle/buf_pool.go b/vendor/github.com/volatiletech/strmangle/buf_pool.go new file mode 100644 index 000000000..750568c29 --- /dev/null +++ b/vendor/github.com/volatiletech/strmangle/buf_pool.go @@ -0,0 +1,27 @@ +package strmangle + +import ( + "bytes" + "sync" +) + +var bufPool = sync.Pool{ + New: newBuffer, +} + +func newBuffer() interface{} { + return &bytes.Buffer{} +} + +// GetBuffer retrieves a buffer from the buffer pool +func GetBuffer() *bytes.Buffer { + buf := bufPool.Get().(*bytes.Buffer) + buf.Reset() + + return buf +} + +// PutBuffer back into the buffer pool +func PutBuffer(buf *bytes.Buffer) { + bufPool.Put(buf) +} diff --git a/vendor/github.com/volatiletech/strmangle/inflect.go b/vendor/github.com/volatiletech/strmangle/inflect.go new file mode 100644 index 000000000..556135cc4 --- /dev/null +++ b/vendor/github.com/volatiletech/strmangle/inflect.go @@ -0,0 +1,205 @@ +package strmangle + +import "github.com/volatiletech/inflect" + +var boilRuleset *inflect.Ruleset + +// create a new ruleset and load it with the default +// set of common English pluralization rules +func newBoilRuleset() *inflect.Ruleset { + rs := inflect.NewRuleset() + rs.AddPlural("s", "s") + rs.AddPlural("testis", "testes") + rs.AddPlural("axis", "axes") + rs.AddPlural("octopus", "octopi") + rs.AddPlural("virus", "viri") + rs.AddPlural("octopi", "octopi") + rs.AddPlural("viri", "viri") + rs.AddPlural("alias", "aliases") + rs.AddPlural("status", "statuses") + rs.AddPlural("bus", "buses") + rs.AddPlural("buffalo", "buffaloes") + rs.AddPlural("tomato", "tomatoes") + rs.AddPlural("tum", "ta") + rs.AddPlural("ium", "ia") + rs.AddPlural("ta", "ta") + rs.AddPlural("ia", "ia") + rs.AddPlural("sis", "ses") + rs.AddPlural("lf", "lves") + rs.AddPlural("rf", "rves") + rs.AddPlural("afe", "aves") + rs.AddPlural("bfe", "bves") + rs.AddPlural("cfe", "cves") + rs.AddPlural("dfe", "dves") + rs.AddPlural("efe", "eves") + rs.AddPlural("gfe", "gves") + rs.AddPlural("hfe", "hves") + rs.AddPlural("ife", "ives") + rs.AddPlural("jfe", "jves") + rs.AddPlural("kfe", "kves") + rs.AddPlural("lfe", "lves") + rs.AddPlural("mfe", "mves") + rs.AddPlural("nfe", "nves") + rs.AddPlural("ofe", "oves") + rs.AddPlural("pfe", "pves") + rs.AddPlural("qfe", "qves") + rs.AddPlural("rfe", "rves") + rs.AddPlural("sfe", "sves") + rs.AddPlural("tfe", "tves") + rs.AddPlural("ufe", "uves") + rs.AddPlural("vfe", "vves") + rs.AddPlural("wfe", "wves") + rs.AddPlural("xfe", "xves") + rs.AddPlural("yfe", "yves") + rs.AddPlural("zfe", "zves") + rs.AddPlural("hive", "hives") + rs.AddPlural("quy", "quies") + rs.AddPlural("by", "bies") + rs.AddPlural("cy", "cies") + rs.AddPlural("dy", "dies") + rs.AddPlural("fy", "fies") + rs.AddPlural("gy", "gies") + rs.AddPlural("hy", "hies") + rs.AddPlural("jy", "jies") + rs.AddPlural("ky", "kies") + rs.AddPlural("ly", "lies") + rs.AddPlural("my", "mies") + rs.AddPlural("ny", "nies") + rs.AddPlural("py", "pies") + rs.AddPlural("qy", "qies") + rs.AddPlural("ry", "ries") + rs.AddPlural("sy", "sies") + rs.AddPlural("ty", "ties") + rs.AddPlural("vy", "vies") + rs.AddPlural("wy", "wies") + rs.AddPlural("xy", "xies") + rs.AddPlural("zy", "zies") + rs.AddPlural("x", "xes") + rs.AddPlural("ch", "ches") + rs.AddPlural("ss", "sses") + rs.AddPlural("sh", "shes") + rs.AddPlural("matrix", "matrices") + rs.AddPlural("vertix", "vertices") + rs.AddPlural("indix", "indices") + rs.AddPlural("matrex", "matrices") + rs.AddPlural("vertex", "vertices") + rs.AddPlural("index", "indices") + rs.AddPlural("mouse", "mice") + rs.AddPlural("louse", "lice") + rs.AddPlural("mice", "mice") + rs.AddPlural("lice", "lice") + rs.AddPluralExact("ox", "oxen", true) + rs.AddPluralExact("oxen", "oxen", true) + rs.AddPluralExact("quiz", "quizzes", true) + rs.AddSingular("s", "") + rs.AddSingular("ss", "ss") + rs.AddSingular("as", "as") + rs.AddSingular("us", "us") + rs.AddSingular("is", "is") + rs.AddSingular("schemas", "schema") + rs.AddSingular("news", "news") + rs.AddSingular("ta", "tum") + rs.AddSingular("ia", "ium") + rs.AddSingular("analyses", "analysis") + rs.AddSingular("bases", "basis") + rs.AddSingular("diagnoses", "diagnosis") + rs.AddSingular("parentheses", "parenthesis") + rs.AddSingular("prognoses", "prognosis") + rs.AddSingular("synopses", "synopsis") + rs.AddSingular("theses", "thesis") + rs.AddSingular("analyses", "analysis") + rs.AddSingular("aves", "afe") + rs.AddSingular("bves", "bfe") + rs.AddSingular("cves", "cfe") + rs.AddSingular("dves", "dfe") + rs.AddSingular("eves", "efe") + rs.AddSingular("gves", "gfe") + rs.AddSingular("hves", "hfe") + rs.AddSingular("ives", "ife") + rs.AddSingular("jves", "jfe") + rs.AddSingular("kves", "kfe") + rs.AddSingular("lves", "lfe") + rs.AddSingular("mves", "mfe") + rs.AddSingular("nves", "nfe") + rs.AddSingular("oves", "ofe") + rs.AddSingular("pves", "pfe") + rs.AddSingular("qves", "qfe") + rs.AddSingular("rves", "rfe") + rs.AddSingular("sves", "sfe") + rs.AddSingular("tves", "tfe") + rs.AddSingular("uves", "ufe") + rs.AddSingular("vves", "vfe") + rs.AddSingular("wves", "wfe") + rs.AddSingular("xves", "xfe") + rs.AddSingular("yves", "yfe") + rs.AddSingular("zves", "zfe") + rs.AddSingular("hives", "hive") + rs.AddSingular("tives", "tive") + rs.AddSingular("lves", "lf") + rs.AddSingular("rves", "rf") + rs.AddSingular("quies", "quy") + rs.AddSingular("bies", "by") + rs.AddSingular("cies", "cy") + rs.AddSingular("dies", "dy") + rs.AddSingular("fies", "fy") + rs.AddSingular("gies", "gy") + rs.AddSingular("hies", "hy") + rs.AddSingular("jies", "jy") + rs.AddSingular("kies", "ky") + rs.AddSingular("lies", "ly") + rs.AddSingular("mies", "my") + rs.AddSingular("nies", "ny") + rs.AddSingular("pies", "py") + rs.AddSingular("qies", "qy") + rs.AddSingular("ries", "ry") + rs.AddSingular("sies", "sy") + rs.AddSingular("ties", "ty") + rs.AddSingular("vies", "vy") + rs.AddSingular("wies", "wy") + rs.AddSingular("xies", "xy") + rs.AddSingular("zies", "zy") + rs.AddSingular("series", "series") + rs.AddSingular("movies", "movie") + rs.AddSingular("xes", "x") + rs.AddSingular("ches", "ch") + rs.AddSingular("sses", "ss") + rs.AddSingular("shes", "sh") + rs.AddSingular("mice", "mouse") + rs.AddSingular("lice", "louse") + rs.AddSingular("buses", "bus") + rs.AddSingular("oes", "o") + rs.AddSingular("shoes", "shoe") + rs.AddSingular("crises", "crisis") + rs.AddSingular("axes", "axis") + rs.AddSingular("testes", "testis") + rs.AddSingular("octopi", "octopus") + rs.AddSingular("viri", "virus") + rs.AddSingular("statuses", "status") + rs.AddSingular("aliases", "alias") + rs.AddSingularExact("oxen", "ox", true) + rs.AddSingular("vertices", "vertex") + rs.AddSingular("indices", "index") + rs.AddSingular("matrices", "matrix") + rs.AddSingularExact("quizzes", "quiz", true) + rs.AddSingular("databases", "database") + rs.AddSingular("menus", "menu") + rs.AddIrregular("person", "people") + rs.AddIrregular("man", "men") + rs.AddIrregular("child", "children") + rs.AddIrregular("sex", "sexes") + rs.AddIrregular("move", "moves") + rs.AddIrregular("zombie", "zombies") + rs.AddIrregular("cookie", "cookies") + rs.AddSingularExact("a", "a", true) + rs.AddSingularExact("i", "i", true) + rs.AddSingularExact("is", "is", true) + rs.AddSingularExact("us", "us", true) + rs.AddSingularExact("as", "as", true) + rs.AddSingularExact("areas", "area", true) + rs.AddPluralExact("a", "a", true) + rs.AddPluralExact("i", "i", true) + rs.AddPluralExact("is", "is", true) + rs.AddPluralExact("us", "us", true) + rs.AddPluralExact("as", "as", true) + return rs +} diff --git a/vendor/github.com/volatiletech/strmangle/sets.go b/vendor/github.com/volatiletech/strmangle/sets.go new file mode 100644 index 000000000..db8bee1a5 --- /dev/null +++ b/vendor/github.com/volatiletech/strmangle/sets.go @@ -0,0 +1,90 @@ +package strmangle + +// SetInclude checks to see if the string is found in the string slice +func SetInclude(str string, slice []string) bool { + for _, s := range slice { + if str == s { + return true + } + } + + return false +} + +// SetComplement subtracts the elements in b from a +func SetComplement(a []string, b []string) []string { + c := make([]string, 0, len(a)) + + for _, aVal := range a { + found := false + for _, bVal := range b { + if aVal == bVal { + found = true + break + } + } + if !found { + c = append(c, aVal) + } + } + + return c +} + +// SetMerge will return a merged slice without duplicates +func SetMerge(a []string, b []string) []string { + merged := make([]string, 0, len(a)+len(b)) + + for _, aVal := range a { + found := false + for _, mVal := range merged { + if aVal == mVal { + found = true + break + } + } + + if !found { + merged = append(merged, aVal) + } + } + + for _, bVal := range b { + found := false + for _, mVal := range merged { + if bVal == mVal { + found = true + break + } + } + + if !found { + merged = append(merged, bVal) + } + } + + return merged +} + +// SortByKeys returns a new ordered slice based on the keys ordering +func SortByKeys(keys []string, strs []string) []string { + c := make([]string, len(strs)) + + index := 0 +Outer: + for _, v := range keys { + for _, k := range strs { + if v == k { + c[index] = v + index++ + + if index > len(strs)-1 { + break Outer + } + break + } + } + } + + return c +} diff --git a/vendor/github.com/volatiletech/strmangle/strmangle.go b/vendor/github.com/volatiletech/strmangle/strmangle.go new file mode 100644 index 000000000..e7967bc69 --- /dev/null +++ b/vendor/github.com/volatiletech/strmangle/strmangle.go @@ -0,0 +1,744 @@ +// Package strmangle is a collection of string manipulation functions. +// Primarily used by boil and templates for code generation. +// Because it is focused on pipelining inside templates +// you will see some odd parameter ordering. +package strmangle + +import ( + "fmt" + "math" + "regexp" + "sort" + "strings" + "sync" +) + +var ( + idAlphabet = []byte("abcdefghijklmnopqrstuvwxyz") + smartQuoteRgx = regexp.MustCompile(`^(?i)"?[a-z_][_a-z0-9\-]*"?(\."?[_a-z][_a-z0-9]*"?)*(\.\*)?$`) + + rgxEnum = regexp.MustCompile(`^enum(\.[a-zA-Z0-9_]+)?\((,?'[^']+')+\)$`) + rgxEnumIsOK = regexp.MustCompile(`^(?i)[a-z][a-z0-9_\s]*$`) + rgxEnumShouldTitle = regexp.MustCompile(`^[a-z][a-zA-Z0-9_]*$`) + rgxWhitespace = regexp.MustCompile(`\s`) +) + +var uppercaseWords = map[string]struct{}{ + "acl": {}, + "api": {}, + "ascii": {}, + "cpu": {}, + "eof": {}, + "guid": {}, + "id": {}, + "ip": {}, + "json": {}, + "ram": {}, + "sla": {}, + "udp": {}, + "ui": {}, + "uid": {}, + "uuid": {}, + "uri": {}, + "url": {}, + "utf8": {}, +} + +var reservedWords = map[string]struct{}{ + "break": {}, + "case": {}, + "chan": {}, + "const": {}, + "continue": {}, + "default": {}, + "defer": {}, + "else": {}, + "fallthrough": {}, + "for": {}, + "func": {}, + "go": {}, + "goto": {}, + "if": {}, + "import": {}, + "interface": {}, + "map": {}, + "package": {}, + "range": {}, + "return": {}, + "select": {}, + "struct": {}, + "switch": {}, + "type": {}, + "var": {}, +} + +func init() { + // Our Boil inflection Ruleset does not include uncountable inflections. + // This way, people using words like Sheep will not have + // collisions with their model name (Sheep) and their + // function name (Sheep()). Instead, it will + // use the regular inflection rules: Sheep, Sheeps(). + boilRuleset = newBoilRuleset() +} + +// SchemaTable returns a table name with a schema prefixed if +// using a database that supports real schemas, for example, +// for Postgres: "schema_name"."table_name", +// for MS SQL: [schema_name].[table_name], versus +// simply "table_name" for MySQL (because it does not support real schemas) +func SchemaTable(lq, rq string, useSchema bool, schema string, table string) string { + if useSchema { + return fmt.Sprintf(`%s%s%s.%s%s%s`, lq, schema, rq, lq, table, rq) + } + + return fmt.Sprintf(`%s%s%s`, lq, table, rq) +} + +// IdentQuote attempts to quote simple identifiers in SQL statements +func IdentQuote(lq rune, rq rune, s string) string { + if strings.EqualFold(s, "null") || s == "?" { + return s + } + + if m := smartQuoteRgx.MatchString(s); m != true { + return s + } + + buf := GetBuffer() + defer PutBuffer(buf) + + splits := strings.Split(s, ".") + for i, split := range splits { + if i != 0 { + buf.WriteByte('.') + } + + if rune(split[0]) == lq || rune(split[len(split)-1]) == rq || split == "*" { + buf.WriteString(split) + continue + } + + buf.WriteRune(lq) + buf.WriteString(split) + buf.WriteRune(rq) + } + + return buf.String() +} + +// IdentQuoteSlice applies IdentQuote to a slice. +func IdentQuoteSlice(lq rune, rq rune, s []string) []string { + if len(s) == 0 { + return s + } + + strs := make([]string, len(s)) + for i, str := range s { + strs[i] = IdentQuote(lq, rq, str) + } + + return strs +} + +// Identifier is a base conversion from Base 10 integers to Base 26 +// integers that are represented by an alphabet from a-z +// See tests for example outputs. +func Identifier(in int) string { + ln := len(idAlphabet) + var n int + if in == 0 { + n = 1 + } else { + n = 1 + int(math.Log(float64(in))/math.Log(float64(ln))) + } + + cols := GetBuffer() + defer PutBuffer(cols) + + for i := 0; i < n; i++ { + divisor := int(math.Pow(float64(ln), float64(n-i-1))) + rem := in / divisor + cols.WriteByte(idAlphabet[rem]) + + in -= rem * divisor + } + + return cols.String() +} + +// QuoteCharacter returns a string that allows the quote character +// to be embedded into a Go string that uses double quotes: +func QuoteCharacter(q rune) string { + if q == '"' { + return `\"` + } + + return string(q) +} + +// Plural converts singular words to plural words (eg: person to people) +func Plural(name string) string { + buf := GetBuffer() + defer PutBuffer(buf) + + splits := strings.Split(name, "_") + + for i := 0; i < len(splits); i++ { + if i != 0 { + buf.WriteByte('_') + } + + if i == len(splits)-1 { + buf.WriteString(boilRuleset.Pluralize(splits[len(splits)-1])) + break + } + + buf.WriteString(splits[i]) + } + + return buf.String() +} + +// Singular converts plural words to singular words (eg: people to person) +func Singular(name string) string { + buf := GetBuffer() + defer PutBuffer(buf) + + splits := strings.Split(name, "_") + + for i := 0; i < len(splits); i++ { + if i != 0 { + buf.WriteByte('_') + } + + if i == len(splits)-1 { + buf.WriteString(boilRuleset.Singularize(splits[len(splits)-1])) + break + } + + buf.WriteString(splits[i]) + } + + return buf.String() +} + +// titleCaseCache holds the mapping of title cases. +// Example: map["MyWord"] == "my_word" +var ( + mut sync.RWMutex + titleCaseCache = map[string]string{} +) + +// TitleCase changes a snake-case variable name +// into a go styled object variable name of "ColumnName". +// titleCase also fully uppercases "ID" components of names, for example +// "column_name_id" to "ColumnNameID". +// +// Note: This method is ugly because it has been highly optimized, +// we found that it was a fairly large bottleneck when we were using regexp. +func TitleCase(n string) string { + // Attempt to fetch from cache + mut.RLock() + val, ok := titleCaseCache[n] + mut.RUnlock() + if ok { + return val + } + + ln := len(n) + name := []byte(n) + buf := GetBuffer() + + start := 0 + end := 0 + for start < ln { + // Find the start and end of the underscores to account + // for the possibility of being multiple underscores in a row. + if end < ln { + if name[start] == '_' { + start++ + end++ + continue + // Once we have found the end of the underscores, we can + // find the end of the first full word. + } else if name[end] != '_' { + end++ + continue + } + } + + word := name[start:end] + wordLen := len(word) + var vowels bool + + numStart := wordLen + for i, c := range word { + vowels = vowels || (c == 97 || c == 101 || c == 105 || c == 111 || c == 117 || c == 121) + + if c > 47 && c < 58 && numStart == wordLen { + numStart = i + } + } + + _, match := uppercaseWords[string(word[:numStart])] + + if match || !vowels { + // Uppercase all a-z characters + for _, c := range word { + if c > 96 && c < 123 { + buf.WriteByte(c - 32) + } else { + buf.WriteByte(c) + } + } + } else { + if c := word[0]; c > 96 && c < 123 { + buf.WriteByte(word[0] - 32) + buf.Write(word[1:]) + } else { + buf.Write(word) + } + } + + start = end + 1 + end = start + } + + ret := buf.String() + PutBuffer(buf) + + // Cache the title case result + mut.Lock() + titleCaseCache[n] = ret + mut.Unlock() + + return ret +} + +// Ignore sets "-" for the tags values, so the fields will be ignored during parsing +func Ignore(table, column string, ignoreList map[string]struct{}) bool { + _, ok := ignoreList[column] + if ok { + return true + } + _, ok = ignoreList[fmt.Sprintf("%s.%s", table, column)] + if ok { + return true + } + return false +} + +// CamelCase takes a variable name in the format of "var_name" and converts +// it into a go styled variable name of "varName". +// camelCase also fully uppercases "ID" components of names, for example +// "var_name_id" to "varNameID". It will also lowercase the first letter +// of the name in the case where it's fed something that starts with uppercase. +func CamelCase(name string) string { + buf := GetBuffer() + defer PutBuffer(buf) + + // Discard all leading '_' + index := -1 + for i := 0; i < len(name); i++ { + if name[i] != '_' { + index = i + break + } + } + + if index != -1 { + name = name[index:] + } else { + return "" + } + + index = -1 + for i := 0; i < len(name); i++ { + if name[i] == '_' { + index = i + break + } + } + + if index == -1 { + buf.WriteString(strings.ToLower(string(name[0]))) + if len(name) > 1 { + buf.WriteString(name[1:]) + } + } else { + buf.WriteString(strings.ToLower(string(name[0]))) + if len(name) > 1 { + buf.WriteString(name[1:index]) + buf.WriteString(TitleCase(name[index+1:])) + } + } + + return buf.String() +} + +// TitleCaseIdentifier splits on dots and then titlecases each fragment. +// map titleCase (split c ".") +func TitleCaseIdentifier(id string) string { + nextDot := strings.IndexByte(id, '.') + if nextDot < 0 { + return TitleCase(id) + } + + buf := GetBuffer() + defer PutBuffer(buf) + lastDot := 0 + ln := len(id) + addDots := false + + for i := 0; nextDot >= 0; i++ { + fragment := id[lastDot:nextDot] + + titled := TitleCase(fragment) + + if addDots { + buf.WriteByte('.') + } + buf.WriteString(titled) + addDots = true + + if nextDot == ln { + break + } + + lastDot = nextDot + 1 + if nextDot = strings.IndexByte(id[lastDot:], '.'); nextDot >= 0 { + nextDot += lastDot + } else { + nextDot = ln + } + } + + return buf.String() +} + +// MakeStringMap converts a map[string]string into the format: +// "key": "value", "key": "value" +func MakeStringMap(types map[string]string) string { + buf := GetBuffer() + defer PutBuffer(buf) + + keys := make([]string, 0, len(types)) + for k := range types { + keys = append(keys, k) + } + sort.Strings(keys) + + c := 0 + for _, k := range keys { + v := types[k] + buf.WriteString(fmt.Sprintf("`%s`: `%s`", k, v)) + if c < len(types)-1 { + buf.WriteString(", ") + } + + c++ + } + + return buf.String() +} + +// StringMap maps a function over a slice of strings. +func StringMap(modifier func(string) string, strs []string) []string { + ret := make([]string, len(strs)) + + for i, str := range strs { + ret[i] = modifier(str) + } + + return ret +} + +// PrefixStringSlice with the given str. +func PrefixStringSlice(str string, strs []string) []string { + ret := make([]string, len(strs)) + + for i, s := range strs { + ret[i] = fmt.Sprintf("%s%s", str, s) + } + + return ret +} + +// Placeholders generates the SQL statement placeholders for in queries. +// For example, ($1,$2,$3),($4,$5,$6) etc. +// It will start counting placeholders at "start". +// If useIndexPlaceholders is false, it will convert to ? instead of $1 etc. +func Placeholders(useIndexPlaceholders bool, count int, start int, group int) string { + buf := GetBuffer() + defer PutBuffer(buf) + + if start == 0 || group == 0 { + panic("Invalid start or group numbers supplied.") + } + + if group > 1 { + buf.WriteByte('(') + } + for i := 0; i < count; i++ { + if i != 0 { + if group > 1 && i%group == 0 { + buf.WriteString("),(") + } else { + buf.WriteByte(',') + } + } + if useIndexPlaceholders { + buf.WriteString(fmt.Sprintf("$%d", start+i)) + } else { + buf.WriteByte('?') + } + } + if group > 1 { + buf.WriteByte(')') + } + + return buf.String() +} + +// SetParamNames takes a slice of columns and returns a comma separated +// list of parameter names for a template statement SET clause. +// eg: "col1"=$1, "col2"=$2, "col3"=$3 +func SetParamNames(lq, rq string, start int, columns []string) string { + buf := GetBuffer() + defer PutBuffer(buf) + + for i, c := range columns { + if start != 0 { + buf.WriteString(fmt.Sprintf(`%s%s%s=$%d`, lq, c, rq, i+start)) + } else { + buf.WriteString(fmt.Sprintf(`%s%s%s=?`, lq, c, rq)) + } + + if i < len(columns)-1 { + buf.WriteByte(',') + } + } + + return buf.String() +} + +// WhereClause returns the where clause using start as the $ flag index +// For example, if start was 2 output would be: "colthing=$2 AND colstuff=$3" +func WhereClause(lq, rq string, start int, cols []string) string { + buf := GetBuffer() + defer PutBuffer(buf) + + for i, c := range cols { + if start != 0 { + buf.WriteString(fmt.Sprintf(`%s%s%s=$%d`, lq, c, rq, start+i)) + } else { + buf.WriteString(fmt.Sprintf(`%s%s%s=?`, lq, c, rq)) + } + + if i < len(cols)-1 { + buf.WriteString(" AND ") + } + } + + return buf.String() +} + +// WhereClauseRepeated returns the where clause repeated with OR clause using start as the $ flag index +// For example, if start was 2 output would be: "(colthing=$2 AND colstuff=$3) OR (colthing=$4 AND colstuff=$5)" +func WhereClauseRepeated(lq, rq string, start int, cols []string, count int) string { + var startIndex int + buf := GetBuffer() + defer PutBuffer(buf) + buf.WriteByte('(') + for i := 0; i < count; i++ { + if i != 0 { + buf.WriteString(") OR (") + } + + startIndex = 0 + if start > 0 { + startIndex = start + i*len(cols) + } + + buf.WriteString(WhereClause(lq, rq, startIndex, cols)) + } + buf.WriteByte(')') + + return buf.String() +} + +// JoinSlices merges two string slices of equal length +func JoinSlices(sep string, a, b []string) []string { + lna, lnb := len(a), len(b) + if lna != lnb { + panic("joinSlices: can only merge slices of same length") + } else if lna == 0 { + return nil + } + + ret := make([]string, len(a)) + for i, elem := range a { + ret[i] = fmt.Sprintf("%s%s%s", elem, sep, b[i]) + } + + return ret +} + +// StringSliceMatch returns true if the length of both +// slices is the same, and the elements of both slices are the same. +// The elements can be in any order. +func StringSliceMatch(a []string, b []string) bool { + if len(a) != len(b) { + return false + } + + for _, aval := range a { + found := false + for _, bval := range b { + if bval == aval { + found = true + break + } + } + if !found { + return false + } + } + + return true +} + +// ContainsAny returns true if any of the passed in strings are +// found in the passed in string slice +func ContainsAny(a []string, finds ...string) bool { + for _, s := range a { + for _, find := range finds { + if s == find { + return true + } + } + } + + return false +} + +// GenerateTags converts a slice of tag strings into tags that +// can be passed onto the end of a struct, for example: +// tags: ["xml", "db"] convert to: xml:"column_name" db:"column_name" +func GenerateTags(tags []string, columnName string) string { + buf := GetBuffer() + defer PutBuffer(buf) + + for _, tag := range tags { + buf.WriteString(tag) + buf.WriteString(`:"`) + buf.WriteString(columnName) + buf.WriteString(`" `) + } + + return buf.String() +} + +// GenerateIgnoreTags converts a slice of tag strings into +// ignore tags that can be passed onto the end of a struct, for example: +// tags: ["xml", "db"] convert to: xml:"-" db:"-" +func GenerateIgnoreTags(tags []string) string { + buf := GetBuffer() + defer PutBuffer(buf) + + for _, tag := range tags { + buf.WriteString(tag) + buf.WriteString(`:"-" `) + } + + return buf.String() +} + +// ParseEnumVals returns the values from an enum string +// +// Postgres and MySQL drivers return different values +// psql: enum.enum_name('values'...) +// mysql: enum('values'...) +func ParseEnumVals(s string) []string { + if !rgxEnum.MatchString(s) { + return nil + } + + startIndex := strings.IndexByte(s, '(') + s = s[startIndex+2 : len(s)-2] + return strings.Split(s, "','") +} + +// ParseEnumName returns the name portion of an enum if it exists +// +// Postgres and MySQL drivers return different values +// psql: enum.enum_name('values'...) +// mysql: enum('values'...) +// In the case of mysql, the name will never return anything +func ParseEnumName(s string) string { + if !rgxEnum.MatchString(s) { + return "" + } + + endIndex := strings.IndexByte(s, '(') + s = s[:endIndex] + startIndex := strings.IndexByte(s, '.') + if startIndex < 0 { + return "" + } + + return s[startIndex+1:] +} + +// IsEnumNormal checks a set of eval values to see if they're "normal" +func IsEnumNormal(values []string) bool { + for _, v := range values { + if !rgxEnumIsOK.MatchString(v) { + return false + } + } + + return true +} + +//StripWhitespace removes all whitespace from a string +func StripWhitespace(value string) string { + return rgxWhitespace.ReplaceAllString(value, "") +} + +// ShouldTitleCaseEnum checks a value to see if it's title-case-able +func ShouldTitleCaseEnum(value string) bool { + return rgxEnumShouldTitle.MatchString(value) +} + +// ReplaceReservedWords takes a word and replaces it with word_ if it's found +// in the list of reserved words. +func ReplaceReservedWords(word string) string { + if _, ok := reservedWords[word]; ok { + return word + "_" + } + return word +} + +// RemoveDuplicates from a string slice +func RemoveDuplicates(dedup []string) []string { + if len(dedup) <= 1 { + return dedup + } + + for i := 0; i < len(dedup)-1; i++ { + for j := i + 1; j < len(dedup); j++ { + if dedup[i] != dedup[j] { + continue + } + + if j != len(dedup)-1 { + dedup[j] = dedup[len(dedup)-1] + j-- + } + dedup = dedup[:len(dedup)-1] + } + } + + return dedup +} diff --git a/vendor/modules.txt b/vendor/modules.txt index ae8821db6..a575391d5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -97,9 +97,15 @@ github.com/docker/go-units # github.com/fatih/color v1.9.0 ## explicit; go 1.13 github.com/fatih/color +# github.com/friendsofgo/errors v0.9.2 +## explicit; go 1.13 +github.com/friendsofgo/errors # github.com/fsnotify/fsnotify v1.4.9 ## explicit; go 1.13 github.com/fsnotify/fsnotify +# github.com/gofrs/uuid v4.2.0+incompatible +## explicit +github.com/gofrs/uuid # github.com/gogo/protobuf v1.3.2 ## explicit; go 1.15 github.com/gogo/protobuf/gogoproto @@ -177,7 +183,7 @@ github.com/mattn/go-runewidth # github.com/mattn/go-shellwords v1.0.12 ## explicit; go 1.13 github.com/mattn/go-shellwords -# github.com/meroxa/meroxa-go v0.0.0-20220302153558-e3b3dc31559c +# github.com/meroxa/meroxa-go v0.0.0-20220302153558-e3b3dc31559c => ../meroxa-go ## explicit; go 1.17 github.com/meroxa/meroxa-go/pkg/meroxa github.com/meroxa/meroxa-go/pkg/mock @@ -254,6 +260,19 @@ github.com/spf13/viper # github.com/subosito/gotenv v1.2.0 ## explicit github.com/subosito/gotenv +# github.com/volatiletech/inflect v0.0.1 +## explicit; go 1.14 +github.com/volatiletech/inflect +# github.com/volatiletech/null/v8 v8.1.2 +## explicit; go 1.14 +github.com/volatiletech/null/v8 +github.com/volatiletech/null/v8/convert +# github.com/volatiletech/randomize v0.0.1 +## explicit; go 1.14 +github.com/volatiletech/randomize +# github.com/volatiletech/strmangle v0.0.2 +## explicit; go 1.14 +github.com/volatiletech/strmangle # go.opencensus.io v0.23.0 ## explicit; go 1.13 go.opencensus.io @@ -342,3 +361,4 @@ gopkg.in/ini.v1 # gopkg.in/yaml.v2 v2.4.0 ## explicit; go 1.15 gopkg.in/yaml.v2 +# github.com/meroxa/meroxa-go => ../meroxa-go