Fork me on GitHub Node-drizzle API

Node-drizzle API

Drizzle/MySQL bindings for Node.js using libdrizzle.

Check out the Github repo for the source and installation guide.

Extra information: Homepage, ChangeLog, Examples, Wiki.

connection.h

./src/drizzle/connection.h

// Copyright 2011 Mariano Iglesias mgiglesias@gmail.com #ifndef SRCDRIZZLECONNECTIONH #define SRCDRIZZLECONNECTIONH

include <libdrizzle/drizzle.h>

include <libdrizzle/drizzle_client.h>

include <string>

include "./exception.h"

include "./result.h"

namespace drizzle { class Connection { public: Connection(); ~Connection(); std::string getHostname() const; void setHostname(const std::string& hostname); std::string getUser() const; void setUser(const std::string& user); std::string getPassword() const; void setPassword(const std::string& password); std::string getDatabase() const; void setDatabase(const std::string& database); uint32t getPort() const; void setPort(uint32t port); bool isMysql() const; void setMysql(bool mysql); bool isOpened() const; void open() throw(Exception&); void close(); std::string escape(const std::string& string) const throw(Exception&); std::string version() const; Result* query(const std::string& query) const throw(Exception&);

protected:
    std::string hostname;
    std::string user;
    std::string password;
    std::string database;
    uint32_t port;
    bool mysql;
    bool opened;

private:
    drizzle_st* drizzle;
    drizzle_con_st* connection;

}; }

endif // SRC_DRIZZLE_CONNECTION_H_

connection.cc

./src/drizzle/connection.cc

// Copyright 2011 Mariano Iglesias mgiglesias@gmail.com #include "./connection.h"

drizzle::Connection::Connection() :port(3306), mysql(true), opened(false), drizzle(NULL), connection(NULL) { }

drizzle::Connection::~Connection() { this->close(); if (this->drizzle != NULL) { drizzle_free(this->drizzle); } }

std::string drizzle::Connection::getHostname() const { return this->hostname; }

void drizzle::Connection::setHostname(const std::string& hostname) { this->hostname = hostname; }

std::string drizzle::Connection::getUser() const { return this->user; }

void drizzle::Connection::setUser(const std::string& user) { this->user = user; }

std::string drizzle::Connection::getPassword() const { return this->password; }

void drizzle::Connection::setPassword(const std::string& password) { this->password = password; }

std::string drizzle::Connection::getDatabase() const { return this->database; }

void drizzle::Connection::setDatabase(const std::string& database) { this->database = database; }

uint32_t drizzle::Connection::getPort() const { return this->port; }

void drizzle::Connection::setPort(uint32_t port) { this->port = port; }

bool drizzle::Connection::isMysql() const { return this->mysql; }

void drizzle::Connection::setMysql(bool mysql) { this->mysql = mysql; }

bool drizzle::Connection::isOpened() const { return this->opened; }

void drizzle::Connection::open() throw(drizzle::Exception&) { this->close();

if (this->drizzle == NULL) {
    this->drizzle = drizzle_create(NULL);
    if (this->drizzle == NULL) {
        throw drizzle::Exception("Cannot create drizzle structure");
    }

    drizzle_add_options(this->drizzle, DRIZZLE_NON_BLOCKING);
}

this->connection = drizzle_con_create(this->drizzle, NULL);
if (this->connection == NULL) {
    throw drizzle::Exception("Cannot create connection structure");
}

drizzle_con_set_tcp(this->connection, this->hostname.c_str(), this->port);
drizzle_con_set_auth(this->connection, this->user.c_str(), this->password.c_str());
drizzle_con_set_db(this->connection, this->database.c_str());
if (this->mysql) {
    drizzle_con_add_options(this->connection, DRIZZLE_CON_MYSQL);
}

drizzle_return_t result;
try {
    while (!this->opened) {
        result = drizzle_con_connect(this->connection);
        if (result == DRIZZLE_RETURN_OK) {
            this->opened = true;
            break;
        } else if (result != DRIZZLE_RETURN_IO_WAIT) {
            throw drizzle::Exception(drizzle_con_error(this->connection));
        }

        if (drizzle_con_wait(this->drizzle) != DRIZZLE_RETURN_OK) {
            throw drizzle::Exception("Could not wait for connection");
        }

        if (drizzle_con_ready(this->drizzle) == NULL) {
            throw drizzle::Exception("Could not fetch connection");
        }
    }
} catch(...) {
    if (this->connection != NULL) {
        drizzle_con_free(this->connection);
        this->opened = false;
        this->connection = NULL;
    }
    throw;
}

}

void drizzle::Connection::close() { if (this->connection != NULL) { drizzleconclose(this->connection); drizzleconfree(this->connection); this->connection = NULL; } this->opened = false; }

std::string drizzle::Connection::escape(const std::string& string) const throw(drizzle::Exception&) { char* buffer = new char[string.length() * 2 + 1]; if (buffer == NULL) { throw drizzle::Exception("Can\'t create buffer to escape string"); }

drizzle_escape_string(buffer, string.c_str(), string.length());

std::string escaped = buffer;
delete [] buffer;
return escaped;

}

std::string drizzle::Connection::version() const { std::string version; if (this->opened) { version = drizzleconserver_version(this->connection); } return version; }

drizzle::Result* drizzle::Connection::query(const std::string& query) const throw(drizzle::Exception&) { if (!this->opened) { throw drizzle::Exception("Can't execute query without an opened connection"); }

drizzle_result_st *result = NULL;
drizzle_return_t executed;
try {
    while (true) {
        result = drizzle_query(this->connection, NULL, query.c_str(), query.length(), &executed);

        if (executed == DRIZZLE_RETURN_OK) {
            break;
        } else if (executed != DRIZZLE_RETURN_IO_WAIT) {
            if (executed == DRIZZLE_RETURN_LOST_CONNECTION) {
                throw drizzle::Exception("Lost connection while executing query");
            }
            throw drizzle::Exception(drizzle_con_error(this->connection));
        }

        if (drizzle_con_wait(this->drizzle) != DRIZZLE_RETURN_OK) {
            throw drizzle::Exception("Could not wait for connection");
        }

        if (drizzle_con_ready(this->drizzle) == NULL) {
            throw drizzle::Exception("Could not fetch connection");
        }
    }
} catch(...) {
    if (result != NULL) {
        drizzle_result_free(result);
    }
    throw;
}

if (result == NULL) {
    throw drizzle::Exception("Could not fetch result of query");
}

return new drizzle::Result(this->drizzle, result);

}

exception.h

./src/drizzle/exception.h

// Copyright 2011 Mariano Iglesias mgiglesias@gmail.com #ifndef SRCDRIZZLEEXCEPTIONH #define SRCDRIZZLEEXCEPTIONH

include <exception>

namespace drizzle { class Exception : public std::exception { public: explicit Exception(const char message); const char what() const throw(); protected: const char* message; }; }

endif // SRC_DRIZZLE_EXCEPTION_H_

exception.cc

./src/drizzle/exception.cc

// Copyright 2011 Mariano Iglesias mgiglesias@gmail.com #include "./exception.h"

drizzle::Exception::Exception(const char* message) : exception(), message(message) { }

const char* drizzle::Exception::what() const throw() { return this->message; }

result.h

./src/drizzle/result.h

// Copyright 2011 Mariano Iglesias mgiglesias@gmail.com #ifndef SRCDRIZZLERESULTH #define SRCDRIZZLERESULTH

include <libdrizzle/drizzle.h>

include <libdrizzle/drizzle_client.h>

include <string>

include <stdexcept>

include "./exception.h"

namespace drizzle { class Result { public: class Column { public: typedef enum { STRING, TEXT, INT, NUMBER, DATE, TIME, DATETIME, BOOL, SET } type_t;

            explicit Column(drizzle_column_st *column);
            ~Column();
            std::string getName() const;
            type_t getType() const;

        protected:
            std::string name;
            type_t type;
    };

    explicit Result(drizzle_st* drizzle, drizzle_result_st* result) throw(Exception&);
    ~Result();
    bool hasNext() const;
    const char** next() throw(Exception&);
    uint64_t index() const throw(std::out_of_range&);
    Column* column(uint16_t i) const throw(std::out_of_range&);
    uint64_t insertId() const;
    uint64_t affectedCount() const;
    uint16_t warningCount() const;
    uint16_t columnCount() const;

protected:
    Column **columns;
    uint16_t totalColumns;
    uint64_t rowNumber;

    char **row() throw(Exception&);

private:
    drizzle_st *drizzle;
    drizzle_result_st *result;
    drizzle_row_t previousRow;
    drizzle_row_t nextRow;

}; }

endif // SRC_DRIZZLE_RESULT_H_

drizzle.h

./src/drizzle.h

// Copyright 2011 Mariano Iglesias mgiglesias@gmail.com #ifndef SRCDRIZZLEH #define SRCDRIZZLEH

include <stdlib.h>

include <node.h>

include <node_buffer.h>

include <node_events.h>

include <string>

include <sstream>

include <vector>

include "./drizzle/connection.h"

include "./drizzle/exception.h"

include "./drizzle/result.h"

include "./drizzle_bindings.h"

namespace node_drizzle { class Drizzle : public node::EventEmitter { public: static void Init(v8::Handle<v8::Object> target);

protected:
    typedef enum {
        COLUMN_TYPE_STRING,
        COLUMN_TYPE_BOOL,
        COLUMN_TYPE_INT,
        COLUMN_TYPE_NUMBER,
        COLUMN_TYPE_DATE,
        COLUMN_TYPE_TIME,
        COLUMN_TYPE_DATETIME,
        COLUMN_TYPE_TEXT,
        COLUMN_TYPE_SET
    } column_type_t;
    struct connect_request_t {
        Drizzle* drizzle;
        const char* error;
        v8::Persistent<v8::Function> cbSuccess;
        v8::Persistent<v8::Function> cbError;
    };
    struct query_request_t {
        bool cast;
        bool buffer;
        Drizzle* drizzle;
        std::string query;
        drizzle::Result *result;
        const char* error;
        std::vector<std::string**>* rows;
        v8::Persistent<v8::Function> cbStart;
        v8::Persistent<v8::Function> cbFinish;
        v8::Persistent<v8::Function> cbSuccess;
        v8::Persistent<v8::Function> cbError;
        v8::Persistent<v8::Function> cbEach;
    };
    drizzle::Connection *connection;

    Drizzle();
    ~Drizzle();
    static v8::Handle<v8::Value> New(const v8::Arguments& args);
    static v8::Handle<v8::Value> Connect(const v8::Arguments& args);
    static v8::Handle<v8::Value> Disconnect(const v8::Arguments& args);
    static v8::Handle<v8::Value> Escape(const v8::Arguments& args);
    static v8::Handle<v8::Value> Query(const v8::Arguments& args);
    static int eioConnect(eio_req* req);
    static void connect(connect_request_t* request);
    static void connectFinished(connect_request_t* request);
    static int eioConnectFinished(eio_req* eioRequest);
    static int eioQuery(eio_req* eioRequest);
    static int eioQueryFinished(eio_req* eioRequest);
    static int eioQueryEach(eio_req* eioRequest);
    static int eioQueryEachFinished(eio_req* eioRequest);
    static void eioQueryCleanup(query_request_t* request);
    static void eioQueryRequestFree(query_request_t* request);
    v8::Local<v8::Object> row(drizzle::Result* result, std::string** currentRow, bool cast) const;
    std::string parseQuery(const std::string& query, v8::Local<v8::Array> values) const throw(drizzle::Exception&);
    std::string value(v8::Local<v8::Value> value, bool inArray = false) const throw(drizzle::Exception&);

private:
    uint64_t toDate(const std::string& value, bool hasTime) const throw(drizzle::Exception&);
    std::string fromDate(const uint64_t timeStamp) const throw(drizzle::Exception&);
    uint64_t toTime(const std::string& value) const;
    // GMT delta calculation borrowed from https://github.com/Sannis/node-mysql-libmysqlclient
    int gmtDelta() const throw(drizzle::Exception&);

}; }

endif // SRC_DRIZZLE_H_

result.cc

./src/drizzle/result.cc

// Copyright 2011 Mariano Iglesias mgiglesias@gmail.com #include "./result.h"

