Skip to content

Commit 48c3c36

Browse files
authored
Merge pull request #4 from msnraju/feature-#1/select-multiple-columns-order-by-clause
ORDER BY, Multi Column Query support implemented
2 parents f63da78 + ec1e623 commit 48c3c36

File tree

7 files changed

+231
-91
lines changed

7 files changed

+231
-91
lines changed

app/src/Inline Query/codeunit/InlineQuery.Codeunit.al

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,14 @@ codeunit 50104 "Inline Query"
108108
begin
109109
InlineQueryImpl.AsVariant(QueryText, ResultVariant);
110110
end;
111+
112+
/// <summary>
113+
/// Apply Filters and Sorting to RecordRef from the Query.
114+
/// </summary>
115+
/// <param name="QueryText">The inline query text</param>
116+
/// <param name="RecordRef">The RecordRef variable to be updated with Sorting and Filters</param>
117+
procedure AsRecord(QueryText: Text; var RecordRef: RecordRef)
118+
begin
119+
InlineQueryImpl.AsRecord(QueryText, RecordRef);
120+
end;
111121
}

app/src/Inline Query/codeunit/InlineQueryCompiler.Codeunit.al

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ codeunit 50103 "Inline Query Compiler"
1414
JTable: JsonObject;
1515
JFields: JsonArray;
1616
JFilters: JsonArray;
17+
JOrderByFields: JsonArray;
1718
NewJASTNode: JsonObject;
1819
begin
1920
if JASTNode.Get('Table', JToken) then
@@ -25,9 +26,13 @@ codeunit 50103 "Inline Query Compiler"
2526
if JASTNode.Get('Filters', JToken) then
2627
JFilters := CompileFilters(JToken.AsArray(), TableID);
2728

29+
if JASTNode.Get('OrderBy', JToken) then
30+
JOrderByFields := CompileOrderByFields(JToken.AsArray(), TableID);
31+
2832
NewJASTNode.Add('Fields', JFields);
2933
NewJASTNode.Add('Table', JTable);
3034
NewJASTNode.Add('Filters', JFilters);
35+
NewJASTNode.Add('OrderBy', JOrderByFields);
3136

3237
exit(NewJASTNode);
3338
end;
@@ -165,6 +170,21 @@ codeunit 50103 "Inline Query Compiler"
165170
exit(NewJFieldNode);
166171
end;
167172

173+
local procedure CompileOrderByFields(JFields: JsonArray; TableID: Integer): JsonArray
174+
var
175+
JToken: JsonToken;
176+
FieldID: Integer;
177+
NewJFields: JsonArray;
178+
begin
179+
foreach JToken in JFields do begin
180+
FieldID := GetFieldID(JToken.AsValue().AsText(), TableID);
181+
NewJFields.Add(FieldID);
182+
end;
183+
184+
exit(NewJFields);
185+
end;
186+
187+
168188
local procedure CompileTable(JTable: JsonObject; var TableID: Integer): JsonObject
169189
var
170190
AllObj: Record AllObj;

app/src/Inline Query/codeunit/InlineQueryImpl.Codeunit.al

Lines changed: 85 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ codeunit 50101 "Inline Query Impl"
99
EmptyQueryErr: Label 'Query should not be empty.';
1010
FunctionExpectedErr: Label 'Function expected.';
1111
SingleFunctionExpectedErr: Label 'A single function expected.';
12+
SortingLbl: Label 'SORTING(%1)', Locked = true, Comment = '%1 = Field';
1213

1314
procedure AsInteger(QueryText: Text): Integer
1415
var
@@ -92,6 +93,14 @@ codeunit 50101 "Inline Query Impl"
9293
GetFunctionValue(RecordRef, JASTNode, ValueVariant);
9394
end;
9495

96+
procedure AsRecord(QueryText: Text; var RecordRef: RecordRef)
97+
var
98+
JASTNode: JsonObject;
99+
begin
100+
JASTNode := QueryAsASTNode(QueryText);
101+
PrepareRecRef(RecordRef, JASTNode);
102+
end;
103+
95104
local procedure QueryAsASTNode(QueryText: Text): JsonObject
96105
var
97106
JTokens: JsonArray;
@@ -120,7 +129,6 @@ codeunit 50101 "Inline Query Impl"
120129
RecCount: Integer;
121130
NumberValue: Decimal;
122131
FunctionType: Enum "Inline Query Function Type";
123-
SortingLbl: Label 'SORTING(%1)', Comment = '%1 = Field';
124132
begin
125133
JASTNode.Get('Fields', JToken);
126134
JFields := JToken.AsArray();
@@ -149,13 +157,13 @@ codeunit 50101 "Inline Query Impl"
149157
ValueVariant := RecordRef.Count();
150158
FunctionType::Min:
151159
begin
152-
RecordRef.SetView(StrSubstNo(SortingLbl, FieldRef.Name));
160+
SetOrderBy(JASTNode, RecordRef, FieldRef.Name);
153161
if RecordRef.FindFirst() then
154162
ValueVariant := FieldRef.Value;
155163
end;
156164
FunctionType::Max:
157165
begin
158-
RecordRef.SetView(StrSubstNo(SortingLbl, FieldRef.Name));
166+
SetOrderBy(JASTNode, RecordRef, FieldRef.Name);
159167
if RecordRef.FindLast() then
160168
ValueVariant := FieldRef.Value;
161169
end;
@@ -196,6 +204,12 @@ codeunit 50101 "Inline Query Impl"
196204
JASTNode.Get('Table', JToken);
197205
OpenTable(RecordRef, JToken.AsObject());
198206

207+
JASTNode.Get('Fields', JToken);
208+
AddLoadFields(RecordRef, JToken.AsArray());
209+
210+
if JASTNode.Get('OrderBy', JToken) then
211+
ApplyOrderBy(RecordRef, JToken.AsArray());
212+
199213
JASTNode.Get('Filters', JToken);
200214
ApplyFilters(RecordRef, JToken.AsArray());
201215
end;
@@ -218,15 +232,43 @@ codeunit 50101 "Inline Query Impl"
218232
RecordRef.Open(TableID)
219233
end;
220234

235+
local procedure AddLoadFields(var RecordRef: RecordRef; JFields: JsonArray)
236+
var
237+
JToken: JsonToken;
238+
begin
239+
foreach JToken in JFields do
240+
AddLoadField(RecordRef, JToken.AsObject());
241+
end;
242+
243+
local procedure AddLoadField(var RecordRef: RecordRef; JField: JsonObject)
244+
var
245+
JToken: JsonToken;
246+
FieldID: Integer;
247+
IsFunction: Boolean;
248+
FunctionType: Enum "Inline Query Function Type";
249+
begin
250+
JField.Get('IsFunction', JToken);
251+
IsFunction := JToken.AsValue().AsBoolean();
252+
253+
if IsFunction then begin
254+
JField.Get('Function', JToken);
255+
FunctionType := "Inline Query Function Type".FromInteger(JToken.AsValue().AsInteger());
256+
if FunctionType = FunctionType::Count then
257+
exit;
258+
end;
259+
260+
JField.Get('Field', JToken);
261+
FieldID := JToken.AsValue().AsInteger();
262+
RecordRef.AddLoadFields(FieldID);
263+
end;
264+
265+
221266
local procedure ApplyFilters(var RecordRef: RecordRef; JFilters: JsonArray)
222267
var
223268
JToken: JsonToken;
224269
begin
225-
RecordRef.FilterGroup := 2;
226270
foreach JToken in JFilters do
227271
ApplyFilter(RecordRef, JToken.AsObject());
228-
229-
RecordRef.FilterGroup := 0;
230272
end;
231273

232274
local procedure ApplyFilter(var RecordRef: RecordRef; JFilter: JsonObject)
@@ -263,4 +305,41 @@ codeunit 50101 "Inline Query Impl"
263305
FieldRef.SetFilter('>=' + FilterValue);
264306
end;
265307
end;
308+
309+
local procedure ApplyOrderBy(var RecordRef: RecordRef; JFields: JsonArray)
310+
var
311+
FieldRef: FieldRef;
312+
JToken: JsonToken;
313+
FieldID: Integer;
314+
TableKey: Text;
315+
begin
316+
if JFields.Count() = 0 then
317+
exit;
318+
319+
foreach JToken in JFields do begin
320+
FieldID := JToken.AsValue().AsInteger();
321+
FieldRef := RecordRef.Field(FieldID);
322+
if TableKey = '' then
323+
TableKey := FieldRef.Name
324+
else
325+
TableKey += ',' + FieldRef.Name;
326+
end;
327+
328+
RecordRef.SetView(StrSubstNo(SortingLbl, TableKey));
329+
end;
330+
331+
local procedure SetOrderBy(JASTNode: JsonObject; var RecordRef: RecordRef; FieldName: Text)
332+
var
333+
JToken: JsonToken;
334+
begin
335+
if not JASTNode.Get('OrderBy', JToken) then
336+
exit;
337+
338+
if JToken.AsArray().Count() > 0 then
339+
exit;
340+
341+
RecordRef.FilterGroup := 2;
342+
RecordRef.SetView(StrSubstNo(SortingLbl, FieldName));
343+
RecordRef.FilterGroup := 0;
344+
end;
266345
}

