Это мощная библиотека SQL ORM для Golang, обладающая некоторыми забавными функциями.
Build Status | Codecov | Go Report Card | GoDoc | Присоединяйтесь к чату |
---|---|---|---|---|
// если база данных mysql
_ "github.com/go-sql-driver/mysql"
// если база данных sqlite3
_ "github.com/mattn/go-sqlite3"
// когда база данных postgres
_ "github.com/lib/pq"
// если базой данных является mysql, убедитесь, что в вашем mysql есть схема toyorm_example
toy, err = toyorm.Open("mysql", "root:@tcp(localhost:3306)/toyorm_example?charset=utf8&parseTime=True")
// если база данных — sqlite3
toy,err = toyorm.Open("sqlite3", "toyorm_test.db")
// при использовании базы данных postgres
toy, err = toyorm.Open("postgres", "user=postgres dbname=toyorm sslmode=disable")
type Extra map[string]interface{}
func (e Extra) Scan(value interface{}) error {
switch v := value.(type) {
case string:
return json.Unmarshal([]byte(v), e)
case []byte:
return json.Unmarshal(v, e)
default:
return errors.New("not support type")
}
}
func (e Extra) Value() (driver.Value, error) {
return json.Marshal(e)
}
type UserDetail struct {
ID int `toyorm:"primary key;auto_increment"`
UserID
version go-1.9
Импортируйте драйвер базы данных.
// если база данных mysql
_ "github.com/go-sql-driver/mysql"
// если база данных sqlite3
_ "github.com/mattn/go-sqlite3"
// когда база данных postgres
_ "github.com/lib/pq"
Создайте игрушку.
// если базой данных является mysql, убедитесь, что в вашем mysql есть схема toyorm_example
toy, err = toyorm.Open("mysql", "root:@tcp(localhost:3306)/toyorm_example?charset=utf8&parseTime=True")
// если база данных — sqlite3
toy,err = toyorm.Open("sqlite3", "toyorm_test.db")
// при использовании базы данных postgres
toy, err = toyorm.Open("postgres", "user=postgres dbname=toyorm sslmode=disable")
type Extra map[string]interface{}
func (e Extra) Scan(value interface{}) error {
switch v := value.(type) {
case string:
return json.Unmarshal([]byte(v), e)
case []byte:
return json.Unmarshal(v, e)
default:
return errors.New("not support type")
}
}
func (e Extra) Value() (driver.Value, error) {
return json.Marshal(e)
}
type UserDetail struct {
ID int `toyorm:"primary key;auto_increment"`
UserID
*Примечание: перевод выполнен с помощью системы машинного перевода.* **Тип translate**
Если тип SQL не совпадает, toyorm проигнорирует его в операции Sql.
Вы можете использовать тег поля **\<type:sql_type\>** для указания их типа SQL.
Следующие типы будут автоматически переведены в типы SQL:
| Тип Go | Тип SQL |
|--------|---------|
bool | BOOLEAN |
int8, int16, int32, uint8, uint16, uint32 | INTEGER |
int64, uint64, int, uint | BIGINT |
float32, float64 | FLOAT |
string | VARCHAR(255) |
time.Time | TIMESTAMP |
[]byte | VARCHAR(255) |
sql.NullBool | BOOLEAN |
sql.NullInt64 | BIGINT |
sql.NullFloat64 | FLOAT |
sql.NullString | VARCHAR(255) |
sql.RawBytes | VARCHAR(255) |
**Специальные поля**
1. Специальные поля имеют некоторые процессы в обработчиках, не пытайтесь изменить их тип или установить значение.
| Имя поля | Тип | Описание |
|----------|-------|------------|
CreatedAt | time.Time | генерируется при создании элемента |
UpdatedAt | time.Time | генерируется при обновлении/создании элемента |
DeletedAt | *time.Time* | режим удаления — мягкий |
Cas | int | (не поддерживается для sqlite3) операция сохранения завершится ошибкой, если её значение будет изменено третьей стороной, например, в postgres: cas = 1 insert xxx conflict (id) update cas = 2 where cas = 1 |
**Теги полей**
1. Формат тега может быть **\<key:value\>** или **\<key\>**.
2. Следующие теги являются специальными:
| Ключ | Значение | Описание |
|--------------|------------------------|-----------|
index | void или string | используется для оптимизации, когда условие поиска имеет это поле, если вы хотите сделать комбинированный, просто установите одинаковое имя индекса с полями |
unique index | void или string | имеет ограничение уникального индекса, остальное аналогично индексу |
primary key | void | допускается несколько первичных ключей, но некоторые операции не поддерживаются |
\- | void | игнорирует это поле в SQL |
type | string | тип SQL |
column | string | имя столбца SQL |
auto_increment| void | рекомендуется, если ваш первичный ключ таблицы имеет атрибут auto_increment, необходимо добавить его |
autoincrement | void | то же, что и auto_increment |
foreign key | void | чтобы добавить функцию внешнего ключа при создании таблицы |
alias | string | изменить имя поля с помощью toyorm |
join | string | выбрать связанное поле при вызове brick.Join |
belong to | string | выбрать связанное поле при вызове brick.Preload с контейнером BelongTo |
one to one | string | выбрать связанное поле при вызове brick.Preload с контейнером OneToOne |
one to many | string | выбрать связанное поле при вызозе brick.Preload с контейнером OneToMany |
default | srring | значение по умолчанию в базе данных |
Другие пользовательские теги будут добавлены в конец поля CREATE TABLE.
#### Связывание моделей
1. Тип модели должен быть структурой или точкой со структурой.
2. Модель — это информация, которую toyorm знает о таблице.
```golang
brick := toy.Model(&User{})
// или
brick := toy.Model(User{})
var err error
_, err = toy.Model(&User{}).Debug().CreateTable()
// CREATE TABLE user (id BIGINT AUTO_INCREMENT,created_at TIMESTAMP NULL,updated_at TIMESTAMP NULL,deleted_at TIMESTAMP NULL,name VARCHAR(255),age BIGINT ,sex VARCHAR(255) , PRIMARY KEY(id))
// CREATE INDEX idx_user_deletedat ON user(deleted_at)
// CREATE UNIQUE INDEX udx_user_name ON user(name)
_, err =toy.Model(&UserDetail{}).Debug().CreateTable()
// CREATE TABLE user_detail (id BIGINT AUTO_INCREMENT,user_id BIGINT,main_page Text,extra VARCHAR(1024), PRIMARY KEY(id))
// CREATE INDEX idx_user_detail_userid ON user_detail(user_id)
_, err =toy.Model(&Blog{}).Debug().CreateTable()
``` CREATE TABLE blog (
id BIGINT AUTO_INCREMENT,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
user_id BIGINT,
title VARCHAR(255),
content VARCHAR(255) ,
PRIMARY KEY(id)
);
// CREATE INDEX idx_blog_deletedat ON blog(deleted_at)
// CREATE INDEX idx_blog_userid ON blog(user_id)
// CREATE INDEX idx_blog_title ON blog(title)
#### drop table
```golang
var err error
_, err =toy.Model(&User{}).Debug().DropTable()
// DROP TABLE user
_, err =toy.Model(&UserDetail{}).Debug().DropTable()
// DROP TABLE user_detail
_, err =toy.Model(&Blog{}).Debug().DropTable()
// DROP TABLE blog
// insert with autoincrement will set id to source data
user := &User{
Name: "bigpigeon",
Age: 18,
Sex: "male",
}
_, err = toy.Model(&User{}).Debug().Insert(&user)
// INSERT INTO user(created_at,updated_at,name,age,sex) VALUES(?,?,?,?,?) , args:[]interface {}{time.Time{wall:0xbe8df5112e7f07c8, ext:210013499, loc:(*time.Location)(0x141af80)}, time.Time{wall:0xbe8df5112e7f1768, ext:210017044, loc:(*time.Location)(0x141af80)}, "bigpigeon", 18, "male"}
// print user format with json
/* {
"ID": 1,
"CreatedAt": "2018-01-11T20:47:00.780077+08:00",
"UpdatedAt": "2018-01-11T20:47:00.780081+08:00",
"DeletedAt": null,
"Name": "bigpigeon",
"Age": 18,
"Sex": "male",
"Detail": null,
"Friends": null,
"Blog": null
}*/
// save data use "REPLACE INTO" when primary key exist
users := []User{
{
ModelDefault: toyorm.ModelDefault{ID: 1},
Name: "bigpigeon",
Age: 18,
Sex: "male",
},
{
Name: "fatpigeon",
Age: 27,
Sex: "male",
},
}
_, err = toy.Model(&User{}).Debug().Save(&user)
// SELECT id,created_at FROM user WHERE id IN (?), args:[]interface {}{0x1}
// REPLACE INTO user(id,created_at,updated_at,name,age,sex) VALUES(?,?,?,?,?,?) , args:[]interface {}{0x1, time.Time{wall:0x0, ext:63651278036, loc:(*time.Location)(nil)}, time.Time{wall:0xbe8dfb5511465918, ext:302600558, loc:(*time.Location)(0x141af80)}, "bigpigeon", 18, "male"}
// INSERT INTO user(created_at,updated_at,name,age,sex) VALUES(?,?,?,?,?) , args:[]interface {}{time.Time{wall:0xbe8dfb551131b7d8, ext:301251230, loc:(*time.Location)(0x141af80)}, time.Time{wall:0xbe8dfb5511465918, ext:302600558, loc:(*time.Location)(0x141af80)}, "fatpigeon", 27, "male"}
toy.Model(&User{}).Debug().Update(&User{
Age: 4,
})
// UPDATE user SET updated_at=?,age=? WHERE deleted_at IS NULL, args:[]interface {}{time.Time{wall:0xbe8df4eb81b6c050, ext:233425327, loc:(*time.Location)(0x141af80)}, 4}
find one
var user User
_, err = toy.Model(&User{}).Debug().Find(&user}
// SELECT id,created_at,updated_at,deleted_at,name,age,sex FROM user WHERE deleted_at IS NULL LIMIT 1, args:[]interface {}(nil)
// print user format with json
/* {
"ID": 1,
"CreatedAt": "2018-01-11T12:47:01Z",
"UpdatedAt": "2018-01-11T12:47:01Z",
"DeletedAt": null,
"Name": "bigpigeon",
"Age": 4,
"Sex": "male",
"Detail": null,
"Friends": null,
"Blog": null
}*/
find multiple
var users []User
_, err = brick.Debug().Find(&users)
fmt.Printf("find users %s\n", JsonEncode(&users))
// SELECT id,created_at,updated_at,deleted_at,name,age,sex FROM user WHERE deleted_at IS NULL, args:[]interface {}(nil)
delete with primary key
_, err = brick.Debug().Delete(&user)
// UPDATE user SET deleted_at=? WHERE id IN (?), args:[]interface {}{(*time.Time)(0xc4200f0520), 0x1}
delete with condition
_, err = brick.Debug().Where(toyorm.ExprEqual, Offsetof(User{}.Name), "bigpigeon").DeleteWithConditions()
// UPDATE user SET deleted_at=? WHERE name = ?, args:[]interface {}{(*time.Time)(0xc4200dbfa0), "bigpigeon"}
use toy.Model will create a ToyBrick, you need use it to build grammar and operate the database brick.Where(, , [value])
whereGroup add multiple condition with same expr
*brick.WhereGroup(<expr>, <group>)*
Conditions will copy conditions and clean old conditions
*brick.Conditions(<toyorm.Search>)*
Or & and condition will use or/and to link new condition when current condition is not nil
*brick.Or().Condition(<expr>, <Key>, [value])*
*brick.Or().ConditionGroup(<expr>, <group>)*
*brick.And().Condition(<expr>, <Key>, [value])*
or & and conditions will use or/and to link new conditions
*brick.Or().Conditions(<toyorm.Search>)*
*brick.And().Conditions(<toyorm.Search>)*
SearchExpr | to sql | example |
---|---|---|
ExprAnd | AND | brick.WhereGroup(ExprAnd, Product{Name:"food one", Count: 4}) // WHERE name = "food one" AND Count = 4 |
ExprOr | OR | brick.WhereGroup(ExprOr, Product{Name:"food one", Count: 4}) // WHERE name = "food one" OR Count = "4" |
ExprEqual | = | brick.Where(ExprEqual, OffsetOf(Product{}.Name), "food one") // WHERE name = "find one" |
ExprNotEqual | <> | brick.Where(ExprNotEqual, OffsetOf(Product{}.Name), "food one") // WHERE name <> "find one" |
ExprGreater | > | brick.Where(ExprGreater, OffsetOf(Product{}.Count), 3) // WHERE count > 3 |
ExprGreaterEqual | >= | brick.Where(ExprGreaterEqual, OffsetOf(Product{}.Count), 3) // WHERE count >= 3 |
ExprLess | < | brick.Where(ExprLess, OffsetOf(Product{}.Count), 3) // WHERE count < 3 |
ExprLessEqual | <= | brick.Where(ExprLessEqual, OffsetOf(Product{}.Count), 3) // WHERE count <= 3 |
ExprBetween | Between | brick.Where(ExprBetween, OffsetOf(Product{}.Count), [2]int{2,3}) // WHERE count BETWEEN 2 AND 3 |
ExprNotBetween | NOT Between | brick.Where(ExprNotBetween, OffsetOf(Product{}.Count), [2]int{2,3}) // WHERE count NOT BETWEEN 2 AND 3 |
ExprIn | IN | brick.Where(ExprIn, OffsetOf(Product{}.Count), []int{1, 2, 3}) // WHERE count IN (1,2,3) |
ExprNotIn | NOT IN | brick.Where(ExprNotIn, OffsetOf(Product{}.Count), []int{1, 2, 3}) // WHERE count NOT IN (1,2,3) |
ExprLike | LIKE | brick.Where(ExprLike, OffsetOf(Product{}.Name), "one") // WHERE name LIKE "one" |
ExprNotLike | NOT LIKE | brick.Where(ExprNotLike, OffsetOf(Product{}.Name), "one") // WHERE name NOT LIKE "one" |
ExprNull | IS NULL | brick.Where(ExprNull, OffsetOf(Product{}.DeletedAt)) // WHERE DeletedAt IS NULL |
ExprNotNull | IS NOT NULL | brick.Where(ExprNotNull, OffsetOf(Product{}.DeletedAt)) // WHERE DeletedAt IS NOT NULL |
Single condition
brick = brick.Where(toyorm.ExprEqual, Offsetof(Product{}.Tag), "food")
// ИЛИ
brick = brick.Where("=", Offsetof(Product{}.Tag), "food")
// WHERE tag = "food"
Combination condition
brick = brick.Where(toyorm.ExprEqual, Offsetof(Product{}.Count), 2).And().
Condition(toyorm.ExprGreater, Offsetof(Product{}.Price), 3).Or().
Condition(toyorm.ExprEqual, Offsetof(Product{}.Count), 4)
// ИЛИ
brick = brick.Where("=", Offsetof(Product{}.Count), 2).And().
Condition(">", Offsetof(Product{}.Price), 3).Or().
Condition("=", Offsetof(Product{}.Count), 4)
// WHERE count = 2 and price > 3 or count = 4
Priority condition
brick.Where(toyorm.ExprGreater, Offsetof(Product{}.Price), 3).And().Conditions(
brick.Where(toyorm.ExprEqual, Offsetof(Product{}.Count), 2).Or().
Condition(toyorm.ExprEqual, Offsetof(Product{}.Count), 1).Search
)
// ИЛИ
brick.Where(">", Offsetof(Product{}.Price), 3).And().Conditions(
brick.Where("=", Offsetof(Product{}.Count), 2).Or().
Condition("=", Offsetof(Product{}.Count), 1).Search
)
// WHERE price > 3 and (count = 2 or count = 1)
``` **Пользовательский поиск**
```golang
var data Product
// если драйвер mysql, то использовать "USE INDEX" вместо "INDEXED BY"
result, err := brick.Template("SELECT $Columns FROM $ModelName INDEXED BY idx_product_name $Conditions").
Where("=", Offsetof(Product{}.Name), "bag").Find(&data)
// SELECT id,created_at,updated_at,deleted_at,name,price,count,tag FROM product INDEXED BY idx_product_name WHERE deleted_at IS NULL AND name = ? LIMIT 1 args:["bag"]
Пользовательское обновление
set count = count + 2
result, err := brick.Template(fmt.Sprintf("UPDATE $ModelName SET $Values,$FN-Count = $0x%x + ? $Conditions", Offsetof(Product{}.Count)), 2).
Where("=", Offsetof(Product{}.Name), "bag").Update(&Product{Price: 200})
// UPDATE product SET updated_at = ?,price = ?,count = count + ? WHERE deleted_at IS NULL AND name = ? args:["2018-04-01T17:50:35.205377+08:00",200,2,"bag"]
Заполнитель
Пример использования заполнителя в шаблоне:
Действие | Заполнитель | $ModelName | $Columns | $Values | $Conditions |
---|---|---|---|---|---|
Поиск | product | id,data,... | - | WHERE ... ORDER BY ... GROUP BY ... LIMIT ... OFFSET ... | |
Вставка | product | id,data,... | ?,?,... | WHERE ... ORDER BY ... GROUP BY ... LIMIT ... OFFSET ... | |
Сохранение | product | id,data,... | ?,?,... | WHERE ... ORDER BY ... GROUP BY ... LIMIT ... OFFSET ... | |
Обновление | product | id,data,... | id = ?,data = ?,... | WHERE ... ORDER BY ... GROUP BY ... LIMIT ... OFFSET ... |
Поточно-безопасный
Поточно-безопасен, если вы соблюдаете следующее соглашение:
Убедитесь, что объект ToyBrick доступен только для чтения. Если вы хотите изменить его, создайте новый.
Не используйте append для изменения данных среза ToyBrick, используйте make и copy для клонирования нового среза.
Предварительная загрузка
Предварительная загрузка требует наличия поля отношения и поля контейнера. Поле отношения используется для связи основной записи и дополнительной записи. Поле контейнера используется для хранения дополнительной записи.
Пример предварительной загрузки: здесь
Один к одному
Поле отношения находится в дополнительной модели. Имя поля отношения должно быть именем типа основной модели + имя первичного ключа основной модели.
type User struct {
toyorm.ModelDefault
// Поле контейнера
Detail *UserDetail
}
type UserDetail struct {
ID int `toyorm:"primary key;auto_increment"`
// Поле отношения
UserID uint `toyorm:"index"`
MainPage string `toyorm:"type:Text"`
}
// Загрузка предварительной загрузки
brick = toy.Model(&User{}).Debug().Preload(OffsetOf(User.Detail)).Enter()
Принадлежит
Поле отношения находится в основной модели. Имя поля отношения должно совпадать с именем поля контейнера дополнительной модели + первичный ключ дополнительной модели.
type User struct {
toyorm.ModelDefault
// Поле контейнера
Detail *UserDetail
// Поле отношения
DetailID int `toyorm:"index"`
}
type UserDetail struct {
ID int `toyorm:"primary key;auto_increment"`
MainPage string `toyorm:"type:Text"`
}
Один ко многим
Поле отношения находится в дополнительной модели. Имя поля отношения должно соответствовать типу основной модели + первичному ключу основной модели.
type User struct {
toyorm.ModelDefault
// Поле контейнера
Blog []Blog
}
type Blog struct {
toyorm.ModelDefault
// Поле отношения
UserID uint `toyorm:"index"`
Title string `toyorm:"index"`
Content string
}
Многие ко многим
Для многих ко многим не нужно указывать связь, она находится в средней модели. ```
stick").
Join(Offsetof(tab.Detail)).
Join(Offsetof(detailTab.ColorJoin)).Or().Condition("=", Offsetof(colorTab.Name), "black").
Swap().Swap()
var scanData []Product
result, err = brick.Find(&scanData)
// SELECT m.id,m.created_at,m.deleted_at,m.name,m.count,m.price,m_0.product_id,m_0.title,m_0.custom_page,m_0.extra,m_0.color,m_0_0.name,m_0_0.code FROM product
as `m` JOIN `product_detail` AS `m_0` ON m.id = m_0.product_id JOIN `color` AS `m_0_0` ON m_0.color = m_0_0.name WHERE m.deleted_at IS NULL AND (m.name = ? OR m_0_0.name = ?) args:["clean stick","black"]
brick := toy.Model(&tab).Debug().
Join(Offsetof(tab.Detail)).
Join(Offsetof(detailTab.ColorJoin)).OrderBy(Offsetof(colorTab.Name)).
Swap().Swap()
var scanData []Product
result, err = brick.Find(&scanData)
// SELECT m.id,m.created_at,m.deleted_at,m.name,m.count,m.price,m_0.product_id,m_0.title,m_0.custom_page,m_0.extra,m_0.color,m_0_0.name,m_0_0.code FROM product
as m
JOIN product_detail
AS m_0
ON m.id = m_0.product_id JOIN color
AS m_0_0
ON m_0.color = m_0_0.name WHERE m.deleted_at IS NULL ORDER BY m_0_0.name
Также может быть установлен GroupBy, но здесь не приводится пример.
**Предварительная загрузка при объединении**
Метод предварительной загрузки также работает в режиме объединения.
```golang
brick := toy.Model(&tab).Debug().
Join(Offsetof(tab.Detail)).Preload(Offsetof(detailTab.Comment)).Enter().
Join(Offsetof(detailTab.ColorJoin)).Swap().Swap()
var scanData []Product
result, err = brick.Find(&scanData)
// SELECT m.id,m.created_at,m.deleted_at,m.name,m.count,m.price,m_0.product_id,m_0.title,m_0.custom_page,m_0.extra,m_0.color,m_0_0.name,m_0_0.code FROM `product` as `m` JOIN `product_detail` AS `m_0` ON m.id = m_0.product_id JOIN `color` AS `m_0_0` ON m_0.color = m_0_0.name WHERE m.deleted_at IS NULL
// SELECT id,created_at,updated_at,deleted_at,product_detail_product_id,data FROM `comment` WHERE deleted_at IS NULL AND product_detail_product_id IN (?,?,?) args:[1,2,3]
Можно настроить собственное имя таблицы для разных платформ.
type User struct {
ID uint32 `toyorm:"primary key"`
Name string `toyorm:"index"`
Platform string `toyorm:"-"`
}
func (u *User) TableName() string {
return "user_" + u.Platform
}
brick := toy.Model(&User{Platform:"p1"}).Debug()
brick.CreateTable()
// CREATE TABLE user_p1 (id BIGINT AUTO_INCREMENT,name VARCHAR(255), PRIMARY KEY(id))
brick := toy.Model(&User{Platform:"p2"}).Debug()
brick.CreateTable()
// CREATE TABLE user_p2 (id BIGINT AUTO_INCREMENT,name VARCHAR(255), PRIMARY KEY(id))
Метод имени таблицы также работает при предварительной загрузке и объединении.
type UserDetail struct {
ID uint32 `toyorm:"primary key"`
UserID uint32
Data string
}
func (u *UserDetail) TableName() string {
return "user_detail_" + u.Platform
}
type User struct {
ID uint32 `toyorm:"primary key"`
Name string `toyorm:"index"`
Detail *UserDetail
Platform string `toyorm:"-"`
}
func (u *User) TableName() string {
return "user_" + u.Platform
}
brick := toy.Model(&User{Platform:"p1", Detail:&UserDetail{Platform:"p1"}}).Debug().
Preload(Offsetof(User{}.UserDetail)).Enter()
brick.CreateTable()
// CREATE TABLE user_p1 (id BIGINT AUTO_INCREMENT,name VARCHAR(255), PRIMARY KEY(id))
// CREATE TABLE user_detail_p1 (id BIGINT AUTO_INCREMEHT, user_id BIGINT, data VARCHAR(255), PRIMARY KEY(id))
В режиме «один ко многим» или «многие ко многим» необходимо установить значение первого элемента. use Report to view sql action
report format
insert
user := User{
Detail: &UserDetail{
MainPage: "some html code with you page",
Extra: Extra{"title": "my blog"},
},
Blog: []Blog{
{Title: "how to write a blog", Content: "first ..."},
{Title: "blog introduction", Content: "..."},
},
Friends: []*User{
{
Detail: &UserDetail{
MainPage: "some html code with you page",
Extra: Extra{},
},
Blog: []Blog{
{Title: "some python tech", Content: "first ..."},
{Title: "my eleme_union_meal usage", Content: "..."},
},
Name: "fatpigeon",
Age: 18,
Sex: "male",
},
},
Name: "bigpigeon",
Age: 18,
Sex: "male",
}
result, err = brick.Save(&user)
// error process ...
fmt.Printf("report:\n%s\n", result.Report())
/*
// [0, ] means affected the 0 element
// [0-0, ] means affected the 0 element the 0 sub element
report:
[0, ] INSERT INTO user(created_at,updated_at,deleted_at,name,age,sex) VALUES(?,?,?,?,?,?) args:["2018-02-28T17:31:20.012285+08:00","2018-02-28T17:31:20.012285+08:00",null,"bigpigeon",18,"male"]
preload Detail
[0-, ] INSERT INTO user_detail(user_id,main_page,extra) VALUES(?,?,?) args:[1,"some html code with you page",{"title":"my blog"}]
preload Blog
[0-0, ] INSERT INTO blog(created_at,updated_at,deleted_at,user_id,title,content) VALUES(?,?,?,?,?,?) args:["2018-02-28T17:31:20.013968+08:00","2018-02-28T17:31:20.013968+08:00",null,1,"how to write a blog","first ..."]
[0-1, ] INSERT INTO blog(created_at,updated_at,deleted_at,user_id,title,content) VALUES(?,?,?,?,?,?) args:["2018-02-28T17:31:20.013968+08:00","2018-02-28T17:31:20.013968+08:00",null,1,"blog introduction","..."]
preload Friends
[0-0, ] INSERT INTO user(created_at,updated_at,deleted_at,name,age,sex) VALUES(?,?,?,?,?,?) args:["2018-02-28T17:31:20.015207+08:00","2018-02-28T17:31:20.015207+08:00",null,"fatpigeon",18,"male"]
preload Detail
[0-0-, ] INSERT INTO user_detail(user_id,main_page,extra) VALUES(?,?,?) args:[2,"some html code with you page",{}]
preload Blog
[0-0-0, ] INSERT INTO blog(created_at,updated_at,deleted_at,user_id,title,content) VALUES(?,?,?,?,?,?) args:["2018-02-28T17:31:20.016389+08:00","2018-02-28T17:31:20.016389+08:00",null,2,"some python tech","first ..."]
[0-0-1, ] INSERT INTO blog(created_at,updated_at,deleted_at,user_id,title,content) VALUES(?,?,?,?,?,?) args:["2018-02-28T17:31:20.016389+08:00","2018-02-28T17:31:20.016389+08:00",null,2,"my eleme_union_meal usage","..."]
*/
find
```golang
brick := brick.Preload(Offsetof(User{}.Friends)).
Preload(Offsetof(User{}.Detail)).Enter().
Preload(Offsetof(User{}.Blog)).Enter().
Enter()
var users []User
result, err = brick.Find(&users)
// some error process
...
// print the report
fmt.Printf("report:\n%s\n", result.Report())
// report log
/*
report:
[0, 1, ] SELECT id,created_at,updated_at,deleted_at,name,age,sex FROM user WHERE deleted_at IS NULL args:null
preload Detail
[0-, 1-, ] SELECT id,user_id,main_page,extra FROM user_detail WHERE user_id IN (?,?) args:[2,1]
preload Blog
[0-0, 0-1, 1-0, 1-1, ] SELECT id,created_at,updated_at,deleted_at,user_id,title,content FROM blog WHERE deleted_at IS NULL AND user_id IN (?,?) args:[1,2]
preload Friends
[0-0, ] SELECT id,created_at,updated_at,deleted_at,name,age,sex FROM user WHERE deleted_at IS NULL AND id IN (?) args:[2]
preload Detail
[0-0-, ] SELECT id,user_id,main_page,extra FROM user_detail WHERE user_id IN (?) args:[2]
preload Blog
[0-0-0, 0-0-1, ] SELECT
* * *
В запросе представлен фрагмент кода на языке Go, который выполняет операции с данными модели пользователя и его друзей. В коде используются структуры данных для представления информации о пользователе, его друзьях, деталях и блогах. Также в коде выполняется сохранение данных в базу данных и их извлечение.
Однако, без контекста сложно понять, что именно делает этот код. Возможно, он создаёт или обновляет записи в базе данных, связанные с пользователями и их друзьями. Или же он просто выводит информацию о существующих записях.
Для более точного понимания того, что делает этот код, необходимо знать контекст его использования и цели, которые он преследует. **use Err to view sql action error**
```golang
var users []struct {
ID uint32
Age bool
Detail *UserDetail
Blog []Blog
}
result, err = brick.Find(&users)
if err != nil {
panic(err)
}
if err := result.Err(); err != nil {
fmt.Printf("error:\n%s\n", err)
}
/*
error:
SELECT id,age FROM user WHERE deleted_at IS NULL args:null errors(
[0]sql: Scan error on column index 1: sql/driver: couldn't convert "18" into type bool
[1]sql: Scan error on column index 1: sql/driver: couldn't convert "18" into тип bool
)
*/
Selector
toyorm поддерживает следующий селектор:
Операция | Селектор | OffsetOf | Имя строки | map[OffsetOf]interface{} | map[string]interface{} | struct |
---|---|---|---|---|---|---|
Update | Нет | Нет | Да | Да | Да | Да |
Insert | Нет | Нет | Да | Да | Да | Да |
Save | Нет | Нет | Да | Да | Да | Да |
Where & Conditions | Да | Да | Нет | Нет | Нет | Нет |
WhereGroup & ConditionGroup | Нет | Нет | Да | Да | Нет | Нет |
BindFields | Да | Да | Нет | Нет | Нет | Нет |
Preload & Custom Preload | Да | Да | Нет | Нет | Нет | Нет |
OrderBy | Да | Да | Нет | Нет | Нет | Нет |
Find | Нет | Нет | Нет | Нет | Нет | Да |
Коллекция предоставляет множество операций с базой данных.
ToyCollection — это основа коллекции, она похожа на Toy.
toyCollection, err = toyorm.OpenCollection("sqlite3", []string{"", ""}...)
CollectionBrick используется для создания грамматики и управления базой данных, как ToyBrick.
brick := toyCollection.Model(&User{})
Селектор используется для выбора базы данных при вставке/сохранении.
CollectionBrick имеет стандартный селектор dbPrimaryKeySelector.
Вы можете настроить селектор БД.
func idSelector(n int, keys ...interface{}) int {
sum := 0
for _, k := range keys {
switch val := k.(type) {
case int:
sum += val
case int32:
sum += int(val)
case uint:
sum += int(val)
case uint32:
sum += int(val)
default:
panic("primary key type not match")
}
}
return sum % n
}
brick = brick.Selector(idSelector)
В этом режиме тег поля auto_increment был недействителен.
Вам нужно создать генератор идентификаторов.
// контекстный генератор идентификаторов
type IDGenerator map[*toyorm.Model]chan int
func (g IDGenerator) CollectionIDGenerate(ctx *toyorm.CollectionContext) error {
if g[ctx.Brick.Model] == nil {
idGenerate := make(chan int)
go func() {
current := 1
for {
// если есть redis, используйте redis-cli
idGenerate <- current
current++
}
}()
g[ctx.Brick.Model] = idGenerate
}
primaryKey := ctx.Brick.Model.GetOnePrimary()
for _, record := range ctx.Result.Records.GetRecords() {
if field := record.Field(primaryKey.Name()); field.IsValid() == false || toyorm.IsZero(field) {
v := <-g[ctx.Brick.Model]
record.SetField(primaryKey.Name(), reflect.ValueOf(v))
}
}
return nil
}
// установить генератор идентификатора в контексте модели
toy.SetModelHandlers("Save", brick.Model,
``` ```
toyorm.CollectionHandlersChain{idGenerate.CollectionIDGenerate})
// Устанавливаем генератор идентификаторов для всех моделей в контексте предварительной загрузки
for _, pBrick := range brick.MapPreloadBrick {
toy.SetModelHandlers("Save", pBrick.Model, toyorm.CollectionHandlersChain{idGenerate.CollectionIDGenerate})
}
SQL-действия с коллекцией Toy аналогичны действиям Toy.
Вставка:
users := []User{
{Name: "Turing"},
{Name: "Shannon"},
{Name: "Ritchie"},
{Name: "Jobs"},
}
result, err = userBrick.Insert(&users)
// Обработка ошибки
// Просмотр журнала отчётов
fmt.Printf("report:\n%s", result.Report())
Поиск:
var jobs User
result, err = userBrick.Where(toyorm.ExprEqual, Offsetof(User{}.Name), "Jobs").Find(&jobs)
// Обработка ошибки
// Просмотр журнала отчётов
fmt.Printf("report:\n%s", result.Report())
Удаление:
result, err = userBrick.Delete(&jobs)
// Обработка ошибки
// Просмотр журнала отчётов
fmt.Printf("delete report:\n%s\n", result.Report())
Проверка параметров в вызове метода ToyBrick
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )