Packages
rocksdb
0.23.0
3.1.1
3.1.0
3.0.0
2.6.2
2.6.1
retired
2.6.0
retired
2.5.0
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
1.9.0
1.8.0
1.7.0
1.6.0
1.5.1
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.1
1.1.0
1.0.0
0.26.2
0.26.1
0.26.0
0.25.0
0.24.0
0.23.3
0.23.2
0.23.1
0.23.0
0.22.0
0.21.0
0.20.1
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
RocksDB for Erlang
Current section
Files
Jump to
Current section
Files
deps/rocksdb/utilities/document/document_db_test.cc
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#ifndef ROCKSDB_LITE
#include <algorithm>
#include "rocksdb/utilities/json_document.h"
#include "rocksdb/utilities/document_db.h"
#include "util/testharness.h"
#include "util/testutil.h"
namespace rocksdb {
class DocumentDBTest : public testing::Test {
public:
DocumentDBTest() {
dbname_ = test::PerThreadDBPath("document_db_test");
DestroyDB(dbname_, Options());
}
~DocumentDBTest() {
delete db_;
DestroyDB(dbname_, Options());
}
void AssertCursorIDs(Cursor* cursor, std::vector<int64_t> expected) {
std::vector<int64_t> got;
while (cursor->Valid()) {
ASSERT_TRUE(cursor->Valid());
ASSERT_TRUE(cursor->document().Contains("_id"));
got.push_back(cursor->document()["_id"].GetInt64());
cursor->Next();
}
std::sort(expected.begin(), expected.end());
std::sort(got.begin(), got.end());
ASSERT_TRUE(got == expected);
}
// converts ' to ", so that we don't have to escape " all over the place
std::string ConvertQuotes(const std::string& input) {
std::string output;
for (auto x : input) {
if (x == '\'') {
output.push_back('\"');
} else {
output.push_back(x);
}
}
return output;
}
void CreateIndexes(std::vector<DocumentDB::IndexDescriptor> indexes) {
for (auto i : indexes) {
ASSERT_OK(db_->CreateIndex(WriteOptions(), i));
}
}
JSONDocument* Parse(const std::string& doc) {
return JSONDocument::ParseJSON(ConvertQuotes(doc).c_str());
}
std::string dbname_;
DocumentDB* db_;
};
TEST_F(DocumentDBTest, SimpleQueryTest) {
DocumentDBOptions options;
DocumentDB::IndexDescriptor index;
index.description = Parse("{\"name\": 1}");
index.name = "name_index";
ASSERT_OK(DocumentDB::Open(options, dbname_, {}, &db_));
CreateIndexes({index});
delete db_;
// now there is index present
ASSERT_OK(DocumentDB::Open(options, dbname_, {index}, &db_));
delete index.description;
std::vector<std::string> json_objects = {
"{\"_id\': 1, \"name\": \"One\"}", "{\"_id\": 2, \"name\": \"Two\"}",
"{\"_id\": 3, \"name\": \"Three\"}", "{\"_id\": 4, \"name\": \"Four\"}"};
for (auto& json : json_objects) {
std::unique_ptr<JSONDocument> document(Parse(json));
ASSERT_TRUE(document.get() != nullptr);
ASSERT_OK(db_->Insert(WriteOptions(), *document));
}
// inserting a document with existing primary key should return failure
{
std::unique_ptr<JSONDocument> document(Parse(json_objects[0]));
ASSERT_TRUE(document.get() != nullptr);
Status s = db_->Insert(WriteOptions(), *document);
ASSERT_TRUE(s.IsInvalidArgument());
}
// find equal to "Two"
{
std::unique_ptr<JSONDocument> query(
Parse("[{'$filter': {'name': 'Two', '$index': 'name_index'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
AssertCursorIDs(cursor.get(), {2});
}
// find less than "Three"
{
std::unique_ptr<JSONDocument> query(Parse(
"[{'$filter': {'name': {'$lt': 'Three'}, '$index': "
"'name_index'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
AssertCursorIDs(cursor.get(), {1, 4});
}
// find less than "Three" without index
{
std::unique_ptr<JSONDocument> query(
Parse("[{'$filter': {'name': {'$lt': 'Three'} }}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
AssertCursorIDs(cursor.get(), {1, 4});
}
// remove less or equal to "Three"
{
std::unique_ptr<JSONDocument> query(
Parse("{'name': {'$lte': 'Three'}, '$index': 'name_index'}"));
ASSERT_OK(db_->Remove(ReadOptions(), WriteOptions(), *query));
}
// find all -- only "Two" left, everything else should be deleted
{
std::unique_ptr<JSONDocument> query(Parse("[]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
AssertCursorIDs(cursor.get(), {2});
}
}
TEST_F(DocumentDBTest, ComplexQueryTest) {
DocumentDBOptions options;
DocumentDB::IndexDescriptor priority_index;
priority_index.description = Parse("{'priority': 1}");
priority_index.name = "priority";
DocumentDB::IndexDescriptor job_name_index;
job_name_index.description = Parse("{'job_name': 1}");
job_name_index.name = "job_name";
DocumentDB::IndexDescriptor progress_index;
progress_index.description = Parse("{'progress': 1}");
progress_index.name = "progress";
ASSERT_OK(DocumentDB::Open(options, dbname_, {}, &db_));
CreateIndexes({priority_index, progress_index});
delete priority_index.description;
delete progress_index.description;
std::vector<std::string> json_objects = {
"{'_id': 1, 'job_name': 'play', 'priority': 10, 'progress': 14.2}",
"{'_id': 2, 'job_name': 'white', 'priority': 2, 'progress': 45.1}",
"{'_id': 3, 'job_name': 'straw', 'priority': 5, 'progress': 83.2}",
"{'_id': 4, 'job_name': 'temporary', 'priority': 3, 'progress': 14.9}",
"{'_id': 5, 'job_name': 'white', 'priority': 4, 'progress': 44.2}",
"{'_id': 6, 'job_name': 'tea', 'priority': 1, 'progress': 12.4}",
"{'_id': 7, 'job_name': 'delete', 'priority': 2, 'progress': 77.54}",
"{'_id': 8, 'job_name': 'rock', 'priority': 3, 'progress': 93.24}",
"{'_id': 9, 'job_name': 'steady', 'priority': 3, 'progress': 9.1}",
"{'_id': 10, 'job_name': 'white', 'priority': 1, 'progress': 61.4}",
"{'_id': 11, 'job_name': 'who', 'priority': 4, 'progress': 39.41}",
"{'_id': 12, 'job_name': 'who', 'priority': -1, 'progress': 39.42}",
"{'_id': 13, 'job_name': 'who', 'priority': -2, 'progress': 39.42}", };
// add index on the fly!
CreateIndexes({job_name_index});
delete job_name_index.description;
for (auto& json : json_objects) {
std::unique_ptr<JSONDocument> document(Parse(json));
ASSERT_TRUE(document != nullptr);
ASSERT_OK(db_->Insert(WriteOptions(), *document));
}
// 2 < priority < 4 AND progress > 10.0, index priority
{
std::unique_ptr<JSONDocument> query(Parse(
"[{'$filter': {'priority': {'$lt': 4, '$gt': 2}, 'progress': {'$gt': "
"10.0}, '$index': 'priority'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
AssertCursorIDs(cursor.get(), {4, 8});
}
// -1 <= priority <= 1, index priority
{
std::unique_ptr<JSONDocument> query(Parse(
"[{'$filter': {'priority': {'$lte': 1, '$gte': -1},"
" '$index': 'priority'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
AssertCursorIDs(cursor.get(), {6, 10, 12});
}
// 2 < priority < 4 AND progress > 10.0, index progress
{
std::unique_ptr<JSONDocument> query(Parse(
"[{'$filter': {'priority': {'$lt': 4, '$gt': 2}, 'progress': {'$gt': "
"10.0}, '$index': 'progress'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
AssertCursorIDs(cursor.get(), {4, 8});
}
// job_name == 'white' AND priority >= 2, index job_name
{
std::unique_ptr<JSONDocument> query(Parse(
"[{'$filter': {'job_name': 'white', 'priority': {'$gte': "
"2}, '$index': 'job_name'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
AssertCursorIDs(cursor.get(), {2, 5});
}
// 35.0 <= progress < 65.5, index progress
{
std::unique_ptr<JSONDocument> query(Parse(
"[{'$filter': {'progress': {'$gt': 5.0, '$gte': 35.0, '$lt': 65.5}, "
"'$index': 'progress'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
AssertCursorIDs(cursor.get(), {2, 5, 10, 11, 12, 13});
}
// 2 < priority <= 4, index priority
{
std::unique_ptr<JSONDocument> query(Parse(
"[{'$filter': {'priority': {'$gt': 2, '$lt': 8, '$lte': 4}, "
"'$index': 'priority'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
AssertCursorIDs(cursor.get(), {4, 5, 8, 9, 11});
}
// Delete all whose progress is bigger than 50%
{
std::unique_ptr<JSONDocument> query(
Parse("{'progress': {'$gt': 50.0}, '$index': 'progress'}"));
ASSERT_OK(db_->Remove(ReadOptions(), WriteOptions(), *query));
}
// 2 < priority < 6, index priority
{
std::unique_ptr<JSONDocument> query(Parse(
"[{'$filter': {'priority': {'$gt': 2, '$lt': 6}, "
"'$index': 'priority'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
AssertCursorIDs(cursor.get(), {4, 5, 9, 11});
}
// update set priority to 10 where job_name is 'white'
{
std::unique_ptr<JSONDocument> query(Parse("{'job_name': 'white'}"));
std::unique_ptr<JSONDocument> update(Parse("{'$set': {'priority': 10}}"));
ASSERT_OK(db_->Update(ReadOptions(), WriteOptions(), *query, *update));
}
// update twice: set priority to 15 where job_name is 'white'
{
std::unique_ptr<JSONDocument> query(Parse("{'job_name': 'white'}"));
std::unique_ptr<JSONDocument> update(Parse("{'$set': {'priority': 10},"
"'$set': {'priority': 15}}"));
ASSERT_OK(db_->Update(ReadOptions(), WriteOptions(), *query, *update));
}
// update twice: set priority to 15 and
// progress to 40 where job_name is 'white'
{
std::unique_ptr<JSONDocument> query(Parse("{'job_name': 'white'}"));
std::unique_ptr<JSONDocument> update(
Parse("{'$set': {'priority': 10, 'progress': 35},"
"'$set': {'priority': 15, 'progress': 40}}"));
ASSERT_OK(db_->Update(ReadOptions(), WriteOptions(), *query, *update));
}
// priority < 0
{
std::unique_ptr<JSONDocument> query(
Parse("[{'$filter': {'priority': {'$lt': 0}, '$index': 'priority'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
ASSERT_OK(cursor->status());
AssertCursorIDs(cursor.get(), {12, 13});
}
// -2 < priority < 0
{
std::unique_ptr<JSONDocument> query(
Parse("[{'$filter': {'priority': {'$gt': -2, '$lt': 0},"
" '$index': 'priority'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
ASSERT_OK(cursor->status());
AssertCursorIDs(cursor.get(), {12});
}
// -2 <= priority < 0
{
std::unique_ptr<JSONDocument> query(
Parse("[{'$filter': {'priority': {'$gte': -2, '$lt': 0},"
" '$index': 'priority'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
ASSERT_OK(cursor->status());
AssertCursorIDs(cursor.get(), {12, 13});
}
// 4 < priority
{
std::unique_ptr<JSONDocument> query(
Parse("[{'$filter': {'priority': {'$gt': 4}, '$index': 'priority'}}]"));
std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
ASSERT_OK(cursor->status());
AssertCursorIDs(cursor.get(), {1, 2, 5});
}
Status s = db_->DropIndex("doesnt-exist");
ASSERT_TRUE(!s.ok());
ASSERT_OK(db_->DropIndex("priority"));
}
} // namespace rocksdb
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
#else
#include <stdio.h>
int main(int /*argc*/, char** /*argv*/) {
fprintf(stderr, "SKIPPED as DocumentDB is not supported in ROCKSDB_LITE\n");
return 0;
}
#endif // !ROCKSDB_LITE