app/src/Inline Query/codeunit/InlineQueryParser.Codeunit.al

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ codeunit 50102 "Inline Query Parser"
1313
JTable: JsonObject;
1414
JFields: JsonArray;
1515
JFilters: JsonArray;
16+
JOrderByFields: JsonArray;
1617
JASTNode: JsonObject;
1718
begin
1819
if JTokens.Count() = 0 then
@@ -25,12 +26,14 @@ codeunit 50102 "Inline Query Parser"
2526
JFields := ParseFields(JTokens, Pos);
2627
JTable := ParseTable(JTokens, Pos);
2728
JFilters := ParseFilters(JTokens, Pos);
29+
JOrderByFields := ParseOrderBy(JTokens, Pos);
2830

2931
EndOfQuery(JTokens, Pos);
3032

3133
JASTNode.Add('Fields', JFields);
3234
JASTNode.Add('Table', JTable);
3335
JASTNode.Add('Filters', JFilters);
36+
JASTNode.Add('OrderBy', JOrderByFields);
3437

3538
exit(JASTNode);
3639
end;
@@ -72,7 +75,7 @@ codeunit 50102 "Inline Query Parser"
7275
exit;
7376

7477
if UpperCase(TokenValue) <> 'WHERE' then
75-
Error(SyntaxErrorErr, 'WHERE');
78+
exit;
7679

7780
Pos += 1;
7881

@@ -116,6 +119,45 @@ codeunit 50102 "Inline Query Parser"
116119
exit(JFilters);
117120
end;
118121

122+
local procedure ParseOrderBy(JTokens: JsonArray; var Pos: Integer): JsonArray
123+
var
124+
TokenValue: Text;
125+
TokenType: Enum "Inline Query Token Type";
126+
FieldName: Text;
127+
JFields: JsonArray;
128+
begin
129+
if not PeekToken(JTokens, Pos, TokenValue, TokenType) then
130+
exit;
131+
132+
if UpperCase(TokenValue) <> 'ORDER' then
133+
exit;
134+
135+
Pos += 1;
136+
137+
if not ReadToken(JTokens, Pos, TokenValue, TokenType) then
138+
Error(SyntaxErrorErr, 'ORDER');
139+
140+
if UpperCase(TokenValue) <> 'BY' then
141+
Error(SyntaxErrorErr, 'BY');
142+
143+
144+
while (UpperCase(TokenValue) = 'BY') or (TokenValue = ',') do begin
145+
if not ReadToken(JTokens, Pos, TokenValue, TokenType) then
146+
Error(SyntaxErrorErr, 'Field');
147+
148+
FieldName := TokenValue;
149+
JFields.Add(FieldName);
150+
151+
if not PeekToken(JTokens, Pos, TokenValue, TokenType) then
152+
Break;
153+
154+
if TokenValue = ',' then
155+
Pos += 1;
156+
end;
157+
158+
exit(JFields);
159+
end;
160+
119161
local procedure ParseTable(JTokens: JsonArray; var Pos: Integer): JsonObject
120162
var
121163
TokenValue: Text;

app/src/test/CustomerListExt.PageExt.al

Lines changed: 0 additions & 10 deletions
This file was deleted.

app/src/test/InlineQueryTest.Page.al

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ page 50100 "Inline Query Test"
1717
field("Result"; Result)
1818
{
1919
Editable = false;
20+
MultiLine = true;
2021
ApplicationArea = All;
2122
ToolTip = 'The Query Result';
2223
Caption = 'Result';
@@ -41,10 +42,16 @@ page 50100 "Inline Query Test"
4142

4243
trigger OnAction()
4344
var
45+
RecordRef: RecordRef;
4446
ResultVariant: Variant;
4547
begin
4648
Result := '';
47-
InlineQuery.AsVariant(QueryText, ResultVariant);
49+
InlineQuery.AsRecord(QueryText, ResultVariant);
50+
if ResultVariant.IsRecordRef then begin
51+
RecordRef := ResultVariant;
52+
Message('%1', RecordRef.GetView());
53+
end;
54+
4855
Result := Format(ResultVariant);
4956
end;
5057
}

0 commit comments

Comments
 (0)