SFDC Stop - Always the latest about Salesforce


Full Tutorial Series with videos, free apps, live sessions, salesforce consulting and much more.


Telegram logo   Join our Telegram Channel

Thursday, 22 July 2021

Custom Labels XML to CSV Convertor and Vice Versa

Hey Everyone,


I have worked on a couple of projects by now dealing with custom labels and it was difficult to update each and every custom label one by one manually as specified by the business analysts or clients from time to time. To solve this problem, I have created a small tool known as: customlabels2csv

CSV file converted from CustomLabels.labels-meta.xml file


Custom Labels XML file created using the above CSV


customlabels2csv tool helps you to convert your custom labels xml file to a csv file, so that you can easily update the error/warning/success messages, you're using in salesforce. You can also convert your csv file back to xml and push/deploy it to your salesforce org to update all the custom labels in one go.


So now, you can create a csv, share it with the BAs or clients, they can update it and send it back to you and then you can deploy it in your salesforce org by converting it back to XML.


Have a look at the readme of GitHub repository to understand how it works in detail: https://github.com/rahulmalhotra/customlabels2csv


Hope it'll be useful for you all.


Happy Trailblazing..!!

Monday, 19 July 2021

Insertion in Binary Tree based on parent node | Custom comparator in Apex | Apex Data Structures Tutorial by SFDC Stop

Hello Trailblazers,


In this tutorial we're going to see how we can insert a new node in binary tree recursively based on the parent node. We're going to refer the code we created in our previous tutorial and add a new insertData() method which is going to accept the new data, the parent data and a comparator class. Then it's going to compare if the parent data is equal to the data of any node in the binary tree or not, in case we find such a node, we're going to consider that node as our parent node and we'll link the new node as a child of the parent node. If not, we'll return NULL which means the node cannot be inserted in our binary tree.

Existing Binary Tree Code

Let's have a quick look at the present code of binary tree from the previous tutorial, before we begin:
/*
*	Author:- Rahul Malhotra
*	Description:- Binary Tree implementation in apex
*	Created Date:- 13-07-2021
*	Last Modified:- 13-07-2021
*       Code Origin:- SFDC Stop (https://www.sfdcstop.com)
*/
public class BinaryTree {

    // * Node class
    public class Node {

        Object data;
        Node left;
        Node right;

        public Node(Object data) {
            this.data = data;
            this.left = NULL;
            this.right = NULL;
        }

    }

    // * Root of binary tree
    Node root;

    // * Method to insert data in binary tree
    private void insertData(Object data) {

        // * If root is NULL, create a new node and return
        if(root==NULL) {
            root = new Node(data);
            return;
        }

        // * Initializing a queue of nodes
        List<Node> nodesQueue = new List<Node>();

        // * Adding root node to the queue
        nodesQueue.add(root);

        // * Looping while queue is not empty
        while(!nodesQueue.isEmpty()) {

            // * Getting the current node and removing it from the queue
            Node current = nodesQueue.get(0);
            nodesQueue.remove(0);

            // * If the left child of current node is not null, add it to the queue
            if(current.left!=NULL) {
                nodesQueue.add(current.left);
            }
            // * Otherwise, create a new node and attach it as the left child
            else {
                current.left = new Node(data);
                return;
            }

            // * If the right child of current node is not null, add it to the queue
            if(current.right!=NULL) {
                nodesQueue.add(current.right);
            }
            // * Otherwise, create a new node and attach it to the right child
            else {
                current.right = new Node(data);
                return;
            }
        }

    }

    /*
    *  Author:- Rahul Malhotra
    *  Description:- This method is used to create a binary tree
    */
    public void createBinaryTree(List<Object> elements) {

        // * Inserting elements in binary tree
        for(Object element : elements) {
            insertData(element);
        }
    }

    /*
    *  Author:- Rahul Malhotra
    *  Description:- This method is used to print binary tree level by level
    */    
    public void levelOrderPrint() {

        // * Checking if root is not NULL
        if(root!=NULL) {

            String result = '\n';

            // * Initializing a queue
            List<Node> nodesQueue = new List<Node>();

            // * Adding root node to the queue
            nodesQueue.add(root);

            // * Looping while queue is not empty
            while(!nodesQueue.isEmpty()) {

                // * Getting nodes at current level
                Integer nodesAtCurrentLevel = nodesQueue.size();

                // * Looping while nodes at current level is more than 0
                while(nodesAtCurrentLevel>0) {

                    // * Getting the current node and removing it from the queue
                    Node current = nodesQueue.get(0);
                    nodesQueue.remove(0);

                    // * Adding current node data to the result
                    result += current.data + ' ';

                    // * If left child of the current node is not NULL, add it to the queue
                    if(current.left!=NULL) {
                        nodesQueue.add(current.left);
                    }

                    // * If right child of the current node is not NULL, add it to the queue
                    if(current.right!=NULL) {
                        nodesQueue.add(current.right);
                    }

                    // * Decrementing nodes at current level by 1
                    nodesAtCurrentLevel--;
                }

                // * Adding a new line to the result for next level
                result += '\n';
            }

            // * Displaying the result
            System.debug(result);
        } 

        // * If root is NULL, display error message
        else {
            System.debug('Tree not found');
        }
    }
}
In the above class, we're going to overload the insertData() method and the new method will insert the data on the basis of parent data. The new insertData() is given below:
/*
*  Author:- Rahul Malhotra
*  Description:- This method is used to insert data inside a binary tree based on the parent node's data
*/
public Node insertData(Object data, Object parentData, Comparator comparator) {

    // * If root node is NULL, create a new node, assign it as the root node and return that
    if(root==NULL) {
        root = new Node(data);
        return root;
    }

    // * Otherwise, call the recursive function using the root node
    return insertDataRecursive(root, data, parentData, comparator);
}
As you can see above, this method is receiving the current data which we need to add to the binary tree, the parent data which is the data of parent node present in the binary tree and a Comparator class instance. The comparator class is a custom comparator which will have a method that can be used to compare two objects and will return true if both the objects are equal and will return false if both the objects are not equal.

This insertData() method is checking if the root node is NULL or not, if it's NULL, we're going to create a new node, assign it as the root node and return that. If the root node exists, we're going to call a private method insertDataRecursive() which is getting the root node, the current object's data and the parent object's data as parameters along with the comparator. Let's have a look at the code of this method to understand how it's working:
/*
*  Author:- Rahul Malhotra
*  Description:- This helper method is used to insert data inside a binary tree based on the parent node's data
*/
private Node insertDataRecursive(Node current, Object data, Object parentData, Comparator comparator) {

    // * If current node's data is equal to parentData
    if(comparator.compare(current.data, parentData)) {

        // * If left child of current node is NULL, add a new node as the left child of the current node and return that
        if(current.left==NULL) {
            current.left = new Node(data);
            return current.left;
        } 
        
        // * Else if the right child of current node is NULL, add a new node as the right child of the current node and return that
        else if(current.right==NULL) {
            current.right = new Node(data);
            return current.right;
        } 
        
        // * Otherwise, return NULL as the current node already has two nodes and a new node cannot be inserted
        else {
            return NULL;
        }
    }

    // * If current node's data is not equal to parentData, check in the left and right subtrees

    // * If left subtree exists
    if(current.left!=NULL) {

        Node left = insertDataRecursive(current.left, data, parentData, comparator);

        // * If the node is inserted in the left subtree, return the value received from the left subtree
        if(left!=NULL) {
            return left;
        }
    }

    // * If right subtree exists
    if(current.right!=NULL) {

        Node right = insertDataRecursive(current.right, data, parentData, comparator);

        // * If the node is inserted in the right subtree, return the value received from the right subtree
        if(right!=NULL) {
            return right;
        }
    }

    // * Otherwise, return NULL as the node cannot be inserted
    return NULL;
}
This method will start from the root node and will traverse the whole tree recursively in order to find a node whose data is equal to our parentData. If such a node is found, a new node will be created with the given data and will be inserted as a child of this node, otherwise, NULL will be returned.