drizzle::Result::Column::Column(drizzlecolumnst *column) { this->name = drizzlecolumnname(column);

switch (drizzle_column_type(column)) {
    case DRIZZLE_COLUMN_TYPE_TINY:
        this->type = (drizzle_column_size(column) == 1 ? BOOL : INT);
        break;
    case DRIZZLE_COLUMN_TYPE_BIT:
    case DRIZZLE_COLUMN_TYPE_SHORT:
    case DRIZZLE_COLUMN_TYPE_YEAR:
    case DRIZZLE_COLUMN_TYPE_INT24:
    case DRIZZLE_COLUMN_TYPE_LONG:
    case DRIZZLE_COLUMN_TYPE_LONGLONG:
        this->type = INT;
        break;
    case DRIZZLE_COLUMN_TYPE_FLOAT:
    case DRIZZLE_COLUMN_TYPE_DOUBLE:
    case DRIZZLE_COLUMN_TYPE_DECIMAL:
    case DRIZZLE_COLUMN_TYPE_NEWDECIMAL:
        this->type = NUMBER;
        break;
    case DRIZZLE_COLUMN_TYPE_DATE:
    case DRIZZLE_COLUMN_TYPE_NEWDATE:
        this->type = DATE;
        break;
    case DRIZZLE_COLUMN_TYPE_TIME:
        this->type = TIME;
        break;
    case DRIZZLE_COLUMN_TYPE_TIMESTAMP:
    case DRIZZLE_COLUMN_TYPE_DATETIME:
        this->type = DATETIME;
        break;
    case DRIZZLE_COLUMN_TYPE_TINY_BLOB:
    case DRIZZLE_COLUMN_TYPE_MEDIUM_BLOB:
    case DRIZZLE_COLUMN_TYPE_LONG_BLOB:
    case DRIZZLE_COLUMN_TYPE_BLOB:
        this->type = TEXT;
        break;
    case DRIZZLE_COLUMN_TYPE_SET:
        this->type = SET;
        break;
    default:
        this->type = STRING;
        break;
}

}

drizzle::Result::Column::~Column() { }

std::string drizzle::Result::Column::getName() const { return this->name; }

drizzle::Result::Column::type_t drizzle::Result::Column::getType() const { return this->type; }

drizzle::Result::Result(drizzlest* drizzle, drizzleresult_st* result) throw(drizzle::Exception&) : columns(NULL), totalColumns(0), rowNumber(0), drizzle(drizzle), result(result), previousRow(NULL), nextRow(NULL) { if (this->result == NULL) { throw drizzle::Exception("Invalid result"); }

if (drizzle_column_buffer(this->result) != DRIZZLE_RETURN_OK) {
    drizzle_result_free(this->result);
    throw drizzle::Exception("Could not buffer columns");
}

this->totalColumns = drizzle_result_column_count(this->result);
if (this->totalColumns > 0) {
    this->columns = new Column*[this->totalColumns];
    if (this->columns == NULL) {
        drizzle_result_free(this->result);
        throw drizzle::Exception("Could not allocate storage for columns");
    }

    uint16_t i = 0;
    drizzle_column_st *current;
    while ((current = drizzle_column_next(this->result)) != NULL) {
        this->columns[i++] = new Column(current);
    }
}

this->nextRow = this->row();

}

drizzle::Result::~Result() { if (this->columns != NULL) { for (uint16t i = 0; i < this->totalColumns; i++) { delete this->columns[i]; } delete [] this->columns; } if (this->result != NULL) { if (this->previousRow != NULL) { drizzlerowfree(this->result, this->previousRow); } if (this->nextRow != NULL) { drizzlerowfree(this->result, this->nextRow); } drizzleresult_free(this->result); } }

bool drizzle::Result::hasNext() const { return (this->nextRow != NULL); }

const char** drizzle::Result::next() throw(drizzle::Exception&) { if (this->previousRow != NULL) { drizzlerowfree(this->result, this->previousRow); }

if (this->nextRow == NULL) {
    return NULL;
}

this->rowNumber++;
this->previousRow = this->nextRow;
this->nextRow = this->row();

return (const char**) this->previousRow;

}

char drizzle::Result::row() throw(drizzle::Exception&) { drizzlereturnt result = DRIZZLERETURNIO_WAIT; char row = NULL;

while (result == DRIZZLE_RETURN_IO_WAIT) {
    row = drizzle_row_buffer(this->result, &result);
    if (result == DRIZZLE_RETURN_IO_WAIT) {
        if (drizzle_con_wait(this->drizzle) != DRIZZLE_RETURN_OK) {
            throw drizzle::Exception("Could not wait for connection");
        }

        if (drizzle_con_ready(this->drizzle) == NULL) {
            throw drizzle::Exception("Could not fetch connection");
        }
    }
}

if (result != DRIZZLE_RETURN_OK) {
    if (row != NULL) {
        drizzle_row_free(this->result, row);
        row = NULL;
    }
    throw drizzle::Exception("Could not prefetch next row");
}

return row;

}

uint64t drizzle::Result::index() const throw(std::outofrange&) { if (this->rowNumber == 0) { throw std::outof_range("Not standing on a row"); } return (this->rowNumber - 1); }

drizzle::Result::Column* drizzle::Result::column(uint16t i) const throw(std::outofrange&) { if (i < 0 || i >= this->totalColumns) { throw std::outof_range("Wrong column index"); } return this->columns[i]; }

uint64t drizzle::Result::insertId() const { return drizzleresultinsertid(this->result); }

uint64t drizzle::Result::affectedCount() const { return drizzleresultaffectedrows(this->result); }

uint16t drizzle::Result::warningCount() const { return drizzleresultwarningcount(this->result); }

uint16_t drizzle::Result::columnCount() const { return this->totalColumns; }

drizzle.cc

./src/drizzle.cc

// Copyright 2011 Mariano Iglesias mgiglesias@gmail.com #include "./drizzle.h"

void node_drizzle::Drizzle::Init(v8::Handle<v8::Object> target) { v8::HandleScope scope;

v8::Local<v8::FunctionTemplate> functionTemplate = v8::FunctionTemplate::New(New);
functionTemplate->Inherit(node::EventEmitter::constructor_template);

v8::Local<v8::ObjectTemplate> instanceTemplate = functionTemplate->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(1);

NODE_DEFINE_CONSTANT(instanceTemplate, COLUMN_TYPE_STRING);
NODE_DEFINE_CONSTANT(instanceTemplate, COLUMN_TYPE_BOOL);
NODE_DEFINE_CONSTANT(instanceTemplate, COLUMN_TYPE_INT);
NODE_DEFINE_CONSTANT(instanceTemplate, COLUMN_TYPE_NUMBER);
NODE_DEFINE_CONSTANT(instanceTemplate, COLUMN_TYPE_DATE);
NODE_DEFINE_CONSTANT(instanceTemplate, COLUMN_TYPE_TIME);
NODE_DEFINE_CONSTANT(instanceTemplate, COLUMN_TYPE_DATETIME);
NODE_DEFINE_CONSTANT(instanceTemplate, COLUMN_TYPE_TEXT);
NODE_DEFINE_CONSTANT(instanceTemplate, COLUMN_TYPE_SET);

NODE_ADD_PROTOTYPE_METHOD(functionTemplate, "connect", Connect);
NODE_ADD_PROTOTYPE_METHOD(functionTemplate, "disconnect", Disconnect);
NODE_ADD_PROTOTYPE_METHOD(functionTemplate, "escape", Escape);
NODE_ADD_PROTOTYPE_METHOD(functionTemplate, "query", Query);

target->Set(v8::String::NewSymbol("Drizzle"), functionTemplate->GetFunction());

}

