Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Infinispan Queries with C++ Client

DZone's Guide to

Infinispan Queries with C++ Client

Come check out how to issue queries against Infinispan using a C++ client known as Hotrod. Example code included!

· Database Zone ·
Free Resource

Download the Altoros NoSQL Performance Benchmark 2018. Compare top NoSQL solutions – Couchbase Server v5.5, MongoDB v3.6, and DataStax Enterprise v6 (Cassandra).

With the C++ Hotrod Client version 8, users can now run queries against Infinispan calling the cache.query() method with the query string as an argument. The query response can contain a result set of: entities, projections as well as aggregate values. The implementation follows the same design of the Java client and is based on Protobuf to define the entity model and to parse the resultset.

The following is an example of C++ query code. Git the full project here.

//Client Setup

This is the cache setup on the client side. Two caches are used:

  • The __protobuf_metadata cache, where the protobuf description of the model is stored.
  • The application cache, where the instances of the model's entities resides. 
#include "addressbook.pb.h"
#include "bank.pb.h"
#include <infinispan/hotrod/BasicTypesProtoStreamMarshaller.h>
#include <infinispan/hotrod/ProtoStreamMarshaller.h>
#include "infinispan/hotrod/ConfigurationBuilder.h"
#include "infinispan/hotrod/RemoteCacheManager.h"
#include "infinispan/hotrod/RemoteCache.h"
#include "infinispan/hotrod/Version.h"
#include "infinispan/hotrod/query.pb.h"
#include "infinispan/hotrod/QueryUtils.h"
#include <vector>
#include <tuple>

#define PROTOBUF_METADATA_CACHE_NAME "___protobuf_metadata"
#define ERRORS_KEY_SUFFIX  ".errors"

using namespace infinispan::hotrod;
using namespace org::infinispan::query::remote::client;

std::string read(std::string file)
{
std::ifstream t(file);
std::stringstream buffer;
buffer << t.rdbuf();
return buffer.str();
}

int main(int argc, char** argv) {
std::cout << "Tests for Query" << std::endl;
    ConfigurationBuilder builder;
    builder.addServer().host(argc > 1 ? argv[1] : "127.0.0.1").port(argc > 2 ? atoi(argv[2]) : 11222).protocolVersion(Configuration::PROTOCOL_VERSION_24);
    builder.balancingStrategyProducer(nullptr);
    RemoteCacheManager cacheManager(builder.build(), false);
    cacheManager.start();
    //Create the Protobuf Metadata cache peer with a Protobuf marshaller
    auto *km = new BasicTypesProtoStreamMarshaller<std::string>();
    auto *vm = new BasicTypesProtoStreamMarshaller<std::string>();
    auto metadataCache = cacheManager.getCache<std::string, std::string>(
    km, &Marshaller<std::string>::destroy, vm, &Marshaller<std::string>::destroy,PROTOBUF_METADATA_CACHE_NAME, false);
    // Install the data model into the Protobuf metadata cache
    metadataCache.put("sample_bank_account/bank.proto", read("proto/bank.proto"));
    if (metadataCache.containsKey(ERRORS_KEY_SUFFIX))
{
      std::cerr << "fail: error in registering .proto model" << std::endl;
      return -1;
}
    //Create the application cache peer with a Protobuf marshaller
    auto *testkm = new BasicTypesProtoStreamMarshaller<int>();
    auto *testvm = new ProtoStreamMarshaller<sample_bank_account::User>();
    auto testCache = cacheManager.getCache<int, sample_bank_account::User>(
    testkm, &Marshaller<int>::destroy, testvm, &Marshaller<sample_bank_account::User>::destroy, "namedCache", false);

//Cache Population

The classes that populate the cache are defined in the Google Protobuf syntax. The example application uses the C++ representation generated by the protoc compiler. (In this example, such code C++ is provided. The way this code can be generated is described here.)

    //Fill the cache with the application data: two users Tom and Jerry
    testCache.clear();
    sample_bank_account::User_Address a;
    sample_bank_account::User user1;
    user1.set_id(3);
    user1.set_name("Tom");
    user1.set_surname("Cat");
    user1.set_gender(sample_bank_account::User_Gender_MALE);
    sample_bank_account::User_Address * addr= user1.add_addresses();
    addr->set_street("Via Roma");
    addr->set_number(3);
    addr->set_postcode("202020");
    testCache.put(3, user1);
    user1.set_id(4);
    user1.set_name("Jerry");
    user1.set_surname("Mouse");
    addr->set_street("Via Milano");
    user1.set_gender(sample_bank_account::User_Gender_MALE);
    testCache.put(4, user1);

//Queries Execution

    // Simple query to get User objects
    {
        QueryRequest qr;
        std::cout << "Query: from sample_bank_account.User" << std::endl;
        qr.set_jpqlstring("from sample_bank_account.User");
        QueryResponse resp = testCache.query(qr);
        std::vector<sample_bank_account::User> res;
        unwrapResults(resp, res);
        for (auto i = 0; i < res.size(); i++) {
            std::cout << "User(id=" << res[i].id() << ",name=" << res[i].name()
            << ",surname=" << res[i].surname() << ")" << std::endl;
        }
    }
    // Simple query to get User objects with where condition
    {
        QueryRequest qr;
        std::cout << "from sample_bank_account.User u where u.addresses.street=\"Via Milano\"" << std::endl;
        qr.set_jpqlstring("from sample_bank_account.User u where u.addresses.street=\"Via Milano\"");
        QueryResponse resp = testCache.query(qr);
        std::vector<sample_bank_account::User> res;
        unwrapResults(resp, res);
        for (auto i = 0; i < res.size(); i++) {
            std::cout << "User(id=" << res[i].id() << ",name=" << res[i].name()
            << ",surname=" << res[i].surname() << ")" << std::endl;
        }
    }
    // Simple query to get projection (name, surname)
    {
        QueryRequest qr;
        std::cout << "Query: select u.name, u.surname from sample_bank_account.User u" << std::endl;
        qr.set_jpqlstring(
        "select u.name, u.surname from sample_bank_account.User u");
        QueryResponse resp = testCache.query(qr);
        //Typed resultset
        std::vector<std::tuple<std::string, std::string> > prjRes;

        unwrapProjection(resp, prjRes);
        for (auto i = 0; i < prjRes.size(); i++) {
            std::cout << "Name: " << std::get<0> (prjRes[i])
            << " Surname: " << std::get<1> (prjRes[i]) << std::endl;
        }
    }
    {
        QueryRequest qr;
        qr.set_jpqlstring("select count(u.id) from sample_bank_account.User u");
        QueryResponse resp = testCache.query(qr);
        int i = unwrapSingleResult<int>(resp);
        std::cout << "Result is: " << i << std::endl;
    }
    cacheManager.stop();
    return 0;
}


Download the whitepaper, Moving From Relational to NoSQL: How to Get Started. We’ll take you step by step through your first NoSQL project.

Topics:
infinispan ,c++ ,database ,queries ,code ,example

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}