( El proyecto beedb no está mantenido actualmente, pero el código sigue ahí ) ( Project beedb is no longer maintained, but the code s still there )
beedb es un ORM ( object relational mapper ) desarrollado en Go, por mi. Usa el lenguaje ideomático de Go para operar con las bases de datos, implementando un mapeo de estructura a base de datos que actua como un Framework ORM liviano de Go. El propósito de desarrollar este ORM no es solamente ayudar a la gente a aprender como implementar un ORM, sino también encontrar un buen balance entre funcionalidad y desempeño en lo que respecta a persistencia de datos.
beedb es un proyecto de código abierto que soporta la funcionalidad básica de un ORM, pero no soporta las consultas asociativas.
Como beedb soporta los estándares de la interfaz database/sql
cualquier manejador que implemente esta interfaz podrá ser usado con beedb. Yo lo he probado con los siguientes manejadores:
Mysql: github.com/ziutek/mymysql/godrv
Mysql: github/go-mysql-driver/mysql
PostgreSQL: github.com/lib/pq
SQLite: github.com/mattn/go-sqlite3
MS ADODB: github.com/mattn/go-adodb
ODBC: bitbucket.org/miquella/mgodbc
Puedes usar el comando go get
para instalar beedb localmente.
go get github.com/astaxie/beedb
Primero debes importar los paquetes necesarios:
import (
"database/sql"
"github.com/astaxie/beedb"
_ "github.com/ziutek/mymysql/godrv"
)
Luego necesitas abrir la conexión a la base de datos y crear un objeto beedb (MySQL en este ejemplo):
db, err := sql.Open("mymysql", "test/xiemengjun/123456")
if err != nil {
panic(err)
}
orm := beedb.New(db)
beedb.New()
actualmente toma dos argumentos. El primero es el objeto de la base de datos y el segundo es para indicar que motor de base de datos estás usando. Si estás usando MySQL o SQLite puedes omitir el segundo argumento.
De otra manera, este argumento debe ser incluido, por ejemplo en el caso de SQLServer:
orm = beedb.New(db, "mssql")
PostgreSQL:
orm = beedb.New(db, "pg")
beedb soporta depuración. Usa el siguiente código para habilitarla:
beedb.OnDebug=true
Después debemos tener una estructura para la tabla Userinfo
que hemos usado en las secciones anteriores.
type Userinfo struct {
Uid int `PK` // Si la llave primaria no es id, necesitas añadir la etiqueta `PK` para una llave primaria personalizada.
Username string
Departname string
Created time.Time
}
Se conciente que beedb autoconvierte la notación de camello a notación de guiones bajos. Por ejemplo, si tenemos UserInfo
como el nombre de la estructura, beedb lo convertirá a user_info
en la base de datos. La misma regla se aplica para los nombres de campos de la estructura.
El siguiente ejemplo muestra como usar beedb a guardar una estructura en vez de usar comandos planos de SQL. Usamos el método Save
de beedb para aplicar el cambio.
var saveone Userinfo
saveone.Username = "Test Add User"
saveone.Departname = "Test Add Departname"
saveone.Created = time.Now()
orm.Save(&saveone)
Puedes verificar el campo saveone.Uid
después de que este registro es insertado; su valor es un identificador autoincrementado por el que el método Save
se ocupa por ti.
beedb provee otra manera de insertar datos, usando el estilo de mapas de Go.
add := make(map[string]interface{})
add["username"] = "astaxie"
add["departname"] = "cloud develop"
add["created"] = "2012-12-02"
orm.SetTable("userinfo").Insert(add)
Insertando varios datos:
addslice := make([]map[string]interface{}, 10)
add:=make(map[string]interface{})
add2:=make(map[string]interface{})
add["username"] = "astaxie"
add["departname"] = "cloud develop"
add["created"] = "2012-12-02"
add2["username"] = "astaxie2"
add2["departname"] = "cloud develop2"
add2["created"] = "2012-12-02"
addslice = append(addslice, add, add2)
orm.SetTable("userinfo").InsertBatch(addslice)
El método mostrado arriba es similar a una consulta encadenada, la cual te podría ser familiar si has usado jQuery. Retorna el objeto del ORM después de la llamada, entonces continua haciendo otros trabajos.
El método SetTable
le dice al ORM que queremos insertar nuestra data en la tabla userinfo
.
Continuemos trabajando con el ejemplo de arriba, para ver como actualizar los datos. Ahora que tenemos la llave primeria de saveone(Uid)
, beedb ejecuta una operación de actualizacieon en lugar de insertar un nuevo registro.
saveone.Username = "Update Username"
saveone.Departname = "Update Departname"
saveone.Created = time.Now()
orm.Save(&saveone) // update
Como antes, también puedes usar un mapa para actualizar los datos:
t := make(map[string]interface{})
t["username"] = "astaxie"
orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)
Permíteme explicar algunos de los métodos usados arriba:
.SetPK()
le dice al ORM queuid
es la llave primaria del registro en la tablauserinfo
.Where()
define condiciones y suporta múltiples argumentos. Si el primer arguento es un entero, es una manera de acortarWhere("<llave primaria>=?", <valor>)
..Update()
acepta un mapa y actualiza la base de datos.
Las consultas con la interface beedb son muy fleibles. Veamos algunos ejemplos:
Ejemplo 1: Consultando por llaves primarias:
var user Userinfo
// Where acepta dos argumentos, el segundo entero
orm.Where("uid=?", 27).Find(&user)
Ejemplo 2:
var user2 Userinfo
orm.Where(3).Find(&user2) // Forma corta que omite el nombre de la llave primaria
Ejemplo 3, otras condiciones de consulta
var user3 Userinfo
// Where acepta dos argumentos, el segundo cadena
orm.Where("name = ?", "john").Find(&user3)
Ejemplo 4, condiciones mas complicadas:
var user4 Userinfo
// Where con tres argumentos aceptados
orm.Where("name = ? and age < ?", "john", 88).Find(&user4)
Ejemplos para obtener múltiples registros
Ejemplo 1, Obtiene 10 registros donde id>3
Que comienzan en la posición 20
var allusers []Userinfo
err := orm.Where("id > ?", "3").Limit(10,20).FindAll(&allusers)
Ejemplo 2, omite el segundo argumento de límite, entonces comienza en 0 y obtiene 10 registros:
var tenusers []Userinfo
err := orm.Where("id > ?", "3").Limit(10).FindAll(&tenusers)
Ejemplo 3, obtener todos los recursos:
var everyone []Userinfo
err := orm.OrderBy("uid desc,username asc").FindAll(&everyone)
Como puedes ver, el método límite es para limitar el número de resultados.
.Limit()
suporta dos argumentos: el número de resultados comenzando en la posición. 0 es el valor por defecto de posición inicial..OrderBy()
es para ordenar resultados. El argumento es la condición de orden.
Todos los ejemplos aquí simplemente mapean registros a estructuras. También puedes colocar data en un mapa como sigue:
a, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap()
.Select()
le dice a beedb cuantos campos quieres obtener desde la tabla de la base de datos. Si no es especifica, todos los registros son retornados por defecto..FindMap()
retorna el tipo[]map[String][]byte
, entonces puedes convertir a otros tipos tu mismo.
beedb provee métodos amplios para eliminar datos.
Ejemplo 1, eliminar un único registro
// saveone es el mismo del ejemplo anterior.
orm.Delete(&saveone)
Ejemplo 2, elimintar todos los usuarios
// alluser es un segmento que tiene múltiples usuarios
orm.DeleteAll(&alluser)
Ejemplo 3, Eliminar registros con SQL
orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow()
beedb no soportar uniones entre asociaciones. Sin embargo, desde que algunas aplicaciones necesitan esta caractarísticas, aquí está una implementación:
a, _ := orm.SetTable("userinfo").Join("LEFT", "userdetail", "userinfo.uid=userdetail.uid")
.Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdetail.profile").FindMap()
Nosotros vemos un método llamado .Join()
que toma tres argumentos
- El primer argumento: Tipo del Join; INNER, LEFT, OUTER, CROSS, etc.
- El segundo argumento: la tabla con la que quieres hacer la unión
- El tercer argumento: la condición de Join
beedb también tiene una implementación de group by
y having
.
a, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='astaxie'").FindMap()
.GroupBy()
indica el campo con el que se va a agrupar..Having()
indica la condición delhaving
.
He recibido un montón de retroalimentación de beedb de muchas personas al rededor del mundo y estoy pensando en reconfigurar los siguientes aspectos:
-
Implementar una interfaz similar a
database/sql/driver
en orden de facilitar las operaciones CRUD -
Implementar asociaciones de bases de datos relacionales como uno a uno, muchos a uno y muchos a muchos.
Aquí hay un ejemplo:
type Profile struct { Nickname string Mobile string } type Userinfo struct { Uid int PK_Username string Departname string Created time.Time Profile HasOne }
-
Auto crear tablas e indices.
-
Implementar una piscina de conexiones usando rutinas.
- Índice
- Sección previa: PostgreSQL
- Siguiente sección section: Bases de Datos NoSQL