Skip to content

Instantly share code, notes, and snippets.

@fahey252
Last active October 6, 2020 15:12
Show Gist options
  • Save fahey252/db190cb9455122c1e226de52aef20e61 to your computer and use it in GitHub Desktop.
Save fahey252/db190cb9455122c1e226de52aef20e61 to your computer and use it in GitHub Desktop.
Determining if Salesforce dependent picklist fields are valid for parent/controlling field

Page layout snippet of a single picklist value. Notice the oAAA in the validFor. The base64 value needs to be decoded to determine which parent items the dependent picklist value is allowed for. See https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_calls_describesobjects_describesobjectresult.htm for more info.

{
  "active": true,
  "defaultValue": false,
  "label": "Canceled",
  "validFor": "oAAA",
  "value": "Canceled"
}

Helper functions:

  /*
  Base64 characters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
  A is index 0 so : 000000
  I is index 8 so : 001000
  Q is index 16 so: 010000
  o is index 40 so: 101000

  QAAA is 010000 000000 000000 000000
    Since binary 1 at 2nd position, not index, means the dependent field is valid option for the 2nd option in parent picklist
  IAAA is 001000 000000 000000 000000
    Since binary 1 at 3rd position, not index, means the dependent field is valid option for the 3rd option in parent picklist
  oAAA is 101000 000000 000000 000000
    Since binary 1 at 1st and 3rd position, not index, means the dependent field is valid option for the 1st and 3rd option in parent picklist

  Given: 'QAAA', return string like: '010000000000000000000000'
  */
  base64EncodingToBinaryBits: (value = '') => {
    const base64CharacterSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    const characterValues = [...value];   // 'QAAA' becomes ['Q', 'A', 'A', 'A']
    const binaryValuesOfCharacterPosition = characterValues.map(character => {
      const characterPosition = base64CharacterSet.indexOf(character);
      const binaryRadix = 2;
      const binaryRepresentation = characterPosition.toString(binaryRadix);
      const base64Radix = 6;    // 2^6 is 64, 6 is the target length of of string
      const base64BinaryRepresentation = binaryRepresentation.padStart(base64Radix, '0'); // adds any needed leading 0's

      return base64BinaryRepresentation;
    });
    const binaryBits = binaryValuesOfCharacterPosition.join('');

    return binaryBits;
  },
  /*
    Binary strings are interpreted from left to right
    Consider on when the binary value is 1
  */
  isBinaryValueOnAtIndex: (binaryStringValue = '', index = 0) => {
    const bit = binaryStringValue[index];
    const isOn = bit
      ? bit === '1'
      : false;

    return isOn;
  }

Tests for helpers:

describe('Base64 string decoded to binary string', () => {
  it('No position on', () => {
    const base64PositionOn = undefined;
    const binaryPositionOn = '';
    const expectedBinaryPositionOn = stringUtilities.base64EncodingToBinaryBits(base64PositionOn);

    expect(expectedBinaryPositionOn).toEqual(binaryPositionOn);
  });

  it('2nd position on', () => {
    const base64PositionOn = 'QAAA';
    const binaryPositionOn = '010000000000000000000000';
    const expectedBinaryPositionOn = stringUtilities.base64EncodingToBinaryBits(base64PositionOn);

    expect(expectedBinaryPositionOn).toEqual(binaryPositionOn);
  });

  it('1st and 3rd position on', () => {
    const base64PositionOn = 'oAAA';
    const binaryPositionOn = '101000000000000000000000';
    const expectedBinaryPositionOn = stringUtilities.base64EncodingToBinaryBits(base64PositionOn);

    expect(expectedBinaryPositionOn).toEqual(binaryPositionOn);
  });
});

describe('Binary string values on or off', () => {
  it('Value on at index for no binary value, index out of bounds', () => {
    const binaryValue = '';
    const someRandomOutOfBoundsIndex = 5;
    const isIndexOn = stringUtilities.isBinaryValueOnAtIndex(binaryValue, someRandomOutOfBoundsIndex);

    expect(isIndexOn).toEqual(false);
  });

  it('Value on at index', () => {
    const binaryValue = '101000000000000000000000';
    const isFirstIndexOn = stringUtilities.isBinaryValueOnAtIndex(binaryValue, 0);
    const isThirdIndexOn = stringUtilities.isBinaryValueOnAtIndex(binaryValue, 2);

    expect(isFirstIndexOn).toEqual(true);
    expect(isThirdIndexOn).toEqual(true);
  });

  it('Value off at index', () => {
    const binaryValue = '101000000000000000000000';
    const isSecondIndexOn = stringUtilities.isBinaryValueOnAtIndex(binaryValue, 1);
    const isFourthIndexOn = stringUtilities.isBinaryValueOnAtIndex(binaryValue, 3);

    expect(isSecondIndexOn).toEqual(false);
    expect(isFourthIndexOn).toEqual(false);
  });
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment