pages are counted correctly

This commit is contained in:
Moriz Wahl 2020-04-14 21:41:45 +02:00
parent 40c35599f6
commit 7562af227e
5 changed files with 136 additions and 183 deletions

View File

@ -19,7 +19,8 @@ const cypherTemplate = (setup) => `
const simpleWhereClause =
'WHERE score >= 0.0 AND NOT (resource.deleted = true OR resource.disabled = true)'
const postWhereClause = `WHERE score >= 0.0 AND NOT (
const postWhereClause = `WHERE score >= 0.0
AND NOT (
author.deleted = true OR author.disabled = true
OR resource.deleted = true OR resource.disabled = true
OR (:User {id: $userId})-[:MUTED]->(author)
@ -66,26 +67,22 @@ const searchHashtagsSetup = {
resultKeyName: 'hashtags',
}
const countSetup = {
returnClause: 'toString(size(collect(resource)))',
limit: '',
}
const countUsersSetup = {
...searchUsersSetup,
...{
returnClause: 'toString(size(collect(resource)))',
limit: '',
},
...countSetup,
}
const countPostsSetup = {
...searchPostsSetup,
...{
returnClause: 'toString(size(collect(resource)))',
limit: '',
},
...countSetup,
}
const countHashtagsSetup = {
...searchHashtagsSetup,
...{
returnClause: 'toString(size(collect(resource)))',
limit: '',
},
...countSetup,
}
const searchResultPromise = async (session, setup, params) => {
@ -94,23 +91,20 @@ const searchResultPromise = async (session, setup, params) => {
})
}
const getSearchResults = async (context, setup, params) => {
const session = context.driver.session()
try {
const results = await searchResultPromise(session, setup, params)
log(results)
return results.records.map((r) => r.get('result'))
} finally {
session.close()
}
const searchResultCallback = (result) => {
return result.records.map((r) => r.get('result'))
}
const countSearchResults = async (context, setup, params) => {
const countResultCallback = (result) => {
return result.records[0].get('result')
}
const getSearchResults = async (context, setup, params, resultCallback = searchResultCallback) => {
const session = context.driver.session()
try {
const results = await searchResultPromise(session, setup, params)
log(results)
return results.records[0].get('result')
return resultCallback(results)
} finally {
session.close()
}
@ -127,15 +121,19 @@ export default {
Query: {
searchPosts: async (_parent, args, context, _resolveInfo) => {
const { query, postsOffset, firstPosts } = args
// const { id: userId } = context.user
const userId = '73'
const { id: userId } = context.user
return {
postCount: countSearchResults(context, countPostsSetup, {
query: queryString(query),
skip: 0,
userId,
}),
postCount: getSearchResults(
context,
countPostsSetup,
{
query: queryString(query),
skip: 0,
userId,
},
countResultCallback,
),
posts: getSearchResults(context, searchPostsSetup, {
query: queryString(query),
skip: postsOffset,
@ -147,10 +145,15 @@ export default {
searchUsers: async (_parent, args, context, _resolveInfo) => {
const { query, usersOffset, firstUsers } = args
return {
userCount: countSearchResults(context, countUsersSetup, {
query: queryString(query),
skip: 0,
}),
userCount: getSearchResults(
context,
countUsersSetup,
{
query: queryString(query),
skip: 0,
},
countResultCallback,
),
users: getSearchResults(context, searchUsersSetup, {
query: queryString(query),
skip: usersOffset,
@ -161,10 +164,15 @@ export default {
searchHashtags: async (_parent, args, context, _resolveInfo) => {
const { query, hashtagsOffset, firstHashtags } = args
return {
hashtagCount: countSearchResults(context, countHashtagsSetup, {
query: queryString(query),
skip: 0,
}),
hashtagCount: getSearchResults(
context,
countHashtagsSetup,
{
query: queryString(query),
skip: 0,
},
countResultCallback,
),
hashtags: getSearchResults(context, searchHashtagsSetup, {
query: queryString(query),
skip: hashtagsOffset,
@ -187,83 +195,24 @@ export default {
userId,
} */
const postCypher = `
CALL db.index.fulltext.queryNodes('post_fulltext_search', $query)
YIELD node as resource, score
MATCH (resource)<-[:WROTE]-(author:User)
WHERE score >= 0.0
AND NOT (
author.deleted = true OR author.disabled = true
OR resource.deleted = true OR resource.disabled = true
OR (:User {id: $userId})-[:MUTED]->(author)
)
WITH resource, author,
[(resource)<-[:COMMENTS]-(comment:Comment) | comment] as comments,
[(resource)<-[:SHOUTED]-(user:User) | user] as shouter
RETURN resource {
.*,
__typename: labels(resource)[0],
author: properties(author),
commentsCount: toString(size(comments)),
shoutedCount: toString(size(shouter))
}
LIMIT $limit
`
const userCypher = `
CALL db.index.fulltext.queryNodes('user_fulltext_search', $query)
YIELD node as resource, score
MATCH (resource)
WHERE score >= 0.0
AND NOT (resource.deleted = true OR resource.disabled = true)
RETURN resource {.*, __typename: labels(resource)[0]}
LIMIT $limit
`
const tagCypher = `
CALL db.index.fulltext.queryNodes('tag_fulltext_search', $query)
YIELD node as resource, score
MATCH (resource)
WHERE score >= 0.0
AND NOT (resource.deleted = true OR resource.disabled = true)
RETURN resource {.*, __typename: labels(resource)[0]}
LIMIT $limit
`
const myQuery = queryString(query)
const session = context.driver.session()
const searchResultPromise = session.readTransaction(async (transaction) => {
const postTransactionResponse = transaction.run(postCypher, {
query: myQuery,
return [
...(await getSearchResults(context, searchPostsSetup, {
query: queryString(query),
skip: 0,
limit,
userId,
})
const userTransactionResponse = transaction.run(userCypher, {
query: myQuery,
})),
...(await getSearchResults(context, searchUsersSetup, {
query: queryString(query),
skip: 0,
limit,
})
const tagTransactionResponse = transaction.run(tagCypher, {
query: myQuery,
})),
...(await getSearchResults(context, searchHashtagsSetup, {
query: queryString(query),
skip: 0,
limit,
})
return Promise.all([
postTransactionResponse,
userTransactionResponse,
tagTransactionResponse,
])
})
try {
const [postResults, userResults, tagResults] = await searchResultPromise
log(postResults)
log(userResults)
log(tagResults)
return [...postResults.records, ...userResults.records, ...tagResults.records].map((r) =>
r.get('resource'),
)
} finally {
session.close()
}
})),
]
},
},
}

View File

@ -24,12 +24,12 @@ beforeAll(async () => {
})
afterAll(async () => {
await cleanDatabase()
// await cleanDatabase()
})
const searchQuery = gql`
query($query: String!) {
findResources(query: $query, limit: 5) {
searchResults(query: $query, limit: 5) {
__typename
... on Post {
id
@ -65,7 +65,7 @@ describe('resolvers/searches', () => {
variables = { query: 'John' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
searchResults: [
{
id: 'a-user',
name: 'John Doe',
@ -95,7 +95,7 @@ describe('resolvers/searches', () => {
variables = { query: 'beitrag' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
searchResults: [
{
__typename: 'Post',
id: 'a-post',
@ -114,7 +114,7 @@ describe('resolvers/searches', () => {
variables = { query: 'BEITRAG' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
searchResults: [
{
__typename: 'Post',
id: 'a-post',
@ -132,7 +132,7 @@ describe('resolvers/searches', () => {
it('returns empty search results', async () => {
await expect(
query({ query: searchQuery, variables: { query: 'Unfug' } }),
).resolves.toMatchObject({ data: { findResources: [] } })
).resolves.toMatchObject({ data: { searchResults: [] } })
})
})
@ -189,7 +189,7 @@ und hinter tausend Stäben keine Welt.`,
variables = { query: 'beitrag' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: expect.arrayContaining([
searchResults: expect.arrayContaining([
{
__typename: 'Post',
id: 'a-post',
@ -216,7 +216,7 @@ und hinter tausend Stäben keine Welt.`,
variables = { query: 'tee-ei' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
searchResults: [
{
__typename: 'Post',
id: 'g-post',
@ -235,7 +235,7 @@ und hinter tausend Stäben keine Welt.`,
variables = { query: '„teeei“' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
searchResults: [
{
__typename: 'Post',
id: 'g-post',
@ -256,7 +256,7 @@ und hinter tausend Stäben keine Welt.`,
variables = { query: '(a - b)²' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
searchResults: [
{
__typename: 'Post',
id: 'c-post',
@ -277,7 +277,7 @@ und hinter tausend Stäben keine Welt.`,
variables = { query: '(a-b)²' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
searchResults: [
{
__typename: 'Post',
id: 'c-post',
@ -298,7 +298,7 @@ und hinter tausend Stäben keine Welt.`,
variables = { query: '+ b² 2.' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
searchResults: [
{
__typename: 'Post',
id: 'c-post',
@ -321,7 +321,7 @@ und hinter tausend Stäben keine Welt.`,
variables = { query: 'der panther' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
searchResults: [
{
__typename: 'Post',
id: 'd-post',
@ -349,7 +349,7 @@ und hinter tausend Stäben keine Welt.`,
variables = { query: 'Vorü Subs' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: expect.arrayContaining([
searchResults: expect.arrayContaining([
{
__typename: 'Post',
id: 'd-post',
@ -395,7 +395,7 @@ und hinter tausend Stäben keine Welt.`,
variables = { query: '-maria-' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: expect.arrayContaining([
searchResults: expect.arrayContaining([
{
__typename: 'User',
id: 'c-user',
@ -440,7 +440,7 @@ und hinter tausend Stäben keine Welt.`,
variables = { query: 'beitrag' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: expect.not.arrayContaining([
searchResults: expect.not.arrayContaining([
{
__typename: 'Post',
id: 'muted-post',
@ -465,7 +465,7 @@ und hinter tausend Stäben keine Welt.`,
variables = { query: 'myha' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
searchResults: [
{
__typename: 'Tag',
id: 'myHashtag',

View File

@ -11,7 +11,7 @@ import { user } from '~/components/UserTeaser/UserTeaser.story.js'
helpers.init()
const postMock = fields => {
const postMock = (fields) => {
return {
...post,
id: faker.random.uuid(),
@ -24,7 +24,7 @@ const postMock = fields => {
}
}
const userMock = fields => {
const userMock = (fields) => {
return {
...user,
id: faker.random.uuid(),

View File

@ -15,7 +15,7 @@
<post-teaser :post="resource" />
</masonry-grid-item>
</masonry-grid>
{{postPage}}
{{ postPage }}
<pagination-buttons
:hasNext="hasMorePosts"
:hasPrevious="hasPreviousPosts"
@ -73,7 +73,6 @@ export default {
PostTeaser,
PaginationButtons,
UserTeaser,
searchHashtags,
HcHashtag,
},
props: {
@ -101,10 +100,6 @@ export default {
postsOffset: 0,
usersOffset: 0,
hashtagsOffset: 0,
hasMorePosts: false,
hasMoreUsers: false,
hasMoreHashtags: false,
}
},
computed: {
@ -125,17 +120,17 @@ export default {
{
type: 'Post',
title: `${this.postCount} ${this.$t('search.heading.Post')}`,
disabled: this.postCount == 0,
disabled: this.postCount === 0,
},
{
type: 'User',
title: `${this.userCount} ${this.$t('search.heading.User')}`,
disabled: this.userCount == 0,
disabled: this.userCount === 0,
},
{
{
type: 'Hashtag',
title: `${this.hashtagCount} ${this.$t('search.heading.Tag')}`,
disabled: this.hashtagCount == 0,
disabled: this.hashtagCount === 0,
},
]
},
@ -148,33 +143,42 @@ export default {
hasPreviousHashtags() {
return this.hashtagsOffset > 0
},
hasMorePosts() {
return (this.postPage + 1) * this.pageSize <= this.postCount
},
hasMoreUsers() {
return (this.userPage + 1) * this.pageSize <= this.userCount
},
hasMoreHashtags() {
return (this.hashtagPage + 1) * this.pageSize <= this.hashtagCount
},
},
methods: {
switchTab(tab) {
this.activeTab = tab
},
previousPosts() {
this.postsOffset = this.postPage * this.pageSize
this.postPage--
this.postsOffset = this.postPage * this.pageSize
},
nextPosts() {
this.postsOffset += this.pageSize
this.postPage++
},
previousUsers() {
this.usersOffset = Math.max(this.usersOffset - this.pageSize, 0)
this.userPage--
this.usersOffset = this.userPage * this.pageSize
},
nextUsers() {
this.usersOffset += this.pageSize
this.userPage++
},
previousHashtags() {
this.usersOffset = Math.max(this.usersOffset - this.pageSize, 0)
this.hashtagPage--
this.hashtagsOffset = this.hashtagPage * this.pageSize
},
nextHashtags() {
this.usersOffset += this.pageSize
this.hashtagsOffset += this.pageSize
this.hashtagPage++
},
},
@ -197,7 +201,6 @@ export default {
update({ searchPosts }) {
this.posts = searchPosts.posts
this.postCount = searchPosts.postCount
this.hasMorePosts = this.postCount >= (this.pageSize * this.postPage)
if (searchPosts.posts.length) this.activeTab = 'Post'
},
fetchPolicy: 'cache-and-network',
@ -220,33 +223,36 @@ export default {
update({ searchUsers }) {
this.users = searchUsers.users
this.userCount = searchUsers.userCount
this.hasMoreUsers = this.users.length >= this.pageSize
if (!searchPosts.posts.length && searchUsers.users.length) this.activeTab = 'User'
},
fetchPolicy: 'cache-and-network',
},
searchHashtags: {
query() {
return searchHashtags
},
variables() {
const { firstHashtags, hashtagsOffset, search } = this
return {
query: search,
firstHashtags,
hashtagsOffset,
}
},
skip() {
return !this.search
},
update({ searchHashtags }) {
this.hashtags = searchHashtags.hashtags
this.hashtagCount = searchHashtags.hashtagCount
this.hasMoreHashtags = this.hashtags.length >= this.pageSize
if (!searchPosts.posts.length && !searchUsers.users.length && searchHashtags.hashtags.length) this.activeTab = 'Hashtag'
},
fetchPolicy: 'cache-and-network',
query() {
return searchHashtags
},
variables() {
const { firstHashtags, hashtagsOffset, search } = this
return {
query: search,
firstHashtags,
hashtagsOffset,
}
},
skip() {
return !this.search
},
update({ searchHashtags }) {
this.hashtags = searchHashtags.hashtags
this.hashtagCount = searchHashtags.hashtagCount
if (
!searchPosts.posts.length &&
!searchUsers.users.length &&
searchHashtags.hashtags.length
)
this.activeTab = 'Hashtag'
},
fetchPolicy: 'cache-and-network',
},
},
}

View File

@ -7,8 +7,7 @@ export const searchQuery = gql`
${tagsCategoriesAndPinnedFragment}
query($query: String!) {
searchResults(query: $query, limit: 5)
{
searchResults(query: $query, limit: 5) {
__typename
... on Post {
...post
@ -38,16 +37,16 @@ export const searchPosts = gql`
searchPosts(query: $query, firstPosts: $firstPosts, postsOffset: $postsOffset) {
postCount
posts {
__typename
...post
...tagsCategoriesAndPinned
commentsCount
shoutedCount
author {
...user
__typename
...post
...tagsCategoriesAndPinned
commentsCount
shoutedCount
author {
...user
}
}
}
}
}
`
@ -58,21 +57,20 @@ export const searchUsers = gql`
searchUsers(query: $query, firstUsers: $firstUsers, usersOffset: $usersOffset) {
userCount
users {
__typename
...user
__typename
...user
}
}
}
`
export const searchHashtags = gql`
query($query: String!, $firstHashtags: Int, $hashtagsOffset: Int) {
searchHashtags(query: $query, firstHashtags: $firstHashtags, hashtagsOffset: $hashtagsOffset) {
hashtagCount
hashtags {
__typename
id
__typename
id
}
}
}