Change url version path
This commit is contained in:
parent
d981ad039d
commit
63f181649a
2 changed files with 283 additions and 283 deletions
|
@ -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;
|
||||||
|
|
|
@ -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)),
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
Loading…
Reference in a new issue