diff --git a/go.mod b/go.mod index 0e57796..7fd64c3 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,9 @@ module github.com/goplus/yap go 1.18 require ( + github.com/go-sql-driver/mysql v1.7.1 github.com/golang-jwt/jwt/v5 v5.2.0 github.com/goplus/gop v1.2.0 + github.com/mattn/go-sqlite3 v1.14.16 github.com/qiniu/x v1.13.4-0.20240205192036-55db357e2bdf ) diff --git a/go.sum b/go.sum index abb4fc8..7710560 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,10 @@ +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/goplus/gop v1.2.0 h1:1EOUKhr4OitJs0BtVBVVbejuUkLbXMiFparS1VW7Fhg= github.com/goplus/gop v1.2.0/go.mod h1:F4xOWRMTPCKzNBaF1gZC/JsEKtYW1+Ldwp7tyFoaOWo= +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/qiniu/x v1.13.4-0.20240205192036-55db357e2bdf h1:FCmAN2cuVQWqWd5Mkko0W6Tuc5q2DT+tuz1Ln1zvd7M= github.com/qiniu/x v1.13.4-0.20240205192036-55db357e2bdf/go.mod h1:INZ2TSWSJVWO/RuELQROERcslBwVgFG7MkTfEdaQz9E= diff --git a/gop.mod b/gop.mod index 1472e73..e19450c 100644 --- a/gop.mod +++ b/gop.mod @@ -12,3 +12,4 @@ import github.com/goplus/yap/ytest/auth/jwt project _ydb.gox AppGen github.com/goplus/yap/ydb class _ydb.gox Sql github.com/goplus/yap/ydb +import github.com/goplus/yap/ydb/mysql diff --git a/reflectutil/reflect_test.go b/reflectutil/reflect_test.go index b56073e..8ff1624 100644 --- a/reflectutil/reflect_test.go +++ b/reflectutil/reflect_test.go @@ -25,7 +25,7 @@ func TestSetZero(t *testing.T) { a := 2 v := reflect.ValueOf(&a).Elem() SetZero(v) - if !v.IsZero() { - t.Fatal("SetZero:", v) + if a != 0 { + t.Fatal("SetZero:", a) } } diff --git a/ydb/classfile.go b/ydb/classfile.go index ec4a6d6..2c79795 100644 --- a/ydb/classfile.go +++ b/ydb/classfile.go @@ -51,14 +51,20 @@ func (p *Sql) initSql() { // Engine initializes database by specified engine name. func (p *Sql) Engine__0(name string, src ...ast.Node) { - if defaultDataSource, ok := engineDataSource[name]; ok { - db, err := sql.Open(name, defaultDataSource) - if err != nil { - log.Panicln("sql.Open:", err) - } - p.db = db - p.driver = name + defaultDataSource, ok := engineDataSource[name] + if !ok { + log.Panicf("engine `%s` not found: please call ydb.Register first\n", name) } + dataSource, ok := defaultDataSource.(string) + if !ok { + dataSource = defaultDataSource.(func() string)() + } + db, err := sql.Open(name, dataSource) + if err != nil { + log.Panicln("sql.Open:", err) + } + p.db = db + p.driver = name } // Engine returns engine name of the database. @@ -120,11 +126,12 @@ func (p *Sql) Class(name string, spec func(), src ...ast.Node) { // ----------------------------------------------------------------------------- var ( - engineDataSource map[string]string // engineName => defaultDataSource + engineDataSource = make(map[string]any) // engineName => defaultDataSource ) // Register registers a engine and its default data source. -func Register(name, defaultDataSource string) { +// defaultDataSource can be a `string` or a `func() string` object. +func Register(name string, defaultDataSource any) { engineDataSource[name] = defaultDataSource } diff --git a/ydb/demo/foo/foo_ydb.gox b/ydb/demo/foo/foo_ydb.gox index b85395d..a551195 100644 --- a/ydb/demo/foo/foo_ydb.gox +++ b/ydb/demo/foo/foo_ydb.gox @@ -1,5 +1,8 @@ import ( "time" + + _ "github.com/goplus/yap/ydb/mysql" + _ "github.com/goplus/yap/ydb/sqlite3" ) type User struct { diff --git a/ydb/demo/foo/gop_autogen.go b/ydb/demo/foo/gop_autogen.go index 2c56649..4a46b52 100644 --- a/ydb/demo/foo/gop_autogen.go +++ b/ydb/demo/foo/gop_autogen.go @@ -3,6 +3,8 @@ package main import ( "errors" "github.com/goplus/yap/ydb" + _ "github.com/goplus/yap/ydb/mysql" + _ "github.com/goplus/yap/ydb/sqlite3" "time" ) @@ -37,7 +39,7 @@ type foo struct { } func main() { -//line ydb/demo/foo/foo_ydb.gox:80:1 +//line ydb/demo/foo/foo_ydb.gox:83:1 ydb.Gopt_AppGen_Main(new(ydb.AppGen), new(foo)) } @@ -52,101 +54,101 @@ func Hmac(pwd string, salt string) string { //line ydb/demo/foo/foo.gop:14:1 return "" } -//line ydb/demo/foo/foo_ydb.gox:33 +//line ydb/demo/foo/foo_ydb.gox:36 func (this *foo) Main() { -//line ydb/demo/foo/foo_ydb.gox:33:1 +//line ydb/demo/foo/foo_ydb.gox:36:1 this.Engine__0("mysql") -//line ydb/demo/foo/foo_ydb.gox:35:1 +//line ydb/demo/foo/foo_ydb.gox:38:1 ydb.Gopt_Sql_Gopx_Table[User](this, "user v0.1.0") -//line ydb/demo/foo/foo_ydb.gox:37:1 +//line ydb/demo/foo/foo_ydb.gox:40:1 ydb.Gopt_Sql_Gopx_Table[Article](this, "v0.1.0") -//line ydb/demo/foo/foo_ydb.gox:38:1 +//line ydb/demo/foo/foo_ydb.gox:41:1 this.From("oldart v0.9.1", func() { }) -//line ydb/demo/foo/foo_ydb.gox:43:1 +//line ydb/demo/foo/foo_ydb.gox:46:1 ydb.Gopt_Sql_Gopx_Table[Tag](this, "v0.1.0") -//line ydb/demo/foo/foo_ydb.gox:45:1 +//line ydb/demo/foo/foo_ydb.gox:48:1 this.Class("Users", func() { -//line ydb/demo/foo/foo_ydb.gox:46:1 +//line ydb/demo/foo/foo_ydb.gox:49:1 this.Use("user") -//line ydb/demo/foo/foo_ydb.gox:48:1 +//line ydb/demo/foo/foo_ydb.gox:51:1 this.Api("register", func(id string, pwd string, nickname string, email string, tel string, ctime time.Time) error { -//line ydb/demo/foo/foo_ydb.gox:49:1 +//line ydb/demo/foo/foo_ydb.gox:52:1 if email == "" && tel == "" { -//line ydb/demo/foo/foo_ydb.gox:50:1 +//line ydb/demo/foo/foo_ydb.gox:53:1 return ErrNoEmailAndTel } -//line ydb/demo/foo/foo_ydb.gox:52:1 +//line ydb/demo/foo/foo_ydb.gox:55:1 this.Limit__2(3, "email=?", email) -//line ydb/demo/foo/foo_ydb.gox:53:1 +//line ydb/demo/foo/foo_ydb.gox:56:1 this.Limit__2(3, "tel=?", tel) -//line ydb/demo/foo/foo_ydb.gox:55:1 +//line ydb/demo/foo/foo_ydb.gox:58:1 salt := Rand() -//line ydb/demo/foo/foo_ydb.gox:56:1 +//line ydb/demo/foo/foo_ydb.gox:59:1 spwd := Hmac(pwd, salt) -//line ydb/demo/foo/foo_ydb.gox:57:1 +//line ydb/demo/foo/foo_ydb.gox:60:1 this.Insert__1(&User{Id: id, Spwd: spwd, Salt: salt, Nickname: nickname, Email: email, Tel: tel, Ctime: ctime}) -//line ydb/demo/foo/foo_ydb.gox:59:1 +//line ydb/demo/foo/foo_ydb.gox:62:1 return nil }) -//line ydb/demo/foo/foo_ydb.gox:61:1 +//line ydb/demo/foo/foo_ydb.gox:64:1 this.Call__1("user", "pwd", "nickname", "", "", time.Now()) -//line ydb/demo/foo/foo_ydb.gox:62:1 +//line ydb/demo/foo/foo_ydb.gox:65:1 this.Ret__1(ErrNoEmailAndTel) -//line ydb/demo/foo/foo_ydb.gox:63:1 +//line ydb/demo/foo/foo_ydb.gox:66:1 this.Call__1("user", "pwd", "nickname", "user@foo.com", "", time.Now()) -//line ydb/demo/foo/foo_ydb.gox:64:1 +//line ydb/demo/foo/foo_ydb.gox:67:1 this.Ret__0(nil) -//line ydb/demo/foo/foo_ydb.gox:65:1 +//line ydb/demo/foo/foo_ydb.gox:68:1 this.Call__1("user", "pwd", "nickname", "user@foo.com", "13500000000", time.Now()) -//line ydb/demo/foo/foo_ydb.gox:66:1 +//line ydb/demo/foo/foo_ydb.gox:69:1 this.Ret__1(ydb.ErrDuplicated) -//line ydb/demo/foo/foo_ydb.gox:68:1 +//line ydb/demo/foo/foo_ydb.gox:71:1 this.Api("login", func(id string, pwd string) bool { -//line ydb/demo/foo/foo_ydb.gox:69:1 +//line ydb/demo/foo/foo_ydb.gox:72:1 var spwd, salt string -//line ydb/demo/foo/foo_ydb.gox:70:1 +//line ydb/demo/foo/foo_ydb.gox:73:1 this.Query__1("id=?", id) -//line ydb/demo/foo/foo_ydb.gox:71:1 +//line ydb/demo/foo/foo_ydb.gox:74:1 this.Ret__1("salt", &salt, "spwd", &spwd) -//line ydb/demo/foo/foo_ydb.gox:72:1 +//line ydb/demo/foo/foo_ydb.gox:75:1 return Hmac(pwd, salt) == spwd }) -//line ydb/demo/foo/foo_ydb.gox:74:1 +//line ydb/demo/foo/foo_ydb.gox:77:1 this.Call__1("", "") -//line ydb/demo/foo/foo_ydb.gox:75:1 +//line ydb/demo/foo/foo_ydb.gox:78:1 this.Ret__1(false) -//line ydb/demo/foo/foo_ydb.gox:76:1 +//line ydb/demo/foo/foo_ydb.gox:79:1 this.Call__1("user", "pwd") -//line ydb/demo/foo/foo_ydb.gox:77:1 +//line ydb/demo/foo/foo_ydb.gox:80:1 this.Ret__1(true) }) -//line ydb/demo/foo/foo_ydb.gox:80:1 +//line ydb/demo/foo/foo_ydb.gox:83:1 this.Class("Articles", func() { -//line ydb/demo/foo/foo_ydb.gox:81:1 +//line ydb/demo/foo/foo_ydb.gox:84:1 this.Use("article") -//line ydb/demo/foo/foo_ydb.gox:83:1 +//line ydb/demo/foo/foo_ydb.gox:86:1 this.Api("listByTag", func(tag string) (result []ArticleEntry) { -//line ydb/demo/foo/foo_ydb.gox:84:1 +//line ydb/demo/foo/foo_ydb.gox:87:1 var ids []string -//line ydb/demo/foo/foo_ydb.gox:85:1 +//line ydb/demo/foo/foo_ydb.gox:88:1 this.Query__1("tag.name=?", tag) -//line ydb/demo/foo/foo_ydb.gox:86:1 +//line ydb/demo/foo/foo_ydb.gox:89:1 this.Ret__1("tag.article", &ids) -//line ydb/demo/foo/foo_ydb.gox:88:1 +//line ydb/demo/foo/foo_ydb.gox:91:1 this.Query__1("id=?", ids) -//line ydb/demo/foo/foo_ydb.gox:89:1 +//line ydb/demo/foo/foo_ydb.gox:92:1 this.Ret__1(&result) -//line ydb/demo/foo/foo_ydb.gox:90:1 +//line ydb/demo/foo/foo_ydb.gox:93:1 return }) -//line ydb/demo/foo/foo_ydb.gox:93:1 +//line ydb/demo/foo/foo_ydb.gox:96:1 this.Api("listByAuthor", func(author string) (result []ArticleEntry) { -//line ydb/demo/foo/foo_ydb.gox:94:1 +//line ydb/demo/foo/foo_ydb.gox:97:1 this.Query__1("author=?", author) -//line ydb/demo/foo/foo_ydb.gox:95:1 +//line ydb/demo/foo/foo_ydb.gox:98:1 this.Ret__1(&result) -//line ydb/demo/foo/foo_ydb.gox:96:1 +//line ydb/demo/foo/foo_ydb.gox:99:1 return }) }) diff --git a/ydb/mysql/mysql.go b/ydb/mysql/mysql.go new file mode 100644 index 0000000..fe63ebf --- /dev/null +++ b/ydb/mysql/mysql.go @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mysql + +import ( + "log" + "os" + + _ "github.com/go-sql-driver/mysql" + "github.com/goplus/yap/ydb" +) + +// Register registers a default data source for `mysql` engine. +func Register(defaultDataSource string) { + ydb.Register("mysql", defaultDataSource) +} + +func init() { + ydb.Register("mysql", func() string { + dataSource := os.Getenv("YDB_MYSQL_TEST") + if dataSource == "" { + log.Panicln("env `YDB_MYSQL_TEST` not found, please set it before running") + } + return dataSource + }) +} diff --git a/ydb/sqlite3/sqlite3.go b/ydb/sqlite3/sqlite3.go new file mode 100644 index 0000000..c7237d8 --- /dev/null +++ b/ydb/sqlite3/sqlite3.go @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sqlite3 + +import ( + "github.com/goplus/yap/ydb" + _ "github.com/mattn/go-sqlite3" +) + +func init() { + ydb.Register("sqlite3", "file:test.db?cache=shared&mode=memory") +}