Merge remote-tracking branch 'origin/master' into feature/mssql

This commit is contained in:
wenzi1
2022-05-17 09:42:21 +08:00
15 changed files with 129 additions and 36 deletions

View File

@ -1,15 +1,30 @@
# drivers
Database drivers for package gdb.
Powerful database drivers for package gdb.
# Installation
Let's take `pgsql` for example.
Let's take `mysql` for example.
```
go get -u github.com/gogf/gf/contrib/drivers/pgsql/v2
go get -u github.com/gogf/gf/contrib/drivers/mysql/v2
```
Choose and import the driver to your project:
```
import _ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
import _ "github.com/gogf/gf/contrib/drivers/mysql/v2"
```
Commonly imported at top of `main.go`:
```go
package main
import (
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
// Other imported packages.
)
func main() {
// Main logics.
}
```
# Supported Drivers

View File

@ -45,6 +45,8 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=

View File

@ -4,7 +4,7 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package mssql
package mssql_test
import (
"context"
@ -18,7 +18,6 @@ import (
)
var (
// 数据库对象/接口
db gdb.DB
dblink gdb.DB
dbErr gdb.DB
@ -110,10 +109,7 @@ func createTable(table ...string) (name string) {
gtest.Fatal(err)
}
// 选择操作数据库
db.Schema("test")
//db.SetDebug(true)
return
}
@ -138,7 +134,6 @@ func createInitTable(table ...string) (name string) {
return
}
// 删除指定表.
func dropTable(table string) {
if _, err := db.Exec(context.Background(), fmt.Sprintf(`
IF EXISTS (SELECT * FROM sysobjects WHERE name='%s' and xtype='U')

View File

@ -4,7 +4,7 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package mssql
package mssql_test
import (
"context"

View File

@ -4,7 +4,7 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package mssql
package mssql_test
import (
"database/sql"

View File

@ -212,7 +212,7 @@ ORDER BY a.attnum`,
Index: i,
Name: m["field"].String(),
Type: m["type"].String(),
Null: m["null"].Bool(),
Null: !m["null"].Bool(),
Key: m["key"].String(),
Default: m["default_value"].Val(),
Comment: m["comment"].String(),

View File

@ -28,6 +28,7 @@ type Command struct {
Examples string // Usage examples.
Additional string // Additional info about this command, which will be appended to the end of help info.
Strict bool // Strict parsing options, which means it returns error if invalid option given.
CaseSensitive bool // CaseSensitive parsing options, which means it parses input options in case-sensitive way.
Config string // Config node name, which also retrieves the values from config component along with command line.
parent *Command // Parent command for internal usage.
commands []*Command // Sub commands of this command.

View File

@ -9,11 +9,14 @@ package gcmd
import (
"context"
"fmt"
"reflect"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/intlog"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/os/gstructs"
@ -285,11 +288,17 @@ func newCommandFromMethod(object interface{}, method reflect.Value) (command *Co
}
// Construct input parameters.
if len(data) > 0 {
intlog.PrintFunc(ctx, func() string {
return fmt.Sprintf(`input command data map: %s`, gjson.MustEncode(data))
})
if inputObject.Kind() == reflect.Ptr {
err = gconv.Scan(data, inputObject.Interface())
} else {
err = gconv.Struct(data, inputObject.Addr().Interface())
}
intlog.PrintFunc(ctx, func() string {
return fmt.Sprintf(`input object assigned data: %s`, gjson.MustEncode(inputObject.Interface()))
})
if err != nil {
return
}

View File

@ -146,7 +146,10 @@ func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error)
}
supportedOptions[optionKey] = !arg.Orphan
}
parser, err := Parse(supportedOptions, c.Strict)
parser, err := Parse(supportedOptions, ParserOption{
CaseSensitive: c.CaseSensitive,
Strict: c.Strict,
})
if err != nil {
return nil, err
}

View File

@ -21,9 +21,15 @@ import (
"github.com/gogf/gf/v2/text/gstr"
)
// ParserOption manages the parsing options.
type ParserOption struct {
CaseSensitive bool // Marks options parsing in case-sensitive way.
Strict bool // Whether stops parsing and returns error if invalid option passed.
}
// Parser for arguments.
type Parser struct {
strict bool // Whether stops parsing and returns error if invalid option passed.
option ParserOption // Parse option.
parsedArgs []string // As name described.
parsedOptions map[string]string // As name described.
passedOptions map[string]bool // User passed supported options, like: map[string]bool{"name,n":true}
@ -47,7 +53,7 @@ func ParserFromCtx(ctx context.Context) *Parser {
// the value item of `supportedOptions` indicates whether corresponding option name needs argument or not.
//
// The optional parameter `strict` specifies whether stops parsing and returns error if invalid option passed.
func Parse(supportedOptions map[string]bool, strict ...bool) (*Parser, error) {
func Parse(supportedOptions map[string]bool, option ...ParserOption) (*Parser, error) {
if supportedOptions == nil {
command.Init(os.Args...)
return &Parser{
@ -55,7 +61,7 @@ func Parse(supportedOptions map[string]bool, strict ...bool) (*Parser, error) {
parsedOptions: GetOptAll(),
}, nil
}
return ParseArgs(os.Args, supportedOptions, strict...)
return ParseArgs(os.Args, supportedOptions, option...)
}
// ParseArgs creates and returns a new Parser with given arguments and supported options.
@ -64,7 +70,7 @@ func Parse(supportedOptions map[string]bool, strict ...bool) (*Parser, error) {
// the value item of `supportedOptions` indicates whether corresponding option name needs argument or not.
//
// The optional parameter `strict` specifies whether stops parsing and returns error if invalid option passed.
func ParseArgs(args []string, supportedOptions map[string]bool, strict ...bool) (*Parser, error) {
func ParseArgs(args []string, supportedOptions map[string]bool, option ...ParserOption) (*Parser, error) {
if supportedOptions == nil {
command.Init(args...)
return &Parser{
@ -72,12 +78,12 @@ func ParseArgs(args []string, supportedOptions map[string]bool, strict ...bool)
parsedOptions: GetOptAll(),
}, nil
}
strictParsing := false
if len(strict) > 0 {
strictParsing = strict[0]
var parserOption ParserOption
if len(option) > 0 {
parserOption = option[0]
}
parser := &Parser{
strict: strictParsing,
option: parserOption,
parsedArgs: make([]string, 0),
parsedOptions: make(map[string]string),
passedOptions: supportedOptions,
@ -118,7 +124,7 @@ func ParseArgs(args []string, supportedOptions map[string]bool, strict ...bool)
}
i++
continue
} else if parser.strict {
} else if parser.option.Strict {
return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid option '%s'`, args[i])
}
}
@ -159,8 +165,18 @@ func (p *Parser) parseOption(argument string) string {
}
func (p *Parser) isOptionValid(name string) bool {
_, ok := p.supportedOptions[name]
return ok
// Case-Sensitive.
if p.option.CaseSensitive {
_, ok := p.supportedOptions[name]
return ok
}
// Case-InSensitive.
for optionName, _ := range p.supportedOptions {
if gstr.Equal(optionName, name) {
return true
}
}
return false
}
func (p *Parser) isOptionNeedArgument(name string) bool {

View File

@ -0,0 +1,50 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gcmd_test
import (
"context"
"os"
"testing"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/test/gtest"
)
type TestParamsCase struct {
g.Meta `name:"root" root:"root"`
}
type TestParamsCaseRootInput struct {
g.Meta `name:"root"`
Name string
}
type TestParamsCaseRootOutput struct {
Content string
}
func (c *TestParamsCase) Root(ctx context.Context, in TestParamsCaseRootInput) (out *TestParamsCaseRootOutput, err error) {
out = &TestParamsCaseRootOutput{
Content: in.Name,
}
return
}
func Test_Command_ParamsCase(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var ctx = gctx.New()
cmd, err := gcmd.NewFromObject(TestParamsCase{})
t.AssertNil(err)
os.Args = []string{"root", "-name=john"}
value, err := cmd.RunWithValueError(ctx)
t.AssertNil(err)
t.Assert(value, `{"Content":"john"}`)
})
}

View File

@ -82,8 +82,8 @@ const (
)
const (
patternKeyForRequired = `required`
patternKeyForIn = `in:`
validationRuleKeyForRequired = `required`
validationRuleKeyForIn = `in:`
)
var (

View File

@ -80,8 +80,9 @@ func (oai *OpenApiV3) newParameterRefWithStructMethod(field gstructs.Field, path
}
// Required check.
if parameter.Schema.Value != nil && parameter.Schema.Value.Pattern != "" {
if gset.NewStrSetFrom(gstr.Split(parameter.Schema.Value.Pattern, "|")).Contains(patternKeyForRequired) {
if parameter.Schema.Value != nil && parameter.Schema.Value.ValidationRules != "" {
validationRuleArray := gstr.Split(parameter.Schema.Value.ValidationRules, "|")
if gset.NewStrSetFrom(validationRuleArray).Contains(validationRuleKeyForRequired) {
parameter.Required = true
}
}

View File

@ -60,6 +60,7 @@ type Schema struct {
AdditionalProperties *SchemaRef `json:"additionalProperties,omitempty"`
Discriminator *Discriminator `json:"discriminator,omitempty"`
XExtensions XExtensions `json:"-"`
ValidationRules string `json:"-"`
}
func (s Schema) MarshalJSON() ([]byte, error) {
@ -183,9 +184,9 @@ func (oai *OpenApiV3) structToSchema(object interface{}) (*Schema, error) {
}
schema.Properties.Iterator(func(key string, ref SchemaRef) bool {
if ref.Value != nil && ref.Value.Pattern != "" {
validationRuleSet := gset.NewStrSetFrom(gstr.Split(ref.Value.Pattern, "|"))
if validationRuleSet.Contains(patternKeyForRequired) {
if ref.Value != nil && ref.Value.ValidationRules != "" {
validationRuleSet := gset.NewStrSetFrom(gstr.Split(ref.Value.ValidationRules, "|"))
if validationRuleSet.Contains(validationRuleKeyForRequired) {
schema.Required = append(schema.Required, key)
}
}
@ -212,14 +213,14 @@ func (oai *OpenApiV3) tagMapToSchema(tagMap map[string]string, schema *Schema) e
for _, tag := range gvalid.GetTags() {
if validationTagValue, ok := tagMap[tag]; ok {
_, validationRules, _ := gvalid.ParseTagValue(validationTagValue)
schema.Pattern = validationRules
schema.ValidationRules = validationRules
// Enum checks.
if len(schema.Enum) == 0 {
for _, rule := range gstr.SplitAndTrim(validationRules, "|") {
if gstr.HasPrefix(rule, patternKeyForIn) {
if gstr.HasPrefix(rule, validationRuleKeyForIn) {
var (
isAllEnumNumber = true
enumArray = gstr.SplitAndTrim(rule[len(patternKeyForIn):], ",")
enumArray = gstr.SplitAndTrim(rule[len(validationRuleKeyForIn):], ",")
)
for _, enum := range enumArray {
if !gstr.IsNumeric(enum) {

View File

@ -11,7 +11,7 @@ import (
)
// XExtensions stores the `x-` custom extensions.
type XExtensions map[string]interface{}
type XExtensions map[string]string
func (oai *OpenApiV3) tagMapToXExtensions(tagMap map[string]string, extensions XExtensions) {
for k, v := range tagMap {