Skip to content

Latest commit

 

History

History
256 lines (218 loc) · 9.61 KB

File metadata and controls

256 lines (218 loc) · 9.61 KB

5.5 Desarrollo de un ORM basado en beedb

( 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

Instalación

Puedes usar el comando go get para instalar beedb localmente.

	go get github.com/astaxie/beedb

Inicialización

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.

Insertar datos

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.

Actualizar datos

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 que uid es la llave primaria del registro en la tabla userinfo
  • .Where() define condiciones y suporta múltiples argumentos. Si el primer arguento es un entero, es una manera de acortar Where("<llave primaria>=?", <valor>).
  • .Update() acepta un mapa y actualiza la base de datos.

Consultado 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.

Eliminar datos

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()

Consultas de asociación

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

Group By y Having

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 del having.

Futuro

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.

Enlaces