[Pkg-javascript-commits] [node-leveldown] 231/492: move createIterator to db.iterator, add tests

Andrew Kelley andrewrk-guest at moszumanska.debian.org
Sun Jul 6 17:14:02 UTC 2014


This is an automated email from the git hooks/post-receive script.

andrewrk-guest pushed a commit to annotated tag rocksdb-0.10.1
in repository node-leveldown.

commit 9468c5800c983d9aadff9c9162e81ce1aad9d2e4
Author: Rod Vagg <rod at vagg.org>
Date:   Sat Feb 23 21:44:30 2013 +1100

    move createIterator to db.iterator, add tests
---
 src/async.cc          |  10 ++--
 src/database.cc       |  15 ++++++
 src/database.h        |   1 +
 src/iterator.cc       | 140 ++++++++++++++++++++++++++++++++++++--------------
 src/iterator.h        |  37 ++++---------
 src/iterator_async.cc |  17 +++---
 src/iterator_async.h  |   6 +--
 src/leveldown.cc      |   2 -
 src/leveldown.h       |  29 +++++------
 test/iterator-test.js |  92 +++++++++++++++++++++++++++++++++
 10 files changed, 250 insertions(+), 99 deletions(-)

diff --git a/src/async.cc b/src/async.cc
index dcd6ca5..8bc4297 100644
--- a/src/async.cc
+++ b/src/async.cc
@@ -14,9 +14,13 @@ namespace leveldown {
 
 /** ASYNC BASE **/
 
-AsyncWorker::AsyncWorker (Database* database, v8::Persistent<v8::Function> callback)
-    : database(database), callback(callback) {
-  request.data = this;
+AsyncWorker::AsyncWorker (
+    Database* database
+  , v8::Persistent<v8::Function> callback
+) : database(database)
+  , callback(callback)
+{
+    request.data = this;
 };
 
 AsyncWorker::~AsyncWorker () {}
diff --git a/src/database.cc b/src/database.cc
index 36415eb..872a1e6 100644
--- a/src/database.cc
+++ b/src/database.cc
@@ -132,6 +132,10 @@ void Database::Init () {
       v8::String::NewSymbol("approximateSize")
     , v8::FunctionTemplate::New(ApproximateSize)->GetFunction()
   );
+  tpl->PrototypeTemplate()->Set(
+      v8::String::NewSymbol("iterator")
+    , v8::FunctionTemplate::New(Iterator)->GetFunction()
+  );
   constructor = v8::Persistent<v8::Function>::New(tpl->GetFunction());
 }
 
@@ -395,4 +399,15 @@ v8::Handle<v8::Value> Database::ApproximateSize (const v8::Arguments& args) {
   return v8::Undefined();
 }
 
+v8::Handle<v8::Value> Database::Iterator (const v8::Arguments& args) {
+  v8::HandleScope scope;
+
+  v8::Local<v8::Object> optionsObj;
+  if (args.Length() > 0 && args[1]->IsObject()) {
+    optionsObj = v8::Local<v8::Object>::Cast(args[1])  ;
+  }
+
+  return scope.Close(Iterator::NewInstance(args.This(), optionsObj));
+}
+
 } // namespace leveldown
diff --git a/src/database.h b/src/database.h
index 31768e6..ae070b8 100644
--- a/src/database.h
+++ b/src/database.h
@@ -73,6 +73,7 @@ private:
   LU_V8_METHOD( Delete   )
   LU_V8_METHOD( Get      )
   LU_V8_METHOD( Batch    )
+  LU_V8_METHOD( Iterator )
   LU_V8_METHOD( ApproximateSize )
 };
 
diff --git a/src/iterator.cc b/src/iterator.cc
index 06dfec7..e132367 100644
--- a/src/iterator.cc
+++ b/src/iterator.cc
@@ -12,6 +12,46 @@
 
 namespace leveldown {
 
+Iterator::Iterator (
+    Database* database
+  , leveldb::Slice* start
+  , std::string* end
+  , bool reverse
+  , bool keys
+  , bool values
+  , int limit
+  , bool fillCache
+  , bool keyAsBuffer
+  , bool valueAsBuffer
+  , v8::Persistent<v8::Value> startPtr
+) : database(database)
+  , start(start)
+  , end(end)
+  , reverse(reverse)
+  , keys(keys)
+  , values(values)
+  , limit(limit)
+  , keyAsBuffer(keyAsBuffer)
+  , valueAsBuffer(valueAsBuffer)
+  , startPtr(startPtr)
+{
+  options    = new leveldb::ReadOptions();
+  options->fill_cache = fillCache;
+  dbIterator = NULL;
+  count      = 0;
+  nexting    = false;
+  ended      = false;
+  endWorker  = NULL;
+};
+
+
+Iterator::~Iterator () {
+  delete options;
+  startPtr.Dispose();
+  if (end != NULL)
+    delete end;
+};
+
 bool Iterator::GetIterator () {
   if (dbIterator == NULL) {
     dbIterator = database->NewIterator(options);
@@ -75,6 +115,10 @@ v8::Handle<v8::Value> Iterator::Next (const v8::Arguments& args) {
   v8::HandleScope scope;
   Iterator* iterator = node::ObjectWrap::Unwrap<Iterator>(args.This());
 
+  if (args.Length() == 0 || !args[0]->IsFunction()) {
+    THROW_RETURN("next() requires a callback argument")
+  }
+
   if (iterator->ended) {
     THROW_RETURN("Cannot call next() after end()")
   }
@@ -83,19 +127,17 @@ v8::Handle<v8::Value> Iterator::Next (const v8::Arguments& args) {
     THROW_RETURN("Cannot call next() before previous next() has completed")
   }
 
-  v8::Persistent<v8::Function> endCallback =
+  v8::Persistent<v8::Function> callback =
       v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(args[0]));
-  v8::Persistent<v8::Function> dataCallback =
-      v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(args[1]));
 
   NextWorker* worker = new NextWorker(
       iterator
-    , dataCallback
-    , endCallback
+    , callback
     , checkEndCallback
   );
   iterator->nexting = true;
   AsyncQueueWorker(worker);
+
   return v8::Undefined();
 }
 
@@ -103,23 +145,30 @@ v8::Handle<v8::Value> Iterator::End (const v8::Arguments& args) {
   v8::HandleScope scope;
   Iterator* iterator = node::ObjectWrap::Unwrap<Iterator>(args.This());
 
+  if (args.Length() == 0 || !args[0]->IsFunction()) {
+    THROW_RETURN("end() requires a callback argument")
+  }
+
   if (iterator->ended) {
     THROW_RETURN("end() already called on iterator")
   }
 
   v8::Persistent<v8::Function> callback =
       v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(args[0]));
+
   EndWorker* worker = new EndWorker(
       iterator
     , callback
   );
   iterator->ended = true;
+
   if (iterator->nexting) {
     // waiting for a next() to return, queue the end
     iterator->endWorker = worker;
   } else {
     AsyncQueueWorker(worker);
   }
+
   return v8::Undefined();
 }
 
