Merge branch 'search-improves'

This commit is contained in:
Tom Moor 2018-08-04 21:28:52 -07:00
commit ad2d1a15bb
4 changed files with 129 additions and 11 deletions

View File

@ -5,7 +5,7 @@ import keydown from 'react-keydown';
import Waypoint from 'react-waypoint';
import { observable, action } from 'mobx';
import { observer, inject } from 'mobx-react';
import { SearchResult } from 'types';
import type { SearchResult } from 'types';
import _ from 'lodash';
import DocumentsStore, {
DEFAULT_PAGINATION_LIMIT,

View File

@ -3,7 +3,7 @@ import TestServer from 'fetch-test-server';
import app from '..';
import { Document, View, Star, Revision } from '../models';
import { flushdb, seed } from '../test/support';
import { buildShare, buildUser } from '../test/factories';
import { buildShare, buildUser, buildDocument } from '../test/factories';
const server = new TestServer(app.callback());
@ -231,6 +231,68 @@ describe('#documents.search', async () => {
expect(body.data[0].document.text).toEqual('# Much guidance');
});
it('should return results in ranked order', async () => {
const { user } = await seed();
const firstResult = await buildDocument({
title: 'search term',
text: 'random text',
userId: user.id,
teamId: user.teamId,
});
const secondResult = await buildDocument({
title: 'random text',
text: 'search term',
userId: user.id,
teamId: user.teamId,
});
const res = await server.post('/api/documents.search', {
body: { token: user.getJwtToken(), query: 'search term' },
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.length).toEqual(2);
expect(body.data[0].document.id).toEqual(firstResult.id);
expect(body.data[1].document.id).toEqual(secondResult.id);
});
it('should return draft documents created by user', async () => {
const { user } = await seed();
await buildDocument({
title: 'search term',
text: 'search term',
publishedAt: null,
userId: user.id,
teamId: user.teamId,
});
const res = await server.post('/api/documents.search', {
body: { token: user.getJwtToken(), query: 'search term' },
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.length).toEqual(1);
expect(body.data[0].document.text).toEqual('search term');
});
it('should not return draft documents created by other users', async () => {
const { user } = await seed();
await buildDocument({
title: 'search term',
text: 'search term',
publishedAt: null,
teamId: user.teamId,
});
const res = await server.post('/api/documents.search', {
body: { token: user.getJwtToken(), query: 'search term' },
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.length).toEqual(0);
});
it('should require authentication', async () => {
const res = await server.post('/api/documents.search');
const body = await res.json();

View File

@ -7,7 +7,7 @@ import Plain from 'slate-plain-serializer';
import Sequelize from 'sequelize';
import isUUID from 'validator/lib/isUUID';
import { Collection } from '../models';
import { Collection, User } from '../models';
import { DataTypes, sequelize } from '../sequelize';
import events from '../events';
import parseTitle from '../../shared/utils/parseTitle';
@ -211,8 +211,11 @@ Document.searchForUser = async (
FROM documents
WHERE "searchVector" @@ plainto_tsquery('english', :query) AND
"teamId" = '${user.teamId}'::uuid AND
"deletedAt" IS NULL
ORDER BY "searchRanking", "updatedAt" DESC
"deletedAt" IS NULL AND
("publishedAt" IS NOT NULL OR "createdById" = '${user.id}')
ORDER BY
"searchRanking" DESC,
"updatedAt" DESC
LIMIT :limit
OFFSET :offset;
`;
@ -227,12 +230,15 @@ Document.searchForUser = async (
});
// Second query to get associated document data
const withViewsScope = { method: ['withViews', user.id] };
const documents = await Document.scope(
'defaultScope',
withViewsScope
).findAll({
const documents = await Document.scope({
method: ['withViews', user.id],
}).findAll({
where: { id: map(results, 'id') },
include: [
{ model: Collection, as: 'collection' },
{ model: User, as: 'createdBy', paranoid: false },
{ model: User, as: 'updatedBy', paranoid: false },
],
});
return map(results, result => ({

View File

@ -1,5 +1,5 @@
// @flow
import { Share, Team, User } from '../models';
import { Share, Team, User, Document, Collection } from '../models';
import uuid from 'uuid';
let count = 0;
@ -45,3 +45,53 @@ export async function buildUser(overrides: Object = {}) {
...overrides,
});
}
export async function buildCollection(overrides: Object = {}) {
count++;
if (!overrides.teamId) {
const team = await buildTeam();
overrides.teamId = team.id;
}
if (!overrides.userId) {
const user = await buildUser();
overrides.userId = user.id;
}
return Collection.create({
name: 'Test Collection',
description: 'Test collection description',
creatorId: overrides.userId,
type: 'atlas',
...overrides,
});
}
export async function buildDocument(overrides: Object = {}) {
count++;
if (!overrides.teamId) {
const team = await buildTeam();
overrides.teamId = team.id;
}
if (!overrides.userId) {
const user = await buildUser();
overrides.userId = user.id;
}
if (!overrides.atlasId) {
const collection = await buildCollection(overrides);
overrides.atlasId = collection.id;
}
return Document.create({
title: `Document ${count}`,
text: 'This is the text in an example document',
publishedAt: new Date(),
lastModifiedById: overrides.userId,
createdById: overrides.userId,
...overrides,
});
}