1
0

Add support for multiple order by (#387)

This commit is contained in:
Siddhant Sanyam 2023-04-19 02:01:27 -07:00 committed by GitHub
parent a28966b410
commit 47acb503cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 20 deletions

View File

@ -13,11 +13,25 @@ export type QueryFilter = {
value: any; value: any;
}; };
export type QueryOrdering = {
orderBy: string;
orderDesc: boolean;
};
export type ParsedQuery = { export type ParsedQuery = {
table: string; table: string;
orderBy?: string;
orderDesc?: boolean;
limit?: number; limit?: number;
ordering: QueryOrdering[];
/** @deprecated Please use ordering.
* Deprecated due to PR #387
* Currently holds ordering[0] if exists
*/
orderBy?: string;
/** @deprecated Please use ordering.
* Deprecated due to PR #387
* Currently holds ordering[0] if exists
*/
orderDesc?: boolean;
filter: QueryFilter[]; filter: QueryFilter[];
select?: string[]; select?: string[];
render?: string; render?: string;
@ -97,22 +111,22 @@ export function applyQuery<T>(parsedQuery: ParsedQuery, records: T[]): T[] {
resultRecords.push(recordAny); resultRecords.push(recordAny);
} }
} }
// Now the sorting
if (parsedQuery.orderBy) {
resultRecords = resultRecords.sort((a: any, b: any) => {
const orderBy = parsedQuery.orderBy!;
const orderDesc = parsedQuery.orderDesc!;
if (a[orderBy] === b[orderBy]) {
return 0;
}
if (a[orderBy] < b[orderBy]) { if (parsedQuery.ordering.length > 0) {
return orderDesc ? 1 : -1; resultRecords = resultRecords.sort((a: any, b: any) => {
} else { for (const { orderBy, orderDesc } of parsedQuery.ordering) {
return orderDesc ? -1 : 1; if (a[orderBy] < b[orderBy] || a[orderBy] === undefined) {
return orderDesc ? 1 : -1;
}
if (a[orderBy] > b[orderBy] || b[orderBy] === undefined) {
return orderDesc ? -1 : 1;
}
// Consider them equal. This way helps with comparing arrays (like tags)
} }
return 0;
}); });
} }
if (parsedQuery.limit) { if (parsedQuery.limit) {
resultRecords = resultRecords.slice(0, parsedQuery.limit); resultRecords = resultRecords.slice(0, parsedQuery.limit);
} }

View File

@ -26,16 +26,33 @@ export function parseQuery(queryTree: ParseTree): ParsedQuery {
const parsedQuery: ParsedQuery = { const parsedQuery: ParsedQuery = {
table: queryNode.children![0].children![0].text!, table: queryNode.children![0].children![0].text!,
filter: [], filter: [],
ordering: [],
}; };
const orderByNode = findNodeOfType(queryNode, "OrderClause");
if (orderByNode) { const orderByNodes = collectNodesOfType(queryNode, "OrderClause");
for (const orderByNode of orderByNodes) {
const nameNode = findNodeOfType(orderByNode, "Name"); const nameNode = findNodeOfType(orderByNode, "Name");
parsedQuery.orderBy = nameNode!.children![0].text!; const orderBy = nameNode!.children![0].text!;
const orderNode = findNodeOfType(orderByNode, "OrderDirection"); const orderNode = findNodeOfType(orderByNode, "OrderDirection");
parsedQuery.orderDesc = orderNode const orderDesc = orderNode
? orderNode.children![0].text! === "desc" ? orderNode.children![0].text! === "desc"
: false; : false;
parsedQuery.ordering.push({ orderBy, orderDesc });
} }
/**
* @deprecated due to PR #387
* We'll take the first ordering and send that as the deprecated
* fields orderBy and orderDesc. This way it will be backward
* Plugs using the old ParsedQuery.
* Remove this block completely when ParsedQuery no longer have
* those two fields
*/
if (parsedQuery.ordering.length > 0) {
parsedQuery.orderBy = parsedQuery.ordering[0].orderBy;
parsedQuery.orderDesc = parsedQuery.ordering[0].orderDesc;
}
/** @end-deprecation due to PR #387 */
const limitNode = findNodeOfType(queryNode, "LimitClause"); const limitNode = findNodeOfType(queryNode, "LimitClause");
if (limitNode) { if (limitNode) {
const nameNode = findNodeOfType(limitNode, "Number"); const nameNode = findNodeOfType(limitNode, "Number");

View File

@ -26,8 +26,9 @@ Deno.test("Test parser", () => {
`task where completed = false and dueDate <= "{{today}}" order by dueDate desc limit 5`, `task where completed = false and dueDate <= "{{today}}" order by dueDate desc limit 5`,
); );
assertEquals(parsedQuery1.table, "task"); assertEquals(parsedQuery1.table, "task");
assertEquals(parsedQuery1.orderBy, "dueDate"); assertEquals(parsedQuery1.ordering.length, 1);
assertEquals(parsedQuery1.orderDesc, true); assertEquals(parsedQuery1.ordering[0].orderBy, "dueDate");
assertEquals(parsedQuery1.ordering[0].orderDesc, true);
assertEquals(parsedQuery1.limit, 5); assertEquals(parsedQuery1.limit, 5);
assertEquals(parsedQuery1.filter.length, 2); assertEquals(parsedQuery1.filter.length, 2);
assertEquals(parsedQuery1.filter[0], { assertEquals(parsedQuery1.filter[0], {
@ -69,6 +70,7 @@ Deno.test("Test parser", () => {
parseQuery(`gh-events where type in ["PushEvent", "somethingElse"]`), parseQuery(`gh-events where type in ["PushEvent", "somethingElse"]`),
{ {
table: "gh-events", table: "gh-events",
ordering: [],
filter: [ filter: [
{ {
op: "in", op: "in",
@ -81,12 +83,14 @@ Deno.test("Test parser", () => {
assertEquals(parseQuery(`something render [[template/table]]`), { assertEquals(parseQuery(`something render [[template/table]]`), {
table: "something", table: "something",
ordering: [],
filter: [], filter: [],
render: "template/table", render: "template/table",
}); });
assertEquals(parseQuery(`something render "template/table"`), { assertEquals(parseQuery(`something render "template/table"`), {
table: "something", table: "something",
ordering: [],
filter: [], filter: [],
render: "template/table", render: "template/table",
}); });