Skip to main content

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