Early Adopters: First 20 receive 20% off with 1 year technical support.

RogueDB logo

RogueDB

DEVELOPERSENTERPRISEDOCSPRICING

Global Protocol

1. Direct Serialization & Type Safety

RogueDB eliminates the "string-matching" vulnerabilities common in SQL and NoSQL environments by using a Registry message with a oneof field for all data transport.

No Aliases or Typos: Because messages serialize directly, there is no risk of misspelling a table or column name in a query string.

Compile-Time Validation: By using the stubs generated from your .proto files, your IDE and compiler catch schema mismatches before the code ever runs.

Schema Synchronization: The database uses the exact same .proto files you provided during the Subscribe phase. This ensures the client and database are always in perfect lock-step.

2. The Write APIs (Insert, Update, Remove)

Write operations are optimized for asynchronous execution with automatic backpressure.

No Response Payload: Success is guaranteed if the stream completes without an error. Failures are reported via standard gRPC/REST status codes with additional context in the error messages.

Mixed Schema Batches: The database properly routes messages according to their schema server side. Send the entire payload in a single request.

Stop-on-Failure: The database processes requests sequentially. If an invalid request occurs, the stream terminates after processing all requests before the invalid request.

Data Integrity: No partial write data corruption with a dual write system (future).

Protobuf

message Insert {
    string api_key = 1; 
    repeated Registry messages = 2;
}

3. The Search API

Search uses expressions and conditions that match programmatic languages. The API allows retrieval for a single Schema type with Join capabilities scheduled and reserved for the OLAP API (future).

The Expression Tree

Queries are constructed using recursive Expression and Conditional blocks. The database executes this logic natively without the overhead of a query planner.

Protobuf

message Search
{
    string api_key = 1;
    repeated Expression queries = 2;
}

message Conditional
{
    ComparisonOperator comparison = 1;
    Registry operand = 2;
    uint32 field = 3;
}

message Expression
{
    LogicalOperator logical_operator = 1;
    repeated Conditional conditionals = 2;
    repeated Expression subexpressions = 3;
}

enum LogicalOperator
{
    AND = 0;
    OR = 1;
}

enum ComparisonOperator
{
    LESSER = 0;
    LESSER_EQUAL = 1;
    GREATER = 2;
    GREATER_EQUAL = 3;
    EQUAL = 4;
    NOT_EQUAL = 5;
}

4. Response Mapping & Completion

The database treats every Search request as a batch of independent queries. Results are returned in an indexed map to allow for asynchronous, multi-query pipelining.

Zero-Indexed Mapping: In the Response map, the key represents the order of the Expression sent. Query 0 maps to results[0], Query 1 to results[1], and so on.

Persistent Indices: Indices increment across the entire connection lifecycle. If the first message contains 5 queries (0–4), the second message begins at index 5.

The `finished` Signal: Because results may arrive in chunks, a query is only considered done when its index appears in the finished array.

Protobuf

message Response
{
    map<uint64, Messages> results = 1;
    repeated uint64 finished = 2;
}

5. Streaming & Flow Control

Clients must read from the stream while writing to prevent blocking. This enables streaming of results and prevents out-of-memory issues for both the client and RogueDB.

Signaling Completion

The database batches requests server-side, so an explicit signal should be sent when finished sending queries to prevent blocking.

gRPC

Perform a "half-close" (e.g., calling WritesDone).

Blocking States

Write Blocking

If the client does not read incoming Search results, the database may block further writes to prevent memory overflow.

Read Blocking

If the client listens for results without signaling the end of the request batch, the database may not process outstanding requests.

6. Example Usage

This requires an API key, JWT token, and database URL.

C++

Python

Go

// rogue::services::Update update{}; // Update API
// rogue::services::Remove remove{}; // Remove API
rogue::services::Insert request{}; // Insert API
request.set_api_key(API_KEY);

// Insert, Update, and Remove are identical in use.
rogue::services::Registry& registry{ *request.add_messages() };
registry.mutable_test()->set_attribute1(10);

std::unique_ptr<rogue::services::RogueDB::Stub> roguedb{ rogue::services::RogueDB::NewStub(
grpc::CreateChannel(
    std::format("{}:443", URL),
    grpc::SslCredentials(grpc::SslCredentialsOptions()))) };
    
grpc::ClientContext context{};
context.AddMetadata("Authorization", std::format("Bearer {}", ENCODED_JWT));
auto stream{ roguedb->insert(&context) };
// auto stream{ roguedb->update(&context) }; // Update API
// auto stream{ roguedb->remove(&context) }; // Remove API

stream->Write(request);
stream->WritesDone(); // Signal all queries sent. Otherwise, blocks.

// No response is given for Insert, Update, and Remove
// Any errors get reported in status.
grpc::Status status{ stream->Finish() };

rogue::services::Search search{};
search.set_api_key(API_KEY);
    
// Test's Index Fields: attribute1, attribute2, and attribute3.
// Search Query: Test.attribute1 >= 1 AND Test.attribute1 <= 10
rogue::services::Expression& expression{ *search.add_queries() };
expression.set_logical_operator(rogue::services::LogicalOperator::AND);

rogue::services::Conditional* conditional{ expression.add_conditionals() };
conditional->set_comparison(rogue::services::ComparisonOperator::GREATER_EQUAL);
conditional->mutable_test()->set_attribute1(1);
conditional->set_field(1);
 
conditional = expression.add_conditionals();
conditional->set_comparison(rogue::services::ComparisonOperator::LESSER_EQUAL);
conditional->mutable_test()->set_attribute1(10);
conditional->set_field(1);

grpc::ClientContext context{};
rogue::services::Response response{};
std::shared_ptr<grpc::ClientReaderWriter<
    rogue::services::Search, rogue::services::Response>> stream{
        roguedb->search(&context) };
        
stream->Write(search);
stream->WritesDone(); // Signal all queries sent. Otherwise, blocks.

// Multiple queries or large queries should be processed on a separate thread
// to prevent blocking the database.
stream->Read(&response);
status = stream->Finish(); // Signal all queries sent. Blocks otherwise.

// Queries are zero-indexed. Partial results get sent
// and mapped to that index.
for(const auto& result : response.results().at(0).messages())
{
    rogue::services::Test& temp{ result.test() };
}

On This Page