As you can see, first of all we're comparing the current node's data with the parentData using the compare() method of comparator class, if both the data are equal, this means that we can create a new node and add it as a child of the current node. For this, we're checking if the left child of the current node is NULL, we can link the new node as the left child of the current node. Otherwise, if it's right child is NULL, we can link the new node as the right child of the current node. If both the left and right child are not NULL, this means that we don't have any space left to link new node with the current node, so, we return NULL here.

If the current node's data is not equal to the parentData, we'll try to insert the node somewhere in the left subtree. If the node is inserted in the left subtree i.e. we get a non NULL value from there, we can simply reutrn that. Otherwise, we can repeat the same process for the right subtree. If we're getting NULL from both the subtrees or if none of left or right subtree exist, this means that, we cannot insert the new node anywhere, therefore we return NULL.

The updated code for the BinaryTree class with both these methods included is given below:
/*
*	Author:- Rahul Malhotra
*	Description:- Binary Tree implementation in apex
*	Created Date:- 13-07-2021
*	Last Modified:- 14-07-2021
*       Code Origin:- SFDC Stop (https://www.sfdcstop.com)
*/
public class BinaryTree {

    // * Node class
    public class Node {

        Object data;
        Node left;
        Node right;

        public Node(Object data) {
            this.data = data;
            this.left = NULL;
            this.right = NULL;
        }

        public Object getData() {
            return data;
        }
    }

    // * Root of binary tree
    Node root;

    // * Method to insert data in binary tree
    private void insertData(Object data) {

        // * If root is NULL, create a new node and return
        if(root==NULL) {
            root = new Node(data);
            return;
        }

        // * Initializing a queue of nodes
        List<Node> nodesQueue = new List<Node>();

        // * Adding root node to the queue
        nodesQueue.add(root);

        // * Looping while queue is not empty
        while(!nodesQueue.isEmpty()) {

            // * Getting the current node and removing it from the queue
            Node current = nodesQueue.get(0);
            nodesQueue.remove(0);

            // * If the left child of current node is not null, add it to the queue
            if(current.left!=NULL) {
                nodesQueue.add(current.left);
            }
            // * Otherwise, create a new node and attach it as the left child
            else {
                current.left = new Node(data);
                return;
            }

            // * If the right child of current node is not null, add it to the queue
            if(current.right!=NULL) {
                nodesQueue.add(current.right);
            }
            // * Otherwise, create a new node and attach it to the right child
            else {
                current.right = new Node(data);
                return;
            }
        }

    }

    /*
    *  Author:- Rahul Malhotra
    *  Description:- This method is used to insert data inside a binary tree based on the parent node's data
    */
    public Node insertData(Object data, Object parentData, Comparator comparator) {

        // * If root node is NULL, create a new node, assign it as the root node and return that
        if(root==NULL) {
            root = new Node(data);
            return root;
        }

        // * Otherwise, call the recursive function using the root node
        return insertDataRecursive(root, data, parentData, comparator);
    }

    /*
    *  Author:- Rahul Malhotra
    *  Description:- This helper method is used to insert data inside a binary tree based on the parent node's data
    */
    private Node insertDataRecursive(Node current, Object data, Object parentData, Comparator comparator) {

        // * If current node's data is equal to parentData
        if(comparator.compare(current.data, parentData)) {

            // * If left child of current node is NULL, add a new node as the left child of the current node and return that
            if(current.left==NULL) {
                current.left = new Node(data);
                return current.left;
            } 
            
            // * Else if the right child of current node is NULL, add a new node as the right child of the current node and return that
            else if(current.right==NULL) {
                current.right = new Node(data);
                return current.right;
            } 
            
            // * Otherwise, return NULL as the current node already has two nodes and a new node cannot be inserted
            else {
                return NULL;
            }
        }

        // * If current node's data is not equal to parentData, check in the left and right subtrees

        // * If left subtree exists
        if(current.left!=NULL) {

            Node left = insertDataRecursive(current.left, data, parentData, comparator);

            // * If the node is inserted in the left subtree, return the value received from the left subtree
            if(left!=NULL) {
                return left;
            }
        }

        // * If right subtree exists
        if(current.right!=NULL) {

            Node right = insertDataRecursive(current.right, data, parentData, comparator);

            // * If the node is inserted in the right subtree, return the value received from the right subtree
            if(right!=NULL) {
                return right;
            }
        }

        // * Otherwise, return NULL as the node cannot be inserted
        return NULL;
    }

    /*
    *  Author:- Rahul Malhotra
    *  Description:- This method is used to create a binary tree
    */
    public void createBinaryTree(List<Object> elements) {

        // * Inserting elements in binary tree
        for(Object element : elements) {
            insertData(element);
        }
    }

    /*
    *  Author:- Rahul Malhotra
    *  Description:- This method is used to print binary tree level by level
    */    
    public void levelOrderPrint() {

        // * Checking if root is not NULL
        if(root!=NULL) {

            String result = '\n';

            // * Initializing a queue
            List<Node> nodesQueue = new List<Node>();

            // * Adding root node to the queue
            nodesQueue.add(root);

            // * Looping while queue is not empty
            while(!nodesQueue.isEmpty()) {

                // * Getting nodes at current level
                Integer nodesAtCurrentLevel = nodesQueue.size();

                // * Looping while nodes at current level is more than 0
                while(nodesAtCurrentLevel>0) {

                    // * Getting the current node and removing it from the queue
                    Node current = nodesQueue.get(0);
                    nodesQueue.remove(0);

                    // * Adding current node data to the result
                    result += current.data + ' ';

                    // * If left child of the current node is not NULL, add it to the queue
                    if(current.left!=NULL) {
                        nodesQueue.add(current.left);
                    }

                    // * If right child of the current node is not NULL, add it to the queue
                    if(current.right!=NULL) {
                        nodesQueue.add(current.right);
                    }

                    // * Decrementing nodes at current level by 1
                    nodesAtCurrentLevel--;
                }

                // * Adding a new line to the result for next level
                result += '\n';
            }

            // * Displaying the result
            System.debug(result);
        } 

        // * If root is NULL, display error message
        else {
            System.debug('Tree not found');
        }
    }
}
Now, our insertData() and insertDataRecursive() methods are complete. Let's have a look at the comparator class as well:
/*
*	Author:- Rahul Malhotra
*	Description:- Comparator class to be used in Binary Tree
*	Created Date:- 14-07-2021
*	Last Modified:- 14-07-2021
*       Code Origin:- SFDC Stop (https://www.sfdcstop.com)
*/
public abstract class Comparator {
    public abstract Boolean compare(Object o1, Object o2);
}
As you can see above, Comparator is an abstract class which is having a single abstract method definition, this method is going to receive two objects and return a Boolean true if both the objects are equal and false if both the objects are not equal. We have created this abstract class to keep our binary tree code independent of data types as we can implement a child of this abstract class and do the comparison there. For example: Let's consider that in our case, we need to compare integers, so, we can create another class as shown below:
/* 
*   Author:- Rahul Malhotra
*   Description:- This helper class is used to compare two integers.
*   It's used in the creation of binary tree
*/
public class IntegerCompare extends Comparator {
    public override Boolean compare(Object o1, Object o2) {
        return (Integer) o1 == (Integer) o2;
    }
}
This IntegerCompare class is extending our abstract Comparator class and is implementing the compare method. For our binary tree, we're checking if both the objects (when typecasted to Integers) are equal or not. If both the Integers are equal, the method will return true, otherwise, it'll return false.

