How to transform a record to a different record type with some fields being optional in Ballerina?

A number of API's that I work with expect to receive only populated nodes. If a node's data is empty and that node is part of the posting payload, an error is returned.
For instance, with this source information:

{
    "name": {
        "firstName": "John",
        "middleName": "Quincy",
        "lastName": "Smith",
        "title": ""
    }
}

the receiving API may support title, but expects that no empty title node would be presented, the hypothetical transformed payload would be something like:

{
    "givenName": "John",
    "middleName": "Quincy",
    "surname": "Smith"
}

whereas if title is populated in the source, it should also be included in the target:

{
    "name": {
        "firstName": "John",
        "middleName": "Quincy",
        "lastName": "Smith",
        "title": "Mr"
    }
}

transforms to:

{
    "givenName": "John",
    "middleName": "Quincy",
    "surname": "Smith",
    "title": "Mr"
}

How can this be achieved in Ballerina?

Upvotes: 1

Views: 41

Answers (2)

user272735
user272735

Reputation: 10648

Here is a variation to dilanSachi's answer that visualizes better with Ballerina's data mapper. This is preferred and IMO idiomatic style for data mapping functions:

import ballerina/io;

type Input record {|
    record {|
        string firstName;
        string middleName;
        string lastName;
        string title;
    |} name;
|};

type Transformed record {|
    string givenName;
    string middleName;
    string surname;
    string title?;
|};

function title(string title) returns string? => 
    title.trim() == "" ? () : title;

function transform(Input input) returns Transformed => {
    givenName:  input.name.firstName,
    middleName: input.name.middleName,
    surname:    input.name.lastName,
    title:      title(input.name.title)
};

public function main() {
    io:println(transform(
        {
            "name": {
                "firstName": "John",
                "middleName": "Quincy",
                "lastName": "Smith",
                "title": "Mr"
            }
        }
    ));
}

Prints:

{"givenName":"John","middleName":"Quincy","surname":"Smith","title":"Mr"}

as expected.

Upvotes: 0

You can do it like this.

type Input record {|
    record {|
        string firstName;
        string middleName;
        string lastName;
        string title;
    |} name;
|};

type Transformed record {|
    string givenName;
    string middleName;
    string surname;
    string title?;
|};

function transform(Input input) returns Transformed =>
    let var {firstName, middleName, lastName, title} = input.name in {
        givenName: firstName,
        // same as `middleName: middleName,`
        middleName,
        surname: lastName,
        // setting `()` as the value results in the field not being set 
        // when the field is an optional field in the record that is not of an optional type
        title: title.trim() == "" ? () : title
    };

Upvotes: 0

Related Questions