Add score column to search_queries (#6253)

* Add score column to search_queries

* Allow user to record search score
This commit is contained in:
Tom Moor
2023-12-06 08:37:46 -05:00
committed by GitHub
parent f494e28ce9
commit cf64da1050
6 changed files with 119 additions and 1 deletions

View File

@@ -0,0 +1,13 @@
"use strict";
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.addColumn("search_queries", "score", {
type: Sequelize.INTEGER,
allowNull: true,
});
},
async down(queryInterface) {
await queryInterface.removeColumn("search_queries", "score");
},
};

View File

@@ -30,12 +30,27 @@ class SearchQuery extends Model {
@CreatedAt
createdAt: Date;
/**
* Where the query originated.
*/
@Column(DataType.ENUM("slack", "app", "api"))
source: string;
/**
* The number of results returned for this query.
*/
@Column
results: number;
/**
* User score for the results for this query, -1 for negative, 1 for positive, null for neutral.
*/
@Column
score: number;
/**
* The query string, automatically truncated to 255 characters.
*/
@Column(DataType.STRING)
set query(value: string) {
this.setDataValue("query", value.substring(0, 255));

View File

@@ -5,5 +5,6 @@ export default function presentSearchQuery(searchQuery: SearchQuery) {
id: searchQuery.id,
query: searchQuery.query,
createdAt: searchQuery.createdAt,
score: searchQuery.score,
};
}

View File

@@ -12,3 +12,12 @@ export const SearchesDeleteSchema = BaseSchema.extend({
});
export type SearchesDeleteReq = z.infer<typeof SearchesDeleteSchema>;
export const SearchesUpdateSchema = BaseSchema.extend({
body: z.object({
id: z.string().uuid(),
score: z.number().min(-1).max(1),
}),
});
export type SearchesUpdateReq = z.infer<typeof SearchesUpdateSchema>;

View File

@@ -44,6 +44,57 @@ describe("#searches.list", () => {
});
});
describe("#searches.update", () => {
let user: User;
let searchQuery: SearchQuery;
beforeEach(async () => {
user = await buildUser();
searchQuery = await buildSearchQuery({
userId: user.id,
teamId: user.teamId,
});
});
it("should fail with status 400 bad request when an invalid id is provided", async () => {
const res = await server.post("/api/searches.update", {
body: {
token: user.getJwtToken(),
id: "id",
score: 1,
},
});
expect(res.status).toEqual(400);
});
it("should fail with status 400 bad request when an invalid score is provided", async () => {
const res = await server.post("/api/searches.update", {
body: {
token: user.getJwtToken(),
id: searchQuery.id,
score: 2,
},
});
expect(res.status).toEqual(400);
});
it("should succeed with status 200 ok and successfully update the query", async () => {
const res = await server.post("/api/searches.update", {
body: {
token: user.getJwtToken(),
id: searchQuery.id,
score: 1,
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.score).toEqual(1);
});
});
describe("#searches.delete", () => {
let user: User;
let searchQuery: SearchQuery;

View File

@@ -1,5 +1,6 @@
import Router from "koa-router";
import auth from "@server/middlewares/authentication";
import { transaction } from "@server/middlewares/transaction";
import validate from "@server/middlewares/validate";
import { SearchQuery } from "@server/models";
import { presentSearchQuery } from "@server/presenters";
@@ -27,13 +28,41 @@ router.post("searches.list", auth(), pagination(), async (ctx: APIContext) => {
};
});
router.post(
"searches.update",
auth(),
validate(T.SearchesUpdateSchema),
transaction(),
async (ctx: APIContext<T.SearchesUpdateReq>) => {
const { id, score } = ctx.input.body;
const { user } = ctx.state.auth;
const { transaction } = ctx.state;
const search = await SearchQuery.findOne({
where: {
id,
userId: user.id,
},
lock: transaction.LOCK.UPDATE,
rejectOnEmpty: true,
transaction,
});
search.score = score;
await search.save({ transaction });
ctx.body = {
data: presentSearchQuery(search),
};
}
);
router.post(
"searches.delete",
auth(),
validate(T.SearchesDeleteSchema),
async (ctx: APIContext<T.SearchesDeleteReq>) => {
const { id, query } = ctx.input.body;
const { user } = ctx.state.auth;
await SearchQuery.destroy({