Skip to content
This repository was archived by the owner on Dec 1, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ If you are working on `leveldown` itself and want to re-compile the C++ code, ru
- <a href="#leveldown_close"><code>db.<b>close()</b></code></a>
- <a href="#leveldown_put"><code>db.<b>put()</b></code></a>
- <a href="#leveldown_get"><code>db.<b>get()</b></code></a>
- <a href="#leveldown_get_many"><code>db.<b>getMany()</b></code></a>
- <a href="#leveldown_del"><code>db.<b>del()</b></code></a>
- <a href="#leveldown_batch"><code>db.<b>batch()</b></code></a> _(array form)_
- <a href="#leveldown_chainedbatch"><code>db.<b>batch()</b></code></a> _(chained form)_
Expand Down Expand Up @@ -210,7 +211,7 @@ The `callback` function will be called with no arguments if the operation is suc

### `db.get(key[, options], callback)`

<code>get()</code> is an instance method on an existing database object, used to fetch individual entries from the LevelDB store.
Get a value from the LevelDB store by `key`.

The `key` object may either be a string or a Buffer and cannot be `undefined` or `null`. Other object types are converted to strings with the `toString()` method and the resulting string _may not_ be a zero-length. A richer set of data-types is catered for in `levelup`.

Expand All @@ -220,11 +221,20 @@ Values fetched via `get()` that are stored as zero-length character arrays (`nul

The optional `options` object may contain:

- `asBuffer` (boolean, default: `true`): Used to determine whether to return the `value` of the entry as a string or a Buffer. Note that converting from a Buffer to a string incurs a cost so if you need a string (and the `value` can legitimately become a UTF8 string) then you should fetch it as one with `{ asBuffer: false }` and you'll avoid this conversion cost.
- `fillCache` (boolean, default: `true`): LevelDB will by default fill the in-memory LRU Cache with data from a call to get. Disabling this is done by setting `fillCache` to `false`.

- `asBuffer` (boolean, default: `true`): Used to determine whether to return the `value` of the entry as a string or a Buffer. Note that converting from a Buffer to a string incurs a cost so if you need a string (and the `value` can legitimately become a UTF8 string) then you should fetch it as one with `{ asBuffer: false }` and you'll avoid this conversion cost.
The `callback` function will be called with a single `error` if the operation failed for any reason, including if the key was not found. If successful the first argument will be `null` and the second argument will be the `value` as a string or Buffer depending on the `asBuffer` option.

<a name="leveldown_get_many"></a>

### `db.getMany(keys[, options][, callback])`

Get multiple values from the store by an array of `keys`. The optional `options` object may contain `asBuffer` and `fillCache`, as described in [`get()`](#leveldown_get).

The `callback` function will be called with an `Error` if the operation failed for any reason. If successful the first argument will be `null` and the second argument will be an array of values with the same order as `keys`. If a key was not found, the relevant value will be `undefined`.

The `callback` function will be called with a single `error` if the operation failed for any reason. If successful the first argument will be `null` and the second argument will be the `value` as a string or Buffer depending on the `asBuffer` option.
If no callback is provided, a promise is returned.

<a name="leveldown_del"></a>

Expand Down
118 changes: 118 additions & 0 deletions binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,31 @@ static std::string* RangeOption (napi_env env, napi_value opts, const char* name
return NULL;
}

/**
* Converts an array containing Buffer or string keys to a vector.
* Empty elements are skipped.
*/
static std::vector<std::string>* KeyArray (napi_env env, napi_value arr) {
uint32_t length;
std::vector<std::string>* result = new std::vector<std::string>();

if (napi_get_array_length(env, arr, &length) == napi_ok) {
result->reserve(length);

for (uint32_t i = 0; i < length; i++) {
napi_value element;

if (napi_get_element(env, arr, i, &element) == napi_ok &&
StringOrBufferLength(env, element) > 0) {
LD_STRING_OR_BUFFER_TO_COPY(env, element, to);
result->emplace_back(toCh_, toSz_);
}
}
}

return result;
}

/**
* Calls a function.
*/
Expand Down Expand Up @@ -1132,6 +1157,98 @@ NAPI_METHOD(db_get) {
NAPI_RETURN_UNDEFINED();
}

/**
* Worker class for getting many values.
*/
struct GetManyWorker final : public PriorityWorker {
GetManyWorker (napi_env env,
Database* database,
const std::vector<std::string>* keys,
napi_value callback,
const bool valueAsBuffer,
const bool fillCache)
: PriorityWorker(env, database, callback, "leveldown.get.many"),
keys_(keys), valueAsBuffer_(valueAsBuffer) {
options_.fill_cache = fillCache;
options_.snapshot = database->NewSnapshot();
}

~GetManyWorker() {
delete keys_;
}

void DoExecute () override {
cache_.reserve(keys_->size());

for (const std::string& key: *keys_) {
std::string* value = new std::string();
leveldb::Status status = database_->Get(options_, key, *value);

if (status.ok()) {
cache_.push_back(value);
} else if (status.IsNotFound()) {
delete value;
cache_.push_back(NULL);
} else {
delete value;
for (const std::string* value: cache_) {
if (value != NULL) delete value;
}
SetStatus(status);
break;
}
}

database_->ReleaseSnapshot(options_.snapshot);
}

void HandleOKCallback (napi_env env, napi_value callback) override {
size_t size = cache_.size();
napi_value array;
napi_create_array_with_length(env, size, &array);

for (size_t idx = 0; idx < size; idx++) {
std::string* value = cache_[idx];
napi_value element;
Entry::Convert(env, value, valueAsBuffer_, &element);
napi_set_element(env, array, static_cast<uint32_t>(idx), element);
if (value != NULL) delete value;
}

napi_value argv[2];
napi_get_null(env, &argv[0]);
argv[1] = array;
CallFunction(env, callback, 2, argv);
}

private:
leveldb::ReadOptions options_;
const std::vector<std::string>* keys_;
const bool valueAsBuffer_;
std::vector<std::string*> cache_;
};

/**
* Gets many values from a database.
*/
NAPI_METHOD(db_get_many) {
NAPI_ARGV(4);
NAPI_DB_CONTEXT();

const std::vector<std::string>* keys = KeyArray(env, argv[1]);
napi_value options = argv[2];
const bool asBuffer = BooleanProperty(env, options, "asBuffer", true);
const bool fillCache = BooleanProperty(env, options, "fillCache", true);
napi_value callback = argv[3];

GetManyWorker* worker = new GetManyWorker(
env, database, keys, callback, asBuffer, fillCache
);

worker->Queue(env);
NAPI_RETURN_UNDEFINED();
}

/**
* Worker class for deleting a value from a database.
*/
Expand Down Expand Up @@ -1916,6 +2033,7 @@ NAPI_INIT() {
NAPI_EXPORT_FUNCTION(db_close);
NAPI_EXPORT_FUNCTION(db_put);
NAPI_EXPORT_FUNCTION(db_get);
NAPI_EXPORT_FUNCTION(db_get_many);
NAPI_EXPORT_FUNCTION(db_del);
NAPI_EXPORT_FUNCTION(db_clear);
NAPI_EXPORT_FUNCTION(db_approximate_size);
Expand Down
5 changes: 5 additions & 0 deletions leveldown.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function LevelDOWN (location) {
permanence: true,
seek: true,
clear: true,
getMany: true,
createIfMissing: true,
errorIfExists: true,
additionalMethods: {
Expand Down Expand Up @@ -59,6 +60,10 @@ LevelDOWN.prototype._get = function (key, options, callback) {
binding.db_get(this.context, key, options, callback)
}

LevelDOWN.prototype._getMany = function (keys, options, callback) {
binding.db_get_many(this.context, keys, options, callback)
}

LevelDOWN.prototype._del = function (key, options, callback) {
binding.db_del(this.context, key, options, callback)
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"prebuild-win32-x64": "prebuildify -t 8.14.0 --napi --strip"
},
"dependencies": {
"abstract-leveldown": "^7.0.0",
"abstract-leveldown": "^7.2.0",
"napi-macros": "~2.0.0",
"node-gyp-build": "~4.2.1"
},
Expand Down
5 changes: 3 additions & 2 deletions test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = suite.common({
return leveldown(tempy.directory())
},

// Opt-in to new clear() tests
clear: true
// Opt-in to new tests
clear: true,
getMany: true
})