Yo soy el autor!!!
Qué es HDO?
Es una librería para acceder a cualquier base de datos.
En la actualidad están disponibles las siguientes (RDL):
- SQLite/SQLCipher
- MySQL/MariaDB estándar y nativa.
-
ODBC/MS SQLServer estándar y nativa. (Con esta se puede acceder a todas las bases de datos que dispongan de drivers)
En proyecto:
- PostgreSQL
- Firebird
Características:
- Escrita 100% en Lenguaje C (Robustez y velocidad)
- Sentencias preparadas en el lado del servidor. (Seguridad y velocidad, evita código inyectado, las tramas enviadas por la red son más pequeñas y en formato binario)
- Compatibilidad entre RDLs gestores de bases de datos ( un programa diferentes bases de datos )
- Funcionan en cualquier sistema: modo texto, FWH, -, miniGUI, etc
- HDOTools que tiene muchas utilidades: RDD, ORM, TTable etc.
Ejemplos:
- Code: Select all Expand view
//-----------------------------------------------------------------------------
// Proyecto: HDO lib
// Fichero: tutor01.prg
// Descripcion: (THDO) Muestra la manera de conectarse a una base de datos
// Autor: Manu Exposito 2014-21
// Fecha: 05/02/2021
// Notas: El control de errores se hace manualmente
//-----------------------------------------------------------------------------
REQUEST RDLMYSQLN // Importante: solicitud para enlazar la RDL usada
//------------------------------------------------------------------------------
procedure main
local oCon // Objeto conexion
// Crea el objeto conexion con una base de datos MySQL usando su RDL
// Tiene que estar en sintonia con el REQUEST
oCon := THDO():new( "mysqln" )
// Intentamos establecer la conexion usando los parametros correspondientes
if oCon:connect( "hdodemo", "127.0.0.1", "hdouser", "hdo" )
Alert( ";Se ha establecido la conexion;;Base de datos: " + oCon:getDbName() )
else
Alert( "No se ha podido;establecer;la conexion" )
endif
oCon:free() // Para terminar hay que liberar recursos
Alert( "Fin" )
return
//------------------------------------------------------------------------------
Otro con RDD:
- Code: Select all Expand view
/*
* Proyecto: hdo_general
* Fichero: tutor38.prg
* Descripcion: Uso de RDD
* Autor: Manu
* Fecha: 05/02/2021
*/
#include "hdo.ch"
//REQUEST HDO // Para el RDD de HDO
REQUEST RDLMYSQLN
procedure main
local n, e
local oHDO := THDO():new( HDO_RDL_MYSQL_NATIVE )
try
cls
oHDO:connect( "hdodemo", "127.0.0.1", "hdouser", "hdo" )
// Asigna objeto conexion por defecto para los USE y DbDreate sin OHDO
HDORDD_DefaultConnect( oHDO )
@ 10, 10 SAY "ESPERE: Cargando datos..."
n := Seconds()
// Abro las dos tablas
USE test ALIAS test NEW VIA "HDO"
Alert( "Tiempo para cargar tabla: " + HB_NToS( Seconds() - n ) )
cls
// Miro el contenido de las dos tablas con el browse estandar
Browse()
catch e
eval( errorBlock(), e )
finally
CLOSE test
// No olvidad cerra la conexion
oHDO:free()
Alert( "Se termino" )
end
return
Otro con ORM:
- Code: Select all Expand view
/*
* Proyecto: hdo HDO_ORM
* Fichero: tutor35.prg
* Descripción: Demo ORM
* Autor: Manu Exposito 2014-21
* Fecha: 05/02/2021
*/
//------------------------------------------------------------------------------
REQUEST RDLMARIADB // Importante: solicitud para enlazar la RDL usada
//------------------------------------------------------------------------------
#include "hdo.ch"
//------------------------------------------------------------------------------
//==============================================================================
// Definicion de la clase modelo de la tabla test, seguramente estara en un fichero aparte
// junto a todas las clase modelo de tablas.
// Para esto haré un programa que lo cree automaticamente a partir de la tabla
//---------------------------
// TODO -> Crear un metodo ::createTableFromModel()
HDOMODEL Test
PROTECTED:
CLASSVAR cTableName INIT "test"
CLASSVAR cIdName INIT "id"
EXPORTED:
DATACOLUMN id TYPE AUTOINC
DATACOLUMN first TYPE CHARACTER LEN 20
DATACOLUMN last TYPE CHARACTER LEN 20
DATACOLUMN street TYPE CHARACTER LEN 30
DATACOLUMN city TYPE CHARACTER LEN 30
DATACOLUMN state TYPE CHARACTER LEN 2
DATACOLUMN zip TYPE CHARACTER LEN 20
DATACOLUMN hiredate TYPE DATE
DATACOLUMN married TYPE BOOL
DATACOLUMN age TYPE INTEGER LEN 11
DATACOLUMN salary TYPE REAL LEN 9 DEC 2
DATACOLUMN notes TYPE CHARACTER LEN 70
CALCCOLUMN salarioDoble IS (::salary * 2)
CALCCOLUMN diasVividos IS Date() - ::hiredate
END HDOMODEL Test
//==============================================================================
procedure main
local oCon, oModel, e, h , i, oCollection
oCon := THDO():new( HDO_RDL_MARIADB )
try
oCon:connect( "hdodemo", "127.0.0.1", "hdouser", "hdo" )
// Asigno el objeto conexion a la clase Test() (ojo no al objeto concreto si no a la clase)
Test( oCon ) //:init( oCon ) //, "Test", "id" )
// Así también se podría hacer
//Test():init( oCon ) //, "Test", "id" )
// O asi
// Test():setConnection( oCon )
// Creacion de un modelo con el id == 1
oModel := Test():find( 9 )
muestra( oModel:toHash(), "Visto como hash" )
muestra( oModel:toArray(), "Visto como array" )
msg( oModel:salarioDoble, "Prueba de campo calculado" )
msg( oModel:diasVividos, "Dias de vida" )
// Creacion de otro modelo con el id == 10 usando la misma variable
oModel := Test():find( 101 )
muestra( oModel:toHash() )
// Jugando con la funcion de clase (como una clase estatica)
muestra( Test():select( "id, last, first" ):find( 20 ):toJSon() )
cls
? "--------------------------------------------------------------------"
? "Identificador (ID): ", oModel:id
? "--------------------------------------------------------------------"
?
? oModel:first
? oModel:last
? oModel:street
? oModel:city
? oModel:state
? oModel:zip
? oModel:hiredate
? oModel:married
? oModel:age
? oModel:salary
? oModel:notes
?
? "--------------------------------------------------------------------"
? "--------------------------------[ Presiona una tecla para seguir ]--"
? "--------------------------------------------------------------------"
Inkey( 100 )
cls
//-------------------------------------------
// Uso de colecciones:
//-------------------------------------------
// Obtenemos la coleccion (uso distinct)
oCollection := Test():distinct:orderBy( 2 ):where( "first < 'Homer'" ):whereBetween( "first", "'Aaron'", "'Alan'" ):findAll()
//:orWhere( "age > 21" ):orWhere( "age = 21" ):limit( 2, 40 )
?
? "Mostramos los 10 priemeros objetos modelos tipo test:"
?
for i := 1 to 10
with object oCollection:current() // Devuelve un objeto modelo
? :id, :first, :last, :age //, :city // Muestra algunos atributos
if oCollection:eof() ; exit ; endif
oCollection:next() // Avanza en la coleccion
// Se puede usar tambien:
// oCollection:skip()
end
next
?
? "Tipo de clase usada"
? "oCollection es de la clase " + oCollection:className()
? "oCollection:current() devuelve un objeto de la clase " + oCollection:current():className()
?
? "Presiona una tecla para seguir..."
Inkey( 100 )
// Se posiciona en el modelo que ocupa el 15 de la coleccion:
oCollection:moveBy( 15 )
// Se puede usar el estilo xBase tambien:
// oCollection:goTo( 15 )
oModel := oCollection:current() // Tambien se puede usar oCollection:get()
// Muestro el modelo como un hash
muestra( oModel:toHash() )
// Esto se encarga de liberar todo en una coleccion
oCollection:free()
Test():find( 35000 ):delete()
// Prueba de borrado
oModel := Test():find( 35 )
if !oModel:delete()
msg( "No se ha podido borrar, tal vez no exista..." )
endif
// Otra forma de borrar con el metodo de clase
if !Test():deleteById( 72 )
msg( "No se ha podido borrar, tal vez no exista..." )
endif
oModel := Test():find( 107 )
// Ver antes de actualizar:
muestra( oModel:toHash() )
oModel:first := "Manolo"
oModel:last := "Calero"
oModel:hiredate := Date()
oModel:married := .t.
oModel:salary := 1500.55
oModel:age := 67
oModel:save()
muestra( Test():count(), "Este es el numero de registros en la tabla antes" )
// Crea un nuevo objeto
oModel := Test():addNew()
oModel:first := "Francisco"
oModel:last := "Sanchez"
oModel:street := "Solana"
oModel:city := "Dos Hermanas"
oModel:state := "XX"
oModel:zip := "41700"
oModel:hiredate := Date() - 1000
oModel:married := .f.
oModel:age := 63
oModel:salary := 1234.89
oModel:notes := "Esto es un nuevo registro de prueba"
oModel:save()
// Otro objeto
oModel := Test():create()
oModel:first := "Georgina 1"
oModel:last := "Sanchez 1"
oModel:street := "Solana 1"
oModel:city := "Dos Hermanas 1"
oModel:state := "A1"
oModel:zip := "41700"
oModel:hiredate := Date() - 1000
oModel:married := .f.
oModel:age := 33
oModel:salary := 1234.89
oModel:notes := "Esto es un nuevo registro de prueba 1"
oModel:save()
msg( Test():count(), "Este es el numero de registros en la tabla despues" )
// Nuevo con esos datos:
oModel := Test():find( 107 )
h := oModel:toHash()
muestra( h )
oModel := Test():addNew( h )
oModel:save()
msg( Test():where( "state = 'NY'" ):count( "salary" ), "Numero de salariados en Nueva York:" )
msg( Test():where( "state = 'NY'" ):min( "salary" ), "Minimo salario en Nueva York:" )
msg( Test():where( "state = 'NY'" ):max( "salary" ), "Maximo salario en Nueva York:" )
msg( Test():where( "state = 'NY'" ):sum( "salary" ), "Total de salarios en Nueva York:" )
msg( Test():where( "state = 'NY'" ):avg( "salary" ), "Media salarios en Nueva York:" )
oModel := Test():findFirst()
muestra( oModel:toHash(), "FINDFIRST" )
muestra( oModel:findLast():toHash(), "FINDLAST" )
catch e
msg( e:Description + " " + e:Operation, "Hay un ERROR" )
end
msg( "FIN" )
oCon:free()
return
Y muchos más!!!