Merge branch 'search-improves'
This commit is contained in:
commit
ad2d1a15bb
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 => ({
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
Reference in New Issue