@@ -128,7 +177,7 @@ v8::Persistent<v8::Function> Iterator::constructor;
 void Iterator::Init () {
   v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(New);
   tpl->SetClassName(v8::String::NewSymbol("Iterator"));
-  tpl->InstanceTemplate()->SetInternalFieldCount(2);
+  tpl->InstanceTemplate()->SetInternalFieldCount(1);
   tpl->PrototypeTemplate()->Set(
       v8::String::NewSymbol("next")
     , v8::FunctionTemplate::New(Next)->GetFunction()
@@ -140,14 +189,21 @@ void Iterator::Init () {
   constructor = v8::Persistent<v8::Function>::New(tpl->GetFunction());
 }
 
-v8::Handle<v8::Value> Iterator::NewInstance (const v8::Arguments& args) {
+v8::Handle<v8::Value> Iterator::NewInstance (
+        v8::Handle<v8::Object> database
+      , v8::Handle<v8::Object> optionsObj
+    ) {
+
   v8::HandleScope scope;
+  v8::Local<v8::Object> instance;
 
-  v8::Handle<v8::Value> argv[2] = {
-      args[0]->ToObject()
-    , args[1]->ToObject()
-  };
-  v8::Local<v8::Object> instance = constructor->NewInstance(2, argv);
+  if (optionsObj.IsEmpty()) {
+    v8::Handle<v8::Value> argv[1] = { database };
+    instance = constructor->NewInstance(1, argv);
+  } else {
+    v8::Handle<v8::Value> argv[2] = { database, optionsObj };
+    instance = constructor->NewInstance(2, argv);
+  }
 
   return scope.Close(instance);
 }
@@ -159,36 +215,48 @@ v8::Handle<v8::Value> Iterator::New (const v8::Arguments& args) {
   v8::Local<v8::Function> callback;
 
   Database* database = node::ObjectWrap::Unwrap<Database>(args[0]->ToObject());
+
+  v8::Local<v8::Value> startBuffer;
   leveldb::Slice* start = NULL;
-  if (args[1]->ToObject()->Has(option_start)
-      && (node::Buffer::HasInstance(args[1]->ToObject()->Get(option_start))
-        || args[1]->ToObject()->Get(option_start)->IsString())) {
-    v8::Local<v8::Value> startBuffer =
-      v8::Local<v8::Value>::New(args[1]->ToObject()->Get(option_start));
-    STRING_OR_BUFFER_TO_SLICE(_start, startBuffer, Start)
-    start = new leveldb::Slice(_start.data(), _start.size());
-  }
   std::string* end = NULL;
-  if (args[1]->ToObject()->Has(option_end)
-      && (node::Buffer::HasInstance(args[1]->ToObject()->Get(option_end))
-        || args[1]->ToObject()->Get(option_end)->IsString())) {
-    v8::Local<v8::Value> endBuffer =
-      v8::Local<v8::Value>::New(args[1]->ToObject()->Get(option_end));
-    STRING_OR_BUFFER_TO_SLICE(_end, endBuffer, End)
-    end = new std::string(_end.data(), _end.size());
+  int limit = -1;
+
+  v8::Local<v8::Object> optionsObj;
+
+  if (args.Length() > 0 && args[1]->IsObject()) {
+    optionsObj = v8::Local<v8::Object>::Cast(args[1]);
+
+    if (optionsObj->Has(option_start)
+        && (node::Buffer::HasInstance(optionsObj->Get(option_start))
+          || optionsObj->Get(option_start)->IsString())) {
+
+      startBuffer = v8::Local<v8::Value>::New(optionsObj->Get(option_start));
+      STRING_OR_BUFFER_TO_SLICE(start, startBuffer, Start)
+    }
+
+    if (optionsObj->Has(option_end)
+        && (node::Buffer::HasInstance(optionsObj->Get(option_end))
+          || optionsObj->Get(option_end)->IsString())) {
+
+      v8::Local<v8::Value> endBuffer =
+          v8::Local<v8::Value>::New(optionsObj->Get(option_end));
+      STRING_OR_BUFFER_TO_SLICE(_end, endBuffer, End)
+      end = new std::string(_end.data(), _end.size());
+    }
+
+    if (!optionsObj.IsEmpty() && optionsObj->Has(option_limit)) {
+      limit =
+        v8::Local<v8::Integer>::Cast(optionsObj->Get(option_limit))->Value();
+    }
   }
-  v8::Local<v8::Object> optionsObj = v8::Local<v8::Object>::Cast(args[1]);
+
   BOOLEAN_OPTION_VALUE(optionsObj, reverse)
   BOOLEAN_OPTION_VALUE_DEFTRUE(optionsObj, keys)
   BOOLEAN_OPTION_VALUE_DEFTRUE(optionsObj, values)
   BOOLEAN_OPTION_VALUE_DEFTRUE(optionsObj, keyAsBuffer)
   BOOLEAN_OPTION_VALUE_DEFTRUE(optionsObj, valueAsBuffer)
   BOOLEAN_OPTION_VALUE(optionsObj, fillCache)
-  int limit = -1;
-  if (args[1]->ToObject()->Has(option_limit)) {
-    limit = v8::Local<v8::
-    Integer>::Cast(args[1]->ToObject()->Get(option_limit))->Value();
-  }
+
   Iterator* iterator = new Iterator(
       database
     , start
@@ -200,15 +268,11 @@ v8::Handle<v8::Value> Iterator::New (const v8::Arguments& args) {
     , fillCache
     , keyAsBuffer
     , valueAsBuffer
+    , v8::Persistent<v8::Value>::New(startBuffer)
   );
   iterator->Wrap(args.This());
 
   return args.This();
 }
 
-v8::Handle<v8::Value> CreateIterator (const v8::Arguments& args) {
-  v8::HandleScope scope;
-  return scope.Close(Iterator::NewInstance(args));
-}
-
 } // namespace leveldown
diff --git a/src/iterator.h b/src/iterator.h
index b44c913..cc5389c 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -28,7 +28,10 @@ v8::Handle<v8::Value> CreateIterator (const v8::Arguments& args);
 class Iterator : public node::ObjectWrap {
 public:
   static void Init ();
-  static v8::Handle<v8::Value> NewInstance (const v8::Arguments& args);
+  static v8::Handle<v8::Value> NewInstance (
+      v8::Handle<v8::Object> database
+    , v8::Handle<v8::Object> optionsObj
+  );
 
   bool IteratorNext (std::string& key, std::string& value);
   leveldb::Status IteratorStatus ();
@@ -45,32 +48,10 @@ public:
     , bool fillCache
     , bool keyAsBuffer
     , bool valueAsBuffer
-  ) : database(database)
-    , start(start)
-    , end(end)
-    , reverse(reverse)
-    , keys(keys)
-    , values(values)
-    , limit(limit)
-    , keyAsBuffer(keyAsBuffer)
-    , valueAsBuffer(valueAsBuffer)
-  {
-    options    = new leveldb::ReadOptions();
-    options->fill_cache = fillCache;
-    dbIterator = NULL;
-    count      = 0;
-    nexting    = false;
-    ended      = false;
-    endWorker  = NULL;
-  };
-
-  ~Iterator () {
-    delete options;
-    if (start != NULL)
-      delete start;
-    if (end != NULL)
-      delete end;
-  };
+    , v8::Persistent<v8::Value> startPtr
+  );
+
+  ~Iterator ();
 
 private:
   Database* database;
@@ -92,6 +73,8 @@ public:
   AsyncWorker* endWorker;
 
 private:
+  v8::Persistent<v8::Value> startPtr;
+
   bool GetIterator ();
 
   static v8::Persistent<v8::Function> constructor;
diff --git a/src/iterator_async.cc b/src/iterator_async.cc
index 7c15b7b..e855d9b 100644
--- a/src/iterator_async.cc
+++ b/src/iterator_async.cc
@@ -17,18 +17,14 @@ namespace leveldown {
 
 NextWorker::NextWorker (
     Iterator* iterator
-  , v8::Persistent<v8::Function> dataCallback
-  , v8::Persistent<v8::Function> endCallback
+  , v8::Persistent<v8::Function> callback
   , void (*localCallback)(Iterator*)
-) : AsyncWorker(database, dataCallback)
+) : AsyncWorker(NULL, callback)
   , iterator(iterator)
-  , endCallback(endCallback)
   , localCallback(localCallback)
 {};
 
-NextWorker::~NextWorker () {
-  endCallback.Dispose();
-}
+NextWorker::~NextWorker () {}
 
 void NextWorker::Execute () {
   ok = iterator->IteratorNext(key, value);
@@ -45,6 +41,7 @@ void NextWorker::HandleOKCallback () {
   } else {
     returnKey = v8::String::New((char*)key.data(), key.size());
   }
+
   v8::Local<v8::Value> returnValue;
   if (iterator->valueAsBuffer) {
     returnValue = v8::Local<v8::Value>::New(
@@ -66,7 +63,7 @@ void NextWorker::HandleOKCallback () {
     RUN_CALLBACK(callback, argv, 3);
   } else {
     v8::Local<v8::Value> argv[0];
-    RUN_CALLBACK(endCallback, argv, 0);
+    RUN_CALLBACK(callback, argv, 0);
   }
 }
 
@@ -74,8 +71,8 @@ void NextWorker::HandleOKCallback () {
 
 EndWorker::EndWorker (
     Iterator* iterator
-  , v8::Persistent<v8::Function> endCallback
-) : AsyncWorker(database, endCallback)
+  , v8::Persistent<v8::Function> callback
+) : AsyncWorker(NULL, callback)
   , iterator(iterator)
 {};
 
diff --git a/src/iterator_async.h b/src/iterator_async.h
index 731a7b8..4325d20 100644
--- a/src/iterator_async.h
+++ b/src/iterator_async.h
@@ -17,8 +17,7 @@ class NextWorker : public AsyncWorker {
 public:
   NextWorker (
       Iterator* iterator
-    , v8::Persistent<v8::Function> dataCallback
-    , v8::Persistent<v8::Function> endCallback
+    , v8::Persistent<v8::Function> callback
     , void (*localCallback)(Iterator*)
   );
 
@@ -28,7 +27,6 @@ public:
 
 private:
   Iterator* iterator;
-  v8::Persistent<v8::Function> endCallback;
   void (*localCallback)(Iterator*);
   std::string key;
   std::string value;
@@ -39,7 +37,7 @@ class EndWorker : public AsyncWorker {
 public:
   EndWorker (
       Iterator* iterator
-    , v8::Persistent<v8::Function> endCallback
+    , v8::Persistent<v8::Function> callback
   );
 
   virtual ~EndWorker ();
diff --git a/src/leveldown.cc b/src/leveldown.cc
index f219352..653855b 100644
--- a/src/leveldown.cc
+++ b/src/leveldown.cc
@@ -17,8 +17,6 @@ void Init (v8::Handle<v8::Object> target) {
 
   target->Set(v8::String::NewSymbol("leveldown")
       , v8::FunctionTemplate::New(LevelDOWN)->GetFunction());
-  target->Set(v8::String::NewSymbol("createIterator")
-      , v8::FunctionTemplate::New(CreateIterator)->GetFunction());
 }
 
 NODE_MODULE(leveldown, Init)
diff --git a/src/leveldown.h b/src/leveldown.h
index 93a3c63..c37aa5b 100644
--- a/src/leveldown.h
+++ b/src/leveldown.h
@@ -2,7 +2,6 @@
  * See list at <https://github.com/rvagg/node-leveldown#contributing>
  * MIT +no-false-attribs License <https://github.com/rvagg/node-leveldown/blob/master/LICENSE>
  */
-
 #ifndef LU_LEVELDOWN_H
 #define LU_LEVELDOWN_H
 
@@ -38,26 +37,14 @@
   if (node::Buffer::HasInstance(from->ToObject())) { \
     to ## Sz_ = node::Buffer::Length(from->ToObject()); \
     if (to ## Sz_ == 0) { \
-      v8::Local<v8::Value> argv[] = { \
-        v8::Local<v8::Value>::New(v8::Exception::Error( \
-          v8::String::New(#name " argument cannot be an empty Buffer")) \
-        ) \
-      }; \
-      RUN_CALLBACK(callback, argv, 1); \
-      return v8::Undefined(); \
+      RETURN_CALLBACK_OR_ERROR(callback, #name " argument cannot be an empty Buffer") \
     } \
     to ## Ch_ = node::Buffer::Data(from->ToObject()); \
   } else { \
     v8::Local<v8::String> to ## Str = from->ToString(); \
     to ## Sz_ = to ## Str->Utf8Length(); \
     if (to ## Sz_ == 0) { \
-      v8::Local<v8::Value> argv[] = { \
-        v8::Local<v8::Value>::New(v8::Exception::Error( \
-          v8::String::New(#name " argument cannot be an empty String")) \
-        ) \
-      }; \
-      RUN_CALLBACK(callback, argv, 1); \
-      return v8::Undefined(); \
+      RETURN_CALLBACK_OR_ERROR(callback, #name " argument cannot be an empty String") \
     } \
     to ## Ch_ = new char[to ## Sz_]; \
     to ## Str->WriteUtf8( \
@@ -85,6 +72,18 @@
       ? optionsObj->Get(option_ ## opt)->Uint32Value() \
       : default;
 
+#define RETURN_CALLBACK_OR_ERROR(callback, msg) \
+  if (callback->IsFunction()) { \
+    v8::Local<v8::Value> argv[] = { \
+      v8::Local<v8::Value>::New(v8::Exception::Error( \
+        v8::String::New(msg)) \
+      ) \
+    }; \
+    RUN_CALLBACK(callback, argv, 1) \
+    return v8::Undefined(); \
+  } \
+  THROW_RETURN(msg)
+
 #define RUN_CALLBACK(callback, argv, length) \
   v8::TryCatch try_catch; \
   callback->Call(v8::Context::GetCurrent()->Global(), length, argv); \
diff --git a/test/iterator-test.js b/test/iterator-test.js
new file mode 100644
index 0000000..87925e4
--- /dev/null
+++ b/test/iterator-test.js
@@ -0,0 +1,92 @@
+const test       = require('tap').test
+    , testCommon = require('./common')
+    , leveldown  = require('../')
+
+var db
+
+test('setUp', function (t) {
+  db = leveldown(testCommon.location())
+  db.open(testCommon.setUp.bind(null, t))
+})
+
+test('test argument-less iterator#next() throws', function (t) {
+  var iterator = db.iterator()
+  t.throws(iterator.next.bind(iterator), 'no-arg iterator#next() throws')
+  iterator.end(t.end.bind(t))
+})
+
+test('test argument-less iterator#end() after next() throws', function (t) {
+  var iterator = db.iterator()
+  iterator.next(function () {
+    t.throws(iterator.end.bind(iterator), 'no-arg iterator#end() throws')
+    iterator.end(t.end.bind(t))
+  })
+})
+
+test('test argument-less iterator#end() throws', function (t) {
+  var iterator = db.iterator()
+  t.throws(iterator.end.bind(iterator), 'no-arg iterator#end() throws')
+  iterator.end(t.end.bind(t))
+})
+
+test('test twice iterator#end() throws', function (t) {
+  var iterator = db.iterator()
+  iterator.end(function (err) {
+    t.notOk(err, 'no error')
+    t.throws(iterator.end.bind(iterator, function () {}), 'twice iterator#end() throws')
+    t.end()
+  })
+})
+
+test('test twice iterator#next() throws', function (t) {
+  var iterator = db.iterator()
+  iterator.next(function (err) {
+    t.notOk(err, 'no error')
+    iterator.end(function (err) {
+      t.notOk(err, 'no error')
+      t.end()
+    })
+  })
+  t.throws(iterator.next.bind(iterator, function () {}), 'twice iterator#next() throws')
+})
+
+test('test simple iterator()', function (t) {
+  var data = [
+          { type: 'put', key: 'foobatch1', value: 'bar1' }
+        , { type: 'put', key: 'foobatch2', value: 'bar2' }
+        , { type: 'put', key: 'foobatch3', value: 'bar3' }
+      ]
+    , idx = 0
+
+  db.batch(data, function (err) {
+    t.notOk(err, 'no error')
+
+    var iterator = db.iterator()
+      , fn = function (err, key, value) {
+          t.notOk(err, 'no error')
+          if (key && value) {
+            t.equal(key.toString(), data[idx].key, 'correct key')
+            t.equal(value.toString(), data[idx].value, 'correct value')
+            process.nextTick(next)
+            idx++
+          } else { // end
+            t.type(err, 'undefined', 'err argument is undefined')
+            t.type(key, 'undefined', 'key argument is undefined')
+            t.type(value, 'undefined', 'value argument is undefined')
+            t.equal(idx, data.length, 'correct number of entries')
+            iterator.end(function () {
+              t.end()
+            })
+          }
+        }
+      , next = function () {
+          iterator.next(fn)
+        }
+
+    next()
+  })
+})
+
+test('tearDown', function (t) {
+  db.close(testCommon.tearDown.bind(null, t))
+})
\ No newline at end of file

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-leveldown.git



More information about the Pkg-javascript-commits mailing list