Add support for multiple order by (#387)
parent
a28966b410
commit
47acb503cb
|
@ -13,11 +13,25 @@ export type QueryFilter = {
|
|||
value: any;
|
||||
};
|
||||
|
||||
export type QueryOrdering = {
|
||||
orderBy: string;
|
||||
orderDesc: boolean;
|
||||
};
|
||||
|
||||
export type ParsedQuery = {
|
||||
table: string;
|
||||
orderBy?: string;
|
||||
orderDesc?: boolean;
|
||||
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[];
|
||||
select?: string[];
|
||||
render?: string;
|
||||
|
@ -97,22 +111,22 @@ export function applyQuery<T>(parsedQuery: ParsedQuery, records: T[]): T[] {
|
|||
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) {
|
||||
resultRecords = resultRecords.sort((a: any, b: any) => {
|
||||
for (const { orderBy, orderDesc } of parsedQuery.ordering) {
|
||||
if (a[orderBy] < b[orderBy] || a[orderBy] === undefined) {
|
||||
return orderDesc ? 1 : -1;
|
||||
} else {
|
||||
}
|
||||
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) {
|
||||
resultRecords = resultRecords.slice(0, parsedQuery.limit);
|
||||
}
|
||||
|
|
|
@ -26,16 +26,33 @@ export function parseQuery(queryTree: ParseTree): ParsedQuery {
|
|||
const parsedQuery: ParsedQuery = {
|
||||
table: queryNode.children![0].children![0].text!,
|
||||
filter: [],
|
||||
ordering: [],
|
||||
};
|
||||
const orderByNode = findNodeOfType(queryNode, "OrderClause");
|
||||
if (orderByNode) {
|
||||
|
||||
const orderByNodes = collectNodesOfType(queryNode, "OrderClause");
|
||||
for (const orderByNode of orderByNodes) {
|
||||
const nameNode = findNodeOfType(orderByNode, "Name");
|
||||
parsedQuery.orderBy = nameNode!.children![0].text!;
|
||||
const orderBy = nameNode!.children![0].text!;
|
||||
const orderNode = findNodeOfType(orderByNode, "OrderDirection");
|
||||
parsedQuery.orderDesc = orderNode
|
||||
const orderDesc = orderNode
|
||||
? orderNode.children![0].text! === "desc"
|
||||
: 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");
|
||||
if (limitNode) {
|
||||
const nameNode = findNodeOfType(limitNode, "Number");
|
||||
|
|
|
@ -26,8 +26,9 @@ Deno.test("Test parser", () => {
|
|||
`task where completed = false and dueDate <= "{{today}}" order by dueDate desc limit 5`,
|
||||
);
|
||||
assertEquals(parsedQuery1.table, "task");
|
||||
assertEquals(parsedQuery1.orderBy, "dueDate");
|
||||
assertEquals(parsedQuery1.orderDesc, true);
|
||||
assertEquals(parsedQuery1.ordering.length, 1);
|
||||
assertEquals(parsedQuery1.ordering[0].orderBy, "dueDate");
|
||||
assertEquals(parsedQuery1.ordering[0].orderDesc, true);
|
||||
assertEquals(parsedQuery1.limit, 5);
|
||||
assertEquals(parsedQuery1.filter.length, 2);
|
||||
assertEquals(parsedQuery1.filter[0], {
|
||||
|
@ -69,6 +70,7 @@ Deno.test("Test parser", () => {
|
|||
parseQuery(`gh-events where type in ["PushEvent", "somethingElse"]`),
|
||||
{
|
||||
table: "gh-events",
|
||||
ordering: [],
|
||||
filter: [
|
||||
{
|
||||
op: "in",
|
||||
|
@ -81,12 +83,14 @@ Deno.test("Test parser", () => {
|
|||
|
||||
assertEquals(parseQuery(`something render [[template/table]]`), {
|
||||
table: "something",
|
||||
ordering: [],
|
||||
filter: [],
|
||||
render: "template/table",
|
||||
});
|
||||
|
||||
assertEquals(parseQuery(`something render "template/table"`), {
|
||||
table: "something",
|
||||
ordering: [],
|
||||
filter: [],
|
||||
render: "template/table",
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue