diff --git a/backend/src/db/migrate/store.js b/backend/src/db/migrate/store.js
index 8bc73b511..02e048c07 100644
--- a/backend/src/db/migrate/store.js
+++ b/backend/src/db/migrate/store.js
@@ -12,6 +12,7 @@ class Store {
[
'CALL db.index.fulltext.createNodeIndex("post_fulltext_search",["Post"],["title", "content"])',
'CALL db.index.fulltext.createNodeIndex("user_fulltext_search",["User"],["name", "slug"])',
+ 'CALL db.index.fulltext.createNodeIndex("tag_fulltext_search",["Tag"],["id"])',
].map(statement => txc.run(statement)),
)
})
diff --git a/backend/src/db/migrate/template.js b/backend/src/db/migrate/template.js
index 9adb0786d..72bfc9b1b 100644
--- a/backend/src/db/migrate/template.js
+++ b/backend/src/db/migrate/template.js
@@ -40,6 +40,7 @@ export async function down(next) {
await transaction.rollback()
// eslint-disable-next-line no-console
console.log('rolled back')
+ throw new Error(error)
} finally {
session.close()
}
diff --git a/backend/src/db/migrations/20200207080200-fulltext_index_for_tags.js b/backend/src/db/migrations/20200207080200-fulltext_index_for_tags.js
new file mode 100644
index 000000000..5064a8b17
--- /dev/null
+++ b/backend/src/db/migrations/20200207080200-fulltext_index_for_tags.js
@@ -0,0 +1,51 @@
+import { getDriver } from '../../db/neo4j'
+
+export const description =
+ 'This migration adds a fulltext index for the tags in order to search for Hasthags.'
+
+export async function up(next) {
+ const driver = getDriver()
+ const session = driver.session()
+ const transaction = session.beginTransaction()
+
+ try {
+ await transaction.run(`
+ CALL db.index.fulltext.createNodeIndex("tag_fulltext_search",["Tag"],["id"])
+ `)
+ await transaction.commit()
+ next()
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.log(error)
+ await transaction.rollback()
+ // eslint-disable-next-line no-console
+ console.log('rolled back')
+ throw new Error(error)
+ } finally {
+ session.close()
+ }
+}
+
+export async function down(next) {
+ const driver = getDriver()
+ const session = driver.session()
+ const transaction = session.beginTransaction()
+
+ try {
+ // Implement your migration here.
+ await transaction.run(`
+ CALL db.index.fulltext.drop("tag_fulltext_search")
+ `)
+ await transaction.commit()
+ next()
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.log(error)
+ await transaction.rollback()
+ // eslint-disable-next-line no-console
+ console.log('rolled back')
+ throw new Error(error)
+ } finally {
+ session.close()
+ }
+}
diff --git a/backend/src/schema/resolvers/searches.js b/backend/src/schema/resolvers/searches.js
index 5c1e43952..3471c783b 100644
--- a/backend/src/schema/resolvers/searches.js
+++ b/backend/src/schema/resolvers/searches.js
@@ -41,6 +41,16 @@ export default {
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()
@@ -55,14 +65,25 @@ export default {
limit,
thisUserId,
})
- return Promise.all([postTransactionResponse, userTransactionResponse])
+ const tagTransactionResponse = transaction.run(tagCypher, {
+ query: myQuery,
+ limit,
+ })
+ return Promise.all([
+ postTransactionResponse,
+ userTransactionResponse,
+ tagTransactionResponse,
+ ])
})
try {
- const [postResults, userResults] = await searchResultPromise
+ const [postResults, userResults, tagResults] = await searchResultPromise
log(postResults)
log(userResults)
- return [...postResults.records, ...userResults.records].map(r => r.get('resource'))
+ log(tagResults)
+ return [...postResults.records, ...userResults.records, ...tagResults.records].map(r =>
+ r.get('resource'),
+ )
} finally {
session.close()
}
diff --git a/backend/src/schema/resolvers/searches.spec.js b/backend/src/schema/resolvers/searches.spec.js
index c454833b8..081d71e55 100644
--- a/backend/src/schema/resolvers/searches.spec.js
+++ b/backend/src/schema/resolvers/searches.spec.js
@@ -41,6 +41,9 @@ const searchQuery = gql`
slug
name
}
+ ... on Tag {
+ id
+ }
}
}
`
@@ -439,6 +442,28 @@ und hinter tausend Stäben keine Welt.`,
})
})
})
+
+ describe('adding a tag', () => {
+ beforeAll(async () => {
+ await Factory.build('tag', { id: 'myHashtag' })
+ })
+
+ describe('query the first four characters of the tag', () => {
+ it('finds the tag', async () => {
+ variables = { query: 'myha' }
+ await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+ data: {
+ findResources: [
+ {
+ __typename: 'Tag',
+ id: 'myHashtag',
+ },
+ ],
+ },
+ })
+ })
+ })
+ })
})
})
})
diff --git a/backend/src/schema/types/type/Search.gql b/backend/src/schema/types/type/Search.gql
index 2c22fa61f..1ce38001d 100644
--- a/backend/src/schema/types/type/Search.gql
+++ b/backend/src/schema/types/type/Search.gql
@@ -1,4 +1,4 @@
-union SearchResult = Post | User
+union SearchResult = Post | User | Tag
type Query {
findResources(query: String!, limit: Int = 5): [SearchResult]!
diff --git a/webapp/components/Hashtag/Hashtag.vue b/webapp/components/Hashtag/Hashtag.vue
index 35762c81c..44e5319f0 100644
--- a/webapp/components/Hashtag/Hashtag.vue
+++ b/webapp/components/Hashtag/Hashtag.vue
@@ -1,5 +1,5 @@
-
+