@nxtedition/rocksdb 7.0.44 → 7.0.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/binding.cc CHANGED
@@ -249,7 +249,7 @@ napi_status Convert(napi_env env, T&& s, bool asBuffer, napi_value& result) {
249
249
  if (!s) {
250
250
  return napi_get_null(env, &result);
251
251
  } else if (asBuffer) {
252
- using Y = typename std::remove_pointer<typename std::decay<decltype(*s)>::type>::type;
252
+ using Y = typename std::decay<decltype(*s)>::type;
253
253
  auto ptr = new Y(std::move(*s));
254
254
  return napi_create_external_buffer(env, ptr->size(), const_cast<char*>(ptr->data()), Finalize<Y>, ptr, &result);
255
255
  } else {
@@ -329,6 +329,13 @@ struct Worker {
329
329
  rocksdb::Status status_;
330
330
  };
331
331
 
332
+ struct ColumnFamily {
333
+ napi_ref ref;
334
+ napi_value val;
335
+ rocksdb::ColumnFamilyHandle* handle;
336
+ rocksdb::ColumnFamilyDescriptor descriptor;
337
+ };
338
+
332
339
  struct Database {
333
340
  void AttachIterator(napi_env env, Iterator* iterator) {
334
341
  iterators_.insert(iterator);
@@ -367,13 +374,228 @@ struct Database {
367
374
  Worker* pendingCloseWorker_;
368
375
  std::set<Iterator*> iterators_;
369
376
  std::set<Updates*> updates_;
370
- std::vector<rocksdb::ColumnFamilyHandle*> columns_;
377
+ std::map<int32_t, ColumnFamily> columns_;
371
378
  napi_ref priorityRef_;
372
379
 
373
380
  private:
374
381
  uint32_t priorityWork_ = 0;
375
382
  };
376
383
 
384
+ enum BatchOp { Empty, Put, Delete, Merge, Data };
385
+
386
+ struct BatchEntry {
387
+ BatchOp op = BatchOp::Empty;
388
+ std::optional<std::string> key;
389
+ std::optional<std::string> val;
390
+ std::optional<ColumnFamily> column;
391
+ };
392
+
393
+ struct BatchIterator : public rocksdb::WriteBatch::Handler {
394
+ BatchIterator(Database* database,
395
+ bool keys = true,
396
+ bool values = true,
397
+ bool data = true,
398
+ const rocksdb::ColumnFamilyHandle* column = nullptr,
399
+ bool keyAsBuffer = false,
400
+ bool valueAsBuffer = false)
401
+ : database_(database),
402
+ keys_(keys),
403
+ values_(values),
404
+ data_(data),
405
+ column_(column),
406
+ keyAsBuffer_(keyAsBuffer),
407
+ valueAsBuffer_(valueAsBuffer) {}
408
+
409
+ napi_status Iterate(napi_env env, const rocksdb::WriteBatch& batch, napi_value* result) {
410
+ cache_.reserve(batch.Count());
411
+ batch.Iterate(this); // TODO (fix): Error?
412
+
413
+ napi_value putStr;
414
+ NAPI_STATUS_RETURN(napi_create_string_utf8(env, "put", NAPI_AUTO_LENGTH, &putStr));
415
+
416
+ napi_value delStr;
417
+ NAPI_STATUS_RETURN(napi_create_string_utf8(env, "del", NAPI_AUTO_LENGTH, &delStr));
418
+
419
+ napi_value mergeStr;
420
+ NAPI_STATUS_RETURN(napi_create_string_utf8(env, "merge", NAPI_AUTO_LENGTH, &mergeStr));
421
+
422
+ napi_value dataStr;
423
+ NAPI_STATUS_RETURN(napi_create_string_utf8(env, "data", NAPI_AUTO_LENGTH, &dataStr));
424
+
425
+ napi_value nullVal;
426
+ NAPI_STATUS_RETURN(napi_get_null(env, &nullVal));
427
+
428
+ NAPI_STATUS_RETURN(napi_create_array_with_length(env, cache_.size() * 4, result));
429
+ for (size_t n = 0; n < cache_.size(); ++n) {
430
+ napi_value op;
431
+ if (cache_[n].op == BatchOp::Put) {
432
+ op = putStr;
433
+ } else if (cache_[n].op == BatchOp::Delete) {
434
+ op = delStr;
435
+ } else if (cache_[n].op == BatchOp::Merge) {
436
+ op = mergeStr;
437
+ } else if (cache_[n].op == BatchOp::Data) {
438
+ op = dataStr;
439
+ } else {
440
+ continue;
441
+ }
442
+
443
+ NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 0, op));
444
+
445
+ napi_value key;
446
+ NAPI_STATUS_RETURN(Convert(env, cache_[n].key, keyAsBuffer_, key));
447
+ NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 1, key));
448
+
449
+ napi_value val;
450
+ NAPI_STATUS_RETURN(Convert(env, cache_[n].val, valueAsBuffer_, val));
451
+ NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 2, val));
452
+
453
+ // TODO (fix)
454
+ // napi_value column = cache_[n].column ? cache_[n].column->val : nullVal;
455
+ NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 3, nullVal));
456
+ }
457
+
458
+ return napi_ok;
459
+ }
460
+
461
+ rocksdb::Status PutCF(uint32_t column_family_id, const rocksdb::Slice& key, const rocksdb::Slice& value) override {
462
+ if (column_ && column_->GetID() != column_family_id) {
463
+ return rocksdb::Status::OK();
464
+ }
465
+
466
+ BatchEntry entry;
467
+
468
+ entry.op = BatchOp::Put;
469
+
470
+ if (keys_) {
471
+ entry.key = key.ToStringView();
472
+ }
473
+
474
+ if (values_) {
475
+ entry.val = value.ToStringView();
476
+ }
477
+
478
+ // if (database_ && database_->columns_.find(column_family_id) != database_->columns_.end()) {
479
+ // entry.column = database_->columns_[column_family_id];
480
+ // }
481
+
482
+ cache_.push_back(entry);
483
+
484
+ return rocksdb::Status::OK();
485
+ }
486
+
487
+ rocksdb::Status DeleteCF(uint32_t column_family_id, const rocksdb::Slice& key) override {
488
+ if (column_ && column_->GetID() != column_family_id) {
489
+ return rocksdb::Status::OK();
490
+ }
491
+
492
+ BatchEntry entry;
493
+
494
+ entry.op = BatchOp::Delete;
495
+
496
+ if (keys_) {
497
+ entry.key = key.ToStringView();
498
+ }
499
+
500
+ // if (database_ && database_->columns_.find(column_family_id) != database_->columns_.end()) {
501
+ // entry.column = database_->columns_[column_family_id];
502
+ // }
503
+
504
+ cache_.push_back(entry);
505
+
506
+ return rocksdb::Status::OK();
507
+ }
508
+
509
+ rocksdb::Status MergeCF(uint32_t column_family_id, const rocksdb::Slice& key, const rocksdb::Slice& value) override {
510
+ if (column_ && column_->GetID() != column_family_id) {
511
+ return rocksdb::Status::OK();
512
+ }
513
+
514
+ BatchEntry entry;
515
+
516
+ entry.op = BatchOp::Merge;
517
+
518
+ if (keys_) {
519
+ entry.key = key.ToStringView();
520
+ }
521
+
522
+ if (values_) {
523
+ entry.val = value.ToStringView();
524
+ }
525
+
526
+ // if (database_ && database_->columns_.find(column_family_id) != database_->columns_.end()) {
527
+ // entry.column = database_->columns_[column_family_id];
528
+ // }
529
+
530
+ cache_.push_back(entry);
531
+
532
+ return rocksdb::Status::OK();
533
+ }
534
+
535
+ void LogData(const rocksdb::Slice& data) override {
536
+ if (!data_) {
537
+ return;
538
+ }
539
+
540
+ BatchEntry entry;
541
+
542
+ entry.op = BatchOp::Data;
543
+
544
+ entry.val = data.ToStringView();
545
+
546
+ cache_.push_back(entry);
547
+ }
548
+
549
+ bool Continue() override { return true; }
550
+
551
+ private:
552
+ Database* database_;
553
+ bool keys_;
554
+ bool values_;
555
+ bool data_;
556
+ const rocksdb::ColumnFamilyHandle* column_;
557
+ bool keyAsBuffer_;
558
+ bool valueAsBuffer_;
559
+ std::vector<BatchEntry> cache_;
560
+ };
561
+
562
+ struct Updates : public BatchIterator {
563
+ Updates(Database* database,
564
+ int64_t seqNumber,
565
+ bool keys,
566
+ bool values,
567
+ bool data,
568
+ const rocksdb::ColumnFamilyHandle* column,
569
+ bool keyAsBuffer,
570
+ bool valueAsBuffer)
571
+ : BatchIterator(database, keys, values, data, column, keyAsBuffer, valueAsBuffer),
572
+ database_(database),
573
+ sequence_(seqNumber),
574
+ start_(seqNumber) {}
575
+
576
+ void Close() { iterator_.reset(); }
577
+
578
+ void Attach(napi_env env, napi_value context) {
579
+ napi_create_reference(env, context, 1, &ref_);
580
+ database_->AttachUpdates(env, this);
581
+ }
582
+
583
+ void Detach(napi_env env) {
584
+ database_->DetachUpdates(env, this);
585
+ if (ref_) {
586
+ napi_delete_reference(env, ref_);
587
+ }
588
+ }
589
+
590
+ Database* database_;
591
+ int64_t sequence_;
592
+ int64_t start_;
593
+ std::unique_ptr<rocksdb::TransactionLogIterator> iterator_;
594
+
595
+ private:
596
+ napi_ref ref_ = nullptr;
597
+ };
598
+
377
599
  struct BaseIterator {
378
600
  BaseIterator(Database* database,
379
601
  rocksdb::ColumnFamilyHandle* column,
@@ -562,53 +784,10 @@ struct Iterator final : public BaseIterator {
562
784
  napi_ref ref_ = nullptr;
563
785
  };
564
786
 
565
- struct Updates {
566
- Updates(Database* database,
567
- int64_t seqNumber,
568
- bool keys,
569
- bool values,
570
- bool data,
571
- const rocksdb::ColumnFamilyHandle* column)
572
- : database_(database),
573
- sequence_(seqNumber),
574
- start_(seqNumber),
575
- keys_(keys),
576
- values_(values),
577
- data_(data),
578
- column_(column) {}
579
-
580
- void Close() { iterator_.reset(); }
581
-
582
- void Attach(napi_env env, napi_value context) {
583
- napi_create_reference(env, context, 1, &ref_);
584
- database_->AttachUpdates(env, this);
585
- }
586
-
587
- void Detach(napi_env env) {
588
- database_->DetachUpdates(env, this);
589
- if (ref_) {
590
- napi_delete_reference(env, ref_);
591
- }
592
- }
593
-
594
- Database* database_;
595
- int64_t sequence_;
596
- int64_t start_;
597
- std::unique_ptr<rocksdb::TransactionLogIterator> iterator_;
598
- bool keys_;
599
- bool values_;
600
- bool data_;
601
- const rocksdb::ColumnFamilyHandle* column_;
602
-
603
- private:
604
- napi_ref ref_ = nullptr;
605
- };
606
-
607
787
  static napi_status GetColumnFamily(Database* database,
608
788
  napi_env env,
609
789
  napi_value options,
610
- rocksdb::ColumnFamilyHandle** column,
611
- bool fallback = true) {
790
+ rocksdb::ColumnFamilyHandle** column) {
612
791
  bool hasColumn = false;
613
792
  NAPI_STATUS_RETURN(napi_has_named_property(env, options, "column", &hasColumn));
614
793
 
@@ -616,7 +795,7 @@ static napi_status GetColumnFamily(Database* database,
616
795
  napi_value value = nullptr;
617
796
  NAPI_STATUS_RETURN(napi_get_named_property(env, options, "column", &value));
618
797
  NAPI_STATUS_RETURN(napi_get_value_external(env, value, reinterpret_cast<void**>(column)));
619
- } else if (fallback) {
798
+ } else if (database) {
620
799
  *column = database->db_->DefaultColumnFamily();
621
800
  } else {
622
801
  *column = nullptr;
@@ -641,18 +820,18 @@ static void env_cleanup_hook(void* arg) {
641
820
  // following code must be a safe noop if called before db_open() or after
642
821
  // db_close().
643
822
  if (database && database->db_) {
644
- for (auto it : database->iterators_) {
823
+ for (auto& it : database->iterators_) {
645
824
  // TODO: does not do `napi_delete_reference`. Problem?
646
825
  it->Close();
647
826
  }
648
827
 
649
- for (auto it : database->updates_) {
828
+ for (auto& it : database->updates_) {
650
829
  // TODO: does not do `napi_delete_reference`. Problem?
651
830
  it->Close();
652
831
  }
653
832
 
654
- for (auto it : database->columns_) {
655
- database->db_->DestroyColumnFamilyHandle(it);
833
+ for (auto& it : database->columns_) {
834
+ database->db_->DestroyColumnFamilyHandle(it.second.handle);
656
835
  }
657
836
 
658
837
  // Having closed the iterators (and released snapshots) we can safely close.
@@ -666,6 +845,9 @@ static void FinalizeDatabase(napi_env env, void* data, void* hint) {
666
845
  napi_remove_env_cleanup_hook(env, env_cleanup_hook, database);
667
846
  if (database->priorityRef_)
668
847
  napi_delete_reference(env, database->priorityRef_);
848
+ for (auto& it : database->columns_) {
849
+ napi_delete_reference(env, it.second.ref);
850
+ }
669
851
  delete database;
670
852
  }
671
853
  }
@@ -688,17 +870,16 @@ struct OpenWorker final : public Worker {
688
870
  napi_value callback,
689
871
  const std::string& location,
690
872
  const rocksdb::Options& options,
691
- std::vector<rocksdb::ColumnFamilyDescriptor> column_families)
873
+ std::vector<rocksdb::ColumnFamilyDescriptor> descriptors)
692
874
  : Worker(env, database, callback, "leveldown.db.open"),
693
875
  options_(options),
694
876
  location_(location),
695
- column_families_(std::move(column_families)) {}
877
+ descriptors_(std::move(descriptors)) {}
696
878
 
697
879
  rocksdb::Status Execute(Database& database) override {
698
880
  rocksdb::DB* db = nullptr;
699
- const auto status = column_families_.empty()
700
- ? rocksdb::DB::Open(options_, location_, &db)
701
- : rocksdb::DB::Open(options_, location_, column_families_, &database.columns_, &db);
881
+ const auto status = descriptors_.empty() ? rocksdb::DB::Open(options_, location_, &db)
882
+ : rocksdb::DB::Open(options_, location_, descriptors_, &handles_, &db);
702
883
  database.db_.reset(db);
703
884
  return status;
704
885
  }
@@ -707,13 +888,19 @@ struct OpenWorker final : public Worker {
707
888
  napi_value argv[2];
708
889
  NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
709
890
 
710
- const auto size = database_->columns_.size();
891
+ const auto size = handles_.size();
711
892
  NAPI_STATUS_RETURN(napi_create_object(env, &argv[1]));
712
893
 
713
894
  for (size_t n = 0; n < size; ++n) {
714
- napi_value column;
715
- NAPI_STATUS_RETURN(napi_create_external(env, database_->columns_[n], nullptr, nullptr, &column));
716
- NAPI_STATUS_RETURN(napi_set_named_property(env, argv[1], column_families_[n].name.c_str(), column));
895
+ ColumnFamily column;
896
+ column.handle = handles_[n];
897
+ column.descriptor = descriptors_[n];
898
+ NAPI_STATUS_RETURN(napi_create_external(env, column.handle, nullptr, nullptr, &column.val));
899
+ NAPI_STATUS_RETURN(napi_create_reference(env, column.val, 1, &column.ref));
900
+
901
+ NAPI_STATUS_RETURN(napi_set_named_property(env, argv[1], descriptors_[n].name.c_str(), column.val));
902
+
903
+ database_->columns_[column.handle->GetID()] = column;
717
904
  }
718
905
 
719
906
  return CallFunction(env, callback, 2, argv);
@@ -721,7 +908,8 @@ struct OpenWorker final : public Worker {
721
908
 
722
909
  rocksdb::Options options_;
723
910
  const std::string location_;
724
- std::vector<rocksdb::ColumnFamilyDescriptor> column_families_;
911
+ std::vector<rocksdb::ColumnFamilyDescriptor> descriptors_;
912
+ std::vector<rocksdb::ColumnFamilyHandle*> handles_;
725
913
  };
726
914
 
727
915
  template <typename T, typename U>
@@ -940,8 +1128,8 @@ struct CloseWorker final : public Worker {
940
1128
  : Worker(env, database, callback, "leveldown.db.close") {}
941
1129
 
942
1130
  rocksdb::Status Execute(Database& database) override {
943
- for (auto it : database.columns_) {
944
- database.db_->DestroyColumnFamilyHandle(it);
1131
+ for (auto& it : database.columns_) {
1132
+ database.db_->DestroyColumnFamilyHandle(it.second.handle);
945
1133
  }
946
1134
 
947
1135
  return database.db_->Close();
@@ -969,7 +1157,7 @@ NAPI_METHOD(db_close) {
969
1157
  return 0;
970
1158
  }
971
1159
 
972
- struct UpdatesNextWorker final : public rocksdb::WriteBatch::Handler, public Worker {
1160
+ struct UpdatesNextWorker final : public Worker {
973
1161
  UpdatesNextWorker(napi_env env, Updates* updates, napi_value callback)
974
1162
  : Worker(env, updates->database_, callback, "rocks_level.db.get"), updates_(updates) {
975
1163
  database_->IncrementPriorityWork(env);
@@ -994,10 +1182,10 @@ struct UpdatesNextWorker final : public rocksdb::WriteBatch::Handler, public Wor
994
1182
 
995
1183
  updates_->sequence_ = batch.sequence;
996
1184
 
997
- count_ = batch.writeBatchPtr->Count();
998
- cache_.reserve(batch.writeBatchPtr->Count() * 4);
1185
+ batch_ = std::move(batch.writeBatchPtr);
1186
+ count_ = batch_->Count();
999
1187
 
1000
- return batch.writeBatchPtr->Iterate(this);
1188
+ return rocksdb::Status::OK();
1001
1189
  }
1002
1190
 
1003
1191
  napi_status OnOk(napi_env env, napi_value callback) override {
@@ -1009,12 +1197,7 @@ struct UpdatesNextWorker final : public rocksdb::WriteBatch::Handler, public Wor
1009
1197
  return CallFunction(env, callback, 1, argv);
1010
1198
  }
1011
1199
 
1012
- NAPI_STATUS_RETURN(napi_create_array_with_length(env, cache_.size(), &argv[1]));
1013
- for (size_t idx = 0; idx < cache_.size(); idx++) {
1014
- napi_value val;
1015
- NAPI_STATUS_RETURN(Convert(env, cache_[idx], false, val));
1016
- NAPI_STATUS_RETURN(napi_set_element(env, argv[1], idx, val));
1017
- }
1200
+ NAPI_STATUS_RETURN(updates_->Iterate(env, *batch_, &argv[1]));
1018
1201
 
1019
1202
  NAPI_STATUS_RETURN(napi_create_int64(env, updates_->sequence_, &argv[2]));
1020
1203
 
@@ -1030,110 +1213,9 @@ struct UpdatesNextWorker final : public rocksdb::WriteBatch::Handler, public Wor
1030
1213
  Worker::Destroy(env);
1031
1214
  }
1032
1215
 
1033
- std::optional<std::string> GetColumnName(uint32_t column_family_id) {
1034
- if (column_family_id == 0) {
1035
- return "default";
1036
- }
1037
- auto columns = database_->columns_;
1038
- auto columnIt = std::find_if(columns.begin(), columns.end(),
1039
- [&](const auto& handle) { return handle->GetID() == column_family_id; });
1040
- return columnIt == columns.end() ? std::nullopt : std::optional<std::string>((*columnIt)->GetName());
1041
- }
1042
-
1043
- rocksdb::Status PutCF(uint32_t column_family_id, const rocksdb::Slice& key, const rocksdb::Slice& value) override {
1044
- if (updates_->column_ && updates_->column_->GetID() != column_family_id) {
1045
- return rocksdb::Status::OK();
1046
- }
1047
-
1048
- cache_.emplace_back("put");
1049
-
1050
- if (updates_->keys_) {
1051
- cache_.emplace_back(key.ToStringView());
1052
- } else {
1053
- cache_.emplace_back(std::nullopt);
1054
- }
1055
-
1056
- if (updates_->values_) {
1057
- cache_.emplace_back(value.ToStringView());
1058
- } else {
1059
- cache_.emplace_back(std::nullopt);
1060
- }
1061
-
1062
- if (!updates_->column_) {
1063
- cache_.emplace_back(GetColumnName(column_family_id));
1064
- } else {
1065
- cache_.emplace_back(std::nullopt);
1066
- }
1067
-
1068
- return rocksdb::Status::OK();
1069
- }
1070
-
1071
- rocksdb::Status DeleteCF(uint32_t column_family_id, const rocksdb::Slice& key) override {
1072
- if (updates_->column_ && updates_->column_->GetID() != column_family_id) {
1073
- return rocksdb::Status::OK();
1074
- }
1075
-
1076
- cache_.emplace_back("del");
1077
-
1078
- if (updates_->keys_) {
1079
- cache_.emplace_back(key.ToStringView());
1080
- } else {
1081
- cache_.emplace_back(std::nullopt);
1082
- }
1083
-
1084
- cache_.emplace_back(std::nullopt);
1085
-
1086
- if (!updates_->column_) {
1087
- cache_.emplace_back(GetColumnName(column_family_id));
1088
- } else {
1089
- cache_.emplace_back(std::nullopt);
1090
- }
1091
-
1092
- return rocksdb::Status::OK();
1093
- }
1094
-
1095
- rocksdb::Status MergeCF(uint32_t column_family_id, const rocksdb::Slice& key, const rocksdb::Slice& value) override {
1096
- if (updates_->column_ && updates_->column_->GetID() != column_family_id) {
1097
- return rocksdb::Status::OK();
1098
- }
1099
-
1100
- cache_.emplace_back("merge");
1101
-
1102
- if (updates_->keys_) {
1103
- cache_.emplace_back(key.ToStringView());
1104
- } else {
1105
- cache_.emplace_back(std::nullopt);
1106
- }
1107
-
1108
- if (updates_->values_) {
1109
- cache_.emplace_back(value.ToStringView());
1110
- } else {
1111
- cache_.emplace_back(std::nullopt);
1112
- }
1113
-
1114
- if (!updates_->column_) {
1115
- cache_.emplace_back(GetColumnName(column_family_id));
1116
- } else {
1117
- cache_.emplace_back(std::nullopt);
1118
- }
1119
-
1120
- return rocksdb::Status::OK();
1121
- }
1122
-
1123
- void LogData(const rocksdb::Slice& data) override {
1124
- if (updates_->data_) {
1125
- cache_.emplace_back("data");
1126
- cache_.emplace_back(std::nullopt);
1127
- cache_.emplace_back(data.ToStringView());
1128
- cache_.emplace_back(std::nullopt);
1129
- }
1130
- }
1131
-
1132
- bool Continue() override { return true; }
1133
-
1134
1216
  private:
1135
1217
  int64_t count_ = -1;
1136
- std::vector<std::optional<std::string>> cache_;
1218
+ std::unique_ptr<rocksdb::WriteBatch> batch_;
1137
1219
  Updates* updates_;
1138
1220
  };
1139
1221
 
@@ -1163,11 +1245,13 @@ NAPI_METHOD(updates_init) {
1163
1245
  NAPI_STATUS_THROWS(napi_get_named_property(env, argv[1], "data", &dataProperty));
1164
1246
  NAPI_STATUS_THROWS(napi_get_value_bool(env, dataProperty, &data));
1165
1247
 
1166
- // TODO (fix): Needs to support { column: null }
1248
+ const bool keyAsBuffer = EncodingIsBuffer(env, argv[1], "keyEncoding");
1249
+ const bool valueAsBuffer = EncodingIsBuffer(env, argv[1], "valueEncoding");
1250
+
1167
1251
  rocksdb::ColumnFamilyHandle* column;
1168
- NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[1], &column, false));
1252
+ NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[1], &column));
1169
1253
 
1170
- auto updates = std::make_unique<Updates>(database, since, keys, values, data, column);
1254
+ auto updates = std::make_unique<Updates>(database, since, keys, values, data, column, keyAsBuffer, valueAsBuffer);
1171
1255
 
1172
1256
  napi_value result;
1173
1257
  NAPI_STATUS_THROWS(napi_create_external(env, updates.get(), Finalize<Updates>, updates.get(), &result));
@@ -1203,102 +1287,6 @@ NAPI_METHOD(updates_close) {
1203
1287
  return 0;
1204
1288
  }
1205
1289
 
1206
- NAPI_METHOD(db_put) {
1207
- NAPI_ARGV(4);
1208
-
1209
- Database* database;
1210
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1211
-
1212
- rocksdb::PinnableSlice key;
1213
- NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1214
-
1215
- rocksdb::PinnableSlice val;
1216
- NAPI_STATUS_THROWS(ToString(env, argv[2], val));
1217
-
1218
- rocksdb::ColumnFamilyHandle* column;
1219
- NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[3], &column));
1220
-
1221
- rocksdb::WriteOptions writeOptions;
1222
- ROCKS_STATUS_THROWS(database->db_->Put(writeOptions, column, key, val));
1223
-
1224
- return 0;
1225
- }
1226
-
1227
- struct GetWorker final : public Worker {
1228
- GetWorker(napi_env env,
1229
- Database* database,
1230
- rocksdb::ColumnFamilyHandle* column,
1231
- napi_value callback,
1232
- const std::string& key,
1233
- const bool asBuffer,
1234
- const bool fillCache)
1235
- : Worker(env, database, callback, "rocks_level.db.get"),
1236
- column_(column),
1237
- key_(key),
1238
- asBuffer_(asBuffer),
1239
- fillCache_(fillCache),
1240
- snapshot_(database_->db_->GetSnapshot(),
1241
- [this](const rocksdb::Snapshot* ptr) { database_->db_->ReleaseSnapshot(ptr); }) {
1242
- database_->IncrementPriorityWork(env);
1243
- }
1244
-
1245
- rocksdb::Status Execute(Database& database) override {
1246
- rocksdb::ReadOptions readOptions;
1247
- readOptions.fill_cache = fillCache_;
1248
- readOptions.snapshot = snapshot_.get();
1249
-
1250
- auto status = database.db_->Get(readOptions, column_, key_, &value_);
1251
-
1252
- key_.clear();
1253
- snapshot_ = nullptr;
1254
-
1255
- return status;
1256
- }
1257
-
1258
- napi_status OnOk(napi_env env, napi_value callback) override {
1259
- napi_value argv[2];
1260
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1261
-
1262
- NAPI_STATUS_RETURN(Convert(env, &value_, asBuffer_, argv[1]));
1263
-
1264
- return CallFunction(env, callback, 2, argv);
1265
- }
1266
-
1267
- void Destroy(napi_env env) override {
1268
- database_->DecrementPriorityWork(env);
1269
- Worker::Destroy(env);
1270
- }
1271
-
1272
- private:
1273
- rocksdb::ColumnFamilyHandle* column_;
1274
- std::string key_;
1275
- rocksdb::PinnableSlice value_;
1276
- const bool asBuffer_;
1277
- const bool fillCache_;
1278
- std::shared_ptr<const rocksdb::Snapshot> snapshot_;
1279
- };
1280
-
1281
- NAPI_METHOD(db_get) {
1282
- NAPI_ARGV(4);
1283
-
1284
- Database* database;
1285
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1286
-
1287
- std::string key;
1288
- NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1289
-
1290
- const auto asBuffer = EncodingIsBuffer(env, argv[2], "valueEncoding");
1291
- const auto fillCache = BooleanProperty(env, argv[2], "fillCache").value_or(true);
1292
-
1293
- rocksdb::ColumnFamilyHandle* column;
1294
- NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[2], &column));
1295
-
1296
- auto worker = new GetWorker(env, database, column, argv[3], key, asBuffer, fillCache);
1297
- worker->Queue(env);
1298
-
1299
- return 0;
1300
- }
1301
-
1302
1290
  struct GetManyWorker final : public Worker {
1303
1291
  GetManyWorker(napi_env env,
1304
1292
  Database* database,
@@ -1388,50 +1376,6 @@ struct GetManyWorker final : public Worker {
1388
1376
  const rocksdb::Snapshot* snapshot_;
1389
1377
  };
1390
1378
 
1391
- typedef std::vector<std::string> Vector;
1392
-
1393
- NAPI_METHOD(vector_init) {
1394
- auto vector = new Vector();
1395
-
1396
- napi_value result;
1397
- NAPI_STATUS_THROWS(napi_create_external(env, vector, Finalize<Vector>, vector, &result));
1398
- }
1399
-
1400
- NAPI_METHOD(vector_push) {
1401
- NAPI_ARGV(2);
1402
-
1403
- Vector* vector;
1404
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&vector)));
1405
-
1406
- std::string value;
1407
- NAPI_STATUS_THROWS(ToString(env, argv[1], value));
1408
-
1409
- vector->push_back(std::move(value));
1410
- }
1411
-
1412
- NAPI_METHOD(db_get_many2) {
1413
- NAPI_ARGV(4);
1414
-
1415
- Database* database;
1416
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1417
-
1418
- Vector* vector;
1419
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&vector)));
1420
-
1421
- const bool asBuffer = EncodingIsBuffer(env, argv[2], "valueEncoding");
1422
- const bool fillCache = BooleanProperty(env, argv[2], "fillCache").value_or(true);
1423
- const bool ignoreRangeDeletions = BooleanProperty(env, argv[2], "ignoreRangeDeletions").value_or(false);
1424
-
1425
- rocksdb::ColumnFamilyHandle* column;
1426
- NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[2], &column));
1427
-
1428
- auto worker =
1429
- new GetManyWorker(env, database, column, std::move(*vector), argv[3], asBuffer, fillCache, ignoreRangeDeletions);
1430
- worker->Queue(env);
1431
-
1432
- return 0;
1433
- }
1434
-
1435
1379
  NAPI_METHOD(db_get_many) {
1436
1380
  NAPI_ARGV(4);
1437
1381
 
@@ -1465,24 +1409,6 @@ NAPI_METHOD(db_get_many) {
1465
1409
  return 0;
1466
1410
  }
1467
1411
 
1468
- NAPI_METHOD(db_del) {
1469
- NAPI_ARGV(3);
1470
-
1471
- Database* database;
1472
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1473
-
1474
- rocksdb::PinnableSlice key;
1475
- NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1476
-
1477
- rocksdb::ColumnFamilyHandle* column;
1478
- NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[2], &column));
1479
-
1480
- rocksdb::WriteOptions writeOptions;
1481
- ROCKS_STATUS_THROWS(database->db_->Delete(writeOptions, column, key));
1482
-
1483
- return 0;
1484
- }
1485
-
1486
1412
  NAPI_METHOD(db_clear) {
1487
1413
  NAPI_ARGV(2);
1488
1414
 
@@ -1851,11 +1777,6 @@ NAPI_METHOD(batch_do) {
1851
1777
  }
1852
1778
 
1853
1779
  NAPI_METHOD(batch_init) {
1854
- NAPI_ARGV(1);
1855
-
1856
- Database* database;
1857
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1858
-
1859
1780
  auto batch = new rocksdb::WriteBatch();
1860
1781
 
1861
1782
  napi_value result;
@@ -1865,53 +1786,79 @@ NAPI_METHOD(batch_init) {
1865
1786
  }
1866
1787
 
1867
1788
  NAPI_METHOD(batch_put) {
1868
- NAPI_ARGV(5);
1869
-
1870
- Database* database;
1871
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1789
+ NAPI_ARGV(4);
1872
1790
 
1873
1791
  rocksdb::WriteBatch* batch;
1874
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], (void**)(&batch)));
1792
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)(&batch)));
1875
1793
 
