Merge branch 'master' into default-app-design
This commit is contained in:
commit
52ee07d152
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||||
"version": "3.5.2",
|
"version": "3.5.3",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"concurrency": 20,
|
"concurrency": 20,
|
||||||
"command": {
|
"command": {
|
||||||
|
|
|
@ -147,9 +147,7 @@ export class FlagSet<T extends { [name: string]: boolean }> {
|
||||||
|
|
||||||
for (const [name, value] of Object.entries(posthogFlags)) {
|
for (const [name, value] of Object.entries(posthogFlags)) {
|
||||||
if (!this.isFlagName(name)) {
|
if (!this.isFlagName(name)) {
|
||||||
// We don't want an unexpected PostHog flag to break the app, so we
|
// We don't want an unexpected PostHog flag to break the app
|
||||||
// just log it and continue.
|
|
||||||
console.warn(`Unexpected posthog flag "${name}": ${value}`)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
Row,
|
Row,
|
||||||
SearchFilters,
|
SearchFilters,
|
||||||
SortOrder,
|
SortOrder,
|
||||||
|
SortType,
|
||||||
TableSchema,
|
TableSchema,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { APIClient } from "../api/types"
|
import { APIClient } from "../api/types"
|
||||||
|
@ -71,6 +72,8 @@ export default abstract class BaseDataFetch<
|
||||||
options: DataFetchOptions<TQuery> & {
|
options: DataFetchOptions<TQuery> & {
|
||||||
datasource: TDatasource
|
datasource: TDatasource
|
||||||
|
|
||||||
|
sortType: SortType | null
|
||||||
|
|
||||||
// Client side feature customisation
|
// Client side feature customisation
|
||||||
clientSideSearching: boolean
|
clientSideSearching: boolean
|
||||||
clientSideSorting: boolean
|
clientSideSorting: boolean
|
||||||
|
@ -103,6 +106,7 @@ export default abstract class BaseDataFetch<
|
||||||
// Sorting config
|
// Sorting config
|
||||||
sortColumn: null,
|
sortColumn: null,
|
||||||
sortOrder: SortOrder.ASCENDING,
|
sortOrder: SortOrder.ASCENDING,
|
||||||
|
sortType: null,
|
||||||
|
|
||||||
// Pagination config
|
// Pagination config
|
||||||
paginate: true,
|
paginate: true,
|
||||||
|
@ -223,12 +227,31 @@ export default abstract class BaseDataFetch<
|
||||||
this.options.sortColumn = this.getDefaultSortColumn(definition, schema)
|
this.options.sortColumn = this.getDefaultSortColumn(definition, schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no sort order, default to ascending
|
// If we don't have a sort column specified then just ensure we don't set
|
||||||
if (!this.options.sortOrder) {
|
// any sorting params
|
||||||
|
if (!this.options.sortColumn) {
|
||||||
this.options.sortOrder = SortOrder.ASCENDING
|
this.options.sortOrder = SortOrder.ASCENDING
|
||||||
|
this.options.sortType = null
|
||||||
} else {
|
} else {
|
||||||
// Ensure sortOrder matches the enum
|
// Otherwise determine what sort type to use base on sort column
|
||||||
this.options.sortOrder = this.options.sortOrder.toLowerCase() as SortOrder
|
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
|
// Build the query
|
||||||
|
@ -271,6 +294,7 @@ export default abstract class BaseDataFetch<
|
||||||
const {
|
const {
|
||||||
sortColumn,
|
sortColumn,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
|
sortType,
|
||||||
limit,
|
limit,
|
||||||
clientSideSearching,
|
clientSideSearching,
|
||||||
clientSideSorting,
|
clientSideSorting,
|
||||||
|
@ -287,8 +311,8 @@ export default abstract class BaseDataFetch<
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't support sorting, do a client-side sort
|
// If we don't support sorting, do a client-side sort
|
||||||
if (!this.features.supportsSort && clientSideSorting && sortColumn) {
|
if (!this.features.supportsSort && clientSideSorting && sortType) {
|
||||||
rows = sort(rows, sortColumn, sortOrder)
|
rows = sort(rows, sortColumn as any, sortOrder, sortType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't support pagination, do a client-side limit
|
// If we don't support pagination, do a client-side limit
|
||||||
|
|
|
@ -29,7 +29,8 @@ export default class TableFetch extends BaseDataFetch<TableDatasource, Table> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getData() {
|
async getData() {
|
||||||
const { datasource, limit, sortColumn, sortOrder, paginate } = this.options
|
const { datasource, limit, sortColumn, sortOrder, sortType, paginate } =
|
||||||
|
this.options
|
||||||
const { tableId } = datasource
|
const { tableId } = datasource
|
||||||
const { cursor, query } = get(this.store)
|
const { cursor, query } = get(this.store)
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ export default class TableFetch extends BaseDataFetch<TableDatasource, Table> {
|
||||||
limit,
|
limit,
|
||||||
sort: sortColumn,
|
sort: sortColumn,
|
||||||
sortOrder: sortOrder ?? SortOrder.ASCENDING,
|
sortOrder: sortOrder ?? SortOrder.ASCENDING,
|
||||||
|
sortType,
|
||||||
paginate,
|
paginate,
|
||||||
bookmark: cursor,
|
bookmark: cursor,
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import {
|
import {
|
||||||
SearchViewRowRequest,
|
|
||||||
SortOrder,
|
SortOrder,
|
||||||
ViewDatasource,
|
ViewDatasource,
|
||||||
ViewV2Enriched,
|
ViewV2Enriched,
|
||||||
|
@ -41,7 +40,8 @@ export default class ViewV2Fetch extends BaseDataFetch<
|
||||||
}
|
}
|
||||||
|
|
||||||
async getData() {
|
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)
|
const { cursor, query, definition } = get(this.store)
|
||||||
|
|
||||||
// If this is a calculation view and we have no calculations, return nothing
|
// If this is a calculation view and we have no calculations, return nothing
|
||||||
|
@ -68,13 +68,14 @@ export default class ViewV2Fetch extends BaseDataFetch<
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const request: SearchViewRowRequest = {
|
const request = {
|
||||||
query,
|
query,
|
||||||
paginate,
|
paginate,
|
||||||
limit,
|
limit,
|
||||||
bookmark: cursor,
|
bookmark: cursor,
|
||||||
sort: sortColumn,
|
sort: sortColumn,
|
||||||
sortOrder: sortOrder,
|
sortOrder: sortOrder,
|
||||||
|
sortType,
|
||||||
}
|
}
|
||||||
if (paginate) {
|
if (paginate) {
|
||||||
const res = await this.API.viewV2.fetch(datasource.id, {
|
const res = await this.API.viewV2.fetch(datasource.id, {
|
||||||
|
|
|
@ -263,6 +263,7 @@ export async function search(ctx: Ctx<SearchRowRequest, SearchRowResponse>) {
|
||||||
limit: searchRequest.limit,
|
limit: searchRequest.limit,
|
||||||
sort: searchRequest.sort ?? undefined,
|
sort: searchRequest.sort ?? undefined,
|
||||||
sortOrder: searchRequest.sortOrder,
|
sortOrder: searchRequest.sortOrder,
|
||||||
|
sortType: searchRequest.sortType ?? undefined,
|
||||||
countRows: searchRequest.countRows,
|
countRows: searchRequest.countRows,
|
||||||
version: searchRequest.version,
|
version: searchRequest.version,
|
||||||
disableEscaping: searchRequest.disableEscaping,
|
disableEscaping: searchRequest.disableEscaping,
|
||||||
|
|
|
@ -63,12 +63,14 @@ function getSortOptions(request: SearchViewRowRequest, view: ViewV2) {
|
||||||
return {
|
return {
|
||||||
sort: request.sort,
|
sort: request.sort,
|
||||||
sortOrder: request.sortOrder,
|
sortOrder: request.sortOrder,
|
||||||
|
sortType: request.sortType ?? undefined,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (view.sort) {
|
if (view.sort) {
|
||||||
return {
|
return {
|
||||||
sort: view.sort.field,
|
sort: view.sort.field,
|
||||||
sortOrder: view.sort.order,
|
sortOrder: view.sort.order,
|
||||||
|
sortType: view.sort.type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ import {
|
||||||
import _ from "lodash"
|
import _ from "lodash"
|
||||||
import tk from "timekeeper"
|
import tk from "timekeeper"
|
||||||
import { encodeJSBinding } from "@budibase/string-templates"
|
import { encodeJSBinding } from "@budibase/string-templates"
|
||||||
import { dataFilters, InMemorySearchQuery } from "@budibase/shared-core"
|
import { dataFilters } from "@budibase/shared-core"
|
||||||
import { Knex } from "knex"
|
import { Knex } from "knex"
|
||||||
import { generator, structures, mocks } from "@budibase/backend-core/tests"
|
import { generator, structures, mocks } from "@budibase/backend-core/tests"
|
||||||
import { DEFAULT_EMPLOYEE_TABLE_SCHEMA } from "../../../db/defaultData/datasource_bb_default"
|
import { DEFAULT_EMPLOYEE_TABLE_SCHEMA } from "../../../db/defaultData/datasource_bb_default"
|
||||||
|
@ -200,26 +200,31 @@ if (descriptions.length) {
|
||||||
const isView = sourceType === "view"
|
const isView = sourceType === "view"
|
||||||
|
|
||||||
class SearchAssertion {
|
class SearchAssertion {
|
||||||
constructor(
|
constructor(private readonly query: SearchRowRequest) {}
|
||||||
private readonly query: SearchRowRequest & {
|
|
||||||
sortType?: SortType
|
|
||||||
}
|
|
||||||
) {}
|
|
||||||
|
|
||||||
private async performSearch(): Promise<SearchResponse<Row>> {
|
private async performSearch(): Promise<SearchResponse<Row>> {
|
||||||
if (isInMemory) {
|
if (isInMemory) {
|
||||||
const inMemoryQuery: RequiredKeys<InMemorySearchQuery> = {
|
const inMemoryQuery: RequiredKeys<
|
||||||
|
Omit<RowSearchParams, "tableId">
|
||||||
|
> = {
|
||||||
sort: this.query.sort ?? undefined,
|
sort: this.query.sort ?? undefined,
|
||||||
query: { ...this.query.query },
|
query: { ...this.query.query },
|
||||||
|
paginate: this.query.paginate,
|
||||||
|
bookmark: this.query.bookmark ?? undefined,
|
||||||
limit: this.query.limit,
|
limit: this.query.limit,
|
||||||
sortOrder: this.query.sortOrder,
|
sortOrder: this.query.sortOrder,
|
||||||
sortType: this.query.sortType ?? undefined,
|
sortType: this.query.sortType ?? undefined,
|
||||||
|
version: this.query.version,
|
||||||
|
disableEscaping: this.query.disableEscaping,
|
||||||
countRows: this.query.countRows,
|
countRows: this.query.countRows,
|
||||||
|
viewId: undefined,
|
||||||
|
fields: undefined,
|
||||||
|
indexer: undefined,
|
||||||
|
rows: undefined,
|
||||||
}
|
}
|
||||||
return dataFilters.search(_.cloneDeep(rows), inMemoryQuery)
|
return dataFilters.search(_.cloneDeep(rows), inMemoryQuery)
|
||||||
} else {
|
} else {
|
||||||
const { sortType, ...query } = this.query
|
return config.api.row.search(tableOrViewId, this.query)
|
||||||
return config.api.row.search(tableOrViewId, query)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,9 +400,7 @@ if (descriptions.length) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectSearch(
|
function expectSearch(query: SearchRowRequest) {
|
||||||
query: SearchRowRequest & { sortType?: SortType }
|
|
||||||
) {
|
|
||||||
return new SearchAssertion(query)
|
return new SearchAssertion(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1116,27 +1119,26 @@ if (descriptions.length) {
|
||||||
}).toMatchExactly([{ name: "foo" }, { name: "bar" }])
|
}).toMatchExactly([{ name: "foo" }, { name: "bar" }])
|
||||||
})
|
})
|
||||||
|
|
||||||
isInMemory &&
|
describe("sortType STRING", () => {
|
||||||
describe("sortType STRING", () => {
|
it("sorts ascending", async () => {
|
||||||
it("sorts ascending", async () => {
|
await expectSearch({
|
||||||
await expectSearch({
|
query: {},
|
||||||
query: {},
|
sort: "name",
|
||||||
sort: "name",
|
sortType: SortType.STRING,
|
||||||
sortType: SortType.STRING,
|
sortOrder: SortOrder.ASCENDING,
|
||||||
sortOrder: SortOrder.ASCENDING,
|
}).toMatchExactly([{ name: "bar" }, { name: "foo" }])
|
||||||
}).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" }])
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("sorts descending", async () => {
|
||||||
|
await expectSearch({
|
||||||
|
query: {},
|
||||||
|
sort: "name",
|
||||||
|
sortType: SortType.STRING,
|
||||||
|
sortOrder: SortOrder.DESCENDING,
|
||||||
|
}).toMatchExactly([{ name: "foo" }, { name: "bar" }])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
!isInternal &&
|
!isInternal &&
|
||||||
!isInMemory &&
|
!isInMemory &&
|
||||||
// This test was added because we automatically add in a sort by the
|
// This test was added because we automatically add in a sort by the
|
||||||
|
@ -1317,26 +1319,25 @@ if (descriptions.length) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
isInMemory &&
|
describe("sortType NUMBER", () => {
|
||||||
describe("sortType NUMBER", () => {
|
it("sorts ascending", async () => {
|
||||||
it("sorts ascending", async () => {
|
await expectSearch({
|
||||||
await expectSearch({
|
query: {},
|
||||||
query: {},
|
sort: "age",
|
||||||
sort: "age",
|
sortType: SortType.NUMBER,
|
||||||
sortType: SortType.NUMBER,
|
sortOrder: SortOrder.ASCENDING,
|
||||||
sortOrder: SortOrder.ASCENDING,
|
}).toMatchExactly([{ age: 1 }, { age: 10 }])
|
||||||
}).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 }])
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("sorts descending", async () => {
|
||||||
|
await expectSearch({
|
||||||
|
query: {},
|
||||||
|
sort: "age",
|
||||||
|
sortType: SortType.NUMBER,
|
||||||
|
sortOrder: SortOrder.DESCENDING,
|
||||||
|
}).toMatchExactly([{ age: 10 }, { age: 1 }])
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("dates", () => {
|
describe("dates", () => {
|
||||||
|
@ -1472,26 +1473,25 @@ if (descriptions.length) {
|
||||||
}).toMatchExactly([{ dob: JAN_10TH }, { dob: JAN_1ST }])
|
}).toMatchExactly([{ dob: JAN_10TH }, { dob: JAN_1ST }])
|
||||||
})
|
})
|
||||||
|
|
||||||
isInMemory &&
|
describe("sortType STRING", () => {
|
||||||
describe("sortType STRING", () => {
|
it("sorts ascending", async () => {
|
||||||
it("sorts ascending", async () => {
|
await expectSearch({
|
||||||
await expectSearch({
|
query: {},
|
||||||
query: {},
|
sort: "dob",
|
||||||
sort: "dob",
|
sortType: SortType.STRING,
|
||||||
sortType: SortType.STRING,
|
sortOrder: SortOrder.ASCENDING,
|
||||||
sortOrder: SortOrder.ASCENDING,
|
}).toMatchExactly([{ dob: JAN_1ST }, { dob: JAN_10TH }])
|
||||||
}).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 }])
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
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", () => {
|
||||||
describe("sortType STRING", () => {
|
it("sorts ascending", async () => {
|
||||||
it("sorts ascending", async () => {
|
await expectSearch({
|
||||||
await expectSearch({
|
query: {},
|
||||||
query: {},
|
sort: "time",
|
||||||
sort: "time",
|
sortType: SortType.STRING,
|
||||||
sortType: SortType.STRING,
|
sortOrder: SortOrder.ASCENDING,
|
||||||
sortOrder: SortOrder.ASCENDING,
|
}).toMatchExactly([
|
||||||
}).toMatchExactly([
|
{ timeid: NULL_TIME__ID },
|
||||||
{ timeid: NULL_TIME__ID },
|
{ time: "00:00:00" },
|
||||||
{ time: "00:00:00" },
|
{ time: "10:00:00" },
|
||||||
{ time: "10:00:00" },
|
{ time: "10:45:00" },
|
||||||
{ time: "10:45:00" },
|
{ time: "12:00:00" },
|
||||||
{ time: "12:00:00" },
|
{ time: "15:30: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 },
|
|
||||||
])
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
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("datetime - date only", () => {
|
describe.each([true, false])(
|
||||||
describe.each([true, false])(
|
"saved with timestamp: %s",
|
||||||
"saved with timestamp: %s",
|
saveWithTimestamp => {
|
||||||
saveWithTimestamp => {
|
describe.each([true, false])(
|
||||||
describe.each([true, false])(
|
"search with timestamp: %s",
|
||||||
"search with timestamp: %s",
|
searchWithTimestamp => {
|
||||||
searchWithTimestamp => {
|
const SAVE_SUFFIX = saveWithTimestamp
|
||||||
const SAVE_SUFFIX = saveWithTimestamp
|
? "T00:00:00.000Z"
|
||||||
? "T00:00:00.000Z"
|
: ""
|
||||||
: ""
|
const SEARCH_SUFFIX = searchWithTimestamp
|
||||||
const SEARCH_SUFFIX = searchWithTimestamp
|
? "T00:00:00.000Z"
|
||||||
? "T00:00:00.000Z"
|
: ""
|
||||||
: ""
|
|
||||||
|
|
||||||
const JAN_1ST = `2020-01-01`
|
const JAN_1ST = `2020-01-01`
|
||||||
const JAN_10TH = `2020-01-10`
|
const JAN_10TH = `2020-01-10`
|
||||||
const JAN_30TH = `2020-01-30`
|
const JAN_30TH = `2020-01-30`
|
||||||
const UNEXISTING_DATE = `2020-01-03`
|
const UNEXISTING_DATE = `2020-01-03`
|
||||||
const NULL_DATE__ID = `null_date__id`
|
const NULL_DATE__ID = `null_date__id`
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
tableOrViewId = await createTableOrView({
|
tableOrViewId = await createTableOrView({
|
||||||
dateid: {
|
dateid: {
|
||||||
name: "dateid",
|
name: "dateid",
|
||||||
type: FieldType.STRING,
|
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: {
|
}).toFindNothing()
|
||||||
name: "date",
|
})
|
||||||
type: FieldType.DATETIME,
|
})
|
||||||
dateOnly: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
await createRows([
|
describe("notEqual", () => {
|
||||||
{ dateid: NULL_DATE__ID, date: null },
|
it("successfully finds a row", async () => {
|
||||||
{ date: `${JAN_1ST}${SAVE_SUFFIX}` },
|
await expectQuery({
|
||||||
{ date: `${JAN_10TH}${SAVE_SUFFIX}` },
|
notEqual: {
|
||||||
|
date: `${JAN_1ST}${SEARCH_SUFFIX}`,
|
||||||
|
},
|
||||||
|
}).toContainExactly([
|
||||||
|
{ date: JAN_10TH },
|
||||||
|
{ dateid: NULL_DATE__ID },
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("equal", () => {
|
it("fails to find nonexistent row", async () => {
|
||||||
it("successfully finds a row", async () => {
|
await expectQuery({
|
||||||
await expectQuery({
|
notEqual: {
|
||||||
equal: { date: `${JAN_1ST}${SEARCH_SUFFIX}` },
|
date: `${JAN_30TH}${SEARCH_SUFFIX}`,
|
||||||
}).toContainExactly([{ date: JAN_1ST }])
|
},
|
||||||
})
|
}).toContainExactly([
|
||||||
|
{ date: JAN_1ST },
|
||||||
|
{ date: JAN_10TH },
|
||||||
|
{ dateid: NULL_DATE__ID },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it("successfully finds an ISO8601 row", async () => {
|
describe("oneOf", () => {
|
||||||
await expectQuery({
|
it("successfully finds a row", async () => {
|
||||||
equal: { date: `${JAN_10TH}${SEARCH_SUFFIX}` },
|
await expectQuery({
|
||||||
}).toContainExactly([{ date: JAN_10TH }])
|
oneOf: { date: [`${JAN_1ST}${SEARCH_SUFFIX}`] },
|
||||||
})
|
}).toContainExactly([{ date: JAN_1ST }])
|
||||||
|
|
||||||
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("notEqual", () => {
|
it("fails to find nonexistent row", async () => {
|
||||||
it("successfully finds a row", async () => {
|
await expectQuery({
|
||||||
await expectQuery({
|
oneOf: {
|
||||||
notEqual: {
|
date: [`${UNEXISTING_DATE}${SEARCH_SUFFIX}`],
|
||||||
date: `${JAN_1ST}${SEARCH_SUFFIX}`,
|
},
|
||||||
},
|
}).toFindNothing()
|
||||||
}).toContainExactly([
|
})
|
||||||
{ date: JAN_10TH },
|
})
|
||||||
{ dateid: NULL_DATE__ID },
|
|
||||||
])
|
|
||||||
})
|
|
||||||
|
|
||||||
it("fails to find nonexistent row", async () => {
|
describe("range", () => {
|
||||||
await expectQuery({
|
it("successfully finds a row", async () => {
|
||||||
notEqual: {
|
await expectQuery({
|
||||||
date: `${JAN_30TH}${SEARCH_SUFFIX}`,
|
range: {
|
||||||
|
date: {
|
||||||
|
low: `${JAN_1ST}${SEARCH_SUFFIX}`,
|
||||||
|
high: `${JAN_1ST}${SEARCH_SUFFIX}`,
|
||||||
},
|
},
|
||||||
}).toContainExactly([
|
},
|
||||||
{ date: JAN_1ST },
|
}).toContainExactly([{ date: JAN_1ST }])
|
||||||
{ date: JAN_10TH },
|
|
||||||
{ dateid: NULL_DATE__ID },
|
|
||||||
])
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("oneOf", () => {
|
it("successfully finds multiple rows", async () => {
|
||||||
it("successfully finds a row", async () => {
|
await expectQuery({
|
||||||
await expectQuery({
|
range: {
|
||||||
oneOf: { date: [`${JAN_1ST}${SEARCH_SUFFIX}`] },
|
date: {
|
||||||
}).toContainExactly([{ date: JAN_1ST }])
|
low: `${JAN_1ST}${SEARCH_SUFFIX}`,
|
||||||
})
|
high: `${JAN_10TH}${SEARCH_SUFFIX}`,
|
||||||
|
|
||||||
it("fails to find nonexistent row", async () => {
|
|
||||||
await expectQuery({
|
|
||||||
oneOf: {
|
|
||||||
date: [`${UNEXISTING_DATE}${SEARCH_SUFFIX}`],
|
|
||||||
},
|
},
|
||||||
}).toFindNothing()
|
},
|
||||||
})
|
}).toContainExactly([
|
||||||
|
{ date: JAN_1ST },
|
||||||
|
{ date: JAN_10TH },
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("range", () => {
|
it("successfully finds no rows", async () => {
|
||||||
it("successfully finds a row", async () => {
|
await expectQuery({
|
||||||
await expectQuery({
|
range: {
|
||||||
range: {
|
date: {
|
||||||
date: {
|
low: `${JAN_30TH}${SEARCH_SUFFIX}`,
|
||||||
low: `${JAN_1ST}${SEARCH_SUFFIX}`,
|
high: `${JAN_30TH}${SEARCH_SUFFIX}`,
|
||||||
high: `${JAN_1ST}${SEARCH_SUFFIX}`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}).toContainExactly([{ date: JAN_1ST }])
|
},
|
||||||
})
|
}).toFindNothing()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it("successfully finds multiple rows", async () => {
|
describe("sort", () => {
|
||||||
await expectQuery({
|
it("sorts ascending", async () => {
|
||||||
range: {
|
await expectSearch({
|
||||||
date: {
|
query: {},
|
||||||
low: `${JAN_1ST}${SEARCH_SUFFIX}`,
|
sort: "date",
|
||||||
high: `${JAN_10TH}${SEARCH_SUFFIX}`,
|
sortOrder: SortOrder.ASCENDING,
|
||||||
},
|
}).toMatchExactly([
|
||||||
},
|
{ dateid: NULL_DATE__ID },
|
||||||
}).toContainExactly([
|
{ date: JAN_1ST },
|
||||||
{ date: JAN_1ST },
|
{ date: JAN_10TH },
|
||||||
{ 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 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 () => {
|
it("sorts ascending", async () => {
|
||||||
await expectSearch({
|
await expectSearch({
|
||||||
query: {},
|
query: {},
|
||||||
sort: "date",
|
sort: "date",
|
||||||
|
sortType: SortType.STRING,
|
||||||
sortOrder: SortOrder.ASCENDING,
|
sortOrder: SortOrder.ASCENDING,
|
||||||
}).toMatchExactly([
|
}).toMatchExactly([
|
||||||
{ dateid: NULL_DATE__ID },
|
{ dateid: NULL_DATE__ID },
|
||||||
|
@ -1841,6 +1865,7 @@ if (descriptions.length) {
|
||||||
await expectSearch({
|
await expectSearch({
|
||||||
query: {},
|
query: {},
|
||||||
sort: "date",
|
sort: "date",
|
||||||
|
sortType: SortType.STRING,
|
||||||
sortOrder: SortOrder.DESCENDING,
|
sortOrder: SortOrder.DESCENDING,
|
||||||
}).toMatchExactly([
|
}).toMatchExactly([
|
||||||
{ date: JAN_10TH },
|
{ date: JAN_10TH },
|
||||||
|
@ -1848,41 +1873,13 @@ if (descriptions.length) {
|
||||||
{ dateid: NULL_DATE__ID },
|
{ 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 &&
|
isInternal &&
|
||||||
!isInMemory &&
|
!isInMemory &&
|
||||||
|
|
|
@ -24,6 +24,7 @@ import {
|
||||||
SearchResponse,
|
SearchResponse,
|
||||||
SearchViewRowRequest,
|
SearchViewRowRequest,
|
||||||
SortOrder,
|
SortOrder,
|
||||||
|
SortType,
|
||||||
StaticQuotaName,
|
StaticQuotaName,
|
||||||
Table,
|
Table,
|
||||||
TableSchema,
|
TableSchema,
|
||||||
|
@ -153,6 +154,7 @@ if (descriptions.length) {
|
||||||
sort: {
|
sort: {
|
||||||
field: "fieldToSort",
|
field: "fieldToSort",
|
||||||
order: SortOrder.DESCENDING,
|
order: SortOrder.DESCENDING,
|
||||||
|
type: SortType.STRING,
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
id: { visible: true },
|
id: { visible: true },
|
||||||
|
@ -215,6 +217,7 @@ if (descriptions.length) {
|
||||||
sort: {
|
sort: {
|
||||||
field: "fieldToSort",
|
field: "fieldToSort",
|
||||||
order: SortOrder.DESCENDING,
|
order: SortOrder.DESCENDING,
|
||||||
|
type: SortType.STRING,
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
id: { visible: true },
|
id: { visible: true },
|
||||||
|
@ -1144,6 +1147,7 @@ if (descriptions.length) {
|
||||||
sort: {
|
sort: {
|
||||||
field: generator.word(),
|
field: generator.word(),
|
||||||
order: SortOrder.DESCENDING,
|
order: SortOrder.DESCENDING,
|
||||||
|
type: SortType.STRING,
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
id: { visible: true },
|
id: { visible: true },
|
||||||
|
@ -3149,6 +3153,7 @@ if (descriptions.length) {
|
||||||
{
|
{
|
||||||
field: string
|
field: string
|
||||||
order?: SortOrder
|
order?: SortOrder
|
||||||
|
type?: SortType
|
||||||
},
|
},
|
||||||
string[]
|
string[]
|
||||||
][] = [
|
][] = [
|
||||||
|
@ -3156,6 +3161,7 @@ if (descriptions.length) {
|
||||||
{
|
{
|
||||||
field: "name",
|
field: "name",
|
||||||
order: SortOrder.ASCENDING,
|
order: SortOrder.ASCENDING,
|
||||||
|
type: SortType.STRING,
|
||||||
},
|
},
|
||||||
["Alice", "Bob", "Charly", "Danny"],
|
["Alice", "Bob", "Charly", "Danny"],
|
||||||
],
|
],
|
||||||
|
@ -3172,6 +3178,22 @@ if (descriptions.length) {
|
||||||
},
|
},
|
||||||
["Danny", "Charly", "Bob", "Alice"],
|
["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",
|
field: "age",
|
||||||
|
@ -3182,13 +3204,15 @@ if (descriptions.length) {
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
field: "age",
|
field: "age",
|
||||||
|
order: SortOrder.DESCENDING,
|
||||||
},
|
},
|
||||||
["Danny", "Alice", "Charly", "Bob"],
|
["Bob", "Charly", "Alice", "Danny"],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
field: "age",
|
field: "age",
|
||||||
order: SortOrder.DESCENDING,
|
order: SortOrder.DESCENDING,
|
||||||
|
type: SortType.NUMBER,
|
||||||
},
|
},
|
||||||
["Bob", "Charly", "Alice", "Danny"],
|
["Bob", "Charly", "Alice", "Danny"],
|
||||||
],
|
],
|
||||||
|
@ -3275,6 +3299,7 @@ if (descriptions.length) {
|
||||||
sort: {
|
sort: {
|
||||||
field: "name",
|
field: "name",
|
||||||
order: SortOrder.ASCENDING,
|
order: SortOrder.ASCENDING,
|
||||||
|
type: SortType.STRING,
|
||||||
},
|
},
|
||||||
schema: viewSchema,
|
schema: viewSchema,
|
||||||
})
|
})
|
||||||
|
@ -3282,6 +3307,7 @@ if (descriptions.length) {
|
||||||
const response = await config.api.viewV2.search(view.id, {
|
const response = await config.api.viewV2.search(view.id, {
|
||||||
sort: sortParams.field,
|
sort: sortParams.field,
|
||||||
sortOrder: sortParams.order,
|
sortOrder: sortParams.order,
|
||||||
|
sortType: sortParams.type,
|
||||||
query: {},
|
query: {},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ export async function search(
|
||||||
query: options.query,
|
query: options.query,
|
||||||
sort: options.sort,
|
sort: options.sort,
|
||||||
sortOrder: options.sortOrder,
|
sortOrder: options.sortOrder,
|
||||||
|
sortType: options.sortType,
|
||||||
limit: options.limit,
|
limit: options.limit,
|
||||||
bookmark: options.bookmark,
|
bookmark: options.bookmark,
|
||||||
paginate: options.paginate,
|
paginate: options.paginate,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import {
|
import {
|
||||||
Aggregation,
|
Aggregation,
|
||||||
AutoFieldSubType,
|
|
||||||
CalculationType,
|
CalculationType,
|
||||||
DocumentType,
|
DocumentType,
|
||||||
EnrichedQueryJson,
|
EnrichedQueryJson,
|
||||||
|
@ -424,11 +423,7 @@ export async function search(
|
||||||
}
|
}
|
||||||
} else if (sortField) {
|
} else if (sortField) {
|
||||||
const sortType =
|
const sortType =
|
||||||
sortField.type === FieldType.NUMBER ||
|
sortField.type === FieldType.NUMBER ? SortType.NUMBER : SortType.STRING
|
||||||
(sortField.type === FieldType.AUTO &&
|
|
||||||
sortField.subtype === AutoFieldSubType.AUTO_ID)
|
|
||||||
? SortType.NUMBER
|
|
||||||
: SortType.STRING
|
|
||||||
request.sort = {
|
request.sort = {
|
||||||
[mapToUserColumn(sortField.name)]: {
|
[mapToUserColumn(sortField.name)]: {
|
||||||
direction: params.sortOrder || SortOrder.ASCENDING,
|
direction: params.sortOrder || SortOrder.ASCENDING,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
SortType,
|
SortType,
|
||||||
FieldConstraints,
|
FieldConstraints,
|
||||||
SortOrder,
|
SortOrder,
|
||||||
|
RowSearchParams,
|
||||||
EmptyFilterOption,
|
EmptyFilterOption,
|
||||||
SearchResponse,
|
SearchResponse,
|
||||||
Table,
|
Table,
|
||||||
|
@ -24,8 +25,6 @@ import {
|
||||||
isArraySearchOperator,
|
isArraySearchOperator,
|
||||||
isRangeSearchOperator,
|
isRangeSearchOperator,
|
||||||
SearchFilter,
|
SearchFilter,
|
||||||
WithRequired,
|
|
||||||
SearchParams,
|
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import dayjs from "dayjs"
|
import dayjs from "dayjs"
|
||||||
import { OperatorOptions, SqlNumberTypeRangeMap } from "./constants"
|
import { OperatorOptions, SqlNumberTypeRangeMap } from "./constants"
|
||||||
|
@ -522,19 +521,9 @@ export function fixupFilterArrays(filters: SearchFilters) {
|
||||||
return filters
|
return filters
|
||||||
}
|
}
|
||||||
|
|
||||||
type SearchQuery = WithRequired<
|
|
||||||
Pick<
|
|
||||||
SearchParams,
|
|
||||||
"query" | "sort" | "sortOrder" | "sortType" | "limit" | "countRows"
|
|
||||||
>,
|
|
||||||
"query"
|
|
||||||
>
|
|
||||||
|
|
||||||
export type InMemorySearchQuery = SearchQuery
|
|
||||||
|
|
||||||
export function search<T extends Record<string, any>>(
|
export function search<T extends Record<string, any>>(
|
||||||
docs: T[],
|
docs: T[],
|
||||||
query: SearchQuery
|
query: Omit<RowSearchParams, "tableId">
|
||||||
): SearchResponse<T> {
|
): SearchResponse<T> {
|
||||||
let result = runQuery(docs, query.query)
|
let result = runQuery(docs, query.query)
|
||||||
if (query.sort) {
|
if (query.sort) {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
export * from "./constants"
|
export * from "./constants"
|
||||||
export * as dataFilters from "./filters"
|
export * as dataFilters from "./filters"
|
||||||
export type * from "./filters"
|
|
||||||
export * as helpers from "./helpers"
|
export * as helpers from "./helpers"
|
||||||
export * as utils from "./utils"
|
export * as utils from "./utils"
|
||||||
export * as sdk from "./sdk"
|
export * as sdk from "./sdk"
|
||||||
|
|
|
@ -8,7 +8,11 @@ import {
|
||||||
SearchFilterKey,
|
SearchFilterKey,
|
||||||
} from "../../../../sdk"
|
} from "../../../../sdk"
|
||||||
import { Row } from "../../../../documents"
|
import { Row } from "../../../../documents"
|
||||||
import { PaginationResponse, SortOrder } from "../../../../api/web/pagination"
|
import {
|
||||||
|
PaginationResponse,
|
||||||
|
SortOrder,
|
||||||
|
SortType,
|
||||||
|
} from "../../../../api/web/pagination"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
const fieldKey = z
|
const fieldKey = z
|
||||||
|
@ -66,6 +70,7 @@ const searchRowRequest = z.object({
|
||||||
limit: z.number().optional(),
|
limit: z.number().optional(),
|
||||||
sort: z.string().nullish(),
|
sort: z.string().nullish(),
|
||||||
sortOrder: z.nativeEnum(SortOrder).optional(),
|
sortOrder: z.nativeEnum(SortOrder).optional(),
|
||||||
|
sortType: z.nativeEnum(SortType).nullish(),
|
||||||
version: z.string().optional(),
|
version: z.string().optional(),
|
||||||
disableEscaping: z.boolean().optional(),
|
disableEscaping: z.boolean().optional(),
|
||||||
countRows: z.boolean().optional(),
|
countRows: z.boolean().optional(),
|
||||||
|
@ -78,6 +83,7 @@ export type SearchViewRowRequest = Pick<
|
||||||
SearchRowRequest,
|
SearchRowRequest,
|
||||||
| "sort"
|
| "sort"
|
||||||
| "sortOrder"
|
| "sortOrder"
|
||||||
|
| "sortType"
|
||||||
| "limit"
|
| "limit"
|
||||||
| "bookmark"
|
| "bookmark"
|
||||||
| "paginate"
|
| "paginate"
|
||||||
|
|
|
@ -50,7 +50,7 @@ export interface SearchParams {
|
||||||
|
|
||||||
// when searching for rows we want a more extensive search type that requires certain properties
|
// when searching for rows we want a more extensive search type that requires certain properties
|
||||||
export interface RowSearchParams
|
export interface RowSearchParams
|
||||||
extends WithRequired<Omit<SearchParams, "sortType">, "tableId" | "query"> {}
|
extends WithRequired<SearchParams, "tableId" | "query"> {}
|
||||||
|
|
||||||
export interface SearchResponse<T> {
|
export interface SearchResponse<T> {
|
||||||
rows: T[]
|
rows: T[]
|
||||||
|
|
Loading…
Reference in New Issue