diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index cc5faa6..5743b49 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -14,6 +14,6 @@ jobs: steps: - uses: actions/checkout@v4 - name: golangci-lint - uses: golangci/golangci-lint-action@v4 + uses: golangci/golangci-lint-action@v6 with: - version: v1.52.0 + version: v1.60.3 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ac6da90..e440d11 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,7 +9,7 @@ jobs: strategy: fail-fast: false matrix: - go-version: [ 1.21.x, 1.22.x ] + go-version: [ 1.21.x, 1.22.x, 1.23.x ] os: [ ubuntu, windows, macOS ] concurrency: group: unit-${{ github.ref }}-${{ matrix.os }}-${{ matrix.go-version }} @@ -38,8 +38,8 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.21.x, 1.22.x] - ydb-version: [23.3, 24.1] + go-version: [ 1.21.x, 1.22.x, 1.23.x ] + ydb-version: [23.3, 24.1, 24.2] concurrency: group: integration-${{ github.ref }}-${{ matrix.go-version }}-${{ matrix.ydb-version }} cancel-in-progress: true diff --git a/.golangci.yml b/.golangci.yml index da0f1b2..9904084 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,11 +1,5 @@ # options for analysis running run: - # default concurrency is a available CPU number - concurrency: 4 - - # timeout for analysis, e.g. 30s, 5m, default is 1m - deadline: 5m - # exit code when at least one issue was found, default is 1 issues-exit-code: 1 @@ -16,13 +10,6 @@ run: #build-tags: # - mytag - # which dirs to skip: they won't be analyzed; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but next dirs are always skipped independently - # from this option's value: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - # skip-dirs: - # which files to skip: they will be analyzed, but issues from them # won't be reported. Default value is empty list, but there is # no need to include all autogenerated files, we confidently recognize @@ -35,7 +22,7 @@ run: # output configuration options output: # colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number" - format: colored-line-number + formats: colored-line-number # print lines of code with issue, default is true print-issued-lines: true @@ -56,26 +43,28 @@ linters-settings: check-blank: false govet: # report about shadowed variables - check-shadowing: true - fieldalignment: true - golint: - # minimal confidence for issues, default is 0.8 - min-confidence: 0.8 + shadow: true gofmt: # simplify code: gofmt with `-s` option, true by default simplify: true + gofumpt: + module-path: github.com/ydb-platform/gorm-driver goimports: # put imports beginning with prefix after 3rd-party packages; # it's a comma-separated list of prefixes local-prefixes: github.com/ydb-platform/gorm-driver + gci: + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - prefix(github.com/ydb-platform/gorm-driver) # Custom section: groups all imports with the specified Prefix. + skip-generated: true goconst: # minimal length of string constant, 3 by default min-len: 2 # minimal occurrences count to trigger, 3 by default min-occurrences: 2 - fieldalignment: - # print struct with more effective memory layout or not, false by default - suggest-new: true + ignore-tests: true misspell: # Correct spellings using locale preferences for US or UK. # Default is to use a neutral variety of English. @@ -106,84 +95,149 @@ linters-settings: - name: empty-block - name: superfluous-else - name: unreachable-code - unused: - # treat code as a program (not a library) and report unused exported identifiers; default is false. - # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: - # if it's called for subdir of a project it can't find funcs usages. All text editor integrations - # with golangci-lint call it on a directory with the changed file. - check-exported: false unparam: - # call graph construction algorithm (cha, rta). In general, use cha for libraries, - # and rta for programs with main packages. Default is cha. - algo: cha - # Inspect exported functions, default is false. Set to true if no external program/library imports your code. # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: # if it's called for subdir of a project it can't find external interfaces. All text editor integrations # with golangci-lint call it on a directory with the changed file. check-exported: false - + gomoddirectives: + replace-local: true + replace-allow-list: + - xorm.io/xorm + gocritic: + disabled-checks: + - whyNoLint # https://github.com/go-critic/go-critic/issues/1063 + - importShadow + - sloppyReassign + # - typeDefFirst + # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks. + # See https://github.com/go-critic/go-critic#usage -> section "Tags". + # Default: [] + enabled-tags: + - diagnostic + - style + - performance + - experimental + - opinionated + # Settings passed to gocritic. + # The settings key is the name of a supported gocritic checker. + # The list of supported checkers can be find in https://go-critic.github.io/overview. + settings: + # Must be valid enabled check name. + captLocal: + # Whether to restrict checker to params only. + # Default: true + paramsOnly: false + elseif: + # Whether to skip balanced if-else pairs. + # Default: true + skipBalanced: false + hugeParam: + # Size in bytes that makes the warning trigger. + # Default: 80 + sizeThreshold: 70 + nestingReduce: + # Min number of statements inside a branch to trigger a warning. + # Default: 5 + bodyWidth: 4 + rangeExprCopy: + # Size in bytes that makes the warning trigger. + # Default: 512 + sizeThreshold: 516 + # Whether to check test functions + # Default: true + skipTestFuncs: false + rangeValCopy: + # Size in bytes that makes the warning trigger. + # Default: 128 + sizeThreshold: 32 + # Whether to check test functions. + # Default: true + skipTestFuncs: false + ruleguard: + # Enable debug to identify which 'Where' condition was rejected. + # The value of the parameter is the name of a function in a ruleguard file. + # + # When a rule is evaluated: + # If: + # The Match() clause is accepted; and + # One of the conditions in the Where() clause is rejected, + # Then: + # ruleguard prints the specific Where() condition that was rejected. + # + # The flag is passed to the ruleguard 'debug-group' argument. + # Default: "" + debug: 'emptyDecl' + # Deprecated, use 'failOn' param. + # If set to true, identical to failOn='all', otherwise failOn='' + failOnError: false + # Determines the behavior when an error occurs while parsing ruleguard files. + # If flag is not set, log error and skip rule files that contain an error. + # If flag is set, the value must be a comma-separated list of error conditions. + # - 'all': fail on all errors. + # - 'import': ruleguard rule imports a package that cannot be found. + # - 'dsl': gorule file does not comply with the ruleguard DSL. + # Default: "" + failOn: dsl + # Comma-separated list of enabled groups or skip empty to enable everything. + # Tags can be defined with # character prefix. + # Default: "" + enable: "myGroupName,#myTagName" + # Comma-separated list of disabled groups or skip empty to enable everything. + # Tags can be defined with # character prefix. + # Default: "" + disable: "myGroupName,#myTagName" + tooManyResultsChecker: + # Maximum number of results. + # Default: 5 + maxResults: 10 + truncateCmp: + # Whether to skip int/uint/uintptr types. + # Default: true + skipArchDependent: false + underef: + # Whether to skip (*x).method() calls where x is a pointer receiver. + # Default: true + skipRecvDeref: false + unnamedResult: + # Whether to check exported functions. + # Default: false + checkExported: true linters: - disable-all: true - enable: - # - cyclop + enable-all: true + disable: + - contextcheck + - cyclop - depguard - - dogsled - # - dupl - - errcheck - - errorlint - # - exhaustive - # - exhaustivestruct - # - forbidigo - # - funlen - # - gci - # - gocognit - - goconst + - dupl + - err113 + - exhaustive + - exhaustruct + - fatcontext + - forbidigo + - gochecknoglobals + - gocognit - gocritic - - gocyclo - # - godot - - godox - - gofmt # On why gofmt when goimports is enabled - https://github.com/golang/go/issues/21476 - - gofumpt - - goheader - - goimports - # - gomnd - # - gomoddirectives - # - gomodguard + - godot + - gomnd - gosec - - gosimple - - govet - - depguard - # - ifshort - # - ireturn - - lll - - makezero - - misspell - - ineffassign - - misspell - - nakedret - - nestif - # - nilnil - # - nlreturn - - nolintlint - - prealloc + - interfacebloat + - intrange + - ireturn + - maintidx + - mnd + - nonamedreturns + - paralleltest + - perfsprint - predeclared - - rowserrcheck - - revive - - staticcheck - - stylecheck - # - tagliatelle - # - testpackage - # - thelper - # - tenv - - typecheck - - unconvert - - unparam - - unused - # - varnamelen - - whitespace -# - wrapcheck -# - wsl + - testableexamples + - testifylint + - testpackage + - thelper + - varnamelen + - wrapcheck + - wsl issues: # List of regexps of issue texts to exclude, empty list by default. @@ -208,8 +262,10 @@ issues: # Default value for this option is true. exclude-use-default: true - # Maximum issues count per one linter. Set to 0 to disable. Default is 50. - max-per-linter: 0 + # Enables exclude of directories: + # - vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + # Default: true + exclude-dirs-use-default: false # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. max-same-issues: 0 @@ -227,4 +283,7 @@ issues: # Show only new issues created in git patch with set file path. # new-from-patch: path/to/patch/file - # exclude-rules: + exclude-rules: + - linters: + - nosnakecase + text : "(?:_[a-z]+(?:[A-Z](?:[a-z\\d]+|[A-Z\\d]+))+|(?:[A-Z][a-z\\d]+|[A-Z][A-Z\\d]+)+_(?:(?:[A-Z][a-z\\d]+|[A-Z\\d][A-Z\\d]+)_?)+)" \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ef16a6..84eeb85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +* Upgraded dependencies: + * github.com/ydb-platform/ydb-go-sdk-auth-environ to v0.5.0 + * github.com/ydb-platform/ydb-go-sdk/v3 to v3.81.4 + * gorm.io/gorm to v1.25.12 +* Added `WithQueryMode` context modifier and `QueryMode` constants + ## v0.1.3 * Upgraded dependencies: * github.com/golang-jwt/jwt/v4 v4.4.1 => v4.5.0 diff --git a/driver.go b/driver.go index d250a3f..483fa53 100644 --- a/driver.go +++ b/driver.go @@ -1,6 +1,7 @@ package ydb import ( + "context" "time" ydb "github.com/ydb-platform/ydb-go-sdk/v3" @@ -31,6 +32,20 @@ func WithConnMaxIdleTime(d time.Duration) Option { return dialect.WithConnMaxIdleTime(d) } +type QueryMode = ydb.QueryMode + +const ( + DataQueryMode = ydb.DataQueryMode + ExplainQueryMode = ydb.ExplainQueryMode + ScanQueryMode = ydb.ScanQueryMode + SchemeQueryMode = ydb.SchemeQueryMode + ScriptingQueryMode = ydb.ScriptingQueryMode +) + +func WithQueryMode(ctx context.Context, mode QueryMode) context.Context { + return ydb.WithQueryMode(ctx, mode) +} + func Open(dsn string, opts ...Option) gorm.Dialector { return dialect.New(dsn, opts...) } diff --git a/example_test.go b/example_test.go new file mode 100644 index 0000000..69c5b75 --- /dev/null +++ b/example_test.go @@ -0,0 +1,99 @@ +package ydb_test + +import ( + "context" + "fmt" + + environ "github.com/ydb-platform/ydb-go-sdk-auth-environ" + "gorm.io/gorm" + + ydb "github.com/ydb-platform/gorm-driver" +) + +//nolint:funlen +func Example_query() { + type Product struct { + ID uint `gorm:"primarykey;not null;autoIncrement:false"` + Code string + Price uint `gorm:"index"` + } + + db, err := gorm.Open( + ydb.Open("grpc://localhost:2136/local", + ydb.With(environ.WithEnvironCredentials()), + ), + ) + if err != nil { + panic(err) + } + + db = db.Debug() + + // Migrate the schema + err = db.AutoMigrate(&Product{}) + if err != nil { + panic(err) + } + + // Create + err = db.Create(&Product{ID: 1, Code: "D42", Price: 100}).Error + if err != nil { + panic(err) + } + + // Scan query + var products []Product + err = db. + WithContext(ydb.WithQueryMode(context.Background(), ydb.ScanQueryMode)). + Model(&Product{}). + Scan(&products). + Error + if err != nil { + panic(err) + } + + // Read + var product Product + err = db.First(&product, 1).Error // find product with integer primary key + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", product) + + err = db.First(&product, "code = ?", "D42").Error // find product with code D42 + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", product) + + // Update - update product's price to 200 + err = db.Model(&product).Update("Price", 200).Error + if err != nil { + panic(err) + } + + // Update - update multiple fields + err = db.Model(&product).Updates(Product{Price: 200, Code: "F42"}).Error // non-zero fields + if err != nil { + panic(err) + } + + err = db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"}).Error + if err != nil { + panic(err) + } + + // Delete - delete product + err = db.Delete(&product, 1).Error + if err != nil { + panic(err) + } + + // Drop table + err = db.Migrator().DropTable(&Product{}) + if err != nil { + panic(err) + } +} diff --git a/go.mod b/go.mod index 07e4add..576fca6 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,13 @@ go 1.21 require ( github.com/google/uuid v1.6.0 - github.com/ydb-platform/ydb-go-sdk-auth-environ v0.3.0 - github.com/ydb-platform/ydb-go-sdk/v3 v3.67.0 - gorm.io/gorm v1.25.10 + github.com/ydb-platform/ydb-go-sdk-auth-environ v0.5.0 + github.com/ydb-platform/ydb-go-sdk/v3 v3.81.4 + gorm.io/gorm v1.25.12 ) // requires for tests only -require github.com/stretchr/testify v1.8.4 +require github.com/stretchr/testify v1.9.0 require ( github.com/davecgh/go-spew v1.1.1 // indirect @@ -20,16 +20,16 @@ require ( github.com/jonboulle/clockwork v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/yandex-cloud/go-genproto v0.0.0-20211115083454-9ca41db5ed9e // indirect - github.com/ydb-platform/ydb-go-genproto v0.0.0-20240316140903-4a47abca1cca // indirect + github.com/ydb-platform/ydb-go-genproto v0.0.0-20241002120727-5acc94bcb119 // indirect github.com/ydb-platform/ydb-go-yc v0.12.1 // indirect github.com/ydb-platform/ydb-go-yc-metadata v0.6.1 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect - google.golang.org/grpc v1.64.0 // indirect + google.golang.org/grpc v1.64.1 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 1df27e7..c6d82cd 100644 --- a/go.sum +++ b/go.sum @@ -769,21 +769,20 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yandex-cloud/go-genproto v0.0.0-20211115083454-9ca41db5ed9e h1:9LPdmD1vqadsDQUva6t2O9MbnyvoOgo8nFNPaOIH5U8= github.com/yandex-cloud/go-genproto v0.0.0-20211115083454-9ca41db5ed9e/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE= github.com/ydb-platform/ydb-go-genproto v0.0.0-20221215182650-986f9d10542f/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= github.com/ydb-platform/ydb-go-genproto v0.0.0-20230528143953-42c825ace222/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= -github.com/ydb-platform/ydb-go-genproto v0.0.0-20240316140903-4a47abca1cca h1:PliQWLwi2gTSOk7QyYQ9GfjvvikmibLWmaplKHy+kfo= -github.com/ydb-platform/ydb-go-genproto v0.0.0-20240316140903-4a47abca1cca/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= -github.com/ydb-platform/ydb-go-sdk-auth-environ v0.3.0 h1:JxSvw+Moont8qCmibP2MjSEIHfkWJLkw0fHZemAk+d0= -github.com/ydb-platform/ydb-go-sdk-auth-environ v0.3.0/go.mod h1:YzCPoNrTbrXZg9bO2YkbjI6eQLkaRIE9Bq8ponu0g8A= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20241002120727-5acc94bcb119 h1:ExSVPjuxuGuu91L0cTD2EZnMOr7VIq1vuA2dVYG0+Xc= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20241002120727-5acc94bcb119/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= +github.com/ydb-platform/ydb-go-sdk-auth-environ v0.5.0 h1:/NyPd9KnCJgzrEXCArqk1ThqCH2Dh31uUwl88o/VkuM= +github.com/ydb-platform/ydb-go-sdk-auth-environ v0.5.0/go.mod h1:9YzkhlIymWaJGX6KMU3vh5sOf3UKbCXkG/ZdjaI3zNM= github.com/ydb-platform/ydb-go-sdk/v3 v3.44.0/go.mod h1:oSLwnuilwIpaF5bJJMAofnGgzPJusoI3zWMNb8I+GnM= github.com/ydb-platform/ydb-go-sdk/v3 v3.47.3/go.mod h1:bWnOIcUHd7+Sl7DN+yhyY1H/I61z53GczvwJgXMgvj0= -github.com/ydb-platform/ydb-go-sdk/v3 v3.48.3/go.mod h1:bWnOIcUHd7+Sl7DN+yhyY1H/I61z53GczvwJgXMgvj0= -github.com/ydb-platform/ydb-go-sdk/v3 v3.67.0 h1:WLxO3+UFEKw+B23y82o2bFjDO67gyUFIUO8CJwMiTNU= -github.com/ydb-platform/ydb-go-sdk/v3 v3.67.0/go.mod h1:hGX4CijskNnUTRgLlqMvZdrBQc1ALZgAnKHytF5nmj4= +github.com/ydb-platform/ydb-go-sdk/v3 v3.81.4 h1:5JABV3DRsISW0/6ZuoUH5y4C7nKxdP4qOC6I6Yp2zMM= +github.com/ydb-platform/ydb-go-sdk/v3 v3.81.4/go.mod h1:BTLL5DJGTAe4sgr3sRum0OQVdNjG1cMjNwZN1qAq7eo= github.com/ydb-platform/ydb-go-yc v0.12.1 h1:qw3Fa+T81+Kpu5Io2vYHJOwcrYrVjgJlT6t/0dOXJrA= github.com/ydb-platform/ydb-go-yc v0.12.1/go.mod h1:t/ZA4ECdgPWjAb4jyDe8AzQZB5dhpGbi3iCahFaNwBY= github.com/ydb-platform/ydb-go-yc-metadata v0.6.1 h1:9E5q8Nsy2RiJMZDNVy0A3KUrIMBPakJ2VgloeWbcI84= @@ -932,8 +931,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1056,8 +1055,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -1080,8 +1079,8 @@ golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1395,8 +1394,8 @@ google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsA google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1427,8 +1426,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= -gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/dialect/dialect.go b/internal/dialect/dialect.go index 8d34bf9..3056d46 100644 --- a/internal/dialect/dialect.go +++ b/internal/dialect/dialect.go @@ -144,12 +144,14 @@ func (d Dialector) ClauseBuilders() map[string]clause.ClauseBuilder { insert, ok := c.Expression.(clause.Insert) if !ok { c.Build(builder) + return } stmt, ok := builder.(*gorm.Statement) if !ok { c.Build(builder) + return } @@ -195,6 +197,7 @@ func (d Dialector) DataTypeOf(field *schema.Field) string { if err != nil { panic(fmt.Errorf("error getting field (model %s, field %s) type: %w", field.Schema.Name, field.Name, err)) } + return t.DatabaseTypeName() } @@ -238,6 +241,7 @@ func (d Dialector) QuoteTo(writer clause.Writer, s string) { backticksCount++ } _ = writer.WriteByte(v) + continue default: if shiftDelimiter-continuousBacktick <= 0 && !underQuoted { diff --git a/internal/dialect/dialect_test.go b/internal/dialect/dialect_test.go index 4e3b64d..8f8147c 100644 --- a/internal/dialect/dialect_test.go +++ b/internal/dialect/dialect_test.go @@ -129,6 +129,7 @@ func TestDialector_DataTypeOf(t *testing.T) { require.Panics(t, func() { d.DataTypeOf(tt.field) }) + return } require.Equal(t, tt.dataType, d.DataTypeOf(tt.field)) diff --git a/internal/dialect/migrator.go b/internal/dialect/migrator.go index 1a42ccd..c9e7713 100644 --- a/internal/dialect/migrator.go +++ b/internal/dialect/migrator.go @@ -62,7 +62,7 @@ func (m Migrator) FullDataTypeOf(field *schema.Field) (expr clause.Expr) { } // CreateTable create table in database for values. -func (m Migrator) CreateTable(values ...interface{}) error { +func (m Migrator) CreateTable(values ...interface{}) error { //nolint:funlen for _, value := range m.ReorderModels(values, false) { tx := m.DB.Session(&gorm.Session{}) @@ -97,7 +97,7 @@ func (m Migrator) CreateTable(values ...interface{}) error { primaryKeys = append(primaryKeys, clause.Column{Name: field.DBName}) } - values = append(values, primaryKeys) + values = append(values, any(primaryKeys)) } for _, idx := range stmt.Schema.ParseIndexes() { @@ -122,7 +122,7 @@ func (m Migrator) CreateTable(values ...interface{}) error { } createTableSQL += "," - values = append(values, + values = append(values, //nolint:forcetypeassert clause.Column{Name: idx.Name}, tx.Migrator().(migrator.BuildIndexOptionsInterface).BuildIndexOptions(idx.Fields, stmt), ) @@ -154,11 +154,13 @@ func (m Migrator) CreateTable(values ...interface{}) error { } err = tx.Exec(createTableSQL, values...).Error + return xerrors.WithStacktrace(err) }); err != nil { return xerrors.WithStacktrace(err) } } + return nil } @@ -185,6 +187,7 @@ func (m Migrator) DropTable(models ...interface{}) error { } } } + return nil } @@ -239,6 +242,7 @@ func (m Migrator) AddColumn(value interface{}, name string) error { "ALTER TABLE ? ADD ? ?", m.CurrentTable(stmt), clause.Column{Name: f.DBName}, m.DB.Migrator().FullDataTypeOf(f), ).Error + return xerrors.WithStacktrace(err) } @@ -256,6 +260,7 @@ func (m Migrator) DropColumn(value interface{}, name string) error { err := m.DB.WithContext(ydbDriver.WithQueryMode(context.Background(), ydbDriver.SchemeQueryMode)).Exec( "ALTER TABLE ? DROP COLUMN ?", m.CurrentTable(stmt), clause.Column{Name: name}, ).Error + return xerrors.WithStacktrace(err) }) } @@ -296,6 +301,7 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) { var desc options.Description err = cc.Table().Do(stmt.Context, func(ctx context.Context, s table.Session) (err error) { desc, err = s.DescribeTable(ctx, pt) + return xerrors.WithStacktrace(err) }, table.WithIdempotent()) if err != nil { @@ -318,7 +324,7 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) { } } - return + return nil }) return columnTypes, xerrors.WithStacktrace(execErr) @@ -329,6 +335,7 @@ func (m Migrator) schemaByValue(model interface{}) (*schema.Schema, error) { if err != nil { return nil, xerrors.WithStacktrace(fmt.Errorf("error parsing schema: %w", err)) } + return s, nil } @@ -336,6 +343,7 @@ func (m Migrator) fullTableName(tableName string) string { d, ok := m.Dialector.(Dialector) if !ok { checkAndAddError(m.DB.Statement, xerrors.WithStacktrace(errors.New("error conversion to Dialector"))) + return "" } @@ -344,12 +352,14 @@ func (m Migrator) fullTableName(tableName string) string { db, err := m.DB.DB() if err != nil { checkAndAddError(m.DB.Statement, xerrors.WithStacktrace(errors.New("error getting DB"))) + return "" } cc, err := ydbDriver.Unwrap(db) if err != nil { checkAndAddError(m.DB.Statement, xerrors.WithStacktrace(errors.New("error unwrapping db"))) + return "" } diff --git a/internal/dialect/migrator_test.go b/internal/dialect/migrator_test.go index 1f6924d..7ebfbd7 100644 --- a/internal/dialect/migrator_test.go +++ b/internal/dialect/migrator_test.go @@ -10,7 +10,7 @@ import ( "gorm.io/gorm/schema" ) -func TestMigrator_FullDataTypeOf(t *testing.T) { +func TestMigrator_FullDataTypeOf(t *testing.T) { //nolint:funlen tests := []struct { name string field *schema.Field @@ -103,6 +103,7 @@ func TestMigrator_FullDataTypeOf(t *testing.T) { require.Panics(t, func() { m.FullDataTypeOf(tt.field) }) + return } diff --git a/internal/dialect/type.go b/internal/dialect/type.go index 76b0964..c9c7eea 100644 --- a/internal/dialect/type.go +++ b/internal/dialect/type.go @@ -57,6 +57,7 @@ func toColumnType(f *schema.Field, t types.Type, opts ...toColumnTypeOption) (go return nil, err } } + return columnType, nil } @@ -64,6 +65,7 @@ func toColumnType(f *schema.Field, t types.Type, opts ...toColumnTypeOption) (go func parseField(f *schema.Field) (gorm.ColumnType, types.Type, error) { wrapType := func(t types.Type) (gorm.ColumnType, types.Type, error) { ct, err := toColumnType(f, t) + return ct, t, err } diff --git a/internal/dialect/type_test.go b/internal/dialect/type_test.go index c4cb3e4..b46e303 100644 --- a/internal/dialect/type_test.go +++ b/internal/dialect/type_test.go @@ -12,7 +12,7 @@ import ( "gorm.io/gorm/schema" ) -func Test_schemaFieldToColumnType(t *testing.T) { +func Test_schemaFieldToColumnType(t *testing.T) { //nolint:funlen tests := []struct { field *schema.Field typesType types.Type @@ -57,6 +57,7 @@ func Test_schemaFieldToColumnType(t *testing.T) { Bool: true, Valid: true, } + return nil }, }, @@ -93,6 +94,7 @@ func Test_schemaFieldToColumnType(t *testing.T) { if tt.isErrors { require.Error(t, err) + return } require.NoError(t, err) @@ -119,7 +121,7 @@ func Test_schemaFieldToColumnType(t *testing.T) { } } -func Test_parseField(t *testing.T) { +func Test_parseField(t *testing.T) { //nolint:funlen tests := []struct { field *schema.Field typesType types.Type @@ -229,6 +231,7 @@ func Test_parseField(t *testing.T) { columnType, typesType, err := parseField(tt.field) if tt.isError { require.Error(t, err) + return } require.NoError(t, err) diff --git a/internal/xerrors/stacktrace.go b/internal/xerrors/stacktrace.go index a75ab82..bde4a24 100644 --- a/internal/xerrors/stacktrace.go +++ b/internal/xerrors/stacktrace.go @@ -11,6 +11,7 @@ func WithStacktrace(err error) error { if err == nil { return nil } + return &stackError{ stackRecord: stackRecord(1), err: err, @@ -20,6 +21,7 @@ func WithStacktrace(err error) error { func stackRecord(depth int) string { function, file, line, _ := runtime.Caller(depth + 1) name := runtime.FuncForPC(function).Name() + return name + "(" + fileName(file) + ":" + strconv.Itoa(line) + ")" } @@ -28,6 +30,7 @@ func fileName(original string) string { if i == -1 { return original } + return original[i+1:] } diff --git a/tests/integration/driver_test.go b/tests/integration/driver_test.go index a106a5f..cb935e0 100644 --- a/tests/integration/driver_test.go +++ b/tests/integration/driver_test.go @@ -1,6 +1,7 @@ package integration import ( + "context" "fmt" "os" "testing" @@ -12,6 +13,7 @@ import ( ydb "github.com/ydb-platform/gorm-driver" ) +//nolint:funlen func TestDriver(t *testing.T) { type Product struct { ID uint `gorm:"primarykey;not null;autoIncrement:false"` @@ -43,6 +45,17 @@ func TestDriver(t *testing.T) { err = db.Create(&Product{ID: 1, Code: "D42", Price: 100}).Error require.NoError(t, err) + // Scan query + var products []Product + err = db. + WithContext(ydb.WithQueryMode(context.Background(), ydb.ScanQueryMode)). + Model(&Product{}). + Scan(&products). + Error + require.NoError(t, err) + + fmt.Printf("%+v\n", products) + // Read var product Product err = db.First(&product, 1).Error // find product with integer primary key diff --git a/tests/integration/migrations_test.go b/tests/integration/migrations_test.go index 780b225..28ff1d7 100644 --- a/tests/integration/migrations_test.go +++ b/tests/integration/migrations_test.go @@ -50,6 +50,7 @@ func TestSequentialAutoMigrate(t *testing.T) { } } +//nolint:funlen func TestMigrateColumn(t *testing.T) { dsn, has := os.LookupEnv("YDB_CONNECTION_STRING") if !has { @@ -283,6 +284,7 @@ func TestCreateTableWithOptions(t *testing.T) { var desc options.Description err = driver.Table().Do(context.Background(), func(ctx context.Context, s table.Session) (err error) { desc, err = s.DescribeTable(ctx, path.Join(driver.Name(), t.Name(), "products")) + return err }, table.WithIdempotent()) require.NoError(t, err)