2019-03-09 05:51:02 +00:00
const _ = require ( 'lodash' )
2019-03-09 23:43:32 +00:00
const tsquery = require ( 'pg-tsquery' ) ( )
2019-03-09 05:51:02 +00:00
module . exports = {
2019-03-09 23:43:32 +00:00
async activate ( ) {
2019-03-09 05:51:02 +00:00
// not used
} ,
2019-03-09 23:43:32 +00:00
async deactivate ( ) {
2019-03-09 05:51:02 +00:00
// not used
} ,
/ * *
* INIT
* /
2019-03-09 23:43:32 +00:00
async init ( ) {
2019-03-10 06:28:58 +00:00
// -> Create Search Index
2019-03-09 23:43:32 +00:00
const indexExists = await WIKI . models . knex . schema . hasTable ( 'pagesVector' )
if ( ! indexExists ) {
await WIKI . models . knex . schema . createTable ( 'pagesVector' , table => {
table . increments ( )
table . string ( 'path' )
table . string ( 'locale' )
table . string ( 'title' )
table . string ( 'description' )
2019-03-10 06:28:58 +00:00
table . specificType ( 'tokens' , 'TSVECTOR' )
2019-03-09 23:43:32 +00:00
} )
}
2019-03-10 06:28:58 +00:00
// -> Create Words Index
const wordsExists = await WIKI . models . knex . schema . hasTable ( 'pagesWords' )
if ( ! wordsExists ) {
await WIKI . models . knex . raw ( `
CREATE TABLE "pagesWords" AS SELECT word FROM ts _stat (
'SELECT to_tsvector(' 'simple' ', pages."title") || to_tsvector(' 'simple' ', pages."description") || to_tsvector(' 'simple' ', pages."content") FROM pages WHERE pages."isPublished" AND NOT pages."isPrivate"'
) ` )
await WIKI . models . knex . raw ( 'CREATE EXTENSION IF NOT EXISTS pg_trgm' )
await WIKI . models . knex . raw ( ` CREATE INDEX "pageWords_idx" ON "pagesWords" USING GIN (word gin_trgm_ops) ` )
}
2019-03-09 05:51:02 +00:00
} ,
/ * *
* QUERY
*
* @ param { String } q Query
* @ param { Object } opts Additional options
* /
async query ( q , opts ) {
2019-03-09 23:43:32 +00:00
try {
2019-03-10 06:28:58 +00:00
let suggestions = [ ]
2019-03-09 23:43:32 +00:00
const results = await WIKI . models . knex . raw ( `
SELECT id , path , locale , title , description
FROM "pagesVector" , to _tsquery ( ? ) query
2019-03-10 06:28:58 +00:00
WHERE query @ @ "tokens"
ORDER BY ts _rank ( tokens , query ) DESC
2019-03-09 23:43:32 +00:00
` , [tsquery(q)])
2019-03-10 06:28:58 +00:00
if ( results . rows . length < 5 ) {
const suggestResults = await WIKI . models . knex . raw ( ` SELECT word, word <-> ? AS rank FROM "pagesWords" WHERE similarity(word, ?) > 0.2 ORDER BY rank LIMIT 5; ` , [ q , q ] )
suggestions = suggestResults . rows . map ( r => r . word )
}
2019-03-09 23:43:32 +00:00
return {
results : results . rows ,
2019-03-10 06:28:58 +00:00
suggestions ,
2019-03-09 23:43:32 +00:00
totalHits : results . rows . length
}
} catch ( err ) {
WIKI . logger . warn ( 'Search Engine Error:' )
WIKI . logger . warn ( err )
}
2019-03-09 05:51:02 +00:00
} ,
/ * *
* CREATE
*
* @ param { Object } page Page to create
* /
async created ( page ) {
2019-03-09 23:43:32 +00:00
await WIKI . models . knex . raw ( `
2019-03-10 06:28:58 +00:00
INSERT INTO "pagesVector" ( path , locale , title , description , tokens ) VALUES (
'?' , '?' , '?' , '?' , ( setweight ( to _tsvector ( '${this.config.dictLanguage}' , '?' ) , 'A' ) || setweight ( to _tsvector ( '${this.config.dictLanguage}' , '?' ) , 'B' ) || setweight ( to _tsvector ( '${this.config.dictLanguage}' , '?' ) , 'C' ) )
2019-03-09 23:43:32 +00:00
)
` , [page.path, page.locale, page.title, page.description, page.title, page.description, page.content])
2019-03-09 05:51:02 +00:00
} ,
/ * *
* UPDATE
*
* @ param { Object } page Page to update
* /
async updated ( page ) {
2019-03-09 23:43:32 +00:00
await WIKI . models . knex . raw ( `
UPDATE "pagesVector" SET
title = '?' ,
description = '?' ,
2019-03-10 06:28:58 +00:00
tokens = ( setweight ( to _tsvector ( '${this.config.dictLanguage}' , '?' ) , 'A' ) ||
setweight ( to _tsvector ( '${this.config.dictLanguage}' , '?' ) , 'B' ) ||
setweight ( to _tsvector ( '${this.config.dictLanguage}' , '?' ) , 'C' ) )
2019-03-09 23:43:32 +00:00
WHERE path = '?' AND locale = '?' LIMIT 1
` , [page.title, page.description, page.title, page.description, page.content, page.path, page.locale])
2019-03-09 05:51:02 +00:00
} ,
/ * *
* DELETE
*
* @ param { Object } page Page to delete
* /
async deleted ( page ) {
2019-03-09 23:43:32 +00:00
await WIKI . models . knex ( 'pagesVector' ) . where ( {
locale : page . locale ,
path : page . path
} ) . del ( ) . limit ( 1 )
2019-03-09 05:51:02 +00:00
} ,
/ * *
* RENAME
*
* @ param { Object } page Page to rename
* /
async renamed ( page ) {
2019-03-09 23:43:32 +00:00
await WIKI . models . knex ( 'pagesVector' ) . where ( {
locale : page . locale ,
path : page . sourcePath
} ) . update ( {
locale : page . locale ,
path : page . destinationPath
} ) . limit ( 1 )
2019-03-09 05:51:02 +00:00
} ,
/ * *
* REBUILD INDEX
* /
async rebuild ( ) {
2019-03-09 23:43:32 +00:00
await WIKI . models . knex ( 'pagesVector' ) . truncate ( )
await WIKI . models . knex . raw ( `
2019-03-10 06:28:58 +00:00
INSERT INTO "pagesVector" ( path , locale , title , description , "tokens" )
SELECT path , "localeCode" AS locale , title , description ,
( setweight ( to _tsvector ( '${this.config.dictLanguage}' , title ) , 'A' ) ||
setweight ( to _tsvector ( '${this.config.dictLanguage}' , description ) , 'B' ) ||
setweight ( to _tsvector ( '${this.config.dictLanguage}' , content ) , 'C' ) ) AS tokens
2019-03-09 23:43:32 +00:00
FROM "pages"
WHERE pages . "isPublished" AND NOT pages . "isPrivate" ` )
2019-03-09 05:51:02 +00:00
}
}