Skip to content

Instantly share code, notes, and snippets.

@HarryR
Created May 13, 2011 14:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HarryR/970667 to your computer and use it in GitHub Desktop.
Save HarryR/970667 to your computer and use it in GitHub Desktop.
Easy interface to HandlerSocket for QT
#ifndef EASYHS_HPP_
#define EASYHS_HPP_
#pragma once
#include <handlersocket/hstcpcli.hpp>
#include <QList>
#include <QVariant>
#include <QRunnable>
#include <QObject>
#include <QMetaProperty>
#include <QMetaObject>
class EasyHS {
private:
struct dena::config hs_cfg;
struct dena::socket_args hs_sa;
dena::hstcpcli_ptr cli;
size_t hs_id;
public:
EasyHS(const char *host, const char *port)
: hs_id(0)
{
hs_cfg["host"] = host;
hs_cfg["port"] = port;
hs_sa.set(hs_cfg);
cli = dena::hstcpcli_i::create(hs_sa);
}
~EasyHS()
{ cli->close(); }
int error_code()
{ return cli->get_error_code(); }
bool is_stable()
{ return cli->stable_point(); }
struct dena::hstcpcli_i *get_cli()
{ return cli.get(); }
size_t next_id()
{ return ++hs_id; }
};
template <typename Tr, typename Ti>
class HSIndex {
int m_id;
EasyHS *m_hs;
public:
typedef QList<Tr*> results_t;
public:
HSIndex()
: m_id(-1), m_hs(NULL)
{}
HSIndex(EasyHS *hs)
: m_id(-1), m_hs(hs)
{}
bool
open( const char *db = NULL, const char *table = NULL, const char *index = NULL ) {
// Get parameters from classinfo
if( db == NULL || table == NULL || index == NULL )
{
const QMetaObject mo = Ti::staticMetaObject;
if( db == NULL ) {
int mo_db = mo.indexOfClassInfo("database");
assert( mo_db >= 0 );
db = mo.classInfo(mo_db).value();
}
if( table == NULL ) {
int mo_table = mo.indexOfClassInfo("table");
assert( mo_table >= 0 );
table = mo.classInfo(mo_table).value();
}
if( index == NULL ) {
int mo_index = mo.indexOfClassInfo("index");
assert( mo_index >= 0 );
index = mo.classInfo(mo_index).value();
}
}
// Fields which will be returned
QByteArray fields;
const QMetaObject mo = Tr::staticMetaObject;
assert( mo.propertyCount() > 0 );
for( int i = mo.propertyOffset(); i < mo.propertyCount(); i++ ) {
QMetaProperty qmp = mo.property(i);
assert( qmp.isWritable() );
assert( qmp.isValid() );
if( fields.size() ) {
fields.append(",");
}
fields.append( qmp.name() );
}
size_t id = m_hs->next_id();
struct dena::hstcpcli_i *cli = m_hs->get_cli();
cli->request_buf_open_index(id, db, table, index, fields.data());
if( cli->get_error_code() < 0 ) {
return false;
}
if( cli->request_send() != 0 ) {
return false;
}
size_t num_flds;
int result = cli->response_recv(num_flds);
if( result >= 0 ) {
cli->response_buf_remove();
m_id = id;
}
return result >= 0;
}
results_t* select(const char *op, Ti* fields_obj, int limit = 1, int skip = 0 )
{
dena::string_ref op_ref = dena::string_ref(op, strlen(op));
dena::string_ref modop_ref;
struct dena::hstcpcli_i * cli = m_hs->get_cli();
assert( m_hs->is_stable() );
const QMetaObject *mo = fields_obj->metaObject();
assert( mo->propertyCount() > 0 );
std::vector<dena::string_ref> fields;
{
int i;
for( i = mo->propertyOffset(); i < mo->propertyCount(); i++ ) {
QMetaProperty qmp = mo->property(i);
assert( qmp.isWritable() );
assert( qmp.isValid() );
QString value = qmp.read(fields_obj).toString();
fields.push_back( dena::string_ref( value.toAscii(), value.size() ) );
}
}
if( limit < 0 ) limit = 0;
if( skip < 0 ) skip = 0;
cli->request_buf_exec_generic(
m_id, op_ref, &fields[0], fields.size(), limit, skip,
// Other parameters not required for selects
dena::string_ref(), 0, 0);
if( cli->request_send() != 0 ) {
return NULL;
}
mo = &Tr::staticMetaObject;
size_t result_num_flds = fields.size();
int result = cli->response_recv(result_num_flds);
results_t* results = NULL;
if( result >= 0 ) {
const dena::string_ref * row;
results = new results_t(); //new results_t();
do {
if( results->size() >= limit ) {
break;
}
row = cli->get_next_row();
if( row ) {
Tr *obj = new Tr();
int i;
for( i = mo->propertyOffset(); i < mo->propertyCount(); i++ ) {
if( i - mo->propertyOffset() >= result_num_flds ) break;
QMetaProperty qmp = mo->property(i);
Q_ASSERT( qmp.isReadable() );
Q_ASSERT( qmp.isWritable() );
Q_ASSERT( qmp.isValid() );
Q_ASSERT( qmp.isScriptable() );
const dena::string_ref ref = row[i - mo->propertyOffset()];
qmp.write(obj, QString::fromUtf8(ref.begin(), ref.size()));
}
results->append( obj );
}
} while( row != NULL );
}
cli->response_buf_remove();
return results;
}
};
#endif
@HarryR
Copy link
Author

HarryR commented May 13, 2011

It uses QObjects with properties and classinfo to infer which fields should be retrieved and to populate the return objects.

class MyTableRow : QObject {
    Q_OBJECT

    Q_PROPERTY(...)
};

class MyTableIndex : public QObject {
    Q_OBJECT
    Q_CLASSINFO("index", "PRIMARY")
    Q_CLASSINFO("database", "somedb")
    Q_CLASSINFO("table", "mytable")
    Q_PROPERTY(uint id READ get_id WRITE set_id)
    uint m_id;
public:
    // getter/setters
};

In order to run queries against an index and return rows you would use:

EasyHS hs("127.0.0.1", "9998");
HSIndex<MyTableRow,MyTableIndex> primary_key(&hs);

if( primary_key.open() ) {
  MyTableIndex pk_search(200);
  QList<MyTableRow*> *results = primary_key.select("=", &pk_search);
  foreach( MyTableRow *row, *results) {
    // use row
  }
} 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment