1
0
Fork 0
mirror of synced 2024-08-15 10:01:34 +12:00

Change url version path

This commit is contained in:
Adria Navarro 2023-07-19 00:17:41 +01:00 committed by Adria Navarro
parent d981ad039d
commit 63f181649a
2 changed files with 283 additions and 283 deletions

View file

@ -1,12 +1,12 @@
import Router from "@koa/router" import Router from "@koa/router";
import * as rowController from "../controllers/row" import * as rowController from "../controllers/row";
import authorized from "../../middleware/authorized" import authorized from "../../middleware/authorized";
import { paramResource, paramSubResource } from "../../middleware/resourceId" import { paramResource, paramSubResource } from "../../middleware/resourceId";
import { permissions } from "@budibase/backend-core" import { permissions } from "@budibase/backend-core";
import { internalSearchValidator } from "./utils/validators" import { internalSearchValidator } from "./utils/validators";
const { PermissionType, PermissionLevel } = permissions const { PermissionType, PermissionLevel } = permissions;
const router: Router = new Router() const router: Router = new Router();
router router
/** /**
@ -147,7 +147,7 @@ router
rowController.search rowController.search
) )
.get( .get(
"/api/views/v2/:viewId/search", "/api/v2/views/:viewId/search",
authorized(PermissionType.VIEW, PermissionLevel.READ), authorized(PermissionType.VIEW, PermissionLevel.READ),
rowController.searchView rowController.searchView
) )
@ -266,6 +266,6 @@ router
paramResource("tableId"), paramResource("tableId"),
authorized(PermissionType.TABLE, PermissionLevel.WRITE), authorized(PermissionType.TABLE, PermissionLevel.WRITE),
rowController.exportRows rowController.exportRows
) );
export default router export default router;

View file

@ -1,12 +1,12 @@
import tk from "timekeeper" import tk from "timekeeper";
const timestamp = new Date("2023-01-26T11:48:57.597Z").toISOString() const timestamp = new Date("2023-01-26T11:48:57.597Z").toISOString();
tk.freeze(timestamp) tk.freeze(timestamp);
import { outputProcessing } from "../../../utilities/rowProcessor" import { outputProcessing } from "../../../utilities/rowProcessor";
import * as setup from "./utilities" import * as setup from "./utilities";
const { basicRow } = setup.structures const { basicRow } = setup.structures;
import { context, tenancy } from "@budibase/backend-core" import { context, tenancy } from "@budibase/backend-core";
import { quotas } from "@budibase/pro" import { quotas } from "@budibase/pro";
import { import {
QuotaUsageType, QuotaUsageType,
StaticQuotaName, StaticQuotaName,
@ -14,39 +14,39 @@ import {
Row, Row,
Table, Table,
FieldType, FieldType,
} from "@budibase/types" } from "@budibase/types";
import { structures } from "@budibase/backend-core/tests" import { structures } from "@budibase/backend-core/tests";
describe("/rows", () => { describe("/rows", () => {
let request = setup.getRequest() let request = setup.getRequest();
let config = setup.getConfig() let config = setup.getConfig();
let table: Table let table: Table;
let row: Row let row: Row;
afterAll(setup.afterAll) afterAll(setup.afterAll);
beforeAll(async () => { beforeAll(async () => {
await config.init() await config.init();
}) });
beforeEach(async () => { beforeEach(async () => {
table = await config.createTable() table = await config.createTable();
row = basicRow(table._id!) row = basicRow(table._id!);
}) });
const loadRow = async (id: string, tbl_Id: string, status = 200) => const loadRow = async (id: string, tbl_Id: string, status = 200) =>
await request await request
.get(`/api/${tbl_Id}/rows/${id}`) .get(`/api/${tbl_Id}/rows/${id}`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(status) .expect(status);
const getRowUsage = async () => { const getRowUsage = async () => {
const { total } = await config.doInContext(null, () => const { total } = await config.doInContext(null, () =>
quotas.getCurrentUsageValues(QuotaUsageType.STATIC, StaticQuotaName.ROWS) quotas.getCurrentUsageValues(QuotaUsageType.STATIC, StaticQuotaName.ROWS)
) );
return total return total;
} };
const getQueryUsage = async () => { const getQueryUsage = async () => {
const { total } = await config.doInContext(null, () => const { total } = await config.doInContext(null, () =>
@ -54,43 +54,43 @@ describe("/rows", () => {
QuotaUsageType.MONTHLY, QuotaUsageType.MONTHLY,
MonthlyQuotaName.QUERIES MonthlyQuotaName.QUERIES
) )
) );
return total return total;
} };
const assertRowUsage = async (expected: number) => { const assertRowUsage = async (expected: number) => {
const usage = await getRowUsage() const usage = await getRowUsage();
expect(usage).toBe(expected) expect(usage).toBe(expected);
} };
const assertQueryUsage = async (expected: number) => { const assertQueryUsage = async (expected: number) => {
const usage = await getQueryUsage() const usage = await getQueryUsage();
expect(usage).toBe(expected) expect(usage).toBe(expected);
} };
describe("save, load, update", () => { describe("save, load, update", () => {
it("returns a success message when the row is created", async () => { it("returns a success message when the row is created", async () => {
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const res = await request const res = await request
.post(`/api/${row.tableId}/rows`) .post(`/api/${row.tableId}/rows`)
.send(row) .send(row)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect((res as any).res.statusMessage).toEqual( expect((res as any).res.statusMessage).toEqual(
`${table.name} saved successfully` `${table.name} saved successfully`
) );
expect(res.body.name).toEqual("Test Contact") expect(res.body.name).toEqual("Test Contact");
expect(res.body._rev).toBeDefined() expect(res.body._rev).toBeDefined();
await assertRowUsage(rowUsage + 1) await assertRowUsage(rowUsage + 1);
await assertQueryUsage(queryUsage + 1) await assertQueryUsage(queryUsage + 1);
}) });
it("Increment row autoId per create row request", async () => { it("Increment row autoId per create row request", async () => {
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const newTable = await config.createTable({ const newTable = await config.createTable({
name: "TestTableAuto", name: "TestTableAuto",
@ -113,9 +113,9 @@ describe("/rows", () => {
}, },
}, },
}, },
}) });
const ids = [1, 2, 3] const ids = [1, 2, 3];
// Performing several create row requests should increment the autoID fields accordingly // Performing several create row requests should increment the autoID fields accordingly
const createRow = async (id: number) => { const createRow = async (id: number) => {
@ -126,27 +126,27 @@ describe("/rows", () => {
}) })
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect((res as any).res.statusMessage).toEqual( expect((res as any).res.statusMessage).toEqual(
`${newTable.name} saved successfully` `${newTable.name} saved successfully`
) );
expect(res.body.name).toEqual("row_" + id) expect(res.body.name).toEqual("row_" + id);
expect(res.body._rev).toBeDefined() expect(res.body._rev).toBeDefined();
expect(res.body["Row ID"]).toEqual(id) expect(res.body["Row ID"]).toEqual(id);
} };
for (let i = 0; i < ids.length; i++) { for (let i = 0; i < ids.length; i++) {
await createRow(ids[i]) await createRow(ids[i]);
} }
await assertRowUsage(rowUsage + ids.length) await assertRowUsage(rowUsage + ids.length);
await assertQueryUsage(queryUsage + ids.length) await assertQueryUsage(queryUsage + ids.length);
}) });
it("updates a row successfully", async () => { it("updates a row successfully", async () => {
const existing = await config.createRow() const existing = await config.createRow();
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const res = await request const res = await request
.post(`/api/${table._id}/rows`) .post(`/api/${table._id}/rows`)
@ -158,25 +158,25 @@ describe("/rows", () => {
}) })
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect((res as any).res.statusMessage).toEqual( expect((res as any).res.statusMessage).toEqual(
`${table.name} updated successfully.` `${table.name} updated successfully.`
) );
expect(res.body.name).toEqual("Updated Name") expect(res.body.name).toEqual("Updated Name");
await assertRowUsage(rowUsage) await assertRowUsage(rowUsage);
await assertQueryUsage(queryUsage + 1) await assertQueryUsage(queryUsage + 1);
}) });
it("should load a row", async () => { it("should load a row", async () => {
const existing = await config.createRow() const existing = await config.createRow();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const res = await request const res = await request
.get(`/api/${table._id}/rows/${existing._id}`) .get(`/api/${table._id}/rows/${existing._id}`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect(res.body).toEqual({ expect(res.body).toEqual({
...row, ...row,
@ -185,65 +185,65 @@ describe("/rows", () => {
type: "row", type: "row",
createdAt: timestamp, createdAt: timestamp,
updatedAt: timestamp, updatedAt: timestamp,
}) });
await assertQueryUsage(queryUsage + 1) await assertQueryUsage(queryUsage + 1);
}) });
it("should list all rows for given tableId", async () => { it("should list all rows for given tableId", async () => {
const newRow = { const newRow = {
tableId: table._id, tableId: table._id,
name: "Second Contact", name: "Second Contact",
status: "new", status: "new",
} };
await config.createRow() await config.createRow();
await config.createRow(newRow) await config.createRow(newRow);
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const res = await request const res = await request
.get(`/api/${table._id}/rows`) .get(`/api/${table._id}/rows`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect(res.body.length).toBe(2) expect(res.body.length).toBe(2);
expect(res.body.find((r: Row) => r.name === newRow.name)).toBeDefined() expect(res.body.find((r: Row) => r.name === newRow.name)).toBeDefined();
expect(res.body.find((r: Row) => r.name === row.name)).toBeDefined() expect(res.body.find((r: Row) => r.name === row.name)).toBeDefined();
await assertQueryUsage(queryUsage + 1) await assertQueryUsage(queryUsage + 1);
}) });
it("load should return 404 when row does not exist", async () => { it("load should return 404 when row does not exist", async () => {
await config.createRow() await config.createRow();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
await request await request
.get(`/api/${table._id}/rows/not-a-valid-id`) .get(`/api/${table._id}/rows/not-a-valid-id`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(404) .expect(404);
await assertQueryUsage(queryUsage) // no change await assertQueryUsage(queryUsage); // no change
}) });
it("row values are coerced", async () => { it("row values are coerced", async () => {
const str = { const str = {
type: FieldType.STRING, type: FieldType.STRING,
name: "str", name: "str",
constraints: { type: "string", presence: false }, constraints: { type: "string", presence: false },
} };
const attachment = { const attachment = {
type: FieldType.ATTACHMENT, type: FieldType.ATTACHMENT,
name: "attachment", name: "attachment",
constraints: { type: "array", presence: false }, constraints: { type: "array", presence: false },
} };
const bool = { const bool = {
type: FieldType.BOOLEAN, type: FieldType.BOOLEAN,
name: "boolean", name: "boolean",
constraints: { type: "boolean", presence: false }, constraints: { type: "boolean", presence: false },
} };
const number = { const number = {
type: FieldType.NUMBER, type: FieldType.NUMBER,
name: "str", name: "str",
constraints: { type: "number", presence: false }, constraints: { type: "number", presence: false },
} };
const datetime = { const datetime = {
type: FieldType.DATETIME, type: FieldType.DATETIME,
name: "datetime", name: "datetime",
@ -252,7 +252,7 @@ describe("/rows", () => {
presence: false, presence: false,
datetime: { earliest: "", latest: "" }, datetime: { earliest: "", latest: "" },
}, },
} };
const arrayField = { const arrayField = {
type: FieldType.ARRAY, type: FieldType.ARRAY,
constraints: { constraints: {
@ -262,7 +262,7 @@ describe("/rows", () => {
}, },
name: "Sample Tags", name: "Sample Tags",
sortable: false, sortable: false,
} };
const optsField = { const optsField = {
fieldName: "Sample Opts", fieldName: "Sample Opts",
name: "Sample Opts", name: "Sample Opts",
@ -309,7 +309,7 @@ describe("/rows", () => {
optsFieldNull: optsField, optsFieldNull: optsField,
optsFieldStrKnown: optsField, optsFieldStrKnown: optsField,
}, },
}) });
row = { row = {
name: "Test Row", name: "Test Row",
@ -344,54 +344,54 @@ describe("/rows", () => {
optsFieldUndefined: undefined, optsFieldUndefined: undefined,
optsFieldNull: null, optsFieldNull: null,
optsFieldStrKnown: "Alpha", optsFieldStrKnown: "Alpha",
} };
const createdRow = await config.createRow(row) const createdRow = await config.createRow(row);
const id = createdRow._id! const id = createdRow._id!;
const saved = (await loadRow(id, table._id!)).body const saved = (await loadRow(id, table._id!)).body;
expect(saved.stringUndefined).toBe(undefined) expect(saved.stringUndefined).toBe(undefined);
expect(saved.stringNull).toBe("") expect(saved.stringNull).toBe("");
expect(saved.stringString).toBe("i am a string") expect(saved.stringString).toBe("i am a string");
expect(saved.numberEmptyString).toBe(null) expect(saved.numberEmptyString).toBe(null);
expect(saved.numberNull).toBe(null) expect(saved.numberNull).toBe(null);
expect(saved.numberUndefined).toBe(undefined) expect(saved.numberUndefined).toBe(undefined);
expect(saved.numberString).toBe(123) expect(saved.numberString).toBe(123);
expect(saved.numberNumber).toBe(123) expect(saved.numberNumber).toBe(123);
expect(saved.datetimeEmptyString).toBe(null) expect(saved.datetimeEmptyString).toBe(null);
expect(saved.datetimeNull).toBe(null) expect(saved.datetimeNull).toBe(null);
expect(saved.datetimeUndefined).toBe(undefined) expect(saved.datetimeUndefined).toBe(undefined);
expect(saved.datetimeString).toBe( expect(saved.datetimeString).toBe(
new Date(row.datetimeString).toISOString() new Date(row.datetimeString).toISOString()
) );
expect(saved.datetimeDate).toBe(row.datetimeDate.toISOString()) expect(saved.datetimeDate).toBe(row.datetimeDate.toISOString());
expect(saved.boolNull).toBe(null) expect(saved.boolNull).toBe(null);
expect(saved.boolEmpty).toBe(null) expect(saved.boolEmpty).toBe(null);
expect(saved.boolUndefined).toBe(undefined) expect(saved.boolUndefined).toBe(undefined);
expect(saved.boolString).toBe(true) expect(saved.boolString).toBe(true);
expect(saved.boolBool).toBe(true) expect(saved.boolBool).toBe(true);
expect(saved.attachmentNull).toEqual([]) expect(saved.attachmentNull).toEqual([]);
expect(saved.attachmentUndefined).toBe(undefined) expect(saved.attachmentUndefined).toBe(undefined);
expect(saved.attachmentEmpty).toEqual([]) expect(saved.attachmentEmpty).toEqual([]);
expect(saved.attachmentEmptyArrayStr).toEqual([]) expect(saved.attachmentEmptyArrayStr).toEqual([]);
expect(saved.arrayFieldEmptyArrayStr).toEqual([]) expect(saved.arrayFieldEmptyArrayStr).toEqual([]);
expect(saved.arrayFieldNull).toEqual([]) expect(saved.arrayFieldNull).toEqual([]);
expect(saved.arrayFieldUndefined).toEqual(undefined) expect(saved.arrayFieldUndefined).toEqual(undefined);
expect(saved.optsFieldEmptyStr).toEqual(null) expect(saved.optsFieldEmptyStr).toEqual(null);
expect(saved.optsFieldUndefined).toEqual(undefined) expect(saved.optsFieldUndefined).toEqual(undefined);
expect(saved.optsFieldNull).toEqual(null) expect(saved.optsFieldNull).toEqual(null);
expect(saved.arrayFieldArrayStrKnown).toEqual(["One"]) expect(saved.arrayFieldArrayStrKnown).toEqual(["One"]);
expect(saved.optsFieldStrKnown).toEqual("Alpha") expect(saved.optsFieldStrKnown).toEqual("Alpha");
}) });
}) });
describe("patch", () => { describe("patch", () => {
it("should update only the fields that are supplied", async () => { it("should update only the fields that are supplied", async () => {
const existing = await config.createRow() const existing = await config.createRow();
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const res = await request const res = await request
.patch(`/api/${table._id}/rows`) .patch(`/api/${table._id}/rows`)
@ -403,26 +403,26 @@ describe("/rows", () => {
}) })
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect((res as any).res.statusMessage).toEqual( expect((res as any).res.statusMessage).toEqual(
`${table.name} updated successfully.` `${table.name} updated successfully.`
) );
expect(res.body.name).toEqual("Updated Name") expect(res.body.name).toEqual("Updated Name");
expect(res.body.description).toEqual(existing.description) expect(res.body.description).toEqual(existing.description);
const savedRow = await loadRow(res.body._id, table._id!) const savedRow = await loadRow(res.body._id, table._id!);
expect(savedRow.body.description).toEqual(existing.description) expect(savedRow.body.description).toEqual(existing.description);
expect(savedRow.body.name).toEqual("Updated Name") expect(savedRow.body.name).toEqual("Updated Name");
await assertRowUsage(rowUsage) await assertRowUsage(rowUsage);
await assertQueryUsage(queryUsage + 2) // account for the second load await assertQueryUsage(queryUsage + 2); // account for the second load
}) });
it("should throw an error when given improper types", async () => { it("should throw an error when given improper types", async () => {
const existing = await config.createRow() const existing = await config.createRow();
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
await request await request
.patch(`/api/${table._id}/rows`) .patch(`/api/${table._id}/rows`)
@ -433,18 +433,18 @@ describe("/rows", () => {
name: 1, name: 1,
}) })
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect(400) .expect(400);
await assertRowUsage(rowUsage) await assertRowUsage(rowUsage);
await assertQueryUsage(queryUsage) await assertQueryUsage(queryUsage);
}) });
}) });
describe("destroy", () => { describe("destroy", () => {
it("should be able to delete a row", async () => { it("should be able to delete a row", async () => {
const createdRow = await config.createRow(row) const createdRow = await config.createRow(row);
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const res = await request const res = await request
.delete(`/api/${table._id}/rows`) .delete(`/api/${table._id}/rows`)
@ -453,55 +453,55 @@ describe("/rows", () => {
}) })
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect(res.body[0]._id).toEqual(createdRow._id) expect(res.body[0]._id).toEqual(createdRow._id);
await assertRowUsage(rowUsage - 1) await assertRowUsage(rowUsage - 1);
await assertQueryUsage(queryUsage + 1) await assertQueryUsage(queryUsage + 1);
}) });
}) });
describe("validate", () => { describe("validate", () => {
it("should return no errors on valid row", async () => { it("should return no errors on valid row", async () => {
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const res = await request const res = await request
.post(`/api/${table._id}/rows/validate`) .post(`/api/${table._id}/rows/validate`)
.send({ name: "ivan" }) .send({ name: "ivan" })
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect(res.body.valid).toBe(true) expect(res.body.valid).toBe(true);
expect(Object.keys(res.body.errors)).toEqual([]) expect(Object.keys(res.body.errors)).toEqual([]);
await assertRowUsage(rowUsage) await assertRowUsage(rowUsage);
await assertQueryUsage(queryUsage) await assertQueryUsage(queryUsage);
}) });
it("should errors on invalid row", async () => { it("should errors on invalid row", async () => {
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const res = await request const res = await request
.post(`/api/${table._id}/rows/validate`) .post(`/api/${table._id}/rows/validate`)
.send({ name: 1 }) .send({ name: 1 })
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect(res.body.valid).toBe(false) expect(res.body.valid).toBe(false);
expect(Object.keys(res.body.errors)).toEqual(["name"]) expect(Object.keys(res.body.errors)).toEqual(["name"]);
await assertRowUsage(rowUsage) await assertRowUsage(rowUsage);
await assertQueryUsage(queryUsage) await assertQueryUsage(queryUsage);
}) });
}) });
describe("bulkDelete", () => { describe("bulkDelete", () => {
it("should be able to delete a bulk set of rows", async () => { it("should be able to delete a bulk set of rows", async () => {
const row1 = await config.createRow() const row1 = await config.createRow();
const row2 = await config.createRow() const row2 = await config.createRow();
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const res = await request const res = await request
.delete(`/api/${table._id}/rows`) .delete(`/api/${table._id}/rows`)
@ -510,115 +510,115 @@ describe("/rows", () => {
}) })
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect(res.body.length).toEqual(2) expect(res.body.length).toEqual(2);
await loadRow(row1._id!, table._id!, 404) await loadRow(row1._id!, table._id!, 404);
await assertRowUsage(rowUsage - 2) await assertRowUsage(rowUsage - 2);
await assertQueryUsage(queryUsage + 1) await assertQueryUsage(queryUsage + 1);
}) });
}) });
describe("fetchView", () => { describe("fetchView", () => {
it("should be able to fetch tables contents via 'view'", async () => { it("should be able to fetch tables contents via 'view'", async () => {
const row = await config.createRow() const row = await config.createRow();
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const res = await request const res = await request
.get(`/api/views/${table._id}`) .get(`/api/views/${table._id}`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect(res.body.length).toEqual(1) expect(res.body.length).toEqual(1);
expect(res.body[0]._id).toEqual(row._id) expect(res.body[0]._id).toEqual(row._id);
await assertRowUsage(rowUsage) await assertRowUsage(rowUsage);
await assertQueryUsage(queryUsage + 1) await assertQueryUsage(queryUsage + 1);
}) });
it("should throw an error if view doesn't exist", async () => { it("should throw an error if view doesn't exist", async () => {
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
await request await request
.get(`/api/views/derp`) .get(`/api/views/derp`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect(404) .expect(404);
await assertRowUsage(rowUsage) await assertRowUsage(rowUsage);
await assertQueryUsage(queryUsage) await assertQueryUsage(queryUsage);
}) });
it("should be able to run on a view", async () => { it("should be able to run on a view", async () => {
const view = await config.createView() const view = await config.createView();
const row = await config.createRow() const row = await config.createRow();
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
const res = await request const res = await request
.get(`/api/views/${view.name}`) .get(`/api/views/${view.name}`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect(res.body.length).toEqual(1) expect(res.body.length).toEqual(1);
expect(res.body[0]._id).toEqual(row._id) expect(res.body[0]._id).toEqual(row._id);
await assertRowUsage(rowUsage) await assertRowUsage(rowUsage);
await assertQueryUsage(queryUsage + 1) await assertQueryUsage(queryUsage + 1);
}) });
}) });
describe("fetchEnrichedRows", () => { describe("fetchEnrichedRows", () => {
it("should allow enriching some linked rows", async () => { it("should allow enriching some linked rows", async () => {
const { table, firstRow, secondRow } = await tenancy.doInTenant( const { table, firstRow, secondRow } = await tenancy.doInTenant(
config.getTenantId(), config.getTenantId(),
async () => { async () => {
const table = await config.createLinkedTable() const table = await config.createLinkedTable();
const firstRow = await config.createRow({ const firstRow = await config.createRow({
name: "Test Contact", name: "Test Contact",
description: "original description", description: "original description",
tableId: table._id, tableId: table._id,
}) });
const secondRow = await config.createRow({ const secondRow = await config.createRow({
name: "Test 2", name: "Test 2",
description: "og desc", description: "og desc",
link: [{ _id: firstRow._id }], link: [{ _id: firstRow._id }],
tableId: table._id, tableId: table._id,
}) });
return { table, firstRow, secondRow } return { table, firstRow, secondRow };
} }
) );
const rowUsage = await getRowUsage() const rowUsage = await getRowUsage();
const queryUsage = await getQueryUsage() const queryUsage = await getQueryUsage();
// test basic enrichment // test basic enrichment
const resBasic = await request const resBasic = await request
.get(`/api/${table._id}/rows/${secondRow._id}`) .get(`/api/${table._id}/rows/${secondRow._id}`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect(resBasic.body.link[0]._id).toBe(firstRow._id) expect(resBasic.body.link[0]._id).toBe(firstRow._id);
expect(resBasic.body.link[0].primaryDisplay).toBe("Test Contact") expect(resBasic.body.link[0].primaryDisplay).toBe("Test Contact");
// test full enrichment // test full enrichment
const resEnriched = await request const resEnriched = await request
.get(`/api/${table._id}/${secondRow._id}/enrich`) .get(`/api/${table._id}/${secondRow._id}/enrich`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect(resEnriched.body.link.length).toBe(1) expect(resEnriched.body.link.length).toBe(1);
expect(resEnriched.body.link[0]._id).toBe(firstRow._id) expect(resEnriched.body.link[0]._id).toBe(firstRow._id);
expect(resEnriched.body.link[0].name).toBe("Test Contact") expect(resEnriched.body.link[0].name).toBe("Test Contact");
expect(resEnriched.body.link[0].description).toBe("original description") expect(resEnriched.body.link[0].description).toBe("original description");
await assertRowUsage(rowUsage) await assertRowUsage(rowUsage);
await assertQueryUsage(queryUsage + 2) await assertQueryUsage(queryUsage + 2);
}) });
}) });
describe("attachments", () => { describe("attachments", () => {
it("should allow enriching attachment rows", async () => { it("should allow enriching attachment rows", async () => {
const table = await config.createAttachmentTable() const table = await config.createAttachmentTable();
const attachmentId = `${structures.uuid()}.csv` const attachmentId = `${structures.uuid()}.csv`;
const row = await config.createRow({ const row = await config.createRow({
name: "test", name: "test",
description: "test", description: "test",
@ -628,22 +628,22 @@ describe("/rows", () => {
}, },
], ],
tableId: table._id, tableId: table._id,
}) });
// the environment needs configured for this // the environment needs configured for this
await setup.switchToSelfHosted(async () => { await setup.switchToSelfHosted(async () => {
context.doInAppContext(config.getAppId(), async () => { context.doInAppContext(config.getAppId(), async () => {
const enriched = await outputProcessing(table, [row]) const enriched = await outputProcessing(table, [row]);
expect((enriched as Row[])[0].attachment[0].url).toBe( expect((enriched as Row[])[0].attachment[0].url).toBe(
`/files/signed/prod-budi-app-assets/${config.getProdAppId()}/attachments/${attachmentId}` `/files/signed/prod-budi-app-assets/${config.getProdAppId()}/attachments/${attachmentId}`
) );
}) });
}) });
}) });
}) });
describe("exportData", () => { describe("exportData", () => {
it("should allow exporting all columns", async () => { it("should allow exporting all columns", async () => {
const existing = await config.createRow() const existing = await config.createRow();
const res = await request const res = await request
.post(`/api/${table._id}/rows/exportRows?format=json`) .post(`/api/${table._id}/rows/exportRows?format=json`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
@ -651,22 +651,22 @@ describe("/rows", () => {
rows: [existing._id], rows: [existing._id],
}) })
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
const results = JSON.parse(res.text) const results = JSON.parse(res.text);
expect(results.length).toEqual(1) expect(results.length).toEqual(1);
const row = results[0] const row = results[0];
// Ensure all original columns were exported // Ensure all original columns were exported
expect(Object.keys(row).length).toBeGreaterThanOrEqual( expect(Object.keys(row).length).toBeGreaterThanOrEqual(
Object.keys(existing).length Object.keys(existing).length
) );
Object.keys(existing).forEach(key => { Object.keys(existing).forEach((key) => {
expect(row[key]).toEqual(existing[key]) expect(row[key]).toEqual(existing[key]);
}) });
}) });
it("should allow exporting only certain columns", async () => { it("should allow exporting only certain columns", async () => {
const existing = await config.createRow() const existing = await config.createRow();
const res = await request const res = await request
.post(`/api/${table._id}/rows/exportRows?format=json`) .post(`/api/${table._id}/rows/exportRows?format=json`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
@ -675,16 +675,16 @@ describe("/rows", () => {
columns: ["_id"], columns: ["_id"],
}) })
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
const results = JSON.parse(res.text) const results = JSON.parse(res.text);
expect(results.length).toEqual(1) expect(results.length).toEqual(1);
const row = results[0] const row = results[0];
// Ensure only the _id column was exported // Ensure only the _id column was exported
expect(Object.keys(row).length).toEqual(1) expect(Object.keys(row).length).toEqual(1);
expect(row._id).toEqual(existing._id) expect(row._id).toEqual(existing._id);
}) });
}) });
describe("view search", () => { describe("view search", () => {
function priceTable(): Table { function priceTable(): Table {
@ -705,27 +705,27 @@ describe("/rows", () => {
}, },
}, },
}, },
} };
} }
it("returns table rows from view", async () => { it("returns table rows from view", async () => {
const table = await config.createTable(priceTable()) const table = await config.createTable(priceTable());
const rows = [] const rows = [];
for (let i = 0; i < 10; i++) for (let i = 0; i < 10; i++)
rows.push(await config.createRow({ tableId: table._id })) rows.push(await config.createRow({ tableId: table._id }));
const createViewResponse = await config.api.viewV2.create() const createViewResponse = await config.api.viewV2.create();
const response = await request const response = await request
.get(`/api/views/v2/${createViewResponse._id}/search`) .get(`/api/v2/views/${createViewResponse._id}/search`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200);
expect(response.body.rows).toHaveLength(10) expect(response.body.rows).toHaveLength(10);
expect(response.body).toEqual({ expect(response.body).toEqual({
rows: expect.arrayContaining(rows.map(expect.objectContaining)), rows: expect.arrayContaining(rows.map(expect.objectContaining)),
}) });
}) });
}) });
}) });