It's time to test our new insertData() method now. Let's consider the below binary tree.
As you can see above, this is not a complete binary tree as the node 1 has two nodes 2 and 3. But both the nodes 2 and 3 have 1 node each as their child. We can use the below code snippet to create this binary tree and print the nodes level by level using the levelOrderPrint():
IntegerCompare integerCompare = new IntegerCompare();
BinaryTree tree = new BinaryTree();
tree.insertData(1, null, integerCompare);
tree.insertData(2, 1, integerCompare);
tree.insertData(3, 1, integerCompare);
tree.insertData(7, 3, integerCompare);
tree.insertData(4, 2, integerCompare);
tree.levelOrderPrint();
Let's have a look at the output as well:
As you can see above, we're getting the node 1 at level 1, node 2, 3 at level 2 and node 4, 7 at level 3. Therefore, we can say that the code is working perfectly fine and we're able to insert the nodes by finding the parent node.

The actual tree that is created will be a little different from the tree image that we've seen above. It'll look as shown below:
Note that the child node of 3 i.e. node 7 will be on the left side and not on the right side. This is because we're not passing any directions with each node to identify if it should be linked as left or right child and by default as per our code, we're inserting the node as the left child, if the left child of parent node is NULL.

The worst case time complexity of this insertion algorithm will be O(n^2). How? Let's consider the tree given below:
In this case, for insertion of each node we have to traverse through n nodes that are present in the tree. Therefore time taken to insert each node in the tree is O(n). Therefore, for insertion of n nodes, the total time taken will be O(n*n) = O(n^2). Such type of tree is also known as a Skew Tree. We can improve this time complexity by doing a slight modification in the code. Now, that's a homework for you. Think about how you can insert a node in this tree faster and let me know your solution in the comments down below.

The whole code for this tutorial can be accessed in the apex-data-structures Github Repository here.

That's all for this tutorial everyone, I hope you liked it and understood the concept of custom comparator, it's usage and how we can insert a new node in an incomplete or complete binary tree by checking value of the parent node.

Happy Trailblazing..!!

Tuesday, 13 July 2021

Binary Tree implementation in Apex | Apex Data Structures Tutorial by SFDC Stop

Hello Trailblazers,


In this post we're going to talk about how we can create a Binary Tree in Apex. Let's see how a Binary Tree looks like:

As you can see above, we have a root node which is 1 in the above image, and each node in the tree can have two children at max. In the above tree, the nodes: 4 5 6 and 7 are called leaf nodes as they have no children.

Tutorial Video



Let's have a quick look at the full code once, then we'll discuss everything in detail.

/*
*	Author:- Rahul Malhotra
*	Description:- Binary Tree implementation in apex
*	Created Date:- 13-07-2021
*	Last Modified:- 13-07-2021
*       Code Origin:- SFDC Stop (https://www.sfdcstop.com)
*/
public class BinaryTree {

    // * Node class
    public class Node {

        Object data;
        Node left;
        Node right;

        public Node(Object data) {
            this.data = data;
            this.left = NULL;
            this.right = NULL;
        }

    }

    // * Root of binary tree
    Node root;

    // * Method to insert data in binary tree
    private void insertData(Object data) {

        // * If root is NULL, create a new node and return
        if(root==NULL) {
            root = new Node(data);
            return;
        }

        // * Initializing a queue of nodes
        List<Node> nodesQueue = new List<Node>();

        // * Adding root node to the queue
        nodesQueue.add(root);

        // * Looping while queue is not empty
        while(!nodesQueue.isEmpty()) {

            // * Getting the current node and removing it from the queue
            Node current = nodesQueue.get(0);
            nodesQueue.remove(0);

            // * If the left child of current node is not null, add it to the queue
            if(current.left!=NULL) {
                nodesQueue.add(current.left);
            }
            // * Otherwise, create a new node and attach it as the left child
            else {
                current.left = new Node(data);
                return;
            }

            // * If the right child of current node is not null, add it to the queue
            if(current.right!=NULL) {
                nodesQueue.add(current.right);
            }
            // * Otherwise, create a new node and attach it to the right child
            else {
                current.right = new Node(data);
                return;
            }
        }

    }

    /*
    *  Author:- Rahul Malhotra
    *  Description:- This method is used to create a binary tree
    */
    public void createBinaryTree(List<Object> elements) {

        // * Inserting elements in binary tree
        for(Object element : elements) {
            insertData(element);
        }
    }

    /*
    *  Author:- Rahul Malhotra
    *  Description:- This method is used to print binary tree level by level
    */    
    public void levelOrderPrint() {

        // * Checking if root is not NULL
        if(root!=NULL) {

            String result = '\n';

            // * Initializing a queue
            List<Node> nodesQueue = new List<Node>();

            // * Adding root node to the queue
            nodesQueue.add(root);

            // * Looping while queue is not empty
            while(!nodesQueue.isEmpty()) {

                // * Getting nodes at current level
                Integer nodesAtCurrentLevel = nodesQueue.size();

                // * Looping while nodes at current level is more than 0
                while(nodesAtCurrentLevel>0) {

                    // * Getting the current node and removing it from the queue
                    Node current = nodesQueue.get(0);
                    nodesQueue.remove(0);

                    // * Adding current node data to the result
                    result += current.data + ' ';

                    // * If left child of the current node is not NULL, add it to the queue
                    if(current.left!=NULL) {
                        nodesQueue.add(current.left);
                    }

                    // * If right child of the current node is not NULL, add it to the queue
                    if(current.right!=NULL) {
                        nodesQueue.add(current.right);
                    }

                    // * Decrementing nodes at current level by 1
                    nodesAtCurrentLevel--;
                }

                // * Adding a new line to the result for next level
                result += '\n';
            }

            // * Displaying the result
            System.debug(result);
        } 

        // * If root is NULL, display error message
        else {
            System.debug('Tree not found');
        }
    }
}

