Choose the language and namespace when executing a statement with Connection::Cursor. Available languages depend on the server’s installed language plugins.
| Data model | Query language | Driver language name |
|---|---|---|
| Relational | SQL | sql |
| Document | MongoQL | mongo |
| Labeled property graph | Cypher | cypher on a server that supports Cypher through Prism |
Build the programs with the Meson application setup. They use a local development server on 127.0.0.1:20590 with the pa account and an empty password. The MongoQL example creates and drops a document namespace. Start with that name available on a development server and use an account that can create and drop namespaces.
Choose a result type
The owning std::unique_ptr<Results::Result> returned by execute holds a RelationalResult, DocumentResult, GraphResult, or ScalarResult. Use get_result_type() when the type is unknown, then call unwrap<T>() for the concrete result. Release a result before issuing another statement on the same cursor. Keep the cursor and connection alive until then.
In v1.0.0, call end() again on each iteration as shown below. Fetching another page can advance the end of a relational, document or graph result while iterating.
SQL rows and column metadata
Use zero-based indexes or column labels to access a row’s values. get_metadata() gives you the columns returned by this query. Use the API reference for all column metadata getters.
#include <cstdint>
#include <iostream>
#include "PolyphenyCPPDriver.h"
int main() {
Connection::Connection connection("127.0.0.1", "pa", "");
Connection::Cursor cursor(connection);
auto result = cursor.execute(
"sql", "SELECT CAST(42 AS INTEGER) AS answer, CAST('Pear' AS VARCHAR(20)) AS name", "public"
);
auto* rows = result->unwrap<Results::RelationalResult>();
const auto metadata = rows->get_metadata();
for (std::uint32_t i = 0; i < metadata->get_column_count(); ++i) {
const auto column = metadata->get_column_meta(i);
std::cout << column.get_column_label() << " (" << column.get_protocol_type_name() << ")\n";
}
for (auto row = rows->begin(); row != rows->end(); ++row) {
std::cout << (*row)[0].as_int32_t() << ' ' << (*row).at("name").as_string() << '\n';
}
}
MongoQL documents and collection metadata
A document is a map of string keys to Types::TypedValue values. Use at() for a required key and find() when the key may be missing. Call as_document() to access a nested object.
The collection metadata calls below require a server that implements Prism 2.2 document metadata. search_entities() can also return table metadata as a Prism Protobuf message. get_document_collections() returns the C++ collection structs and accepts an optional server-side name pattern as its second argument.
#include <iostream>
#include "PolyphenyCPPDriver.h"
int main() {
Connection::Connection connection("127.0.0.1", "pa", "");
Connection::Cursor cursor(connection);
cursor.execute("sql", "CREATE DOCUMENT NAMESPACE cpp_docs_inventory", "public");
cursor.execute("mongo", R"(db.createCollection("products"))", "cpp_docs_inventory");
cursor.execute(
"mongo", R"(db.products.insertOne({name: "Pear", details: {color: "green"}}))",
"cpp_docs_inventory"
);
{
auto result = cursor.execute("mongo", "db.products.find()", "cpp_docs_inventory");
auto* documents = result->unwrap<Results::DocumentResult>();
for (auto document = documents->begin(); document != documents->end(); ++document) {
auto details = (*document).at("details").as_document();
std::cout << (*document).at("name").as_string() << ' '
<< details.at("color").as_string() << '\n';
}
}
const auto entities = connection.search_entities("cpp_docs_inventory", "products");
std::cout << "Matching entities: " << entities.entities_size() << '\n';
for (const auto& collection : connection.get_document_collections("cpp_docs_inventory", "products")) {
std::cout << collection.namespace_name << '.' << collection.collection_name << '\n';
for (const auto& field : collection.fields) {
std::cout << field.field_path << " (" << field.type_name << ')'
<< (field.is_optional ? " optional" : "") << '\n';
}
if (collection.sample_document_json) {
std::cout << *collection.sample_document_json << '\n';
}
for (const auto& index : collection.document_indexes) {
std::cout << index.field_path << " (" << index.index_type << ')'
<< (index.unique ? " unique" : "") << '\n';
}
}
cursor.execute("sql", "DROP NAMESPACE cpp_docs_inventory", "public");
}
The server can infer field types and optionality from sampled documents. A collection may return an empty field list or omit the JSON sample. Index availability depends on the storage adapter. Use the metadata field reference for field and index semantics.
Graph nodes and edges
Polypheny-DB’s Prism 2.2 interface currently executes relational and document queries. A Cypher request to that server fails with No result retriever registered for namespace type GRAPH. Use the Polypheny UI to run Cypher against a graph namespace.
The C++ driver can decode Prism graph frames when a server supplies them. A graph result contains shared pointers to graph elements. Each element provides an ID, labels, and a property map. Check get_element_type() before casting an edge to read its endpoint IDs. The following helper reads an existing graph result.
#include <iostream>
#include "PolyphenyCPPDriver.h"
#include "results/Edge.h"
void print_graph(Results::GraphResult& graph) {
for (auto item = graph.begin(); item != graph.end(); ++item) {
const auto element = *item;
if (element->get_element_type() == GraphElementType::NODE) {
std::cout << "Node " << element->get_id() << '\n';
} else {
const auto& edge = static_cast<const Results::Edge&>(*element);
std::cout << edge.get_left() << " -> " << edge.get_right() << '\n';
}
}
}
Handle errors
A server rejection during raw statement execution raises std::runtime_error. Synchronous requests such as preparation and metadata lookup can raise Errors::ServerError. A closed socket can raise Errors::ConnectionClosedError, and invalid result or value conversions can raise std::runtime_error. See exceptions and resource ownership for the error headers and cursor lifetime.