Search code examples
ballerina

Ballerina: How can I search for a record in a table?


I am just learning Ballerina (I imagine we all are still at this point). I am trying to do this JSON Exercism exercise. There are probably other ways to do it, but I would like to solve it in the following way, because I think this is generally useful for many situations:

  1. Create the record and table that I would like for both the ingested data and the output data:
public type FillUpEntry record {|
    int employeeId;
    int odometerReading;
    decimal gallons;
    decimal gasPrice;
|};

public type EmployeeFillUpSummary record {|
    readonly int employeeId;
    int gasFillUpCount;
    decimal totalFuelCost;
    decimal totalGallons;
    int totalMilesAccrued;
|};

type IntermediarySummary record {|
    readonly int employeeId;
    int gasFillUpCount;
    int firstOdometerReading;
    int lastOdometerReading;

|};

public type EntryTable table<FillUpEntry>;

public type SummaryTable table<EmployeeFillUpSummary> key(employeeId);

type IntermediaryTable table<IntermediarySummary> key(employeeId);

(Not sure if I'll need the intermediary table... I thought I might because I need to keep track of the smallest and largest odometer reading to determine the total # of miles travelled.)

  1. Then after ingesting the data into a table, I figured I could loop through the input table, and save it to the intermediary table (or the output table). But to do this, I need to be able to see if I already have an entry in the intermediary table. Ie, I need something a bit like this:
    json|io:Error rawInput = io:fileReadJson(inputFilePath);
    if rawInput is io:Error {
        io:println(rawInput.message());
        return ();
    }
    SummaryTable output;
    IntermediaryTable intermediary;
    EntryTable input = check rawInput.cloneWithType();
    check from var item in input
        do { // assuming that this is the first time I see the entry
             // So I need some sort of `item.employeeId in intermediary.keys()` check.  How can I do this??
            intermediary.put({
                employeeId: item.employeeId,
                gasFillUpCount: 1,
                firstOdometerReading: item.odometerReading,
                lastOdometerReading: item.odometerReading
            });
        };
        do { // assuming I have seen this entry before
            intermediary.put({
                employeeId: item.employeeId,
                gasFillUpCount: <previous_value+1>,
                firstOdometerReading: <previous_value>,
                lastOdometerReading: item.odometerReading
            });
        };

I'm sure there are smarter ways to handle this, and to skip the intermediary altogether, but my key question is still important, I think:

  • I want to know how I can find whether a record already exists in the table intermediary based upon the table record that I am currently iterating through.
    • This seems like it must be done fairly often.

Solution

  • You can check whether a particular record exists in a table using the hasKey() function defined in the ballerina/lang.table langlib module. Langlib modules are imported to the program implicitly, so there is no need to import them explicitly.

    Are you looking for something like this?

    json|io:Error rawInput = io:fileReadJson(inputFilePath);
    if rawInput is io:Error {
        io:println(rawInput.message());
        return ();
    }
    SummaryTable output;
    IntermediaryTable intermediary = table [];
    EntryTable input = check rawInput.cloneWithType();
    check from var item in input
        do {
            if intermediary.hasKey(item.employeeId) {
                // assuming I have seen this entry before
                intermediary.put({
                    employeeId: item.employeeId,
                    gasFillUpCount: <previous_value+1 > ,
                    firstOdometerReading: <previous_value>,
                    lastOdometerReading: item.odometerReading
                });
            } else {
                // assuming that this is the first time I see the entry
                intermediary.put({
                    employeeId: item.employeeId,
                    gasFillUpCount: 1,
                    firstOdometerReading: item.odometerReading,
                    lastOdometerReading: item.odometerReading
                });
            }
    
        };