Creating Node class

    // * Node class
    public class Node {

        Object data;
        Node left;
        Node right;

        public Node(Object data) {
            this.data = data;
            this.left = NULL;
            this.right = NULL;
        }

    }
As you can see above, we've created a simple node class. Each node of the binary tree will consist of data and references to the left and right child of the current node.

Insertion in Binary Tree

The insertData method is used to insert a new node in binary tree:
    // * Root of binary tree
    Node root;

    // * Method to insert data in binary tree
    private void insertData(Object data) {

        // * If root is NULL, create a new node and return
        if(root==NULL) {
            root = new Node(data);
            return;
        }

        // * Initializing a queue of nodes
        List<Node> nodesQueue = new List<Node>();

        // * Adding root node to the queue
        nodesQueue.add(root);

        // * Looping while queue is not empty
        while(!nodesQueue.isEmpty()) {

            // * Getting the current node and removing it from the queue
            Node current = nodesQueue.get(0);
            nodesQueue.remove(0);

            // * If the left child of current node is not null, add it to the queue
            if(current.left!=NULL) {
                nodesQueue.add(current.left);
            }
            // * Otherwise, create a new node and attach it as the left child
            else {
                current.left = new Node(data);
                return;
            }

            // * If the right child of current node is not null, add it to the queue
            if(current.right!=NULL) {
                nodesQueue.add(current.right);
            }
            // * Otherwise, create a new node and attach it to the right child
            else {
                current.right = new Node(data);
                return;
            }
        }

    }
We have created a data member of the main class named as root which will store the root of a binary tree. Inside insertData method, we're receiving the data as a parameter. After that we're checking, if root is NULL, we create a new node, assign it as the root of the tree and return. 

In case we have a root of the tree defined, we initialize a queue of nodes and add the root node to the queue. This queue is mainly used to traverse the tree level by level so that we can add the new node to the tree at the next available position.

We're looping while the queue is not empty, in each iteration, we get the current node from the queue. After that we check if the left child of the current node is NULL or not. If it's NULL that means we can add our new node at this position and return, if not, we're going to add the left child to the queue and we're going to repeat the same process for the right child.

Level Order Print of Binary Tree

The below method is used to print all nodes of the binary tree level by level:
    /*
    *  Author:- Rahul Malhotra
    *  Description:- This method is used to print binary tree level by level
    */    
    public void levelOrderPrint() {

        // * Checking if root is not NULL
        if(root!=NULL) {

            String result = '\n';

            // * Initializing a queue
            List<Node> nodesQueue = new List<Node>();

            // * Adding root node to the queue
            nodesQueue.add(root);

            // * Looping while queue is not empty
            while(!nodesQueue.isEmpty()) {

                // * Getting nodes at current level
                Integer nodesAtCurrentLevel = nodesQueue.size();

                // * Looping while nodes at current level is more than 0
                while(nodesAtCurrentLevel>0) {

                    // * Getting the current node and removing it from the queue
                    Node current = nodesQueue.get(0);
                    nodesQueue.remove(0);

                    // * Adding current node data to the result
                    result += current.data + ' ';

                    // * If left child of the current node is not NULL, add it to the queue
                    if(current.left!=NULL) {
                        nodesQueue.add(current.left);
                    }

                    // * If right child of the current node is not NULL, add it to the queue
                    if(current.right!=NULL) {
                        nodesQueue.add(current.right);
                    }

                    // * Decrementing nodes at current level by 1
                    nodesAtCurrentLevel--;
                }

                // * Adding a new line to the result for next level
                result += '\n';
            }

            // * Displaying the result
            System.debug(result);
        } 

        // * If root is NULL, display error message
        else {
            System.debug('Tree not found');
        }
    }
In this method as well, we're using the same logic as specified in the insertion method. First of all, we're checking:- If the root node is not NULL, we'll proceed forward, if it's NULL, we're going to simply display the message as: Tree not Found which means we haven't added any element to the binary tree yet. After that we're creating a queue of nodes, inserting the root node in that queue and looping the queue while it's not empty.

In each iteration, we're getting the total number of nodes present in the queue which is nothing but the total number of nodes present at the current level in the binary tree. We're storing that count in nodesAtCurrentLevel variable. Then, we're having another loop which will process all the nodes at the current level together. For each iteration of this inner loop, we're getting the node at the front of the queue and removing it from the queue. Then, we're adding the data of current node to our result string. After that we're checking if the left and right child of the current node is not NULL, if so, we're going to add those to the queue as well. Finally, we're decrementing the nodesAtCurrentLevel variable by 1 as we have processed one node present at the current level.

If you see carefully, the only difference here and in insertion method is that, here we're getting the number of nodes present in the current level, processing all those nodes together and adding a new line in the result string after processing so that we can display all the nodes at the current level in the same line. This is added only for formatting purposes.

At the end, we're displaying the result string.

Creating Binary Tree from a list of elements

Now it's time to create our binary tree using the insertData method. Let's have a look at the below method which will accept the list of elements from the user and will create a binary tree by passing each element one by one into the insertData method.
    /*
    *  Author:- Rahul Malhotra
    *  Description:- This method is used to create a binary tree
    */
    public void createBinaryTree(List<object> elements) {

        // * Inserting elements in binary tree
        for(Object element : elements) {
            insertData(element);
        }
    }
This is a fairly simple method where we're iterating all the elements using a for loop and adding them to our binary tree one by one.

Code Execution and Output

Congratulations! You've created a binary tree in apex by yourself. Now, it's time to execute the code and verify the result. Let's have a look at the below code snippet:
BinaryTree tree = new BinaryTree();
tree.createBinaryTree(new List<Integer>{1,2,3,4,5,6,7});
tree.levelOrderPrint();
As you can see above, we're simply creating an object of our BinaryTree class, then we're creating a binary tree by passing a list of integers and we're finally printing the binary tree elements level by level. After executing the above code, you'll get the output as shown below:


As you can see above, the first element of our list is the root node i.e. 1, after that the two elements 2 and 3 are inserted in the tree at the second level as the child of 1. And the other remaining elements, 4 5 6 and 7 are inserted at the third level in the binary tree. These nodes at the last level of the binary tree are called leaf nodes. Therefore, in our above example, 4 5 6 and 7 are leaf nodes.

If you've noticed the full code carefully, you might have observed that we have used Object everywhere as the data type instead of a specific data type such as String or Integer. Object is a generic data type in salesforce which can be used as a template to handle other data types. This is the reason it's working fine when we passed a list of integers to create a tree. Let's pass a list of strings this time to see if that works:
BinaryTree tree = new BinaryTree();
tree.createBinaryTree(new List<String>{'A','B','C','D','E','F','G'});
tree.levelOrderPrint();
As you can see above, this time we are passing a list of strings instead of integers, let's see the output when the above code is executed:


As you can see above, this time also, we're getting the correct output as the tree is created successfully. This means that our code is generic and can be used with different data types.

So, that's all for this tutorial everyone, I hope you learned something new. Try to implement this by your own and let me know if you have any questions in the comments down below. You can find the full code for this tutorial in the apex-data-structures github repository here.

Happy Trailblazing..!!

Sunday, 4 July 2021

Scheduled Jobs Custom LWC Component

Hello Trailblazers,

Today I am going to share a custom component developed in lwc which can be used to filter out scheduled jobs related to a particular user. This is the first guest post on SFDC Stop. Let's see what the author has to say about this component in his own words:

User related schedule jobs

Use Case

Sometimes we need to know about any user's scheduled or apex jobs. I don’t get any standard view in salesforce to list all jobs, apart from navigating to setup which needs View Setup and Configuration permission and exposes the user to much more details except just viewing or interacting with scheduled jobs. This Apex Jobs section display the list of jobs either schedule or completed jobs but does not provide everything with details.

What are Scheduled Jobs?

Schedule jobs includes scheduled batches, scheduled apex and scheduled flows in salesforce. To query a schedule job we need to query two objects: CronTrigger and CronJobDetail. CronTrigger contains information for a scheduled job. CronJobDetail contains details about the associated scheduled job, such as the job’s name and type.

To know the status of the job we can write a SOQL on CronTrigger object. Use CronJobDetail relationship to get the job’s name and type as given below:

AsyncApexJob represents an individual apex sharing recalculation job, a batch apex job, a method with the future annotation, or a job that implements Queueable. Use this object to query apex batch jobs in your organization. Below SOQL query can be used to get the status of ApexJob

By applying those above SOQL I have build a component which can help to view all jobs related to a particular user.


This post was contributed by Shamim Siddiquee. You can connect with him on linkedin here: https://www.linkedin.com/in/shamim-siddiquee

Happy Trailblazing..!!

Friday, 2 July 2021

Error while installing lwc local server? Here is how to resolve it!!

Hello Trailblazers,

I received a couple of comments from fellow trailblazers who were following my LWC ToDo App Project Tutorial Series that they were not able to setup local dev server to preview their LWC component locally. I remember that I faced some issues as well while setting that up, so I decided to install the local dev server myself again with the latest version of node and sfdx, so that I can explain the resolution to common issues. Let's talk about the pre requisites first of all.

Pre Requisites

There are some pre requisites to setup local dev server in your system for lwc. Please follow the below steps to make sure you have that covered.

1. Install Node Js. Download it here: https://nodejs.org

2. Install SFDX CLI. Download it here: https://developer.salesforce.com/tools/sfdxcli

Once you've downloaded and installed the above tools in your system. You can try setting up the local dev server. Open terminal/cmd and run the below command to install lwc local dev server:

As you run the above command, it should automatically install the local dev server in your system. If not, you may face some common issues. I am sharing the issues I faced and their resolution as well below:

1. npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules'


In case you're facing this issue or any similar permission issue, that means you don't have access to make changes in the required folder whose path is provided to you. A simple solution for this is to run the same install command again by running CMD as an Administrator in case of windows, you can also try opening the folder manually as the path is given to you and check it's permissions manually in folder properties and provide Full Access permissions from there to your user. In case of mac, running the command prefixed with sudo should do the job for you.

2. node-gyp not found! Please ensure node-gyp is in your PATH--


This issue is mainly related to the node-gyp module which should be installed globally in your system. The lwc local server has a dependency on this module. You can install the module by running the below command:

In case you face some permission issues while running the above command, I have already given the resolution above. In windows, run cmd as an administrator and try running the command again. In mac/linux, you can try running the command by prefixing it with sudo as: sudo npm install -g node-gyp and it should work fine.

I faced the above two issues and resolved them quickly by taking the steps mentioned. Do you face any issue apart from this? Make sure to share it in the comments below and also the resolution for the same if you've got it resolved. I'll update the post according to your comments so that it's easier for others to get these issues sorted.

Once your lwc local server is installed, you can preview your components locally by right clicking a lwc component in VSCode and selecting SFDX:Preview Component Locally and choose the Desktop Browser to preview component from the next option.


You should have the component preview in local server as shown below:


Happy Trailblazing..!!

Friday, 14 May 2021

How to solve UNABLE_TO_LOCK_ROW, unable to obtain exclusive access to this record or N records?

Hello Trailblazers,


Recently, I faced this issue in one of the projects I was working on. The issue was UNABLE_TO_LOCK_ROW, unable to obtain exclusive access to this record or N records, here N is just a placeholder in "N records" it can be 10, 20, 30 or even 100...200 for you. Let's have a look at the use case first and then we'll discuss the solution.

Use Case

I was having two objects connected with master detail relationship. So, you can consider it like: Object A which is the parent object and Object B which is the child object.

Object B (Child) -> Object A (Parent)

To simplify the terminology here, we're going to consider that our custom Object B is "Product Parts" and our custom Object A is "Product". So, each product part must be linked to a single product and one product can have multiple parts. So, our relationship is simplified as:

Product Part (Child) -> Product (Parent)

Let's consider that we have a field named as: Product__c on the Product Part object which is a master detail relationship between product and product parts.

Now, there were around 1.5 million records of Product Part and as we have a master detail relationship, so, it was sure that each Product Part record is linked to a record of Product. In our use case, we're updating the count of each product part on a daily basis using a batch class.

So, you can consider that 1.5 million records are updated on a daily basis. Even if we consider the maximum batch size of 2000, there will be around 750 batches that are running on a daily basis to update all records.

This is how the start method of my batch class looked like:

As you can see above, I am simply returning all the records of my Product_Part__c object as I need to update the count of all of them. Let's have a quick look at execute method as well.

As you can see above, I am simply updating the count of all the product parts to 100. There was nothing in my finish() method, so, I am not specifying that here. It was an empty method.

So, let's consider that for about 1.5M product parts, we're having around 15,000 products to which these product parts are linked to. When I ran my batch class over these records, I got the below error:

Developer script exception from SFDC Stop : 'ProductPartCountUpdateBatch' for job id '1024K0000OVBnlO' : Update failed. First exception on row 0 with id o1g4N00002wG5R4MBT; first error: UNABLE_TO_LOCK_ROW, unable to obtain exclusive access to this record or 100 records: 025A4m00003uCJs5QBL,025LO00002eCVhoAGH,.....

So, my batch class failed, I wasn't able to find any issue in the code, so, let's learn why it failed first of all.

Why it failed?

I noticed that all those ids that I got in my error message were not really the id of my Product Part records, They were the ids of my Product records. Interesting right?

After proceeding with my investigation, I read this in Salesforce documentationIf a record on the master side of a master-detail relationship has too many child records (thousands) you are likely to encounter these errors as well, as every time you edit the detail record, the master record is locked. 

So, now we know that our batch was failing because I was querying the records in the random order and multiple batches were trying to lock the same parent (product) record again and again. Let's have a look at the resolution now.

How to resolve it?

To resolve this issue, I just ordered my query in the start method as shown below:

As you can see above, I just ordered my product part records by using the Product__c which is nothing but the master detail field connecting product and product parts. Due to this small change, my product part records were clubbed together that belong to the same Product and were processed together as well.

There was no record locking issue after that as all the product part records which are linked to the same product were processed together and the same product record was not locked again and again by different child records in different batches.

Easy! right?

So, next time you face this UNABLE_TO_LOCK_ROW issue make sure to have a look at your object relationships and try to minimize the possibilities of error by making small enhancements in your query/code. Here we resolved a big issue by just Ordering the records together!