1876
1794
  rocksdb::PinnableSlice key;
1877
- NAPI_STATUS_THROWS(ToString(env, argv[2], key));
1795
+ NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1878
1796
 
1879
1797
  rocksdb::PinnableSlice val;
1880
- NAPI_STATUS_THROWS(ToString(env, argv[3], val));
1798
+ NAPI_STATUS_THROWS(ToString(env, argv[2], val));
1881
1799
 
1882
1800
  rocksdb::ColumnFamilyHandle* column;
1883
- NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[4], &column));
1801
+ NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[3], &column));
1884
1802
 
1885
- ROCKS_STATUS_THROWS(batch->Put(column, key, val));
1803
+ if (column) {
1804
+ ROCKS_STATUS_THROWS(batch->Put(column, key, val));
1805
+ } else {
1806
+ ROCKS_STATUS_THROWS(batch->Put(key, val));
1807
+ }
1886
1808
 
1887
1809
  return 0;
1888
1810
  }
1889
1811
 
1890
1812
  NAPI_METHOD(batch_del) {
1891
- NAPI_ARGV(4);
1813
+ NAPI_ARGV(3);
1892
1814
 
1893
- Database* database;
1894
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1815
+ rocksdb::WriteBatch* batch;
1816
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
1817
+
1818
+ rocksdb::PinnableSlice key;
1819
+ NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1820
+
1821
+ rocksdb::ColumnFamilyHandle* column;
1822
+ NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[2], &column));
1823
+
1824
+ if (column) {
1825
+ ROCKS_STATUS_THROWS(batch->Delete(column, key));
1826
+ } else {
1827
+ ROCKS_STATUS_THROWS(batch->Delete(key));
1828
+ }
1829
+
1830
+ return 0;
1831
+ }
1832
+
1833
+ NAPI_METHOD(batch_merge) {
1834
+ NAPI_ARGV(4);
1895
1835
 
1896
1836
  rocksdb::WriteBatch* batch;
1897
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
1837
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)(&batch)));
1898
1838
 
