go>> dali>> 返回
项目作者: mibk

项目描述 :
a thin layer over Go's database/sql
高级语言: Go
项目地址: git://github.com/mibk/dali.git
创建时间: 2015-10-21T18:49:36Z
项目社区:https://github.com/mibk/dali

开源协议:MIT License

下载


DALí Logo
GoDoc
Build Status

Database Abstraction Layer (í)

DALí is not exactly a database abstration layer. It doesn’t try to abstract the SQL in a way
that the queries could run unchanged on any supported database. It rather abstracts
just the placeholder manipulation and provides convenient ways for some common situations.

The main goal of this project is to provide a clean, compact API for communication with
SQL databases.

Quickstart

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "time"
  6. _ "github.com/go-sql-driver/mysql"
  7. "github.com/mibk/dali"
  8. )
  9. func main() {
  10. db, err := dali.Open("mysql", "root@/example?parseTime=true")
  11. if err != nil {
  12. log.Fatal(err)
  13. }
  14. q := db.Query(`INSERT INTO [group] ?values`, dali.Map{"name": "admins"})
  15. groupID, err := dali.LastInsertID(q.Exec())
  16. if err != nil {
  17. log.Fatal(err)
  18. }
  19. // INSERT INTO `group` (`name`) VALUES ('admins')
  20. users := []User{
  21. {0, "Peter", "peter@foo.com", groupID, time.Now()},
  22. {0, "Nick", "nick@bar.org", groupID, time.Now()},
  23. }
  24. _, err = db.Query(`INSERT INTO [user] ?values...`, users).Exec()
  25. if err != nil {
  26. log.Fatal(err)
  27. }
  28. // ?values... expands a slice of struct into multi insert
  29. // INSERT INTO `user` (`name`, `email`, `group_id`, `created`) VALUES
  30. // ('Peter', 'peter@foo.com', 1, '2015-11-20 13:59:59'),
  31. // ('Nick', 'nick@bar.org', 1, '2015-11-20 13:59:59')
  32. var u User
  33. q = db.Query(`SELECT * FROM ?ident WHERE group_id IN (?...) LIMIT 1`,
  34. "user", []int{1, 2, 5})
  35. fmt.Println(q) // dali.Query implements fmt.Stringer. It prints:
  36. // SELECT * FROM `user` WHERE group_id IN (1, 2, 5) LIMIT 1
  37. if err := q.One(&u); err != nil {
  38. log.Fatal(err)
  39. }
  40. fmt.Println(u)
  41. u.Email = "peter@foo.net"
  42. u.GroupID = 2
  43. _, err = db.Query(`UPDATE [user] ?set WHERE [id] = ?`,
  44. dali.Map{
  45. "email": u.Email,
  46. "group_id": u.GroupID,
  47. }, 1).Exec()
  48. if err != nil {
  49. log.Fatal(err)
  50. }
  51. // UPDATE `user` SET `email` = 'peter@foo.net', `group_id` = 2
  52. // WHERE `id` = 1
  53. }
  54. type User struct {
  55. ID int64 `db:",selectonly"` // omitted on INSERT, UPDATE, etc.
  56. Name string `db:"name"`
  57. Email string `db:"email"`
  58. GroupID int64 `db:"group_id"`
  59. Registered time.Time `db:"created"`
  60. }

Instalation

  1. $ go get github.com/mibk/dali

Caveats

DALí processes the query unaware of the actual SQL syntax. This means it is quite stupid
on deciding whether the placeholder is inside a string literal.

  1. conn.Query(`SELECT * FROM foo WHERE name = 'really?'`)
  2. // This will return an error because it would try to replace the `?` with an argument
  3. // that is missing.

To avoid this just use the whole string as a parameter.

  1. conn.Query(`SELECT * FROM foo WHERE name = ?`, "really?")

Features

Identifier escaping

This feature comes from the need to fix the clumsy way of escaping identifiers in MySQL in
Go’s raw string literals. So instead of

  1. sql := `SELECT `+"`where`"+`
  2. FROM location`

you can use

  1. sql := `SELECT [where]
  2. FROM location

So there is one way to escape identifiers among all dialects.

Handy placeholders

Again, placeholder manipulation is the same for all dialects and besides that it also provides
some additional placeholders. The complete list is:

  1. ? primitive value or a value implementing driver.Valuer
  2. ?... a slice of values which is going to be expanded (especially useful in
  3. IN clauses)
  4. ?values expects either Map, or a struct as an argument. It derives column names
  5. from map keys or struct fields and constructs a VALUES clause (e.g.
  6. INSERT INTO user ?values)
  7. ?set similar to ?values but used for SET clauses (e.g. UPDATE user SET ?set)
  8. ?values... expects a slice of structs as an argument which is expanded into multi
  9. INSERT clause
  10. ?ident used for identifiers (column or table name)
  11. ?ident... expands identifiers and separates them with a comma
  12. ?sql inserts the parameter, a string or Marshaler, as is (meant for SQL parts)

Using the placeholders it is easy and quite expressive to write common SQL queries, but it is
also possible to adjust these queries to a specific need (which is often not so easy when using
query builders).

Note: only ?, ?ident, ?ident..., and ?sql are allowed in prepared statements (see the
method Prepare for more information).

Profiling and other

Using the DB.SetMiddlewareFunc it is
possible to do additional operations before and after execution of every query. This example
logs every executed query:

  1. var db *dali.DB // init db...
  2. func init() {
  3. db.SetMiddlewareFunc(profile)
  4. }
  5. func profile(e dali.Execer) dali.Execer {
  6. return profiler{e}
  7. }
  8. type profiler struct {
  9. ex dali.Execer
  10. }
  11. func (p profiler) Exec(query string, args ...interface{}) (sql.Result, error) {
  12. log.Println(query, args)
  13. return p.ex.Exec(query, args...)
  14. }
  15. func (p profiler) Query(query string, args ...interface{}) (*sql.Rows, error) {
  16. log.Println(query, args)
  17. return p.ex.Query(query, args...)
  18. }
  19. func (p profiler) QueryRow(query string, args ...interface{}) *sql.Row {
  20. log.Println(query, args)
  21. return p.ex.QueryRow(query, args...)
  22. }

Faster performance

DALí interpolates all parameters before it gets to the database which has a huge performance
benefit. This behaviour is taken from the gocraft/dbr library. See
this
for more information.

Supported dialects

Currently, only a MySQL dialect is implemented directly in this package (see dialects
for more information). Nevertheless, supporting another dialect should be as easy as creating
a new dialect implementing dialects.Dialect interface. The most common dialects will be
implemented directly in the future.

Thanks

Ideas for building this library come mainly from these sources:

License

DALí is distributed under the MIT license found in the LICENSE file.