This is an example on how to create a complex and nested user-defined type in PlinyCompute. Here complex and nested means a user-defined type that has containers (such as pdb::Vector, pdb::Map, etc.).

In this example, the classes Customer, Order, and SupplierData, derive from pdb::Object. For clarity purposes only a partial depiction of the classes is included in these listings; also the .cc files are omitted. To view the complete content of this code, click here: Customer.h, Order.h, and SupplierData.h.

Let us imagine a class with information about Customers. A Customer has a pdb::Vector<Order>, containing information about all Orders a customer has ordered (line 4 in Customer.h). Each Order in turn, has a pdb::Vector<LineItem>, which contains information about all Items included in that Order (line 4 in Order.h). Lastly, SupplierData contains information about the Parts that a supplier has sold to each Customer, represented as pdb :: String and pdb :: Map<pdb :: String, pdb :: Vector<int>> respectively (see lines 14 and 15 in SupplierData.h).

Keep in mind that these classes have to:

  • derive from pdb::Object
  • include the ENABLE_DEEP_COPY macro in their public method/member section

This code has to be compiled and built as a shared library (see Step 3 here). Lastly, users have to register the shared library into PlinyCompute’s catalog in their client code (see Step 4 here).

class Customer : public pdb::Object {

public:
    pdb::Vector<Order> orders;
    int custKey;
    pdb::String name;
    pdb::String address;
    int nationKey;
    pdb::String phone;
    double accbal;
    pdb::String mktsegment;
    pdb::String comment;


    ENABLE_DEEP_COPY

    ~Customer() {}

    Customer() {}

    // Constructor with arguments using std::string

    Customer(pdb::Vector<Order> orders,
             int custKey,
             std::string name,
             std::string address,
             int nationKey,
             std::string phone,
             double accbal,
             std::string mktsegment,
             std::string comment) {
        this->orders = orders;
        this->custKey = custKey;
        this->name = name;
        this->address = address;
        this->nationKey = nationKey;
        this->phone = phone;
        this->accbal = accbal;
        this->mktsegment = mktsegment;
        this->comment = comment;
    }

    /* methods not included... */};
    
}

Give a name to this file (e.g. Customer.h) and save it in the sharedLibraries/headers/ folder.

Then, Order objects have a nested container (pdb::Vector) of LineItem objects:

class Order : public pdb::Object {

public:
    pdb::Vector<LineItem> lineItems;

    int orderKey;
    int custKey;
    pdb::String orderStatus;
    double totalPrice;
    pdb::String orderDate;
    pdb::String orderPriority;
    pdb::String clerk;
    int shipPriority;
    pdb::String comment;


    ENABLE_DEEP_COPY

    ~Order() {}

    Order() {}

    Order(pdb::Vector<LineItem> lineItems,
          int orderkey,
          int custkey,
          std::string orderstatus,
          double totalprice,
          std::string orderdate,
          std::string orderpriority,
          std::string clerk,
          int shippriority,
          std::string comment) {
        this->lineItems = lineItems;
        this->orderKey = orderkey;
        this->custKey = custkey;
        this->orderStatus = orderstatus;
        this->totalPrice = totalprice;
        this->orderDate = orderdate;
        this->orderPriority = orderpriority;
        this->clerk = clerk;
        this->shipPriority = shippriority;
        this->comment = comment;
    }
    
    /* methods not included... */};
    
}

Give a name to this file (e.g. Order.h) and save it in the sharedLibraries/headers/ folder.

SupplierData is defined as follows:


class SupplierData : public pdb::Object {

#include "Object.h"
#include "PDBVector.h"
#include "PDBString.h"
#include "Handle.h"

using namespace pdb;
// This class represents a triple that holds a triple of (customerName, SupplierName, PartID)

class SupplierData : public pdb::Object {

public:
    pdb::String supplierName;
    pdb::Map<pdb::String, pdb::Vector<int>> soldPartIDs;

    ENABLE_DEEP_COPY

    // Default constructor:
    SupplierData() {}

    // Default destructor:
    ~SupplierData() {}

    // Constructor with arguments:
    SupplierData(pdb::String supplierName) {
        this->supplierName = supplierName;
    }

    /* methods not included... */};
    
}

Give a name to this file (e.g. SupplierData.h) and save it in the sharedLibraries/headers/ folder.

Step 2: For each of the previous classes, create the corresponding source files, whose content is shown below:

Create the Customer.cc file and save it in the sharedLibraries/source/ folder.

#include "Customer.h"
#include "GetVTable.h"

GET_V_TABLE(Customer)

Create the Order.cc file and save it in the sharedLibraries/source/ folder.

#include "Order.h"
#include "GetVTable.h"

GET_V_TABLE(Order)

Create the SupplierData.cc file and save it in the sharedLibraries/source/ folder.

#include "SupplierData.h"
#include "GetVTable.h"

GET_V_TABLE(SupplierData)

Step 3: Compile and build.

Run the following make commands

$ make Customer
$ make Order
$ make SupplierData

This will create the following shared libraries libCustomer.so, libOrder.so, and libSupplierData.so in the libraries/ folder.
At this point, three user-defined data types have been successfully created as shared libraries. You can repeat the previous steps to create additional user-defined data types.

Step 4: Register the shared libraries in PlinyCompute’s catalog.

The final step to make these user-defined data types available to PlinyCompute, is to register them in an instance of PlinyCompute’s catalog. This can be done by including the following statements in your client code, which assumes that the shared libraries created in the previous step are located in the libraries folder.

   pdbClient.registerType("libraries/libCustomer.so");
   pdbClient.registerType("libraries/libOrder.so");
   pdbClient.registerType("libraries/libSupplierData.so");