1899
1839
  rocksdb::PinnableSlice key;
1900
- NAPI_STATUS_THROWS(ToString(env, argv[2], key));
1840
+ NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1841
+
1842
+ rocksdb::PinnableSlice val;
1843
+ NAPI_STATUS_THROWS(ToString(env, argv[2], val));
1901
1844
 
1902
1845
  rocksdb::ColumnFamilyHandle* column;
1903
- NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[3], &column));
1846
+ NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[3], &column));
1904
1847
 
1905
- ROCKS_STATUS_THROWS(batch->Delete(column, key));
1848
+ if (column) {
1849
+ ROCKS_STATUS_THROWS(batch->Merge(column, key, val));
1850
+ } else {
1851
+ ROCKS_STATUS_THROWS(batch->Merge(key, val));
1852
+ }
1906
1853
 
1907
1854
  return 0;
1908
1855
  }
1909
1856
 
1910
1857
  NAPI_METHOD(batch_clear) {
1911
- NAPI_ARGV(2);
1858
+ NAPI_ARGV(1);
1912
1859
 
1913
1860
  rocksdb::WriteBatch* batch;
1914
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
1861
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
1915
1862
 
1916
1863
  batch->Clear();
1917
1864
 
@@ -1934,53 +1881,65 @@ NAPI_METHOD(batch_write) {
1934
1881
  }
1935
1882
 
1936
1883
  NAPI_METHOD(batch_put_log_data) {
1937
- NAPI_ARGV(4);
1938
-
1939
- Database* database;
1940
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1884
+ NAPI_ARGV(3);
1941
1885
 
1942
1886
  rocksdb::WriteBatch* batch;
1943
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
1887
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
1944
1888
 
1945
1889
  rocksdb::PinnableSlice logData;
1946
- NAPI_STATUS_THROWS(ToString(env, argv[2], logData));
1890
+ NAPI_STATUS_THROWS(ToString(env, argv[1], logData));
1947
1891
 
1948
1892
  ROCKS_STATUS_THROWS(batch->PutLogData(logData));
1949
1893
 
1950
1894
  return 0;
1951
1895
  }
1952
1896
 
1953
- NAPI_METHOD(batch_merge) {
1954
- NAPI_ARGV(5);
1897
+ NAPI_METHOD(batch_count) {
1898
+ NAPI_ARGV(1);
1899
+
1900
+ rocksdb::WriteBatch* batch;
1901
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
1902
+
1903
+ napi_value result;
1904
+ NAPI_STATUS_THROWS(napi_create_int64(env, batch->Count(), &result));
1905
+
1906
+ return result;
1907
+ }
1908
+
1909
+ NAPI_METHOD(batch_iterate) {
1910
+ NAPI_ARGV(3);
1955
1911
 
1956
1912
  Database* database;
1957
1913
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1958
1914
 
1959
1915
  rocksdb::WriteBatch* batch;
1960
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], (void**)(&batch)));
1961
-
1962
- rocksdb::PinnableSlice key;
1963
- NAPI_STATUS_THROWS(ToString(env, argv[2], key));
1964
-
1965
- rocksdb::PinnableSlice val;
1966
- NAPI_STATUS_THROWS(ToString(env, argv[3], val));
1916
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
1967
1917
 
1968
- rocksdb::ColumnFamilyHandle* column;
1969
- NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[4], &column));
1918
+ napi_value keysProperty;
1919
+ bool keys;
1920
+ NAPI_STATUS_THROWS(napi_get_named_property(env, argv[2], "keys", &keysProperty));
1921
+ NAPI_STATUS_THROWS(napi_get_value_bool(env, keysProperty, &keys));
1970
1922
 
1971
- ROCKS_STATUS_THROWS(batch->Merge(column, key, val));
1923
+ napi_value valuesProperty;
1924
+ bool values;
1925
+ NAPI_STATUS_THROWS(napi_get_named_property(env, argv[2], "values", &valuesProperty));
1926
+ NAPI_STATUS_THROWS(napi_get_value_bool(env, valuesProperty, &values));
1972
1927
 
1973
- return 0;
1974
- }
1928
+ napi_value dataProperty;
1929
+ bool data;
1930
+ NAPI_STATUS_THROWS(napi_get_named_property(env, argv[2], "data", &dataProperty));
1931
+ NAPI_STATUS_THROWS(napi_get_value_bool(env, dataProperty, &data));
1975
1932
 
1976
- NAPI_METHOD(batch_count) {
1977
- NAPI_ARGV(2);
1933
+ const bool keyAsBuffer = EncodingIsBuffer(env, argv[1], "keyEncoding");
1934
+ const bool valueAsBuffer = EncodingIsBuffer(env, argv[1], "valueEncoding");
1978
1935
 
1979
- rocksdb::WriteBatch* batch;
1980
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
1936
+ rocksdb::ColumnFamilyHandle* column;
1937
+ NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[2], &column));
1981
1938
 
