Compare commits

...

7 Commits
v0.0.5 ... main

Author SHA1 Message Date
2cbe41587e 升级异常机制 2025-12-12 21:51:15 +08:00
480250c04c update for gojs 2025-12-01 00:34:23 +08:00
20d283a270 update gojs 2025-11-30 23:03:03 +08:00
Star
3a991746ad update for ssgo/dao 2025-07-15 17:18:36 +08:00
195cbc6b59 update packages 2025-06-25 22:56:06 +08:00
Star
12fcb95b9d add querya 2025-01-14 14:28:26 +08:00
7eee72b053 fix nil bug for query11
add query1s query1a
2024-12-15 19:22:13 +08:00
5 changed files with 197 additions and 57 deletions

155
db.go
View File

@ -2,9 +2,12 @@ package db
import (
_ "embed"
"strings"
"apigo.cc/gojs"
"apigo.cc/gojs/goja"
_ "github.com/go-sql-driver/mysql"
_ "github.com/jackc/pgx/v5/stdlib"
"github.com/ssgo/dao/dao"
"github.com/ssgo/db"
"github.com/ssgo/log"
@ -16,19 +19,32 @@ var dbTS string
//go:embed README.md
var dbMD string
var defaultDB = "default"
// var defaultDB = "default"
// var defaultDBLock = sync.RWMutex{}
func init() {
obj := map[string]any{
"get": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args := gojs.MakeArgs(&argsIn, vm).Check(1)
conn := db.GetDB(args.Str(0), args.Logger)
// 检查sqlite文件访问是否超出沙盒 userPath
dsn := fixDsn(vm, args.Str(0))
conn := db.GetDB(dsn, args.Logger)
return vm.ToValue(makeDBObject(conn, nil))
},
"setDefault": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args := gojs.MakeArgs(&argsIn, vm).Check(1)
defaultDB = args.Str(0)
conn := db.GetDB(defaultDB, args.Logger)
// 检查sqlite文件访问是否超出沙盒 userPath
dsn := fixDsn(vm, args.Str(0))
// defaultDBLock.Lock()
// defaultDB = dsn
// defaultDBLock.Unlock()
conn := db.GetDB(dsn, args.Logger)
args.This.ToObject(vm).Set("conn", conn)
return nil
},
@ -36,7 +52,7 @@ func init() {
gojs.Register("apigo.cc/gojs/db", gojs.Module{
ObjectMaker: func(vm *goja.Runtime) gojs.Map {
conn := db.GetDB(defaultDB, gojs.GetLogger(vm))
conn := db.GetDB("default", gojs.GetLogger(vm))
dbObj := makeDBObject(conn, nil)
for k, v := range obj {
dbObj[k] = v
@ -52,6 +68,20 @@ func init() {
})
}
func fixDsn(vm *goja.Runtime, dsn string) string {
// 检查sqlite文件访问是否超出沙盒 userPath
rootPath := u.String(vm.GetData("userPath"))
if rootPath != "" && strings.HasPrefix(dsn, "sqlite") && strings.Contains(dsn, "://") {
filename := strings.SplitN(dsn, "://", 2)[1]
filename = strings.SplitN(dsn, "?", 2)[0]
fixedFilename := gojs.FixPath(vm, filename)
if fixedFilename != filename {
dsn = strings.Replace(dsn, filename, fixedFilename, 1)
}
}
return dsn
}
func makeDBObject(conn *db.DB, tx *db.Tx) map[string]any {
obj := map[string]any{
"conn": conn,
@ -67,7 +97,27 @@ func makeDBObject(conn *db.DB, tx *db.Tx) map[string]any {
if r.Error == nil {
return vm.ToValue(makeQueryResult(r, r.MapResults()))
} else {
panic(vm.NewGoError(r.Error))
// panic(vm.NewGoError(r.Error))
vm.SetData("_lastError", r.Error)
gojs.GetLogger(vm).Error(r.Error.Error())
return nil
}
},
"querya": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args, conn, tx, _ := initDBArgs(argsIn, vm, 1)
var r *db.QueryResult
if tx != nil {
r = tx.Query(args.Str(0), args.Array(1)...)
} else {
r = conn.Query(args.Str(0), args.Array(1)...)
}
if r.Error == nil {
return vm.ToValue(makeQueryResult(r, r.SliceResults()))
} else {
// panic(vm.NewGoError(r.Error))
vm.SetData("_lastError", r.Error)
gojs.GetLogger(vm).Error(r.Error.Error())
return nil
}
},
"query1": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
@ -81,7 +131,35 @@ func makeDBObject(conn *db.DB, tx *db.Tx) map[string]any {
if r.Error == nil {
return vm.ToValue(makeQueryResult(r, r.MapOnR1()))
} else {
panic(vm.NewGoError(r.Error))
// panic(vm.NewGoError(r.Error))
vm.SetData("_lastError", r.Error)
gojs.GetLogger(vm).Error(r.Error.Error())
return nil
}
},
"query1a": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args, conn, tx, _ := initDBArgs(argsIn, vm, 1)
var r *db.QueryResult
if tx != nil {
r = tx.Query(args.Str(0), args.Array(1)...)
} else {
r = conn.Query(args.Str(0), args.Array(1)...)
}
if r.Error == nil {
a := r.SliceResults()
if len(a) > 0 && len(a[0]) > 0 {
list := make([]any, len(a))
for i := 0; i < len(a); i++ {
list[i] = a[i][0]
}
return vm.ToValue(makeQueryResult(r, list))
}
return vm.ToValue(makeQueryResult(r, nil))
} else {
// panic(vm.NewGoError(r.Error))
vm.SetData("_lastError", r.Error)
gojs.GetLogger(vm).Error(r.Error.Error())
return nil
}
},
"query11": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
@ -97,9 +175,12 @@ func makeDBObject(conn *db.DB, tx *db.Tx) map[string]any {
if len(a) > 0 && len(a[0]) > 0 {
return vm.ToValue(makeQueryResult(r, a[0][0]))
}
return vm.ToValue(nil)
return vm.ToValue(makeQueryResult(r, nil))
} else {
panic(vm.NewGoError(r.Error))
// panic(vm.NewGoError(r.Error))
vm.SetData("_lastError", r.Error)
gojs.GetLogger(vm).Error(r.Error.Error())
return nil
}
},
"exec": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
@ -113,7 +194,10 @@ func makeDBObject(conn *db.DB, tx *db.Tx) map[string]any {
if r.Error == nil {
return vm.ToValue(makeExecResult(r))
} else {
panic(vm.NewGoError(r.Error))
// panic(vm.NewGoError(r.Error))
vm.SetData("_lastError", r.Error)
gojs.GetLogger(vm).Error(r.Error.Error())
return vm.ToValue(false)
}
},
"insert": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
@ -127,7 +211,10 @@ func makeDBObject(conn *db.DB, tx *db.Tx) map[string]any {
if r.Error == nil {
return vm.ToValue(makeExecResult(r))
} else {
panic(vm.NewGoError(r.Error))
// panic(vm.NewGoError(r.Error))
vm.SetData("_lastError", r.Error)
gojs.GetLogger(vm).Error(r.Error.Error())
return vm.ToValue(false)
}
},
"replace": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
@ -141,7 +228,10 @@ func makeDBObject(conn *db.DB, tx *db.Tx) map[string]any {
if r.Error == nil {
return vm.ToValue(makeExecResult(r))
} else {
panic(vm.NewGoError(r.Error))
// panic(vm.NewGoError(r.Error))
vm.SetData("_lastError", r.Error)
gojs.GetLogger(vm).Error(r.Error.Error())
return vm.ToValue(false)
}
},
"update": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
@ -155,7 +245,10 @@ func makeDBObject(conn *db.DB, tx *db.Tx) map[string]any {
if r.Error == nil {
return vm.ToValue(makeExecResult(r))
} else {
panic(vm.NewGoError(r.Error))
// panic(vm.NewGoError(r.Error))
vm.SetData("_lastError", r.Error)
gojs.GetLogger(vm).Error(r.Error.Error())
return vm.ToValue(false)
}
},
"delete": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
@ -169,7 +262,10 @@ func makeDBObject(conn *db.DB, tx *db.Tx) map[string]any {
if r.Error == nil {
return vm.ToValue(makeExecResult(r))
} else {
panic(vm.NewGoError(r.Error))
// panic(vm.NewGoError(r.Error))
vm.SetData("_lastError", r.Error)
gojs.GetLogger(vm).Error(r.Error.Error())
return vm.ToValue(false)
}
},
"makeInKeys": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
@ -182,7 +278,7 @@ func makeDBObject(conn *db.DB, tx *db.Tx) map[string]any {
obj["make"] = func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args, conn, _, logger := initDBArgs(argsIn, vm, 1)
erDesc := args.Str(0)
tryFile := gojs.FindPath(vm, erDesc)
tryFile := gojs.FixPath(vm, erDesc)
if u.FileExists(tryFile) {
erDesc = u.ReadFileN(tryFile)
}
@ -197,7 +293,10 @@ data t
`, logger); err == nil {
return nil
} else {
panic(vm.NewGoError(err))
// panic(vm.NewGoError(err))
vm.SetData("_lastError", err)
gojs.GetLogger(vm).Error(err.Error())
return vm.ToValue(false)
}
}
@ -205,20 +304,27 @@ data t
args, _, _, logger := initDBArgs(argsIn, vm, 1)
outputFile := args.Str(0)
erDesc := args.Str(1)
tryFile := gojs.FindPath(vm, erDesc)
dbType := args.Str(2)
if dbType == "" {
dbType = "mysql"
}
tryFile := gojs.FixPath(vm, erDesc)
if u.FileExists(tryFile) {
erDesc = u.ReadFileN(tryFile)
}
dao.MakeERFile(erDesc, "", outputFile, logger)
return nil
dao.MakeERFile(dbType, erDesc, "", outputFile, logger)
return vm.ToValue(true)
}
obj["destroy"] = func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
_, conn, _, _ := initDBArgs(argsIn, vm, 0)
if err := conn.Destroy(); err == nil {
return nil
return vm.ToValue(true)
} else {
panic(vm.NewGoError(err))
// panic(vm.NewGoError(err))
vm.SetData("_lastError", err)
gojs.GetLogger(vm).Error(err.Error())
return vm.ToValue(false)
}
}
@ -232,9 +338,12 @@ data t
obj["end"] = func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args, _, tx, _ := initDBArgs(argsIn, vm, 1)
if err := tx.Finish(args.Bool(0)); err != nil {
panic(vm.NewGoError(err))
// panic(vm.NewGoError(err))
vm.SetData("_lastError", err)
gojs.GetLogger(vm).Error(err.Error())
return vm.ToValue(false)
}
return nil
return vm.ToValue(true)
}
}
return obj

33
db.ts
View File

@ -7,6 +7,7 @@ export default {
makeER,
query,
query1,
query1a,
query11,
exec,
insert,
@ -20,10 +21,12 @@ export default {
function get(dbName: string): DB { return null as any }
function setDefault(dbName: string): void { }
function make(descFileOrContent: string): Array<Object> { return null as any }
function makeER(outputFile: string, descFileOrContent: string): void { }
function make(descFileOrContent: string): Object[] { return null as any }
function makeER(outputFile: string, descFileOrContent: string, dbType: string = 'mysql'): void { }
function query(sql: string, ...args: any): QueryResult { return null as any }
function querya(sql: string, ...args: any): QueryResultA { return null as any }
function query1(sql: string, ...args: any): QueryResult1 { return null as any }
function query1a(sql: string, ...args: any): QueryResult1A { return null as any }
function query11(sql: string, ...args: any): QueryResult11 { return null as any }
function exec(sql: string, ...args: any): ExecResult { return null as any }
function insert(table: string, data: Object): ExecResult { return null as any }
@ -35,9 +38,10 @@ function begin(): Tx { return null as any }
function makeInKeys(numKeys: number): string { return '' }
interface DB {
make(descFileOrContent: string): Array<Object>
make(descFileOrContent: string): Object[]
query(sql: string, ...args: any): QueryResult
query1(sql: string, ...args: any): QueryResult1
query1a(sql: string, ...args: any): QueryResult1A
query11(sql: string, ...args: any): QueryResult11
exec(sql: string, ...args: any): ExecResult
insert(table: string, data: Object): ExecResult
@ -52,6 +56,7 @@ interface DB {
interface Tx {
query(sql: string, ...args: any): QueryResult
query1(sql: string, ...args: any): QueryResult1
query1a(sql: string, ...args: any): QueryResult1A
query11(sql: string, ...args: any): QueryResult11
exec(sql: string, ...args: any): ExecResult
insert(table: string, data: Object): ExecResult
@ -64,25 +69,37 @@ interface Tx {
interface QueryResult {
sql: string
args: Array<any>
result: Array<Object>
args: any[]
result: Object[]
}
interface QueryResultA {
sql: string
args: any[]
result: any[][]
}
interface QueryResult1 {
sql: string
args: Array<any>
args: any[]
result: Object
}
interface QueryResult1A {
sql: string
args: any[]
result: any[]
}
interface QueryResult11 {
sql: string
args: Array<any>
args: any[]
result: any
}
interface ExecResult {
sql: string
args: Array<any>
args: any[]
id: number
changes: number
}

View File

@ -6,13 +6,14 @@ import (
"testing"
"apigo.cc/gojs"
_ "apigo.cc/gojs/console"
_ "apigo.cc/gojs/db"
"github.com/ssgo/u"
_ "modernc.org/sqlite"
)
func Test(t *testing.T) {
// gojs.ExportForDev()
gojs.ExportForDev()
defer os.Remove("test.db")
r, err := gojs.RunFile("db_test.js", "Tom")
if err != nil {

View File

@ -1,4 +1,5 @@
import db from 'apigo.cc/gojs/db'
import co from 'apigo.cc/gojs/console'
function main(testUserName) {
db.setDefault('sqlite://test.db')
@ -15,5 +16,15 @@ function main(testUserName) {
`)
db.insert('User', { name: testUserName })
let user = db.query1('SELECT * FROM User').result
let r = db.query1('SELECT * FROM User WHERE name = ?', testUserName)
co.info(r)
// db.delete('User', "name=?", testUserName)
db.insert('_deleted', { table: 'User', id: r.result.id })
r = db.query('SELECT * FROM _deleted')
co.info(r)
return user
}

52
go.mod
View File

@ -1,43 +1,45 @@
module apigo.cc/gojs/db
go 1.21
toolchain go1.22.5
go 1.24.0
require (
apigo.cc/gojs v0.0.8
github.com/ssgo/dao v0.1.5
github.com/ssgo/db v1.7.11
github.com/ssgo/log v1.7.7
github.com/ssgo/u v1.7.13
modernc.org/sqlite v1.34.2
apigo.cc/gojs v0.0.32
apigo.cc/gojs/console v0.0.4
github.com/go-sql-driver/mysql v1.9.3
github.com/jackc/pgx/v5 v5.7.6
github.com/ssgo/dao v0.1.13
github.com/ssgo/db v1.7.13
github.com/ssgo/log v1.7.10
github.com/ssgo/u v1.7.23
modernc.org/sqlite v1.40.1
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
github.com/google/pprof v0.0.0-20250903194437-c28834ac2320 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/ssgo/config v1.7.9 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/ssgo/config v1.7.10 // indirect
github.com/ssgo/standard v1.7.7 // indirect
github.com/ssgo/tool v0.4.27 // indirect
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
github.com/ssgo/tool v0.4.29 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852 // indirect
modernc.org/libc v1.61.4 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
modernc.org/libc v1.66.10 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)