Happy Trailblazing..!!

Tuesday, 2 March 2021

Inheritance in JavaScript ES6 | Class Inheritance | JavaScript Tutorial Series by SFDC Stop

 Hello Trailblazers,


Welcome to the seventh tutorial in JavaScript Tutorial Series by SFDC Stop. In this tutorial, we're going to learn about Inheritance in JavaScript ES6. Inheritance is defined as the process where one (derived) class acquires the properties of another (base) class. We'll see how we can define a base class and a derived class, how we can call the constructor of the base class from the derived class, how we can use the base class methods from the derived class object with an example. This tutorial is published on SFDC Stop YouTube Channel. So, if you want to learn in detail, have a look at the tutorial video down below. Otherwise, you can scroll down to have a look at the code gist with explanation.

Tutorial Video


Concept

The concept of inheritance is to move from Generalization to Specialization. Inheritance plays a vital role in keeping your code reusable as you can keep all the methods that are common in a single base class and you can use them in derived (child) classes. You can basically create a hierarchy where each child has access to all the properties of it's parent as well as it has some other properties that are specific to itself.

Code Gist with Explanation

We're going to define a simple class named as Phone. This will be our base class. Then we're going to define another class named as TouchPhone which will be our derived class. Let's have a quick look at the code below and then we'll understand it properly:


Let's talk about the base class first. Our Phone class is accepting two parameters in it's constructor namely: name and price. The name and price received in the constructor is assigned to the data members of the class with the same name i.e. name and price. After the constructor() we have two methods that are responsible to print the name and price of the phone namely: printName() and printPrice()


Now, let's talk about the derived class. Our TouchPhone classs is extending the Phone class using the extends keyword, this class is our derived class. Inside the TouchPhone class, we have a constructor which is accepting 3 parameters namely: name, price and touchSensitivity. The name and price received in the constructor are passed to the constructor of the base class by using the super().


We know that the base class Phone accepts two parameters inside the constructor i.e. name and price, therefore, we've passed name and price in our super(). After that we've assigned the 3rd parameter which is nothing but touchSensitivity to the data member of the derived class with the same name. After the constructor, we have defined one method named as printTouchSensitivity() which is responsible to print the touch sensitivity of the touch phone.


Conceptual Note: There are some properties which are common to every mobile phone for ex: name and price. That's why we've kept them as a part of the base (parent) class. Now, there can be some phone specific properties as well. Like: we can divide a phone into 2 basic categories:


1. A touch screen phone


2. A basic phone with keypad


For this, we have derived a class from the phone class and named it as TouchPhone, which represents a touch screen phone with an additional property i.e. touchSensitivity. As we're moving from parent to child class, we're also moving from Generalization to Specialization as the child class has more specific properties as compared to base class.


On line number 39, we have created an instance of our TouchPhone class named as iPhone and passed the name, price and sensitivity as iPhone11, 200 and 1.5 respectively to the derived class constructor. The name and price are automatically passed to the Phone class constructor through the super(). Then we're calling the printName(), printPrice() and printTouchSensitivity() methods from the derived class object. The concept to learn here is that: The derived class object can directly access the methods of the base class and can also access the constructor of the base class using the super().


After that we just added a console.log('---------') to divide the result into two parts. In the second part, we're creating an instance of the base class named as basicPhone. We're passing two values inside the constructor named as: Basic Phone and 100. Then we're printing the name and price of the basic phone by calling the printName() and printPrice() methods.


The output when the above code is executed is given below:


As you can see above, we're able to get the name, price and touch sensitivity of the touch phone as: iPhone11, 200 and 1.5 from the instance of the TouchPhone class. After that we're displaying the name and price of the basic phone which is Basic Phone and 100 using the instance of Phone class.


So, we understood that the derived class can easily call the member functions of the base class but is the reverse possible? Can the base class call the member functions of the derived class? Let's try that..!!


As you can see below, we modified our code a little and at the last line we're trying to call the printTouchSensitivity() method of the derived class from the instance of the base class. 



The execution of the above code resulted in an error as "Uncaught TypeError: basicPhone.printTouchSensitivity is not a function". This is because, we cannot call the member function of a derived class from the base class.


To summarize, the learnings are given below:-

  • Inheritance is defined as the process where one (derived) class acquires the properties of another (base) class.

  • A class can extend another class by using extends keyword.

  • The derived class can call the constructor of the base class by using the super().

  • The instance of the derived class can directly call the methods of the base class.

  • The instance of the base classs cannot directly call the methods of the derived class.

That's all for this tutorial. I hope you liked it. All the code used in this tutorial is available on GitHub and you can have a look at that by clicking here. Make sure to have a look at the video if you want to learn in detail and let me know your feedback in the comments down below.

Happy Trailblazing..!!

Sunday, 21 February 2021

ES6 Classes in JavaScript | JavaScript Classes Private Variables | JavaScript Tutorial Series by SFDC Stop

Hello Trailblazers,


Welcome to the sixth tutorial in JavaScript Tutorial Series by SFDC Stop. In this tutorial, we're going to learn about ES6 classes in JavaScript. We'll see how we used to define classes in JavaScript before ES6 and how easy it is to define a class now using ES6 syntax. We'll also learn about defining private variables in JavaScript classes. This tutorial is published on SFDC Stop YouTube Channel. So, if you want to learn in detail, have a look at the tutorial video down below. Otherwise, you can scroll down to have a look at the code gist with explanation.

Tutorial Video


Code Gist with Explanation

How we used to create a class in JavaScript before ES6?

We're going to define a simple class named as Car. The code for the class is given below:


As you can see above, the class car is defined as a function itself because classses in JavaScript are special functions. It will receive two parameters inside the constructor: name and speed, which are parameters to the car function in the code. These two parameters name and speed are used to initialize two data members of the class with the same name i.e. name and speed. Note that the data members are referred by using this keyword.


After the constructor, we have a function named as showSpeed() which is used to display the speed of the car. This function belongs to the Car class, that is why we've used Car.prototype.<function-name> syntax to define the member function. This function can access the data members of the car by using the this keyword.


After the function definition, we simply created the instance of the car class named as audi and passed the name and speed of the car in the constructor as: audi and 200. Finally, we called our showSpeed() method to display the speed of the car by using the class instance. The output when we run this code is given below:

The code is executed successfully and we're getting the expected result i.e. 200 which is the speed of the car.

How can we now define a class in JavaScript using ES6 syntax?

Using ES6 we can define a class using class keyword and the constructor of the class can be defined using constructor keyword. Let's have a look at the same Car class but this time, it's defined using ES6 as shown below:

As you can see in the above code, this time we've defined a Car class using the class keyword. This syntax is very similar to other programming languages. Inside the class, we've defined a constructor by using the constructor keyword. This constructor is accepting two parameters: name and speed. The two data members name and speed of the class are referred using this keyword inside the constructor and are given the values passed inside the constructor. After that we've a function inside the class itself named as showSpeed() which is responsible to display the speed of the car.

