[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