node_drizzle::Drizzle::Drizzle(): node::EventEmitter(), connection(NULL) { }

node_drizzle::Drizzle::~Drizzle() { if (this->connection != NULL) { delete this->connection; } }

v8::Handle<v8::Value> node_drizzle::Drizzle::New(const v8::Arguments& args) { v8::HandleScope scope;

node_drizzle::Drizzle *drizzle = new node_drizzle::Drizzle();
drizzle->Wrap(args.This());

return args.This();

}

v8::Handle<v8::Value> node_drizzle::Drizzle::Connect(const v8::Arguments& args) { v8::HandleScope scope;

ARG_CHECK_OBJECT(0, options);

v8::Local<v8::Object> options = args[0]->ToObject();

ARG_CHECK_OBJECT_ATTR_STRING(options, hostname);
ARG_CHECK_OBJECT_ATTR_STRING(options, user);
ARG_CHECK_OBJECT_ATTR_STRING(options, password);
ARG_CHECK_OBJECT_ATTR_STRING(options, database);
ARG_CHECK_OBJECT_ATTR_OPTIONAL_UINT32(options, port);
ARG_CHECK_OBJECT_ATTR_OPTIONAL_BOOL(options, mysql);
ARG_CHECK_OBJECT_ATTR_OPTIONAL_FUNCTION(options, success);
ARG_CHECK_OBJECT_ATTR_OPTIONAL_FUNCTION(options, error);
ARG_CHECK_OBJECT_ATTR_OPTIONAL_BOOL(options, async);

node_drizzle::Drizzle *drizzle = node::ObjectWrap::Unwrap<node_drizzle::Drizzle>(args.This());
assert(drizzle);

if (drizzle->connection != NULL) {
    delete drizzle->connection;
}

v8::String::Utf8Value hostname(options->Get(hostname_key)->ToString());
v8::String::Utf8Value user(options->Get(user_key)->ToString());
v8::String::Utf8Value password(options->Get(password_key)->ToString());
v8::String::Utf8Value database(options->Get(database_key)->ToString());

drizzle->connection = new drizzle::Connection();
drizzle->connection->setHostname(*hostname);
drizzle->connection->setUser(*user);
drizzle->connection->setPassword(*password);
drizzle->connection->setDatabase(*database);

if (options->Has(port_key)) {
    drizzle->connection->setPort(options->Get(mysql_key)->ToInt32()->Value());
}

if (options->Has(mysql_key)) {
    drizzle->connection->setMysql(options->Get(mysql_key)->IsTrue());
}

connect_request_t *request = new connect_request_t();
request->drizzle = drizzle;
request->error = NULL;

if (options->Has(success_key)) {
    request->cbSuccess = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(options->Get(success_key)));
}

if (options->Has(error_key)) {
    request->cbError = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(options->Get(error_key)));
}

bool async = options->Has(async_key) ? options->Get(async_key)->IsTrue() : true;
if (async) {
    request->drizzle->Ref();
    eio_custom(eioConnect, EIO_PRI_DEFAULT, eioConnectFinished, request);
    ev_ref(EV_DEFAULT_UC);
} else {
    connect(request);
    connectFinished(request);
}

return v8::Undefined();

}

void nodedrizzle::Drizzle::connect(connectrequest_t* request) { try { request->drizzle->connection->open(); } catch(const drizzle::Exception& exception) { request->error = exception.what(); } }

void nodedrizzle::Drizzle::connectFinished(connectrequest_t* request) { bool connected = request->drizzle->connection->isOpened();

v8::TryCatch tryCatch;

if (connected && !request->cbSuccess.IsEmpty()) {
    v8::Local<v8::Object> server = v8::Object::New();
    server->Set(v8::String::New("version"), v8::String::New(request->drizzle->connection->version().c_str()));
    server->Set(v8::String::New("hostname"), v8::String::New(request->drizzle->connection->getHostname().c_str()));
    server->Set(v8::String::New("user"), v8::String::New(request->drizzle->connection->getUser().c_str()));
    server->Set(v8::String::New("database"), v8::String::New(request->drizzle->connection->getDatabase().c_str()));

    v8::Local<v8::Value> argv[1];
    argv[0] = server;

    request->cbSuccess->Call(v8::Context::GetCurrent()->Global(), 1, argv);
} else if (!connected && !request->cbError.IsEmpty()) {
    v8::Local<v8::Value> argv[1];
    argv[0] = v8::String::New(request->error != NULL ? request->error : "(unknown error)");
    request->cbError->Call(v8::Context::GetCurrent()->Global(), 1, argv);
}

if (tryCatch.HasCaught()) {
    node::FatalException(tryCatch);
}

request->cbSuccess.Dispose();
request->cbError.Dispose();

delete request;

}

int nodedrizzle::Drizzle::eioConnect(eioreq* eioRequest) { connectrequestt *request = staticcast<connectrequest_t *>(eioRequest->data); assert(request);

connect(request);

return 0;

}

int nodedrizzle::Drizzle::eioConnectFinished(eioreq* eioRequest) { v8::HandleScope scope;

connect_request_t *request = static_cast<connect_request_t *>(eioRequest->data);
assert(request);

ev_unref(EV_DEFAULT_UC);
request->drizzle->Unref();

connectFinished(request);

return 0;

}

v8::Handle<v8::Value> node_drizzle::Drizzle::Disconnect(const v8::Arguments& args) { v8::HandleScope scope;

node_drizzle::Drizzle *drizzle = node::ObjectWrap::Unwrap<node_drizzle::Drizzle>(args.This());
assert(drizzle);

if (drizzle->connection != NULL) {
    drizzle->connection->close();
    delete drizzle->connection;
}

return v8::Undefined();

}

v8::Handle<v8::Value> node_drizzle::Drizzle::Escape(const v8::Arguments& args) { v8::HandleScope scope;

ARG_CHECK_STRING(0, string);

node_drizzle::Drizzle *drizzle = node::ObjectWrap::Unwrap<node_drizzle::Drizzle>(args.This());
assert(drizzle);

std::string escaped;

try {
    v8::String::Utf8Value string(args[0]->ToString());
    std::string unescaped(*string);
    escaped = drizzle->connection->escape(unescaped);
} catch(const drizzle::Exception& exception) {
    return v8::ThrowException(v8::Exception::Error(v8::String::New(exception.what())));
}

return v8::String::New(escaped.c_str());

}

v8::Handle<v8::Value> node_drizzle::Drizzle::Query(const v8::Arguments& args) { v8::HandleScope scope;

ARG_CHECK_STRING(0, query);

if (args.Length() > 2) {
    ARG_CHECK_ARRAY(1, values);
    ARG_CHECK_OBJECT(2, options);
} else {
    ARG_CHECK_OBJECT(1, options);
}

v8::Local<v8::Object> options = args[args.Length() > 2 ? 2 : 1]->ToObject();

ARG_CHECK_OBJECT_ATTR_OPTIONAL_BOOL(options, buffer);
ARG_CHECK_OBJECT_ATTR_OPTIONAL_BOOL(options, cast);
ARG_CHECK_OBJECT_ATTR_OPTIONAL_FUNCTION(options, start);
ARG_CHECK_OBJECT_ATTR_OPTIONAL_FUNCTION(options, finish);
ARG_CHECK_OBJECT_ATTR_OPTIONAL_FUNCTION(options, success);
ARG_CHECK_OBJECT_ATTR_OPTIONAL_FUNCTION(options, error);
ARG_CHECK_OBJECT_ATTR_OPTIONAL_FUNCTION(options, each);

v8::String::Utf8Value query(args[0]->ToString());

node_drizzle::Drizzle *drizzle = node::ObjectWrap::Unwrap<node_drizzle::Drizzle>(args.This());
assert(drizzle);

query_request_t *request = new query_request_t();
request->drizzle = drizzle;
request->cast = true;
request->buffer = true;
request->query = *query;
request->result = NULL;
request->rows = NULL;
request->error = NULL;

if (options->Has(buffer_key)) {
    request->buffer = options->Get(buffer_key)->IsTrue();
}

if (options->Has(cast_key)) {
    request->cast = options->Get(cast_key)->IsTrue();
}

if (options->Has(start_key)) {
    request->cbStart = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(options->Get(start_key)));
}

if (options->Has(finish_key)) {
    request->cbFinish = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(options->Get(finish_key)));
}

if (options->Has(success_key)) {
    request->cbSuccess = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(options->Get(success_key)));
}

if (options->Has(error_key)) {
    request->cbError = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(options->Get(error_key)));
}

if (options->Has(each_key)) {
    request->cbEach = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(options->Get(each_key)));
}

v8::Local<v8::Array> values;

if (args.Length() > 2) {
    values = v8::Array::Cast(*args[1]);
} else {
    values = v8::Array::New();
}

try {
    request->query = drizzle->parseQuery(request->query, values);
} catch(const drizzle::Exception& exception) {
    return v8::ThrowException(v8::Exception::Error(v8::String::New(exception.what())));
}

if (!request->cbStart.IsEmpty()) {
    v8::Local<v8::Value> argv[1];
    argv[0] = v8::String::New(request->query.c_str());

    v8::TryCatch tryCatch;
    v8::Handle<v8::Value> result = request->cbStart->Call(v8::Context::GetCurrent()->Global(), 1, argv);
    if (tryCatch.HasCaught()) {
        node::FatalException(tryCatch);
    }

    if (!result->IsUndefined()) {
        if (result->IsFalse()) {
            eioQueryRequestFree(request);
            return v8::Undefined();
        } else if (result->IsString()) {
            v8::String::Utf8Value modifiedQuery(result->ToString());
            request->query = *modifiedQuery;
        }
    }
}

request->drizzle->Ref();
eio_custom(eioQuery, EIO_PRI_DEFAULT, eioQueryFinished, request);
ev_ref(EV_DEFAULT_UC);

return v8::Undefined();

}

int nodedrizzle::Drizzle::eioQuery(eioreq* eioRequest) { queryrequestt *request = staticcast<queryrequest_t *>(eioRequest->data); assert(request);

try {
    request->result = request->drizzle->connection->query(request->query);

    if (request->buffer) {
        request->rows = new std::vector<std::string**>();
        if (request->rows == NULL) {
            throw drizzle::Exception("Could not create buffer for rows");
        }

        uint16_t columnCount = request->result->columnCount();
        while (request->result->hasNext()) {
            const char **currentRow = request->result->next();
            std::string** row = new std::string*[columnCount];
            if (row == NULL) {
                throw drizzle::Exception("Could not create buffer for row");
            }

            for (uint16_t i = 0; i < columnCount; i++) {
                if (currentRow[i] != NULL) {
                    row[i] = new std::string(currentRow[i]);
                } else {
                    row[i] = NULL;
                }
            }

            request->rows->push_back(row);
        }
    }
} catch(const drizzle::Exception& exception) {
    if (request->rows != NULL) {
        delete request->rows;
    }
    request->error = exception.what();
}

return 0;

}

int nodedrizzle::Drizzle::eioQueryFinished(eioreq* eioRequest) { v8::HandleScope scope;

query_request_t *request = static_cast<query_request_t *>(eioRequest->data);
assert(request);

uint16_t columnCount = (request->result != NULL ? request->result->columnCount() : 0);
if (request->error == NULL) {
    assert(request->result);

    v8::Local<v8::Value> argv[2];
    uint8_t argc = 1;

    v8::Local<v8::Array> columns = v8::Array::New(columnCount);
    for (uint16_t j = 0; j < columnCount; j++) {
        drizzle::Result::Column *currentColumn = request->result->column(j);
        v8::Local<v8::Value> columnType;

        switch (currentColumn->getType()) {
            case drizzle::Result::Column::BOOL:
                columnType = NODE_CONSTANT(COLUMN_TYPE_BOOL);
                break;
            case drizzle::Result::Column::INT:
                columnType = NODE_CONSTANT(COLUMN_TYPE_INT);
                break;
            case drizzle::Result::Column::NUMBER:
                columnType = NODE_CONSTANT(COLUMN_TYPE_NUMBER);
                break;
            case drizzle::Result::Column::DATE:
                columnType = NODE_CONSTANT(COLUMN_TYPE_DATE);
                break;
            case drizzle::Result::Column::TIME:
                columnType = NODE_CONSTANT(COLUMN_TYPE_TIME);
                break;
            case drizzle::Result::Column::DATETIME:
                columnType = NODE_CONSTANT(COLUMN_TYPE_DATETIME);
                break;
            case drizzle::Result::Column::TEXT:
                columnType = NODE_CONSTANT(COLUMN_TYPE_TEXT);
                break;
            case drizzle::Result::Column::SET:
                columnType = NODE_CONSTANT(COLUMN_TYPE_SET);
                break;
            default:
                columnType = NODE_CONSTANT(COLUMN_TYPE_STRING);
                break;
        }

        v8::Local<v8::Object> column = v8::Object::New();
        column->Set(v8::String::New("name"), v8::String::New(currentColumn->getName().c_str()));
        column->Set(v8::String::New("type"), columnType);

        columns->Set(j, column);
    }

    argv[0] = columns;

    v8::Local<v8::Array> rows = v8::Array::New();

    if (request->buffer) {
        assert(request->rows);

        uint64_t index = 0;
        for (std::vector<std::string**>::iterator iterator = request->rows->begin(), end = request->rows->end(); iterator != end; ++iterator, index++) {
            std::string** row = *iterator;
            rows->Set(index, request->drizzle->row(request->result, row, request->cast));
        }

        argc = 2;
        argv[1] = rows;
    }

    if (!request->cbSuccess.IsEmpty()) {
        v8::TryCatch tryCatch;
        request->cbSuccess->Call(v8::Context::GetCurrent()->Global(), argc, argv);
        if (tryCatch.HasCaught()) {
            node::FatalException(tryCatch);
        }
    }

    if (request->buffer && !request->cbEach.IsEmpty()) {
        uint64_t index = 0;
        for (std::vector<std::string**>::iterator iterator = request->rows->begin(), end = request->rows->end(); iterator != end; ++iterator, index++) {
            v8::Local<v8::Value> eachArgv[3];

            eachArgv[0] = rows->Get(index);
            eachArgv[1] = v8::Number::New(index);
            eachArgv[2] = v8::Local<v8::Value>::New(iterator == end ? v8::True() : v8::False());

            v8::TryCatch tryCatch;
            request->cbEach->Call(v8::Context::GetCurrent()->Global(), 3, eachArgv);
            if (tryCatch.HasCaught()) {
                node::FatalException(tryCatch);
            }
        }
    }
} else if (!request->cbError.IsEmpty()) {
    v8::Local<v8::Value> argv[1];
    argv[0] = v8::String::New(request->error != NULL ? request->error : "(unknown error)");

    v8::TryCatch tryCatch;
    request->cbError->Call(v8::Context::GetCurrent()->Global(), 1, argv);
    if (tryCatch.HasCaught()) {
        node::FatalException(tryCatch);
    }
}

eioQueryCleanup(request);

return 0;

}

int nodedrizzle::Drizzle::eioQueryEach(eioreq* eioRequest) { queryrequestt *request = staticcast<queryrequest_t *>(eioRequest->data); assert(request);

try {
    if (request->result->hasNext()) {
        const char **currentRow = request->result->next();
        request->rows = new std::vector<std::string**>();
        if (request->rows == NULL) {
            throw drizzle::Exception("Could not create buffer for rows");
        }

        uint16_t columnCount = request->result->columnCount();
        std::string** row = new std::string*[columnCount];
        if (row == NULL) {
            throw drizzle::Exception("Could not create buffer for row");
        }

        for (uint16_t i = 0; i < columnCount; i++) {
            if (currentRow[i] != NULL) {
                row[i] = new std::string(currentRow[i]);
            } else {
                row[i] = NULL;
            }
        }

        request->rows->push_back(row);
    }
} catch(const drizzle::Exception& exception) {
    if (request->rows != NULL) {
        delete request->rows;
    }
    request->error = exception.what();
}

return 0;

}

int nodedrizzle::Drizzle::eioQueryEachFinished(eioreq* eioRequest) { v8::HandleScope scope;

query_request_t *request = static_cast<query_request_t *>(eioRequest->data);
assert(request);

if (!request->cbEach.IsEmpty() && request->rows != NULL) {
    v8::Local<v8::Value> eachArgv[3];

    eachArgv[0] = request->drizzle->row(request->result, request->rows->front(), request->cast);
    eachArgv[1] = v8::Number::New(request->result->index());
    eachArgv[2] = v8::Local<v8::Value>::New(request->result->hasNext() ? v8::False() : v8::True());

    v8::TryCatch tryCatch;
    request->cbEach->Call(v8::Context::GetCurrent()->Global(), 3, eachArgv);
    if (tryCatch.HasCaught()) {
        node::FatalException(tryCatch);
    }
}

eioQueryCleanup(request);

return 0;

}

void nodedrizzle::Drizzle::eioQueryCleanup(queryrequestt* request) { evunref(EVDEFAULTUC); request->drizzle->Unref();

if (request->result == NULL || !request->result->hasNext()) {
    if (!request->cbFinish.IsEmpty()) {
        v8::TryCatch tryCatch;
        request->cbFinish->Call(v8::Context::GetCurrent()->Global(), 0, NULL);
        if (tryCatch.HasCaught()) {
            node::FatalException(tryCatch);
        }
    }

    eioQueryRequestFree(request);
} else {
    request->drizzle->Ref();
    eio_custom(eioQueryEach, EIO_PRI_DEFAULT, eioQueryEachFinished, request);
    ev_ref(EV_DEFAULT_UC);
}

}

void nodedrizzle::Drizzle::eioQueryRequestFree(queryrequestt* request) { if (request->result != NULL) { if (request->rows != NULL) { uint16t columnCount = request->result->columnCount(); for (std::vector<std::string>::iterator iterator = request->rows->begin(), end = request->rows->end(); iterator != end; ++iterator) { std::string row = *iterator; for (uint16_t i = 0; i < columnCount; i++) { if (row[i] != NULL) { delete row[i]; } } delete [] row; }

        delete request->rows;
    }

    delete request->result;
}

request->cbStart.Dispose();
request->cbFinish.Dispose();
request->cbSuccess.Dispose();
request->cbError.Dispose();
request->cbEach.Dispose();

delete request;

}

v8::Local<v8::Object> node_drizzle::Drizzle::row(drizzle::Result* result, std::string** currentRow, bool cast) const { v8::Local<v8::Object> row = v8::Object::New();

for (uint16_t j = 0, limitj = result->columnCount(); j < limitj; j++) {
    drizzle::Result::Column* currentColumn = result->column(j);
    v8::Local<v8::Value> value;

    if (currentRow[j] != NULL) {
        const char* currentValue = currentRow[j]->c_str();
        if (cast) {
            switch (currentColumn->getType()) {
                case drizzle::Result::Column::BOOL:
                    value = v8::Local<v8::Value>::New(currentRow[j]->empty() || currentRow[j]->compare("0") != 0 ? v8::True() : v8::False());
                    break;
                case drizzle::Result::Column::INT:
                    value = v8::String::New(currentValue)->ToInteger();
                    break;
                case drizzle::Result::Column::NUMBER:
                    value = v8::Number::New(::atof(currentValue));
                    break;
                case drizzle::Result::Column::DATE:
                    try {
                        value = v8::Date::New(this->toDate(*currentRow[j], false));
                    } catch(const drizzle::Exception&) {
                        value = v8::String::New(currentValue);
                    }
                    break;
                case drizzle::Result::Column::TIME:
                    value = v8::Date::New(this->toTime(*currentRow[j]));
                    break;
                case drizzle::Result::Column::DATETIME:
                    try {
                        value = v8::Date::New(this->toDate(*currentRow[j], true));
                    } catch(const drizzle::Exception&) {
                        value = v8::String::New(currentValue);
                    }
                    break;
                case drizzle::Result::Column::TEXT:
                    value = v8::Local<v8::Value>::New(node::Buffer::New(v8::String::New(currentValue, currentRow[j]->length())));
                    break;
                case drizzle::Result::Column::SET:
                    {
                        v8::Local<v8::Array> values = v8::Array::New();
                        std::istringstream stream(*currentRow[j]);
                        std::string item;
                        uint64_t index = 0;
                        while (std::getline(stream, item, ',')) {
                            if (!item.empty()) {
                                values->Set(v8::Integer::New(index++), v8::String::New(item.c_str()));
                            }
                        }
                        value = values;
                    }
                    break;
                default:
                    value = v8::String::New(currentValue);
                    break;
            }
        } else {
            value = v8::String::New(currentValue);
        }
    } else {
        value = v8::Local<v8::Value>::New(v8::Null());
    }
    row->Set(v8::String::New(currentColumn->getName().c_str()), value);
}

return row;

}

std::string nodedrizzle::Drizzle::parseQuery(const std::string& query, v8::Local<v8::Array> values) const throw(drizzle::Exception&) { std::string parsed(query); std::vector<std::string::sizetype> positions; char quote = 0; bool escaped = false; uint32_t delta = 0;

for (std::string::size_type i = 0, limiti = query.length(); i < limiti; i++) {
    char currentChar = query[i];
    if (escaped) {
        if (currentChar == '?') {
            parsed.replace(i - 1 - delta, 1, "");
            delta++;
        }
        escaped = false;
    } else if (currentChar == '\\') {
        escaped = true;
    } else if (quote && currentChar == quote) {
        quote = 0;
    } else if (!quote && (currentChar == '\'' || currentChar == '"')) {
        quote = currentChar;
    } else if (!quote && currentChar == '?') {
        positions.push_back(i - delta);
    }
}

if (positions.size() != values->Length()) {
    throw drizzle::Exception("Wrong number of values to escape");
}

uint32_t index = 0;
delta = 0;
for (std::vector<std::string::size_type>::iterator iterator = positions.begin(), end = positions.end(); iterator != end; ++iterator, index++) {
    std::string value = this->value(values->Get(index));
    parsed.replace(*iterator + delta, 1, value);
    delta += (value.length() - 1);
}

return parsed;

}

std::string node_drizzle::Drizzle::value(v8::Local<v8::Value> value, bool inArray) const throw(drizzle::Exception&) { std::ostringstream currentStream;

if (value->IsArray()) {
    v8::Local<v8::Array> array = v8::Array::Cast(*value);
    if (!inArray) {
        currentStream << "(";
    }
    for (uint32_t i = 0, limiti = array->Length(); i < limiti; i++) {
        v8::Local<v8::Value> child = array->Get(i);
        if (child->IsArray() && i > 0) {
            currentStream << "),(";
        } else if (i > 0) {
            currentStream << ",";
        }

        currentStream << this->value(child, true);
    }
    if (!inArray) {
        currentStream << ")";
    }
} else if (value->IsDate()) {
    currentStream << '\'' <<  this->fromDate(v8::Date::Cast(*value)->NumberValue()) << '\'';
} else if (value->IsBoolean()) {
    currentStream << (value->IsTrue() ? "1" : "0");
} else if (value->IsNumber()) {
    currentStream << value->ToNumber()->Value();
} else if (value->IsString()) {
    v8::String::Utf8Value currentString(value->ToString());
    std::string string = *currentString;
    currentStream << '\'' <<  this->connection->escape(string) << '\'';
}

return currentStream.str();

}

uint64t nodedrizzle::Drizzle::toDate(const std::string& value, bool hasTime) const throw(drizzle::Exception&) { int day, month, year, hour, min, sec; char sep; std::istringstream stream(value, std::istringstream::in);

if (hasTime) {
    stream >> year >> sep >> month >> sep >> day >> hour >> sep >> min >> sep >> sec;
} else {
    stream >> year >> sep >> month >> sep >> day;
    hour = min = sec = 0;
}

time_t rawtime;
struct tm timeinfo;

time(&rawtime);
if (!localtime_r(&rawtime, &timeinfo)) {
    throw drizzle::Exception("Can't get local time");
}

timeinfo.tm_year = year - 1900;
timeinfo.tm_mon = month - 1;
timeinfo.tm_mday = day;
timeinfo.tm_hour = hour;
timeinfo.tm_min = min;
timeinfo.tm_sec = sec;

return static_cast<uint64_t>((mktime(&timeinfo) + this->gmtDelta()) * 1000);

}

std::string nodedrizzle::Drizzle::fromDate(const uint64t timeStamp) const throw(drizzle::Exception&) { char* buffer = new char[20]; if (buffer == NULL) { throw drizzle::Exception("Can\'t create buffer to write parsed date"); }

struct tm timeinfo;
time_t rawtime = timeStamp / 1000;
if (!localtime_r(&rawtime, &timeinfo)) {
    throw drizzle::Exception("Can't get local time");
}

strftime(buffer, 20, "%Y-%m-%d %H:%M:%S", &timeinfo);

std::string date(buffer);
delete [] buffer;

return date;

}

int nodedrizzle::Drizzle::gmtDelta() const throw(drizzle::Exception&) { int localHour, gmtHour, localMin, gmtMin; timet rawtime; struct tm timeinfo;

time(&rawtime);
if (!localtime_r(&rawtime, &timeinfo)) {
    throw drizzle::Exception("Can't get local time");
}
localHour = timeinfo.tm_hour - (timeinfo.tm_isdst > 0 ? 1 : 0);
localMin = timeinfo.tm_min;

if (!gmtime_r(&rawtime, &timeinfo)) {
    throw drizzle::Exception("Can't get GMT time");
}
gmtHour = timeinfo.tm_hour;
gmtMin = timeinfo.tm_min;

int gmtDelta = ((localHour - gmtHour) * 60 + (localMin - gmtMin)) * 60;
if (gmtDelta <= -(12 * 60 * 60)) {
    gmtDelta += 24 * 60 * 60;
} else if (gmtDelta > (12 * 60 * 60)) {
    gmtDelta -= 24 * 60 * 60;
}

return gmtDelta;

}

uint64t nodedrizzle::Drizzle::toTime(const std::string& value) const { int hour, min, sec; char sep; std::istringstream stream(value, std::istringstream::in);

stream >> hour >> sep >> min >> sep >> sec;

time_t rawtime;
struct tm timeinfo;

time(&rawtime);
if (!localtime_r(&rawtime, &timeinfo)) {
    throw drizzle::Exception("Can't get local time");
}

timeinfo.tm_hour = hour;
timeinfo.tm_min = min;
timeinfo.tm_sec = sec;

return static_cast<uint64_t>((mktime(&timeinfo) + this->gmtDelta()) * 1000);

}

drizzle_bindings.h

./src/drizzle_bindings.h

// Copyright 2011 Mariano Iglesias mgiglesias@gmail.com #ifndef SRCDRIZZLEBINDINGSH #define SRCDRIZZLEBINDINGSH

include <node.h>

define NODE_CONSTANT(constant) v8::Integer::New(constant)

define NODE_ADD_PROTOTYPE_METHOD(templ, name, callback) \

do { \ v8::Local<v8::Signature> callback##_SIG = v8::Signature::New(templ); \ v8::Local<v8::FunctionTemplate> callback##TEM = \ v8::FunctionTemplate::New(callback, v8::Handle<v8::Value>(), \ __callback##SIG); \ templ->PrototypeTemplate()->Set(v8::String::NewSymbol(name), \ __callback##_TEM); \ } while (0)

define ARG_CHECK_OPTIONAL_STRING(I, VAR) \

if (args.Length() > I && !args[I]->IsString()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" must be a valid string"))); \
}

define ARG_CHECK_STRING(I, VAR) \

if (args.Length() <= I) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" is mandatory"))); \
} else if (!args[I]->IsString()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" must be a valid string"))); \
}

define ARG_CHECK_OPTIONAL_OBJECT(I, VAR) \

if (args.Length() > I && (!args[I]->IsObject() || args[I]->IsFunction() || args[I]->IsUndefined())) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" must be a valid object"))); \
}

define ARG_CHECK_OBJECT(I, VAR) \

if (args.Length() <= I) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" is mandatory"))); \
} else if (!args[I]->IsObject() || args[I]->IsFunction() || args[I]->IsUndefined()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" must be a valid object"))); \
}

define ARG_CHECK_OPTIONAL_FUNCTION(I, VAR) \

if (args.Length() > I && !args[I]->IsFunction()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" must be a valid function"))); \
}

define ARG_CHECK_FUNCTION(I, VAR) \

if (args.Length() <= I) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" is mandatory"))); \
} else if (!args[I]->IsFunction()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" must be a valid function"))); \
}

define ARG_CHECK_OPTIONAL_ARRAY(I, VAR) \

if (args.Length() > I && args[I]->IsArray()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" must be a valid array"))); \
}

define ARG_CHECK_ARRAY(I, VAR) \

if (args.Length() <= I) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" is mandatory"))); \
} else if (!args[I]->IsArray()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument \"" #VAR "\" must be a valid array"))); \
}

define ARG_CHECK_OBJECT_ATTR_STRING(VAR, KEY) \

v8::Local<v8::String> KEY##_##key = v8::String::New("" #KEY ""); \
if (!VAR->Has(KEY##_##key)) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" is mandatory"))); \
} else if (!VAR->Get(KEY##_##key)->IsString()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" must be a valid string"))); \
}

define ARG_CHECK_OBJECT_ATTR_OPTIONAL_STRING(VAR, KEY) \

v8::Local<v8::String> KEY##_##key = v8::String::New("" #KEY ""); \
if (VAR->Has(KEY##_##key) && !VAR->Get(KEY##_##key)->IsString()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" must be a valid string"))); \
}

define ARG_CHECK_OBJECT_ATTR_UINT32(VAR, KEY) \

v8::Local<v8::String> KEY##_##key = v8::String::New("" #KEY ""); \
if (!VAR->Has(KEY##_##key)) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" is mandatory"))); \
} else if (!VAR->Get(KEY##_##key)->IsUint32()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" must be a valid UINT32"))); \
}

define ARG_CHECK_OBJECT_ATTR_OPTIONAL_UINT32(VAR, KEY) \

v8::Local<v8::String> KEY##_##key = v8::String::New("" #KEY ""); \
if (VAR->Has(KEY##_##key) && !VAR->Get(KEY##_##key)->IsUint32()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" must be a valid UINT32"))); \
}

define ARG_CHECK_OBJECT_ATTR_BOOL(VAR, KEY) \

v8::Local<v8::String> KEY##_##key = v8::String::New("" #KEY ""); \
if (!VAR->Has(KEY##_##key)) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" is mandatory"))); \
} else if (!VAR->Get(KEY##_##key)->IsBoolean()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" must be a valid boolean"))); \
}

define ARG_CHECK_OBJECT_ATTR_OPTIONAL_BOOL(VAR, KEY) \

v8::Local<v8::String> KEY##_##key = v8::String::New("" #KEY ""); \
if (VAR->Has(KEY##_##key) && !VAR->Get(KEY##_##key)->IsBoolean()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" must be a valid boolean"))); \
}

define ARG_CHECK_OBJECT_ATTR_FUNCTION(VAR, KEY) \

v8::Local<v8::String> KEY##_##key = v8::String::New("" #KEY ""); \
if (!VAR->Has(KEY##_##key)) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" is mandatory"))); \
} else if (!VAR->Get(KEY##_##key)->IsFunction()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" must be a valid function"))); \
}

define ARG_CHECK_OBJECT_ATTR_OPTIONAL_FUNCTION(VAR, KEY) \

v8::Local<v8::String> KEY##_##key = v8::String::New("" #KEY ""); \
if (VAR->Has(KEY##_##key) && !VAR->Get(KEY##_##key)->IsFunction()) { \
    return v8::ThrowException(v8::Exception::Error(v8::String::New("Option \"" #KEY "\" must be a valid function"))); \
}

endif // SRC_DRIZZLE_BINDINGS_H_

drizzle_bindings.cc

./src/drizzle_bindings.cc

// Copyright 2011 Mariano Iglesias mgiglesias@gmail.com #include "./drizzle_bindings.h" #include "./drizzle.h"

extern "C" { void init(v8::Handle<v8::Object> target) { node_drizzle::Drizzle::Init(target); }

NODE_MODULE(drizzle_bindings, init);

}

drizzle

./drizzle.js