The remaining code snippet is same, we've again created the instance of the Car class named as audi and passed the name and speed of the car in the constructor as: audi and 300. Finally, we called our showSpeed() method to display the speed of the car by using the class instance. The output when we run this code is given below:


As you can see above, we're getting the speed of the car displayed as 300 in the console.

Can we have private variables inside classes in JavaScript?

The answer is YES! You can define private variables inside classes in JavaScript. Let's have a look at the modified code snippet to understand how:

As you can see above, we have added one more parameter to the constructor of our class Car named as: color. This parameter is assigned to a new data member identified by #color which is also declared above in the class. Here # specifies that, the color data member is private. Also note that it's mandatory to declare the private data member in the class body, that's why we've declared it above at line number 3.

We've also created one more member function named as showColor() which is displaying the value of color data member. Below the class, we've added two statements at line number 22 and 23, where we're displaying the name and speed of the car audi by directly accessing the data members outside the class. We can do that because the data members are public and we can access the public data members directly outside the class. However, we also have a commented statement at line 24 where we're trying to access the color data member outside the class.

As we know, that the color data member is private, we cannot access it outside the class. You can give it a try by un-commenting the line and running the code snippet. You'll get an error as shown below:


If we comment that line again and try to access the color using the showColor() function which is called at the last, the code will work fine and you'll get the output as shown below:


So, as you can see above, we're getting the value 300 from showSpeed(), then we're getting the name and speed of the car by directly accessing the public variables outside the class with values: audi and 300. Finally, we're displaying the color of the car by using the showColor() which is displayed as red as it's the same color that we've passed in the constructor of the class.

To summarize, the learnings are given below:-
  • Before ES6, we used to define a class by using the syntax of a function because classes in JavaScript are Special Functions. The member functions of the class were defined outside the classs function.
  • ES6 made it very simple to define a class using the class keyword. We can define a constructor inside the class as well by using the constructor keyword. The member functions of the class can be defined inside the class body itself.
  • We can also define private variables in a class. Private variables must be explicitly declared inside the class body and are prefixed by a #. They can only be accessed inside class member functions.

That's all for this tutorial. I hope you liked it. All the code used in this tutorial is available on GitHub and you can have a look at that by clicking here. Make sure to have a look at the video if you want to learn in detail and let me know your feedback in the comments down below.

Happy Trailblazing..!!

Tuesday, 9 February 2021

ES6 Spread Operator | Rest Parameters in JavaScript | JavaScript Tutorial Series by SFDC Stop

 Hello Trailblazers,


Welcome to the fifth tutorial in JavaScript Tutorial Series by SFDC Stop. In this tutorial, we're going to learn about Spread Operator in ES6. We'll see how we can spread an array into multiple elements using the spread operator and also, how we can combine multiple elements into a single array by using spread operator as a rest parameter in ES6 JavaScript functions. This tutorial is published on SFDC Stop YouTube Channel. So, if you want to learn in detail, have a look at the tutorial video down below. Otherwise, you can scroll down to have a look at the code gist with explanation.

Tutorial Video


Code Gist with Explanation

How we used to pass array elements as parameters inside the function before ES6?

We're going to define a simple JavaScript function which will display the array elements passed as parameters. The code for that function is given below:


As you can see, we're having a function named as eats which has 3 parameters fruit1, fruit2, fruit3 and will print the statement consisting of the values of these. We're passing the fruits array elements into the function as fruits[0], fruits[1] and fruits[2]. The output when we run this code is given below:


The code is executed successfully and we're getting the expected result i.e. Baby eats:- apple, mango and banana

How can we now pass array elements into function using spread operator in ES6?

ES6 has defined spread operator and it made it much simpler to pass array elements as parameters to a function in JavaScript. The updated code is given below:

As you can see in the above code, we're passing the array elements to function parameters by using the statement eats(...fruits);. When we specify three dots (...) before an array then it spreads the array into it's elements. That's why this operator is known as the spread operator. Therefore, while passing the array into the eats function, we're spreading it into multiple elements. The output when the above code is executed is given below:


As you can see above, the output is exactly the same as we've seen before.

What are Rest parameters in JavaScript ES6?

We've seen above that the ES6 spread operator (...) can be used to break an array into it's elements. But do you know that we can also use it to combine multiple JavaScript variables into a single array? We can pass multiple parameters to a JavaScript function and we can combine all those parameters to an array by using the spread operator. Let's see how:

As you can see above, we have created a function named as car. It has two parameters: name and features with a spread operator. This features parameter is nothing but an array and we're displaying the features of the car by iterating this array using the forEach loop. You can see above that we've called the car method with different values as: car('Audi', 'Great Speed', 'Good Color', 'Comfort', 'Good Looks');. So, here, the first argument is the car name Audi and is assigned to the name parameter. All the other arguments are car features and are combined together to form the features array by using the spread operator.

This is why we say that the spread operator can also be used as a Rest Parameter because it collects all the extra - rest of the parameters that are passed to a JavaScript function and forms an array. The output of the above code is given below:


As you can see above, all the features of the car are combined in a features array and we're able to display those features.

Concatenating two arrays using Spread Operator

Do you know we can also concatenate two arrays using spread operator? Let's have a look at the below code snippet to understand how:

As you can see in the above code snippet, we've created two arrays: features and moreFeatures. The features array is having 4 entries :- 'Great Speed', 'Good Color', 'Comfort' and 'Good Looks', whereas the moreFeatures array is having 2 entries:- 'Great Mileage' and 'Amazing Design'. We're using Array.push() method on the features array as features.push() which is basically used to push one element at the end of the array but here, we're spreading our moreFeatures array into multiple elements by using the spread operator. Therefore, these elements are then pushed one by one into the features array automatically and both the arrays are combined into the features array.

The output we're getting when the above code snippet is executed is given below:


As you can see above, it's pushing the elements of moreFeatures array into the features array using the push() and we're getting the output as 6, as the total number of elements are now 6. Also, we displayed the features array and it's showing us all the 6 features together. Therefore, we're able to concatenate two arrays using the spread operator. 

The same can be achieved when you're defining the second array as shown in the below code snippet:

As you can see above, we've passed the features array as an array element after the 'Amazing Design' entry while defining the moreFeatures array. We're spreading this array using the spread operator. This means that the moreFeatures array should contain all the elements of the features array after it's own two elements. Let's have a look at the output below as we're displaying the moreFeatures array using console.log() :


As you can see above, the moreFeatures array has all the elements of the features array appended after it's own elements, so, the spread operator is working perfectly fine.

To summarize, the learnings are given below:-
  • Before ES6, if we need to pass array elements as parameters to js function, each array element was specified one by one using the index as array[0], array[1], array[2].
  • ES6 made it very simple and we can simply pass the whole array as a single parameter by using the spread operator like: ...array
  • In case, we're passing passing multiple values to a function we can combine them to an array using the spread operator. The spread operator is called a rest parameter in such a case.
  • We can also concatenate two arrays using the spread operator.

That's all for this tutorial. I hope you liked it. All the code used in this tutorial is available on GitHub and you can have a look at that by clicking here. Make sure to have a look at the video if you want to learn in detail and let me know your feedback in the comments down below.

Happy Trailblazing..!!

Tuesday, 2 February 2021

