Skip to content

Commit

Permalink
Merge pull request #53 from adangel/convert-currency
Browse files Browse the repository at this point in the history
Support convertCurrency() function in SOQL and SOSL
  • Loading branch information
pwrightcertinia authored Sep 26, 2024
2 parents 609d972 + bb50485 commit 07c4de6
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 3 deletions.
1 change: 1 addition & 0 deletions antlr/ApexLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ STANDARD : 'standard';
DISTANCE : 'distance';
GEOLOCATION : 'geolocation';
GROUPING : 'grouping';
CONVERT_CURRENCY : 'convertcurrency'; // used in both SOQL and SOSL

// SOQL Date functions
CALENDAR_MONTH : 'calendar_month';
Expand Down
9 changes: 7 additions & 2 deletions antlr/ApexParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ soqlFunction
| MAX LPAREN fieldName RPAREN
| SUM LPAREN fieldName RPAREN
| TOLABEL LPAREN fieldName RPAREN
| FORMAT LPAREN fieldName RPAREN
| FORMAT LPAREN ( fieldName | soqlFunction ) RPAREN
| CALENDAR_MONTH LPAREN dateFieldName RPAREN
| CALENDAR_QUARTER LPAREN dateFieldName RPAREN
| CALENDAR_YEAR LPAREN dateFieldName RPAREN
Expand All @@ -637,6 +637,7 @@ soqlFunction
| FIELDS LPAREN soqlFieldsParameter RPAREN
| DISTANCE LPAREN locationValue COMMA locationValue COMMA StringLiteral RPAREN
| GROUPING LPAREN fieldName RPAREN
| CONVERT_CURRENCY LPAREN fieldName RPAREN
;

dateFieldName
Expand Down Expand Up @@ -865,7 +866,9 @@ fieldSpec

fieldList
: soslId (COMMA fieldList)*
| TOLABEL LPAREN soslId RPAREN
| TOLABEL LPAREN soslId RPAREN soslId?
| CONVERT_CURRENCY LPAREN soslId RPAREN soslId?
| FORMAT LPAREN (soslId | soqlFunction) RPAREN soslId?
;

updateList
Expand Down Expand Up @@ -965,6 +968,7 @@ id
| DISTANCE
| GEOLOCATION
| GROUPING
| CONVERT_CURRENCY
// SOQL date functions
| CALENDAR_MONTH
| CALENDAR_QUARTER
Expand Down Expand Up @@ -1164,6 +1168,7 @@ anyId
| DISTANCE
| GEOLOCATION
| GROUPING
| CONVERT_CURRENCY
// SOQL date functions
| CALENDAR_MONTH
| CALENDAR_QUARTER
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,38 @@ void testGroupingFunction() {
assertNotNull(context);
assertEquals(0, parserAndCounter.getValue().getNumErrors());
}

@Test
void testConvertCurrency() {
Map.Entry<ApexParser, SyntaxErrorCounter> parserAndCounter = createParser(
"[ SELECT convertCurrency(Amount) FROM Opportunity ]"
);
ApexParser.SoqlLiteralContext context = parserAndCounter.getKey().soqlLiteral();
assertNotNull(context);
assertEquals(0, parserAndCounter.getValue().getNumErrors());
}

@Test
void testConvertCurrencyWithFormat() {
Map.Entry<ApexParser, SyntaxErrorCounter> parserAndCounter = createParser(
"[\n" +
"SELECT Amount, FORMAT(amount) Amt, convertCurrency(amount) convertedAmount,\n" +
" FORMAT(convertCurrency(amount)) convertedCurrency\n" +
"FROM Opportunity where id = '006R00000024gDtIAI'\n" +
"]"
);
ApexParser.SoqlLiteralContext context = parserAndCounter.getKey().soqlLiteral();
assertNotNull(context);
assertEquals(0, parserAndCounter.getValue().getNumErrors());
}

@Test
void testFormatWithAggregate() {
Map.Entry<ApexParser, SyntaxErrorCounter> parserAndCounter = createParser(
"[ SELECT FORMAT(MIN(closedate)) Amt FROM opportunity ]"
);
ApexParser.SoqlLiteralContext context = parserAndCounter.getKey().soqlLiteral();
assertNotNull(context);
assertEquals(0, parserAndCounter.getValue().getNumErrors());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,43 @@ void testToLabel() {
assertNotNull(context);
assertEquals(0, parserAndCounter.getValue().getNumErrors());
}

@Test
void testToLabelWithAlias() {
Map.Entry<ApexParser, SyntaxErrorCounter> parserAndCounter = createParser(
"[FIND :searchTerm IN ALL FIELDS RETURNING Account(Id, toLabel(Name) AliasName) LIMIT 10]");
ApexParser.SoslLiteralContext context = parserAndCounter.getKey().soslLiteral();
assertNotNull(context);
assertEquals(0, parserAndCounter.getValue().getNumErrors());
}

@Test
void testConvertCurrency() {
Map.Entry<ApexParser, SyntaxErrorCounter> parserAndCounter = createParser(
"[ FIND 'test' RETURNING Opportunity(Name, convertCurrency(Amount), convertCurrency(Amount) AliasCurrency) ]"
);
ApexParser.SoslLiteralContext context = parserAndCounter.getKey().soslLiteral();
assertNotNull(context);
assertEquals(0, parserAndCounter.getValue().getNumErrors());
}

@Test
void testConvertCurrencyWithFormat() {
Map.Entry<ApexParser, SyntaxErrorCounter> parserAndCounter = createParser(
"[ FIND 'Acme' RETURNING Account(AnnualRevenue, FORMAT(convertCurrency(AnnualRevenue)) convertedCurrency) ]"
);
ApexParser.SoslLiteralContext context = parserAndCounter.getKey().soslLiteral();
assertNotNull(context);
assertEquals(0, parserAndCounter.getValue().getNumErrors());
}

@Test
void testFormatWithAggregate() {
Map.Entry<ApexParser, SyntaxErrorCounter> parserAndCounter = createParser(
"[ FIND 'Acme' RETURNING Account(AnnualRevenue, FORMAT(MIN(CloseDate))) ]"
);
ApexParser.SoslLiteralContext context = parserAndCounter.getKey().soslLiteral();
assertNotNull(context);
assertEquals(0, parserAndCounter.getValue().getNumErrors());
}
}
36 changes: 35 additions & 1 deletion npm/src/__tests__/SOQLParserTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
*/
import { QueryContext, StatementContext } from "../ApexParser";
import { QueryContext, StatementContext, SoqlLiteralContext } from "../ApexParser";
import { createParser } from "./SyntaxErrorCounter";

test("SOQL Query", () => {
Expand Down Expand Up @@ -138,3 +138,37 @@ test("Grouping function", () => {
expect(context).toBeInstanceOf(QueryContext);
expect(errorCounter.getNumErrors()).toEqual(0);
});

test("Convert Currency function", () => {
const [parser, errorCounter] = createParser(
'[ SELECT convertCurrency(Amount) FROM Opportunity ]'
);
const context = parser.soqlLiteral();

expect(context).toBeInstanceOf(SoqlLiteralContext);
expect(errorCounter.getNumErrors()).toEqual(0);
});

test("Convert Currency with format", () => {
const [parser, errorCounter] = createParser(
`[
SELECT Amount, FORMAT(amount) Amt, convertCurrency(amount) convertedAmount,
FORMAT(convertCurrency(amount)) convertedCurrency
FROM Opportunity where id = '006R00000024gDtIAI'
]`
);
const context = parser.soqlLiteral();

expect(context).toBeInstanceOf(SoqlLiteralContext);
expect(errorCounter.getNumErrors()).toEqual(0);
});

test("Format function with aggregate", () => {
const [parser, errorCounter] = createParser(
'[ SELECT FORMAT(MIN(closedate)) Amt FROM opportunity ]'
)
const context = parser.soqlLiteral();

expect(context).toBeInstanceOf(SoqlLiteralContext);
expect(errorCounter.getNumErrors()).toEqual(0);
});
48 changes: 48 additions & 0 deletions npm/src/__tests__/SOSLParserTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,51 @@ test('testToLabel', () => {
expect(context).toBeInstanceOf(SoslLiteralContext)
expect(errorCounter.getNumErrors()).toEqual(0)
})

test('testToLabelWithAlias', () => {
const [parser, errorCounter] = createParser(
"[FIND :searchTerm IN ALL FIELDS RETURNING Account(Id, toLabel(Name) AliasName) LIMIT 10]")
const context = parser.soslLiteral()

expect(context).toBeInstanceOf(SoslLiteralContext)
expect(errorCounter.getNumErrors()).toEqual(0)
})

test('testConvertCurrency', () => {
const [parser, errorCounter] = createParser(
`[
FIND 'test' RETURNING Opportunity(
Name,
convertCurrency(Amount),
convertCurrency(Amount) AliasCurrency
)
]`)
const context = parser.soslLiteral()

expect(context).toBeInstanceOf(SoslLiteralContext)
expect(errorCounter.getNumErrors()).toEqual(0)
})

test('testConvertCurrencyWithFormat', () => {
const [parser, errorCounter] = createParser(
`[
FIND 'Acme' RETURNING Account(
AnnualRevenue,
FORMAT(convertCurrency(AnnualRevenue)) convertedCurrency
)
]`)
const context = parser.soslLiteral()

expect(context).toBeInstanceOf(SoslLiteralContext)
expect(errorCounter.getNumErrors()).toEqual(0)
})

test('testFormatWithAggregate', () => {
const [parser, errorCounter] = createParser(
"[ FIND 'Acme' RETURNING Account(AnnualRevenue, FORMAT(MIN(CloseDate))) ]"
)
const context = parser.soslLiteral()

expect(context).toBeInstanceOf(SoslLiteralContext)
expect(errorCounter.getNumErrors()).toEqual(0)
})

0 comments on commit 07c4de6

Please sign in to comment.