Add support for multiple order by (#387)
This commit is contained in:
parent
a28966b410
commit
47acb503cb
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
@ -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",
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user