Early Adopters: First 20 receive 20% off with 1 year technical support.
Global Protocol
RogueDB provides four explicit APIs for data interaction: Insert, Update, Remove, and Search. These operations utilize high-throughput, bidirectional streaming with built-in batching.
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.
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;
}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).
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;
}
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;
}
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.
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).
If the client does not read incoming Search results, the database may block further writes to prevent memory overflow.
If the client listens for results without signaling the end of the request batch, the database may not process outstanding requests.
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() };
}