Commit 1c3f74e2 authored by liupei's avatar liupei

1

parent d7259e6f
.vscode
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.DS_Store
# binary files
*.exe
# SQLite database files
*.db
*.sqlite
*.sqlite3
\ No newline at end of file
......@@ -2,10 +2,10 @@ package ndbclient
import (
"context"
"fmt"
"net/http"
"net/url"
"path"
gojson "github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/tidwall/gjson"
)
......@@ -40,38 +40,85 @@ func request(ctx context.Context, urlPath string, arg map[string]interface{}) Re
"pwd": gOption.Pwd,
},
}
addr := gOption.Addr
u, _ := url.Parse(addr)
finalUrl := path.Join(u.Path, urlPath)
finalUrl := gOption.Addr + urlPath
r, err := client.ContentJson().Post(ctx, finalUrl, body)
if err != nil {
panic(err)
return newResponse(ctx, finalUrl, body, err, nil)
}
defer r.Close()
return newResponse(r.ReadAllString())
return newResponse(ctx, finalUrl, body, err, r.ReadAll())
}
type Response struct {
result gjson.Result
errMsg string
response []byte
result gjson.Result
url string
body map[string]interface{}
err error
errMsg string
ctx context.Context
}
func newResponse(result string) Response {
return Response{
result: gjson.Parse(result),
func newResponse(ctx context.Context, url string, body map[string]interface{}, err error, response []byte) Response {
r := Response{
ctx: ctx,
url: url,
body: body,
err: err,
response: response,
result: gjson.ParseBytes(response),
}
r.checkErr()
// 全局输出错误日志
if !r.IsSuccess() {
g.Log().Errorf(r.ctx, "%s", r.err.Error())
}
return r
}
func (r *Response) IsSuccess() bool {
if r.result.Get("code").Exists() && r.result.Get("code").Int() == 0 {
return true
func (r *Response) checkErr() {
jsonBody, err := gojson.New(r.body).ToJsonString()
if err != nil {
r.err = fmt.Errorf("request url: %s,body: %v, body json_encode err: %w", r.url, r.body, err)
r.errMsg = "arg is invalid json"
return
}
var _response string
if r.response != nil {
if len(_response) > 10000 {
_response = string(r.response[:10000]) + "..."
} else {
_response = string(r.response)
}
}
if r.err != nil {
r.err = fmt.Errorf("request url: %s, body: %s, response:%s, error: %w", r.url, jsonBody, _response, r.err)
r.errMsg = r.err.Error()
return
}
if !r.result.Get("code").Exists() {
r.err = fmt.Errorf("request url: %s, body: %s, code: %s, response: %s", r.url, jsonBody, "null", _response)
r.errMsg = fmt.Sprintf("code: %s, response: %s", "null", _response)
return
}
return false
if r.result.Get("code").Int() != 0 {
r.err = fmt.Errorf("request url: %s, body: %s, code: %d, response: %s, error: %s", r.url, jsonBody, r.result.Get("code").Int(), _response, r.result.Get("msg").String())
r.errMsg = fmt.Sprintf("code: %d, error: %s", r.result.Get("code").Int(), r.result.Get("msg").String())
return
}
r.err = nil
r.errMsg = ""
}
func (r *Response) IsSuccess() bool {
return r.err == nil
}
func (r *Response) GetErrMsg() string {
if !r.IsSuccess() {
return r.result.Get("msg").String()
}
return ""
return r.errMsg
}
func (r *Response) GetResult() gjson.Result {
return r.result
}
package ndbclient
import "context"
var (
dataDeletePath = "/jsgo.xbind.ndb.api.data/Delete"
)
type DataDelete struct {
groupId string
formIdId map[string][]string
arg map[string]interface{}
}
func Delete(groupId string) *DataDelete {
return &DataDelete{
groupId: groupId,
}
}
func (d *DataDelete) SetGroupId(groupId string) *DataDelete {
d.groupId = groupId
return d
}
func (d *DataDelete) SetDataIds(formId string, dataIds []string) *DataDelete {
if _, ok := d.formIdId[formId]; ok {
d.formIdId[formId] = nil
}
for _, v := range dataIds {
d.AddDataId(formId, v)
}
return d
}
func (d *DataDelete) AddDataId(formId string, dataId string) *DataDelete {
if d.formIdId == nil {
d.formIdId = make(map[string][]string)
}
d.formIdId[formId] = append(d.formIdId[formId], dataId)
return d
}
func (d *DataDelete) Do(ctx context.Context) Response {
return request(ctx, dataDeletePath, map[string]interface{}{
"group_id": d.groupId,
"form_id/id": d.formIdId,
})
}
package ndbclient
import (
"context"
"testing"
)
func TestDelete(t *testing.T) {
groupId := "test"
res := Delete(groupId).SetDataIds("test", []string{
"d5pddkc3shdonjtgk4ag",
}).Do(context.Background())
if !res.IsSuccess() {
t.Errorf("detail err:%s", res.GetErrMsg())
return
}
t.Log(res.GetResult())
}
package ndbclient
import "context"
var (
dataDetailPath = "/jsgo.xbind.ndb.api.data/Detail"
)
type DataDetail struct {
groupId string
formIdId map[string][]string
arg map[string]interface{}
}
func Detail(groupId string) *DataDetail {
return &DataDetail{
groupId: groupId,
}
}
func (d *DataDetail) SetGroupId(groupId string) *DataDetail {
d.groupId = groupId
return d
}
func (d *DataDetail) SetDataIds(formId string, dataIds []string) *DataDetail {
if _, ok := d.formIdId[formId]; ok {
d.formIdId[formId] = nil
}
for _, v := range dataIds {
d.AddDataId(formId, v)
}
return d
}
func (d *DataDetail) AddDataId(formId string, dataId string) *DataDetail {
if d.formIdId == nil {
d.formIdId = make(map[string][]string)
}
d.formIdId[formId] = append(d.formIdId[formId], dataId)
return d
}
func (d *DataDetail) Do(ctx context.Context) Response {
return request(ctx, dataDetailPath, map[string]interface{}{
"group_id": d.groupId,
"form_id/id": d.formIdId,
})
}
package ndbclient
import (
"context"
"testing"
)
func TestDetail(t *testing.T) {
groupId := "test"
res := Detail(groupId).SetDataIds("test", []string{
"d5pdeck3shdonjtgk4bg",
}).SetDataIds("test1", []string{
"d5pdghk3shdonjtgk4f0",
"d5pdghk3shdonjtgk4eg",
}).Do(context.Background())
if !res.IsSuccess() {
t.Errorf("detail err:%s", res.GetErrMsg())
return
}
t.Log(res.GetResult())
}
......@@ -23,25 +23,27 @@ func (i *DataInsert) SetGroupId(groupId string) *DataInsert {
return i
}
func (i *DataInsert) SetRows(tableName string, rows []interface{}) *DataInsert {
i.rows = nil
func (i *DataInsert) SetFormRows(formId string, rows []interface{}) *DataInsert {
if _, ok := i.rows[formId]; ok {
i.rows[formId] = nil
}
for _, v := range rows {
i.AddRow(tableName, v)
i.AddFormRow(formId, v)
}
return i
}
func (i *DataInsert) AddRow(tableName string, row interface{}) *DataInsert {
func (i *DataInsert) AddFormRow(formId string, row interface{}) *DataInsert {
if i.rows == nil {
i.rows = make(map[string][]interface{})
}
i.rows[tableName] = append(i.rows[tableName], row)
i.rows[formId] = append(i.rows[formId], row)
return i
}
func (i *DataInsert) Do(ctx context.Context) Response {
return request(ctx, dataInsertPath, map[string]interface{}{
"groupId": i.groupId,
"rows": i.rows,
"group_id": i.groupId,
"rows": i.rows,
})
}
......@@ -6,18 +6,26 @@ import (
)
func TestInsert(t *testing.T) {
groupId := "liupei"
res := Insert(groupId).SetRows("test", []interface{}{
groupId := "test"
res := Insert(groupId).SetFormRows("test", []interface{}{
map[string]interface{}{
"id": 1,
"name": "liupei",
"name": "john",
},
map[string]interface{}{
"id": 2,
"name": "liupei",
"name": "lucy",
},
}).SetFormRows("test1", []interface{}{
map[string]interface{}{
"age": 18,
"name": "john",
},
map[string]interface{}{
"name": "lucy",
"age": 28,
},
}).Do(context.Background())
if !res.IsSuccess() {
t.Errorf("err:%s", res.GetErrMsg())
t.Errorf("insert err:%s", res.GetErrMsg())
return
}
}
......@@ -8,10 +8,8 @@ import (
func TestMain(m *testing.M) {
// 在所有测试之前进行全局设置
setup()
// 运行所有测试
exitCode := m.Run()
// 退出程序
os.Exit(exitCode)
}
......
package ndbclient
type Result struct {
}
package ndbclient
import (
"context"
)
var (
dataSqlPath = "/jsgo.xbind.ndb.api.data/Sql"
)
type DataSql struct {
groupId string
sql string
args []interface{}
limit int
detail map[string]interface{}
update map[string]interface{}
del map[string]interface{}
}
func Sql(groupId string) *DataSql {
return &DataSql{
groupId: groupId,
}
}
func (s *DataSql) SetGroupId(groupId string) *DataSql {
s.groupId = groupId
return s
}
func (s *DataSql) SetSql(sql string, args ...interface{}) *DataSql {
s.sql = sql
s.args = args
return s
}
func (s *DataSql) SetLimit(limit int) *DataSql {
s.limit = limit
return s
}
func (s *DataSql) SetDetail(detail map[string]interface{}) *DataSql {
s.detail = detail
return s
}
func (s *DataSql) SetUpdate(update map[string]interface{}) *DataSql {
s.update = update
return s
}
func (s *DataSql) SetDel(del map[string]interface{}) *DataSql {
s.del = del
return s
}
func (s *DataSql) Do(ctx context.Context) Response {
arg := map[string]interface{}{
"group_id": s.groupId,
"sql": s.sql,
}
if s.args != nil {
arg["args"] = s.args
}
if s.limit != 0 {
arg["limit"] = s.limit
}
if s.detail != nil {
arg["detail"] = s.detail
}
if s.update != nil {
arg["update"] = s.update
}
if s.del != nil {
arg["del"] = s.del
}
//fmt.Println(gojson.New(arg).ToJsonString())
return request(ctx, dataSqlPath, arg)
}
package ndbclient
type SqlBuilder interface {
Select(fields ...string) SqlBuilder
From(formId string) SqlBuilder
Where(sql interface{}, args ...interface{}) SqlBuilder
GetWhere() []Where
WhereOr(sql interface{}, args ...interface{}) SqlBuilder
//Limit(param ...int) SqlBuilder
GroupBy(groupBy string) SqlBuilder
OrderBy(orderBy string) SqlBuilder
Build() (string, []interface{})
}
type Where struct {
WhereType string
Sql string
Args []interface{}
Child []Where
}
func GetDefaultSqlBuilder() SqlBuilder {
return NewDuckDBSqlBuilder()
}
package ndbclient
import (
"fmt"
"strings"
)
// DuckDBSqlBuilder DuckDB SQL 构建器实现
type DuckDBSqlBuilder struct {
fields []string
formId string
where []Where
whereArgs []interface{}
limitPage int
limitSize int
groupBy string
orderBy string
}
// NewDuckDBSqlBuilder 创建新的 DuckDB SQL 构建器
func NewDuckDBSqlBuilder() SqlBuilder {
return &DuckDBSqlBuilder{
fields: make([]string, 0),
where: make([]Where, 0),
whereArgs: make([]interface{}, 0),
}
}
// Select 实现 Select 方法
func (d *DuckDBSqlBuilder) Select(fields ...string) SqlBuilder {
d.fields = fields
return d
}
// From 实现 From 方法
func (d *DuckDBSqlBuilder) From(formId string) SqlBuilder {
d.formId = formId
return d
}
func (d *DuckDBSqlBuilder) GetWhere() []Where {
return d.where
}
// Where 实现 Where 方法
func (d *DuckDBSqlBuilder) Where(sql interface{}, args ...interface{}) SqlBuilder {
switch sql.(type) {
case string:
d.where = append(d.where, Where{
Sql: sql.(string),
WhereType: "AND",
Args: args,
})
case SqlBuilder:
d.where = append(d.where, Where{
Sql: "",
WhereType: "AND",
Child: sql.(SqlBuilder).GetWhere(),
})
}
return d
}
// WhereOr 实现 WhereOr 方法
func (d *DuckDBSqlBuilder) WhereOr(sql interface{}, args ...interface{}) SqlBuilder {
switch sql.(type) {
case string:
d.where = append(d.where, Where{
Sql: sql.(string),
WhereType: "OR",
Args: args,
})
case SqlBuilder:
d.where = append(d.where, Where{
Sql: "",
WhereType: "OR",
Child: sql.(SqlBuilder).GetWhere(),
})
}
return d
}
// Limit 方法
// 如果是2个以上参数,则第一个参数为页码,第二个参数为每页数量
// 如果是1个参数,则参数为数量
func (d *DuckDBSqlBuilder) Limit(limitParam ...int) SqlBuilder {
if len(limitParam) == 1 {
d.limitSize = limitParam[0]
} else if len(limitParam) >= 2 {
d.limitPage = limitParam[0]
d.limitSize = limitParam[1]
}
return d
}
// GroupBy 实现 GroupBy 方法
func (d *DuckDBSqlBuilder) GroupBy(groupBy string) SqlBuilder {
d.groupBy = groupBy
return d
}
// OrderBy 实现 OrderBy 方法
func (d *DuckDBSqlBuilder) OrderBy(orderBy string) SqlBuilder {
d.orderBy = orderBy
return d
}
func (d *DuckDBSqlBuilder) buildWhere(wheres []Where) string {
sql := ""
for k, where := range wheres {
_sql := ""
if where.Sql != "" {
_sql = where.Sql
} else if where.Child != nil {
_sql = d.buildWhere(where.Child)
}
if k == 0 {
sql += " ( " + _sql + " ) "
} else {
sql += " " + where.WhereType + " ( " + _sql + " ) "
}
if len(where.Args) > 0 {
d.whereArgs = append(d.whereArgs, where.Args...)
}
}
return sql
}
func (d *DuckDBSqlBuilder) Build() (string, []interface{}) {
sql := ""
if len(d.fields) > 0 {
sql += "SELECT " + strings.Join(d.fields, ",")
}
if d.formId != "" {
sql += " FROM " + d.formId
}
if len(d.where) > 0 {
sql += fmt.Sprintf(" WHERE %s", d.buildWhere(d.where))
}
if d.groupBy != "" {
sql += " GROUP BY " + d.groupBy
}
if d.orderBy != "" {
sql += " ORDER BY " + d.orderBy
}
if d.limitSize > 0 {
sql += fmt.Sprintf(" LIMIT %d", d.limitSize)
}
if d.limitPage > 0 {
sql += fmt.Sprintf(" OFFSET %d", d.limitSize*(d.limitPage-1))
}
return sql, d.whereArgs
}
package ndbclient
import (
"testing"
)
func TestBuild(t *testing.T) {
builder := GetDefaultSqlBuilder()
sql, args := builder.Select("name", "age").
From("test").
Where("name in (?, ?)", "john", "lucy").
WhereOr(GetDefaultSqlBuilder().Where("create_at > ?", "2020-01-01").WhereOr("update_at > ?", "2020-01-01")).
WhereOr("age = ?", 10).
GroupBy("id desc").
OrderBy("id desc").
Build()
t.Log(sql, args)
}
package ndbclient
import (
"context"
"fmt"
)
type DataSqlModel struct {
groupId string
limit int
offset int
sql string
args []interface{}
detail map[string]interface{}
update map[string]interface{}
del map[string]interface{}
formId string
ctx context.Context
}
func SqlModel(groupId string, formId string) *DataSqlModel {
d := &DataSqlModel{
groupId: groupId,
formId: formId,
}
return d
}
func (d *DataSqlModel) SqlBuilder(sqlBuilder SqlBuilder) *DataSqlModel {
d.sql, d.args = sqlBuilder.Build()
return d
}
func (d *DataSqlModel) Sql(sql string, args ...interface{}) *DataSqlModel {
d.sql, d.args = sql, args
return d
}
// Limit
// 如果是2个以上参数,则第一个参数为页码,第二个参数为每页数量
// 如果是1个参数,则参数为数量
// example:1,10
func (d *DataSqlModel) Limit(limitParam ...int) *DataSqlModel {
if len(limitParam) == 1 {
d.limit = limitParam[0]
} else if len(limitParam) >= 2 {
d.offset = (limitParam[0] - 1) * limitParam[1]
d.limit = limitParam[1]
}
return d
}
func (d *DataSqlModel) Ctx(ctx context.Context) *DataSqlModel {
d.ctx = ctx
return d
}
func (d *DataSqlModel) Find() Response {
if d.offset != 0 {
d.sql += fmt.Sprintf(" OFFSET %d", d.offset)
}
db := Sql(d.groupId).SetSql(d.sql, d.args...)
if d.limit != 0 {
db.SetLimit(d.limit)
}
return db.Do(context.Background())
}
// Update 更新内容
//
// example: updateData :=map[string]interface{}{
// "name": "john2",
// }
func (d *DataSqlModel) Update(updateData map[string]interface{}) Response {
db := Sql(d.groupId).SetSql(d.sql, d.args...)
if d.limit != 0 {
db.SetLimit(d.limit)
}
return db.SetUpdate(map[string]interface{}{
"form_id": d.formId,
"set": updateData,
}).Do(context.Background())
}
// Delete 删除,默认是软删除
func (d *DataSqlModel) Delete(trueDel ...bool) Response {
db := Sql(d.groupId).SetSql(d.sql, d.args...)
if d.limit != 0 {
db.SetLimit(d.limit)
}
softDel := 1
if len(trueDel) > 0 && trueDel[0] {
softDel = 0
}
return db.SetDel(map[string]interface{}{
"form_id": d.formId,
"softdel": softDel,
}).Do(context.Background())
}
package ndbclient
import (
"context"
"testing"
)
func TestSqlModelQuery(t *testing.T) {
groupId := "test"
formId := "test"
sqlBuilder := NewDuckDBSqlBuilder().Select("*").From(formId).Where("name = ?", "john2")
res := SqlModel(groupId, formId).SqlBuilder(sqlBuilder).Ctx(context.Background()).Find()
if !res.IsSuccess() {
t.Errorf("find err:%s", res.GetErrMsg())
return
}
t.Log(res.GetResult())
}
func TestSqlModelUpdate(t *testing.T) {
groupId := "test"
formId := "test"
sqlBuilder := NewDuckDBSqlBuilder().Select("id").From(formId).Where("name = ?", "john2")
res := SqlModel(groupId, formId).SqlBuilder(sqlBuilder).Ctx(context.Background()).Update(map[string]interface{}{
"name": "john3",
})
if !res.IsSuccess() {
t.Errorf("update err:%s", res.GetErrMsg())
return
}
t.Log(res.GetResult())
}
func TestSqlModelDelete(t *testing.T) {
groupId := "test"
formId := "test"
sqlBuilder := NewDuckDBSqlBuilder().Select("id").From(formId).Where("name = ?", "john")
res := SqlModel(groupId, formId).SqlBuilder(sqlBuilder).Ctx(context.Background()).Delete()
if !res.IsSuccess() {
t.Errorf("update err:%s", res.GetErrMsg())
return
}
t.Log(res.GetResult())
}
//func TestSqlUpdate(t *testing.T) {
// groupId := "test"
// sql := "select * from test where name = ?"
// res := Sql(groupId).SetSql(sql, "john").SetUpdate(map[string]interface{}{
// "form_id": "test",
// "set": map[string]interface{}{
// "name": "john2",
// },
// }).Do(context.Background())
// if !res.IsSuccess() {
// t.Errorf("sql err:%s", res.GetErrMsg())
// return
// }
// t.Log(res.GetResult())
//}
//
//func TestSqlDel(t *testing.T) {
// groupId := "test"
// sql := "select * from test where name = ? and id = ?"
// res := Sql(groupId).SetSql(sql, "john2", "d5pdghk3shdonjtgk4dg").SetDel(map[string]interface{}{
// "form_id": "test",
// "softdel": 1,
// }).Do(context.Background())
// if !res.IsSuccess() {
// t.Errorf("sql err:%s", res.GetErrMsg())
// return
// }
// t.Log(res.GetResult())
//}
package ndbclient
import (
"context"
"testing"
)
func TestSqlQuery(t *testing.T) {
groupId := "test"
sql := "select * from test where name = ?"
res := Sql(groupId).SetSql(sql, "john").Do(context.Background())
if !res.IsSuccess() {
t.Errorf("sql err:%s", res.GetErrMsg())
return
}
t.Log(res.GetResult())
}
func TestSqlUpdate(t *testing.T) {
groupId := "test"
sql := "select * from test where name = ?"
res := Sql(groupId).SetSql(sql, "john").SetUpdate(map[string]interface{}{
"form_id": "test",
"set": map[string]interface{}{
"name": "john2",
},
}).Do(context.Background())
if !res.IsSuccess() {
t.Errorf("sql err:%s", res.GetErrMsg())
return
}
t.Log(res.GetResult())
}
func TestSqlDel(t *testing.T) {
groupId := "test"
sql := "select * from test where name = ? and id = ?"
res := Sql(groupId).SetSql(sql, "john2", "d5pdghk3shdonjtgk4dg").SetDel(map[string]interface{}{
"form_id": "test",
"softdel": 1,
}).Do(context.Background())
if !res.IsSuccess() {
t.Errorf("sql err:%s", res.GetErrMsg())
return
}
t.Log(res.GetResult())
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment