Skip to content
Browse files

Refactoring so value placeholders can easily be extended

  • Loading branch information...
1 parent 7ef22e6 commit 82ddda0843dc36d17085377cced1625a5b33c438 @mariano committed Jun 2, 2011
Showing with 86 additions and 58 deletions.
  1. +1 −1 connection.h
  2. +39 −31 query.cc
  3. +6 −3 query.h
  4. +40 −23 tests.js
View
2 connection.h
@@ -26,7 +26,7 @@ class Connection {
virtual void setDatabase(const std::string& database);
virtual uint32_t getPort() const;
virtual void setPort(uint32_t port);
- virtual bool isAlive(bool ping=false);
+ virtual bool isAlive(bool ping = false);
virtual std::string escapeName(const std::string& string) const throw(Exception&);
virtual void open() throw(Exception&) = 0;
virtual void close() = 0;
View
70 query.cc
@@ -34,7 +34,10 @@ node_db::Query::Query(): node::EventEmitter(),
}
node_db::Query::~Query() {
- this->values.Dispose();
+ for (std::vector< v8::Persistent<v8::Value> >::iterator iterator = this->values.begin(), end = this->values.end(); iterator != end; ++iterator) {
+ iterator->Dispose();
+ }
+
if (this->cbStart != NULL) {
node::cb_destroy(this->cbStart);
}
@@ -181,15 +184,11 @@ v8::Handle<v8::Value> node_db::Query::Join(const v8::Arguments& args) {
if (join->Has(conditions_key)) {
v8::String::Utf8Value conditions(join->Get(conditions_key)->ToObject());
std::string currentConditions = *conditions;
- v8::Local<v8::Array> currentValues;
if (args.Length() > 1) {
- currentValues = v8::Array::Cast(*args[1]);
- }
-
- try {
- currentConditions = query->parseQuery(currentConditions, *currentValues);
- } catch(const node_db::Exception& exception) {
- THROW_EXCEPTION(exception.what())
+ v8::Local<v8::Array> currentValues = v8::Array::Cast(*args[1]);
+ for (uint32_t i = 0, limiti = currentValues->Length(); i < limiti; i++) {
+ query->values.push_back(v8::Persistent<v8::Value>::New(currentValues->Get(i)));
+ }
}
query->sql << " ON (" << currentConditions << ")";
@@ -601,10 +600,10 @@ v8::Handle<v8::Value> node_db::Query::Execute(const v8::Arguments& args) {
}
}
- std::string sql = query->sql.str();
+ std::string sql;
try {
- sql = query->parseQuery(sql, *(query->values));
+ sql = query->parseQuery();
} catch(const node_db::Exception& exception) {
THROW_EXCEPTION(exception.what())
}
@@ -662,7 +661,7 @@ int node_db::Query::eioExecute(eio_req* eioRequest) {
try {
request->query->connection->lock();
- request->result = request->query->connection->query(request->query->sql.str());
+ request->result = request->query->execute();
request->query->connection->unlock();
if (!request->result->isEmpty() && request->result != NULL) {
@@ -821,7 +820,7 @@ void node_db::Query::executeAsync(execute_request_t* request) {
bool freeAll = true;
try {
this->connection->lock();
- request->result = this->connection->query(this->sql.str());
+ request->result = this->execute();
this->connection->unlock();
if (request->result != NULL) {
@@ -855,7 +854,7 @@ void node_db::Query::executeAsync(execute_request_t* request) {
while (request->result->hasNext()) {
row.columnLengths = (unsigned long*) request->result->columnLengths();
- row.columns = (char**) request->result->next();
+ row.columns = reinterpret_cast<char**>(request->result->next());
v8::Local<v8::Object> jsRow = this->row(request->result, &row);
v8::Local<v8::Value> eachArgv[3];
@@ -911,6 +910,10 @@ void node_db::Query::executeAsync(execute_request_t* request) {
Query::freeRequest(request, freeAll);
}
+node_db::Result* node_db::Query::execute() const throw(node_db::Exception&) {
+ return this->connection->query(this->sql.str());
+}
+
void node_db::Query::freeRequest(execute_request_t* request, bool freeAll) {
if (request->rows != NULL) {
for (std::vector<row_t*>::iterator iterator = request->rows->begin(), end = request->rows->end(); iterator != end; ++iterator) {
@@ -1057,7 +1060,9 @@ v8::Handle<v8::Value> node_db::Query::set(const v8::Arguments& args) {
if (valuesIndex >= 0) {
v8::Local<v8::Array> values = v8::Array::Cast(*args[valuesIndex]);
- this->values = v8::Persistent<v8::Array>::New(values);
+ for (uint32_t i = 0, limiti = values->Length(); i < limiti; i++) {
+ this->values.push_back(v8::Persistent<v8::Value>::New(values->Get(i)));
+ }
}
if (callbackIndex >= 0) {
@@ -1178,15 +1183,11 @@ v8::Handle<v8::Value> node_db::Query::addCondition(const v8::Arguments& args, co
v8::String::Utf8Value conditions(args[0]->ToString());
std::string currentConditions = *conditions;
- v8::Local<v8::Array> currentValues;
if (args.Length() > 1) {
- currentValues = v8::Array::Cast(*args[1]);
- }
-
- try {
- currentConditions = this->parseQuery(currentConditions, *currentValues);
- } catch(const node_db::Exception& exception) {
- THROW_EXCEPTION(exception.what())
+ v8::Local<v8::Array> currentValues = v8::Array::Cast(*args[1]);
+ for (uint32_t i = 0, limiti = currentValues->Length(); i < limiti; i++) {
+ this->values.push_back(v8::Persistent<v8::Value>::New(currentValues->Get(i)));
+ }
}
this->sql << " " << separator << " ";
@@ -1313,18 +1314,20 @@ v8::Local<v8::Object> node_db::Query::row(node_db::Result* result, row_t* curren
return row;
}
-std::string node_db::Query::parseQuery(const std::string& query, v8::Array* values) const throw(node_db::Exception&) {
- std::string parsed(query);
+std::vector<std::string::size_type> node_db::Query::placeholders(std::string* parsed) const throw(node_db::Exception&) {
+ std::string query = this->sql.str();
std::vector<std::string::size_type> positions;
char quote = 0;
bool escaped = false;
uint32_t delta = 0;
+ *parsed = query;
+
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, "");
+ parsed->replace(i - 1 - delta, 1, "");
delta++;
}
escaped = false;
@@ -1339,15 +1342,20 @@ std::string node_db::Query::parseQuery(const std::string& query, v8::Array* valu
}
}
- uint32_t valuesLength = values != NULL ? values->Length() : 0;
- if (positions.size() != valuesLength) {
+ if (positions.size() != this->values.size()) {
throw node_db::Exception("Wrong number of values to escape");
}
- uint32_t index = 0;
- delta = 0;
+ return positions;
+}
+
+std::string node_db::Query::parseQuery() const throw(node_db::Exception&) {
+ std::string parsed;
+ std::vector<std::string::size_type> positions = this->placeholders(&parsed);
+
+ 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));
+ std::string value = this->value(*(this->values[index]));
parsed.replace(*iterator + delta, 1, value);
delta += (value.length() - 1);
}
View
9 query.h
@@ -39,10 +39,10 @@ class Query : public node::EventEmitter {
};
Connection* connection;
std::ostringstream sql;
+ std::vector< v8::Persistent<v8::Value> > values;
bool async;
bool cast;
bool bufferText;
- v8::Persistent<v8::Array> values;
v8::Persistent<v8::Function>* cbStart;
v8::Persistent<v8::Function>* cbExecute;
v8::Persistent<v8::Function>* cbFinish;
@@ -72,12 +72,15 @@ class Query : public node::EventEmitter {
void executeAsync(execute_request_t* request);
static void freeRequest(execute_request_t* request, bool freeAll = true);
std::string fieldName(v8::Local<v8::Value> value) const throw(Exception&);
- std::string tableName(v8::Local<v8::Value> value, bool escape=true) const throw(Exception&);
+ std::string tableName(v8::Local<v8::Value> value, bool escape = true) const throw(Exception&);
v8::Handle<v8::Value> addCondition(const v8::Arguments& args, const char* separator);
v8::Local<v8::Object> row(Result* result, row_t* currentRow) const;
- std::string parseQuery(const std::string& query, v8::Array* values) const throw(Exception&);
+ virtual std::string parseQuery() const throw(Exception&);
+ virtual std::vector<std::string::size_type> placeholders(std::string* parsed) const throw(Exception&);
+ virtual Result* execute() const throw(Exception&);
std::string value(v8::Local<v8::Value> value, bool inArray = false, bool escape = true) const throw(Exception&);
+
private:
static bool gmtDeltaLoaded;
static int gmtDelta;
View
63 tests.js
@@ -364,23 +364,27 @@ exports.get = function(createDbClient) {
test.throws(
function () {
- client.query().where("id = ?");
+ client.query().where("id = ?").execute({ start: function (query) { return false; } });
},
"Wrong number of values to escape"
);
test.throws(
function () {
- client.query().where("id = ?", []);
+ client.query().where("id = ?", []).execute({ start: function (query) { return false; } });
},
"Wrong number of values to escape"
);
- query = client.query().where("id=?", [ 1 ]).sql();
- test.equal(" WHERE id=1", query);
+ query = client.query().where("id=?", [ 1 ]).execute({ start: function (query) {
+ test.equal(" WHERE id=1", query);
+ return false;
+ }});
- query = client.query().where("(id=? OR name=?) AND created > ?", [ 1, "Janine O'Hara", new Date(2011,2,12,20,15,0) ]).sql();
- test.equal(" WHERE (id=1 OR name='Janine O\\'Hara') AND created > '2011-03-12 20:15:00'", query);
+ query = client.query().where("(id=? OR name=?) AND created > ?", [ 1, "Janine O'Hara", new Date(2011,2,12,20,15,0) ]).execute({ start: function (query) {
+ test.equal(" WHERE (id=1 OR name='Janine O\\'Hara') AND created > '2011-03-12 20:15:00'", query);
+ return false;
+ }});
query = client.query().where("1=1").and("2=2").sql();
test.equal(" WHERE 1=1 AND 2=2", query);
@@ -423,7 +427,7 @@ exports.get = function(createDbClient) {
"table": "profiles",
"alias": "p",
"conditions": "p.id = u.profile_id"
- }, [ 1, new Date(2011, 2, 12, 19, 49, 0) ]);
+ }, [ 1, new Date(2011, 2, 12, 19, 49, 0) ]).execute({ start: function (query) { return false; } });
},
"Wrong number of values to escape"
);
@@ -435,8 +439,10 @@ exports.get = function(createDbClient) {
"conditions": "p.id = u.profile_id AND approved = ? AND created >= ?"
},
[ 1, new Date(2011, 2, 12, 19, 49, 0) ]
- ).sql();
- test.equal(" INNER JOIN `profiles` AS `p` ON (p.id = u.profile_id AND approved = 1 AND created >= '2011-03-12 19:49:00')", query);
+ ).execute({ start: function (query) {
+ test.equal(" INNER JOIN `profiles` AS `p` ON (p.id = u.profile_id AND approved = 1 AND created >= '2011-03-12 19:49:00')", query);
+ return false;
+ }});
query = client.query().join({
"type": "left",
@@ -650,9 +656,10 @@ exports.get = function(createDbClient) {
join({"table": "profiles", "alias": "p", "conditions": "p.id=users.profile_id"}).
where("created > ?", [ new Date(2011,02,12,20,16,0) ]).
limit(10).
- sql();
-
- test.equal("SELECT * FROM `users` INNER JOIN `profiles` AS `p` ON (p.id=users.profile_id) WHERE created > '2011-03-12 20:16:00' LIMIT 10", query);
+ execute({ start: function (query) {
+ test.equal("SELECT * FROM `users` INNER JOIN `profiles` AS `p` ON (p.id=users.profile_id) WHERE created > '2011-03-12 20:16:00' LIMIT 10", query);
+ return false;
+ }});
query = client.query().
select("*").
@@ -661,16 +668,18 @@ exports.get = function(createDbClient) {
select(["id"]).
from("profiles")
]).
- sql();
- test.equal("SELECT * FROM `users` WHERE id IN (SELECT `id` FROM `profiles`)", query);
+ execute({ start: function (query) {
+ test.equal("SELECT * FROM `users` WHERE id IN (SELECT `id` FROM `profiles`)", query);
+ return false;
+ }});
test.throws(
function () {
sql = client.query().
select("*").
from("users").
where("id IN ?", [ { "test": "value" }]).
- sql();
+ execute({ start: function (query) { return false; }});
},
"Objects can't be converted to a SQL value"
);
@@ -685,16 +694,20 @@ exports.get = function(createDbClient) {
delete().
from("users").
where("created > ?", [ new Date(2011,02,12,20,16,0) ]).
- sql();
- test.equal("DELETE FROM `users` WHERE created > '2011-03-12 20:16:00'", query);
+ execute({ start: function (query) {
+ test.equal("DELETE FROM `users` WHERE created > '2011-03-12 20:16:00'", query);
+ return false;
+ }});
query = client.query().
delete("users").
from("users").
join({"table": "profiles", "alias": "p", "conditions": "p.id=users.profile_id"}).
where("created > ?", [ new Date(2011,02,12,20,16,0) ]).
- sql();
- test.equal("DELETE `users` FROM `users` INNER JOIN `profiles` AS `p` ON (p.id=users.profile_id) WHERE created > '2011-03-12 20:16:00'", query);
+ execute({ start: function (query) {
+ test.equal("DELETE `users` FROM `users` INNER JOIN `profiles` AS `p` ON (p.id=users.profile_id) WHERE created > '2011-03-12 20:16:00'", query);
+ return false;
+ }});
test.done();
},
@@ -709,8 +722,10 @@ exports.get = function(createDbClient) {
join({"table": "profiles", "alias": "p", "conditions": "p.id=users.profile_id"}).
where("created > ?", [ new Date(2011,02,12,20,16,0) ]).
limit(10).
- sql();
- test.equal("INSERT INTO `profiles`(`name`,`age`,`created`) SELECT `name`,32 AS `value`,`created` FROM `users` INNER JOIN `profiles` AS `p` ON (p.id=users.profile_id) WHERE created > '2011-03-12 20:16:00' LIMIT 10", query);
+ execute({ start: function (query) {
+ test.equal("INSERT INTO `profiles`(`name`,`age`,`created`) SELECT `name`,32 AS `value`,`created` FROM `users` INNER JOIN `profiles` AS `p` ON (p.id=users.profile_id) WHERE created > '2011-03-12 20:16:00' LIMIT 10", query);
+ return false;
+ }});
test.done();
},
@@ -724,8 +739,10 @@ exports.get = function(createDbClient) {
set({ "name": "New Name" }).
where("created > ?", [ new Date(2011,02,12,20,16,0) ]).
limit(10).
- sql();
- test.equal("UPDATE `users` INNER JOIN `profiles` AS `p` ON (p.id=users.profile_id) SET `name`='New Name' WHERE created > '2011-03-12 20:16:00' LIMIT 10", query);
+ execute({ start: function (query) {
+ test.equal("UPDATE `users` INNER JOIN `profiles` AS `p` ON (p.id=users.profile_id) SET `name`='New Name' WHERE created > '2011-03-12 20:16:00' LIMIT 10", query);
+ return false;
+ }});
test.done();
}

0 comments on commit 82ddda0

Please sign in to comment.
Something went wrong with that request. Please try again.