From 7fe57b4fc410e8e0a03a966bd256f9bc03ad6326 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 13 Mar 2025 12:43:23 +0100 Subject: [PATCH] Revert "Remove unnecessary sortType on api definition" --- packages/frontend-core/src/fetch/DataFetch.ts | 36 +- .../frontend-core/src/fetch/TableFetch.ts | 4 +- .../frontend-core/src/fetch/ViewV2Fetch.ts | 7 +- .../server/src/api/controllers/row/index.ts | 1 + .../server/src/api/controllers/row/views.ts | 2 + .../src/api/routes/tests/search.spec.ts | 525 +++++++++--------- .../src/api/routes/tests/viewV2.spec.ts | 28 +- packages/server/src/sdk/app/rows/search.ts | 1 + .../src/sdk/app/rows/search/internal/sqs.ts | 7 +- packages/shared-core/src/filters.ts | 15 +- packages/shared-core/src/index.ts | 1 - .../src/tests/{cron.spec.ts => cron.test.ts} | 0 .../src/tests/{themes.spec.ts => themes.ts} | 0 packages/types/src/api/web/app/rows/search.ts | 8 +- packages/types/src/sdk/row.ts | 2 +- 15 files changed, 340 insertions(+), 297 deletions(-) rename packages/shared-core/src/tests/{cron.spec.ts => cron.test.ts} (100%) rename packages/shared-core/src/tests/{themes.spec.ts => themes.ts} (100%) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index cbc9972484..298413b1e8 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -8,6 +8,7 @@ import { Row, SearchFilters, SortOrder, + SortType, TableSchema, } from "@budibase/types" import { APIClient } from "../api/types" @@ -71,6 +72,8 @@ export default abstract class BaseDataFetch< options: DataFetchOptions & { datasource: TDatasource + sortType: SortType | null + // Client side feature customisation clientSideSearching: boolean clientSideSorting: boolean @@ -103,6 +106,7 @@ export default abstract class BaseDataFetch< // Sorting config sortColumn: null, sortOrder: SortOrder.ASCENDING, + sortType: null, // Pagination config paginate: true, @@ -223,12 +227,31 @@ export default abstract class BaseDataFetch< this.options.sortColumn = this.getDefaultSortColumn(definition, schema) } - // If no sort order, default to ascending - if (!this.options.sortOrder) { + // If we don't have a sort column specified then just ensure we don't set + // any sorting params + if (!this.options.sortColumn) { this.options.sortOrder = SortOrder.ASCENDING + this.options.sortType = null } else { - // Ensure sortOrder matches the enum - this.options.sortOrder = this.options.sortOrder.toLowerCase() as SortOrder + // Otherwise determine what sort type to use base on sort column + this.options.sortType = SortType.STRING + const fieldSchema = schema?.[this.options.sortColumn] + if ( + fieldSchema?.type === FieldType.NUMBER || + fieldSchema?.type === FieldType.BIGINT || + ("calculationType" in fieldSchema && fieldSchema?.calculationType) + ) { + this.options.sortType = SortType.NUMBER + } + + // If no sort order, default to ascending + if (!this.options.sortOrder) { + this.options.sortOrder = SortOrder.ASCENDING + } else { + // Ensure sortOrder matches the enum + this.options.sortOrder = + this.options.sortOrder.toLowerCase() as SortOrder + } } // Build the query @@ -271,6 +294,7 @@ export default abstract class BaseDataFetch< const { sortColumn, sortOrder, + sortType, limit, clientSideSearching, clientSideSorting, @@ -287,8 +311,8 @@ export default abstract class BaseDataFetch< } // If we don't support sorting, do a client-side sort - if (!this.features.supportsSort && clientSideSorting && sortColumn) { - rows = sort(rows, sortColumn, sortOrder) + if (!this.features.supportsSort && clientSideSorting && sortType) { + rows = sort(rows, sortColumn as any, sortOrder, sortType) } // If we don't support pagination, do a client-side limit diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index 59bfc588f5..a6f92c0ab3 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -29,7 +29,8 @@ export default class TableFetch extends BaseDataFetch { } async getData() { - const { datasource, limit, sortColumn, sortOrder, paginate } = this.options + const { datasource, limit, sortColumn, sortOrder, sortType, paginate } = + this.options const { tableId } = datasource const { cursor, query } = get(this.store) @@ -40,6 +41,7 @@ export default class TableFetch extends BaseDataFetch { limit, sort: sortColumn, sortOrder: sortOrder ?? SortOrder.ASCENDING, + sortType, paginate, bookmark: cursor, }) diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index 4495450a23..fd2eab2d53 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -1,5 +1,4 @@ import { - SearchViewRowRequest, SortOrder, ViewDatasource, ViewV2Enriched, @@ -41,7 +40,8 @@ export default class ViewV2Fetch extends BaseDataFetch< } async getData() { - const { datasource, limit, sortColumn, sortOrder, paginate } = this.options + const { datasource, limit, sortColumn, sortOrder, sortType, paginate } = + this.options const { cursor, query, definition } = get(this.store) // If this is a calculation view and we have no calculations, return nothing @@ -68,13 +68,14 @@ export default class ViewV2Fetch extends BaseDataFetch< } try { - const request: SearchViewRowRequest = { + const request = { query, paginate, limit, bookmark: cursor, sort: sortColumn, sortOrder: sortOrder, + sortType, } if (paginate) { const res = await this.API.viewV2.fetch(datasource.id, { diff --git a/packages/server/src/api/controllers/row/index.ts b/packages/server/src/api/controllers/row/index.ts index 07ed4172ab..8f4629a5b0 100644 --- a/packages/server/src/api/controllers/row/index.ts +++ b/packages/server/src/api/controllers/row/index.ts @@ -263,6 +263,7 @@ export async function search(ctx: Ctx) { limit: searchRequest.limit, sort: searchRequest.sort ?? undefined, sortOrder: searchRequest.sortOrder, + sortType: searchRequest.sortType ?? undefined, countRows: searchRequest.countRows, version: searchRequest.version, disableEscaping: searchRequest.disableEscaping, diff --git a/packages/server/src/api/controllers/row/views.ts b/packages/server/src/api/controllers/row/views.ts index 78931c5d4d..418aa462c4 100644 --- a/packages/server/src/api/controllers/row/views.ts +++ b/packages/server/src/api/controllers/row/views.ts @@ -63,12 +63,14 @@ function getSortOptions(request: SearchViewRowRequest, view: ViewV2) { return { sort: request.sort, sortOrder: request.sortOrder, + sortType: request.sortType ?? undefined, } } if (view.sort) { return { sort: view.sort.field, sortOrder: view.sort.order, + sortType: view.sort.type, } } diff --git a/packages/server/src/api/routes/tests/search.spec.ts b/packages/server/src/api/routes/tests/search.spec.ts index cf7c7cf9fa..e115297ee9 100644 --- a/packages/server/src/api/routes/tests/search.spec.ts +++ b/packages/server/src/api/routes/tests/search.spec.ts @@ -38,7 +38,7 @@ import { import _ from "lodash" import tk from "timekeeper" import { encodeJSBinding } from "@budibase/string-templates" -import { dataFilters, InMemorySearchQuery } from "@budibase/shared-core" +import { dataFilters } from "@budibase/shared-core" import { Knex } from "knex" import { generator, structures, mocks } from "@budibase/backend-core/tests" import { DEFAULT_EMPLOYEE_TABLE_SCHEMA } from "../../../db/defaultData/datasource_bb_default" @@ -200,26 +200,31 @@ if (descriptions.length) { const isView = sourceType === "view" class SearchAssertion { - constructor( - private readonly query: SearchRowRequest & { - sortType?: SortType - } - ) {} + constructor(private readonly query: SearchRowRequest) {} private async performSearch(): Promise> { if (isInMemory) { - const inMemoryQuery: RequiredKeys = { + const inMemoryQuery: RequiredKeys< + Omit + > = { sort: this.query.sort ?? undefined, query: { ...this.query.query }, + paginate: this.query.paginate, + bookmark: this.query.bookmark ?? undefined, limit: this.query.limit, sortOrder: this.query.sortOrder, sortType: this.query.sortType ?? undefined, + version: this.query.version, + disableEscaping: this.query.disableEscaping, countRows: this.query.countRows, + viewId: undefined, + fields: undefined, + indexer: undefined, + rows: undefined, } return dataFilters.search(_.cloneDeep(rows), inMemoryQuery) } else { - const { sortType, ...query } = this.query - return config.api.row.search(tableOrViewId, query) + return config.api.row.search(tableOrViewId, this.query) } } @@ -395,9 +400,7 @@ if (descriptions.length) { } } - function expectSearch( - query: SearchRowRequest & { sortType?: SortType } - ) { + function expectSearch(query: SearchRowRequest) { return new SearchAssertion(query) } @@ -1116,27 +1119,26 @@ if (descriptions.length) { }).toMatchExactly([{ name: "foo" }, { name: "bar" }]) }) - isInMemory && - describe("sortType STRING", () => { - it("sorts ascending", async () => { - await expectSearch({ - query: {}, - sort: "name", - sortType: SortType.STRING, - sortOrder: SortOrder.ASCENDING, - }).toMatchExactly([{ name: "bar" }, { name: "foo" }]) - }) - - it("sorts descending", async () => { - await expectSearch({ - query: {}, - sort: "name", - sortType: SortType.STRING, - sortOrder: SortOrder.DESCENDING, - }).toMatchExactly([{ name: "foo" }, { name: "bar" }]) - }) + describe("sortType STRING", () => { + it("sorts ascending", async () => { + await expectSearch({ + query: {}, + sort: "name", + sortType: SortType.STRING, + sortOrder: SortOrder.ASCENDING, + }).toMatchExactly([{ name: "bar" }, { name: "foo" }]) }) + it("sorts descending", async () => { + await expectSearch({ + query: {}, + sort: "name", + sortType: SortType.STRING, + sortOrder: SortOrder.DESCENDING, + }).toMatchExactly([{ name: "foo" }, { name: "bar" }]) + }) + }) + !isInternal && !isInMemory && // This test was added because we automatically add in a sort by the @@ -1317,26 +1319,25 @@ if (descriptions.length) { }) }) - isInMemory && - describe("sortType NUMBER", () => { - it("sorts ascending", async () => { - await expectSearch({ - query: {}, - sort: "age", - sortType: SortType.NUMBER, - sortOrder: SortOrder.ASCENDING, - }).toMatchExactly([{ age: 1 }, { age: 10 }]) - }) - - it("sorts descending", async () => { - await expectSearch({ - query: {}, - sort: "age", - sortType: SortType.NUMBER, - sortOrder: SortOrder.DESCENDING, - }).toMatchExactly([{ age: 10 }, { age: 1 }]) - }) + describe("sortType NUMBER", () => { + it("sorts ascending", async () => { + await expectSearch({ + query: {}, + sort: "age", + sortType: SortType.NUMBER, + sortOrder: SortOrder.ASCENDING, + }).toMatchExactly([{ age: 1 }, { age: 10 }]) }) + + it("sorts descending", async () => { + await expectSearch({ + query: {}, + sort: "age", + sortType: SortType.NUMBER, + sortOrder: SortOrder.DESCENDING, + }).toMatchExactly([{ age: 10 }, { age: 1 }]) + }) + }) }) describe("dates", () => { @@ -1472,26 +1473,25 @@ if (descriptions.length) { }).toMatchExactly([{ dob: JAN_10TH }, { dob: JAN_1ST }]) }) - isInMemory && - describe("sortType STRING", () => { - it("sorts ascending", async () => { - await expectSearch({ - query: {}, - sort: "dob", - sortType: SortType.STRING, - sortOrder: SortOrder.ASCENDING, - }).toMatchExactly([{ dob: JAN_1ST }, { dob: JAN_10TH }]) - }) - - it("sorts descending", async () => { - await expectSearch({ - query: {}, - sort: "dob", - sortType: SortType.STRING, - sortOrder: SortOrder.DESCENDING, - }).toMatchExactly([{ dob: JAN_10TH }, { dob: JAN_1ST }]) - }) + describe("sortType STRING", () => { + it("sorts ascending", async () => { + await expectSearch({ + query: {}, + sort: "dob", + sortType: SortType.STRING, + sortOrder: SortOrder.ASCENDING, + }).toMatchExactly([{ dob: JAN_1ST }, { dob: JAN_10TH }]) }) + + it("sorts descending", async () => { + await expectSearch({ + query: {}, + sort: "dob", + sortType: SortType.STRING, + sortOrder: SortOrder.DESCENDING, + }).toMatchExactly([{ dob: JAN_10TH }, { dob: JAN_1ST }]) + }) + }) }) }) @@ -1639,196 +1639,220 @@ if (descriptions.length) { ]) }) - isInMemory && - describe("sortType STRING", () => { - it("sorts ascending", async () => { - await expectSearch({ - query: {}, - sort: "time", - sortType: SortType.STRING, - sortOrder: SortOrder.ASCENDING, - }).toMatchExactly([ - { timeid: NULL_TIME__ID }, - { time: "00:00:00" }, - { time: "10:00:00" }, - { time: "10:45:00" }, - { time: "12:00:00" }, - { time: "15:30:00" }, - ]) - }) - - it("sorts descending", async () => { - await expectSearch({ - query: {}, - sort: "time", - sortType: SortType.STRING, - sortOrder: SortOrder.DESCENDING, - }).toMatchExactly([ - { time: "15:30:00" }, - { time: "12:00:00" }, - { time: "10:45:00" }, - { time: "10:00:00" }, - { time: "00:00:00" }, - { timeid: NULL_TIME__ID }, - ]) - }) + describe("sortType STRING", () => { + it("sorts ascending", async () => { + await expectSearch({ + query: {}, + sort: "time", + sortType: SortType.STRING, + sortOrder: SortOrder.ASCENDING, + }).toMatchExactly([ + { timeid: NULL_TIME__ID }, + { time: "00:00:00" }, + { time: "10:00:00" }, + { time: "10:45:00" }, + { time: "12:00:00" }, + { time: "15:30:00" }, + ]) }) + + it("sorts descending", async () => { + await expectSearch({ + query: {}, + sort: "time", + sortType: SortType.STRING, + sortOrder: SortOrder.DESCENDING, + }).toMatchExactly([ + { time: "15:30:00" }, + { time: "12:00:00" }, + { time: "10:45:00" }, + { time: "10:00:00" }, + { time: "00:00:00" }, + { timeid: NULL_TIME__ID }, + ]) + }) + }) }) }) - !isInMemory && - describe("datetime - date only", () => { - describe.each([true, false])( - "saved with timestamp: %s", - saveWithTimestamp => { - describe.each([true, false])( - "search with timestamp: %s", - searchWithTimestamp => { - const SAVE_SUFFIX = saveWithTimestamp - ? "T00:00:00.000Z" - : "" - const SEARCH_SUFFIX = searchWithTimestamp - ? "T00:00:00.000Z" - : "" + describe("datetime - date only", () => { + describe.each([true, false])( + "saved with timestamp: %s", + saveWithTimestamp => { + describe.each([true, false])( + "search with timestamp: %s", + searchWithTimestamp => { + const SAVE_SUFFIX = saveWithTimestamp + ? "T00:00:00.000Z" + : "" + const SEARCH_SUFFIX = searchWithTimestamp + ? "T00:00:00.000Z" + : "" - const JAN_1ST = `2020-01-01` - const JAN_10TH = `2020-01-10` - const JAN_30TH = `2020-01-30` - const UNEXISTING_DATE = `2020-01-03` - const NULL_DATE__ID = `null_date__id` + const JAN_1ST = `2020-01-01` + const JAN_10TH = `2020-01-10` + const JAN_30TH = `2020-01-30` + const UNEXISTING_DATE = `2020-01-03` + const NULL_DATE__ID = `null_date__id` - beforeAll(async () => { - tableOrViewId = await createTableOrView({ - dateid: { - name: "dateid", - type: FieldType.STRING, + beforeAll(async () => { + tableOrViewId = await createTableOrView({ + dateid: { + name: "dateid", + type: FieldType.STRING, + }, + date: { + name: "date", + type: FieldType.DATETIME, + dateOnly: true, + }, + }) + + await createRows([ + { dateid: NULL_DATE__ID, date: null }, + { date: `${JAN_1ST}${SAVE_SUFFIX}` }, + { date: `${JAN_10TH}${SAVE_SUFFIX}` }, + ]) + }) + + describe("equal", () => { + it("successfully finds a row", async () => { + await expectQuery({ + equal: { date: `${JAN_1ST}${SEARCH_SUFFIX}` }, + }).toContainExactly([{ date: JAN_1ST }]) + }) + + it("successfully finds an ISO8601 row", async () => { + await expectQuery({ + equal: { date: `${JAN_10TH}${SEARCH_SUFFIX}` }, + }).toContainExactly([{ date: JAN_10TH }]) + }) + + it("finds a row with ISO8601 timestamp", async () => { + await expectQuery({ + equal: { date: `${JAN_1ST}${SEARCH_SUFFIX}` }, + }).toContainExactly([{ date: JAN_1ST }]) + }) + + it("fails to find nonexistent row", async () => { + await expectQuery({ + equal: { + date: `${UNEXISTING_DATE}${SEARCH_SUFFIX}`, }, - date: { - name: "date", - type: FieldType.DATETIME, - dateOnly: true, - }, - }) + }).toFindNothing() + }) + }) - await createRows([ - { dateid: NULL_DATE__ID, date: null }, - { date: `${JAN_1ST}${SAVE_SUFFIX}` }, - { date: `${JAN_10TH}${SAVE_SUFFIX}` }, + describe("notEqual", () => { + it("successfully finds a row", async () => { + await expectQuery({ + notEqual: { + date: `${JAN_1ST}${SEARCH_SUFFIX}`, + }, + }).toContainExactly([ + { date: JAN_10TH }, + { dateid: NULL_DATE__ID }, ]) }) - describe("equal", () => { - it("successfully finds a row", async () => { - await expectQuery({ - equal: { date: `${JAN_1ST}${SEARCH_SUFFIX}` }, - }).toContainExactly([{ date: JAN_1ST }]) - }) + it("fails to find nonexistent row", async () => { + await expectQuery({ + notEqual: { + date: `${JAN_30TH}${SEARCH_SUFFIX}`, + }, + }).toContainExactly([ + { date: JAN_1ST }, + { date: JAN_10TH }, + { dateid: NULL_DATE__ID }, + ]) + }) + }) - it("successfully finds an ISO8601 row", async () => { - await expectQuery({ - equal: { date: `${JAN_10TH}${SEARCH_SUFFIX}` }, - }).toContainExactly([{ date: JAN_10TH }]) - }) - - it("finds a row with ISO8601 timestamp", async () => { - await expectQuery({ - equal: { date: `${JAN_1ST}${SEARCH_SUFFIX}` }, - }).toContainExactly([{ date: JAN_1ST }]) - }) - - it("fails to find nonexistent row", async () => { - await expectQuery({ - equal: { - date: `${UNEXISTING_DATE}${SEARCH_SUFFIX}`, - }, - }).toFindNothing() - }) + describe("oneOf", () => { + it("successfully finds a row", async () => { + await expectQuery({ + oneOf: { date: [`${JAN_1ST}${SEARCH_SUFFIX}`] }, + }).toContainExactly([{ date: JAN_1ST }]) }) - describe("notEqual", () => { - it("successfully finds a row", async () => { - await expectQuery({ - notEqual: { - date: `${JAN_1ST}${SEARCH_SUFFIX}`, - }, - }).toContainExactly([ - { date: JAN_10TH }, - { dateid: NULL_DATE__ID }, - ]) - }) + it("fails to find nonexistent row", async () => { + await expectQuery({ + oneOf: { + date: [`${UNEXISTING_DATE}${SEARCH_SUFFIX}`], + }, + }).toFindNothing() + }) + }) - it("fails to find nonexistent row", async () => { - await expectQuery({ - notEqual: { - date: `${JAN_30TH}${SEARCH_SUFFIX}`, + describe("range", () => { + it("successfully finds a row", async () => { + await expectQuery({ + range: { + date: { + low: `${JAN_1ST}${SEARCH_SUFFIX}`, + high: `${JAN_1ST}${SEARCH_SUFFIX}`, }, - }).toContainExactly([ - { date: JAN_1ST }, - { date: JAN_10TH }, - { dateid: NULL_DATE__ID }, - ]) - }) + }, + }).toContainExactly([{ date: JAN_1ST }]) }) - describe("oneOf", () => { - it("successfully finds a row", async () => { - await expectQuery({ - oneOf: { date: [`${JAN_1ST}${SEARCH_SUFFIX}`] }, - }).toContainExactly([{ date: JAN_1ST }]) - }) - - it("fails to find nonexistent row", async () => { - await expectQuery({ - oneOf: { - date: [`${UNEXISTING_DATE}${SEARCH_SUFFIX}`], + it("successfully finds multiple rows", async () => { + await expectQuery({ + range: { + date: { + low: `${JAN_1ST}${SEARCH_SUFFIX}`, + high: `${JAN_10TH}${SEARCH_SUFFIX}`, }, - }).toFindNothing() - }) + }, + }).toContainExactly([ + { date: JAN_1ST }, + { date: JAN_10TH }, + ]) }) - describe("range", () => { - it("successfully finds a row", async () => { - await expectQuery({ - range: { - date: { - low: `${JAN_1ST}${SEARCH_SUFFIX}`, - high: `${JAN_1ST}${SEARCH_SUFFIX}`, - }, + it("successfully finds no rows", async () => { + await expectQuery({ + range: { + date: { + low: `${JAN_30TH}${SEARCH_SUFFIX}`, + high: `${JAN_30TH}${SEARCH_SUFFIX}`, }, - }).toContainExactly([{ date: JAN_1ST }]) - }) + }, + }).toFindNothing() + }) + }) - it("successfully finds multiple rows", async () => { - await expectQuery({ - range: { - date: { - low: `${JAN_1ST}${SEARCH_SUFFIX}`, - high: `${JAN_10TH}${SEARCH_SUFFIX}`, - }, - }, - }).toContainExactly([ - { date: JAN_1ST }, - { date: JAN_10TH }, - ]) - }) - - it("successfully finds no rows", async () => { - await expectQuery({ - range: { - date: { - low: `${JAN_30TH}${SEARCH_SUFFIX}`, - high: `${JAN_30TH}${SEARCH_SUFFIX}`, - }, - }, - }).toFindNothing() - }) + describe("sort", () => { + it("sorts ascending", async () => { + await expectSearch({ + query: {}, + sort: "date", + sortOrder: SortOrder.ASCENDING, + }).toMatchExactly([ + { dateid: NULL_DATE__ID }, + { date: JAN_1ST }, + { date: JAN_10TH }, + ]) }) - describe("sort", () => { + it("sorts descending", async () => { + await expectSearch({ + query: {}, + sort: "date", + sortOrder: SortOrder.DESCENDING, + }).toMatchExactly([ + { date: JAN_10TH }, + { date: JAN_1ST }, + { dateid: NULL_DATE__ID }, + ]) + }) + + describe("sortType STRING", () => { it("sorts ascending", async () => { await expectSearch({ query: {}, sort: "date", + sortType: SortType.STRING, sortOrder: SortOrder.ASCENDING, }).toMatchExactly([ { dateid: NULL_DATE__ID }, @@ -1841,6 +1865,7 @@ if (descriptions.length) { await expectSearch({ query: {}, sort: "date", + sortType: SortType.STRING, sortOrder: SortOrder.DESCENDING, }).toMatchExactly([ { date: JAN_10TH }, @@ -1848,41 +1873,13 @@ if (descriptions.length) { { dateid: NULL_DATE__ID }, ]) }) - - isInMemory && - describe("sortType STRING", () => { - it("sorts ascending", async () => { - await expectSearch({ - query: {}, - sort: "date", - sortType: SortType.STRING, - sortOrder: SortOrder.ASCENDING, - }).toMatchExactly([ - { dateid: NULL_DATE__ID }, - { date: JAN_1ST }, - { date: JAN_10TH }, - ]) - }) - - it("sorts descending", async () => { - await expectSearch({ - query: {}, - sort: "date", - sortType: SortType.STRING, - sortOrder: SortOrder.DESCENDING, - }).toMatchExactly([ - { date: JAN_10TH }, - { date: JAN_1ST }, - { dateid: NULL_DATE__ID }, - ]) - }) - }) }) - } - ) - } - ) - }) + }) + } + ) + } + ) + }) isInternal && !isInMemory && diff --git a/packages/server/src/api/routes/tests/viewV2.spec.ts b/packages/server/src/api/routes/tests/viewV2.spec.ts index 3f1bb43016..ad41aa618c 100644 --- a/packages/server/src/api/routes/tests/viewV2.spec.ts +++ b/packages/server/src/api/routes/tests/viewV2.spec.ts @@ -24,6 +24,7 @@ import { SearchResponse, SearchViewRowRequest, SortOrder, + SortType, StaticQuotaName, Table, TableSchema, @@ -153,6 +154,7 @@ if (descriptions.length) { sort: { field: "fieldToSort", order: SortOrder.DESCENDING, + type: SortType.STRING, }, schema: { id: { visible: true }, @@ -215,6 +217,7 @@ if (descriptions.length) { sort: { field: "fieldToSort", order: SortOrder.DESCENDING, + type: SortType.STRING, }, schema: { id: { visible: true }, @@ -1144,6 +1147,7 @@ if (descriptions.length) { sort: { field: generator.word(), order: SortOrder.DESCENDING, + type: SortType.STRING, }, schema: { id: { visible: true }, @@ -3149,6 +3153,7 @@ if (descriptions.length) { { field: string order?: SortOrder + type?: SortType }, string[] ][] = [ @@ -3156,6 +3161,7 @@ if (descriptions.length) { { field: "name", order: SortOrder.ASCENDING, + type: SortType.STRING, }, ["Alice", "Bob", "Charly", "Danny"], ], @@ -3172,6 +3178,22 @@ if (descriptions.length) { }, ["Danny", "Charly", "Bob", "Alice"], ], + [ + { + field: "name", + order: SortOrder.DESCENDING, + type: SortType.STRING, + }, + ["Danny", "Charly", "Bob", "Alice"], + ], + [ + { + field: "age", + order: SortOrder.ASCENDING, + type: SortType.NUMBER, + }, + ["Danny", "Alice", "Charly", "Bob"], + ], [ { field: "age", @@ -3182,13 +3204,15 @@ if (descriptions.length) { [ { field: "age", + order: SortOrder.DESCENDING, }, - ["Danny", "Alice", "Charly", "Bob"], + ["Bob", "Charly", "Alice", "Danny"], ], [ { field: "age", order: SortOrder.DESCENDING, + type: SortType.NUMBER, }, ["Bob", "Charly", "Alice", "Danny"], ], @@ -3275,6 +3299,7 @@ if (descriptions.length) { sort: { field: "name", order: SortOrder.ASCENDING, + type: SortType.STRING, }, schema: viewSchema, }) @@ -3282,6 +3307,7 @@ if (descriptions.length) { const response = await config.api.viewV2.search(view.id, { sort: sortParams.field, sortOrder: sortParams.order, + sortType: sortParams.type, query: {}, }) diff --git a/packages/server/src/sdk/app/rows/search.ts b/packages/server/src/sdk/app/rows/search.ts index 8de46dc9fe..3a582a46ea 100644 --- a/packages/server/src/sdk/app/rows/search.ts +++ b/packages/server/src/sdk/app/rows/search.ts @@ -46,6 +46,7 @@ export async function search( query: options.query, sort: options.sort, sortOrder: options.sortOrder, + sortType: options.sortType, limit: options.limit, bookmark: options.bookmark, paginate: options.paginate, diff --git a/packages/server/src/sdk/app/rows/search/internal/sqs.ts b/packages/server/src/sdk/app/rows/search/internal/sqs.ts index 76b496f92a..84162a67af 100644 --- a/packages/server/src/sdk/app/rows/search/internal/sqs.ts +++ b/packages/server/src/sdk/app/rows/search/internal/sqs.ts @@ -1,6 +1,5 @@ import { Aggregation, - AutoFieldSubType, CalculationType, DocumentType, EnrichedQueryJson, @@ -421,11 +420,7 @@ export async function search( } } else if (sortField) { const sortType = - sortField.type === FieldType.NUMBER || - (sortField.type === FieldType.AUTO && - sortField.subtype === AutoFieldSubType.AUTO_ID) - ? SortType.NUMBER - : SortType.STRING + sortField.type === FieldType.NUMBER ? SortType.NUMBER : SortType.STRING request.sort = { [mapToUserColumn(sortField.name)]: { direction: params.sortOrder || SortOrder.ASCENDING, diff --git a/packages/shared-core/src/filters.ts b/packages/shared-core/src/filters.ts index 5da5c34a4f..afe99d9565 100644 --- a/packages/shared-core/src/filters.ts +++ b/packages/shared-core/src/filters.ts @@ -11,6 +11,7 @@ import { SortType, FieldConstraints, SortOrder, + RowSearchParams, EmptyFilterOption, SearchResponse, Table, @@ -24,8 +25,6 @@ import { isArraySearchOperator, isRangeSearchOperator, SearchFilter, - WithRequired, - SearchParams, } from "@budibase/types" import dayjs from "dayjs" import { OperatorOptions, SqlNumberTypeRangeMap } from "./constants" @@ -522,19 +521,9 @@ export function fixupFilterArrays(filters: SearchFilters) { return filters } -type SearchQuery = WithRequired< - Pick< - SearchParams, - "query" | "sort" | "sortOrder" | "sortType" | "limit" | "countRows" - >, - "query" -> - -export type InMemorySearchQuery = SearchQuery - export function search>( docs: T[], - query: SearchQuery + query: Omit ): SearchResponse { let result = runQuery(docs, query.query) if (query.sort) { diff --git a/packages/shared-core/src/index.ts b/packages/shared-core/src/index.ts index daf4601c03..a4f4208f4a 100644 --- a/packages/shared-core/src/index.ts +++ b/packages/shared-core/src/index.ts @@ -1,6 +1,5 @@ export * from "./constants" export * as dataFilters from "./filters" -export type * from "./filters" export * as helpers from "./helpers" export * as utils from "./utils" export * as sdk from "./sdk" diff --git a/packages/shared-core/src/tests/cron.spec.ts b/packages/shared-core/src/tests/cron.test.ts similarity index 100% rename from packages/shared-core/src/tests/cron.spec.ts rename to packages/shared-core/src/tests/cron.test.ts diff --git a/packages/shared-core/src/tests/themes.spec.ts b/packages/shared-core/src/tests/themes.ts similarity index 100% rename from packages/shared-core/src/tests/themes.spec.ts rename to packages/shared-core/src/tests/themes.ts diff --git a/packages/types/src/api/web/app/rows/search.ts b/packages/types/src/api/web/app/rows/search.ts index 4d903d44b6..7ba23bceca 100644 --- a/packages/types/src/api/web/app/rows/search.ts +++ b/packages/types/src/api/web/app/rows/search.ts @@ -8,7 +8,11 @@ import { SearchFilterKey, } from "../../../../sdk" import { Row } from "../../../../documents" -import { PaginationResponse, SortOrder } from "../../../../api/web/pagination" +import { + PaginationResponse, + SortOrder, + SortType, +} from "../../../../api/web/pagination" import { z } from "zod" const fieldKey = z @@ -66,6 +70,7 @@ const searchRowRequest = z.object({ limit: z.number().optional(), sort: z.string().nullish(), sortOrder: z.nativeEnum(SortOrder).optional(), + sortType: z.nativeEnum(SortType).nullish(), version: z.string().optional(), disableEscaping: z.boolean().optional(), countRows: z.boolean().optional(), @@ -78,6 +83,7 @@ export type SearchViewRowRequest = Pick< SearchRowRequest, | "sort" | "sortOrder" + | "sortType" | "limit" | "bookmark" | "paginate" diff --git a/packages/types/src/sdk/row.ts b/packages/types/src/sdk/row.ts index da5eb0b041..6328a80ba1 100644 --- a/packages/types/src/sdk/row.ts +++ b/packages/types/src/sdk/row.ts @@ -50,7 +50,7 @@ export interface SearchParams { // when searching for rows we want a more extensive search type that requires certain properties export interface RowSearchParams - extends WithRequired, "tableId" | "query"> {} + extends WithRequired {} export interface SearchResponse { rows: T[]