Skip to content

Commit ab5abc9

Browse files
committed
Add LAST_YEAR support in SOQL with related tests and comparables
1 parent 052641b commit ab5abc9

File tree

8 files changed

+141
-27
lines changed

8 files changed

+141
-27
lines changed

moxygen/main/default/classes/database/MockDatabaseTest.cls

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7365,4 +7365,32 @@ private class MockDatabaseTest {
73657365
'Incorrect number of opportunities'
73667366
);
73677367
}
7368+
7369+
@isTest
7370+
static void ensureLastYearWorksInWhereClause() {
7371+
List<Opportunity> oppList = new List<Opportunity>();
7372+
Date startOfYear = Date.newInstance(Gmt.today().year(), 1, 1);
7373+
for (Integer i = 0; i < 36; i++) {
7374+
oppList.add(
7375+
new Opportunity(
7376+
Name = 'Opp' + i,
7377+
CloseDate = startOfYear.addMonths(-i)
7378+
)
7379+
);
7380+
}
7381+
7382+
MockDatabase.doInsert(oppList, true);
7383+
7384+
Test.startTest();
7385+
List<Opportunity> opportunities = MockDatabase.query(
7386+
'SELECT Id, CloseDate FROM Opportunity WHERE CloseDate = LAST_YEAR'
7387+
);
7388+
Test.stopTest();
7389+
7390+
Assert.areEqual(
7391+
12,
7392+
opportunities.size(),
7393+
'Incorrect number of opportunities'
7394+
);
7395+
}
73687396
}

moxygen/main/default/classes/database/Token.cls

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,16 @@ public with sharing class Token {
149149
public final static String LAST_N_FISCAL_YEARS_LITERAL = 'last_n_fiscal_years';
150150
public final static String NEXT_FISCAL_YEAR_LITERAL = 'next_fiscal_year';
151151
public final static String LAST_FISCAL_YEAR_LITERAL = 'last_fiscal_year';
152-
public final static String NEXT_N_FISCAL_YEARS = 'next_n_fiscal_years';
153-
public final static String N_FISCAL_YEARS_AGO = 'n_fiscal_years_ago';
154-
public final static String N_YEARS_AGO = 'n_years_ago';
155-
public final static String LAST_N_FISCAL_QUARTERS = 'last_n_fiscal_quarters';
156-
public final static String NEXT_FISCAL_QUARTER = 'next_fiscal_quarter';
157-
public final static String NEXT_N_FISCAL_QUARTERS = 'next_n_fiscal_quarters';
158-
public final static String LAST_FISCAL_QUARTER = 'last_fiscal_quarter';
159-
public final static String THIS_FISCAL_QUARTER = 'this_fiscal_quarter';
160-
public final static String LAST_N_YEARS = 'last_n_years';
152+
public final static String NEXT_N_FISCAL_YEARS_LITERAL = 'next_n_fiscal_years';
153+
public final static String N_FISCAL_YEARS_AGO_LITERAL = 'n_fiscal_years_ago';
154+
public final static String N_YEARS_AGO_LITERAL = 'n_years_ago';
155+
public final static String LAST_N_FISCAL_QUARTERS_LITERAL = 'last_n_fiscal_quarters';
156+
public final static String NEXT_FISCAL_QUARTER_LITERAL = 'next_fiscal_quarter';
157+
public final static String NEXT_N_FISCAL_QUARTERS_LITERAL = 'next_n_fiscal_quarters';
158+
public final static String LAST_FISCAL_QUARTER_LITERAL = 'last_fiscal_quarter';
159+
public final static String THIS_FISCAL_QUARTER_LITERAL = 'this_fiscal_quarter';
160+
public final static String LAST_N_YEARS_LITERAL = 'last_n_years';
161+
public final static String LAST_YEAR_LITERAL = 'last_year';
161162

162163
public final static Set<String> DATE_LITERAL_TOKENS = new Set<String>{
163164
TODAY_LITERAL,
@@ -186,14 +187,15 @@ public with sharing class Token {
186187
LAST_N_FISCAL_YEARS_LITERAL,
187188
NEXT_FISCAL_YEAR_LITERAL,
188189
LAST_FISCAL_YEAR_LITERAL,
189-
NEXT_N_FISCAL_YEARS,
190-
N_FISCAL_YEARS_AGO,
191-
N_YEARS_AGO,
192-
LAST_N_FISCAL_QUARTERS,
193-
NEXT_FISCAL_QUARTER,
194-
NEXT_N_FISCAL_QUARTERS,
195-
LAST_FISCAL_QUARTER,
196-
THIS_FISCAL_QUARTER,
197-
LAST_N_YEARS
190+
NEXT_N_FISCAL_YEARS_LITERAL,
191+
N_FISCAL_YEARS_AGO_LITERAL,
192+
N_YEARS_AGO_LITERAL,
193+
LAST_N_FISCAL_QUARTERS_LITERAL,
194+
NEXT_FISCAL_QUARTER_LITERAL,
195+
NEXT_N_FISCAL_QUARTERS_LITERAL,
196+
LAST_FISCAL_QUARTER_LITERAL,
197+
THIS_FISCAL_QUARTER_LITERAL,
198+
LAST_N_YEARS_LITERAL,
199+
LAST_YEAR_LITERAL
198200
};
199201
}

moxygen/main/default/classes/database/soql-engine/interpreter/operator-handler/date-literal-comparable/DateLiteralComparableFactory.cls

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,16 @@ public with sharing class DateLiteralComparableFactory {
3232
Token.THIS_FISCAL_YEAR_LITERAL => ThisFiscalYearComparable.class,
3333
Token.LAST_N_FISCAL_YEARS_LITERAL => LastNFiscalYearsComparable.class,
3434
Token.LAST_FISCAL_YEAR_LITERAL => LastFiscalYearComparable.class,
35-
Token.NEXT_N_FISCAL_YEARS => NextNFiscalYearsComparable.class,
36-
Token.N_FISCAL_YEARS_AGO => NFiscalYearsAgoComparable.class,
37-
Token.N_YEARS_AGO => NYearsAgoComparable.class,
38-
Token.LAST_N_FISCAL_QUARTERS => LastNFiscalQuartersComparable.class,
39-
Token.NEXT_FISCAL_QUARTER => NextFiscalQuarterComparable.class,
40-
Token.NEXT_N_FISCAL_QUARTERS => NextNFiscalQuartersComparable.class,
41-
Token.LAST_FISCAL_QUARTER => LastFiscalQuarterComparable.class,
42-
Token.THIS_FISCAL_QUARTER => ThisFiscalQuarterComparable.class,
43-
Token.LAST_N_YEARS => LastNYearsComparable.class
35+
Token.NEXT_N_FISCAL_YEARS_LITERAL => NextNFiscalYearsComparable.class,
36+
Token.N_FISCAL_YEARS_AGO_LITERAL => NFiscalYearsAgoComparable.class,
37+
Token.N_YEARS_AGO_LITERAL => NYearsAgoComparable.class,
38+
Token.LAST_N_FISCAL_QUARTERS_LITERAL => LastNFiscalQuartersComparable.class,
39+
Token.NEXT_FISCAL_QUARTER_LITERAL => NextFiscalQuarterComparable.class,
40+
Token.NEXT_N_FISCAL_QUARTERS_LITERAL => NextNFiscalQuartersComparable.class,
41+
Token.LAST_FISCAL_QUARTER_LITERAL => LastFiscalQuarterComparable.class,
42+
Token.THIS_FISCAL_QUARTER_LITERAL => ThisFiscalQuarterComparable.class,
43+
Token.LAST_N_YEARS_LITERAL => LastNYearsComparable.class,
44+
Token.LAST_YEAR_LITERAL => LastYearComparable.class
4445
};
4546

4647
@TestVisible
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @description Comparable class for LAST_YEAR
3+
* @author Zackary Frazier
4+
* @since 2/2/2025
5+
* @group Soql Engine
6+
*/
7+
public with sharing class LastYearComparable extends DateLiteralComparable {
8+
public override Boolean isLessThan(Datetime fieldValue) {
9+
Date startOfThisYear = Date.newInstance(Gmt.today().year(), 1, 1);
10+
Date startOfLastYear = startOfThisYear.addYears(-1);
11+
return fieldValue < startOfLastYear;
12+
}
13+
14+
public override Boolean isGreaterThan(Datetime fieldValue) {
15+
Date startOfThisYear = Date.newInstance(Gmt.today().year(), 1, 1);
16+
return fieldValue >= startOfThisYear;
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>62.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@isTest
2+
private class LastYearComparableTest {
3+
@isTest
4+
static void ensureIsLessThanWorks() {
5+
LastYearComparable lastYearComparable = new LastYearComparable();
6+
Date startOfThisYear = Date.newInstance(Gmt.today().year(), 1, 1);
7+
Date startOfLastYear = startOfThisYear.addYears(-1);
8+
Date startOfLastYearMinusOne = startOfLastYear.addDays(-1);
9+
10+
Assert.isTrue(
11+
lastYearComparable.isLessThan(startOfLastYearMinusOne),
12+
'LastYearComparable.isLessThan should return true when fieldValue is less than startOfLastYear'
13+
);
14+
15+
Assert.isFalse(
16+
lastYearComparable.isLessThan(startOfLastYear),
17+
'LastYearComparable.isLessThan should return false when fieldValue is equal to startOfLastYear'
18+
);
19+
}
20+
21+
@isTest
22+
static void ensureIsGreaterThanWorks() {
23+
LastYearComparable lastYearComparable = new LastYearComparable();
24+
Date startOfThisYear = Date.newInstance(Gmt.today().year(), 1, 1);
25+
Date startOfThisYearMinusOne = startOfThisYear.addDays(-1);
26+
27+
Assert.isFalse(
28+
lastYearComparable.isGreaterThan(startOfThisYearMinusOne),
29+
'LastYearComparable.isGreaterThan should return false when fieldValue is less than startOfLastYear'
30+
);
31+
32+
Assert.isTrue(
33+
lastYearComparable.isGreaterThan(startOfThisYear),
34+
'LastYearComparable.isGreaterThan should return true when fieldValue is equal to startOfLastYear'
35+
);
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>62.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>

moxygen/main/default/classes/database/soql-engine/parser/ParserTest.cls

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,4 +842,22 @@ private class ParserTest {
842842
}
843843
Test.stopTest();
844844
}
845+
846+
@isTest
847+
static void ensureLastYearCanBeParsed() {
848+
Parser p = new Parser();
849+
String soqlQuery = 'SELECT Id FROM Opportunity WHERE CreatedDate = LAST_YEAR';
850+
Test.startTest();
851+
try {
852+
p.parse(soqlQuery);
853+
} catch (Exception e) {
854+
Assert.fail(
855+
'Expected no exception but got ' +
856+
e.getMessage() +
857+
' for ' +
858+
soqlQuery
859+
);
860+
}
861+
Test.stopTest();
862+
}
845863
}

0 commit comments

Comments
 (0)