coocood / qbs Goto Github PK
View Code? Open in Web Editor NEWQBS stands for Query By Struct. A Go ORM.
License: MIT License
QBS stands for Query By Struct. A Go ORM.
License: MIT License
Is there any reason to make base private?
when I try the code:
func FindUserByName(q _qbs.Qbs, n string) (_User, error) {
user := new(User)
err := q.WhereEqual("name", n).Find(user)
return user, err
}
It return an error "sql: no rows in result set"
I try the the git://github.com/insionng/toropress .
It can't not select user info to login In Postgresql .
But in sqlite everything is ok.
The testutil*.go are non-test files, but they import the "testing" package. This causes all of the command-line flags from the "testing" package to appear in projects that use the "qbs" package.
When I executed CreateTableIfNotExists on a struct, it only creates Id column.
I tried to debug it and found that in function structPtrToModel in models.go file, all the other fields are getting omitted in this following code,
fieldValue := structValue.FieldByName(structField.Name)
if !fieldValue.CanInterface() {
continue
}
There is a panic in qbs.Count when the rows returned to count don't exist (because the table doesn't exist yet, the connection hasn't come up yet, etc).
2015/02/10 01:46:58 setting up DB: postgres://postgres:seekret@localhost/candidate?sslmode=disable
qbs:2015/02/10 01:46:58 pq: the database system is starting up
qbs:2015/02/10 01:46:58 pq: the database system is starting up
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x6ba924]
goroutine 26 [running]:
runtime.panic(0x863220, 0xb4ddd3)
/opt/go/src/pkg/runtime/panic.c:279 +0xf5
database/sql.(*Row).Scan(0x0, 0x7f715abf8d90, 0x1, 0x1, 0x0, 0x0)
/opt/go/src/pkg/database/sql/sql.go:1636 +0x44
github.com/coocood/qbs.(*Qbs).Count(0xc208060880, 0x891fc0, 0xc208029b20, 0x0)
/go/src/github.com/coocood/qbs/qbs.go:610 +0x293
If you look at qbs.go:610, you'll see that it calls the following:
if q.criteria.condition != nil {
conditionSql, args := q.criteria.condition.Merge()
query += " WHERE " + conditionSql
row = q.QueryRow(query, args...)
} else {
row = q.QueryRow(query)
}
var count int64
err := row.Scan(&count)
And QueryRow
can return a nil row
, thus calling the row.Scan
with a nil row
value:
func (q *Qbs) QueryRow(query string, args ...interface{}) *sql.Row {
q.log(query, args...)
query = q.Dialect.substituteMarkers(query)
stmt, err := q.prepare(query)
if err != nil {
q.updateTxError(err)
return nil
}
return stmt.QueryRow(args...)
}
In this case q.prepare is failing, as postgres is still coming up. Thus return nil
is called, and not checked in the callers of QueryRow. I see this as a bug in:
ContainsValue
on line 578Count
on line 610Whereas doQueryRow
returns the errors all the way out. I'm pushing a pull request that fixes this up a bit in a moment.
Tell me please, what is current status of project?
Latest commit on Jan, is development stopped?
What is the preferred English pronunciation of qbs
? I like "cubes" - it sounds a lot nicer than "queue bee ess". :)
Are there any plans to implement relationships between tables and Joins?
package main
import (
"fmt"
"github.com/coocood/qbs"
_ "github.com/mattn/go-sqlite3"
"time"
)
type Book struct {
Id int64
Title string
Author string
Published time.Time
}
func main() {
qbs.Register("sqlite3", "book.db", "qbs_test", qbs.NewSqlite3())
q, err := qbs.GetQbs()
migration, err := qbs.GetMigration()
defer migration.Close()
err = migration.CreateTableIfNotExists(new(Book))
fmt.Println(err)
var book = &Book{
Title: "new book",
Author: "qbs",
Published: time.Now(),
}
out, err := q.Save(book)
fmt.Println(out,err)
var books []*Book
err = q.Limit(10).Offset(10).FindAll(&books)
fmt.Println(err)
for k, v := range books {
fmt.Println(k, v)
}
/*
sqlite> select * from book;
4|new book|qbs|2021-10-14 07:27:48.3926642+08:00
*/
}
D:\GOPATH\src\github.com\coocood\qbs>go install
testutil_db.go:6:2: cannot find package "github.com/coocood/assrt" in any of:
c:\go\src\pkg\github.com\coocood\assrt (from $GOROOT)
D:\GOPATH\src\github.com\coocood\assrt (from $GOPATH)
Forgot to commit something?
Hi,
I would like to test QBS performance on the TechEmpower Benchmarks. However, the test uses a database schema that uses TitleCase naming convention instead of snake_case -- is it possible to change the convention, or QBS only supports snake case?
Thanks!
Rob
I suggest that the source code get's linted with https://github.com/golang/lint
According to the linter, it is for example necessary to name all methods that contain the keyword id
uppercase, for example getId
must be getID
and so on.
here is a complete list of those uppercase keywords: https://github.com/golang/lint/blob/master/lint.go#L656
type User struct {
Id int64
Loginname string `qbs:"size:50,notnull,unique"`
Name, Password string `qbs:"size:50,index"`
Registered bool `qbs:"default:false,notnull,index"`
Created time.Time `qbs:"index"`
Updated time.Time `qbs:"index"`
}
func FindUserById(q *qbs.Qbs, id int64) (*User, error) {
user := new(User)
user.Id = id
err := q.Find(user)
return user, err
}
//////////////////////////////////////////////////////////////////////////////
q, err := qbs.GetQbs()
if err != nil {
fmt.Println(err)
this.Controller.Ctx.ResponseWriter.WriteHeader(500)
return
}
defer q.Close()
u, err := db.FindUserById(q, 1)
fmt.Fprintf(this.Controller.Ctx.ResponseWriter, u.Loginname)
//////////////////////////////////////////////////////////////////////////////////
error:
reflect.Set: value of type []uint8 is not assignable to type time.Time
github.com/coocood/qbs.base.setModelValue(0x1f0bb7e0, 0x1f010828, 0x5fc800, 0x1f0ebfb8, 0x146, ...)
D:/My Design/golang/src/github.com/coocood/qbs/base.go:56 +0x415
qbs.Register("mysql", "root:password@/database1?charset=utf8&parseTime=true&loc=Local", "database2", qbs.NewMysql())
如上述配置文件中,database1
不同于database2
虽然可以正常创建表,但会导致在CreateTableIfNotExists
检查数据库中字段数目是否相等时,用到的TABLE_SCHEMA
不同,qbs会重新添加字段,实际上字段已经存在,所以报如下错误
Duplicate column name 'xx'
看是否有必要检查此配置文件错误,并给出友好提示啊?
When we try to insert a struct with Id as pk and Name as string, the result query with arguments is:
INSERT INTO `cars` (`id`, `name`) VALUES (?, ?) []interface {}{0, "test"}
when it should be
INSERT INTO `cars` (`name`) VALUES (?) []interface {}{"test"}
or
INSERT INTO `cars` (`id`, `name`) VALUES (?, ?) []interface {}{NULL, "test"}
请教,在执行多次qbs.Exec(sql)后,会报这个错误
1461: Can' t create more than max_prepared_stmt_count statements (current value: 16382)
数据库显示:
| Com_stmt_close | 456 |
| Com_stmt_execute | 132936 |
| Com_stmt_fetch | 0 |
| Com_stmt_prepare | 91187 |
请问,要在哪进行com_stmt_close关闭
package main
import (
"fmt"
"github.com/coocood/qbs"
_ "github.com/mattn/go-sqlite3"
"log"
"time"
)
type Blog struct {
Id int64
Title string `db:"title"`
Author string `db:"author"`
Published time.Time `db:"published"`
}
func checkErr(err error, msg string) {
if err != nil {
log.Fatalln(msg, err)
}
}
func main() {
qbs.Register("sqlite3", "blog.db", "qbs_test", qbs.NewSqlite3())
q, err := qbs.GetQbs()
fmt.Print(q, err)
migration, err := qbs.GetMigration()
defer migration.Close()
err = migration.CreateTableIfNotExists(new(Blog))
fmt.Println(err)
}
generate table schema
CREATE TABLE `blog` ( `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, `title` text, `author` text, `published` text )
例如有如下需求:
type TranStatus uint16
const (
Isolated = TranStatus(0x10)
Canceled = TranStatus(0x20)
Pending = TranStatus(0x40)
Completed = TranStatus(0x80)
)
type Transaction struct {
Session string `qbs:"size:32,pk"`
Sys string `qbs:"size:20"`
SysTrans string `qbs:"size:32"`
BeginTime time.Time
CancelTime time.Time
CompleteTime time.Time
IsolateTime time.Time
Status TranStatus
}
其中Transaction
中的Status
非基本数据类型,在创建数据表时抛出panic: invalid sql type
错误
建议提供更友好的错误提示,或者支持此类操作,golang本身的json库能很好的处理该问题:http://play.golang.org/p/pQ9qkXS_HV
when I "go get github.com/coocood/qbs" there is a problem,How can I fix it?
michael2008s$ go get github.com/coocood/qbs
src/github.com/coocood/qbs/qbs.go:51: db.SetMaxIdleConns undefined (type *sql.DB has no field or method SetMaxIdleConns)
src/github.com/coocood/qbs/qbs.go:100: db.SetMaxIdleConns undefined (type *sql.DB has no field or method SetMaxIdleConns)
I would like to modify the JSON formatting of date, so I had to declare new type based on time.Time. Now the problem is Qbs doesn't allow the type of table field to be anything other than built-in types. It would be nice if it can detect the derived types and still treat it like normal.
表结构
CREATE TABLE md_grab_product
(
id
int(11) NOT NULL AUTO_INCREMENT,
product_name
varchar(100) NOT NULL COMMENT '产品名字',
product_desc
varchar(255) NOT NULL COMMENT '产品描述',
market_price
int(11) NOT NULL COMMENT '市场价格 单位是分',
max_price
int(11) NOT NULL COMMENT '最大价格 单位是分',
min_price
int(11) NOT NULL DEFAULT '1' COMMENT '最小价格 单位是分',
product_count
int(11) NOT NULL DEFAULT '1' COMMENT '产品总数',
surplus_count
int(11) NOT NULL DEFAULT '1' COMMENT '产品剩余的总数',
alert_price
int(11) NOT NULL DEFAULT '0' COMMENT '警示价',
grab_start_time
datetime NOT NULL COMMENT '抢购开始时间',
grab_end_time
datetime NOT NULL COMMENT '抢购结束时间',
createtime
datetime NOT NULL COMMENT '创建时间',
upatetime
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (id
),
KEY start
(grab_start_time
),
KEY end
(grab_end_time
)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COMMENT='抢购产品表'
struct:
type Md_grab_product struct {
Id int64
Product_name string qbs:"size:100"
Product_desc string qbs:"size:255"
Market_price int64
Max_price int64
Min_price int64
Product_count int64
Surplus_count int64
Alert_price int64
Grab_start_time time.Time
Grab_end_time time.Time
Createtime time.Time
}
方法:
func FindById(q _qbs.Qbs, id int64) (_Md_grab_product, error) {
q.Log = true
grabProduct := new(Md_grab_product)
grabProduct.Id = id
err := q.Find(grabProduct)
return grabProduct, err
}
sql log:
qbs:2013/11/26 17:59:55 SELECT id
, product_name
, product_desc
, market_price
, max_price
, min_price
, product_count
, surplus_count
, alert_price
, grab_start_time
, grab_end_time
, createtime
FROM md_grab_product
WHERE md_grab_product
.id
= ? LIMIT ?
qbs:2013/11/26 17:59:55 2 1
死活查不出数据求救
Sqlite3 has an own data type for timestamps: datetime.
Qbs does not support "datetime" with sqlite. So it's hard to use an existing database.
When I use "text" for my time.Time types, it's working well. But this is not acceptable, because it is not possible to use the sqlite datetime features.
HI, I created a table with this structure:
type Groups struct {
Id int64 `qbs:"pk"`
FacultyId int64 `qbs:"fk:Faculty"`
Faculty *Faculties
FullName string `qbs:"size:100"`
ShortName string `qbs:"size:20"`
NumOfStudents int
Year int
}
And when I use the function WhereEqual() in this context:
group := new(Groups)
err := q.WhereEqual("ShortName", "string").Find(group)
I have an error "Unknown column 'ShortName'"
In real table this column named as "short_name", but when I write:
err := q.WhereEqual("short_name", "string").Find(group)
I have an error "Column 'short_name' in where clause is ambiguous".
what to do in this situation? rename table columns? or is there another method?
I noticed that lib/pq
started to support COPY FROM STDIN
. Does it make sense to rewrite BulkInsert
method to use this technique for postgres (maybe by making it a part of dialect)? It is so much faster to import large amounts of data using COPY FROM STDIN
.
Using postgres
dialect on PostgreSQL 9.1.9
for struct:
type Foo struct {
Id int64
Text string
}
inserting
Foo { Id: 1, Text:"bar"}
using Save
then doing a Find
with
Foo { Id: 0, Text: "baz"}
will return
Foo { Id: 1, Text:"bar"}
pretty certain it should return an error of no rows found since it doesn't match any.
Hello,
I'm from test this:
type Test struct {
Id qbs.Id
FatherId int64 `sql:"fk:Father"`
Father *Test
}
If i'm make, 3 elems,
t0.FatherId = 0
t1.FatherId = t0.Id
t2.FatherId = t1.Id
And want to Find t2.
t := &Test{Id: 3}
qbs.Find(t)
t.Father -> Ok
t.Father.Father -> nil
My question is:
You know this "effect" or "not-effect", if yes, you wand to make recursively in future? Or just 1 parent ?
Personally, the both is ok for my app.
Regards.
(Sorry for my English.)
Currently I only read the docs and i read this:
If Id is set to a positive integer, Save would query the count of the row to find
out if the row already exists, if not then execute INSERT statement.
otherwise execute UPDATE.
This is not the best solution, since you need 3 queries to check if a row exists.
It would be way easier to just update the row. Check if the query was successfull or greater than zero and if not just insert the statement.
我定义的struct如下:
type Card struct {
Id int64 `qbs:"index"`
Worth float64
KeyPre int64 `qbs:"unique"
keySub int64
Hash string `qbs:"size:40,index"`
User int64
Time time.Time
}
其中的 keySub
不需要导出,在调用 CreateTableIfNotExists
,提示如下错误:
panic: reflect.Value.Interface: cannot return value obtained from unexported field or method
goroutine 1 [running]:
reflect.valueInterface(0x501560, 0x126a9ed8, 0x67, 0x126ac301, 0x1, ...)
D:/workspace/golang/sdk/1.1/src/pkg/reflect/value.go:983 +0x99
reflect.Value.Interface(0x501560, 0x126a9ed8, 0x67, 0x0, 0x0, ...)
D:/workspace/golang/sdk/1.1/src/pkg/reflect/value.go:972 +0x41
github.com/coocood/qbs.structPtrToModel(0x52cc60, 0x126a9ec0, 0x1d0001, 0x0, 0x0, ...)
D:/workspace/golang/3rdparty/src/github.com/coocood/qbs/model.go:194 +0x468
github.com/coocood/qbs.(*Migration).CreateTableIfNotExists(0x126bce20, 0x52cc60, 0x126a9ec0, 0x1, 0x1, ...)
D:/workspace/golang/3rdparty/src/github.com/coocood/qbs/migration.go:19 +0x4b
应该是 model.go
在反射字段时,未排查unexported field
Can I create struct like this:
User -> Account -> Subscription
with FK
and then get third from first,
like User.Account.Subscription.Name
?
If I try get fields values from second, all good
User.Account.SomeField
,
but when I try get access to User.Account.Subscription
, it return nil.
I have a table in a MySQL database describable by the following qbs struct
type LongTextTable struct {
Id int64
Parent_id int64 `qbs:"fk:Parent"`
Parent *ParentTable
Key string `qbs:"size:255"`
String_value string `qbs:"size:4294967295"` // This field is longtext, null in the table
}
I cannot seem to load the String_value field from the db, though I can load the other fields just fine using FindAll(). Are longtext fields supported by qbs or am I perhaps doing something wrong?
Hello,
First one, thank you for your work.
I found a bug in FindAll(qbs.scanRows).
Here is the error:
panic: reflect: call of reflect.Value.FieldByName on zero Value
goroutine 1 [running]:
reflect.flag.mustBe(0x0, 0x19, 0x100000001, 0x0)
/opt/golang/src/pkg/reflect/value.go:241 +0xa2
reflect.Value.FieldByName(0x0, 0x0, 0x0, 0xf840074fc0, 0x2, ...)
/opt/golang/src/pkg/reflect/value.go:688 +0x40
github.com/coocood/qbs.(*Qbs).scanRows(0xf840032780, 0x47fa38, 0xf840078440, 0x160, 0xf840077a20, ...)
./exp_qbs/src/github.com/coocood/qbs/qbs.go:218 +0x524
github.com/coocood/qbs.(*Qbs).doQueryRows(0xf840032780, 0x47e8b8, 0xf84006e180, 0xf840079000, 0xf8000001ca, ...)
./exp_qbs/src/github.com/coocood/qbs/qbs.go:192 +0x3ba
github.com/coocood/qbs.(*Qbs).FindAll(0xf840032780, 0x47e8b8, 0xf84006e180, 0xf84006e180, 0xf840060fc0, ...)
./exp_qbs/src/github.com/coocood/qbs/qbs.go:149 +0x1fd
main.main()
./exp_qbs/qbs_exp.go:80 +0xdcf
goroutine 2 [syscall]:
created by runtime.main
/opt/golang/src/pkg/runtime/proc.c:221
exit status 2
Short snippet code:
tmpFindAll := make([]*Event, 0)
o.Limit(2).FindAll(&tmpFindAll)
My structure is nested, i thinks is linked.
So I tinker a fix:
diff --git a/qbs.go b/qbs.go
index d989102..2861dc3 100644
--- a/qbs.go
+++ b/qbs.go
@@ -215,9 +215,6 @@ func (q *Qbs) scanRows(rowValue reflect.Value, rows *sql.Rows) (err error) {
paths := strings.Split(key, "___")
if len(paths) == 2 {
subStruct := rowValue.Elem().FieldByName(snakeToUpperCamel(paths[0]))
+ if subStruct.IsNil() {
+ subStruct.Set(reflect.New(subStruct.Type().Elem()))
+ }
subField := subStruct.Elem().FieldByName(snakeToUpperCamel(paths[1]))
if subField.IsValid() {
err = q.Dialect.SetModelValue(value, subField)
创建表报错:Column name has changed, rename column migration is not supported.
mattn/go-sqlite3 15天前的升级
mattn/go-sqlite3@4a7ad32
把row.Next()返回由string变为了slice
qbs\sqlite3.go 的 columnsInTable 函数应当要修改一下
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.