1982
1939
  napi_value result;
1983
- NAPI_STATUS_THROWS(napi_create_int64(env, batch->Count(), &result));
1940
+ BatchIterator iterator(nullptr, keys, values, data, column, keyAsBuffer, valueAsBuffer);
1941
+
1942
+ NAPI_STATUS_THROWS(iterator.Iterate(env, *batch, &result));
1984
1943
 
1985
1944
  return result;
1986
1945
  }
@@ -2065,10 +2024,7 @@ NAPI_INIT() {
2065
2024
  NAPI_EXPORT_FUNCTION(db_init);
2066
2025
  NAPI_EXPORT_FUNCTION(db_open);
2067
2026
  NAPI_EXPORT_FUNCTION(db_close);
2068
- NAPI_EXPORT_FUNCTION(db_put);
2069
- NAPI_EXPORT_FUNCTION(db_get);
2070
2027
  NAPI_EXPORT_FUNCTION(db_get_many);
2071
- NAPI_EXPORT_FUNCTION(db_del);
2072
2028
  NAPI_EXPORT_FUNCTION(db_clear);
2073
2029
  NAPI_EXPORT_FUNCTION(db_get_property);
2074
2030
  NAPI_EXPORT_FUNCTION(db_get_latest_sequence);
@@ -2096,8 +2052,5 @@ NAPI_INIT() {
2096
2052
  NAPI_EXPORT_FUNCTION(batch_put_log_data);
2097
2053
  NAPI_EXPORT_FUNCTION(batch_merge);
2098
2054
  NAPI_EXPORT_FUNCTION(batch_count);
2099
-
2100
- NAPI_EXPORT_FUNCTION(vector_init);
2101
- NAPI_EXPORT_FUNCTION(vector_push);
2102
- NAPI_EXPORT_FUNCTION(db_get_many2);
2055
+ NAPI_EXPORT_FUNCTION(batch_iterate);
2103
2056
  }
package/chained-batch.js CHANGED
@@ -2,55 +2,110 @@
2
2
 
3
3
  const { AbstractChainedBatch } = require('abstract-level')
4
4
  const binding = require('./binding')
5
+ const ModuleError = require('module-error')
6
+ const { fromCallback } = require('catering')
5
7
 
6
- const kDbContext = Symbol('db')
7
- const kBatchContext = Symbol('context')
8
+ const kWrite = Symbol('write')
9
+ const kBatchContext = Symbol('batchContext')
10
+ const kDbContext = Symbol('dbContext')
11
+ const kPromise = Symbol('promise')
12
+
13
+ const EMPTY = {}
8
14
 
9
15
  class ChainedBatch extends AbstractChainedBatch {
10
- constructor (db, context) {
16
+ constructor (db, context, write) {
11
17
  super(db)
12
18
 
19
+ this[kWrite] = write
13
20
  this[kDbContext] = context
14
- this[kBatchContext] = binding.batch_init(this[kDbContext])
21
+ this[kBatchContext] = binding.batch_init()
15
22
  }
16
23
 
17
24
  _put (key, value, options) {
18
- binding.batch_put(this[kDbContext], this[kBatchContext], key, value, options)
25
+ if (key === null || key === undefined) {
26
+ throw new ModuleError('Key cannot be null or undefined', {
27
+ code: 'LEVEL_INVALID_KEY'
28
+ })
29
+ }
30
+
31
+ if (value === null || value === undefined) {
32
+ throw new ModuleError('value cannot be null or undefined', {
33
+ code: 'LEVEL_INVALID_VALUE'
34
+ })
35
+ }
36
+
37
+ binding.batch_put(this[kBatchContext], key, value, options ?? EMPTY)
19
38
  }
20
39
 
21
40
  _del (key, options) {
22
- binding.batch_del(this[kDbContext], this[kBatchContext], key, options)
41
+ if (key === null || key === undefined) {
42
+ throw new ModuleError('Key cannot be null or undefined', {
43
+ code: 'LEVEL_INVALID_KEY'
44
+ })
45
+ }
46
+
47
+ binding.batch_del(this[kBatchContext], key, options ?? EMPTY)
23
48
  }
24
49
 
25
50
  _clear () {
26
- binding.batch_clear(this[kDbContext], this[kBatchContext])
51
+ binding.batch_clear(this[kBatchContext])
27
52
  }
28
53
 
29
54
  _write (options, callback) {
30
- try {
31
- binding.batch_write(this[kDbContext], this[kBatchContext], options)
32
- process.nextTick(callback, null)
33
- } catch (err) {
34
- process.nextTick(callback, err)
35
- }
55
+ callback = fromCallback(callback, kPromise)
56
+
57
+ this[kWrite](this, this[kBatchContext], options ?? EMPTY, callback)
58
+
59
+ return callback[kPromise]
36
60
  }
37
61
 
38
62
  _close (callback) {
39
63
  process.nextTick(callback)
40
64
  }
41
65
 
42
- putLogData (data, options) {
43
- // TODO (fix): Check if open...
44
- binding.batch_put_log_data(this[kDbContext], this[kBatchContext], data, options)
66
+ get length () {
67
+ return binding.batch_count(this[kBatchContext])
45
68
  }
46
69
 
47
- merge (key, value, options = {}) {
48
- // TODO (fix): Check if open...
49
- binding.batch_merge(this[kDbContext], this[kBatchContext], key, value, options)
70
+ _putLogData (value, options) {
71
+ if (value === null || value === undefined) {
72
+ throw new ModuleError('value cannot be null or undefined', {
73
+ code: 'LEVEL_INVALID_VALUE'
74
+ })
75
+ }
76
+
77
+ binding.batch_put_log_data(this[kBatchContext], value, options ?? EMPTY)
50
78
  }
51
79
 
52
- get count () {
53
- return binding.batch_count(this[kDbContext], this[kBatchContext])
80
+ _merge (key, value, options) {
81
+ if (key === null || key === undefined) {
82
+ throw new ModuleError('Key cannot be null or undefined', {
83
+ code: 'LEVEL_INVALID_KEY'
84
+ })
85
+ }
86
+
87
+ if (value === null || value === undefined) {
88
+ throw new ModuleError('value cannot be null or undefined', {
89
+ code: 'LEVEL_INVALID_VALUE'
90
+ })
91
+ }
92
+
93
+ binding.batch_merge(this[kBatchContext], key, value, options ?? EMPTY)
94
+ }
95
+
96
+ * [Symbol.iterator] () {
97
+ const rows = binding.batch_iterate(this[kDbContext], this[kBatchContext], {
98
+ keys: true,
99
+ values: true,
100
+ data: true
101
+ })
102
+ for (let n = 0; n < rows.length; n += 4) {
103
+ yield {
104
+ type: rows[n + 0],
105
+ key: rows[n + 1],
106
+ value: rows[n + 2]
107
+ }
108
+ }
54
109
  }
55
110
  }
56
111
 
package/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const { fromCallback } = require('catering')
3
4
  const { AbstractLevel } = require('abstract-level')
4
5
  const ModuleError = require('module-error')
5
6
  const fs = require('fs')
@@ -11,6 +12,9 @@ const os = require('os')
11
12
  const kContext = Symbol('context')
12
13
  const kColumns = Symbol('columns')
13
14
  const kLocation = Symbol('location')
15
+ const kPromise = Symbol('promise')
16
+
17
+ const EMPTY = {}
14
18
 
15
19
  class RocksLevel extends AbstractLevel {
16
20
  constructor (location, options, _) {
@@ -95,55 +99,101 @@ class RocksLevel extends AbstractLevel {
95
99
  }
96
100
 
97
101
  _put (key, value, options, callback) {
102
+ callback = fromCallback(callback, kPromise)
103
+
98
104
  try {
99
- binding.db_put(this[kContext], key, value, options)
100
- process.nextTick(callback, null)
105
+ const batch = this.batch()
106
+ batch.put(key, value, options ?? EMPTY)
107
+ batch.write(callback)
101
108
  } catch (err) {
102
109
  process.nextTick(callback, err)
103
110
  }
111
+
112
+ return callback[kPromise]
104
113
  }
105
114
 
106
115
  _get (key, options, callback) {
107
- binding.db_get(this[kContext], key, options, callback)
116
+ this._getMany([key], options ?? EMPTY, (err, val) => {
117
+ if (err) {
118
+ callback(err)
119
+ } else if (val[0] === undefined) {
120
+ callback(Object.assign(new Error('not found'), {
121
+ code: 'LEVEL_NOT_FOUND'
122
+ }))
123
+ } else {
124
+ callback(null, val[0])
125
+ }
126
+ })
108
127
  }
109
128
 
110
129
  _getMany (keys, options, callback) {
111
- binding.db_get_many(this[kContext], keys, options, callback)
130
+ callback = fromCallback(callback, kPromise)
131
+
132
+ try {
133
+ binding.db_get_many(this[kContext], keys, options ?? EMPTY, callback)
134
+ } catch (err) {
135
+ process.nextTick(callback, err)
136
+ }
137
+
138
+ return callback[kPromise]
112
139
  }
113
140
 
114
141
  _del (key, options, callback) {
142
+ callback = fromCallback(callback, kPromise)
143
+
115
144
  try {
116
- binding.db_del(this[kContext], key, options)
117
- process.nextTick(callback, null)
145
+ const batch = this.batch()
146
+ batch.del(key, options ?? EMPTY)
147
+ batch.write(callback)
118
148
  } catch (err) {
119
149
  process.nextTick(callback, err)
120
150
  }
151
+
152
+ return callback[kPromise]
121
153
  }
122
154
 
123
155
  _clear (options, callback) {
156
+ callback = fromCallback(callback, kPromise)
157
+
124
158
  try {
125
- binding.db_clear(this[kContext], options)
159
+ // TODO (fix): Use batch + DeleteRange...
160
+ binding.db_clear(this[kContext], options ?? EMPTY)
126
161
  process.nextTick(callback, null)
127
162
  } catch (err) {
128
163
  process.nextTick(callback, err)
129
164
  }
165
+
166
+ return callback[kPromise]
130
167
  }
131
168
 
132
169
  _chainedBatch () {
133
- return new ChainedBatch(this, this[kContext])
170
+ return new ChainedBatch(this, this[kContext], (batch, context, options, callback) => {
171
+ try {
172
+ const seq = this.sequence
173
+ binding.batch_write(this[kContext], context, options)
174
+ this.emit('write', batch, seq + 1)
175
+ process.nextTick(callback, null)
176
+ } catch (err) {
177
+ process.nextTick(callback, err)
178
+ }
179
+ })
134
180
  }
135
181
 
136
182
  _batch (operations, options, callback) {
183
+ callback = fromCallback(callback, kPromise)
184
+
137
185
  try {
138
- binding.batch_do(this[kContext], operations, options)
186
+ binding.batch_do(this[kContext], operations, options ?? EMPTY)
139
187
  process.nextTick(callback, null)
140
188
  } catch (err) {
141
189
  process.nextTick(callback, err)
142
190
  }
191
+
192
+ return callback[kPromise]
143
193
  }
144
194
 
145
195
  _iterator (options) {
146
- return new Iterator(this, this[kContext], options)
196
+ return new Iterator(this, this[kContext], options ?? EMPTY)
147
197
  }
148
198
 
149
199
  getProperty (property) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/rocksdb",
3
- "version": "7.0.44",
3
+ "version": "7.0.47",
4
4
  "description": "A low-level Node.js RocksDB binding",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -12,7 +12,8 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "abstract-level": "^1.0.2",
15
- "module-error": "^1.0.1",
15
+ "catering": "^2.1.1",
16
+ "module-error": "^1.0.2",
16
17
  "napi-macros": "~2.0.0",
17
18
  "node-gyp-build": "^4.3.0"
18
19
  },
Binary file
Binary file