forked from mirror/gorm
Update README
This commit is contained in:
parent
bf1db1534e
commit
094a546815
39
README.md
39
README.md
|
@ -12,41 +12,51 @@ Yet Another ORM library for Go, aims for developer friendly
|
||||||
* Transaction
|
* Transaction
|
||||||
* Logger Support
|
* Logger Support
|
||||||
* Bind struct with tag
|
* Bind struct with tag
|
||||||
|
* Iteration Support via sql.Rows
|
||||||
|
* sql.Scanner
|
||||||
* Every feature comes with tests
|
* Every feature comes with tests
|
||||||
* Convention Over Configuration
|
* Convention Over Configuration
|
||||||
* Developer Friendly
|
* Developer Friendly
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
|
* Table name is the plural of struct name's snake case.
|
||||||
|
Disable pluralization with `db.SingularTable(true)`, or [specify your table name](#specify-table-name)
|
||||||
|
* Column name is the snake case of field's name.
|
||||||
|
* Use `Id int64` field as primary key.
|
||||||
|
* Use tag `sql` to change field's property, change the tag name with `db.SetTagIdentifier(new_name)`.
|
||||||
|
* Use `CreatedAt` to store record's created time if it exist.
|
||||||
|
* Use `UpdatedAt` to store record's updated time if it exist.
|
||||||
|
* Use `DeletedAt` to store record's deleted time if it exist. [Soft Delete](#soft-delete)
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// TableName: `users`, gorm will pluralize struct's name as table name, you are possible to turn off this feature
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Id int64 // Id: Database Primary key
|
Id int64
|
||||||
Birthday time.Time
|
Birthday time.Time
|
||||||
Age int64
|
Age int64
|
||||||
Name string `sql:"size:255"` // set this field's length in database
|
Name string `sql:"size:255"`
|
||||||
CreatedAt time.Time // Time of record is created, will be insert automatically
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time // Time of record is updated, will be updated automatically
|
UpdatedAt time.Time
|
||||||
DeletedAt time.Time // Time of record is deleted, refer `Soft Delete` for more
|
DeletedAt time.Time
|
||||||
|
|
||||||
Emails []Email // Embedded structs
|
Emails []Email // Embedded structs
|
||||||
BillingAddress Address // Embedded struct
|
BillingAddress Address // Embedded struct
|
||||||
BillingAddressId sql.NullInt64 // Embedded struct BillingAddress's foreign key
|
BillingAddressId sql.NullInt64 // BillingAddress's foreign key
|
||||||
ShippingAddress Address // Embedded struct
|
ShippingAddress Address // Another Embedded struct with same type
|
||||||
ShippingAddressId int64 // Embedded struct ShippingAddress's foreign key
|
ShippingAddressId int64 // ShippingAddress's foreign key
|
||||||
IgnoreMe int64 `sql:"-"` // Ignore this field
|
IgnoreMe int64 `sql:"-"` // Ignore this field
|
||||||
}
|
}
|
||||||
|
|
||||||
type Email struct { // TableName: `emails`
|
type Email struct {
|
||||||
Id int64
|
Id int64
|
||||||
UserId int64 // Foreign key for above embedded structs
|
UserId int64 // Foreign key for User
|
||||||
Email string `sql:"type:varchar(100);"` // Set this field's type in database
|
Email string `sql:"type:varchar(100);"` // Set this field's type
|
||||||
Subscribed bool
|
Subscribed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Address struct { // TableName: `addresses`
|
type Address struct {
|
||||||
Id int64
|
Id int64
|
||||||
Address1 string `sql:"not null;unique"` // Set this field as not null and unique in database
|
Address1 string `sql:"not null;unique"` // Set this field as not nullable and unique in database
|
||||||
Address2 string `sql:"type:varchar(100);unique"`
|
Address2 string `sql:"type:varchar(100);unique"`
|
||||||
Post sql.NullString `sql:not null`
|
Post sql.NullString `sql:not null`
|
||||||
// FYI, "NOT NULL" will only works well with NullXXX Scanner, because golang will initalize a default value for most type...
|
// FYI, "NOT NULL" will only works well with NullXXX Scanner, because golang will initalize a default value for most type...
|
||||||
|
@ -735,7 +745,6 @@ db.Where("email = ?", "x@example.org").Attrs(User{RegisteredIp: "111.111.111.111
|
||||||
```
|
```
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
* Rows, Row
|
|
||||||
* Cache Stmt for performance
|
* Cache Stmt for performance
|
||||||
* Join, Having, Group, Includes
|
* Join, Having, Group, Includes
|
||||||
* Scopes, Valiations
|
* Scopes, Valiations
|
||||||
|
|
23
do.go
23
do.go
|
@ -341,6 +341,16 @@ func (s *Do) related(value interface{}, foreign_keys ...string) *Do {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Do) row() *sql.Row {
|
||||||
|
s.prepareQuerySql()
|
||||||
|
return s.db.db.QueryRow(s.sql, s.sqlVars...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Do) rows() (*sql.Rows, error) {
|
||||||
|
s.prepareQuerySql()
|
||||||
|
return s.db.db.Query(s.sql, s.sqlVars...)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Do) query() *Do {
|
func (s *Do) query() *Do {
|
||||||
defer s.trace(time.Now())
|
defer s.trace(time.Now())
|
||||||
var (
|
var (
|
||||||
|
@ -400,12 +410,8 @@ func (s *Do) query() *Do {
|
||||||
|
|
||||||
func (s *Do) count(value interface{}) *Do {
|
func (s *Do) count(value interface{}) *Do {
|
||||||
defer s.trace(time.Now())
|
defer s.trace(time.Now())
|
||||||
|
|
||||||
s.search = s.search.clone().selects("count(*)")
|
s.search = s.search.clone().selects("count(*)")
|
||||||
s.prepareQuerySql()
|
s.err(s.row().Scan(value))
|
||||||
if !s.db.hasError() {
|
|
||||||
s.err(s.db.db.QueryRow(s.sql, s.sqlVars...).Scan(value))
|
|
||||||
}
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,11 +425,7 @@ func (s *Do) pluck(column string, value interface{}) *Do {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
s.prepareQuerySql()
|
rows, err := s.rows()
|
||||||
|
|
||||||
if !s.db.hasError() {
|
|
||||||
rows, err := s.db.db.Query(s.sql, s.sqlVars...)
|
|
||||||
|
|
||||||
if s.err(err) == nil {
|
if s.err(err) == nil {
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
|
@ -432,7 +434,6 @@ func (s *Do) pluck(column string, value interface{}) *Do {
|
||||||
dest_out.Set(reflect.Append(dest_out, reflect.ValueOf(dest).Elem()))
|
dest_out.Set(reflect.Append(dest_out, reflect.ValueOf(dest).Elem()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
27
gorm_test.go
27
gorm_test.go
|
@ -1364,6 +1364,33 @@ func TestQueryChain(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRow(t *testing.T) {
|
||||||
|
row := db.Table("users").Where("name = ?", "2").Select("age").Row()
|
||||||
|
var age int64
|
||||||
|
row.Scan(&age)
|
||||||
|
if age != 20 {
|
||||||
|
t.Errorf("Scan with Row")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRows(t *testing.T) {
|
||||||
|
rows, err := db.Table("users").Where("name = ?", "3").Select("name, age").Rows()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Not error should happen, but got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
for rows.Next() {
|
||||||
|
var name string
|
||||||
|
var age int64
|
||||||
|
rows.Scan(&name, &age)
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if count != 2 {
|
||||||
|
t.Errorf("Should found two records with name 3")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkGorm(b *testing.B) {
|
func BenchmarkGorm(b *testing.B) {
|
||||||
b.N = 2000
|
b.N = 2000
|
||||||
for x := 0; x < b.N; x++ {
|
for x := 0; x < b.N; x++ {
|
||||||
|
|
8
main.go
8
main.go
|
@ -93,6 +93,14 @@ func (s *DB) Find(out interface{}, where ...interface{}) *DB {
|
||||||
return s.clone().do(out).where(where...).query().db
|
return s.clone().do(out).where(where...).query().db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DB) Row() *sql.Row {
|
||||||
|
return s.do(s.data).row()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DB) Rows() (*sql.Rows, error) {
|
||||||
|
return s.do(s.data).rows()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DB) Attrs(attrs ...interface{}) *DB {
|
func (s *DB) Attrs(attrs ...interface{}) *DB {
|
||||||
return s.clone().search.attrs(attrs...).db
|
return s.clone().search.attrs(attrs...).db
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue