├── .bingo ├── .gitignore ├── README.md ├── Variables.mk ├── bingo.mod ├── bingo.sum ├── go.mod ├── gofumpt.mod ├── golangci-lint.mod ├── golangci-lint.sum └── variables.env ├── .envrc ├── .github ├── dependabot.yml ├── stale.yml └── workflows │ └── go_test.yml ├── .gitignore ├── .golangci.yml ├── .ignore ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── bench_scanner_test.go ├── columns.go ├── columns_test.go ├── doc.go ├── example_scanner_test.go ├── examples_values_columns_test.go ├── fakes_test.go ├── go.mod ├── go.sum ├── interface.go ├── scanner.go ├── scanner_test.go ├── values.go ├── values_test.go └── vendor ├── github.com ├── davecgh │ └── go-spew │ │ ├── LICENSE │ │ └── spew │ │ ├── bypass.go │ │ ├── bypasssafe.go │ │ ├── common.go │ │ ├── config.go │ │ ├── doc.go │ │ ├── dump.go │ │ ├── format.go │ │ └── spew.go ├── pmezard │ └── go-difflib │ │ ├── LICENSE │ │ └── difflib │ │ └── difflib.go ├── proullon │ └── ramsql │ │ ├── LICENSE │ │ ├── driver │ │ ├── conn.go │ │ ├── driver.go │ │ ├── init.go │ │ ├── result.go │ │ ├── rows.go │ │ ├── stmt.go │ │ └── tx.go │ │ └── engine │ │ ├── attribute.go │ │ ├── condition.go │ │ ├── delete.go │ │ ├── distinct.go │ │ ├── drop.go │ │ ├── engine.go │ │ ├── insert.go │ │ ├── join.go │ │ ├── limit.go │ │ ├── log │ │ └── log.go │ │ ├── operator.go │ │ ├── orderby.go │ │ ├── parser │ │ ├── create.go │ │ ├── date.go │ │ ├── delete.go │ │ ├── drop.go │ │ ├── interface.go │ │ ├── lexer.go │ │ ├── log.go │ │ ├── parser.go │ │ ├── select.go │ │ ├── truncate.go │ │ └── where.go │ │ ├── predicate.go │ │ ├── protocol │ │ ├── buffer.go │ │ ├── channel.go │ │ └── public.go │ │ ├── relation.go │ │ ├── select.go │ │ ├── table.go │ │ ├── truncate.go │ │ ├── tuple.go │ │ └── update.go └── stretchr │ └── testify │ ├── LICENSE │ ├── assert │ ├── assertion_compare.go │ ├── assertion_compare_can_convert.go │ ├── assertion_compare_legacy.go │ ├── assertion_format.go │ ├── assertion_format.go.tmpl │ ├── assertion_forward.go │ ├── assertion_forward.go.tmpl │ ├── assertion_order.go │ ├── assertions.go │ ├── doc.go │ ├── errors.go │ ├── forward_assertions.go │ └── http_assertions.go │ └── require │ ├── doc.go │ ├── forward_requirements.go │ ├── require.go │ ├── require.go.tmpl │ ├── require_forward.go │ ├── require_forward.go.tmpl │ └── requirements.go ├── golang.org └── x │ └── text │ ├── LICENSE │ ├── PATENTS │ ├── cases │ ├── cases.go │ ├── context.go │ ├── fold.go │ ├── icu.go │ ├── info.go │ ├── map.go │ ├── tables10.0.0.go │ ├── tables11.0.0.go │ ├── tables12.0.0.go │ ├── tables13.0.0.go │ ├── tables15.0.0.go │ ├── tables9.0.0.go │ └── trieval.go │ ├── internal │ ├── internal.go │ ├── language │ │ ├── common.go │ │ ├── compact.go │ │ ├── compact │ │ │ ├── compact.go │ │ │ ├── language.go │ │ │ ├── parents.go │ │ │ ├── tables.go │ │ │ └── tags.go │ │ ├── compose.go │ │ ├── coverage.go │ │ ├── language.go │ │ ├── lookup.go │ │ ├── match.go │ │ ├── parse.go │ │ ├── tables.go │ │ └── tags.go │ ├── match.go │ └── tag │ │ └── tag.go │ ├── language │ ├── coverage.go │ ├── doc.go │ ├── language.go │ ├── match.go │ ├── parse.go │ ├── tables.go │ └── tags.go │ ├── transform │ └── transform.go │ └── unicode │ └── norm │ ├── composition.go │ ├── forminfo.go │ ├── input.go │ ├── iter.go │ ├── normalize.go │ ├── readwriter.go │ ├── tables10.0.0.go │ ├── tables11.0.0.go │ ├── tables12.0.0.go │ ├── tables13.0.0.go │ ├── tables15.0.0.go │ ├── tables9.0.0.go │ ├── transform.go │ └── trie.go ├── gopkg.in └── yaml.v3 │ ├── LICENSE │ ├── NOTICE │ ├── README.md │ ├── apic.go │ ├── decode.go │ ├── emitterc.go │ ├── encode.go │ ├── parserc.go │ ├── readerc.go │ ├── resolve.go │ ├── scannerc.go │ ├── sorter.go │ ├── writerc.go │ ├── yaml.go │ ├── yamlh.go │ └── yamlprivateh.go └── modules.txt /.bingo/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Ignore everything 3 | * 4 | 5 | # But not these files: 6 | !.gitignore 7 | !*.mod 8 | !*.sum 9 | !README.md 10 | !Variables.mk 11 | !variables.env 12 | 13 | *tmp.mod 14 | -------------------------------------------------------------------------------- /.bingo/README.md: -------------------------------------------------------------------------------- 1 | # Project Development Dependencies. 2 | 3 | This is directory which stores Go modules with pinned buildable package that is used within this repository, managed by https://github.com/bwplotka/bingo. 4 | 5 | * Run `bingo get` to install all tools having each own module file in this directory. 6 | * Run `bingo get ` to install that have own module file in this directory. 7 | * For Makefile: Make sure to put `include .bingo/Variables.mk` in your Makefile, then use $() variable where is the .bingo/.mod. 8 | * For shell: Run `source .bingo/variables.env` to source all environment variable for each tool. 9 | * For go: Import `.bingo/variables.go` to for variable names. 10 | * See https://github.com/bwplotka/bingo or -h on how to add, remove or change binaries dependencies. 11 | 12 | ## Requirements 13 | 14 | * Go 1.14+ 15 | -------------------------------------------------------------------------------- /.bingo/Variables.mk: -------------------------------------------------------------------------------- 1 | # Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.6. DO NOT EDIT. 2 | # All tools are designed to be build inside $GOBIN. 3 | BINGO_DIR := $(dir $(lastword $(MAKEFILE_LIST))) 4 | GOPATH ?= $(shell go env GOPATH) 5 | GOBIN ?= $(firstword $(subst :, ,${GOPATH}))/bin 6 | GO ?= $(shell which go) 7 | 8 | # Below generated variables ensure that every time a tool under each variable is invoked, the correct version 9 | # will be used; reinstalling only if needed. 10 | # For example for bingo variable: 11 | # 12 | # In your main Makefile (for non array binaries): 13 | # 14 | #include .bingo/Variables.mk # Assuming -dir was set to .bingo . 15 | # 16 | #command: $(BINGO) 17 | # @echo "Running bingo" 18 | # @$(BINGO) 19 | # 20 | BINGO := $(GOBIN)/bingo-v0.4.3 21 | $(BINGO): $(BINGO_DIR)/bingo.mod 22 | @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. 23 | @echo "(re)installing $(GOBIN)/bingo-v0.4.3" 24 | @cd $(BINGO_DIR) && $(GO) build -mod=mod -modfile=bingo.mod -o=$(GOBIN)/bingo-v0.4.3 "github.com/bwplotka/bingo" 25 | 26 | GOFUMPT := $(GOBIN)/gofumpt-v0.1.1 27 | $(GOFUMPT): $(BINGO_DIR)/gofumpt.mod 28 | @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. 29 | @echo "(re)installing $(GOBIN)/gofumpt-v0.1.1" 30 | @cd $(BINGO_DIR) && $(GO) build -mod=mod -modfile=gofumpt.mod -o=$(GOBIN)/gofumpt-v0.1.1 "mvdan.cc/gofumpt" 31 | 32 | GOLANGCI_LINT := $(GOBIN)/golangci-lint-v1.46.2 33 | $(GOLANGCI_LINT): $(BINGO_DIR)/golangci-lint.mod 34 | @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. 35 | @echo "(re)installing $(GOBIN)/golangci-lint-v1.46.2" 36 | @cd $(BINGO_DIR) && $(GO) build -mod=mod -modfile=golangci-lint.mod -o=$(GOBIN)/golangci-lint-v1.46.2 "github.com/golangci/golangci-lint/cmd/golangci-lint" 37 | 38 | -------------------------------------------------------------------------------- /.bingo/bingo.mod: -------------------------------------------------------------------------------- 1 | module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT 2 | 3 | go 1.16 4 | 5 | require github.com/bwplotka/bingo v0.4.3 6 | -------------------------------------------------------------------------------- /.bingo/bingo.sum: -------------------------------------------------------------------------------- 1 | github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= 2 | github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= 3 | github.com/bwplotka/bingo v0.4.3 h1:lVJ0CU0tRUWue1GP/UyqHtc4ukPvyhKHdk8vJyAPQjs= 4 | github.com/bwplotka/bingo v0.4.3/go.mod h1:I/Km90ZtlRi/romboXtQnuNZ6SAj/uc8bZcvqjUZFKY= 5 | github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/efficientgo/tools/core v0.0.0-20210201220623-8118984754c2 h1:GD19G/vhEa8amDJDBYcTaFXZjxKed67Ev0ZFPHdd/LQ= 9 | github.com/efficientgo/tools/core v0.0.0-20210201220623-8118984754c2/go.mod h1:cFZoHUhKg31xkPnPjhPKFtevnx0Xcg67ptBRxbpaxtk= 10 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 11 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 12 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 13 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 14 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 15 | github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= 16 | github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= 17 | github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28= 18 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 19 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 20 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 21 | github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 22 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 23 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 24 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 25 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 26 | go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= 27 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 28 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 29 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 30 | golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= 31 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 32 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 33 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 34 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 35 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 36 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= 37 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 38 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 39 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 40 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 41 | golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 h1:HlFl4V6pEMziuLXyRkm5BIYq1y1GAbb02pRlWvI54OM= 42 | golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 43 | golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407 h1:5zh5atpUEdIc478E/ebrIaHLKcfVvG6dL/fGv7BcMoM= 44 | golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 45 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 46 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 47 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 48 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 49 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 50 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= 51 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 52 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 53 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 54 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 55 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 56 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 57 | mvdan.cc/editorconfig v0.1.1-0.20200121172147-e40951bde157/go.mod h1:Ge4atmRUYqueGppvJ7JNrtqpqokoJEFxYbP0Z+WeKS8= 58 | mvdan.cc/sh/v3 v3.2.4 h1:+fZaWcXWRjYAvqzEKoDhDM3DkxdDUykU2iw0VMKFe9s= 59 | mvdan.cc/sh/v3 v3.2.4/go.mod h1:fPQmabBpREM/XQ9YXSU5ZFZ/Sm+PmKP9/vkFHgYKJEI= 60 | -------------------------------------------------------------------------------- /.bingo/go.mod: -------------------------------------------------------------------------------- 1 | module _ // Fake go.mod auto-created by 'bingo' for go -moddir compatibility with non-Go projects. Commit this file, together with other .mod files. -------------------------------------------------------------------------------- /.bingo/gofumpt.mod: -------------------------------------------------------------------------------- 1 | module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT 2 | 3 | go 1.16 4 | 5 | require mvdan.cc/gofumpt v0.1.1 6 | -------------------------------------------------------------------------------- /.bingo/golangci-lint.mod: -------------------------------------------------------------------------------- 1 | module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT 2 | 3 | go 1.16 4 | 5 | require github.com/golangci/golangci-lint v1.46.2 // cmd/golangci-lint 6 | -------------------------------------------------------------------------------- /.bingo/variables.env: -------------------------------------------------------------------------------- 1 | # Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.6. DO NOT EDIT. 2 | # All tools are designed to be build inside $GOBIN. 3 | # Those variables will work only until 'bingo get' was invoked, or if tools were installed via Makefile's Variables.mk. 4 | GOBIN=${GOBIN:=$(go env GOBIN)} 5 | 6 | if [ -z "$GOBIN" ]; then 7 | GOBIN="$(go env GOPATH)/bin" 8 | fi 9 | 10 | 11 | BINGO="${GOBIN}/bingo-v0.4.3" 12 | 13 | GOFUMPT="${GOBIN}/gofumpt-v0.1.1" 14 | 15 | GOLANGCI_LINT="${GOBIN}/golangci-lint-v1.46.2" 16 | 17 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | . ./.bingo/variables.env 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "11:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Number of days of inactivity before an issue becomes stale 3 | daysUntilStale: 30 4 | # Number of days of inactivity before a stale issue is closed 5 | daysUntilClose: 14 6 | # Issues with these labels will never be considered stale 7 | exemptLabels: 8 | - pinned 9 | - security 10 | - wip 11 | # Label to use when marking an issue as stale 12 | staleLabel: stale 13 | # Comment to post when marking an issue as stale. Set to `false` to disable 14 | markComment: > 15 | This issue has been automatically marked as stale because it has not had 16 | recent activity. It will be closed if no further activity occurs. Thank you 17 | for your contributions. 18 | # Comment to post when closing a stale issue. Set to `false` to disable 19 | closeComment: false 20 | -------------------------------------------------------------------------------- /.github/workflows/go_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: go test 3 | 4 | on: 5 | push: 6 | branches: [ master ] 7 | pull_request: 8 | branches: [ master ] 9 | 10 | jobs: 11 | build: 12 | name: go test 13 | runs-on: ubuntu-latest 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | go: 18 | - '1.17' 19 | - '1.18' 20 | - '1.19' 21 | - '1.20' 22 | - '1.21' 23 | 24 | steps: 25 | - name: Set up Go 1.x 26 | uses: actions/setup-go@v3 27 | with: 28 | go-version: ${{ matrix.go }} 29 | id: go 30 | 31 | - uses: actions/checkout@v3 32 | 33 | - name: Lint 34 | uses: golangci/golangci-lint-action@v3 35 | with: 36 | version: v1.51 37 | 38 | - name: Test 39 | run: go test -v -coverprofile=.coverprofile . 40 | 41 | - name: Report coveralls.io 42 | uses: shogo82148/actions-goveralls@v1 43 | with: 44 | path-to-profile: .coverprofile 45 | flag-name: Go-${{ matrix.go }} 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .coverprofile 2 | .idea 3 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | run: 3 | tests: false 4 | skip-files: 5 | - "example_.+_test.go$" 6 | 7 | # golangci.com configuration 8 | # https://github.com/golangci/golangci/wiki/Configuration 9 | linters-settings: 10 | govet: 11 | check-shadowing: true 12 | maligned: 13 | suggest-new: true 14 | misspell: 15 | locale: US 16 | 17 | linters: 18 | enable-all: false 19 | enable: 20 | - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases 21 | - goerr113 # checks that errors are wrapped according to go 1.13 error wrapping tools 22 | - gofumpt # checks that gofumpt was run on all source code 23 | - goimports # checks that goimports was run on all source code 24 | - gosimple # Linter for Go source code that specializes in simplifying a code 25 | - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string 26 | - ineffassign # Detects when assignments to existing variables are not used 27 | - misspell # spell checker 28 | - rowserrcheck # checks whether Err of rows is checked successfully 29 | - staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks 30 | - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code 31 | - unused # Checks Go code for unused constants, variables, functions and types 32 | 33 | issues: 34 | exclude-use-default: false 35 | exclude-rules: 36 | - text: "weak cryptographic primitive" 37 | linters: 38 | - gosec 39 | -------------------------------------------------------------------------------- /.ignore: -------------------------------------------------------------------------------- 1 | vendor 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Release 1.3.0 2 | 3 | Features: add RowStrict and RowsStrict to allow scanning to structs using only `db` tags 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Brett 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include .bingo/Variables.mk 2 | 3 | .DEFAULT_GOAL := build 4 | 5 | GOFILES=$(shell find . -type f -iname '*.go') 6 | 7 | .PHONY: build 8 | build: $(GOFILES) 9 | go build -o /dev/null *.go 10 | 11 | .PHONY: test 12 | test: 13 | go test -tags=integration ./... 14 | 15 | .PHONY: lint 16 | lint: $(GOLANGCI_LINT) 17 | $(GOLANGCI_LINT) run 18 | 19 | fmt: $(GOFUMPT) 20 | $(GOFUMPT) -w $(GOFILES) 21 | -------------------------------------------------------------------------------- /bench_scanner_test.go: -------------------------------------------------------------------------------- 1 | package scan_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/blockloop/scan/v2" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func BenchmarkScanRowOneField(b *testing.B) { 11 | var item struct { 12 | First string 13 | } 14 | 15 | b.ResetTimer() 16 | for i := 0; i < b.N; i++ { 17 | rows := fakeRowsWithColumns(b, 1, "First") 18 | if err := scan.Row(&item, rows); err != nil { 19 | b.Fatalf("unexpected error: %v", err) 20 | } 21 | } 22 | } 23 | 24 | func BenchmarkScanRowFiveFields(b *testing.B) { 25 | var item struct { 26 | First string `db:"first"` 27 | Age int8 `db:"age"` 28 | Active bool `db:"active"` 29 | City string `db:"city"` 30 | State string `db:"state"` 31 | } 32 | cols, err := scan.Columns(&item) 33 | assert.NoError(b, err) 34 | 35 | b.ResetTimer() 36 | for i := 0; i < b.N; i++ { 37 | rows := fakeRowsWithColumns(b, 1, cols...) 38 | if err := scan.Row(&item, rows); err != nil { 39 | b.Fatalf("unexpected error: %v", err) 40 | } 41 | } 42 | } 43 | 44 | func BenchmarkScanTenRowsOneField(b *testing.B) { 45 | type item struct { 46 | First string `db:"First"` 47 | } 48 | var items []item 49 | cols, err := scan.Columns(&item{}) 50 | assert.NoError(b, err) 51 | 52 | b.ResetTimer() 53 | for i := 0; i < b.N; i++ { 54 | rows := fakeRowsWithColumns(b, 10, cols...) 55 | if err := scan.Rows(&items, rows); err != nil { 56 | b.Fatalf("unexpected error: %v", err) 57 | } 58 | } 59 | } 60 | 61 | func BenchmarkScanTenRowsTenFields(b *testing.B) { 62 | type item struct { 63 | One string `db:"one"` 64 | Two string `db:"two"` 65 | Three int8 `db:"three"` 66 | Four bool `db:"four"` 67 | Five string `db:"five"` 68 | Six string `db:"six"` 69 | Seven string `db:"seven"` 70 | Eight string `db:"eight"` 71 | Nine string `db:"nine"` 72 | Ten string `db:"ten"` 73 | } 74 | var items []item 75 | cols, err := scan.Columns(&item{}) 76 | assert.NoError(b, err) 77 | 78 | b.ResetTimer() 79 | for i := 0; i < b.N; i++ { 80 | rows := fakeRowsWithColumns(b, 10, cols...) 81 | if err := scan.Rows(&items, rows); err != nil { 82 | b.Fatalf("unexpected error: %v", err) 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /columns.go: -------------------------------------------------------------------------------- 1 | package scan 2 | 3 | import ( 4 | "database/sql/driver" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | "sync" 9 | ) 10 | 11 | const dbTag = "db" 12 | 13 | var ( 14 | // ErrNotAPointer is returned when a non-pointer is received 15 | // when a pointer is expected. 16 | ErrNotAPointer = errors.New("not a pointer") 17 | 18 | // ErrNotAStructPointer is returned when a non-struct pointer 19 | // is received but a struct pointer was expected 20 | ErrNotAStructPointer = errors.New("not a struct pointer") 21 | 22 | // ErrNotASlicePointer is returned when receiving an argument 23 | // that is expected to be a slice pointer, but it is not 24 | ErrNotASlicePointer = errors.New("not a slice pointer") 25 | 26 | // ErrStructFieldMissing is returned when trying to scan a value 27 | // to a column which does not match a struct. This means that 28 | // the struct does not have a field that matches the column 29 | // specified. 30 | ErrStructFieldMissing = errors.New("struct field missing") 31 | 32 | // ColumnsMapper transforms struct/map field names 33 | // into the database column names. 34 | // E.g. you can set function for convert CamelCase into snake_case 35 | ColumnsMapper = func(name string) string { return name } 36 | ) 37 | 38 | var columnsCache cache = &sync.Map{} 39 | 40 | type cacheKey struct { 41 | Type reflect.Type 42 | Strict bool 43 | } 44 | 45 | // Columns scans a struct and returns a list of strings 46 | // that represent the assumed column names based on the 47 | // db struct tag, or the field name. Any field or struct 48 | // tag that matches a string within the excluded list 49 | // will be excluded from the result. 50 | func Columns(v interface{}, excluded ...string) ([]string, error) { 51 | return columns(v, false, excluded...) 52 | } 53 | 54 | // ColumnsStrict is identical to Columns, but it only 55 | // searches struct tags and excludes fields not tagged 56 | // with the db struct tag. 57 | func ColumnsStrict(v interface{}, excluded ...string) ([]string, error) { 58 | return columns(v, true, excluded...) 59 | } 60 | 61 | func columns(v interface{}, strict bool, excluded ...string) ([]string, error) { 62 | model, err := reflectValue(v) 63 | if err != nil { 64 | return nil, fmt.Errorf("columns: %w", err) 65 | } 66 | 67 | key := cacheKey{model.Type(), strict} 68 | 69 | if cache, ok := columnsCache.Load(key); ok { 70 | cached := cache.([]string) 71 | res := make([]string, 0, len(cached)) 72 | 73 | keep := func(k string) bool { 74 | for _, c := range excluded { 75 | if c == k { 76 | return false 77 | } 78 | } 79 | return true 80 | } 81 | 82 | for _, k := range cached { 83 | if keep(k) { 84 | res = append(res, k) 85 | } 86 | } 87 | return res, nil 88 | } 89 | 90 | names := columnNames(model, strict, excluded...) 91 | toCache := append(names, excluded...) 92 | columnsCache.Store(key, toCache) 93 | return names, nil 94 | } 95 | 96 | func columnNames(model reflect.Value, strict bool, excluded ...string) []string { 97 | numfield := model.NumField() 98 | names := make([]string, 0, numfield) 99 | 100 | for i := 0; i < numfield; i++ { 101 | valField := model.Field(i) 102 | if !valField.IsValid() || !valField.CanSet() { 103 | continue 104 | } 105 | 106 | typeField := model.Type().Field(i) 107 | 108 | if typeField.Type.Kind() == reflect.Struct && !isValidSqlValue(valField) { 109 | embeddedNames := columnNames(valField, strict, excluded...) 110 | names = append(names, embeddedNames...) 111 | continue 112 | } 113 | 114 | fieldName := ColumnsMapper(typeField.Name) 115 | if tag, hasTag := typeField.Tag.Lookup(dbTag); hasTag { 116 | if tag == "-" { 117 | continue 118 | } 119 | fieldName = tag 120 | } else if strict { 121 | // there's no tag name and we're in strict mode so move on 122 | continue 123 | } 124 | 125 | if isExcluded(fieldName, excluded...) { 126 | continue 127 | } 128 | 129 | if supportedColumnType(valField) || isValidSqlValue(valField) { 130 | names = append(names, fieldName) 131 | } 132 | } 133 | 134 | return names 135 | } 136 | 137 | func isExcluded(name string, excluded ...string) bool { 138 | for _, ex := range excluded { 139 | if ex == name { 140 | return true 141 | } 142 | } 143 | return false 144 | } 145 | 146 | func reflectValue(v interface{}) (reflect.Value, error) { 147 | vType := reflect.TypeOf(v) 148 | vKind := vType.Kind() 149 | if vKind != reflect.Ptr { 150 | return reflect.Value{}, fmt.Errorf("%q must be a pointer: %w", vKind.String(), ErrNotAPointer) 151 | } 152 | 153 | vVal := reflect.Indirect(reflect.ValueOf(v)) 154 | if vVal.Kind() != reflect.Struct { 155 | return reflect.Value{}, fmt.Errorf("%q must be a pointer to a struct: %w", vKind.String(), ErrNotAStructPointer) 156 | } 157 | return vVal, nil 158 | } 159 | 160 | func supportedColumnType(v reflect.Value) bool { 161 | switch v.Kind() { 162 | case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, 163 | reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, 164 | reflect.Uint64, reflect.Float32, reflect.Float64, reflect.Interface, 165 | reflect.String: 166 | return true 167 | case reflect.Ptr, reflect.Slice, reflect.Array: 168 | ptrVal := reflect.New(v.Type().Elem()) 169 | return supportedColumnType(ptrVal.Elem()) 170 | default: 171 | return false 172 | } 173 | } 174 | 175 | func isValidSqlValue(v reflect.Value) bool { 176 | // This method covers two cases in which we know the Value can be converted to sql: 177 | // 1. It returns true for sql.driver's type check for types like time.Time 178 | // 2. It implements the driver.Valuer interface allowing conversion directly 179 | // into sql statements 180 | if v.Kind() == reflect.Ptr { 181 | ptrVal := reflect.New(v.Type().Elem()) 182 | return isValidSqlValue(ptrVal.Elem()) 183 | } 184 | 185 | if driver.IsValue(v.Interface()) { 186 | return true 187 | } 188 | 189 | valuerType := reflect.TypeOf((*driver.Valuer)(nil)).Elem() 190 | return v.Type().Implements(valuerType) 191 | } 192 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Package scan provides functionality for scanning database/sql rows into slices, 2 | // structs, and primitive types dynamically 3 | package scan 4 | -------------------------------------------------------------------------------- /examples_values_columns_test.go: -------------------------------------------------------------------------------- 1 | package scan_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/blockloop/scan/v2" 7 | ) 8 | 9 | func ExampleValues() { 10 | person := struct { 11 | ID int `db:"id"` 12 | Name string `db:"name"` 13 | }{ 14 | ID: 1, 15 | Name: "Brett", 16 | } 17 | 18 | cols := []string{"id", "name"} 19 | vals, _ := scan.Values(cols, &person) 20 | fmt.Printf("%+v", vals) 21 | // Output: 22 | // [1 Brett] 23 | } 24 | 25 | func ExampleValues_nested() { 26 | type Address struct { 27 | Street string 28 | City string 29 | } 30 | 31 | person := struct { 32 | ID int 33 | Name string 34 | Address 35 | }{ 36 | Name: "Brett", 37 | ID: 1, 38 | Address: Address{ 39 | City: "San Francisco", 40 | }, 41 | } 42 | 43 | cols := []string{"Name", "City"} 44 | vals, _ := scan.Values(cols, &person) 45 | fmt.Printf("%+v", vals) 46 | // Output: 47 | // [Brett San Francisco] 48 | } 49 | 50 | func ExampleColumns() { 51 | var person struct { 52 | ID int `db:"person_id"` 53 | Name string 54 | } 55 | 56 | cols, _ := scan.Columns(&person) 57 | fmt.Printf("%+v", cols) 58 | // Output: 59 | // [person_id Name] 60 | } 61 | 62 | func ExampleColumns_exclude() { 63 | var person struct { 64 | ID int `db:"id"` 65 | Name string `db:"name"` 66 | Age string `db:"-"` 67 | } 68 | 69 | cols, _ := scan.Columns(&person) 70 | fmt.Printf("%+v", cols) 71 | // Output: 72 | // [id name] 73 | } 74 | 75 | func ExampleColumnsStrict() { 76 | var person struct { 77 | ID int `db:"id"` 78 | Name string 79 | Age string `db:"age"` 80 | } 81 | 82 | cols, _ := scan.ColumnsStrict(&person) 83 | fmt.Printf("%+v", cols) 84 | // Output: 85 | // [id age] 86 | } 87 | 88 | func ExampleColumnsNested() { 89 | var person struct { 90 | ID int `db:"person.id"` 91 | Name string `db:"person.name"` 92 | Company struct { 93 | ID int `db:"company.id"` 94 | Name string 95 | } 96 | } 97 | 98 | cols, _ := scan.Columns(&person) 99 | fmt.Printf("%+v", cols) 100 | // Output: 101 | // [person.id person.name company.id Name] 102 | } 103 | 104 | func ExampleColumnsNestedStrict() { 105 | var person struct { 106 | ID int `db:"person.id"` 107 | Name string `db:"person.name"` 108 | Company struct { 109 | ID int `db:"company.id"` 110 | Name string 111 | } 112 | } 113 | 114 | cols, _ := scan.ColumnsStrict(&person) 115 | fmt.Printf("%+v", cols) 116 | // Output: 117 | // [person.id person.name company.id] 118 | } 119 | 120 | func ExampleColumnsNested_exclude() { 121 | var person struct { 122 | ID int `db:"person.id"` 123 | Name string `db:"person.name"` 124 | Company struct { 125 | ID int `db:"-"` 126 | Name string `db:"company.name"` 127 | } 128 | } 129 | 130 | cols, _ := scan.Columns(&person) 131 | fmt.Printf("%+v", cols) 132 | // Output: 133 | // [person.id person.name company.name] 134 | } 135 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/blockloop/scan/v2 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/proullon/ramsql v0.0.1 7 | github.com/stretchr/testify v1.8.2 8 | golang.org/x/text v0.14.0 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/kr/pretty v0.2.1 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect 16 | gopkg.in/yaml.v3 v3.0.1 // indirect 17 | ) 18 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/go-gorp/gorp v2.0.0+incompatible h1:dIQPsBtl6/H1MjVseWuWPXa7ET4p6Dve4j3Hg+UjqYw= 5 | github.com/go-gorp/gorp v2.0.0+incompatible/go.mod h1:7IfkAQnO7jfT/9IQ3R9wL1dFhukN6aQxzKTHnkxzA/E= 6 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 7 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 8 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 9 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 10 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 11 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 12 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 13 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 14 | github.com/proullon/ramsql v0.0.1 h1:tI7qN48Oj1LTmgdo4aWlvI9z45a4QlWaXlmdJ+IIfbU= 15 | github.com/proullon/ramsql v0.0.1/go.mod h1:jG8oAQG0ZPHPyxg5QlMERS31airDC+ZuqiAe8DUvFVo= 16 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 17 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 18 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 19 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 20 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 21 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 22 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 23 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 24 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 25 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 26 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 27 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 28 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 29 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 30 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 31 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 32 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 33 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 34 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 35 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 36 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 37 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 38 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 39 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 40 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 41 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 42 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 43 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 44 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 45 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 46 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 47 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 48 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 49 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 50 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 51 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 52 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 53 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 54 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 55 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 56 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 57 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 58 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 59 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 60 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 61 | -------------------------------------------------------------------------------- /interface.go: -------------------------------------------------------------------------------- 1 | package scan 2 | 3 | import "database/sql" 4 | 5 | // RowsScanner is a database scanner for many rows. It is most commonly the 6 | // result of *sql.DB Query(...). 7 | type RowsScanner interface { 8 | Close() error 9 | Scan(dest ...interface{}) error 10 | Columns() ([]string, error) 11 | ColumnTypes() ([]*sql.ColumnType, error) 12 | Err() error 13 | Next() bool 14 | } 15 | 16 | // cache is an interface for a sync.Map that is used for cache internally 17 | type cache interface { 18 | Delete(key interface{}) 19 | Load(key interface{}) (value interface{}, ok bool) 20 | LoadOrStore(key interface{}, value interface{}) (actual interface{}, loaded bool) 21 | Range(f func(key interface{}, value interface{}) bool) 22 | Store(key interface{}, value interface{}) 23 | } 24 | -------------------------------------------------------------------------------- /scanner.go: -------------------------------------------------------------------------------- 1 | package scan 2 | 3 | import ( 4 | "database/sql" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "reflect" 9 | 10 | "golang.org/x/text/cases" 11 | "golang.org/x/text/language" 12 | ) 13 | 14 | var ( 15 | // ErrTooManyColumns indicates that a select query returned multiple columns and 16 | // attempted to bind to a slice of a primitive type. For example, trying to bind 17 | // `select col1, col2 from mutable` to []string 18 | ErrTooManyColumns = errors.New("too many columns returned for primitive slice") 19 | 20 | // ErrSliceForRow occurs when trying to use Row on a slice 21 | ErrSliceForRow = errors.New("cannot scan Row into slice") 22 | 23 | // AutoClose is true when scan should automatically close Scanner when the scan 24 | // is complete. If you set it to false, then you must defer rows.Close() manually 25 | AutoClose = true 26 | 27 | // OnAutoCloseError can be used to log errors which are returned from rows.Close() 28 | // By default this is a NOOP function 29 | OnAutoCloseError = func(error) {} 30 | 31 | // ScannerMapper transforms database field names into struct/map field names 32 | // E.g. you can set function for convert snake_case into CamelCase 33 | ScannerMapper = func(name string) string { return cases.Title(language.English).String(name) } 34 | ) 35 | 36 | // Row scans a single row into a single variable. It requires that you use 37 | // db.Query and not db.QueryRow, because QueryRow does not return column names. 38 | // There is no performance impact in using one over the other. QueryRow only 39 | // defers returning err until Scan is called, which is an unnecessary 40 | // optimization for this library. 41 | func Row(v interface{}, r RowsScanner) error { 42 | if AutoClose { 43 | defer closeRows(r) 44 | } 45 | 46 | return row(v, r, false) 47 | } 48 | 49 | // RowStrict scans a single row into a single variable. It is identical to 50 | // Row, but it ignores fields that do not have a db tag 51 | func RowStrict(v interface{}, r RowsScanner) error { 52 | if AutoClose { 53 | defer closeRows(r) 54 | } 55 | 56 | return row(v, r, true) 57 | } 58 | 59 | func row(v interface{}, r RowsScanner, strict bool) error { 60 | vType := reflect.TypeOf(v) 61 | if k := vType.Kind(); k != reflect.Ptr { 62 | return fmt.Errorf("%q must be a pointer: %w", k.String(), ErrNotAPointer) 63 | } 64 | 65 | vType = vType.Elem() 66 | vVal := reflect.ValueOf(v).Elem() 67 | if vType.Kind() == reflect.Slice { 68 | return ErrSliceForRow 69 | } 70 | 71 | sl := reflect.New(reflect.SliceOf(vType)) 72 | err := rows(sl.Interface(), r, strict) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | sl = sl.Elem() 78 | 79 | if sl.Len() == 0 { 80 | return sql.ErrNoRows 81 | } 82 | 83 | vVal.Set(sl.Index(0)) 84 | 85 | return nil 86 | } 87 | 88 | // Rows scans sql rows into a slice (v) 89 | func Rows(v interface{}, r RowsScanner) (outerr error) { 90 | if AutoClose { 91 | defer closeRows(r) 92 | } 93 | 94 | return rows(v, r, false) 95 | } 96 | 97 | // RowsStrict scans sql rows into a slice (v) only using db tags 98 | func RowsStrict(v interface{}, r RowsScanner) (outerr error) { 99 | if AutoClose { 100 | defer closeRows(r) 101 | } 102 | 103 | return rows(v, r, true) 104 | } 105 | 106 | func rows(v interface{}, r RowsScanner, strict bool) (outerr error) { 107 | vType := reflect.TypeOf(v) 108 | if k := vType.Kind(); k != reflect.Ptr { 109 | return fmt.Errorf("%q must be a pointer: %w", k.String(), ErrNotAPointer) 110 | } 111 | sliceType := vType.Elem() 112 | if reflect.Slice != sliceType.Kind() { 113 | return fmt.Errorf("%q must be a slice: %w", sliceType.String(), ErrNotASlicePointer) 114 | } 115 | 116 | sliceVal := reflect.Indirect(reflect.ValueOf(v)) 117 | itemType := sliceType.Elem() 118 | 119 | cols, err := r.Columns() 120 | if err != nil { 121 | return err 122 | } 123 | 124 | isPrimitive := itemType.Kind() != reflect.Struct 125 | 126 | for r.Next() { 127 | sliceItem := reflect.New(itemType).Elem() 128 | 129 | var pointers []interface{} 130 | if isPrimitive { 131 | if len(cols) > 1 { 132 | return ErrTooManyColumns 133 | } 134 | pointers = []interface{}{sliceItem.Addr().Interface()} 135 | } else { 136 | pointers = structPointers(sliceItem, cols, strict) 137 | } 138 | 139 | if len(pointers) == 0 { 140 | return nil 141 | } 142 | 143 | err := r.Scan(pointers...) 144 | if err != nil { 145 | return err 146 | } 147 | sliceVal.Set(reflect.Append(sliceVal, sliceItem)) 148 | } 149 | return r.Err() 150 | } 151 | 152 | // Initialization the tags from struct. 153 | func initFieldTag(sliceItem reflect.Value, fieldTagMap *map[string]reflect.Value) { 154 | typ := sliceItem.Type() 155 | for i := 0; i < sliceItem.NumField(); i++ { 156 | if typ.Field(i).Anonymous || typ.Field(i).Type.Kind() == reflect.Struct { 157 | // found an embedded struct 158 | sliceItemOfAnonymous := sliceItem.Field(i) 159 | initFieldTag(sliceItemOfAnonymous, fieldTagMap) 160 | } 161 | tag, ok := typ.Field(i).Tag.Lookup("db") 162 | if ok && tag != "" { 163 | (*fieldTagMap)[tag] = sliceItem.Field(i) 164 | } 165 | } 166 | } 167 | 168 | func structPointers(sliceItem reflect.Value, cols []string, strict bool) []interface{} { 169 | pointers := make([]interface{}, 0, len(cols)) 170 | fieldTag := make(map[string]reflect.Value, len(cols)) 171 | initFieldTag(sliceItem, &fieldTag) 172 | 173 | for _, colName := range cols { 174 | var fieldVal reflect.Value 175 | if v, ok := fieldTag[colName]; ok { 176 | fieldVal = v 177 | } else { 178 | if strict { 179 | fieldVal = reflect.ValueOf(nil) 180 | } else { 181 | fieldVal = sliceItem.FieldByName(ScannerMapper(colName)) 182 | } 183 | } 184 | if !fieldVal.IsValid() || !fieldVal.CanSet() { 185 | // have to add if we found a column because Scan() requires 186 | // len(cols) arguments or it will error. This way we can scan to 187 | // a useless pointer 188 | var nothing interface{} 189 | pointers = append(pointers, ¬hing) 190 | continue 191 | } 192 | 193 | pointers = append(pointers, fieldVal.Addr().Interface()) 194 | } 195 | return pointers 196 | } 197 | 198 | func closeRows(c io.Closer) { 199 | if err := c.Close(); err != nil { 200 | if OnAutoCloseError != nil { 201 | OnAutoCloseError(err) 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /values.go: -------------------------------------------------------------------------------- 1 | package scan 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "sync" 7 | ) 8 | 9 | var valuesCache cache = &sync.Map{} 10 | 11 | // Values scans a struct and returns the values associated with the columns 12 | // provided. Only simple value types are supported (i.e. Bool, Ints, Uints, 13 | // Floats, Interface, String) 14 | func Values(cols []string, v interface{}) ([]interface{}, error) { 15 | vals := make([]interface{}, len(cols)) 16 | model, err := reflectValue(v) 17 | if err != nil { 18 | return nil, fmt.Errorf("values: %w", err) 19 | } 20 | 21 | fields := loadFields(model) 22 | 23 | for i, col := range cols { 24 | j, ok := fields[col] 25 | if !ok { 26 | return nil, fmt.Errorf("field %T.%q either does not exist or is unexported: %w", v, col, ErrStructFieldMissing) 27 | } 28 | 29 | vals[i] = model.FieldByIndex(j).Interface() 30 | } 31 | return vals, nil 32 | } 33 | 34 | func loadFields(val reflect.Value) map[string][]int { 35 | if cache, cached := valuesCache.Load(val.Type()); cached { 36 | return cache.(map[string][]int) 37 | } 38 | return writeFieldsCache(val) 39 | } 40 | 41 | func writeFieldsCache(val reflect.Value) map[string][]int { 42 | m := map[string][]int{} 43 | writeFields(val, m, []int{}) 44 | valuesCache.Store(val.Type(), m) 45 | return m 46 | } 47 | 48 | func writeFields(val reflect.Value, m map[string][]int, index []int) { 49 | typ := val.Type() 50 | numfield := val.NumField() 51 | 52 | for i := 0; i < numfield; i++ { 53 | valField := val.Field(i) 54 | if !valField.CanSet() { 55 | continue 56 | } 57 | 58 | field := typ.Field(i) 59 | fieldIndex := append(index, field.Index...) 60 | 61 | if field.Type.Kind() == reflect.Struct && !isValidSqlValue(valField) { 62 | writeFields(valField, m, fieldIndex) 63 | continue 64 | } 65 | 66 | m[field.Name] = fieldIndex 67 | if tag, ok := field.Tag.Lookup(dbTag); ok { 68 | m[tag] = fieldIndex 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2012-2016 Dave Collins 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypass.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is not running on Google App Engine, compiled by GopherJS, and 17 | // "-tags safe" is not added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // Go versions prior to 1.4 are disabled because they use a different layout 20 | // for interfaces which make the implementation of unsafeReflectValue more complex. 21 | // +build !js,!appengine,!safe,!disableunsafe,go1.4 22 | 23 | package spew 24 | 25 | import ( 26 | "reflect" 27 | "unsafe" 28 | ) 29 | 30 | const ( 31 | // UnsafeDisabled is a build-time constant which specifies whether or 32 | // not access to the unsafe package is available. 33 | UnsafeDisabled = false 34 | 35 | // ptrSize is the size of a pointer on the current arch. 36 | ptrSize = unsafe.Sizeof((*byte)(nil)) 37 | ) 38 | 39 | type flag uintptr 40 | 41 | var ( 42 | // flagRO indicates whether the value field of a reflect.Value 43 | // is read-only. 44 | flagRO flag 45 | 46 | // flagAddr indicates whether the address of the reflect.Value's 47 | // value may be taken. 48 | flagAddr flag 49 | ) 50 | 51 | // flagKindMask holds the bits that make up the kind 52 | // part of the flags field. In all the supported versions, 53 | // it is in the lower 5 bits. 54 | const flagKindMask = flag(0x1f) 55 | 56 | // Different versions of Go have used different 57 | // bit layouts for the flags type. This table 58 | // records the known combinations. 59 | var okFlags = []struct { 60 | ro, addr flag 61 | }{{ 62 | // From Go 1.4 to 1.5 63 | ro: 1 << 5, 64 | addr: 1 << 7, 65 | }, { 66 | // Up to Go tip. 67 | ro: 1<<5 | 1<<6, 68 | addr: 1 << 8, 69 | }} 70 | 71 | var flagValOffset = func() uintptr { 72 | field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") 73 | if !ok { 74 | panic("reflect.Value has no flag field") 75 | } 76 | return field.Offset 77 | }() 78 | 79 | // flagField returns a pointer to the flag field of a reflect.Value. 80 | func flagField(v *reflect.Value) *flag { 81 | return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset)) 82 | } 83 | 84 | // unsafeReflectValue converts the passed reflect.Value into a one that bypasses 85 | // the typical safety restrictions preventing access to unaddressable and 86 | // unexported data. It works by digging the raw pointer to the underlying 87 | // value out of the protected value and generating a new unprotected (unsafe) 88 | // reflect.Value to it. 89 | // 90 | // This allows us to check for implementations of the Stringer and error 91 | // interfaces to be used for pretty printing ordinarily unaddressable and 92 | // inaccessible values such as unexported struct fields. 93 | func unsafeReflectValue(v reflect.Value) reflect.Value { 94 | if !v.IsValid() || (v.CanInterface() && v.CanAddr()) { 95 | return v 96 | } 97 | flagFieldPtr := flagField(&v) 98 | *flagFieldPtr &^= flagRO 99 | *flagFieldPtr |= flagAddr 100 | return v 101 | } 102 | 103 | // Sanity checks against future reflect package changes 104 | // to the type or semantics of the Value.flag field. 105 | func init() { 106 | field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") 107 | if !ok { 108 | panic("reflect.Value has no flag field") 109 | } 110 | if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() { 111 | panic("reflect.Value flag field has changed kind") 112 | } 113 | type t0 int 114 | var t struct { 115 | A t0 116 | // t0 will have flagEmbedRO set. 117 | t0 118 | // a will have flagStickyRO set 119 | a t0 120 | } 121 | vA := reflect.ValueOf(t).FieldByName("A") 122 | va := reflect.ValueOf(t).FieldByName("a") 123 | vt0 := reflect.ValueOf(t).FieldByName("t0") 124 | 125 | // Infer flagRO from the difference between the flags 126 | // for the (otherwise identical) fields in t. 127 | flagPublic := *flagField(&vA) 128 | flagWithRO := *flagField(&va) | *flagField(&vt0) 129 | flagRO = flagPublic ^ flagWithRO 130 | 131 | // Infer flagAddr from the difference between a value 132 | // taken from a pointer and not. 133 | vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A") 134 | flagNoPtr := *flagField(&vA) 135 | flagPtr := *flagField(&vPtrA) 136 | flagAddr = flagNoPtr ^ flagPtr 137 | 138 | // Check that the inferred flags tally with one of the known versions. 139 | for _, f := range okFlags { 140 | if flagRO == f.ro && flagAddr == f.addr { 141 | return 142 | } 143 | } 144 | panic("reflect.Value read-only flag has changed semantics") 145 | } 146 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypasssafe.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is running on Google App Engine, compiled by GopherJS, or 17 | // "-tags safe" is added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build js appengine safe disableunsafe !go1.4 20 | 21 | package spew 22 | 23 | import "reflect" 24 | 25 | const ( 26 | // UnsafeDisabled is a build-time constant which specifies whether or 27 | // not access to the unsafe package is available. 28 | UnsafeDisabled = true 29 | ) 30 | 31 | // unsafeReflectValue typically converts the passed reflect.Value into a one 32 | // that bypasses the typical safety restrictions preventing access to 33 | // unaddressable and unexported data. However, doing this relies on access to 34 | // the unsafe package. This is a stub version which simply returns the passed 35 | // reflect.Value when the unsafe package is not available. 36 | func unsafeReflectValue(v reflect.Value) reflect.Value { 37 | return v 38 | } 39 | -------------------------------------------------------------------------------- /vendor/github.com/pmezard/go-difflib/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Patrick Mezard 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | The names of its contributors may not be used to endorse or promote 14 | products derived from this software without specific prior written 15 | permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 18 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/driver/conn.go: -------------------------------------------------------------------------------- 1 | package ramsql 2 | 3 | import ( 4 | "database/sql/driver" 5 | "sync" 6 | 7 | "github.com/proullon/ramsql/engine/log" 8 | "github.com/proullon/ramsql/engine/protocol" 9 | ) 10 | 11 | // Conn implements sql/driver Conn interface 12 | type Conn struct { 13 | // Mutex is locked when a Statement is created 14 | // then released on Statement.Exec or Statement.Query 15 | mutex sync.Mutex 16 | 17 | // Socket is the network connection to RamSQL engine 18 | conn protocol.DriverConn 19 | // socket net.Conn 20 | 21 | // This conn belongs to this server 22 | parent *Server 23 | } 24 | 25 | func newConn(conn protocol.DriverConn, parent *Server) driver.Conn { 26 | parent.openingConn() 27 | return &Conn{conn: conn, parent: parent} 28 | } 29 | 30 | // Prepare returns a prepared statement, bound to this connection. 31 | func (c *Conn) Prepare(query string) (driver.Stmt, error) { 32 | 33 | stmt := prepareStatement(c, query) 34 | 35 | return stmt, nil 36 | } 37 | 38 | // Close invalidates and potentially stops any current 39 | // prepared statements and transactions, marking this 40 | // connection as no longer in use. 41 | // 42 | // Because the sql package maintains a free pool of 43 | // connections and only calls Close when there's a surplus of 44 | // idle connections, it shouldn't be necessary for drivers to 45 | // do their own connection caching. 46 | func (c *Conn) Close() error { 47 | log.Debug("Conn.Close") 48 | c.conn.Close() 49 | 50 | if c.parent != nil { 51 | c.parent.closingConn() 52 | } 53 | 54 | return nil 55 | } 56 | 57 | // Begin starts and returns a new transaction. 58 | func (c *Conn) Begin() (driver.Tx, error) { 59 | 60 | tx := Tx{ 61 | conn: c, 62 | } 63 | 64 | return &tx, nil 65 | } 66 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/driver/driver.go: -------------------------------------------------------------------------------- 1 | package ramsql 2 | 3 | import ( 4 | "database/sql" 5 | "database/sql/driver" 6 | "errors" 7 | "strings" 8 | "sync" 9 | "time" 10 | 11 | "github.com/proullon/ramsql/engine" 12 | "github.com/proullon/ramsql/engine/log" 13 | "github.com/proullon/ramsql/engine/protocol" 14 | ) 15 | 16 | func init() { 17 | sql.Register("ramsql", NewDriver()) 18 | log.SetLevel(log.WarningLevel) 19 | } 20 | 21 | // Server structs holds engine for each sql.DB instance. 22 | // This way a sql.DB cann open as much connection to engine as wanted 23 | // without colliding with another engine (during tests for example) 24 | // with the unique constraint of providing a unique DataSourceName 25 | type Server struct { 26 | endpoint protocol.DriverEndpoint 27 | server *engine.Engine 28 | 29 | // Kill server on last connection closing 30 | sync.Mutex 31 | connCount int64 32 | } 33 | 34 | // Driver is the driver entrypoint, 35 | // implementing database/sql/driver interface 36 | type Driver struct { 37 | // Mutex protect the map of Server 38 | sync.Mutex 39 | // Holds all matching sql.DB instances of RamSQL engine 40 | servers map[string]*Server 41 | } 42 | 43 | // NewDriver creates a driver object 44 | func NewDriver() *Driver { 45 | d := &Driver{} 46 | d.servers = make(map[string]*Server) 47 | return d 48 | } 49 | 50 | type connConf struct { 51 | Proto string 52 | Addr string 53 | Laddr string 54 | Db string 55 | Password string 56 | User string 57 | Timeout time.Duration 58 | } 59 | 60 | // Open return an active connection so RamSQL server 61 | // If there is no connection in pool, start a new server. 62 | // After first instantiation of the server, 63 | func (rs *Driver) Open(dsn string) (conn driver.Conn, err error) { 64 | rs.Lock() 65 | 66 | connConf, err := parseConnectionURI(dsn) 67 | if err != nil { 68 | rs.Unlock() 69 | return nil, err 70 | } 71 | 72 | dsnServer, exist := rs.servers[dsn] 73 | if !exist { 74 | driverEndpoint, engineEndpoint, err := endpoints(connConf) 75 | if err != nil { 76 | rs.Unlock() 77 | return nil, err 78 | } 79 | 80 | server, err := engine.New(engineEndpoint) 81 | if err != nil { 82 | rs.Unlock() 83 | return nil, err 84 | } 85 | 86 | driverConn, err := driverEndpoint.New(dsn) 87 | if err != nil { 88 | rs.Unlock() 89 | return nil, err 90 | } 91 | 92 | s := &Server{ 93 | endpoint: driverEndpoint, 94 | server: server, 95 | } 96 | rs.servers[dsn] = s 97 | 98 | rs.Unlock() 99 | return newConn(driverConn, s), nil 100 | } 101 | 102 | rs.Unlock() 103 | driverConn, err := dsnServer.endpoint.New(dsn) 104 | return newConn(driverConn, dsnServer), err 105 | } 106 | 107 | func endpoints(conf *connConf) (protocol.DriverEndpoint, protocol.EngineEndpoint, error) { 108 | switch conf.Proto { 109 | default: 110 | driver, engine := protocol.NewChannelEndpoints() 111 | return driver, engine, nil 112 | } 113 | } 114 | 115 | // The uri need to have the following syntax: 116 | // 117 | // [PROTOCOL_SPECFIIC*]DBNAME/USER/PASSWD 118 | // 119 | // where protocol spercific part may be empty (this means connection to 120 | // local server using default protocol). Currently possible forms: 121 | // 122 | // DBNAME/USER/PASSWD 123 | // unix:SOCKPATH*DBNAME/USER/PASSWD 124 | // unix:SOCKPATH,OPTIONS*DBNAME/USER/PASSWD 125 | // tcp:ADDR*DBNAME/USER/PASSWD 126 | // tcp:ADDR,OPTIONS*DBNAME/USER/PASSWD 127 | // cloudsql:INSTANCE*DBNAME/USER/PASSWD 128 | // 129 | // OPTIONS can contain comma separated list of options in form: 130 | // opt1=VAL1,opt2=VAL2,boolopt3,boolopt4 131 | // Currently implemented options: 132 | // laddr - local address/port (eg. 1.2.3.4:0) 133 | // timeout - connect timeout in format accepted by time.ParseDuration 134 | func parseConnectionURI(uri string) (*connConf, error) { 135 | c := &connConf{} 136 | 137 | if uri == "" { 138 | log.Info("Empty data source name, using 'default' engine") 139 | uri = "default" 140 | } 141 | 142 | pd := strings.SplitN(uri, "*", 2) 143 | if len(pd) == 2 { 144 | // Parse protocol part of URI 145 | p := strings.SplitN(pd[0], ":", 2) 146 | if len(p) != 2 { 147 | // Wrong protocol part of URI 148 | return c, nil 149 | } 150 | c.Proto = p[0] 151 | options := strings.Split(p[1], ",") 152 | c.Addr = options[0] 153 | for _, o := range options[1:] { 154 | kv := strings.SplitN(o, "=", 2) 155 | var k, v string 156 | if len(kv) == 2 { 157 | k, v = kv[0], kv[1] 158 | } else { 159 | k, v = o, "true" 160 | } 161 | switch k { 162 | case "laddr": 163 | c.Laddr = v 164 | case "timeout": 165 | to, err := time.ParseDuration(v) 166 | if err != nil { 167 | return nil, err 168 | } 169 | c.Timeout = to 170 | default: 171 | return nil, errors.New("Unknown option: " + k) 172 | } 173 | } 174 | // Remove protocol part 175 | pd = pd[1:] 176 | } 177 | // Parse database part of URI 178 | dup := strings.SplitN(pd[0], "/", 3) 179 | if len(dup) != 3 { 180 | // Wrong database part of URI 181 | return c, nil 182 | } 183 | 184 | c.Db = dup[0] 185 | c.User = dup[1] 186 | c.Password = dup[2] 187 | return c, nil 188 | } 189 | 190 | func (s *Server) openingConn() { 191 | 192 | s.Lock() 193 | defer s.Unlock() 194 | s.connCount++ 195 | } 196 | 197 | func (s *Server) closingConn() { 198 | s.Lock() 199 | defer s.Unlock() 200 | s.connCount-- 201 | 202 | if s.connCount == 0 { 203 | s.server.Stop() 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/driver/init.go: -------------------------------------------------------------------------------- 1 | package ramsql 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | "path" 9 | "strings" 10 | ) 11 | 12 | // InitSchemas execute each query in provided sql file 13 | // Expected sql file path into $GOPATH/src 14 | func InitSchemas(db *sql.DB, sqlfile string) error { 15 | gopath := os.Getenv("GOPATH") 16 | 17 | content, err := ioutil.ReadFile(path.Join(gopath, "src", sqlfile)) 18 | if err != nil { 19 | return err 20 | } 21 | 22 | queries := strings.Split(string(content), ";") 23 | 24 | for _, q := range queries { 25 | q = strings.Trim(q, "\n") 26 | 27 | if q == "" { 28 | continue 29 | } 30 | 31 | _, err := db.Exec(q) 32 | if err != nil { 33 | return fmt.Errorf("Query '%s': %s", q, err) 34 | } 35 | 36 | } 37 | 38 | return nil 39 | } 40 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/driver/result.go: -------------------------------------------------------------------------------- 1 | package ramsql 2 | 3 | // Result is the type returned by sql/driver after an Exec statement. 4 | type Result struct { 5 | err error 6 | lastInsertedID int64 7 | rowsAffected int64 8 | } 9 | 10 | func newResult(lastInsertedID int64, rowsAffected int64) *Result { 11 | r := &Result{ 12 | lastInsertedID: lastInsertedID, 13 | rowsAffected: rowsAffected, 14 | } 15 | 16 | return r 17 | } 18 | 19 | // LastInsertId returns the database's auto-generated ID 20 | // after, for example, an INSERT into a table with primary 21 | // key. 22 | func (r *Result) LastInsertId() (int64, error) { 23 | if r.err != nil { 24 | return 0, r.err 25 | } 26 | return r.lastInsertedID, nil 27 | } 28 | 29 | // RowsAffected returns the number of rows affected by the 30 | // query. 31 | func (r *Result) RowsAffected() (int64, error) { 32 | if r.err != nil { 33 | return 0, r.err 34 | } 35 | return r.rowsAffected, nil 36 | } 37 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/driver/rows.go: -------------------------------------------------------------------------------- 1 | package ramsql 2 | 3 | import ( 4 | "database/sql/driver" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "sync" 9 | 10 | "github.com/proullon/ramsql/engine/log" 11 | "github.com/proullon/ramsql/engine/parser" 12 | ) 13 | 14 | // Rows implements the sql/driver Rows interface 15 | type Rows struct { 16 | rowsChannel chan []string 17 | columns []string 18 | 19 | sync.Mutex 20 | } 21 | 22 | func newRows(channel chan []string) *Rows { 23 | r := &Rows{rowsChannel: channel} 24 | c, ok := <-channel 25 | if !ok { 26 | log.Critical("Cannot receive column names from channel") 27 | return nil 28 | } 29 | 30 | r.columns = c 31 | return r 32 | } 33 | 34 | // Columns returns the names of the columns. The number of 35 | // columns of the result is inferred from the length of the 36 | // slice. If a particular column name isn't known, an empty 37 | // string should be returned for that entry. 38 | func (r *Rows) Columns() []string { 39 | return r.columns 40 | } 41 | 42 | // Close closes the rows iterator. 43 | func (r *Rows) Close() error { 44 | r.Lock() 45 | defer r.Unlock() 46 | 47 | if r.rowsChannel == nil { 48 | return nil 49 | } 50 | 51 | _, ok := <-r.rowsChannel 52 | if !ok { 53 | return nil 54 | } 55 | 56 | // Tels UnlimitedRowsChannel to close itself 57 | //r.rowsChannel <- []string{} 58 | r.rowsChannel = nil 59 | return nil 60 | } 61 | 62 | // Next is called to populate the next row of data into 63 | // the provided slice. The provided slice will be the same 64 | // size as the Columns() are wide. 65 | // 66 | // The dest slice may be populated only with 67 | // a driver Value type, but excluding string. 68 | // All string values must be converted to []byte. 69 | // 70 | // Next should return io.EOF when there are no more rows. 71 | func (r *Rows) Next(dest []driver.Value) (err error) { 72 | r.Lock() 73 | defer r.Unlock() 74 | 75 | if r.rowsChannel == nil { 76 | return io.EOF 77 | } 78 | 79 | value, ok := <-r.rowsChannel 80 | if !ok { 81 | r.rowsChannel = nil 82 | return io.EOF 83 | } 84 | 85 | if len(dest) < len(value) { 86 | return fmt.Errorf("slice too short (%d slots for %d values)", len(dest), len(value)) 87 | } 88 | 89 | for i, v := range value { 90 | if v == "" { 91 | dest[i] = nil 92 | continue 93 | } 94 | 95 | // TODO: make rowsChannel send virtualRows, 96 | // so we have the type and don't blindy try to parse date here 97 | if t, err := parser.ParseDate(string(v)); err == nil { 98 | dest[i] = *t 99 | } else { 100 | 101 | dest[i] = []byte(v) 102 | } 103 | } 104 | 105 | return nil 106 | } 107 | 108 | func (r *Rows) setColumns(columns []string) { 109 | r.columns = columns 110 | } 111 | 112 | func assignValue(s string, v driver.Value) error { 113 | dest, ok := v.(*string) 114 | if !ok { 115 | err := errors.New("cannot assign value") 116 | return err 117 | } 118 | 119 | *dest = s 120 | return nil 121 | } 122 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/driver/stmt.go: -------------------------------------------------------------------------------- 1 | package ramsql 2 | 3 | import ( 4 | "database/sql/driver" 5 | "fmt" 6 | "regexp" 7 | "strconv" 8 | "strings" 9 | 10 | "github.com/proullon/ramsql/engine/log" 11 | ) 12 | 13 | // Stmt implements the Statement interface of sql/driver 14 | type Stmt struct { 15 | conn *Conn 16 | query string 17 | numInput int 18 | } 19 | 20 | func countArguments(query string) int { 21 | for id := 1; id > 0; id++ { 22 | sep := fmt.Sprintf("$%d", id) 23 | if strings.Count(query, sep) == 0 { 24 | return id - 1 25 | } 26 | } 27 | 28 | return -1 29 | } 30 | 31 | func prepareStatement(c *Conn, query string) *Stmt { 32 | 33 | // Parse number of arguments here 34 | // Should handler either Postgres ($*) or ODBC (?) parameter markers 35 | numInput := strings.Count(query, "?") 36 | // if numInput == 0, maybe it's Postgres format 37 | if numInput == 0 { 38 | numInput = countArguments(query) 39 | } 40 | 41 | // Create statement 42 | stmt := &Stmt{ 43 | conn: c, 44 | query: query, 45 | numInput: numInput, 46 | } 47 | 48 | stmt.conn.mutex.Lock() 49 | return stmt 50 | } 51 | 52 | // Close closes the statement. 53 | // 54 | // As of Go 1.1, a Stmt will not be closed if it's in use 55 | // by any queries. 56 | func (s *Stmt) Close() error { 57 | return fmt.Errorf("Not implemented.") 58 | } 59 | 60 | // NumInput returns the number of placeholder parameters. 61 | // 62 | // If NumInput returns >= 0, the sql package will sanity check 63 | // argument counts from callers and return errors to the caller 64 | // before the statement's Exec or Query methods are called. 65 | // 66 | // NumInput may also return -1, if the driver doesn't know 67 | // its number of placeholders. In that case, the sql package 68 | // will not sanity check Exec or Query argument counts. 69 | func (s *Stmt) NumInput() int { 70 | return s.numInput 71 | } 72 | 73 | // Exec executes a query that doesn't return rows, such 74 | // as an INSERT or UPDATE. 75 | func (s *Stmt) Exec(args []driver.Value) (r driver.Result, err error) { 76 | defer func() { 77 | if r := recover(); r != nil { 78 | err = fmt.Errorf("fatalf error: %s", r) 79 | return 80 | } 81 | }() 82 | defer s.conn.mutex.Unlock() 83 | 84 | if s.query == "" { 85 | return nil, fmt.Errorf("empty statement") 86 | } 87 | 88 | var finalQuery string 89 | 90 | // replace $* by arguments in query string 91 | finalQuery = replaceArguments(s.query, args) 92 | log.Info("Exec <%s>\n", finalQuery) 93 | 94 | // Send query to server 95 | err = s.conn.conn.WriteExec(finalQuery) 96 | if err != nil { 97 | log.Warning("Exec: Cannot send query to server: %s", err) 98 | return nil, fmt.Errorf("Cannot send query to server: %s", err) 99 | } 100 | 101 | // Get answer from server 102 | lastInsertedID, rowsAffected, err := s.conn.conn.ReadResult() 103 | if err != nil { 104 | return nil, err 105 | } 106 | 107 | // Create a driver.Result 108 | return newResult(lastInsertedID, rowsAffected), nil 109 | } 110 | 111 | // Query executes a query that may return rows, such as a 112 | // SELECT. 113 | func (s *Stmt) Query(args []driver.Value) (r driver.Rows, err error) { 114 | defer func() { 115 | if r := recover(); r != nil { 116 | err = fmt.Errorf("fatalf error: %s", r) 117 | return 118 | } 119 | }() 120 | defer s.conn.mutex.Unlock() 121 | 122 | if s.query == "" { 123 | return nil, fmt.Errorf("empty statement") 124 | } 125 | 126 | finalQuery := replaceArguments(s.query, args) 127 | log.Info("Query < %s >\n", finalQuery) 128 | err = s.conn.conn.WriteQuery(finalQuery) 129 | if err != nil { 130 | return nil, err 131 | } 132 | 133 | rowsChannel, err := s.conn.conn.ReadRows() 134 | if err != nil { 135 | return nil, err 136 | } 137 | 138 | r = newRows(rowsChannel) 139 | return r, nil 140 | } 141 | 142 | // replace $* by arguments in query string 143 | func replaceArguments(query string, args []driver.Value) string { 144 | 145 | holder := regexp.MustCompile(`[^\$]\$[0-9]+`) 146 | replacedQuery := "" 147 | 148 | if strings.Count(query, "?") == len(args) { 149 | return replaceArgumentsODBC(query, args) 150 | } 151 | 152 | allloc := holder.FindAllIndex([]byte(query), -1) 153 | queryB := []byte(query) 154 | for i, loc := range allloc { 155 | match := queryB[loc[0]+1 : loc[1]] 156 | 157 | index, err := strconv.Atoi(string(match[1:])) 158 | if err != nil { 159 | log.Warning("Matched %s as a placeholder but cannot get index: %s\n", match, err) 160 | return query 161 | } 162 | 163 | var v string 164 | if args[index-1] == nil { 165 | v = "null" 166 | } else if b, ok := args[index-1].([]byte); ok { 167 | v = fmt.Sprintf("$$%s$$", b) 168 | } else { 169 | v = fmt.Sprintf("$$%v$$", args[index-1]) 170 | } 171 | if i == 0 { 172 | replacedQuery = fmt.Sprintf("%s%s%s", replacedQuery, string(queryB[:loc[0]+1]), v) 173 | } else { 174 | replacedQuery = fmt.Sprintf("%s%s%s", replacedQuery, string(queryB[allloc[i-1][1]:loc[0]+1]), v) 175 | } 176 | } 177 | // add remaining query 178 | replacedQuery = fmt.Sprintf("%s%s", replacedQuery, string(queryB[allloc[len(allloc)-1][1]:])) 179 | 180 | return replacedQuery 181 | } 182 | 183 | func replaceArgumentsODBC(query string, args []driver.Value) string { 184 | finalQuery := &strings.Builder{} 185 | 186 | queryParts := strings.Split(query, "?") 187 | 188 | finalQuery.WriteString(queryParts[0]) 189 | 190 | for i := range args { 191 | var arg string 192 | switch v := args[i].(type) { 193 | case string: 194 | if !strings.HasSuffix(query, "'") { 195 | arg = fmt.Sprintf("$$%s$$", v) 196 | } 197 | case []byte: 198 | if !strings.HasSuffix(query, "'") { 199 | arg = fmt.Sprintf("$$%s$$", v) 200 | } 201 | default: 202 | arg = fmt.Sprintf("%v", v) 203 | } 204 | finalQuery.WriteString(arg) 205 | finalQuery.WriteString(queryParts[i+1]) 206 | } 207 | 208 | return finalQuery.String() 209 | } 210 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/driver/tx.go: -------------------------------------------------------------------------------- 1 | package ramsql 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Tx implements SQL transaction method 8 | type Tx struct { 9 | conn *Conn 10 | } 11 | 12 | // Commit the transaction on server 13 | func (t *Tx) Commit() error { 14 | // TODO: Not implemented 15 | return nil 16 | } 17 | 18 | // Rollback all changes 19 | func (t *Tx) Rollback() error { 20 | return fmt.Errorf("Not implemented") 21 | } 22 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/attribute.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "time" 7 | 8 | "github.com/proullon/ramsql/engine/log" 9 | "github.com/proullon/ramsql/engine/parser" 10 | ) 11 | 12 | // Domain is the set of allowable values for an Attribute. 13 | type Domain struct { 14 | } 15 | 16 | // Attribute is a named column of a relation 17 | // AKA Field 18 | // AKA Column 19 | type Attribute struct { 20 | name string 21 | typeName string 22 | typeInstance interface{} 23 | defaultValue interface{} 24 | domain Domain 25 | autoIncrement bool 26 | unique bool 27 | } 28 | 29 | func parseAttribute(decl *parser.Decl) (Attribute, error) { 30 | attr := Attribute{} 31 | 32 | // Attribute name 33 | if decl.Token != parser.StringToken { 34 | return attr, fmt.Errorf("engine: expected attribute name, got %v", decl.Token) 35 | } 36 | attr.name = decl.Lexeme 37 | 38 | // Attribute type 39 | if len(decl.Decl) < 1 { 40 | return attr, fmt.Errorf("Attribute %s has no type", decl.Lexeme) 41 | } 42 | if decl.Decl[0].Token != parser.StringToken { 43 | return attr, fmt.Errorf("engine: expected attribute type, got %v:%v", decl.Decl[0].Token, decl.Decl[0].Lexeme) 44 | } 45 | attr.typeName = decl.Decl[0].Lexeme 46 | 47 | // Maybe domain and special thing like primary key 48 | typeDecl := decl.Decl[1:] 49 | for i := range typeDecl { 50 | log.Debug("Got %v for %s %s", typeDecl[i], attr.name, attr.typeName) 51 | if typeDecl[i].Token == parser.AutoincrementToken { 52 | attr.autoIncrement = true 53 | } 54 | 55 | if typeDecl[i].Token == parser.DefaultToken { 56 | log.Debug("we get a default value for %s: %s!\n", attr.name, typeDecl[i].Decl[0].Lexeme) 57 | switch typeDecl[i].Decl[0].Token { 58 | case parser.LocalTimestampToken, parser.NowToken: 59 | log.Debug("Setting default value to NOW() func !\n") 60 | attr.defaultValue = func() interface{} { return time.Now().Format(parser.DateLongFormat) } 61 | default: 62 | log.Debug("Setting default value to '%v'\n", typeDecl[i].Decl[0].Lexeme) 63 | attr.defaultValue = typeDecl[i].Decl[0].Lexeme 64 | } 65 | } 66 | 67 | // Check if attribute is unique 68 | if typeDecl[i].Token == parser.UniqueToken { 69 | attr.unique = true 70 | } 71 | 72 | } 73 | 74 | if strings.ToLower(attr.typeName) == "bigserial" { 75 | attr.autoIncrement = true 76 | } 77 | 78 | return attr, nil 79 | } 80 | 81 | // NewAttribute initialize a new Attribute struct 82 | func NewAttribute(name string, typeName string, autoIncrement bool) Attribute { 83 | a := Attribute{ 84 | name: name, 85 | typeName: typeName, 86 | autoIncrement: autoIncrement, 87 | } 88 | 89 | return a 90 | } 91 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/condition.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/proullon/ramsql/engine/parser" 7 | "github.com/proullon/ramsql/engine/protocol" 8 | ) 9 | 10 | func ifExecutor(e *Engine, ifDecl *parser.Decl, conn protocol.EngineConn) error { 11 | 12 | if len(ifDecl.Decl) == 0 { 13 | return fmt.Errorf("malformed condition") 14 | } 15 | 16 | if e.opsExecutors[ifDecl.Decl[0].Token] != nil { 17 | return e.opsExecutors[ifDecl.Decl[0].Token](e, ifDecl.Decl[0], conn) 18 | } 19 | 20 | return fmt.Errorf("error near %v, unknown keyword", ifDecl.Decl[0].Lexeme) 21 | } 22 | 23 | func notExecutor(e *Engine, tableDecl *parser.Decl, conn protocol.EngineConn) error { 24 | return nil 25 | } 26 | 27 | func existsExecutor(e *Engine, tableDecl *parser.Decl, conn protocol.EngineConn) error { 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/delete.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | // "errors" 5 | "fmt" 6 | 7 | "github.com/proullon/ramsql/engine/log" 8 | "github.com/proullon/ramsql/engine/parser" 9 | "github.com/proullon/ramsql/engine/protocol" 10 | ) 11 | 12 | func deleteExecutor(e *Engine, deleteDecl *parser.Decl, conn protocol.EngineConn) error { 13 | log.Debug("deleteExecutor") 14 | 15 | // get tables to be deleted 16 | tables := fromExecutor(deleteDecl.Decl[0]) 17 | 18 | // If len is 1, it means no predicates so truncate table 19 | if len(deleteDecl.Decl) == 1 { 20 | return truncateTable(e, tables[0], conn) 21 | } 22 | 23 | // get WHERE declaration 24 | predicates, err := whereExecutor(deleteDecl.Decl[1], tables[0].name) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | // and delete 30 | return deleteRows(e, tables, conn, predicates) 31 | } 32 | 33 | func deleteRows(e *Engine, tables []*Table, conn protocol.EngineConn, predicates []Predicate) error { 34 | var rowsDeleted int64 35 | 36 | r := e.relation(tables[0].name) 37 | if r == nil { 38 | return fmt.Errorf("Table %s not found", tables[0].name) 39 | } 40 | r.Lock() 41 | defer r.Unlock() 42 | 43 | var ok, res bool 44 | var err error 45 | lenRows := len(r.rows) 46 | for i := 0; i < lenRows; i++ { 47 | ok = true 48 | // If the row validate all predicates, write it 49 | for _, predicate := range predicates { 50 | if res, err = predicate.Evaluate(r.rows[i], r.table); err != nil { 51 | return err 52 | } 53 | if res == false { 54 | ok = false 55 | continue 56 | } 57 | } 58 | 59 | if ok { 60 | switch i { 61 | case 0: 62 | r.rows = r.rows[1:] 63 | case lenRows - 1: 64 | r.rows = r.rows[:lenRows-1] 65 | default: 66 | r.rows = append(r.rows[:i], r.rows[i+1:]...) 67 | i-- 68 | } 69 | lenRows-- 70 | rowsDeleted++ 71 | } 72 | } 73 | 74 | return conn.WriteResult(0, rowsDeleted) 75 | } 76 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/distinct.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/proullon/ramsql/engine/log" 5 | "github.com/proullon/ramsql/engine/protocol" 6 | ) 7 | 8 | type distinct struct { 9 | realConn protocol.EngineConn 10 | seen seen 11 | len int 12 | } 13 | 14 | func distinctedConn(conn protocol.EngineConn, len int) protocol.EngineConn { 15 | return &distinct{ 16 | realConn: conn, 17 | len: len, 18 | seen: make(seen), 19 | } 20 | } 21 | 22 | // Not needed 23 | func (l *distinct) ReadStatement() (string, error) { 24 | log.Debug("limit.ReadStatement: should not be used\n") 25 | return "", nil 26 | } 27 | 28 | // Not needed 29 | func (l *distinct) WriteResult(last int64, ra int64) error { 30 | log.Debug("limit.WriteResult: should not be used\n") 31 | return nil 32 | } 33 | 34 | func (l *distinct) WriteError(err error) error { 35 | return l.realConn.WriteError(err) 36 | } 37 | 38 | func (l *distinct) WriteRowHeader(header []string) error { 39 | if l.len > 0 { 40 | // Postgres returns only columns outside of DISTINCT ON 41 | return l.realConn.WriteRowHeader(header[l.len:]) 42 | } 43 | return l.realConn.WriteRowHeader(header) 44 | } 45 | 46 | func (l *distinct) WriteRow(row []string) error { 47 | if l.len > 0 { 48 | if l.seen.exists(row[:l.len]) { 49 | return nil 50 | } 51 | // Postgres returns only columns outside of DISTINCT ON 52 | return l.realConn.WriteRow(row[l.len:]) 53 | } else { 54 | if l.seen.exists(row) { 55 | return nil 56 | } 57 | return l.realConn.WriteRow(row) 58 | } 59 | } 60 | 61 | func (l *distinct) WriteRowEnd() error { 62 | return l.realConn.WriteRowEnd() 63 | } 64 | 65 | func (l *distinct) equalRows(a, b []string) bool { 66 | if l.len > 0 { 67 | if len(a) < l.len || len(b) < l.len { 68 | return false 69 | } 70 | 71 | for idx := 0; idx < l.len; idx++ { 72 | if a[idx] != b[idx] { 73 | return false 74 | } 75 | } 76 | 77 | return true 78 | } 79 | 80 | if len(a) != len(b) { 81 | return false 82 | } 83 | for idx := range a { 84 | if a[idx] != b[idx] { 85 | return false 86 | } 87 | } 88 | 89 | return true 90 | } 91 | 92 | type seen map[string]seen 93 | 94 | func (s seen) exists(r []string) bool { 95 | if c, ok := s[r[0]]; ok { 96 | if len(r) == 1 { 97 | return true 98 | } 99 | 100 | return c.exists(r[1:]) 101 | } 102 | 103 | s[r[0]] = make(seen) 104 | if len(r) == 1 { 105 | return false 106 | } 107 | 108 | // does not exists, but we want to populate the tree fully 109 | return s[r[0]].exists(r[1:]) 110 | } 111 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/drop.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/proullon/ramsql/engine/parser" 7 | "github.com/proullon/ramsql/engine/protocol" 8 | ) 9 | 10 | func dropExecutor(e *Engine, dropDecl *parser.Decl, conn protocol.EngineConn) error { 11 | 12 | // Should have table token 13 | if dropDecl.Decl == nil || 14 | len(dropDecl.Decl) != 1 || 15 | dropDecl.Decl[0].Token != parser.TableToken || 16 | len(dropDecl.Decl[0].Decl) != 1 { 17 | return fmt.Errorf("unexpected drop arguments") 18 | } 19 | 20 | table := dropDecl.Decl[0].Decl[0].Lexeme 21 | 22 | r := e.relation(table) 23 | if r == nil { 24 | return fmt.Errorf("relation '%s' not found", table) 25 | } 26 | 27 | e.drop(table) 28 | 29 | return conn.WriteResult(0, 1) 30 | } 31 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/engine.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | "sync" 8 | 9 | "github.com/proullon/ramsql/engine/log" 10 | "github.com/proullon/ramsql/engine/parser" 11 | "github.com/proullon/ramsql/engine/protocol" 12 | ) 13 | 14 | type executor func(*Engine, *parser.Decl, protocol.EngineConn) error 15 | 16 | // Engine is the root struct of RamSQL server 17 | type Engine struct { 18 | endpoint protocol.EngineEndpoint 19 | relations map[string]*Relation 20 | opsExecutors map[int]executor 21 | 22 | // Any value send to this channel (through Engine.stop) 23 | // Will stop the listening loop 24 | stop chan bool 25 | 26 | sync.Mutex 27 | } 28 | 29 | // New initialize a new RamSQL server 30 | func New(endpoint protocol.EngineEndpoint) (e *Engine, err error) { 31 | 32 | e = &Engine{ 33 | endpoint: endpoint, 34 | } 35 | 36 | e.stop = make(chan bool) 37 | 38 | e.opsExecutors = map[int]executor{ 39 | parser.CreateToken: createExecutor, 40 | parser.TableToken: createTableExecutor, 41 | parser.SelectToken: selectExecutor, 42 | parser.InsertToken: insertIntoTableExecutor, 43 | parser.DeleteToken: deleteExecutor, 44 | parser.UpdateToken: updateExecutor, 45 | parser.IfToken: ifExecutor, 46 | parser.NotToken: notExecutor, 47 | parser.ExistsToken: existsExecutor, 48 | parser.TruncateToken: truncateExecutor, 49 | parser.DropToken: dropExecutor, 50 | parser.GrantToken: grantExecutor, 51 | } 52 | 53 | e.relations = make(map[string]*Relation) 54 | 55 | err = e.start() 56 | if err != nil { 57 | return nil, err 58 | } 59 | 60 | return 61 | } 62 | 63 | func (e *Engine) start() (err error) { 64 | go e.listen() 65 | return nil 66 | } 67 | 68 | // Stop shutdown the RamSQL server 69 | func (e *Engine) Stop() { 70 | if e.stop == nil { 71 | // already stopped 72 | return 73 | } 74 | go func() { 75 | e.stop <- true 76 | close(e.stop) 77 | e.stop = nil 78 | }() 79 | } 80 | 81 | func (e *Engine) relation(name string) *Relation { 82 | // Lock ? 83 | r := e.relations[name] 84 | // Unlock ? 85 | 86 | return r 87 | } 88 | 89 | func (e *Engine) drop(name string) { 90 | e.Lock() 91 | delete(e.relations, name) 92 | e.Unlock() 93 | } 94 | 95 | func (e *Engine) listen() { 96 | newConnectionChannel := make(chan protocol.EngineConn) 97 | 98 | go func() { 99 | for { 100 | conn, err := e.endpoint.Accept() 101 | if err != nil { 102 | e.Stop() 103 | return 104 | } 105 | 106 | newConnectionChannel <- conn 107 | } 108 | }() 109 | 110 | for { 111 | select { 112 | case conn := <-newConnectionChannel: 113 | go e.handleConnection(conn) 114 | break 115 | 116 | case <-e.stop: 117 | e.endpoint.Close() 118 | return 119 | } 120 | } 121 | 122 | } 123 | 124 | func (e *Engine) handleConnection(conn protocol.EngineConn) { 125 | 126 | for { 127 | stmt, err := conn.ReadStatement() 128 | if err == io.EOF { 129 | // Todo: close engine if there is no conn left 130 | return 131 | } 132 | if err != nil { 133 | log.Warning("Enginge.handleConnection: cannot read : %s", err) 134 | return 135 | } 136 | 137 | instructions, err := parser.ParseInstruction(stmt) 138 | if err != nil { 139 | conn.WriteError(err) 140 | continue 141 | } 142 | 143 | err = e.executeQueries(instructions, conn) 144 | if err != nil { 145 | conn.WriteError(err) 146 | continue 147 | } 148 | } 149 | } 150 | 151 | func (e *Engine) executeQueries(instructions []parser.Instruction, conn protocol.EngineConn) (err error) { 152 | defer func() { 153 | if r := recover(); r != nil { 154 | err = fmt.Errorf("fatal error: %s", r) 155 | return 156 | } 157 | }() 158 | 159 | for _, i := range instructions { 160 | err = e.executeQuery(i, conn) 161 | if err != nil { 162 | return err 163 | } 164 | } 165 | 166 | return nil 167 | } 168 | 169 | func (e *Engine) executeQuery(i parser.Instruction, conn protocol.EngineConn) error { 170 | 171 | if e.opsExecutors[i.Decls[0].Token] != nil { 172 | return e.opsExecutors[i.Decls[0].Token](e, i.Decls[0], conn) 173 | } 174 | 175 | return errors.New("Not Implemented") 176 | } 177 | 178 | func createExecutor(e *Engine, createDecl *parser.Decl, conn protocol.EngineConn) error { 179 | 180 | if len(createDecl.Decl) == 0 { 181 | return errors.New("Parsing failed, no declaration after CREATE") 182 | } 183 | 184 | if e.opsExecutors[createDecl.Decl[0].Token] != nil { 185 | return e.opsExecutors[createDecl.Decl[0].Token](e, createDecl.Decl[0], conn) 186 | } 187 | 188 | return errors.New("Parsing failed, unknown token " + createDecl.Decl[0].Lexeme) 189 | } 190 | 191 | func grantExecutor(e *Engine, decl *parser.Decl, conn protocol.EngineConn) error { 192 | return conn.WriteResult(0, 0) 193 | } 194 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/insert.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strconv" 7 | "strings" 8 | "time" 9 | 10 | "github.com/proullon/ramsql/engine/log" 11 | "github.com/proullon/ramsql/engine/parser" 12 | "github.com/proullon/ramsql/engine/protocol" 13 | ) 14 | 15 | /* 16 | |-> INSERT 17 | |-> INTO 18 | |-> user 19 | |-> last_name 20 | |-> first_name 21 | |-> email 22 | |-> VALUES 23 | |-> ( 24 | |-> Roullon 25 | |-> Pierre 26 | |-> pierre.roullon@gmail.com 27 | |-> RETURNING 28 | |-> email 29 | 30 | */ 31 | func insertIntoTableExecutor(e *Engine, insertDecl *parser.Decl, conn protocol.EngineConn) error { 32 | // Get table and concerned attributes and write lock it 33 | intoDecl := insertDecl.Decl[0] 34 | r, attributes, err := getRelation(e, intoDecl) 35 | if err != nil { 36 | return err 37 | } 38 | r.Lock() 39 | defer r.Unlock() 40 | 41 | // Check for RETURNING clause 42 | var returnedID string 43 | if len(insertDecl.Decl) > 2 { 44 | for i := range insertDecl.Decl { 45 | if insertDecl.Decl[i].Token == parser.ReturningToken { 46 | returningDecl := insertDecl.Decl[i] 47 | returnedID = returningDecl.Lexeme 48 | break 49 | } 50 | } 51 | } 52 | 53 | // Create a new tuple with values 54 | ids := []int64{} 55 | valuesDecl := insertDecl.Decl[1] 56 | for _, valueListDecl := range valuesDecl.Decl { 57 | // TODO handle all inserts atomically 58 | id, err := insert(r, attributes, valueListDecl.Decl, returnedID) 59 | if err != nil { 60 | return err 61 | } 62 | 63 | ids = append(ids, id) 64 | } 65 | 66 | // if RETURNING decl is not present 67 | if returnedID != "" { 68 | conn.WriteRowHeader([]string{returnedID}) 69 | for _, id := range ids { 70 | conn.WriteRow([]string{fmt.Sprintf("%v", id)}) 71 | } 72 | conn.WriteRowEnd() 73 | } else { 74 | conn.WriteResult(ids[len(ids)-1], (int64)(len(ids))) 75 | } 76 | return nil 77 | } 78 | 79 | /* 80 | |-> INTO 81 | |-> user 82 | |-> last_name 83 | |-> first_name 84 | |-> email 85 | */ 86 | func getRelation(e *Engine, intoDecl *parser.Decl) (*Relation, []*parser.Decl, error) { 87 | 88 | // Decl[0] is the table name 89 | r := e.relation(intoDecl.Decl[0].Lexeme) 90 | if r == nil { 91 | return nil, nil, errors.New("table " + intoDecl.Decl[0].Lexeme + " does not exist") 92 | } 93 | 94 | for i := range intoDecl.Decl[0].Decl { 95 | err := attributeExistsInTable(e, intoDecl.Decl[0].Decl[i].Lexeme, intoDecl.Decl[0].Lexeme) 96 | if err != nil { 97 | return nil, nil, err 98 | } 99 | } 100 | 101 | return r, intoDecl.Decl[0].Decl, nil 102 | } 103 | 104 | func insert(r *Relation, attributes []*parser.Decl, values []*parser.Decl, returnedID string) (int64, error) { 105 | var assigned = false 106 | var id int64 107 | var valuesindex int 108 | 109 | // Create tuple 110 | t := NewTuple() 111 | 112 | 113 | for attrindex, attr := range r.table.attributes { 114 | assigned = false 115 | 116 | for x, decl := range attributes { 117 | if attr.name == decl.Lexeme && attr.autoIncrement == false { 118 | // Before adding value in tuple, check it's not a builtin func or arithmetic operation 119 | switch values[x].Token { 120 | case parser.NowToken: 121 | t.Append(time.Now().Format(parser.DateLongFormat)) 122 | default: 123 | switch strings.ToLower(attr.typeName) { 124 | case "int64", "int": 125 | val, err := strconv.ParseInt(values[x].Lexeme, 10, 64) 126 | if err != nil { 127 | return 0, err 128 | } 129 | t.Append(val) 130 | case "numeric", "decimal": 131 | val, err := strconv.ParseFloat(values[x].Lexeme, 64) 132 | if err != nil { 133 | return 0, err 134 | } 135 | t.Append(val) 136 | default: 137 | t.Append(values[x].Lexeme) 138 | } 139 | } 140 | valuesindex = x 141 | assigned = true 142 | if returnedID == attr.name { 143 | var err error 144 | id, err = strconv.ParseInt(values[x].Lexeme, 10, 64) 145 | if err != nil { 146 | return 0, err 147 | } 148 | } 149 | } 150 | } 151 | 152 | // If attribute is AUTO INCREMENT, compute it and assign it 153 | if attr.autoIncrement { 154 | assigned = true 155 | id = int64(len(r.rows) + 1) 156 | t.Append(id) 157 | } 158 | 159 | // Do we have a UNIQUE attribute ? if so 160 | if attr.unique { 161 | for i := range r.rows { // check all value already in relation (yup, no index tree) 162 | if r.rows[i].Values[attrindex].(string) == string(values[valuesindex].Lexeme) { 163 | return 0, fmt.Errorf("UNIQUE constraint violation") 164 | } 165 | } 166 | } 167 | 168 | // If values was not explicitly given, set default value 169 | if assigned == false { 170 | switch val := attr.defaultValue.(type) { 171 | case func() interface{}: 172 | v := (func() interface{})(val)() 173 | log.Debug("Setting func value '%v' to %s\n", v, attr.name) 174 | t.Append(v) 175 | default: 176 | log.Debug("Setting default value '%v' to %s\n", val, attr.name) 177 | t.Append(attr.defaultValue) 178 | } 179 | } 180 | } 181 | 182 | log.Info("New tuple : %v", t) 183 | 184 | // Insert tuple 185 | err := r.Insert(t) 186 | if err != nil { 187 | return 0, err 188 | } 189 | 190 | return id, nil 191 | } 192 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/limit.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "github.com/proullon/ramsql/engine/log" 5 | "github.com/proullon/ramsql/engine/protocol" 6 | ) 7 | 8 | type limit struct { 9 | realConn protocol.EngineConn 10 | limit int 11 | current int 12 | } 13 | 14 | func limitedConn(conn protocol.EngineConn, l int) protocol.EngineConn { 15 | c := &limit{ 16 | realConn: conn, 17 | limit: l, 18 | current: 0, 19 | } 20 | return c 21 | } 22 | 23 | // Not needed 24 | func (l *limit) ReadStatement() (string, error) { 25 | log.Debug("limit.ReadStatement: should not be used\n") 26 | return "", nil 27 | } 28 | 29 | // Not needed 30 | func (l *limit) WriteResult(last int64, ra int64) error { 31 | log.Debug("limit.WriteResult: should not be used\n") 32 | return nil 33 | } 34 | 35 | func (l *limit) WriteError(err error) error { 36 | return l.realConn.WriteError(err) 37 | } 38 | 39 | func (l *limit) WriteRowHeader(header []string) error { 40 | return l.realConn.WriteRowHeader(header) 41 | } 42 | 43 | func (l *limit) WriteRow(row []string) error { 44 | if l.current == l.limit { 45 | // We are done here 46 | return nil 47 | } 48 | l.current++ 49 | return l.realConn.WriteRow(row) 50 | } 51 | 52 | func (l *limit) WriteRowEnd() error { 53 | return l.realConn.WriteRowEnd() 54 | } 55 | 56 | type offset struct { 57 | realConn protocol.EngineConn 58 | offset int 59 | current int 60 | } 61 | 62 | func offsetedConn(conn protocol.EngineConn, o int) protocol.EngineConn { 63 | c := &offset{ 64 | realConn: conn, 65 | offset: o, 66 | } 67 | return c 68 | } 69 | 70 | // Not needed 71 | func (l *offset) ReadStatement() (string, error) { 72 | log.Debug("limit.ReadStatement: should not be used\n") 73 | return "", nil 74 | } 75 | 76 | // Not needed 77 | func (l *offset) WriteResult(last int64, ra int64) error { 78 | log.Debug("limit.WriteResult: should not be used\n") 79 | return nil 80 | } 81 | 82 | func (l *offset) WriteError(err error) error { 83 | return l.realConn.WriteError(err) 84 | } 85 | 86 | func (l *offset) WriteRowHeader(header []string) error { 87 | return l.realConn.WriteRowHeader(header) 88 | } 89 | 90 | func (l *offset) WriteRow(row []string) error { 91 | if l.current < l.offset { 92 | // skip this line 93 | l.current++ 94 | return nil 95 | } 96 | 97 | return l.realConn.WriteRow(row) 98 | } 99 | 100 | func (l *offset) WriteRowEnd() error { 101 | return l.realConn.WriteRowEnd() 102 | } 103 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/log/log.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | // TODO: add a file logger 5 | "log" 6 | "sync" 7 | "testing" 8 | ) 9 | 10 | func init() { 11 | level = WarningLevel 12 | logger = BaseLogger{} 13 | } 14 | 15 | // Level of logging trigger 16 | type Level int 17 | 18 | // Available logging levels 19 | const ( 20 | DebugLevel Level = iota 21 | InfoLevel 22 | NoticeLevel 23 | WarningLevel 24 | CriticalLevel 25 | ) 26 | 27 | var ( 28 | logger Logger 29 | level Level 30 | mu sync.Mutex 31 | ) 32 | 33 | // Logger defines the logs levels used by RamSQL engine 34 | type Logger interface { 35 | Logf(fmt string, values ...interface{}) 36 | } 37 | 38 | // SetLevel controls the categories of logs written 39 | func SetLevel(lvl Level) { 40 | mu.Lock() 41 | level = lvl 42 | mu.Unlock() 43 | } 44 | 45 | func lvl() Level { 46 | mu.Lock() 47 | defer mu.Unlock() 48 | return level 49 | } 50 | 51 | // Debug prints debug log 52 | func Debug(format string, values ...interface{}) { 53 | if lvl() <= DebugLevel { 54 | logger.Logf("[DEBUG] "+format, values...) 55 | } 56 | } 57 | 58 | // Info prints information log 59 | func Info(format string, values ...interface{}) { 60 | if lvl() <= InfoLevel { 61 | logger.Logf("[INFO] "+format, values...) 62 | } 63 | } 64 | 65 | // Notice prints information that should be seen 66 | func Notice(format string, values ...interface{}) { 67 | if lvl() <= NoticeLevel { 68 | logger.Logf("[NOTICE] "+format, values...) 69 | } 70 | } 71 | 72 | // Warning prints warnings for user 73 | func Warning(format string, values ...interface{}) { 74 | if lvl() <= WarningLevel { 75 | logger.Logf("[WARNING] "+format, values...) 76 | } 77 | } 78 | 79 | // Critical prints error informations 80 | func Critical(format string, values ...interface{}) { 81 | mu.Lock() 82 | logger.Logf("[CRITICAL] "+format, values...) 83 | mu.Unlock() 84 | } 85 | 86 | // BaseLogger logs on stdout 87 | type BaseLogger struct { 88 | } 89 | 90 | // Logf logs on stdout 91 | func (l BaseLogger) Logf(fmt string, values ...interface{}) { 92 | log.Printf(fmt, values...) 93 | } 94 | 95 | // TestLogger uses *testing.T as a backend for RamSQL logs 96 | type TestLogger struct { 97 | t *testing.T 98 | } 99 | 100 | // Logf logs in testing log buffer 101 | func (l TestLogger) Logf(fmt string, values ...interface{}) { 102 | l.t.Logf(fmt, values...) 103 | } 104 | 105 | // UseTestLogger should be used only by unit tests 106 | func UseTestLogger(t testing.TB) { 107 | mu.Lock() 108 | logger = t 109 | mu.Unlock() 110 | SetLevel(WarningLevel) 111 | } 112 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/operator.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "fmt" 5 | "github.com/proullon/ramsql/engine/log" 6 | "github.com/proullon/ramsql/engine/parser" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | // Operator compares 2 values and return a boolean 12 | type Operator func(leftValue Value, rightValue Value) bool 13 | 14 | // NewOperator initializes the operator matching the Token number 15 | func NewOperator(token int, lexeme string) (Operator, error) { 16 | switch token { 17 | case parser.EqualityToken: 18 | return equalityOperator, nil 19 | case parser.DistinctnessToken: 20 | return distinctnessOperator, nil 21 | case parser.LeftDipleToken: 22 | return lessThanOperator, nil 23 | case parser.RightDipleToken: 24 | return greaterThanOperator, nil 25 | case parser.LessOrEqualToken: 26 | return lessOrEqualOperator, nil 27 | case parser.GreaterOrEqualToken: 28 | return greaterOrEqualOperator, nil 29 | } 30 | 31 | return nil, fmt.Errorf("Operator '%s' does not exist", lexeme) 32 | } 33 | 34 | func convToDate(t interface{}) (time.Time, error) { 35 | 36 | switch t := t.(type) { 37 | default: 38 | log.Debug("convToDate> unexpected type %T\n", t) 39 | return time.Time{}, fmt.Errorf("unexpected internal type %T", t) 40 | case string: 41 | d, err := parser.ParseDate(string(t)) 42 | if err != nil { 43 | return time.Time{}, fmt.Errorf("cannot parse date %v", t) 44 | } 45 | 46 | return *d, nil 47 | } 48 | 49 | } 50 | 51 | func convToFloat(t interface{}) (float64, error) { 52 | 53 | switch t := t.(type) { 54 | default: 55 | log.Debug("convToFloat> unexpected type %T\n", t) 56 | return 0, fmt.Errorf("unexpected internal type %T", t) 57 | case float64: 58 | return float64(t), nil 59 | case int64: 60 | return float64(int64(t)), nil 61 | case int: 62 | return float64(int(t)), nil 63 | case string: 64 | return strconv.ParseFloat(string(t), 64) 65 | } 66 | 67 | } 68 | 69 | func greaterThanOperator(leftValue Value, rightValue Value) bool { 70 | log.Debug("GreaterThanOperator") 71 | var left, right float64 72 | var err error 73 | 74 | var rvalue interface{} 75 | if rightValue.v != nil { 76 | rvalue = rightValue.v 77 | } else { 78 | rvalue = rightValue.lexeme 79 | } 80 | 81 | var leftDate time.Time 82 | var isDate bool 83 | 84 | left, err = convToFloat(leftValue.v) 85 | if err != nil { 86 | leftDate, err = convToDate(leftValue.v) 87 | if err != nil { 88 | log.Debug("GreaterThanOperator> %s\n", err) 89 | return false 90 | } 91 | isDate = true 92 | } 93 | 94 | if !isDate { 95 | right, err = convToFloat(rvalue) 96 | if err != nil { 97 | log.Debug("GreaterThanOperator> %s\n", err) 98 | return false 99 | } 100 | 101 | return left > right 102 | } 103 | 104 | rightDate, err := convToDate(rvalue) 105 | if err != nil { 106 | log.Debug("GreaterThanOperator> %s\n", err) 107 | return false 108 | } 109 | 110 | return leftDate.After(rightDate) 111 | } 112 | 113 | func lessOrEqualOperator(leftValue Value, rightValue Value) bool { 114 | return lessThanOperator(leftValue, rightValue) || equalityOperator(leftValue, rightValue) 115 | } 116 | 117 | func greaterOrEqualOperator(leftValue Value, rightValue Value) bool { 118 | return greaterThanOperator(leftValue, rightValue) || equalityOperator(leftValue, rightValue) 119 | } 120 | 121 | func lessThanOperator(leftValue Value, rightValue Value) bool { 122 | log.Debug("LessThanOperator") 123 | var left, right float64 124 | var err error 125 | 126 | var rvalue interface{} 127 | if rightValue.v != nil { 128 | rvalue = rightValue.v 129 | } else { 130 | rvalue = rightValue.lexeme 131 | } 132 | 133 | var leftDate time.Time 134 | var isDate bool 135 | 136 | left, err = convToFloat(leftValue.v) 137 | if err != nil { 138 | leftDate, err = convToDate(leftValue.v) 139 | if err != nil { 140 | log.Debug("LessThanOperator> %s\n", err) 141 | return false 142 | } 143 | isDate = true 144 | } 145 | 146 | if !isDate { 147 | right, err = convToFloat(rvalue) 148 | if err != nil { 149 | log.Debug("LessThanOperator> %s\n", err) 150 | return false 151 | } 152 | 153 | return left < right 154 | } 155 | 156 | rightDate, err := convToDate(rvalue) 157 | if err != nil { 158 | log.Debug("LessThanOperator> %s\n", err) 159 | return false 160 | } 161 | 162 | return leftDate.Before(rightDate) 163 | } 164 | 165 | // EqualityOperator checks if given value are equal 166 | func equalityOperator(leftValue Value, rightValue Value) bool { 167 | 168 | if fmt.Sprintf("%v", leftValue.v) == rightValue.lexeme { 169 | return true 170 | } 171 | 172 | return false 173 | } 174 | 175 | // DistinctnessOperator checks if given value are distinct 176 | func distinctnessOperator(leftValue Value, rightValue Value) bool { 177 | 178 | if fmt.Sprintf("%v", leftValue.v) != rightValue.lexeme { 179 | return true 180 | } 181 | 182 | return false 183 | } 184 | 185 | // TrueOperator always returns true 186 | func TrueOperator(leftValue Value, rightValue Value) bool { 187 | return true 188 | } 189 | 190 | func inOperator(leftValue Value, rightValue Value) bool { 191 | // Right value should be a slice of string 192 | values, ok := rightValue.v.([]string) 193 | if !ok { 194 | log.Debug("InOperator: rightValue.v is not a []string !") 195 | return false 196 | } 197 | 198 | for i := range values { 199 | log.Debug("InOperator: Testing %v against %s", leftValue.v, values[i]) 200 | if fmt.Sprintf("%v", leftValue.v) == values[i] { 201 | return true 202 | } 203 | } 204 | 205 | return false 206 | } 207 | 208 | func notInOperator(leftValue Value, rightValue Value) bool { 209 | return !inOperator(leftValue, rightValue) 210 | } 211 | 212 | func isNullOperator(leftValue Value, rightValue Value) bool { 213 | return leftValue.v == nil 214 | } 215 | 216 | func isNotNullOperator(leftValue Value, rightValue Value) bool { 217 | return leftValue.v != nil 218 | } 219 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/parser/date.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // DateLongFormat is same as time.Time#String(), except this does not include monotonic time section 9 | const DateLongFormat = "2006-01-02 15:04:05.999999999 -0700 MST" 10 | 11 | // DateShortFormat is a short format 12 | const DateShortFormat = "2006-Jan-02" 13 | 14 | const DateNumberFormat = "2006-01-02" 15 | 16 | // ParseDate intends to parse all SQL date format 17 | func ParseDate(data string) (*time.Time, error) { 18 | t, err := time.Parse(DateLongFormat, data) 19 | if err == nil { 20 | return &t, nil 21 | } 22 | 23 | t, err = time.Parse(time.RFC3339, data) 24 | if err == nil { 25 | return &t, nil 26 | } 27 | 28 | t, err = time.Parse(DateShortFormat, data) 29 | if err == nil { 30 | return &t, nil 31 | } 32 | 33 | t, err = time.Parse(DateNumberFormat, data) 34 | if err == nil { 35 | return &t, nil 36 | } 37 | 38 | return nil, fmt.Errorf("not a date") 39 | } 40 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/parser/delete.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import () 4 | 5 | func (p *parser) parseDelete() (*Instruction, error) { 6 | i := &Instruction{} 7 | 8 | // Set DELETE decl 9 | deleteDecl, err := p.consumeToken(DeleteToken) 10 | if err != nil { 11 | return nil, err 12 | } 13 | i.Decls = append(i.Decls, deleteDecl) 14 | 15 | // should be From 16 | fromDecl, err := p.consumeToken(FromToken) 17 | if err != nil { 18 | return nil, err 19 | } 20 | deleteDecl.Add(fromDecl) 21 | 22 | // Should be a table name 23 | nameDecl, err := p.parseQuotedToken() 24 | if err != nil { 25 | return nil, err 26 | } 27 | fromDecl.Add(nameDecl) 28 | 29 | // MAY be WHERE here 30 | debug("WHERE ? %v", p.tokens[p.index]) 31 | if !p.hasNext() { 32 | return i, nil 33 | } 34 | 35 | err = p.parseWhere(deleteDecl) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | return i, nil 41 | } 42 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/parser/drop.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "github.com/proullon/ramsql/engine/log" 5 | ) 6 | 7 | func (p *parser) parseDrop() (*Instruction, error) { 8 | i := &Instruction{} 9 | 10 | trDecl, err := p.consumeToken(DropToken) 11 | if err != nil { 12 | log.Debug("WTF\n") 13 | return nil, err 14 | } 15 | i.Decls = append(i.Decls, trDecl) 16 | 17 | tableDecl, err := p.consumeToken(TableToken) 18 | if err != nil { 19 | log.Debug("Consume table !\n") 20 | return nil, err 21 | } 22 | trDecl.Add(tableDecl) 23 | 24 | // Should be a table name 25 | nameDecl, err := p.parseQuotedToken() 26 | if err != nil { 27 | log.Debug("UH ?\n") 28 | return nil, err 29 | } 30 | tableDecl.Add(nameDecl) 31 | 32 | return i, nil 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/parser/interface.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // ParseInstruction calls lexer and parser, then return Decl tree for each instruction 8 | func ParseInstruction(instruction string) ([]Instruction, error) { 9 | 10 | l := lexer{} 11 | tokens, err := l.lex([]byte(instruction)) 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | p := parser{} 17 | instructions, err := p.parse(tokens) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | if len(instructions) == 0 { 23 | return nil, errors.New("Error in syntax near " + instruction) 24 | } 25 | 26 | return instructions, nil 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/parser/log.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | //"github.com/proullon/ramsql/engine/log" 5 | ) 6 | 7 | func debug(format string, v ...interface{}) { 8 | //log.Debug(format, v...) 9 | } 10 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/parser/select.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func (p *parser) parseSelect(tokens []Token) (*Instruction, error) { 8 | i := &Instruction{} 9 | var err error 10 | 11 | // Create select decl 12 | selectDecl := NewDecl(tokens[p.index]) 13 | i.Decls = append(i.Decls, selectDecl) 14 | 15 | // After select token, should be either 16 | // a StarToken 17 | // a list of table names + (StarToken Or Attribute) 18 | // a builtin func (COUNT, MAX, ...) 19 | if err = p.next(); err != nil { 20 | return nil, fmt.Errorf("SELECT token must be followed by attributes to select") 21 | } 22 | 23 | var ( 24 | distinctDecl *Decl 25 | distinctOpen bool 26 | ) 27 | if p.is(DistinctToken) { 28 | distinctDecl, err = p.consumeToken(DistinctToken) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | if p.is(OnToken) { 34 | if err := p.next(); err != nil { 35 | return nil, err 36 | } 37 | if !p.is(BracketOpeningToken) { 38 | return nil, fmt.Errorf("Syntax error near %v, opening bracket expected\n", tokens[p.index]) 39 | } 40 | if err := p.next(); err != nil { 41 | return nil, err 42 | } 43 | distinctOpen = true 44 | } 45 | 46 | selectDecl.Add(distinctDecl) 47 | } 48 | 49 | for { 50 | switch { 51 | case p.is(CountToken): 52 | attrDecl, err := p.parseBuiltinFunc() 53 | if err != nil { 54 | return nil, err 55 | } 56 | selectDecl.Add(attrDecl) 57 | default: 58 | attrDecl, err := p.parseAttribute() 59 | if err != nil { 60 | return nil, err 61 | } 62 | if distinctOpen { 63 | distinctDecl.Add(attrDecl) 64 | } 65 | selectDecl.Add(attrDecl) 66 | } 67 | 68 | switch { 69 | case distinctOpen && p.is(BracketClosingToken): 70 | if err := p.next(); err != nil { 71 | return nil, err 72 | } 73 | distinctOpen = false 74 | continue 75 | case p.is(CommaToken): 76 | if err := p.next(); err != nil { 77 | return nil, err 78 | } 79 | continue 80 | } 81 | 82 | break 83 | } 84 | 85 | // Must be from now 86 | if tokens[p.index].Token != FromToken { 87 | return nil, fmt.Errorf("Syntax error near %v\n", tokens[p.index]) 88 | } 89 | fromDecl := NewDecl(tokens[p.index]) 90 | selectDecl.Add(fromDecl) 91 | 92 | // Now must be a list of table 93 | for { 94 | // string 95 | if err = p.next(); err != nil { 96 | return nil, fmt.Errorf("Unexpected end. Syntax error near %v\n", tokens[p.index]) 97 | } 98 | tableNameDecl, err := p.parseAttribute() 99 | if err != nil { 100 | return nil, err 101 | } 102 | fromDecl.Add(tableNameDecl) 103 | 104 | // If no next, then it's implicit where 105 | if !p.hasNext() { 106 | addImplicitWhereAll(selectDecl) 107 | return i, nil 108 | } 109 | // if not comma, break 110 | if tokens[p.index].Token != CommaToken { 111 | break // No more table 112 | } 113 | } 114 | 115 | // JOIN OR ...? 116 | for p.is(JoinToken) { 117 | joinDecl, err := p.parseJoin() 118 | if err != nil { 119 | return nil, err 120 | } 121 | selectDecl.Add(joinDecl) 122 | } 123 | 124 | hazWhereClause := false 125 | for { 126 | switch p.cur().Token { 127 | case WhereToken: 128 | err := p.parseWhere(selectDecl) 129 | if err != nil { 130 | return nil, err 131 | } 132 | hazWhereClause = true 133 | case OrderToken: 134 | if hazWhereClause == false { 135 | // WHERE clause is implicit 136 | addImplicitWhereAll(selectDecl) 137 | } 138 | err := p.parseOrderBy(selectDecl) 139 | if err != nil { 140 | return nil, err 141 | } 142 | case LimitToken: 143 | limitDecl, err := p.consumeToken(LimitToken) 144 | if err != nil { 145 | return nil, err 146 | } 147 | selectDecl.Add(limitDecl) 148 | numDecl, err := p.consumeToken(NumberToken) 149 | if err != nil { 150 | return nil, err 151 | } 152 | limitDecl.Add(numDecl) 153 | case OffsetToken: 154 | offsetDecl, err := p.consumeToken(OffsetToken) 155 | if err != nil { 156 | return nil, err 157 | } 158 | selectDecl.Add(offsetDecl) 159 | offsetValue, err := p.consumeToken(NumberToken) 160 | if err != nil { 161 | return nil, err 162 | } 163 | offsetDecl.Add(offsetValue) 164 | case ForToken: 165 | err := p.parseForUpdate(selectDecl) 166 | if err != nil { 167 | return nil, err 168 | } 169 | default: 170 | return i, nil 171 | } 172 | } 173 | } 174 | 175 | func addImplicitWhereAll(decl *Decl) { 176 | 177 | whereDecl := &Decl{ 178 | Token: WhereToken, 179 | Lexeme: "where", 180 | } 181 | whereDecl.Add(&Decl{ 182 | Token: NumberToken, 183 | Lexeme: "1", 184 | }) 185 | 186 | decl.Add(whereDecl) 187 | } 188 | 189 | func (p *parser) parseForUpdate(decl *Decl) error { 190 | // Optionnal 191 | if !p.is(ForToken) { 192 | return nil 193 | } 194 | 195 | d, err := p.consumeToken(ForToken) 196 | if err != nil { 197 | return err 198 | } 199 | 200 | u, err := p.consumeToken(UpdateToken) 201 | if err != nil { 202 | return err 203 | } 204 | 205 | d.Add(u) 206 | decl.Add(d) 207 | return nil 208 | } 209 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/parser/truncate.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | func (p *parser) parseTruncate() (*Instruction, error) { 4 | i := &Instruction{} 5 | 6 | // Set TRUNCATE decl 7 | trDecl, err := p.consumeToken(TruncateToken) 8 | if err != nil { 9 | return nil, err 10 | } 11 | i.Decls = append(i.Decls, trDecl) 12 | 13 | // Should be a table name 14 | nameDecl, err := p.parseQuotedToken() 15 | if err != nil { 16 | return nil, err 17 | } 18 | trDecl.Add(nameDecl) 19 | 20 | return i, nil 21 | } 22 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/parser/where.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/proullon/ramsql/engine/log" 7 | ) 8 | 9 | func (p *parser) parseWhere(selectDecl *Decl) error { 10 | 11 | // May be WHERE here 12 | // Can be ORDER BY if WHERE cause if implicit 13 | whereDecl, err := p.consumeToken(WhereToken) 14 | if err != nil { 15 | return err 16 | } 17 | selectDecl.Add(whereDecl) 18 | 19 | // Now should be a list of: Attribute and Operator and Value 20 | gotClause := false 21 | for { 22 | if !p.hasNext() && gotClause { 23 | break 24 | } 25 | 26 | if p.is(OrderToken, LimitToken, ForToken) { 27 | break 28 | } 29 | 30 | attributeDecl, err := p.parseCondition() 31 | if err != nil { 32 | return err 33 | } 34 | whereDecl.Add(attributeDecl) 35 | 36 | if p.is(AndToken, OrToken) { 37 | linkDecl, err := p.consumeToken(p.cur().Token) 38 | if err != nil { 39 | return err 40 | } 41 | whereDecl.Add(linkDecl) 42 | } 43 | 44 | // Got at least one clause 45 | gotClause = true 46 | } 47 | 48 | return nil 49 | } 50 | 51 | func (p *parser) parseCondition() (*Decl, error) { 52 | // Optionnaly, brackets 53 | 54 | // We may have the WHERE 1 condition 55 | if t := p.cur(); t.Token == NumberToken && t.Lexeme == "1" { 56 | attributeDecl := NewDecl(t) 57 | p.next() 58 | // in case of 1 = 1 59 | if p.cur().Token == EqualityToken { 60 | t, err := p.isNext(NumberToken) 61 | if err == nil && t.Lexeme == "1" { 62 | p.consumeToken(EqualityToken) 63 | p.consumeToken(NumberToken) 64 | } 65 | } 66 | return attributeDecl, nil 67 | } 68 | 69 | // do we have brackets ? 70 | hasBracket := false 71 | if p.is(BracketOpeningToken) { 72 | p.consumeToken(BracketOpeningToken) 73 | hasBracket = true 74 | } 75 | 76 | // Attribute 77 | attributeDecl, err := p.parseAttribute() 78 | if err != nil { 79 | return nil, err 80 | } 81 | 82 | switch p.cur().Token { 83 | case EqualityToken, DistinctnessToken, LeftDipleToken, RightDipleToken, LessOrEqualToken, GreaterOrEqualToken: 84 | decl, err := p.consumeToken(p.cur().Token) 85 | if err != nil { 86 | return nil, err 87 | } 88 | attributeDecl.Add(decl) 89 | break 90 | case InToken: 91 | inDecl, err := p.parseIn() 92 | if err != nil { 93 | return nil, err 94 | } 95 | attributeDecl.Add(inDecl) 96 | return attributeDecl, nil 97 | case NotToken: 98 | notDecl, err := p.consumeToken(p.cur().Token) 99 | if err != nil { 100 | return nil, err 101 | } 102 | 103 | if p.cur().Token != InToken { 104 | return nil, fmt.Errorf("expected IN after NOT") 105 | } 106 | 107 | inDecl, err := p.parseIn() 108 | if err != nil { 109 | return nil, err 110 | } 111 | notDecl.Add(inDecl) 112 | 113 | attributeDecl.Add(notDecl) 114 | return attributeDecl, nil 115 | case IsToken: 116 | log.Debug("parseCondition: IsToken\n") 117 | decl, err := p.consumeToken(IsToken) 118 | if err != nil { 119 | return nil, err 120 | } 121 | attributeDecl.Add(decl) 122 | if p.cur().Token == NotToken { 123 | log.Debug("parseCondition: NotToken\n") 124 | notDecl, err := p.consumeToken(NotToken) 125 | if err != nil { 126 | return nil, err 127 | } 128 | decl.Add(notDecl) 129 | } 130 | if p.cur().Token == NullToken { 131 | log.Debug("parseCondition: NullToken\n") 132 | nullDecl, err := p.consumeToken(NullToken) 133 | if err != nil { 134 | return nil, err 135 | } 136 | decl.Add(nullDecl) 137 | } 138 | return attributeDecl, nil 139 | } 140 | 141 | // Value 142 | valueDecl, err := p.parseValue() 143 | if err != nil { 144 | return nil, err 145 | } 146 | attributeDecl.Add(valueDecl) 147 | 148 | if hasBracket { 149 | if _, err = p.consumeToken(BracketClosingToken); err != nil { 150 | return nil, err 151 | } 152 | } 153 | 154 | return attributeDecl, nil 155 | } 156 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/predicate.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // PredicateLinker referes to AND and OR operators. 8 | type PredicateLinker interface { 9 | Eval(v virtualRow) (bool, error) 10 | } 11 | 12 | type andOperator struct { 13 | pred []PredicateLinker 14 | } 15 | 16 | func (o *andOperator) Add(p PredicateLinker) { 17 | o.pred = append(o.pred, p) 18 | } 19 | 20 | func (o *andOperator) Eval(v virtualRow) (bool, error) { 21 | 22 | for i := range o.pred { 23 | ok, err := o.pred[i].Eval(v) 24 | if err != nil { 25 | return false, err 26 | } 27 | if !ok { 28 | return false, nil 29 | } 30 | } 31 | 32 | return true, nil 33 | } 34 | 35 | type orOperator struct { 36 | pred []PredicateLinker 37 | } 38 | 39 | func (o *orOperator) Add(p PredicateLinker) { 40 | o.pred = append(o.pred, p) 41 | } 42 | 43 | func (o *orOperator) Eval(v virtualRow) (bool, error) { 44 | 45 | for i := range o.pred { 46 | ok, err := o.pred[i].Eval(v) 47 | if err != nil { 48 | return false, err 49 | } 50 | if ok { 51 | return true, nil 52 | } 53 | } 54 | 55 | return false, nil 56 | } 57 | 58 | // TruePredicate is a predicate which return always true 59 | var TruePredicate = Predicate{ 60 | True: true, 61 | } 62 | 63 | // Value is a value given to predicates 64 | type Value struct { 65 | v interface{} 66 | valid bool 67 | lexeme string 68 | constant bool 69 | table string 70 | } 71 | 72 | // Predicate evaluate if a condition is valid with 2 values and an operator on this 2 values 73 | type Predicate struct { 74 | LeftValue Value 75 | Operator Operator 76 | RightValue Value 77 | True bool 78 | } 79 | 80 | func (p Predicate) String() string { 81 | var left, right string 82 | 83 | if p.True { 84 | return "AlwaysTrue" 85 | } 86 | 87 | left = "?" 88 | right = "?" 89 | 90 | if p.LeftValue.valid { 91 | left = p.LeftValue.lexeme 92 | } 93 | 94 | if p.RightValue.valid { 95 | right = p.RightValue.lexeme 96 | } 97 | 98 | return fmt.Sprintf("[%s] vs [%s]", left, right) 99 | } 100 | 101 | // Eval fetches operand from virtual row and run operator 102 | func (p *Predicate) Eval(row virtualRow) (bool, error) { 103 | 104 | if p.True { 105 | return true, nil 106 | } 107 | 108 | // Find left attribute 109 | left := p.LeftValue.table + "." + p.LeftValue.lexeme 110 | val, ok := row[left] 111 | if !ok { 112 | return false, fmt.Errorf("Attribute [%s] not found in row", left) 113 | } 114 | p.LeftValue.v = val.v 115 | 116 | return p.Operator(p.LeftValue, p.RightValue), nil 117 | } 118 | 119 | // Evaluate is deprecated (see Eval). It calls operators and use tuple as operand 120 | // TODO: Delete that 121 | func (p *Predicate) Evaluate(t *Tuple, table *Table) (bool, error) { 122 | 123 | if p.True { 124 | return true, nil 125 | } 126 | 127 | // Find left 128 | var i = 0 129 | lenTable := len(table.attributes) 130 | for i = 0; i < lenTable; i++ { 131 | if table.attributes[i].name == p.LeftValue.lexeme { 132 | break 133 | } 134 | } 135 | if i == lenTable { 136 | return false, fmt.Errorf("Attribute [%s] not found in table [%s]", p.LeftValue.lexeme, table.name) 137 | } 138 | 139 | p.LeftValue.v = t.Values[i] 140 | return p.Operator(p.LeftValue, p.RightValue), nil 141 | } 142 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/protocol/buffer.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "container/list" 5 | 6 | "github.com/proullon/ramsql/engine/log" 7 | ) 8 | 9 | // UnlimitedRowsChannel buffers incomming message from bufferThis channel and forward them to 10 | // returned channel. 11 | // ONLY CREATED CHANNEL IS CLOSED HERE. 12 | func UnlimitedRowsChannel(bufferThis chan message, firstMessage message) chan []string { 13 | driverChannel := make(chan []string) 14 | rowList := list.New() 15 | 16 | rowList.PushBack(firstMessage.Value) 17 | 18 | go func() { 19 | for { 20 | // If nothing comes in and nothing is going out... 21 | if rowList.Len() == 0 && bufferThis == nil { 22 | close(driverChannel) 23 | return 24 | } 25 | 26 | // Create a copy of driverChannel because if there is nothing to send 27 | // We can disable the case in select with a nil channel and get a chance 28 | // to fetch new data on bufferThis channel 29 | driverChannelNullable := driverChannel 30 | var nextRow []string 31 | if rowList.Len() != 0 { 32 | nextRow = rowList.Front().Value.([]string) 33 | } else { 34 | driverChannelNullable = nil 35 | } 36 | 37 | select { 38 | // In case a new row is sent to driver 39 | case driverChannelNullable <- nextRow: 40 | if nextRow != nil { 41 | rowList.Remove(rowList.Front()) 42 | } 43 | // In case we receive a new value to buffer from engine channel 44 | case newRow, ok := <-bufferThis: 45 | if !ok || newRow.Type == rowEndMessage { 46 | // Stop listening to bufferThis channel 47 | bufferThis = nil 48 | // If there is nothing more to listen and there is nothing in buffer, exit 49 | // close driverChannel so *Rows knows there is nothing more to read 50 | if rowList.Len() == 0 { 51 | if driverChannel != nil { 52 | close(driverChannel) 53 | } 54 | return 55 | } 56 | 57 | if driverChannel == nil { 58 | log.Critical("Unlimited: But there is nobody to read it, exiting") 59 | return 60 | } 61 | } else if newRow.Type == errMessage { 62 | log.Critical("Runtime error: %s", newRow.Value[0]) 63 | if driverChannel != nil { 64 | close(driverChannel) 65 | } 66 | return 67 | } else { 68 | // Everything is ok, buffering new value 69 | rowList.PushBack(newRow.Value) 70 | } 71 | case exit := <-driverChannel: 72 | // this means driverChannel is closed 73 | // set driverChannel to nil so we don't try to close it again 74 | driverChannel = nil 75 | _ = exit 76 | } 77 | } 78 | }() 79 | 80 | return driverChannel 81 | } 82 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/protocol/public.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | // DriverConn is a networking helper hiding implementation 4 | // either with channels or network sockets. 5 | type DriverConn interface { 6 | WriteQuery(query string) error 7 | WriteExec(stmt string) error 8 | ReadResult() (lastInsertedID int64, rowsAffected int64, err error) 9 | ReadRows() (chan []string, error) 10 | Close() 11 | } 12 | 13 | // EngineConn is a networking helper hiding implementation 14 | // either with channels or network sockets. 15 | type EngineConn interface { 16 | ReadStatement() (string, error) 17 | WriteResult(lastInsertedID int64, rowsAffected int64) error 18 | WriteError(err error) error 19 | WriteRowHeader(header []string) error 20 | WriteRow(row []string) error 21 | WriteRowEnd() error 22 | } 23 | 24 | // EngineEndpoint is the query entrypoint of RamSQL engine. 25 | type EngineEndpoint interface { 26 | Accept() (EngineConn, error) 27 | Close() 28 | } 29 | 30 | // DriverEndpoint instanciates either 31 | // - an Engine and communication channels 32 | // - a network socket to connect to an existing RamSQL engine 33 | type DriverEndpoint interface { 34 | New(string) (DriverConn, error) 35 | } 36 | 37 | // NewChannelEndpoints instanciates a Driver and 38 | // Engine channel endpoints 39 | func NewChannelEndpoints() (DriverEndpoint, EngineEndpoint) { 40 | channel := make(chan chan message) 41 | 42 | return NewChannelDriverEndpoint(channel), NewChannelEngineEndpoint(channel) 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/relation.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | // Relation is a table with column and rows 8 | // AKA File 9 | type Relation struct { 10 | sync.RWMutex 11 | table *Table 12 | rows []*Tuple 13 | } 14 | 15 | // NewRelation initializes a new Relation struct 16 | func NewRelation(t *Table) *Relation { 17 | r := &Relation{ 18 | table: t, 19 | } 20 | 21 | return r 22 | } 23 | 24 | // Insert a tuple in relation 25 | func (r *Relation) Insert(t *Tuple) error { 26 | // Maybe do somthing like lock read/write here 27 | // Maybe index 28 | r.rows = append(r.rows, t) 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/table.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/proullon/ramsql/engine/parser" 7 | "github.com/proullon/ramsql/engine/protocol" 8 | ) 9 | 10 | // Table is defined by a name and attributes 11 | // A table with data is called a Relation 12 | type Table struct { 13 | name string 14 | attributes []Attribute 15 | } 16 | 17 | // NewTable initializes a new Table 18 | func NewTable(name string) *Table { 19 | t := &Table{ 20 | name: name, 21 | } 22 | 23 | return t 24 | } 25 | 26 | // AddAttribute is used by CREATE TABLE and ALTER TABLE 27 | // Want to check that name isn't already taken 28 | func (t *Table) AddAttribute(attr Attribute) error { 29 | t.attributes = append(t.attributes, attr) 30 | return nil 31 | } 32 | 33 | // String returns a printable string with table name and attributes 34 | func (t Table) String() string { 35 | stringy := t.name + " (" 36 | for i, a := range t.attributes { 37 | if i != 0 { 38 | stringy += " | " 39 | } 40 | stringy += a.name + " " + a.typeName 41 | } 42 | stringy += ")" 43 | return stringy 44 | } 45 | 46 | func createTableExecutor(e *Engine, tableDecl *parser.Decl, conn protocol.EngineConn) error { 47 | var i int 48 | 49 | if len(tableDecl.Decl) == 0 { 50 | return fmt.Errorf("parsing failed, malformed query") 51 | } 52 | 53 | // Check for specific attribute 54 | i = 0 55 | for i < len(tableDecl.Decl) { 56 | 57 | if e.opsExecutors[tableDecl.Decl[i].Token] != nil { 58 | if err := e.opsExecutors[tableDecl.Decl[i].Token](e, tableDecl.Decl[i], conn); err != nil { 59 | return err 60 | } 61 | } else { 62 | break 63 | } 64 | 65 | i++ 66 | } 67 | 68 | // Check if 'IF NOT EXISTS' is present 69 | ifNotExists := hasIfNotExists(tableDecl) 70 | 71 | // Check if table does not exists 72 | r := e.relation(tableDecl.Decl[i].Lexeme) 73 | if r != nil && !ifNotExists { 74 | return fmt.Errorf("table %s already exists", tableDecl.Decl[i].Lexeme) 75 | } 76 | 77 | // Fetch table name 78 | t := NewTable(tableDecl.Decl[i].Lexeme) 79 | 80 | // Fetch attributes 81 | i++ 82 | for i < len(tableDecl.Decl) { 83 | attr, err := parseAttribute(tableDecl.Decl[i]) 84 | if err != nil { 85 | return err 86 | } 87 | err = t.AddAttribute(attr) 88 | if err != nil { 89 | return err 90 | } 91 | 92 | i++ 93 | } 94 | 95 | e.relations[t.name] = NewRelation(t) 96 | conn.WriteResult(0, 1) 97 | return nil 98 | } 99 | 100 | func hasIfNotExists(tableDecl *parser.Decl) bool { 101 | for _, d := range tableDecl.Decl { 102 | if d.Token == parser.IfToken { 103 | if len(d.Decl) > 0 && d.Decl[0].Token == parser.NotToken { 104 | not := d.Decl[0] 105 | if len(not.Decl) > 0 && not.Decl[0].Token == parser.ExistsToken { 106 | return true 107 | } 108 | } 109 | } 110 | } 111 | 112 | return false 113 | } 114 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/truncate.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/proullon/ramsql/engine/log" 7 | "github.com/proullon/ramsql/engine/parser" 8 | "github.com/proullon/ramsql/engine/protocol" 9 | ) 10 | 11 | func truncateExecutor(e *Engine, trDecl *parser.Decl, conn protocol.EngineConn) error { 12 | log.Debug("truncateExecutor") 13 | 14 | // get tables to be deleted 15 | table := NewTable(trDecl.Decl[0].Lexeme) 16 | 17 | return truncateTable(e, table, conn) 18 | } 19 | 20 | func truncateTable(e *Engine, table *Table, conn protocol.EngineConn) error { 21 | var rowsDeleted int64 22 | 23 | // get relations and write lock them 24 | r := e.relation(table.name) 25 | if r == nil { 26 | return fmt.Errorf("Table %v not found", table.name) 27 | } 28 | r.Lock() 29 | defer r.Unlock() 30 | 31 | if r.rows != nil { 32 | rowsDeleted = int64(len(r.rows)) 33 | } 34 | r.rows = make([]*Tuple, 0) 35 | 36 | return conn.WriteResult(0, rowsDeleted) 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/tuple.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | // Tuple is a row in a relation 4 | type Tuple struct { 5 | Values []interface{} 6 | } 7 | 8 | // NewTuple should check that value are for the right Attribute and match domain 9 | func NewTuple(values ...interface{}) *Tuple { 10 | t := &Tuple{} 11 | 12 | for _, v := range values { 13 | t.Values = append(t.Values, v) 14 | } 15 | return t 16 | } 17 | 18 | // Append add a value to the tuple 19 | func (t *Tuple) Append(value interface{}) { 20 | t.Values = append(t.Values, value) 21 | } 22 | -------------------------------------------------------------------------------- /vendor/github.com/proullon/ramsql/engine/update.go: -------------------------------------------------------------------------------- 1 | package engine 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "time" 7 | 8 | "github.com/proullon/ramsql/engine/log" 9 | "github.com/proullon/ramsql/engine/parser" 10 | "github.com/proullon/ramsql/engine/protocol" 11 | ) 12 | 13 | /* 14 | |-> update 15 | |-> account 16 | |-> set 17 | |-> email 18 | |-> = 19 | |-> roger@gmail.com 20 | |-> where 21 | |-> id 22 | |-> = 23 | |-> 2 24 | */ 25 | func updateExecutor(e *Engine, updateDecl *parser.Decl, conn protocol.EngineConn) error { 26 | var num int64 27 | 28 | updateDecl.Stringy(0) 29 | 30 | // Fetch table from name and write lock it 31 | r := e.relation(updateDecl.Decl[0].Lexeme) 32 | if r == nil { 33 | return fmt.Errorf("Table %s does not exist", updateDecl.Decl[0].Lexeme) 34 | } 35 | r.Lock() 36 | r.Unlock() 37 | 38 | // Set decl 39 | values, err := setExecutor(updateDecl.Decl[1]) 40 | if err != nil { 41 | return err 42 | } 43 | 44 | // Where decl 45 | predicates, err := whereExecutor(updateDecl.Decl[2], r.table.name) 46 | if err != nil { 47 | return err 48 | } 49 | 50 | var ok, res bool 51 | for i := range r.rows { 52 | ok = true 53 | // If the row validate all predicates, write it 54 | for _, predicate := range predicates { 55 | if res, err = predicate.Evaluate(r.rows[i], r.table); err != nil { 56 | return err 57 | } 58 | if res == false { 59 | ok = false 60 | continue 61 | } 62 | } 63 | 64 | if ok { 65 | num++ 66 | err = updateValues(r, i, values) 67 | if err != nil { 68 | return err 69 | } 70 | } 71 | } 72 | 73 | return conn.WriteResult(0, num) 74 | } 75 | 76 | /* 77 | |-> set 78 | |-> email 79 | |-> = 80 | |-> roger@gmail.com 81 | */ 82 | func setExecutor(setDecl *parser.Decl) (map[string]interface{}, error) { 83 | 84 | values := make(map[string]interface{}) 85 | 86 | for _, attr := range setDecl.Decl { 87 | if attr.Decl[1].Token == parser.NullToken { 88 | values[attr.Lexeme] = nil 89 | } else { 90 | values[attr.Lexeme] = attr.Decl[1].Lexeme 91 | } 92 | } 93 | 94 | return values, nil 95 | } 96 | 97 | func updateValues(r *Relation, row int, values map[string]interface{}) error { 98 | for i := range r.table.attributes { 99 | val, ok := values[r.table.attributes[i].name] 100 | if !ok { 101 | continue 102 | } 103 | log.Debug("Type of '%s' is '%s'\n", r.table.attributes[i].name, r.table.attributes[i].typeName) 104 | switch strings.ToLower(r.table.attributes[i].typeName) { 105 | case "timestamp", "localtimestamp": 106 | s, ok := val.(string) 107 | if ok && (s == "current_timestamp" || s == "now()") { 108 | val = time.Now() 109 | } 110 | // format time.Time into parsable string 111 | if t, ok := val.(time.Time); ok { 112 | val = t.Format(parser.DateLongFormat) 113 | } 114 | } 115 | r.rows[row].Values[i] = fmt.Sprintf("%v", val) 116 | } 117 | 118 | return nil 119 | } 120 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go: -------------------------------------------------------------------------------- 1 | //go:build go1.17 2 | // +build go1.17 3 | 4 | // TODO: once support for Go 1.16 is dropped, this file can be 5 | // merged/removed with assertion_compare_go1.17_test.go and 6 | // assertion_compare_legacy.go 7 | 8 | package assert 9 | 10 | import "reflect" 11 | 12 | // Wrapper around reflect.Value.CanConvert, for compatibility 13 | // reasons. 14 | func canConvert(value reflect.Value, to reflect.Type) bool { 15 | return value.CanConvert(to) 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go: -------------------------------------------------------------------------------- 1 | //go:build !go1.17 2 | // +build !go1.17 3 | 4 | // TODO: once support for Go 1.16 is dropped, this file can be 5 | // merged/removed with assertion_compare_go1.17_test.go and 6 | // assertion_compare_can_convert.go 7 | 8 | package assert 9 | 10 | import "reflect" 11 | 12 | // Older versions of Go does not have the reflect.Value.CanConvert 13 | // method. 14 | func canConvert(value reflect.Value, to reflect.Type) bool { 15 | return false 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentFormat}} 2 | func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { 3 | if h, ok := t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { 3 | if h, ok := a.t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_order.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | // isOrdered checks that collection contains orderable elements. 9 | func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { 10 | objKind := reflect.TypeOf(object).Kind() 11 | if objKind != reflect.Slice && objKind != reflect.Array { 12 | return false 13 | } 14 | 15 | objValue := reflect.ValueOf(object) 16 | objLen := objValue.Len() 17 | 18 | if objLen <= 1 { 19 | return true 20 | } 21 | 22 | value := objValue.Index(0) 23 | valueInterface := value.Interface() 24 | firstValueKind := value.Kind() 25 | 26 | for i := 1; i < objLen; i++ { 27 | prevValue := value 28 | prevValueInterface := valueInterface 29 | 30 | value = objValue.Index(i) 31 | valueInterface = value.Interface() 32 | 33 | compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind) 34 | 35 | if !isComparable { 36 | return Fail(t, fmt.Sprintf("Can not compare type \"%s\" and \"%s\"", reflect.TypeOf(value), reflect.TypeOf(prevValue)), msgAndArgs...) 37 | } 38 | 39 | if !containsValue(allowedComparesResults, compareResult) { 40 | return Fail(t, fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...) 41 | } 42 | } 43 | 44 | return true 45 | } 46 | 47 | // IsIncreasing asserts that the collection is increasing 48 | // 49 | // assert.IsIncreasing(t, []int{1, 2, 3}) 50 | // assert.IsIncreasing(t, []float{1, 2}) 51 | // assert.IsIncreasing(t, []string{"a", "b"}) 52 | func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 53 | return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) 54 | } 55 | 56 | // IsNonIncreasing asserts that the collection is not increasing 57 | // 58 | // assert.IsNonIncreasing(t, []int{2, 1, 1}) 59 | // assert.IsNonIncreasing(t, []float{2, 1}) 60 | // assert.IsNonIncreasing(t, []string{"b", "a"}) 61 | func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 62 | return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) 63 | } 64 | 65 | // IsDecreasing asserts that the collection is decreasing 66 | // 67 | // assert.IsDecreasing(t, []int{2, 1, 0}) 68 | // assert.IsDecreasing(t, []float{2, 1}) 69 | // assert.IsDecreasing(t, []string{"b", "a"}) 70 | func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 71 | return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) 72 | } 73 | 74 | // IsNonDecreasing asserts that the collection is not decreasing 75 | // 76 | // assert.IsNonDecreasing(t, []int{1, 1, 2}) 77 | // assert.IsNonDecreasing(t, []float{1, 2}) 78 | // assert.IsNonDecreasing(t, []string{"a", "b"}) 79 | func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 80 | return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) 81 | } 82 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/doc.go: -------------------------------------------------------------------------------- 1 | // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. 2 | // 3 | // Example Usage 4 | // 5 | // The following is a complete example using assert in a standard test function: 6 | // import ( 7 | // "testing" 8 | // "github.com/stretchr/testify/assert" 9 | // ) 10 | // 11 | // func TestSomething(t *testing.T) { 12 | // 13 | // var a string = "Hello" 14 | // var b string = "Hello" 15 | // 16 | // assert.Equal(t, a, b, "The two words should be the same.") 17 | // 18 | // } 19 | // 20 | // if you assert many times, use the format below: 21 | // 22 | // import ( 23 | // "testing" 24 | // "github.com/stretchr/testify/assert" 25 | // ) 26 | // 27 | // func TestSomething(t *testing.T) { 28 | // assert := assert.New(t) 29 | // 30 | // var a string = "Hello" 31 | // var b string = "Hello" 32 | // 33 | // assert.Equal(a, b, "The two words should be the same.") 34 | // } 35 | // 36 | // Assertions 37 | // 38 | // Assertions allow you to easily write test code, and are global funcs in the `assert` package. 39 | // All assertion functions take, as the first argument, the `*testing.T` object provided by the 40 | // testing framework. This allows the assertion funcs to write the failings and other details to 41 | // the correct place. 42 | // 43 | // Every assertion function also takes an optional string message as the final argument, 44 | // allowing custom error messages to be appended to the message the assertion method outputs. 45 | package assert 46 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/errors.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // AnError is an error instance useful for testing. If the code does not care 8 | // about error specifics, and only needs to return the error for example, this 9 | // error should be used to make the test code more readable. 10 | var AnError = errors.New("assert.AnError general error for testing") 11 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/forward_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs" 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/doc.go: -------------------------------------------------------------------------------- 1 | // Package require implements the same assertions as the `assert` package but 2 | // stops test execution when a test fails. 3 | // 4 | // Example Usage 5 | // 6 | // The following is a complete example using require in a standard test function: 7 | // import ( 8 | // "testing" 9 | // "github.com/stretchr/testify/require" 10 | // ) 11 | // 12 | // func TestSomething(t *testing.T) { 13 | // 14 | // var a string = "Hello" 15 | // var b string = "Hello" 16 | // 17 | // require.Equal(t, a, b, "The two words should be the same.") 18 | // 19 | // } 20 | // 21 | // Assertions 22 | // 23 | // The `require` package have same global functions as in the `assert` package, 24 | // but instead of returning a boolean result they call `t.FailNow()`. 25 | // 26 | // Every assertion function also takes an optional string message as the final argument, 27 | // allowing custom error messages to be appended to the message the assertion method outputs. 28 | package require 29 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/forward_requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs" 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.Comment}} 2 | func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { 3 | if h, ok := t.(tHelper); ok { h.Helper() } 4 | if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } 5 | t.FailNow() 6 | } 7 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { 3 | if h, ok := a.t.(tHelper); ok { h.Helper() } 4 | {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // TestingT is an interface wrapper around *testing.T 4 | type TestingT interface { 5 | Errorf(format string, args ...interface{}) 6 | FailNow() 7 | } 8 | 9 | type tHelper interface { 10 | Helper() 11 | } 12 | 13 | // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful 14 | // for table driven tests. 15 | type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) 16 | 17 | // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful 18 | // for table driven tests. 19 | type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) 20 | 21 | // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful 22 | // for table driven tests. 23 | type BoolAssertionFunc func(TestingT, bool, ...interface{}) 24 | 25 | // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful 26 | // for table driven tests. 27 | type ErrorAssertionFunc func(TestingT, error, ...interface{}) 28 | 29 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" 30 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/cases/cases.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:generate go run gen.go gen_trieval.go 6 | 7 | // Package cases provides general and language-specific case mappers. 8 | package cases // import "golang.org/x/text/cases" 9 | 10 | import ( 11 | "golang.org/x/text/language" 12 | "golang.org/x/text/transform" 13 | ) 14 | 15 | // References: 16 | // - Unicode Reference Manual Chapter 3.13, 4.2, and 5.18. 17 | // - https://www.unicode.org/reports/tr29/ 18 | // - https://www.unicode.org/Public/6.3.0/ucd/CaseFolding.txt 19 | // - https://www.unicode.org/Public/6.3.0/ucd/SpecialCasing.txt 20 | // - https://www.unicode.org/Public/6.3.0/ucd/DerivedCoreProperties.txt 21 | // - https://www.unicode.org/Public/6.3.0/ucd/auxiliary/WordBreakProperty.txt 22 | // - https://www.unicode.org/Public/6.3.0/ucd/auxiliary/WordBreakTest.txt 23 | // - http://userguide.icu-project.org/transforms/casemappings 24 | 25 | // TODO: 26 | // - Case folding 27 | // - Wide and Narrow? 28 | // - Segmenter option for title casing. 29 | // - ASCII fast paths 30 | // - Encode Soft-Dotted property within trie somehow. 31 | 32 | // A Caser transforms given input to a certain case. It implements 33 | // transform.Transformer. 34 | // 35 | // A Caser may be stateful and should therefore not be shared between 36 | // goroutines. 37 | type Caser struct { 38 | t transform.SpanningTransformer 39 | } 40 | 41 | // Bytes returns a new byte slice with the result of converting b to the case 42 | // form implemented by c. 43 | func (c Caser) Bytes(b []byte) []byte { 44 | b, _, _ = transform.Bytes(c.t, b) 45 | return b 46 | } 47 | 48 | // String returns a string with the result of transforming s to the case form 49 | // implemented by c. 50 | func (c Caser) String(s string) string { 51 | s, _, _ = transform.String(c.t, s) 52 | return s 53 | } 54 | 55 | // Reset resets the Caser to be reused for new input after a previous call to 56 | // Transform. 57 | func (c Caser) Reset() { c.t.Reset() } 58 | 59 | // Transform implements the transform.Transformer interface and transforms the 60 | // given input to the case form implemented by c. 61 | func (c Caser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { 62 | return c.t.Transform(dst, src, atEOF) 63 | } 64 | 65 | // Span implements the transform.SpanningTransformer interface. 66 | func (c Caser) Span(src []byte, atEOF bool) (n int, err error) { 67 | return c.t.Span(src, atEOF) 68 | } 69 | 70 | // Upper returns a Caser for language-specific uppercasing. 71 | func Upper(t language.Tag, opts ...Option) Caser { 72 | return Caser{makeUpper(t, getOpts(opts...))} 73 | } 74 | 75 | // Lower returns a Caser for language-specific lowercasing. 76 | func Lower(t language.Tag, opts ...Option) Caser { 77 | return Caser{makeLower(t, getOpts(opts...))} 78 | } 79 | 80 | // Title returns a Caser for language-specific title casing. It uses an 81 | // approximation of the default Unicode Word Break algorithm. 82 | func Title(t language.Tag, opts ...Option) Caser { 83 | return Caser{makeTitle(t, getOpts(opts...))} 84 | } 85 | 86 | // Fold returns a Caser that implements Unicode case folding. The returned Caser 87 | // is stateless and safe to use concurrently by multiple goroutines. 88 | // 89 | // Case folding does not normalize the input and may not preserve a normal form. 90 | // Use the collate or search package for more convenient and linguistically 91 | // sound comparisons. Use golang.org/x/text/secure/precis for string comparisons 92 | // where security aspects are a concern. 93 | func Fold(opts ...Option) Caser { 94 | return Caser{makeFold(getOpts(opts...))} 95 | } 96 | 97 | // An Option is used to modify the behavior of a Caser. 98 | type Option func(o options) options 99 | 100 | // TODO: consider these options to take a boolean as well, like FinalSigma. 101 | // The advantage of using this approach is that other providers of a lower-case 102 | // algorithm could set different defaults by prefixing a user-provided slice 103 | // of options with their own. This is handy, for instance, for the precis 104 | // package which would override the default to not handle the Greek final sigma. 105 | 106 | var ( 107 | // NoLower disables the lowercasing of non-leading letters for a title 108 | // caser. 109 | NoLower Option = noLower 110 | 111 | // Compact omits mappings in case folding for characters that would grow the 112 | // input. (Unimplemented.) 113 | Compact Option = compact 114 | ) 115 | 116 | // TODO: option to preserve a normal form, if applicable? 117 | 118 | type options struct { 119 | noLower bool 120 | simple bool 121 | 122 | // TODO: segmenter, max ignorable, alternative versions, etc. 123 | 124 | ignoreFinalSigma bool 125 | } 126 | 127 | func getOpts(o ...Option) (res options) { 128 | for _, f := range o { 129 | res = f(res) 130 | } 131 | return 132 | } 133 | 134 | func noLower(o options) options { 135 | o.noLower = true 136 | return o 137 | } 138 | 139 | func compact(o options) options { 140 | o.simple = true 141 | return o 142 | } 143 | 144 | // HandleFinalSigma specifies whether the special handling of Greek final sigma 145 | // should be enabled. Unicode prescribes handling the Greek final sigma for all 146 | // locales, but standards like IDNA and PRECIS override this default. 147 | func HandleFinalSigma(enable bool) Option { 148 | if enable { 149 | return handleFinalSigma 150 | } 151 | return ignoreFinalSigma 152 | } 153 | 154 | func ignoreFinalSigma(o options) options { 155 | o.ignoreFinalSigma = true 156 | return o 157 | } 158 | 159 | func handleFinalSigma(o options) options { 160 | o.ignoreFinalSigma = false 161 | return o 162 | } 163 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/cases/fold.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package cases 6 | 7 | import "golang.org/x/text/transform" 8 | 9 | type caseFolder struct{ transform.NopResetter } 10 | 11 | // caseFolder implements the Transformer interface for doing case folding. 12 | func (t *caseFolder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { 13 | c := context{dst: dst, src: src, atEOF: atEOF} 14 | for c.next() { 15 | foldFull(&c) 16 | c.checkpoint() 17 | } 18 | return c.ret() 19 | } 20 | 21 | func (t *caseFolder) Span(src []byte, atEOF bool) (n int, err error) { 22 | c := context{src: src, atEOF: atEOF} 23 | for c.next() && isFoldFull(&c) { 24 | c.checkpoint() 25 | } 26 | return c.retSpan() 27 | } 28 | 29 | func makeFold(o options) transform.SpanningTransformer { 30 | // TODO: Special case folding, through option Language, Special/Turkic, or 31 | // both. 32 | // TODO: Implement Compact options. 33 | return &caseFolder{} 34 | } 35 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/cases/icu.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build icu 6 | 7 | package cases 8 | 9 | // Ideally these functions would be defined in a test file, but go test doesn't 10 | // allow CGO in tests. The build tag should ensure either way that these 11 | // functions will not end up in the package. 12 | 13 | // TODO: Ensure that the correct ICU version is set. 14 | 15 | /* 16 | #cgo LDFLAGS: -licui18n.57 -licuuc.57 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | */ 23 | import "C" 24 | 25 | import "unsafe" 26 | 27 | func doICU(tag, caser, input string) string { 28 | err := C.UErrorCode(0) 29 | loc := C.CString(tag) 30 | cm := C.ucasemap_open(loc, C.uint32_t(0), &err) 31 | 32 | buf := make([]byte, len(input)*4) 33 | dst := (*C.char)(unsafe.Pointer(&buf[0])) 34 | src := C.CString(input) 35 | 36 | cn := C.int32_t(0) 37 | 38 | switch caser { 39 | case "fold": 40 | cn = C.ucasemap_utf8FoldCase(cm, 41 | dst, C.int32_t(len(buf)), 42 | src, C.int32_t(len(input)), 43 | &err) 44 | case "lower": 45 | cn = C.ucasemap_utf8ToLower(cm, 46 | dst, C.int32_t(len(buf)), 47 | src, C.int32_t(len(input)), 48 | &err) 49 | case "upper": 50 | cn = C.ucasemap_utf8ToUpper(cm, 51 | dst, C.int32_t(len(buf)), 52 | src, C.int32_t(len(input)), 53 | &err) 54 | case "title": 55 | cn = C.ucasemap_utf8ToTitle(cm, 56 | dst, C.int32_t(len(buf)), 57 | src, C.int32_t(len(input)), 58 | &err) 59 | } 60 | return string(buf[:cn]) 61 | } 62 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/cases/info.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package cases 6 | 7 | func (c info) cccVal() info { 8 | if c&exceptionBit != 0 { 9 | return info(exceptions[c>>exceptionShift]) & cccMask 10 | } 11 | return c & cccMask 12 | } 13 | 14 | func (c info) cccType() info { 15 | ccc := c.cccVal() 16 | if ccc <= cccZero { 17 | return cccZero 18 | } 19 | return ccc 20 | } 21 | 22 | // TODO: Implement full Unicode breaking algorithm: 23 | // 1) Implement breaking in separate package. 24 | // 2) Use the breaker here. 25 | // 3) Compare table size and performance of using the more generic breaker. 26 | // 27 | // Note that we can extend the current algorithm to be much more accurate. This 28 | // only makes sense, though, if the performance and/or space penalty of using 29 | // the generic breaker is big. Extra data will only be needed for non-cased 30 | // runes, which means there are sufficient bits left in the caseType. 31 | // ICU prohibits breaking in such cases as well. 32 | 33 | // For the purpose of title casing we use an approximation of the Unicode Word 34 | // Breaking algorithm defined in Annex #29: 35 | // https://www.unicode.org/reports/tr29/#Default_Grapheme_Cluster_Table. 36 | // 37 | // For our approximation, we group the Word Break types into the following 38 | // categories, with associated rules: 39 | // 40 | // 1) Letter: 41 | // ALetter, Hebrew_Letter, Numeric, ExtendNumLet, Extend, Format_FE, ZWJ. 42 | // Rule: Never break between consecutive runes of this category. 43 | // 44 | // 2) Mid: 45 | // MidLetter, MidNumLet, Single_Quote. 46 | // (Cf. case-ignorable: MidLetter, MidNumLet, Single_Quote or cat is Mn, 47 | // Me, Cf, Lm or Sk). 48 | // Rule: Don't break between Letter and Mid, but break between two Mids. 49 | // 50 | // 3) Break: 51 | // Any other category: NewLine, MidNum, CR, LF, Double_Quote, Katakana, and 52 | // Other. 53 | // These categories should always result in a break between two cased letters. 54 | // Rule: Always break. 55 | // 56 | // Note 1: the Katakana and MidNum categories can, in esoteric cases, result in 57 | // preventing a break between two cased letters. For now we will ignore this 58 | // (e.g. [ALetter] [ExtendNumLet] [Katakana] [ExtendNumLet] [ALetter] and 59 | // [ALetter] [Numeric] [MidNum] [Numeric] [ALetter].) 60 | // 61 | // Note 2: the rule for Mid is very approximate, but works in most cases. To 62 | // improve, we could store the categories in the trie value and use a FA to 63 | // manage breaks. See TODO comment above. 64 | // 65 | // Note 3: according to the spec, it is possible for the Extend category to 66 | // introduce breaks between other categories grouped in Letter. However, this 67 | // is undesirable for our purposes. ICU prevents breaks in such cases as well. 68 | 69 | // isBreak returns whether this rune should introduce a break. 70 | func (c info) isBreak() bool { 71 | return c.cccVal() == cccBreak 72 | } 73 | 74 | // isLetter returns whether the rune is of break type ALetter, Hebrew_Letter, 75 | // Numeric, ExtendNumLet, or Extend. 76 | func (c info) isLetter() bool { 77 | ccc := c.cccVal() 78 | if ccc == cccZero { 79 | return !c.isCaseIgnorable() 80 | } 81 | return ccc != cccBreak 82 | } 83 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/internal.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package internal contains non-exported functionality that are used by 6 | // packages in the text repository. 7 | package internal // import "golang.org/x/text/internal" 8 | 9 | import ( 10 | "sort" 11 | 12 | "golang.org/x/text/language" 13 | ) 14 | 15 | // SortTags sorts tags in place. 16 | func SortTags(tags []language.Tag) { 17 | sort.Sort(sorter(tags)) 18 | } 19 | 20 | type sorter []language.Tag 21 | 22 | func (s sorter) Len() int { 23 | return len(s) 24 | } 25 | 26 | func (s sorter) Swap(i, j int) { 27 | s[i], s[j] = s[j], s[i] 28 | } 29 | 30 | func (s sorter) Less(i, j int) bool { 31 | return s[i].String() < s[j].String() 32 | } 33 | 34 | // UniqueTags sorts and filters duplicate tags in place and returns a slice with 35 | // only unique tags. 36 | func UniqueTags(tags []language.Tag) []language.Tag { 37 | if len(tags) <= 1 { 38 | return tags 39 | } 40 | SortTags(tags) 41 | k := 0 42 | for i := 1; i < len(tags); i++ { 43 | if tags[k].String() < tags[i].String() { 44 | k++ 45 | tags[k] = tags[i] 46 | } 47 | } 48 | return tags[:k+1] 49 | } 50 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/common.go: -------------------------------------------------------------------------------- 1 | // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. 2 | 3 | package language 4 | 5 | // This file contains code common to the maketables.go and the package code. 6 | 7 | // AliasType is the type of an alias in AliasMap. 8 | type AliasType int8 9 | 10 | const ( 11 | Deprecated AliasType = iota 12 | Macro 13 | Legacy 14 | 15 | AliasTypeUnknown AliasType = -1 16 | ) 17 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/compact.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package language 6 | 7 | // CompactCoreInfo is a compact integer with the three core tags encoded. 8 | type CompactCoreInfo uint32 9 | 10 | // GetCompactCore generates a uint32 value that is guaranteed to be unique for 11 | // different language, region, and script values. 12 | func GetCompactCore(t Tag) (cci CompactCoreInfo, ok bool) { 13 | if t.LangID > langNoIndexOffset { 14 | return 0, false 15 | } 16 | cci |= CompactCoreInfo(t.LangID) << (8 + 12) 17 | cci |= CompactCoreInfo(t.ScriptID) << 12 18 | cci |= CompactCoreInfo(t.RegionID) 19 | return cci, true 20 | } 21 | 22 | // Tag generates a tag from c. 23 | func (c CompactCoreInfo) Tag() Tag { 24 | return Tag{ 25 | LangID: Language(c >> 20), 26 | RegionID: Region(c & 0x3ff), 27 | ScriptID: Script(c>>12) & 0xff, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/compact/compact.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package compact defines a compact representation of language tags. 6 | // 7 | // Common language tags (at least all for which locale information is defined 8 | // in CLDR) are assigned a unique index. Each Tag is associated with such an 9 | // ID for selecting language-related resources (such as translations) as well 10 | // as one for selecting regional defaults (currency, number formatting, etc.) 11 | // 12 | // It may want to export this functionality at some point, but at this point 13 | // this is only available for use within x/text. 14 | package compact // import "golang.org/x/text/internal/language/compact" 15 | 16 | import ( 17 | "sort" 18 | "strings" 19 | 20 | "golang.org/x/text/internal/language" 21 | ) 22 | 23 | // ID is an integer identifying a single tag. 24 | type ID uint16 25 | 26 | func getCoreIndex(t language.Tag) (id ID, ok bool) { 27 | cci, ok := language.GetCompactCore(t) 28 | if !ok { 29 | return 0, false 30 | } 31 | i := sort.Search(len(coreTags), func(i int) bool { 32 | return cci <= coreTags[i] 33 | }) 34 | if i == len(coreTags) || coreTags[i] != cci { 35 | return 0, false 36 | } 37 | return ID(i), true 38 | } 39 | 40 | // Parent returns the ID of the parent or the root ID if id is already the root. 41 | func (id ID) Parent() ID { 42 | return parents[id] 43 | } 44 | 45 | // Tag converts id to an internal language Tag. 46 | func (id ID) Tag() language.Tag { 47 | if int(id) >= len(coreTags) { 48 | return specialTags[int(id)-len(coreTags)] 49 | } 50 | return coreTags[id].Tag() 51 | } 52 | 53 | var specialTags []language.Tag 54 | 55 | func init() { 56 | tags := strings.Split(specialTagsStr, " ") 57 | specialTags = make([]language.Tag, len(tags)) 58 | for i, t := range tags { 59 | specialTags[i] = language.MustParse(t) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/compact/tags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package compact 6 | 7 | var ( 8 | und = Tag{} 9 | 10 | Und Tag = Tag{} 11 | 12 | Afrikaans Tag = Tag{language: afIndex, locale: afIndex} 13 | Amharic Tag = Tag{language: amIndex, locale: amIndex} 14 | Arabic Tag = Tag{language: arIndex, locale: arIndex} 15 | ModernStandardArabic Tag = Tag{language: ar001Index, locale: ar001Index} 16 | Azerbaijani Tag = Tag{language: azIndex, locale: azIndex} 17 | Bulgarian Tag = Tag{language: bgIndex, locale: bgIndex} 18 | Bengali Tag = Tag{language: bnIndex, locale: bnIndex} 19 | Catalan Tag = Tag{language: caIndex, locale: caIndex} 20 | Czech Tag = Tag{language: csIndex, locale: csIndex} 21 | Danish Tag = Tag{language: daIndex, locale: daIndex} 22 | German Tag = Tag{language: deIndex, locale: deIndex} 23 | Greek Tag = Tag{language: elIndex, locale: elIndex} 24 | English Tag = Tag{language: enIndex, locale: enIndex} 25 | AmericanEnglish Tag = Tag{language: enUSIndex, locale: enUSIndex} 26 | BritishEnglish Tag = Tag{language: enGBIndex, locale: enGBIndex} 27 | Spanish Tag = Tag{language: esIndex, locale: esIndex} 28 | EuropeanSpanish Tag = Tag{language: esESIndex, locale: esESIndex} 29 | LatinAmericanSpanish Tag = Tag{language: es419Index, locale: es419Index} 30 | Estonian Tag = Tag{language: etIndex, locale: etIndex} 31 | Persian Tag = Tag{language: faIndex, locale: faIndex} 32 | Finnish Tag = Tag{language: fiIndex, locale: fiIndex} 33 | Filipino Tag = Tag{language: filIndex, locale: filIndex} 34 | French Tag = Tag{language: frIndex, locale: frIndex} 35 | CanadianFrench Tag = Tag{language: frCAIndex, locale: frCAIndex} 36 | Gujarati Tag = Tag{language: guIndex, locale: guIndex} 37 | Hebrew Tag = Tag{language: heIndex, locale: heIndex} 38 | Hindi Tag = Tag{language: hiIndex, locale: hiIndex} 39 | Croatian Tag = Tag{language: hrIndex, locale: hrIndex} 40 | Hungarian Tag = Tag{language: huIndex, locale: huIndex} 41 | Armenian Tag = Tag{language: hyIndex, locale: hyIndex} 42 | Indonesian Tag = Tag{language: idIndex, locale: idIndex} 43 | Icelandic Tag = Tag{language: isIndex, locale: isIndex} 44 | Italian Tag = Tag{language: itIndex, locale: itIndex} 45 | Japanese Tag = Tag{language: jaIndex, locale: jaIndex} 46 | Georgian Tag = Tag{language: kaIndex, locale: kaIndex} 47 | Kazakh Tag = Tag{language: kkIndex, locale: kkIndex} 48 | Khmer Tag = Tag{language: kmIndex, locale: kmIndex} 49 | Kannada Tag = Tag{language: knIndex, locale: knIndex} 50 | Korean Tag = Tag{language: koIndex, locale: koIndex} 51 | Kirghiz Tag = Tag{language: kyIndex, locale: kyIndex} 52 | Lao Tag = Tag{language: loIndex, locale: loIndex} 53 | Lithuanian Tag = Tag{language: ltIndex, locale: ltIndex} 54 | Latvian Tag = Tag{language: lvIndex, locale: lvIndex} 55 | Macedonian Tag = Tag{language: mkIndex, locale: mkIndex} 56 | Malayalam Tag = Tag{language: mlIndex, locale: mlIndex} 57 | Mongolian Tag = Tag{language: mnIndex, locale: mnIndex} 58 | Marathi Tag = Tag{language: mrIndex, locale: mrIndex} 59 | Malay Tag = Tag{language: msIndex, locale: msIndex} 60 | Burmese Tag = Tag{language: myIndex, locale: myIndex} 61 | Nepali Tag = Tag{language: neIndex, locale: neIndex} 62 | Dutch Tag = Tag{language: nlIndex, locale: nlIndex} 63 | Norwegian Tag = Tag{language: noIndex, locale: noIndex} 64 | Punjabi Tag = Tag{language: paIndex, locale: paIndex} 65 | Polish Tag = Tag{language: plIndex, locale: plIndex} 66 | Portuguese Tag = Tag{language: ptIndex, locale: ptIndex} 67 | BrazilianPortuguese Tag = Tag{language: ptBRIndex, locale: ptBRIndex} 68 | EuropeanPortuguese Tag = Tag{language: ptPTIndex, locale: ptPTIndex} 69 | Romanian Tag = Tag{language: roIndex, locale: roIndex} 70 | Russian Tag = Tag{language: ruIndex, locale: ruIndex} 71 | Sinhala Tag = Tag{language: siIndex, locale: siIndex} 72 | Slovak Tag = Tag{language: skIndex, locale: skIndex} 73 | Slovenian Tag = Tag{language: slIndex, locale: slIndex} 74 | Albanian Tag = Tag{language: sqIndex, locale: sqIndex} 75 | Serbian Tag = Tag{language: srIndex, locale: srIndex} 76 | SerbianLatin Tag = Tag{language: srLatnIndex, locale: srLatnIndex} 77 | Swedish Tag = Tag{language: svIndex, locale: svIndex} 78 | Swahili Tag = Tag{language: swIndex, locale: swIndex} 79 | Tamil Tag = Tag{language: taIndex, locale: taIndex} 80 | Telugu Tag = Tag{language: teIndex, locale: teIndex} 81 | Thai Tag = Tag{language: thIndex, locale: thIndex} 82 | Turkish Tag = Tag{language: trIndex, locale: trIndex} 83 | Ukrainian Tag = Tag{language: ukIndex, locale: ukIndex} 84 | Urdu Tag = Tag{language: urIndex, locale: urIndex} 85 | Uzbek Tag = Tag{language: uzIndex, locale: uzIndex} 86 | Vietnamese Tag = Tag{language: viIndex, locale: viIndex} 87 | Chinese Tag = Tag{language: zhIndex, locale: zhIndex} 88 | SimplifiedChinese Tag = Tag{language: zhHansIndex, locale: zhHansIndex} 89 | TraditionalChinese Tag = Tag{language: zhHantIndex, locale: zhHantIndex} 90 | Zulu Tag = Tag{language: zuIndex, locale: zuIndex} 91 | ) 92 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/compose.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package language 6 | 7 | import ( 8 | "sort" 9 | "strings" 10 | ) 11 | 12 | // A Builder allows constructing a Tag from individual components. 13 | // Its main user is Compose in the top-level language package. 14 | type Builder struct { 15 | Tag Tag 16 | 17 | private string // the x extension 18 | variants []string 19 | extensions []string 20 | } 21 | 22 | // Make returns a new Tag from the current settings. 23 | func (b *Builder) Make() Tag { 24 | t := b.Tag 25 | 26 | if len(b.extensions) > 0 || len(b.variants) > 0 { 27 | sort.Sort(sortVariants(b.variants)) 28 | sort.Strings(b.extensions) 29 | 30 | if b.private != "" { 31 | b.extensions = append(b.extensions, b.private) 32 | } 33 | n := maxCoreSize + tokenLen(b.variants...) + tokenLen(b.extensions...) 34 | buf := make([]byte, n) 35 | p := t.genCoreBytes(buf) 36 | t.pVariant = byte(p) 37 | p += appendTokens(buf[p:], b.variants...) 38 | t.pExt = uint16(p) 39 | p += appendTokens(buf[p:], b.extensions...) 40 | t.str = string(buf[:p]) 41 | // We may not always need to remake the string, but when or when not 42 | // to do so is rather tricky. 43 | scan := makeScanner(buf[:p]) 44 | t, _ = parse(&scan, "") 45 | return t 46 | 47 | } else if b.private != "" { 48 | t.str = b.private 49 | t.RemakeString() 50 | } 51 | return t 52 | } 53 | 54 | // SetTag copies all the settings from a given Tag. Any previously set values 55 | // are discarded. 56 | func (b *Builder) SetTag(t Tag) { 57 | b.Tag.LangID = t.LangID 58 | b.Tag.RegionID = t.RegionID 59 | b.Tag.ScriptID = t.ScriptID 60 | // TODO: optimize 61 | b.variants = b.variants[:0] 62 | if variants := t.Variants(); variants != "" { 63 | for _, vr := range strings.Split(variants[1:], "-") { 64 | b.variants = append(b.variants, vr) 65 | } 66 | } 67 | b.extensions, b.private = b.extensions[:0], "" 68 | for _, e := range t.Extensions() { 69 | b.AddExt(e) 70 | } 71 | } 72 | 73 | // AddExt adds extension e to the tag. e must be a valid extension as returned 74 | // by Tag.Extension. If the extension already exists, it will be discarded, 75 | // except for a -u extension, where non-existing key-type pairs will added. 76 | func (b *Builder) AddExt(e string) { 77 | if e[0] == 'x' { 78 | if b.private == "" { 79 | b.private = e 80 | } 81 | return 82 | } 83 | for i, s := range b.extensions { 84 | if s[0] == e[0] { 85 | if e[0] == 'u' { 86 | b.extensions[i] += e[1:] 87 | } 88 | return 89 | } 90 | } 91 | b.extensions = append(b.extensions, e) 92 | } 93 | 94 | // SetExt sets the extension e to the tag. e must be a valid extension as 95 | // returned by Tag.Extension. If the extension already exists, it will be 96 | // overwritten, except for a -u extension, where the individual key-type pairs 97 | // will be set. 98 | func (b *Builder) SetExt(e string) { 99 | if e[0] == 'x' { 100 | b.private = e 101 | return 102 | } 103 | for i, s := range b.extensions { 104 | if s[0] == e[0] { 105 | if e[0] == 'u' { 106 | b.extensions[i] = e + s[1:] 107 | } else { 108 | b.extensions[i] = e 109 | } 110 | return 111 | } 112 | } 113 | b.extensions = append(b.extensions, e) 114 | } 115 | 116 | // AddVariant adds any number of variants. 117 | func (b *Builder) AddVariant(v ...string) { 118 | for _, v := range v { 119 | if v != "" { 120 | b.variants = append(b.variants, v) 121 | } 122 | } 123 | } 124 | 125 | // ClearVariants removes any variants previously added, including those 126 | // copied from a Tag in SetTag. 127 | func (b *Builder) ClearVariants() { 128 | b.variants = b.variants[:0] 129 | } 130 | 131 | // ClearExtensions removes any extensions previously added, including those 132 | // copied from a Tag in SetTag. 133 | func (b *Builder) ClearExtensions() { 134 | b.private = "" 135 | b.extensions = b.extensions[:0] 136 | } 137 | 138 | func tokenLen(token ...string) (n int) { 139 | for _, t := range token { 140 | n += len(t) + 1 141 | } 142 | return 143 | } 144 | 145 | func appendTokens(b []byte, token ...string) int { 146 | p := 0 147 | for _, t := range token { 148 | b[p] = '-' 149 | copy(b[p+1:], t) 150 | p += 1 + len(t) 151 | } 152 | return p 153 | } 154 | 155 | type sortVariants []string 156 | 157 | func (s sortVariants) Len() int { 158 | return len(s) 159 | } 160 | 161 | func (s sortVariants) Swap(i, j int) { 162 | s[j], s[i] = s[i], s[j] 163 | } 164 | 165 | func (s sortVariants) Less(i, j int) bool { 166 | return variantIndex[s[i]] < variantIndex[s[j]] 167 | } 168 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/coverage.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package language 6 | 7 | // BaseLanguages returns the list of all supported base languages. It generates 8 | // the list by traversing the internal structures. 9 | func BaseLanguages() []Language { 10 | base := make([]Language, 0, NumLanguages) 11 | for i := 0; i < langNoIndexOffset; i++ { 12 | // We included "und" already for the value 0. 13 | if i != nonCanonicalUnd { 14 | base = append(base, Language(i)) 15 | } 16 | } 17 | i := langNoIndexOffset 18 | for _, v := range langNoIndex { 19 | for k := 0; k < 8; k++ { 20 | if v&1 == 1 { 21 | base = append(base, Language(i)) 22 | } 23 | v >>= 1 24 | i++ 25 | } 26 | } 27 | return base 28 | } 29 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/tags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package language 6 | 7 | // MustParse is like Parse, but panics if the given BCP 47 tag cannot be parsed. 8 | // It simplifies safe initialization of Tag values. 9 | func MustParse(s string) Tag { 10 | t, err := Parse(s) 11 | if err != nil { 12 | panic(err) 13 | } 14 | return t 15 | } 16 | 17 | // MustParseBase is like ParseBase, but panics if the given base cannot be parsed. 18 | // It simplifies safe initialization of Base values. 19 | func MustParseBase(s string) Language { 20 | b, err := ParseBase(s) 21 | if err != nil { 22 | panic(err) 23 | } 24 | return b 25 | } 26 | 27 | // MustParseScript is like ParseScript, but panics if the given script cannot be 28 | // parsed. It simplifies safe initialization of Script values. 29 | func MustParseScript(s string) Script { 30 | scr, err := ParseScript(s) 31 | if err != nil { 32 | panic(err) 33 | } 34 | return scr 35 | } 36 | 37 | // MustParseRegion is like ParseRegion, but panics if the given region cannot be 38 | // parsed. It simplifies safe initialization of Region values. 39 | func MustParseRegion(s string) Region { 40 | r, err := ParseRegion(s) 41 | if err != nil { 42 | panic(err) 43 | } 44 | return r 45 | } 46 | 47 | // Und is the root language. 48 | var Und Tag 49 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/match.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package internal 6 | 7 | // This file contains matchers that implement CLDR inheritance. 8 | // 9 | // See https://unicode.org/reports/tr35/#Locale_Inheritance. 10 | // 11 | // Some of the inheritance described in this document is already handled by 12 | // the cldr package. 13 | 14 | import ( 15 | "golang.org/x/text/language" 16 | ) 17 | 18 | // TODO: consider if (some of the) matching algorithm needs to be public after 19 | // getting some feel about what is generic and what is specific. 20 | 21 | // NewInheritanceMatcher returns a matcher that matches based on the inheritance 22 | // chain. 23 | // 24 | // The matcher uses canonicalization and the parent relationship to find a 25 | // match. The resulting match will always be either Und or a language with the 26 | // same language and script as the requested language. It will not match 27 | // languages for which there is understood to be mutual or one-directional 28 | // intelligibility. 29 | // 30 | // A Match will indicate an Exact match if the language matches after 31 | // canonicalization and High if the matched tag is a parent. 32 | func NewInheritanceMatcher(t []language.Tag) *InheritanceMatcher { 33 | tags := &InheritanceMatcher{make(map[language.Tag]int)} 34 | for i, tag := range t { 35 | ct, err := language.All.Canonicalize(tag) 36 | if err != nil { 37 | ct = tag 38 | } 39 | tags.index[ct] = i 40 | } 41 | return tags 42 | } 43 | 44 | type InheritanceMatcher struct { 45 | index map[language.Tag]int 46 | } 47 | 48 | func (m InheritanceMatcher) Match(want ...language.Tag) (language.Tag, int, language.Confidence) { 49 | for _, t := range want { 50 | ct, err := language.All.Canonicalize(t) 51 | if err != nil { 52 | ct = t 53 | } 54 | conf := language.Exact 55 | for { 56 | if index, ok := m.index[ct]; ok { 57 | return ct, index, conf 58 | } 59 | if ct == language.Und { 60 | break 61 | } 62 | ct = ct.Parent() 63 | conf = language.High 64 | } 65 | } 66 | return language.Und, 0, language.No 67 | } 68 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/tag/tag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package tag contains functionality handling tags and related data. 6 | package tag // import "golang.org/x/text/internal/tag" 7 | 8 | import "sort" 9 | 10 | // An Index converts tags to a compact numeric value. 11 | // 12 | // All elements are of size 4. Tags may be up to 4 bytes long. Excess bytes can 13 | // be used to store additional information about the tag. 14 | type Index string 15 | 16 | // Elem returns the element data at the given index. 17 | func (s Index) Elem(x int) string { 18 | return string(s[x*4 : x*4+4]) 19 | } 20 | 21 | // Index reports the index of the given key or -1 if it could not be found. 22 | // Only the first len(key) bytes from the start of the 4-byte entries will be 23 | // considered for the search and the first match in Index will be returned. 24 | func (s Index) Index(key []byte) int { 25 | n := len(key) 26 | // search the index of the first entry with an equal or higher value than 27 | // key in s. 28 | index := sort.Search(len(s)/4, func(i int) bool { 29 | return cmp(s[i*4:i*4+n], key) != -1 30 | }) 31 | i := index * 4 32 | if cmp(s[i:i+len(key)], key) != 0 { 33 | return -1 34 | } 35 | return index 36 | } 37 | 38 | // Next finds the next occurrence of key after index x, which must have been 39 | // obtained from a call to Index using the same key. It returns x+1 or -1. 40 | func (s Index) Next(key []byte, x int) int { 41 | if x++; x*4 < len(s) && cmp(s[x*4:x*4+len(key)], key) == 0 { 42 | return x 43 | } 44 | return -1 45 | } 46 | 47 | // cmp returns an integer comparing a and b lexicographically. 48 | func cmp(a Index, b []byte) int { 49 | n := len(a) 50 | if len(b) < n { 51 | n = len(b) 52 | } 53 | for i, c := range b[:n] { 54 | switch { 55 | case a[i] > c: 56 | return 1 57 | case a[i] < c: 58 | return -1 59 | } 60 | } 61 | switch { 62 | case len(a) < len(b): 63 | return -1 64 | case len(a) > len(b): 65 | return 1 66 | } 67 | return 0 68 | } 69 | 70 | // Compare returns an integer comparing a and b lexicographically. 71 | func Compare(a string, b []byte) int { 72 | return cmp(Index(a), b) 73 | } 74 | 75 | // FixCase reformats b to the same pattern of cases as form. 76 | // If returns false if string b is malformed. 77 | func FixCase(form string, b []byte) bool { 78 | if len(form) != len(b) { 79 | return false 80 | } 81 | for i, c := range b { 82 | if form[i] <= 'Z' { 83 | if c >= 'a' { 84 | c -= 'z' - 'Z' 85 | } 86 | if c < 'A' || 'Z' < c { 87 | return false 88 | } 89 | } else { 90 | if c <= 'Z' { 91 | c += 'z' - 'Z' 92 | } 93 | if c < 'a' || 'z' < c { 94 | return false 95 | } 96 | } 97 | b[i] = c 98 | } 99 | return true 100 | } 101 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/language/coverage.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package language 6 | 7 | import ( 8 | "fmt" 9 | "sort" 10 | 11 | "golang.org/x/text/internal/language" 12 | ) 13 | 14 | // The Coverage interface is used to define the level of coverage of an 15 | // internationalization service. Note that not all types are supported by all 16 | // services. As lists may be generated on the fly, it is recommended that users 17 | // of a Coverage cache the results. 18 | type Coverage interface { 19 | // Tags returns the list of supported tags. 20 | Tags() []Tag 21 | 22 | // BaseLanguages returns the list of supported base languages. 23 | BaseLanguages() []Base 24 | 25 | // Scripts returns the list of supported scripts. 26 | Scripts() []Script 27 | 28 | // Regions returns the list of supported regions. 29 | Regions() []Region 30 | } 31 | 32 | var ( 33 | // Supported defines a Coverage that lists all supported subtags. Tags 34 | // always returns nil. 35 | Supported Coverage = allSubtags{} 36 | ) 37 | 38 | // TODO: 39 | // - Support Variants, numbering systems. 40 | // - CLDR coverage levels. 41 | // - Set of common tags defined in this package. 42 | 43 | type allSubtags struct{} 44 | 45 | // Regions returns the list of supported regions. As all regions are in a 46 | // consecutive range, it simply returns a slice of numbers in increasing order. 47 | // The "undefined" region is not returned. 48 | func (s allSubtags) Regions() []Region { 49 | reg := make([]Region, language.NumRegions) 50 | for i := range reg { 51 | reg[i] = Region{language.Region(i + 1)} 52 | } 53 | return reg 54 | } 55 | 56 | // Scripts returns the list of supported scripts. As all scripts are in a 57 | // consecutive range, it simply returns a slice of numbers in increasing order. 58 | // The "undefined" script is not returned. 59 | func (s allSubtags) Scripts() []Script { 60 | scr := make([]Script, language.NumScripts) 61 | for i := range scr { 62 | scr[i] = Script{language.Script(i + 1)} 63 | } 64 | return scr 65 | } 66 | 67 | // BaseLanguages returns the list of all supported base languages. It generates 68 | // the list by traversing the internal structures. 69 | func (s allSubtags) BaseLanguages() []Base { 70 | bs := language.BaseLanguages() 71 | base := make([]Base, len(bs)) 72 | for i, b := range bs { 73 | base[i] = Base{b} 74 | } 75 | return base 76 | } 77 | 78 | // Tags always returns nil. 79 | func (s allSubtags) Tags() []Tag { 80 | return nil 81 | } 82 | 83 | // coverage is used by NewCoverage which is used as a convenient way for 84 | // creating Coverage implementations for partially defined data. Very often a 85 | // package will only need to define a subset of slices. coverage provides a 86 | // convenient way to do this. Moreover, packages using NewCoverage, instead of 87 | // their own implementation, will not break if later new slice types are added. 88 | type coverage struct { 89 | tags func() []Tag 90 | bases func() []Base 91 | scripts func() []Script 92 | regions func() []Region 93 | } 94 | 95 | func (s *coverage) Tags() []Tag { 96 | if s.tags == nil { 97 | return nil 98 | } 99 | return s.tags() 100 | } 101 | 102 | // bases implements sort.Interface and is used to sort base languages. 103 | type bases []Base 104 | 105 | func (b bases) Len() int { 106 | return len(b) 107 | } 108 | 109 | func (b bases) Swap(i, j int) { 110 | b[i], b[j] = b[j], b[i] 111 | } 112 | 113 | func (b bases) Less(i, j int) bool { 114 | return b[i].langID < b[j].langID 115 | } 116 | 117 | // BaseLanguages returns the result from calling s.bases if it is specified or 118 | // otherwise derives the set of supported base languages from tags. 119 | func (s *coverage) BaseLanguages() []Base { 120 | if s.bases == nil { 121 | tags := s.Tags() 122 | if len(tags) == 0 { 123 | return nil 124 | } 125 | a := make([]Base, len(tags)) 126 | for i, t := range tags { 127 | a[i] = Base{language.Language(t.lang())} 128 | } 129 | sort.Sort(bases(a)) 130 | k := 0 131 | for i := 1; i < len(a); i++ { 132 | if a[k] != a[i] { 133 | k++ 134 | a[k] = a[i] 135 | } 136 | } 137 | return a[:k+1] 138 | } 139 | return s.bases() 140 | } 141 | 142 | func (s *coverage) Scripts() []Script { 143 | if s.scripts == nil { 144 | return nil 145 | } 146 | return s.scripts() 147 | } 148 | 149 | func (s *coverage) Regions() []Region { 150 | if s.regions == nil { 151 | return nil 152 | } 153 | return s.regions() 154 | } 155 | 156 | // NewCoverage returns a Coverage for the given lists. It is typically used by 157 | // packages providing internationalization services to define their level of 158 | // coverage. A list may be of type []T or func() []T, where T is either Tag, 159 | // Base, Script or Region. The returned Coverage derives the value for Bases 160 | // from Tags if no func or slice for []Base is specified. For other unspecified 161 | // types the returned Coverage will return nil for the respective methods. 162 | func NewCoverage(list ...interface{}) Coverage { 163 | s := &coverage{} 164 | for _, x := range list { 165 | switch v := x.(type) { 166 | case func() []Base: 167 | s.bases = v 168 | case func() []Script: 169 | s.scripts = v 170 | case func() []Region: 171 | s.regions = v 172 | case func() []Tag: 173 | s.tags = v 174 | case []Base: 175 | s.bases = func() []Base { return v } 176 | case []Script: 177 | s.scripts = func() []Script { return v } 178 | case []Region: 179 | s.regions = func() []Region { return v } 180 | case []Tag: 181 | s.tags = func() []Tag { return v } 182 | default: 183 | panic(fmt.Sprintf("language: unsupported set type %T", v)) 184 | } 185 | } 186 | return s 187 | } 188 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/language/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package language implements BCP 47 language tags and related functionality. 6 | // 7 | // The most important function of package language is to match a list of 8 | // user-preferred languages to a list of supported languages. 9 | // It alleviates the developer of dealing with the complexity of this process 10 | // and provides the user with the best experience 11 | // (see https://blog.golang.org/matchlang). 12 | // 13 | // # Matching preferred against supported languages 14 | // 15 | // A Matcher for an application that supports English, Australian English, 16 | // Danish, and standard Mandarin can be created as follows: 17 | // 18 | // var matcher = language.NewMatcher([]language.Tag{ 19 | // language.English, // The first language is used as fallback. 20 | // language.MustParse("en-AU"), 21 | // language.Danish, 22 | // language.Chinese, 23 | // }) 24 | // 25 | // This list of supported languages is typically implied by the languages for 26 | // which there exists translations of the user interface. 27 | // 28 | // User-preferred languages usually come as a comma-separated list of BCP 47 29 | // language tags. 30 | // The MatchString finds best matches for such strings: 31 | // 32 | // handler(w http.ResponseWriter, r *http.Request) { 33 | // lang, _ := r.Cookie("lang") 34 | // accept := r.Header.Get("Accept-Language") 35 | // tag, _ := language.MatchStrings(matcher, lang.String(), accept) 36 | // 37 | // // tag should now be used for the initialization of any 38 | // // locale-specific service. 39 | // } 40 | // 41 | // The Matcher's Match method can be used to match Tags directly. 42 | // 43 | // Matchers are aware of the intricacies of equivalence between languages, such 44 | // as deprecated subtags, legacy tags, macro languages, mutual 45 | // intelligibility between scripts and languages, and transparently passing 46 | // BCP 47 user configuration. 47 | // For instance, it will know that a reader of Bokmål Danish can read Norwegian 48 | // and will know that Cantonese ("yue") is a good match for "zh-HK". 49 | // 50 | // # Using match results 51 | // 52 | // To guarantee a consistent user experience to the user it is important to 53 | // use the same language tag for the selection of any locale-specific services. 54 | // For example, it is utterly confusing to substitute spelled-out numbers 55 | // or dates in one language in text of another language. 56 | // More subtly confusing is using the wrong sorting order or casing 57 | // algorithm for a certain language. 58 | // 59 | // All the packages in x/text that provide locale-specific services 60 | // (e.g. collate, cases) should be initialized with the tag that was 61 | // obtained at the start of an interaction with the user. 62 | // 63 | // Note that Tag that is returned by Match and MatchString may differ from any 64 | // of the supported languages, as it may contain carried over settings from 65 | // the user tags. 66 | // This may be inconvenient when your application has some additional 67 | // locale-specific data for your supported languages. 68 | // Match and MatchString both return the index of the matched supported tag 69 | // to simplify associating such data with the matched tag. 70 | // 71 | // # Canonicalization 72 | // 73 | // If one uses the Matcher to compare languages one does not need to 74 | // worry about canonicalization. 75 | // 76 | // The meaning of a Tag varies per application. The language package 77 | // therefore delays canonicalization and preserves information as much 78 | // as possible. The Matcher, however, will always take into account that 79 | // two different tags may represent the same language. 80 | // 81 | // By default, only legacy and deprecated tags are converted into their 82 | // canonical equivalent. All other information is preserved. This approach makes 83 | // the confidence scores more accurate and allows matchers to distinguish 84 | // between variants that are otherwise lost. 85 | // 86 | // As a consequence, two tags that should be treated as identical according to 87 | // BCP 47 or CLDR, like "en-Latn" and "en", will be represented differently. The 88 | // Matcher handles such distinctions, though, and is aware of the 89 | // equivalence relations. The CanonType type can be used to alter the 90 | // canonicalization form. 91 | // 92 | // # References 93 | // 94 | // BCP 47 - Tags for Identifying Languages http://tools.ietf.org/html/bcp47 95 | package language // import "golang.org/x/text/language" 96 | 97 | // TODO: explanation on how to match languages for your own locale-specific 98 | // service. 99 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/language/tags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package language 6 | 7 | import "golang.org/x/text/internal/language/compact" 8 | 9 | // TODO: Various sets of commonly use tags and regions. 10 | 11 | // MustParse is like Parse, but panics if the given BCP 47 tag cannot be parsed. 12 | // It simplifies safe initialization of Tag values. 13 | func MustParse(s string) Tag { 14 | t, err := Parse(s) 15 | if err != nil { 16 | panic(err) 17 | } 18 | return t 19 | } 20 | 21 | // MustParse is like Parse, but panics if the given BCP 47 tag cannot be parsed. 22 | // It simplifies safe initialization of Tag values. 23 | func (c CanonType) MustParse(s string) Tag { 24 | t, err := c.Parse(s) 25 | if err != nil { 26 | panic(err) 27 | } 28 | return t 29 | } 30 | 31 | // MustParseBase is like ParseBase, but panics if the given base cannot be parsed. 32 | // It simplifies safe initialization of Base values. 33 | func MustParseBase(s string) Base { 34 | b, err := ParseBase(s) 35 | if err != nil { 36 | panic(err) 37 | } 38 | return b 39 | } 40 | 41 | // MustParseScript is like ParseScript, but panics if the given script cannot be 42 | // parsed. It simplifies safe initialization of Script values. 43 | func MustParseScript(s string) Script { 44 | scr, err := ParseScript(s) 45 | if err != nil { 46 | panic(err) 47 | } 48 | return scr 49 | } 50 | 51 | // MustParseRegion is like ParseRegion, but panics if the given region cannot be 52 | // parsed. It simplifies safe initialization of Region values. 53 | func MustParseRegion(s string) Region { 54 | r, err := ParseRegion(s) 55 | if err != nil { 56 | panic(err) 57 | } 58 | return r 59 | } 60 | 61 | var ( 62 | und = Tag{} 63 | 64 | Und Tag = Tag{} 65 | 66 | Afrikaans Tag = Tag(compact.Afrikaans) 67 | Amharic Tag = Tag(compact.Amharic) 68 | Arabic Tag = Tag(compact.Arabic) 69 | ModernStandardArabic Tag = Tag(compact.ModernStandardArabic) 70 | Azerbaijani Tag = Tag(compact.Azerbaijani) 71 | Bulgarian Tag = Tag(compact.Bulgarian) 72 | Bengali Tag = Tag(compact.Bengali) 73 | Catalan Tag = Tag(compact.Catalan) 74 | Czech Tag = Tag(compact.Czech) 75 | Danish Tag = Tag(compact.Danish) 76 | German Tag = Tag(compact.German) 77 | Greek Tag = Tag(compact.Greek) 78 | English Tag = Tag(compact.English) 79 | AmericanEnglish Tag = Tag(compact.AmericanEnglish) 80 | BritishEnglish Tag = Tag(compact.BritishEnglish) 81 | Spanish Tag = Tag(compact.Spanish) 82 | EuropeanSpanish Tag = Tag(compact.EuropeanSpanish) 83 | LatinAmericanSpanish Tag = Tag(compact.LatinAmericanSpanish) 84 | Estonian Tag = Tag(compact.Estonian) 85 | Persian Tag = Tag(compact.Persian) 86 | Finnish Tag = Tag(compact.Finnish) 87 | Filipino Tag = Tag(compact.Filipino) 88 | French Tag = Tag(compact.French) 89 | CanadianFrench Tag = Tag(compact.CanadianFrench) 90 | Gujarati Tag = Tag(compact.Gujarati) 91 | Hebrew Tag = Tag(compact.Hebrew) 92 | Hindi Tag = Tag(compact.Hindi) 93 | Croatian Tag = Tag(compact.Croatian) 94 | Hungarian Tag = Tag(compact.Hungarian) 95 | Armenian Tag = Tag(compact.Armenian) 96 | Indonesian Tag = Tag(compact.Indonesian) 97 | Icelandic Tag = Tag(compact.Icelandic) 98 | Italian Tag = Tag(compact.Italian) 99 | Japanese Tag = Tag(compact.Japanese) 100 | Georgian Tag = Tag(compact.Georgian) 101 | Kazakh Tag = Tag(compact.Kazakh) 102 | Khmer Tag = Tag(compact.Khmer) 103 | Kannada Tag = Tag(compact.Kannada) 104 | Korean Tag = Tag(compact.Korean) 105 | Kirghiz Tag = Tag(compact.Kirghiz) 106 | Lao Tag = Tag(compact.Lao) 107 | Lithuanian Tag = Tag(compact.Lithuanian) 108 | Latvian Tag = Tag(compact.Latvian) 109 | Macedonian Tag = Tag(compact.Macedonian) 110 | Malayalam Tag = Tag(compact.Malayalam) 111 | Mongolian Tag = Tag(compact.Mongolian) 112 | Marathi Tag = Tag(compact.Marathi) 113 | Malay Tag = Tag(compact.Malay) 114 | Burmese Tag = Tag(compact.Burmese) 115 | Nepali Tag = Tag(compact.Nepali) 116 | Dutch Tag = Tag(compact.Dutch) 117 | Norwegian Tag = Tag(compact.Norwegian) 118 | Punjabi Tag = Tag(compact.Punjabi) 119 | Polish Tag = Tag(compact.Polish) 120 | Portuguese Tag = Tag(compact.Portuguese) 121 | BrazilianPortuguese Tag = Tag(compact.BrazilianPortuguese) 122 | EuropeanPortuguese Tag = Tag(compact.EuropeanPortuguese) 123 | Romanian Tag = Tag(compact.Romanian) 124 | Russian Tag = Tag(compact.Russian) 125 | Sinhala Tag = Tag(compact.Sinhala) 126 | Slovak Tag = Tag(compact.Slovak) 127 | Slovenian Tag = Tag(compact.Slovenian) 128 | Albanian Tag = Tag(compact.Albanian) 129 | Serbian Tag = Tag(compact.Serbian) 130 | SerbianLatin Tag = Tag(compact.SerbianLatin) 131 | Swedish Tag = Tag(compact.Swedish) 132 | Swahili Tag = Tag(compact.Swahili) 133 | Tamil Tag = Tag(compact.Tamil) 134 | Telugu Tag = Tag(compact.Telugu) 135 | Thai Tag = Tag(compact.Thai) 136 | Turkish Tag = Tag(compact.Turkish) 137 | Ukrainian Tag = Tag(compact.Ukrainian) 138 | Urdu Tag = Tag(compact.Urdu) 139 | Uzbek Tag = Tag(compact.Uzbek) 140 | Vietnamese Tag = Tag(compact.Vietnamese) 141 | Chinese Tag = Tag(compact.Chinese) 142 | SimplifiedChinese Tag = Tag(compact.SimplifiedChinese) 143 | TraditionalChinese Tag = Tag(compact.TraditionalChinese) 144 | Zulu Tag = Tag(compact.Zulu) 145 | ) 146 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/unicode/norm/input.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package norm 6 | 7 | import "unicode/utf8" 8 | 9 | type input struct { 10 | str string 11 | bytes []byte 12 | } 13 | 14 | func inputBytes(str []byte) input { 15 | return input{bytes: str} 16 | } 17 | 18 | func inputString(str string) input { 19 | return input{str: str} 20 | } 21 | 22 | func (in *input) setBytes(str []byte) { 23 | in.str = "" 24 | in.bytes = str 25 | } 26 | 27 | func (in *input) setString(str string) { 28 | in.str = str 29 | in.bytes = nil 30 | } 31 | 32 | func (in *input) _byte(p int) byte { 33 | if in.bytes == nil { 34 | return in.str[p] 35 | } 36 | return in.bytes[p] 37 | } 38 | 39 | func (in *input) skipASCII(p, max int) int { 40 | if in.bytes == nil { 41 | for ; p < max && in.str[p] < utf8.RuneSelf; p++ { 42 | } 43 | } else { 44 | for ; p < max && in.bytes[p] < utf8.RuneSelf; p++ { 45 | } 46 | } 47 | return p 48 | } 49 | 50 | func (in *input) skipContinuationBytes(p int) int { 51 | if in.bytes == nil { 52 | for ; p < len(in.str) && !utf8.RuneStart(in.str[p]); p++ { 53 | } 54 | } else { 55 | for ; p < len(in.bytes) && !utf8.RuneStart(in.bytes[p]); p++ { 56 | } 57 | } 58 | return p 59 | } 60 | 61 | func (in *input) appendSlice(buf []byte, b, e int) []byte { 62 | if in.bytes != nil { 63 | return append(buf, in.bytes[b:e]...) 64 | } 65 | for i := b; i < e; i++ { 66 | buf = append(buf, in.str[i]) 67 | } 68 | return buf 69 | } 70 | 71 | func (in *input) copySlice(buf []byte, b, e int) int { 72 | if in.bytes == nil { 73 | return copy(buf, in.str[b:e]) 74 | } 75 | return copy(buf, in.bytes[b:e]) 76 | } 77 | 78 | func (in *input) charinfoNFC(p int) (uint16, int) { 79 | if in.bytes == nil { 80 | return nfcData.lookupString(in.str[p:]) 81 | } 82 | return nfcData.lookup(in.bytes[p:]) 83 | } 84 | 85 | func (in *input) charinfoNFKC(p int) (uint16, int) { 86 | if in.bytes == nil { 87 | return nfkcData.lookupString(in.str[p:]) 88 | } 89 | return nfkcData.lookup(in.bytes[p:]) 90 | } 91 | 92 | func (in *input) hangul(p int) (r rune) { 93 | var size int 94 | if in.bytes == nil { 95 | if !isHangulString(in.str[p:]) { 96 | return 0 97 | } 98 | r, size = utf8.DecodeRuneInString(in.str[p:]) 99 | } else { 100 | if !isHangul(in.bytes[p:]) { 101 | return 0 102 | } 103 | r, size = utf8.DecodeRune(in.bytes[p:]) 104 | } 105 | if size != hangulUTF8Size { 106 | return 0 107 | } 108 | return r 109 | } 110 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/unicode/norm/readwriter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package norm 6 | 7 | import "io" 8 | 9 | type normWriter struct { 10 | rb reorderBuffer 11 | w io.Writer 12 | buf []byte 13 | } 14 | 15 | // Write implements the standard write interface. If the last characters are 16 | // not at a normalization boundary, the bytes will be buffered for the next 17 | // write. The remaining bytes will be written on close. 18 | func (w *normWriter) Write(data []byte) (n int, err error) { 19 | // Process data in pieces to keep w.buf size bounded. 20 | const chunk = 4000 21 | 22 | for len(data) > 0 { 23 | // Normalize into w.buf. 24 | m := len(data) 25 | if m > chunk { 26 | m = chunk 27 | } 28 | w.rb.src = inputBytes(data[:m]) 29 | w.rb.nsrc = m 30 | w.buf = doAppend(&w.rb, w.buf, 0) 31 | data = data[m:] 32 | n += m 33 | 34 | // Write out complete prefix, save remainder. 35 | // Note that lastBoundary looks back at most 31 runes. 36 | i := lastBoundary(&w.rb.f, w.buf) 37 | if i == -1 { 38 | i = 0 39 | } 40 | if i > 0 { 41 | if _, err = w.w.Write(w.buf[:i]); err != nil { 42 | break 43 | } 44 | bn := copy(w.buf, w.buf[i:]) 45 | w.buf = w.buf[:bn] 46 | } 47 | } 48 | return n, err 49 | } 50 | 51 | // Close forces data that remains in the buffer to be written. 52 | func (w *normWriter) Close() error { 53 | if len(w.buf) > 0 { 54 | _, err := w.w.Write(w.buf) 55 | if err != nil { 56 | return err 57 | } 58 | } 59 | return nil 60 | } 61 | 62 | // Writer returns a new writer that implements Write(b) 63 | // by writing f(b) to w. The returned writer may use an 64 | // internal buffer to maintain state across Write calls. 65 | // Calling its Close method writes any buffered data to w. 66 | func (f Form) Writer(w io.Writer) io.WriteCloser { 67 | wr := &normWriter{rb: reorderBuffer{}, w: w} 68 | wr.rb.init(f, nil) 69 | return wr 70 | } 71 | 72 | type normReader struct { 73 | rb reorderBuffer 74 | r io.Reader 75 | inbuf []byte 76 | outbuf []byte 77 | bufStart int 78 | lastBoundary int 79 | err error 80 | } 81 | 82 | // Read implements the standard read interface. 83 | func (r *normReader) Read(p []byte) (int, error) { 84 | for { 85 | if r.lastBoundary-r.bufStart > 0 { 86 | n := copy(p, r.outbuf[r.bufStart:r.lastBoundary]) 87 | r.bufStart += n 88 | if r.lastBoundary-r.bufStart > 0 { 89 | return n, nil 90 | } 91 | return n, r.err 92 | } 93 | if r.err != nil { 94 | return 0, r.err 95 | } 96 | outn := copy(r.outbuf, r.outbuf[r.lastBoundary:]) 97 | r.outbuf = r.outbuf[0:outn] 98 | r.bufStart = 0 99 | 100 | n, err := r.r.Read(r.inbuf) 101 | r.rb.src = inputBytes(r.inbuf[0:n]) 102 | r.rb.nsrc, r.err = n, err 103 | if n > 0 { 104 | r.outbuf = doAppend(&r.rb, r.outbuf, 0) 105 | } 106 | if err == io.EOF { 107 | r.lastBoundary = len(r.outbuf) 108 | } else { 109 | r.lastBoundary = lastBoundary(&r.rb.f, r.outbuf) 110 | if r.lastBoundary == -1 { 111 | r.lastBoundary = 0 112 | } 113 | } 114 | } 115 | } 116 | 117 | // Reader returns a new reader that implements Read 118 | // by reading data from r and returning f(data). 119 | func (f Form) Reader(r io.Reader) io.Reader { 120 | const chunk = 4000 121 | buf := make([]byte, chunk) 122 | rr := &normReader{rb: reorderBuffer{}, r: r, inbuf: buf} 123 | rr.rb.init(f, buf) 124 | return rr 125 | } 126 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/unicode/norm/transform.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package norm 6 | 7 | import ( 8 | "unicode/utf8" 9 | 10 | "golang.org/x/text/transform" 11 | ) 12 | 13 | // Reset implements the Reset method of the transform.Transformer interface. 14 | func (Form) Reset() {} 15 | 16 | // Transform implements the Transform method of the transform.Transformer 17 | // interface. It may need to write segments of up to MaxSegmentSize at once. 18 | // Users should either catch ErrShortDst and allow dst to grow or have dst be at 19 | // least of size MaxTransformChunkSize to be guaranteed of progress. 20 | func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { 21 | // Cap the maximum number of src bytes to check. 22 | b := src 23 | eof := atEOF 24 | if ns := len(dst); ns < len(b) { 25 | err = transform.ErrShortDst 26 | eof = false 27 | b = b[:ns] 28 | } 29 | i, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), eof) 30 | n := copy(dst, b[:i]) 31 | if !ok { 32 | nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF) 33 | return nDst + n, nSrc + n, err 34 | } 35 | 36 | if err == nil && n < len(src) && !atEOF { 37 | err = transform.ErrShortSrc 38 | } 39 | return n, n, err 40 | } 41 | 42 | func flushTransform(rb *reorderBuffer) bool { 43 | // Write out (must fully fit in dst, or else it is an ErrShortDst). 44 | if len(rb.out) < rb.nrune*utf8.UTFMax { 45 | return false 46 | } 47 | rb.out = rb.out[rb.flushCopy(rb.out):] 48 | return true 49 | } 50 | 51 | var errs = []error{nil, transform.ErrShortDst, transform.ErrShortSrc} 52 | 53 | // transform implements the transform.Transformer interface. It is only called 54 | // when quickSpan does not pass for a given string. 55 | func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { 56 | // TODO: get rid of reorderBuffer. See CL 23460044. 57 | rb := reorderBuffer{} 58 | rb.init(f, src) 59 | for { 60 | // Load segment into reorder buffer. 61 | rb.setFlusher(dst[nDst:], flushTransform) 62 | end := decomposeSegment(&rb, nSrc, atEOF) 63 | if end < 0 { 64 | return nDst, nSrc, errs[-end] 65 | } 66 | nDst = len(dst) - len(rb.out) 67 | nSrc = end 68 | 69 | // Next quickSpan. 70 | end = rb.nsrc 71 | eof := atEOF 72 | if n := nSrc + len(dst) - nDst; n < end { 73 | err = transform.ErrShortDst 74 | end = n 75 | eof = false 76 | } 77 | end, ok := rb.f.quickSpan(rb.src, nSrc, end, eof) 78 | n := copy(dst[nDst:], rb.src.bytes[nSrc:end]) 79 | nSrc += n 80 | nDst += n 81 | if ok { 82 | if err == nil && n < rb.nsrc && !atEOF { 83 | err = transform.ErrShortSrc 84 | } 85 | return nDst, nSrc, err 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/unicode/norm/trie.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package norm 6 | 7 | type valueRange struct { 8 | value uint16 // header: value:stride 9 | lo, hi byte // header: lo:n 10 | } 11 | 12 | type sparseBlocks struct { 13 | values []valueRange 14 | offset []uint16 15 | } 16 | 17 | var nfcSparse = sparseBlocks{ 18 | values: nfcSparseValues[:], 19 | offset: nfcSparseOffset[:], 20 | } 21 | 22 | var nfkcSparse = sparseBlocks{ 23 | values: nfkcSparseValues[:], 24 | offset: nfkcSparseOffset[:], 25 | } 26 | 27 | var ( 28 | nfcData = newNfcTrie(0) 29 | nfkcData = newNfkcTrie(0) 30 | ) 31 | 32 | // lookup determines the type of block n and looks up the value for b. 33 | // For n < t.cutoff, the block is a simple lookup table. Otherwise, the block 34 | // is a list of ranges with an accompanying value. Given a matching range r, 35 | // the value for b is by r.value + (b - r.lo) * stride. 36 | func (t *sparseBlocks) lookup(n uint32, b byte) uint16 { 37 | offset := t.offset[n] 38 | header := t.values[offset] 39 | lo := offset + 1 40 | hi := lo + uint16(header.lo) 41 | for lo < hi { 42 | m := lo + (hi-lo)/2 43 | r := t.values[m] 44 | if r.lo <= b && b <= r.hi { 45 | return r.value + uint16(b-r.lo)*header.value 46 | } 47 | if b < r.lo { 48 | hi = m 49 | } else { 50 | lo = m + 1 51 | } 52 | } 53 | return 0 54 | } 55 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | This project is covered by two different licenses: MIT and Apache. 3 | 4 | #### MIT License #### 5 | 6 | The following files were ported to Go from C files of libyaml, and thus 7 | are still covered by their original MIT license, with the additional 8 | copyright staring in 2011 when the project was ported over: 9 | 10 | apic.go emitterc.go parserc.go readerc.go scannerc.go 11 | writerc.go yamlh.go yamlprivateh.go 12 | 13 | Copyright (c) 2006-2010 Kirill Simonov 14 | Copyright (c) 2006-2011 Kirill Simonov 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy of 17 | this software and associated documentation files (the "Software"), to deal in 18 | the Software without restriction, including without limitation the rights to 19 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 20 | of the Software, and to permit persons to whom the Software is furnished to do 21 | so, subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be included in all 24 | copies or substantial portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | SOFTWARE. 33 | 34 | ### Apache License ### 35 | 36 | All the remaining project files are covered by the Apache license: 37 | 38 | Copyright (c) 2011-2019 Canonical Ltd 39 | 40 | Licensed under the Apache License, Version 2.0 (the "License"); 41 | you may not use this file except in compliance with the License. 42 | You may obtain a copy of the License at 43 | 44 | http://www.apache.org/licenses/LICENSE-2.0 45 | 46 | Unless required by applicable law or agreed to in writing, software 47 | distributed under the License is distributed on an "AS IS" BASIS, 48 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 49 | See the License for the specific language governing permissions and 50 | limitations under the License. 51 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2011-2016 Canonical Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/README.md: -------------------------------------------------------------------------------- 1 | # YAML support for the Go language 2 | 3 | Introduction 4 | ------------ 5 | 6 | The yaml package enables Go programs to comfortably encode and decode YAML 7 | values. It was developed within [Canonical](https://www.canonical.com) as 8 | part of the [juju](https://juju.ubuntu.com) project, and is based on a 9 | pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) 10 | C library to parse and generate YAML data quickly and reliably. 11 | 12 | Compatibility 13 | ------------- 14 | 15 | The yaml package supports most of YAML 1.2, but preserves some behavior 16 | from 1.1 for backwards compatibility. 17 | 18 | Specifically, as of v3 of the yaml package: 19 | 20 | - YAML 1.1 bools (_yes/no, on/off_) are supported as long as they are being 21 | decoded into a typed bool value. Otherwise they behave as a string. Booleans 22 | in YAML 1.2 are _true/false_ only. 23 | - Octals encode and decode as _0777_ per YAML 1.1, rather than _0o777_ 24 | as specified in YAML 1.2, because most parsers still use the old format. 25 | Octals in the _0o777_ format are supported though, so new files work. 26 | - Does not support base-60 floats. These are gone from YAML 1.2, and were 27 | actually never supported by this package as it's clearly a poor choice. 28 | 29 | and offers backwards 30 | compatibility with YAML 1.1 in some cases. 31 | 1.2, including support for 32 | anchors, tags, map merging, etc. Multi-document unmarshalling is not yet 33 | implemented, and base-60 floats from YAML 1.1 are purposefully not 34 | supported since they're a poor design and are gone in YAML 1.2. 35 | 36 | Installation and usage 37 | ---------------------- 38 | 39 | The import path for the package is *gopkg.in/yaml.v3*. 40 | 41 | To install it, run: 42 | 43 | go get gopkg.in/yaml.v3 44 | 45 | API documentation 46 | ----------------- 47 | 48 | If opened in a browser, the import path itself leads to the API documentation: 49 | 50 | - [https://gopkg.in/yaml.v3](https://gopkg.in/yaml.v3) 51 | 52 | API stability 53 | ------------- 54 | 55 | The package API for yaml v3 will remain stable as described in [gopkg.in](https://gopkg.in). 56 | 57 | 58 | License 59 | ------- 60 | 61 | The yaml package is licensed under the MIT and Apache License 2.0 licenses. 62 | Please see the LICENSE file for details. 63 | 64 | 65 | Example 66 | ------- 67 | 68 | ```Go 69 | package main 70 | 71 | import ( 72 | "fmt" 73 | "log" 74 | 75 | "gopkg.in/yaml.v3" 76 | ) 77 | 78 | var data = ` 79 | a: Easy! 80 | b: 81 | c: 2 82 | d: [3, 4] 83 | ` 84 | 85 | // Note: struct fields must be public in order for unmarshal to 86 | // correctly populate the data. 87 | type T struct { 88 | A string 89 | B struct { 90 | RenamedC int `yaml:"c"` 91 | D []int `yaml:",flow"` 92 | } 93 | } 94 | 95 | func main() { 96 | t := T{} 97 | 98 | err := yaml.Unmarshal([]byte(data), &t) 99 | if err != nil { 100 | log.Fatalf("error: %v", err) 101 | } 102 | fmt.Printf("--- t:\n%v\n\n", t) 103 | 104 | d, err := yaml.Marshal(&t) 105 | if err != nil { 106 | log.Fatalf("error: %v", err) 107 | } 108 | fmt.Printf("--- t dump:\n%s\n\n", string(d)) 109 | 110 | m := make(map[interface{}]interface{}) 111 | 112 | err = yaml.Unmarshal([]byte(data), &m) 113 | if err != nil { 114 | log.Fatalf("error: %v", err) 115 | } 116 | fmt.Printf("--- m:\n%v\n\n", m) 117 | 118 | d, err = yaml.Marshal(&m) 119 | if err != nil { 120 | log.Fatalf("error: %v", err) 121 | } 122 | fmt.Printf("--- m dump:\n%s\n\n", string(d)) 123 | } 124 | ``` 125 | 126 | This example will generate the following output: 127 | 128 | ``` 129 | --- t: 130 | {Easy! {2 [3 4]}} 131 | 132 | --- t dump: 133 | a: Easy! 134 | b: 135 | c: 2 136 | d: [3, 4] 137 | 138 | 139 | --- m: 140 | map[a:Easy! b:map[c:2 d:[3 4]]] 141 | 142 | --- m dump: 143 | a: Easy! 144 | b: 145 | c: 2 146 | d: 147 | - 3 148 | - 4 149 | ``` 150 | 151 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/sorter.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2011-2019 Canonical Ltd 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package yaml 17 | 18 | import ( 19 | "reflect" 20 | "unicode" 21 | ) 22 | 23 | type keyList []reflect.Value 24 | 25 | func (l keyList) Len() int { return len(l) } 26 | func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 27 | func (l keyList) Less(i, j int) bool { 28 | a := l[i] 29 | b := l[j] 30 | ak := a.Kind() 31 | bk := b.Kind() 32 | for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { 33 | a = a.Elem() 34 | ak = a.Kind() 35 | } 36 | for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { 37 | b = b.Elem() 38 | bk = b.Kind() 39 | } 40 | af, aok := keyFloat(a) 41 | bf, bok := keyFloat(b) 42 | if aok && bok { 43 | if af != bf { 44 | return af < bf 45 | } 46 | if ak != bk { 47 | return ak < bk 48 | } 49 | return numLess(a, b) 50 | } 51 | if ak != reflect.String || bk != reflect.String { 52 | return ak < bk 53 | } 54 | ar, br := []rune(a.String()), []rune(b.String()) 55 | digits := false 56 | for i := 0; i < len(ar) && i < len(br); i++ { 57 | if ar[i] == br[i] { 58 | digits = unicode.IsDigit(ar[i]) 59 | continue 60 | } 61 | al := unicode.IsLetter(ar[i]) 62 | bl := unicode.IsLetter(br[i]) 63 | if al && bl { 64 | return ar[i] < br[i] 65 | } 66 | if al || bl { 67 | if digits { 68 | return al 69 | } else { 70 | return bl 71 | } 72 | } 73 | var ai, bi int 74 | var an, bn int64 75 | if ar[i] == '0' || br[i] == '0' { 76 | for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- { 77 | if ar[j] != '0' { 78 | an = 1 79 | bn = 1 80 | break 81 | } 82 | } 83 | } 84 | for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { 85 | an = an*10 + int64(ar[ai]-'0') 86 | } 87 | for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { 88 | bn = bn*10 + int64(br[bi]-'0') 89 | } 90 | if an != bn { 91 | return an < bn 92 | } 93 | if ai != bi { 94 | return ai < bi 95 | } 96 | return ar[i] < br[i] 97 | } 98 | return len(ar) < len(br) 99 | } 100 | 101 | // keyFloat returns a float value for v if it is a number/bool 102 | // and whether it is a number/bool or not. 103 | func keyFloat(v reflect.Value) (f float64, ok bool) { 104 | switch v.Kind() { 105 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 106 | return float64(v.Int()), true 107 | case reflect.Float32, reflect.Float64: 108 | return v.Float(), true 109 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 110 | return float64(v.Uint()), true 111 | case reflect.Bool: 112 | if v.Bool() { 113 | return 1, true 114 | } 115 | return 0, true 116 | } 117 | return 0, false 118 | } 119 | 120 | // numLess returns whether a < b. 121 | // a and b must necessarily have the same kind. 122 | func numLess(a, b reflect.Value) bool { 123 | switch a.Kind() { 124 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 125 | return a.Int() < b.Int() 126 | case reflect.Float32, reflect.Float64: 127 | return a.Float() < b.Float() 128 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 129 | return a.Uint() < b.Uint() 130 | case reflect.Bool: 131 | return !a.Bool() && b.Bool() 132 | } 133 | panic("not a number") 134 | } 135 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/writerc.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2011-2019 Canonical Ltd 3 | // Copyright (c) 2006-2010 Kirill Simonov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | // this software and associated documentation files (the "Software"), to deal in 7 | // the Software without restriction, including without limitation the rights to 8 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | // of the Software, and to permit persons to whom the Software is furnished to do 10 | // so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package yaml 24 | 25 | // Set the writer error and return false. 26 | func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { 27 | emitter.error = yaml_WRITER_ERROR 28 | emitter.problem = problem 29 | return false 30 | } 31 | 32 | // Flush the output buffer. 33 | func yaml_emitter_flush(emitter *yaml_emitter_t) bool { 34 | if emitter.write_handler == nil { 35 | panic("write handler not set") 36 | } 37 | 38 | // Check if the buffer is empty. 39 | if emitter.buffer_pos == 0 { 40 | return true 41 | } 42 | 43 | if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { 44 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 45 | } 46 | emitter.buffer_pos = 0 47 | return true 48 | } 49 | -------------------------------------------------------------------------------- /vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/davecgh/go-spew v1.1.1 2 | ## explicit 3 | github.com/davecgh/go-spew/spew 4 | # github.com/kr/pretty v0.2.1 5 | ## explicit; go 1.12 6 | # github.com/pmezard/go-difflib v1.0.0 7 | ## explicit 8 | github.com/pmezard/go-difflib/difflib 9 | # github.com/proullon/ramsql v0.0.1 10 | ## explicit 11 | github.com/proullon/ramsql/driver 12 | github.com/proullon/ramsql/engine 13 | github.com/proullon/ramsql/engine/log 14 | github.com/proullon/ramsql/engine/parser 15 | github.com/proullon/ramsql/engine/protocol 16 | # github.com/stretchr/testify v1.8.2 17 | ## explicit; go 1.13 18 | github.com/stretchr/testify/assert 19 | github.com/stretchr/testify/require 20 | # golang.org/x/text v0.14.0 21 | ## explicit; go 1.18 22 | golang.org/x/text/cases 23 | golang.org/x/text/internal 24 | golang.org/x/text/internal/language 25 | golang.org/x/text/internal/language/compact 26 | golang.org/x/text/internal/tag 27 | golang.org/x/text/language 28 | golang.org/x/text/transform 29 | golang.org/x/text/unicode/norm 30 | # gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 31 | ## explicit 32 | # gopkg.in/yaml.v3 v3.0.1 33 | ## explicit 34 | gopkg.in/yaml.v3 35 | --------------------------------------------------------------------------------