ES6 Default Parameters in JavaScript Functions | JavaScript Tutorial Series by SFDC Stop

Hello Trailblazers,


Welcome to the fourth tutorial in JavaScript Tutorial Series by SFDC Stop. In this tutorial, we're going to learn about ES6 Default Parameters in JavaScript Functions. We're going to see how we used to define default parameters before ES6 and how we can do it using ES6 syntax. This tutorial is published on SFDC Stop YouTube Channel. So, if you want to learn in detail, have a look at the tutorial video down below. Otherwise, you can scroll down to have a look at the code gist with explanation.

Tutorial Video


Code Gist with Explanation

We're going to define a simple JavaScript function which will add two values and display the result. The code for that function is given below:


Now, let's run this code once and then we'll learn about the default parameters. The output when we're calling this function with values 3 and 5 is given below:


As you can see, we're getting the result of addition of 3 and 5 displayed as 8. 

How we used to define default parameters before ES6?

Now, let's see how we used to define default parameters before ES6. For this, we're going to provide a default value for the parameter b. The updated code is given below:

As you can see in the above code, inside the function we're checking that if b is defined i.e. we're passing a value for parameter b, we're using that b itself otherwise, we're going to assign a default value to b which is 2. The output when the above function is called is given below. This time, we're only going to pass 1 value to the function which will be used for parameter a and the parameter b will take up the default value.


As you can see above, we're passing only one parameter as 3 and the default value 2 is being taken up for parameter b giving us the total sum as 5.

How can we define default parameters using ES6 syntax?

ES6 has made it much simpler to define default parameters for functions in JavaScript. We're going to re-write the same function again now and see how we can define a default value for parameter b using ES6. The updated code is given below:

As you can see above, it is so simple to provide the default value for any parameter in ES6 by just giving that value with an equals = sign. Here we're giving the default value for parameter b as 2 by specifying b=2 in the function parameters itself. The output when the above function is called is given below:


As you can see above, we're getting the output as 5 when the parameters a and b are added as the default value for b is automatically considered as 2 and we're passing the value for a as 3.

How can we define a default value if we're passing an object to a function in JavaScript?

The syntax to define the default value, when an object is passed to a function parameter is given below:

As you can see in the above code snippet, we've defined a function named as personAge which is accepting two parameters, the age of the person and the person object itself. The person object has two properties:- firstName and lastName. We've defined the default value for firstName as Richard and the lastName as Hendricks. Therefore, if this function is called with just one parameter, these values will be taken up as the default values for the person object.

One important thing to notice is that we're assigning an empty object to the person object which has the default values like:- { firstName = 'Richard', lastName = 'Hendricks' } = {}. This is important because we're telling the JavaScript function that the default value for this second parameter as a whole is an empty object which has no values for firstName and lastName, so, the default values for these properties i.e. Richard and Hendricks can be taken up.

The output we're getting when the above function is called is given below:


As you can see above, we've only passed a single value for the age parameter as 20 and we're getting the output as: Richard Hendricks is 20 years old which is perfect. So, this is how you can define default values for an object passed as a parameter to a JavaScript function.

To summarize, the learnings are given below:-
  • Before ES6, we were using conditional operator to define the default values for parameters
  • ES6 made it very simple and we can simply define a default value for a parameter by providing the value after the = sign at the same place where the parameter is defined
  • In case, we're passing an object to the function, we need to define a default value as an empty object after the = sign for the object parameter as a whole. Although, for the object properties, we can define the default values within the parameter definition. Both these steps are important to make sure that the object is initialized as well as the parameters also get their default values.

That's all for this tutorial. I hope you liked it. All the code used in this tutorial is available on GitHub and you can have a look at that by clicking here. Make sure to have a look at the video if you want to learn in detail and let me know your feedback in the comments down below.

Happy Trailblazing..!!

Thursday, 28 January 2021

SOQL FIELDS() is now Generally Available | Advantages and Limitations | Salesforce Spring '21 Release | SFDC Stop

Hello Trailblazers,


In this post, I am going to discuss about one of my favorite updates from Salesforce Spring '21 Release (v51.0) for Salesforce Developers which is:

SOQL FIELDS() is Generally Available

This is the best thing I read in this release, no more long SOQL queries to retrieve a lot of fields while integrating with external systems. 

You must be thinking that we don't need to update the apex code again and again to accomodate more fields due to frequent changes in the data model. IS IT REALLY SO? Let's find out.

Concept

You can query standard fields by using FIELDS(STANDARD) in the SOQL query:

SELECT FIELDS(Standard) FROM Account


Although most of the fields I queried are NULL :P because I just created some dummy account records using apex, but this is really amazing!!

You can query custom fields by using FIELDS(CUSTOM) in the SOQL query, Make sure to specify a limit as well (at max 200) as shown below:

SELECT FIELDS(Custom) FROM Account ORDER By LastModifiedDate DESC LIMIT 2



You can query all fields standard + custom by using FIELDS(ALL) in SOQL query:

SELECT FIELDS(ALL) FROM Account ORDER BY LastModifiedDate DESC LIMIT 5


As you can see above, first of all we're getting all the standard fields and at the end we're getting al the custom fields as well.

What CAN be done and what NOT?

1. You cannot have duplicate fields in SOQL query. Have a look at the below query, I am using FIELDS(Custom) which will query all custom fields and I am explicitly specifying Cost__c custom field as well which results in field duplication.


2. You cannot query custom fields using Apex. For Ex: the below code is not valid.


I even tried the above function by using Database.query() the file was saved successfully but I wasn't able to execute the function and got the same error as you can see below:


Although you can query all standard fields with some custom fields explicitly specified as shown below:


It worked perfectly fine as you can see the result:


You'll find the similar behaviour, if you try to use FIELDS(ALL).

Reason: FIELDS(ALL) and FIELDS(CUSTOM) are considered unbounded because the number of fields are not predetermined because the custom fields are created by admins/developers. Learn more about bounded and unbounded limitations here.

3. You must specify a LIMIT while querying unbounded fields i.e. using FIELDS(ALL) or FIELDS(CUSTOM) in the query. The limit can be 200 at max.


4. If you're specifying a set of IDs in the query, that must be a set of 200 ids at most. For ex:


5.  The SOQL query may query less records than specified in the LIMIT while using FIELDS() if your object contains CLOB or BLOB fields. In this case, it's recommended to checkout the number of records returned and update your offset accordingly to get the next set of records. You can use nextRecordsUrl  in case of REST API and queryMore() in case of SOAP API to query more records.

6. If you try to query custom fields for an object that doesn't have any, you'll receive an error as shown below:


Although if you specify even a single standard  field along with this query, the error will be ignored and your query will return the standard fields as shown below:


7. If you don't have access to a field (Field Level Security) it's automatically ignored. If you see in point number 4, the field Cost__c was also queried. However, now, I have removed the access to that field. You can see the result below:


So, that's all for this post everyone, I hope you liked it. I am also hoping that we can get over this bounded and unbounded fields limitation in the future releases so that we can query all custom fields in apex as well. Let me know your feedback about this post and your suggestions in the comments down below. 

Happy Trailblazing..!!