diff --git a/packages/server/src/api/routes/tests/search.spec.ts b/packages/server/src/api/routes/tests/search.spec.ts index a904c0c469..caa651f3bb 100644 --- a/packages/server/src/api/routes/tests/search.spec.ts +++ b/packages/server/src/api/routes/tests/search.spec.ts @@ -3550,6 +3550,31 @@ if (descriptions.length) { limit: 1, }).toContainExactly([row]) }) + + isInternal && + describe("search by _id for relations", () => { + it("can filter by the related _id", async () => { + await expectSearch({ + query: { + equal: { "rel._id": row.rel[0]._id }, + }, + }).toContainExactly([row]) + + await expectSearch({ + query: { + equal: { "rel._id": row.rel[1]._id }, + }, + }).toContainExactly([row]) + }) + + it("can filter by the related _id and find nothing", async () => { + await expectSearch({ + query: { + equal: { "rel._id": "rel_none" }, + }, + }).toFindNothing() + }) + }) }) !isInternal && diff --git a/packages/server/src/automations/tests/branching.spec.ts b/packages/server/src/automations/tests/branching.spec.ts index bf9b9ce3f8..4572871c44 100644 --- a/packages/server/src/automations/tests/branching.spec.ts +++ b/packages/server/src/automations/tests/branching.spec.ts @@ -1,5 +1,5 @@ import * as automation from "../index" -import { Table, AutomationStatus } from "@budibase/types" +import { Table, AutomationStatus, EmptyFilterOption } from "@budibase/types" import { createAutomationBuilder } from "./utilities/AutomationTestBuilder" import TestConfiguration from "../../tests/utilities/TestConfiguration" @@ -280,4 +280,23 @@ describe("Branching automations", () => { expect(results.steps[2].outputs.message).toContain("Special user") }) + + it("should not fail with empty conditions", async () => { + const results = await createAutomationBuilder(config) + .onAppAction() + .branch({ + specialBranch: { + steps: stepBuilder => stepBuilder.serverLog({ text: "Hello!" }), + condition: { + onEmptyFilter: EmptyFilterOption.RETURN_NONE, + }, + }, + }) + .test({ fields: { test_trigger: true } }) + + expect(results.steps[0].outputs.success).toEqual(false) + expect(results.steps[0].outputs.status).toEqual( + AutomationStatus.NO_CONDITION_MET + ) + }) }) diff --git a/packages/server/src/sdk/app/rows/queryUtils.ts b/packages/server/src/sdk/app/rows/queryUtils.ts index ddd32870be..8ab50ea1b7 100644 --- a/packages/server/src/sdk/app/rows/queryUtils.ts +++ b/packages/server/src/sdk/app/rows/queryUtils.ts @@ -7,6 +7,7 @@ import { } from "@budibase/types" import { cloneDeep } from "lodash/fp" import sdk from "../../../sdk" +import { isInternal } from "../tables/utils" export const removeInvalidFilters = ( filters: SearchFilters, @@ -70,6 +71,10 @@ export const getQueryableFields = async ( opts?: { noRelationships?: boolean } ): Promise => { const result = [] + if (isInternal({ table })) { + result.push("_id") + } + for (const field of Object.keys(table.schema).filter( f => allowedFields.includes(f) && table.schema[f].visible !== false )) { @@ -113,14 +118,13 @@ export const getQueryableFields = async ( return result } - const result = [ - "_id", // Querying by _id is always allowed, even if it's never part of the schema - ] + // Querying by _id is always allowed, even if it's never part of the schema + const result = ["_id"] if (fields == null) { fields = Object.keys(table.schema) } result.push(...(await extractTableFields(table, fields, [table._id!]))) - return result + return Array.from(new Set(result)) } diff --git a/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts b/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts index f399801f1e..26a8431446 100644 --- a/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts +++ b/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts @@ -250,6 +250,8 @@ describe("query utils", () => { expect(result).toEqual([ "_id", "name", + "aux._id", + "auxTable._id", "aux.title", "auxTable.title", "aux.name", @@ -284,7 +286,14 @@ describe("query utils", () => { const result = await config.doInContext(config.appId, () => { return getQueryableFields(table) }) - expect(result).toEqual(["_id", "name", "aux.name", "auxTable.name"]) + expect(result).toEqual([ + "_id", + "name", + "aux._id", + "auxTable._id", + "aux.name", + "auxTable.name", + ]) }) it("excludes all relationship fields if hidden", async () => { @@ -387,10 +396,14 @@ describe("query utils", () => { "_id", "name", // aux1 primitive props + "aux1._id", + "aux1Table._id", "aux1.name", "aux1Table.name", // aux2 primitive props + "aux2._id", + "aux2Table._id", "aux2.title", "aux2Table.title", ]) @@ -405,14 +418,18 @@ describe("query utils", () => { "name", // aux2_1 primitive props + "aux2_1._id", + "aux2Table._id", "aux2_1.title", "aux2Table.title", // aux2_2 primitive props + "aux2_2._id", "aux2_2.title", - "aux2Table.title", // table primitive props + "table._id", + "TestTable._id", "table.name", "TestTable.name", ]) @@ -427,14 +444,18 @@ describe("query utils", () => { "title", // aux1_1 primitive props + "aux1_1._id", + "aux1Table._id", "aux1_1.name", "aux1Table.name", // aux1_2 primitive props + "aux1_2._id", "aux1_2.name", - "aux1Table.name", // table primitive props + "table._id", + "TestTable._id", "table.name", "TestTable.name", ]) @@ -481,6 +502,8 @@ describe("query utils", () => { "name", // deep 1 aux primitive props + "aux._id", + "auxTable._id", "aux.title", "auxTable.title", ]) @@ -495,6 +518,8 @@ describe("query utils", () => { "title", // deep 1 dependency primitive props + "table._id", + "TestTable._id", "table.name", "TestTable.name", ]) diff --git a/packages/server/src/sdk/app/tables/tests/tables.spec.ts b/packages/server/src/sdk/app/tables/tests/tables.spec.ts deleted file mode 100644 index 41ac808f5c..0000000000 --- a/packages/server/src/sdk/app/tables/tests/tables.spec.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - FieldType, - INTERNAL_TABLE_SOURCE_ID, - Table, - TableSourceType, - ViewV2, -} from "@budibase/types" -import { generator } from "@budibase/backend-core/tests" -import sdk from "../../.." - -jest.mock("../../views", () => ({ - ...jest.requireActual("../../views"), - enrichSchema: jest.fn().mockImplementation(v => ({ ...v, mocked: true })), -})) - -describe("table sdk", () => { - describe("enrichViewSchemas", () => { - const basicTable: Table = { - _id: generator.guid(), - name: "TestTable", - type: "table", - sourceId: INTERNAL_TABLE_SOURCE_ID, - sourceType: TableSourceType.INTERNAL, - schema: { - name: { - type: FieldType.STRING, - name: "name", - visible: true, - width: 80, - order: 2, - constraints: { - type: "string", - }, - }, - description: { - type: FieldType.STRING, - name: "description", - visible: true, - width: 200, - constraints: { - type: "string", - }, - }, - id: { - type: FieldType.NUMBER, - name: "id", - visible: true, - order: 1, - constraints: { - type: "number", - }, - }, - hiddenField: { - type: FieldType.STRING, - name: "hiddenField", - visible: false, - constraints: { - type: "string", - }, - }, - }, - } - - it("should fetch the default schema if not overriden", async () => { - const tableId = basicTable._id! - function getTable() { - const view: ViewV2 = { - version: 2, - id: generator.guid(), - name: generator.guid(), - tableId, - } - return view - } - const view1 = getTable() - const view2 = getTable() - const view3 = getTable() - const res = await sdk.tables.enrichViewSchemas({ - ...basicTable, - views: { - [view1.name]: view1, - [view2.name]: view2, - [view3.name]: view3, - }, - }) - - expect(sdk.views.enrichSchema).toHaveBeenCalledTimes(3) - - expect(res).toEqual({ - ...basicTable, - views: { - [view1.name]: { - ...view1, - mocked: true, - }, - [view2.name]: { - ...view2, - mocked: true, - }, - [view3.name]: { - ...view3, - mocked: true, - }, - }, - }) - }) - }) -}) diff --git a/packages/server/src/threads/automation.ts b/packages/server/src/threads/automation.ts index 762da1cbc1..def2ab4201 100644 --- a/packages/server/src/threads/automation.ts +++ b/packages/server/src/threads/automation.ts @@ -367,6 +367,8 @@ class Orchestrator { if (e.errno === "ETIME") { span?.addTags({ timedOut: true }) console.warn(`Automation execution timed out after ${timeout}ms`) + } else { + throw e } } diff --git a/packages/types/src/sdk/search.ts b/packages/types/src/sdk/search.ts index 992e9961d4..99c3658fa8 100644 --- a/packages/types/src/sdk/search.ts +++ b/packages/types/src/sdk/search.ts @@ -3,6 +3,7 @@ import { Row, DocumentType, Table, Datasource } from "../documents" import { SortOrder, SortType } from "../api" import { Knex } from "knex" import { Aggregation } from "./row" +import _ from "lodash" export enum BasicOperator { EQUAL = "equal", @@ -83,7 +84,7 @@ type RangeFilter = Record< type LogicalFilter = { conditions: SearchFilters[] } export function isLogicalFilter(filter: any): filter is LogicalFilter { - return "conditions" in filter + return _.isPlainObject(filter) && "conditions" in filter } export type AnySearchFilter = BasicFilter | ArrayFilter | RangeFilter