nodejs-db-informix  master
nodejs bindings for Informix
 All Classes Functions Pages
binding.cxx
1 #include "binding.h"
2 
3 
4 /**
5  *
6  */
7 nodejs_db::Binding::Binding() : nodejs_db::EventEmitter()
8  , connection(NULL)
9  , cbConnect(NULL)
10 {}
11 
12 
13 /**
14  *
15  */
16 nodejs_db::Binding::~Binding() {
17  if (this->cbConnect != NULL) {
18  node::cb_destroy(this->cbConnect);
19  }
20 }
21 
22 #if NODE_VERSION_AT_LEAST(0, 7, 8)
23 uv_async_t nodejs_db::Binding::g_async;
24 #endif
25 
26 
27 /**
28  * \fn Initialise the constructor for Bindings.
29  *
30  */
31 void nodejs_db::Binding::Init(v8::Handle<v8::Object> target
32  , v8::Persistent<v8::FunctionTemplate> constructorTemplate
33 ) {
34  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_STRING,
35  nodejs_db::Result::Column::STRING);
36  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_TEXT,
37  nodejs_db::Result::Column::TEXT);
38  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_INT,
39  nodejs_db::Result::Column::INT);
40  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_NUMBER,
41  nodejs_db::Result::Column::NUMBER);
42  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_MONEY,
43  nodejs_db::Result::Column::MONEY);
44  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_DATE,
45  nodejs_db::Result::Column::DATE);
46  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_TIME,
47  nodejs_db::Result::Column::TIME);
48  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_INTERVAL,
49  nodejs_db::Result::Column::INTERVAL);
50  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_DATETIME,
51  nodejs_db::Result::Column::DATETIME);
52  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_BOOL,
53  nodejs_db::Result::Column::BOOL);
54  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_BLOB,
55  nodejs_db::Result::Column::BLOB);
56  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_SET,
57  nodejs_db::Result::Column::SET);
58  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_ROW,
59  nodejs_db::Result::Column::ROW);
60  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_COLLECTION,
61  nodejs_db::Result::Column::COLLECTION);
62  NODE_ADD_CONSTANT(constructorTemplate, COLUMN_TYPE_CONSTRUCTED,
63  nodejs_db::Result::Column::CONSTRUCTED);
64 
65  NODE_ADD_PROTOTYPE_METHOD(constructorTemplate, "connect", Connect);
66  NODE_ADD_PROTOTYPE_METHOD(constructorTemplate, "disconnect", Disconnect);
67  NODE_ADD_PROTOTYPE_METHOD(constructorTemplate, "isConnected", IsConnected);
68  NODE_ADD_PROTOTYPE_METHOD(constructorTemplate, "escape", Escape);
69  NODE_ADD_PROTOTYPE_METHOD(constructorTemplate, "name", Name);
70  NODE_ADD_PROTOTYPE_METHOD(constructorTemplate, "query", Query);
71 }
72 
73 
74 /**
75  *
76  */
77 v8::Handle<v8::Value>
78 nodejs_db::Binding::Connect(const v8::Arguments& args) {
79  v8::HandleScope scope;
80 
81  nodejs_db::Binding* binding =
82  node::ObjectWrap::Unwrap<nodejs_db::Binding>(args.This());
83  assert(binding);
84 
85  bool async = true;
86  int optionsIndex = -1,
87  callbackIndex = -1;
88 
89  if (args.Length() > 0) {
90  if (args.Length() > 1) {
91  ARG_CHECK_OBJECT(0, options);
92  ARG_CHECK_FUNCTION(1, callback);
93  optionsIndex = 0;
94  callbackIndex = 1;
95  } else if (args[0]->IsFunction()) {
96  ARG_CHECK_FUNCTION(0, callback);
97  callbackIndex = 0;
98  } else {
99  ARG_CHECK_OBJECT(0, options);
100  optionsIndex = 0;
101  }
102 
103  if (optionsIndex >= 0) {
104  v8::Local<v8::Object> options = args[optionsIndex]->ToObject();
105 
106  v8::Handle<v8::Value> set = binding->set(options);
107  if (!set.IsEmpty()) {
108  return scope.Close(set);
109  }
110 
111  ARG_CHECK_OBJECT_ATTR_OPTIONAL_BOOL(options, async);
112 
113  if (options->Has(async_key) && options->Get(async_key)->IsFalse()) {
114  async = false;
115  }
116  }
117 
118  if (callbackIndex >= 0) {
119  binding->cbConnect = node::cb_persist(args[callbackIndex]);
120  }
121  }
122 
123  connect_request_t* request = new connect_request_t();
124  if (request == NULL) {
125  THROW_EXCEPTION("Could not create UV request")
126  }
127 
128  request->context = v8::Persistent<v8::Object>::New(args.This());
129  request->binding = binding;
130  request->error = NULL;
131 
132  if (async) {
133  request->binding->Ref();
134 
135  uv_work_t* req = new uv_work_t();
136  req->data = request;
137  uv_queue_work(uv_default_loop(), req, uvConnect, (uv_after_work_cb)uvConnectFinished);
138 
139 #if NODE_VERSION_AT_LEAST(0, 7, 9)
140  uv_ref((uv_handle_t *)&g_async);
141 #else
142  uv_ref(uv_default_loop());
143 #endif // NODE_VERSION_AT_LEAST(0, 7, 9)
144 
145  } else {
146  connect(request);
147  connectFinished(request);
148  }
149 
150  return scope.Close(v8::Undefined());
151 }
152 
153 
154 /**
155  *
156  */
157 void nodejs_db::Binding::connect(connect_request_t* request) {
158  try {
159  request->binding->connection->open();
160  } catch(const nodejs_db::Exception& exception) {
161  request->error = exception.what();
162  }
163 }
164 
165 
166 /**
167  *
168  */
169 void nodejs_db::Binding::connectFinished(connect_request_t* request) {
170  bool connected = request->binding->connection->isAlive();
171  v8::Local<v8::Value> argv[2];
172 
173  if (connected) {
174  v8::Local<v8::Object> server = v8::Object::New();
175  server->Set(v8::String::New("version"), v8::String::New(request->binding->connection->version().c_str()));
176  server->Set(v8::String::New("hostname"), v8::String::New(request->binding->connection->getHostname().c_str()));
177  server->Set(v8::String::New("user"), v8::String::New(request->binding->connection->getUser().c_str()));
178  server->Set(v8::String::New("database"), v8::String::New(request->binding->connection->getDatabase().c_str()));
179 
180  argv[0] = v8::Local<v8::Value>::New(v8::Null());
181  argv[1] = server;
182 
183  request->binding->Emit("ready", 1, &argv[1]);
184  } else {
185  argv[0] = v8::String::New(request->error != NULL ? request->error : "(unknown error)");
186 
187  request->binding->Emit("error", 1, argv);
188  }
189 
190  if (request->binding->cbConnect != NULL && !request->binding->cbConnect->IsEmpty()) {
191  v8::TryCatch tryCatch;
192  (*(request->binding->cbConnect))->Call(request->context, connected ? 2 : 1, argv);
193  if (tryCatch.HasCaught()) {
194  node::FatalException(tryCatch);
195  }
196  }
197 
198  request->context.Dispose();
199 
200  delete request;
201 }
202 
203 
204 /**
205  *
206  */
207 void nodejs_db::Binding::uvConnect(uv_work_t* uvRequest) {
208  connect_request_t* request = static_cast<connect_request_t*>(uvRequest->data);
209  assert(request);
210 
211  request->binding->connection->lock();
212  connect(request);
213  request->binding->connection->unlock();
214 }
215 
216 
217 /**
218  *
219  */
220 void nodejs_db::Binding::uvConnectFinished(uv_work_t* uvRequest, int status) {
221  v8::HandleScope scope;
222 
223  connect_request_t* request = static_cast<connect_request_t*>(uvRequest->data);
224  assert(request);
225 
226 #if NODE_VERSION_AT_LEAST(0, 7, 9)
227  uv_unref((uv_handle_t *)&g_async);
228 #else
229  uv_unref(uv_default_loop());
230 #endif
231 
232  request->binding->Unref();
233 
234  connectFinished(request);
235 }
236 
237 
238 /**
239  *
240  */
241 v8::Handle<v8::Value> nodejs_db::Binding::Disconnect(const v8::Arguments& args) {
242  v8::HandleScope scope;
243 
244  nodejs_db::Binding* binding = node::ObjectWrap::Unwrap<nodejs_db::Binding>(args.This());
245  assert(binding);
246 
247  try {
248  binding->connection->lock();
249  binding->connection->close();
250  binding->connection->unlock();
251  } catch(const nodejs_db::Exception& exception) {
252  binding->connection->unlock();
253  }
254 
255  return scope.Close(v8::Undefined());
256 }
257 
258 
259 /**
260  *
261  */
262 v8::Handle<v8::Value> nodejs_db::Binding::IsConnected(const v8::Arguments& args) {
263  v8::HandleScope scope;
264 
265  nodejs_db::Binding* binding = node::ObjectWrap::Unwrap<nodejs_db::Binding>(args.This());
266  assert(binding);
267 
268  return scope.Close(binding->connection->isAlive() ? v8::True() : v8::False());
269 }
270 
271 
272 /**
273  *
274  */
275 v8::Handle<v8::Value> nodejs_db::Binding::Escape(const v8::Arguments& args) {
276  v8::HandleScope scope;
277 
278  ARG_CHECK_STRING(0, string);
279 
280  nodejs_db::Binding* binding = node::ObjectWrap::Unwrap<nodejs_db::Binding>(args.This());
281  assert(binding);
282 
283  std::string escaped;
284 
285  try {
286  v8::String::Utf8Value string(args[0]->ToString());
287  std::string unescaped(*string);
288  escaped = binding->connection->escape(unescaped);
289  } catch(const nodejs_db::Exception& exception) {
290  THROW_EXCEPTION(exception.what())
291  }
292 
293  return scope.Close(v8::String::New(escaped.c_str()));
294 }
295 
296 
297 /**
298  *
299  */
300 v8::Handle<v8::Value>
301 nodejs_db::Binding::Name(const v8::Arguments& args) {
302  v8::HandleScope scope;
303 
304  ARG_CHECK_STRING(0, table);
305 
306  nodejs_db::Binding* binding = node::ObjectWrap::Unwrap<nodejs_db::Binding>(args.This());
307  assert(binding);
308 
309  std::ostringstream escaped;
310 
311  try {
312  v8::String::Utf8Value string(args[0]->ToString());
313  std::string unescaped(*string);
314  escaped << binding->connection->escapeName(unescaped);
315  } catch(const nodejs_db::Exception& exception) {
316  THROW_EXCEPTION(exception.what())
317  }
318 
319  return scope.Close(v8::String::New(escaped.str().c_str()));
320 }
321 
322 
323 /**
324  * Bind the query object
325  */
326 v8::Handle<v8::Value>
327 nodejs_db::Binding::Query(const v8::Arguments& args) {
328  v8::HandleScope scope;
329 
330  nodejs_db::Binding* binding =
331  node::ObjectWrap::Unwrap<nodejs_db::Binding>(args.This());
332 
333  assert(binding);
334 
335  v8::Persistent<v8::Object> query = binding->createQuery();
336  if (query.IsEmpty()) {
337  THROW_EXCEPTION("Could not create query");
338  }
339 
340  nodejs_db::Query* queryInstance =
341  node::ObjectWrap::Unwrap<nodejs_db::Query>(query);
342  queryInstance->setConnection(binding->connection);
343 
344  v8::Handle<v8::Value> set = queryInstance->set(args);
345  if (!set.IsEmpty()) {
346  return scope.Close(set);
347  }
348 
349  return scope.Close(query);
350 }