SQL/DBF microORM
DotHRB features a simple, yet efficient micro ORM layer that unifies the syntax for all CRUD operations across both DBF and SQL databases. This design offers crucial flexibility: users can start projects with DBF for compatibility with the existing codebase, and then seamlessly add new features that leverage the integrated SQLite.
#include "dothrb.ch"
class CustRepository from Repository
var oCtx
var oModel
method init constructor
destructor finalize
method create
method read
method update
method delete
end class
method init(oCtx) class CustRepository
::super:init()
::oCtx := oCtx
::oModel := new CustModel()
return Self
method finalize() class CustRepository
::oCtx:close()
return nil
method create(hData) class CustRepository
return ::oCtx:useModelCreate(::oModel, hData)
method update(hData) class CustRepository
return ::oCtx:useModelUpdate(::oModel, hData)
method read(hData, hFind, aOrder, aFields) class CustRepository
return ::oCtx:useModelRead(::oModel, hData, @hFind, @aOrder, @aFields)
method delete(hData) class CustRepository
return ::oCtx:useModelDelete(::oModel, hData)
In addition to the ORM's CRUD capabilities, DotHRB provides an API for executing custom SQL queries securely through parameterized statements, effectively eliminating the risk of SQL injection.
method search() class CustService
local dbArgs
local sql
local res
dbArgs := new HdbcDbArgs(hData)
text to var sql
select
id,
concat_ws(' - ', title, status) as text
from
activity
where
lower(concat_ws(' - ', title, status)) like '%' || lower(@search) || '%'
limit @limit
endtext
res := oCtx:query(sql, dbArgs)
oCtx:close()
return res
DotHRB offers seamless data access: Harbour's standard database functions are always available and can be freely mixed with the ORM methods.
method get() class TaxesService
...
local res := {}
local row
if !tryParseISODate(hData['start'], @dStart, @hStart) .or. !tryParseISODate(hData['end'], @dEnd, @hEnd)
return false
end if
...
oCtx:useDbfArea("table1")
oCtx:useDbfArea("table2")
dbSetRelation("table1", {|| table2->cfield7})
oCtx:useDbfArea("table3")
table3->(ordsetfocus("index1"))
table3->(dbseek(hStart['year']))
while !table3->(eof()) .and. table3->cyear <= hEnd['year']
...
row := {=>}
row["account"] := table2->caccount
...
aadd(res, row)
table3->(dbskip())
end while
return res