diff --git a/packages/server/src/api/routes/tests/search.spec.ts b/packages/server/src/api/routes/tests/search.spec.ts index 2b08f9afc1..f5d107d0de 100644 --- a/packages/server/src/api/routes/tests/search.spec.ts +++ b/packages/server/src/api/routes/tests/search.spec.ts @@ -2,7 +2,13 @@ import { tableForDatasource } from "../../../tests/utilities/structures" import { DatabaseName, getDatasource } from "../../../integrations/tests/utils" import * as setup from "./utilities" -import { Datasource, FieldType, SearchFilters, Table } from "@budibase/types" +import { + Datasource, + EmptyFilterOption, + FieldType, + SearchFilters, + Table, +} from "@budibase/types" jest.unmock("mssql") @@ -40,20 +46,20 @@ describe.each([ } }) - beforeEach(async () => { - table = await config.api.table.save( - tableForDatasource(datasource, { - schema: { - name: { - name: "name", - type: FieldType.STRING, - }, - }, - }) - ) - }) - describe("strings", () => { + beforeEach(async () => { + table = await config.api.table.save( + tableForDatasource(datasource, { + schema: { + name: { + name: "name", + type: FieldType.STRING, + }, + }, + }) + ) + }) + const rows = [{ name: "foo" }, { name: "bar" }] interface StringSearchTest { @@ -63,7 +69,16 @@ describe.each([ const stringSearchTests: StringSearchTest[] = [ { query: {}, expected: rows }, + { + query: { onEmptyFilter: EmptyFilterOption.RETURN_ALL }, + expected: rows, + }, + { + query: { onEmptyFilter: EmptyFilterOption.RETURN_NONE }, + expected: [], + }, { query: { string: { name: "foo" } }, expected: [rows[0]] }, + { query: { string: { name: "none" } }, expected: [] }, { query: { fuzzy: { name: "oo" } }, expected: [rows[0]] }, { query: { equal: { name: "foo" } }, expected: [rows[0]] }, { query: { notEqual: { name: "foo" } }, expected: [rows[1]] }, @@ -76,13 +91,190 @@ describe.each([ it.each(stringSearchTests)( `should be able to run query: $query`, async ({ query, expected }) => { - await Promise.all(rows.map(r => config.api.row.save(table._id!, r))) + const savedRows = await Promise.all( + rows.map(r => config.api.row.save(table._id!, r)) + ) const { rows: foundRows } = await config.api.row.search(table._id!, { tableId: table._id!, query, }) expect(foundRows).toEqual( - expect.arrayContaining(expected.map(r => expect.objectContaining(r))) + expect.arrayContaining( + expected.map(r => + expect.objectContaining(savedRows.find(sr => sr.name === r.name)!) + ) + ) + ) + } + ) + }) + + describe("number", () => { + beforeEach(async () => { + table = await config.api.table.save( + tableForDatasource(datasource, { + schema: { + age: { + name: "age", + type: FieldType.NUMBER, + }, + }, + }) + ) + }) + + const rows = [{ age: 1 }, { age: 10 }] + + interface NumberSearchTest { + query: SearchFilters + expected: (typeof rows)[number][] + } + + const numberSearchTests: NumberSearchTest[] = [ + { query: {}, expected: rows }, + { + query: { onEmptyFilter: EmptyFilterOption.RETURN_ALL }, + expected: rows, + }, + { + query: { onEmptyFilter: EmptyFilterOption.RETURN_NONE }, + expected: [], + }, + { query: { equal: { age: 1 } }, expected: [rows[0]] }, + { query: { equal: { age: 2 } }, expected: [] }, + { query: { notEqual: { age: 1 } }, expected: [rows[1]] }, + { query: { oneOf: { age: [1] } }, expected: [rows[0]] }, + { query: { range: { age: { low: 1, high: 5 } } }, expected: [rows[0]] }, + { query: { range: { age: { low: 0, high: 1 } } }, expected: [rows[0]] }, + { query: { range: { age: { low: 3, high: 4 } } }, expected: [] }, + { query: { range: { age: { low: 0, high: 11 } } }, expected: rows }, + ] + + it.each(numberSearchTests)( + `should be able to run query: $query`, + async ({ query, expected }) => { + const savedRows = await Promise.all( + rows.map(r => config.api.row.save(table._id!, r)) + ) + const { rows: foundRows } = await config.api.row.search(table._id!, { + tableId: table._id!, + query, + }) + expect(foundRows).toEqual( + expect.arrayContaining( + expected.map(r => + expect.objectContaining(savedRows.find(sr => sr.age === r.age)!) + ) + ) + ) + } + ) + }) + + describe("dates", () => { + beforeEach(async () => { + table = await config.api.table.save( + tableForDatasource(datasource, { + schema: { + dob: { + name: "dob", + type: FieldType.DATETIME, + }, + }, + }) + ) + }) + + const rows = [ + { dob: new Date("2020-01-01") }, + { dob: new Date("2020-01-10") }, + ] + + interface DateSearchTest { + query: SearchFilters + expected: (typeof rows)[number][] + } + + const dateSearchTests: DateSearchTest[] = [ + { query: {}, expected: rows }, + { + query: { onEmptyFilter: EmptyFilterOption.RETURN_ALL }, + expected: rows, + }, + { + query: { onEmptyFilter: EmptyFilterOption.RETURN_NONE }, + expected: [], + }, + { + query: { equal: { dob: new Date("2020-01-01") } }, + expected: [rows[0]], + }, + { query: { equal: { dob: new Date("2020-01-02") } }, expected: [] }, + { + query: { notEqual: { dob: new Date("2020-01-01") } }, + expected: [rows[1]], + }, + { + query: { oneOf: { dob: [new Date("2020-01-01")] } }, + expected: [rows[0]], + }, + { + query: { + range: { + dob: { + low: new Date("2020-01-01").toISOString(), + high: new Date("2020-01-05").toISOString(), + }, + }, + }, + expected: [rows[0]], + }, + { + query: { + range: { + dob: { + low: new Date("2020-01-01").toISOString(), + high: new Date("2020-01-10").toISOString(), + }, + }, + }, + expected: rows, + }, + { + query: { + range: { + dob: { + low: new Date("2020-01-05").toISOString(), + high: new Date("2020-01-10").toISOString(), + }, + }, + }, + expected: [rows[1]], + }, + ] + + it.each(dateSearchTests)( + `should be able to run query: $query`, + async ({ query, expected }) => { + // TODO(samwho): most of these work for SQS, but not all. Fix 'em. + if (isSqs) { + return + } + const savedRows = await Promise.all( + rows.map(r => config.api.row.save(table._id!, r)) + ) + const { rows: foundRows } = await config.api.row.search(table._id!, { + tableId: table._id!, + query, + }) + expect(foundRows).toEqual( + expect.arrayContaining( + expected.map(r => + expect.objectContaining( + savedRows.find(sr => sr.dob === r.dob.toISOString())! + ) + ) + ) ) } )