From 672fc634ef20b0b669add730872b19a193d3e739 Mon Sep 17 00:00:00 2001 From: what Date: Wed, 8 May 2024 21:35:26 +0800 Subject: [PATCH] first commit --- global_params.go | 55 ++++++++++ global_params_support.go | 231 +++++++++++++++++++++++++++++++++++++++ go.mod | 20 ++++ go.sum | 33 ++++++ resource.go | 96 ++++++++++++++++ response.go | 10 ++ routing.go | 109 ++++++++++++++++++ user.go | 50 +++++++++ 8 files changed, 604 insertions(+) create mode 100755 global_params.go create mode 100644 global_params_support.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 resource.go create mode 100755 response.go create mode 100755 routing.go create mode 100644 user.go diff --git a/global_params.go b/global_params.go new file mode 100755 index 0000000..07620db --- /dev/null +++ b/global_params.go @@ -0,0 +1,55 @@ +package req + +import ( + "time" +) + +type GlobalParams interface { + User() User + // 获取路径内容 + Get(p string) GlobalParams + // 路径包裹 + Wrapped(p string) GlobalParams + // 追加到新 json + AppendTo(root, p string) GlobalParams + // 通过路径设置参数 + Set(p string, v any) bool + // 通过路径设置原始参数 + SetRaw(p string, v string) bool + // 删除路径参数 + Delete(p string) bool + // 获取原始JOSN字符串 + Raw() string + // 转数组 GlobalParams + Array() []GlobalParams + // 判断内容是否存在 + Exists() bool + + Value() any + Bool() bool + Time() time.Time + TimeInDefaultLocation(l *time.Location) time.Time + Float64() float64 + Float32() float32 + Int64() int64 + Int32() int32 + Int16() int16 + Int8() int8 + Int() int + Uint() uint + Uint64() uint64 + Uint32() uint32 + Uint16() uint16 + Uint8() uint8 + String() string + StringMapString() map[string]string + StringMapStringSlice() map[string][]string + StringMapBool() map[string]bool + StringMapInt() map[string]int + StringMapInt64() map[string]int64 + StringMap() map[string]any + Slice() []any + BoolSlice() []bool + StringSlice() []string + IntSlice() []int +} diff --git a/global_params_support.go b/global_params_support.go new file mode 100644 index 0000000..f9a5e75 --- /dev/null +++ b/global_params_support.go @@ -0,0 +1,231 @@ +package req + +import ( + "time" + + "github.com/samber/lo" + "github.com/spf13/cast" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +type iGlobalParams struct { + user *User + gjson gjson.Result +} + +// 获取用户信息 +func (this iGlobalParams) User() User { + return *this.user +} + +// 获取指定路径的 value +func (this iGlobalParams) Get(key string) GlobalParams { + return &iGlobalParams{ + user: this.user, + gjson: this.gjson.Get(key), + } +} + +func (this iGlobalParams) Array() []GlobalParams { + return lo.Map(this.gjson.Array(), func(item gjson.Result, _ int) GlobalParams { + return &iGlobalParams{user: this.user, gjson: gjson.Parse(item.Raw)} + }) +} + +// 获取golang原始类型 +func (this iGlobalParams) Value() any { + return this.gjson.Value() +} + +func (this iGlobalParams) Raw() string { + return this.gjson.Raw +} + +// 设置json值 +func (this *iGlobalParams) Set(p string, v any) bool { + if s, err := sjson.Set(this.Raw(), p, v); err != nil { + return false + } else { + this.gjson = gjson.Parse(s) + } + return true +} + +// 设置json原始值 +func (this *iGlobalParams) SetRaw(p, v string) bool { + if s, err := sjson.SetRaw(this.Raw(), p, v); err != nil { + return false + } else { + this.gjson = gjson.Parse(s) + } + return true +} + +// 删除路径内容 +func (this *iGlobalParams) Delete(p string) bool { + if s, err := sjson.Delete(this.Raw(), p); err != nil { + return false + } else { + this.gjson = gjson.Parse(s) + } + return true +} + +// 路径包裹 +func (this *iGlobalParams) Wrapped(p string) GlobalParams { + return this.AppendTo("", p) +} + +// 包裹内容 +func (this *iGlobalParams) AppendTo(root, p string) GlobalParams { + if root != "" && !gjson.Valid(root) { + root = "" + } + + json := lo.Must(sjson.SetRaw(root, p, this.Raw())) + + return &iGlobalParams{ + user: this.user, + gjson: gjson.Parse(json), + } +} + +// 判断值是否存在 +func (this iGlobalParams) Exists() bool { + return this.gjson.Exists() +} + +// to Bool +func (this iGlobalParams) Bool() bool { + return cast.ToBool(this.Value()) +} + +// to Time +func (this iGlobalParams) Time() time.Time { + return cast.ToTime(this.Value()) +} + +// to Location Time +func (this iGlobalParams) TimeInDefaultLocation(location *time.Location) time.Time { + return cast.ToTimeInDefaultLocation(this, location) +} + +// to float64 +func (this iGlobalParams) Float64() float64 { + return cast.ToFloat64(this.Value()) +} + +// to float32 +func (this iGlobalParams) Float32() float32 { + return cast.ToFloat32(this.Value()) +} + +// to int64 +func (this iGlobalParams) Int64() int64 { + return cast.ToInt64(this.Value()) +} + +// to int32 +func (this iGlobalParams) Int32() int32 { + return cast.ToInt32(this.Value()) +} + +// to int16 +func (this iGlobalParams) Int16() int16 { + return cast.ToInt16(this.Value()) +} + +// to int8 +func (this iGlobalParams) Int8() int8 { + return cast.ToInt8(this.Value()) +} + +// to int +func (this iGlobalParams) Int() int { + return cast.ToInt(this.Value()) +} + +// to uint +func (this iGlobalParams) Uint() uint { + return cast.ToUint(this.Value()) +} + +// to uint64 +func (this iGlobalParams) Uint64() uint64 { + return cast.ToUint64(this.Value()) +} + +// to uint32 +func (this iGlobalParams) Uint32() uint32 { + return cast.ToUint32(this.Value()) +} + +// to uint16 +func (this iGlobalParams) Uint16() uint16 { + return cast.ToUint16(this.Value()) +} + +// to uint8 +func (this iGlobalParams) Uint8() uint8 { + return cast.ToUint8(this.Value()) +} + +// to string +func (this iGlobalParams) String() string { + return cast.ToString(this.Value()) +} + +// to map[string]string +func (this iGlobalParams) StringMapString() map[string]string { + return cast.ToStringMapString(this.Value()) +} + +// to map[string][]string +func (this iGlobalParams) StringMapStringSlice() map[string][]string { + return cast.ToStringMapStringSlice(this.Value()) +} + +// to map[string]bool +func (this iGlobalParams) StringMapBool() map[string]bool { + return cast.ToStringMapBool(this.Value()) +} + +// to map[string]int +func (this iGlobalParams) StringMapInt() map[string]int { + return cast.ToStringMapInt(this.Value()) +} + +// to map[string]int64 +func (this iGlobalParams) StringMapInt64() map[string]int64 { + return cast.ToStringMapInt64(this.Value()) +} + +// to map[string]any +func (this iGlobalParams) StringMap() map[string]any { + return cast.ToStringMap(this.Value()) +} + +// to []any +func (this iGlobalParams) Slice() []any { + return cast.ToSlice(this.Value()) +} + +// to []bool +func (this iGlobalParams) BoolSlice() []bool { + return cast.ToBoolSlice(this.Value()) +} + +// to []string +func (this iGlobalParams) StringSlice() []string { + return cast.ToStringSlice(this.Value()) +} + +// to []int +func (this iGlobalParams) IntSlice() []int { + return cast.ToIntSlice(this.Value()) +} + +func NewGlobalParam(data string, user User) GlobalParams { + return &iGlobalParams{user: &user, gjson: gjson.Parse(data)} +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ee0c5c2 --- /dev/null +++ b/go.mod @@ -0,0 +1,20 @@ +module git.fsdpf.net/go/req + +go 1.21 + +require ( + git.fsdpf.net/go/db v0.0.0-20230731125324-11651ea6640b + github.com/go-chi/chi/v5 v5.0.12 + github.com/samber/lo v1.39.0 + github.com/spf13/cast v1.6.0 + github.com/tidwall/gjson v1.17.1 + github.com/tidwall/sjson v1.2.5 +) + +require ( + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/mattn/go-sqlite3 v1.14.16 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..79048c9 --- /dev/null +++ b/go.sum @@ -0,0 +1,33 @@ +git.fsdpf.net/go/db v0.0.0-20230731125324-11651ea6640b h1:fRgWNOQ9dAYuUZHQ24oi1XqRbJIcJvZGbnQDaAKI7IY= +git.fsdpf.net/go/db v0.0.0-20230731125324-11651ea6640b/go.mod h1:397Sdx1cJS0OlHtTX1bVl//9k3Xn0Klnc6jC4MAkb6w= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= +github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= +github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= +github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= diff --git a/resource.go b/resource.go new file mode 100644 index 0000000..368426f --- /dev/null +++ b/resource.go @@ -0,0 +1,96 @@ +package req + +import ( + "reflect" + + "git.fsdpf.net/go/db" + "git.fsdpf.net/go/db/schema" +) + +type ResDataType string +type ResAuthDB int + +const ( + // 关闭权限过滤 + ResAuthOff ResAuthDB = iota + // 开启权限过滤, 不包括关联资源 + ResAuthOn + // 开启权限过滤, 包括关联资源 + ResAuthAll +) + +const ( + ResString ResDataType = "string" + ResText ResDataType = "text" + ResInteger ResDataType = "integer" + ResSmallInteger ResDataType = "smallInteger" + ResDecimal ResDataType = "decimal" + ResBoolean ResDataType = "boolean" + ResJson ResDataType = "json" + ResEnum ResDataType = "enum" + ResTimestamp ResDataType = "timestamp" + ResDate ResDataType = "date" + ResDatetime ResDataType = "dateTime" +) + +const ( + IsExpr = 1 << iota + IsOmitempty + Ignored +) + +type Resource interface { + GetUuid() string + GetName() string + GetCode() string + GetPrimarykey() string + GetFields() []ResField + GetField(string) (ResField, bool) + HasField(string) bool + + BeginTransaction() (*db.Transaction, error) + + GetTable() db.Expression + GetDBConn() *db.Connection + GetDBBuilder() *db.Builder + GetDBTable(params ...any) *db.Builder + GetAuthDBTable(u User, params ...any) *db.Builder + GetStruct(extends ...reflect.StructField) any + GetSliceStruct(extends ...reflect.StructField) any + + WithRolesCondition(b *db.Builder, t string, u User) error + + // 是否虚拟资源 + IsVirtual() bool + // 是否系统资源 + IsSystem() bool +} + +type ResField interface { + GetName() string + GetCode() string + GetCodeResource() string + GetDataType() ResDataType + GetQueryDataType() RouteParamType + GetRawDefault(driver string) db.Expression + ToStructField(tags ...string) reflect.StructField + ToValue(any) any + ToBlueprint(table *schema.Blueprint) *schema.ColumnDefinition + ToQueryField(t RouteParamType, alias string, options int) QueryField +} + +type QueryField interface { + ResField + Type() RouteParamType + Alias() string + GetCodeOrAlias() string + IsExpr() bool + IsOmitempty() bool + Ignored() bool + SetOptions(int) QueryField + ToSql() db.Expression + ToStructField(tags ...string) reflect.StructField +} + +// 资源 +type GetResource func(code string) (Resource, bool) diff --git a/response.go b/response.go new file mode 100755 index 0000000..a5a301b --- /dev/null +++ b/response.go @@ -0,0 +1,10 @@ +package req + +import ( + "net/http" +) + +type HttpResponse interface { + Get(path ...string) GlobalParams + Send(w http.ResponseWriter, r *http.Request) +} diff --git a/routing.go b/routing.go new file mode 100755 index 0000000..0d8a8e2 --- /dev/null +++ b/routing.go @@ -0,0 +1,109 @@ +package req + +import ( + "net/http" + + "github.com/go-chi/chi/v5" +) + +type RouteMethod string +type RouteCategory string +type RouteService string +type RouteParamType string +type RouteParamCategory string + +type RouteCtx struct { + Name string +} + +const ( + GET RouteMethod = "GET" + POST RouteMethod = "POST" + PUT RouteMethod = "PUT" + DELETE RouteMethod = "DELETE" +) + +const ( + WS RouteCategory = "ws" + GRPC RouteCategory = "grpc" + FUNC RouteCategory = "func" + SHOW RouteCategory = "show" + QUERY RouteCategory = "query" + STORE RouteCategory = "store" + DESTROY RouteCategory = "destroy" + STRUCTURE RouteCategory = "structure" +) + +const ( + API RouteService = "api" + FSM RouteService = "fsm" + LIST RouteService = "list" + XLSX RouteService = "xlsx" + IMPORT RouteService = "import" + PRINT RouteService = "print" + LAYOUT RouteService = "layout" + GRID_LAYOUT RouteService = "grid-layout" + GRID_LAYOUT_FORM RouteService = "grid-layout-form" + ECHART RouteService = "echart" + APPROVAL RouteService = "approval" + SELECTOR RouteService = "selector" + LIST_DETAIL RouteService = "list-detail" + LIST_DATA_STORE RouteService = "list-data-store" + LIST_GRID_LAYOUT RouteService = "list-grid-layout" + LIST_CONDITION_LAYOUT RouteService = "list-condition-layout" + LIST_OPERATIONS_ACCESS RouteService = "list-operations-access" +) + +const ( + STRING RouteParamType = "string" + BOOL RouteParamType = "bool" + NUMBER RouteParamType = "number" + INTEGER RouteParamType = "integer" + FLOAT RouteParamType = "float" + JSON RouteParamType = "json" + ARRAY RouteParamType = "array" + ANY RouteParamType = "any" +) + +const ( + ROUTER RouteParamCategory = "router" + HEADER RouteParamCategory = "header" + PARAM RouteParamCategory = "param" +) + +func (k RouteCtx) String() string { + return k.Name +} + +type RouteMiddleware interface { + HttpMiddleware(r Route) func(next http.Handler) http.Handler +} + +type Router interface { + Call(r *http.Request, code string, params map[string]any, category ...RouteCategory) (HttpResponse, error) + Get(uuid string, category ...RouteCategory) (Route, bool) + Register(cr chi.Router) + RefreshRoutes() error +} + +type Route interface { + GetUuid() string + GetCode() string + GetPrimaryKey() string + GetUri() string + GetUris() []string + GetParamValues(*http.Request, ...RouteParam) (GlobalParams, error) + GetResource() Resource + GetCategory() RouteCategory + GetService() RouteService + GetRoles() []string + MakeRequest(r *http.Request, params map[string]any) (*http.Request, error) +} + +type RouteParam interface { + GetCode() string + GetDataType() RouteParamType + GetCategory() RouteParamCategory + IsRequired() bool + InjectRequestToGlobalParams(*http.Request, GlobalParams) error +} diff --git a/user.go b/user.go new file mode 100644 index 0000000..4776884 --- /dev/null +++ b/user.go @@ -0,0 +1,50 @@ +package req + +type User interface { + Runtime() UserRuntime + // 用户ID + ID() int64 + // 用户UUID + Uuid() string + // 用户名称 + Username() string + // 用户昵称 + Nickname() string + // 用户明细 + GetUserInfo() map[string]any + // 用户权限 + Roles() []string + // 用户权限检查 + HasUserRoles(roles ...string) bool + // 是否匿名用户 + IsAnonymous() bool +} + +type UserRuntime struct { + platform string + saas string +} + +// 账号运行平台 +func (this UserRuntime) Platform() string { + return this.platform +} + +// 账号运行租户 +func (this UserRuntime) SaaS() string { + return this.saas +} + +type UserRuntimeOption func(option *UserRuntime) + +func UserRuntimePlatform(value string) UserRuntimeOption { + return func(option *UserRuntime) { + option.platform = value + } +} + +func UserRuntimeSaaS(value string) UserRuntimeOption { + return func(option *UserRuntime) { + option.saas = value + } +}