fix: standard style fixes

pull/6038/head
dzruyk 4 years ago
parent cf41b97d2d
commit c47e63383e

@ -1,6 +1,5 @@
const stream = require('stream') const stream = require('stream')
const Promise = require('bluebird') const Promise = require('bluebird')
const pipeline = Promise.promisify(stream.pipeline)
const _ = require('lodash') const _ = require('lodash')
const matchquery = require('./match-query') const matchquery = require('./match-query')
@ -94,7 +93,7 @@ module.exports = {
description = ?, description = ?,
content = ? content = ?
WHERE path = ? AND locale = ? WHERE path = ? AND locale = ?
`, [page.title, page.description, page.safeContent, page.path, page.localeCode]) `, [page.title, page.description, page.safeContent, page.path, page.localeCode])
}, },
/** /**
* DELETE * DELETE

@ -1,5 +1,4 @@
const _ = require('lodash') const _ = require('lodash')
/* /*
* Full text query preprocessor for sqlite3 FTS similar to pg-tsquery. * Full text query preprocessor for sqlite3 FTS similar to pg-tsquery.
* Converts input string into internal sqlite match query * Converts input string into internal sqlite match query
@ -16,20 +15,20 @@ const _ = require('lodash')
| `foo*,bar* bana*` | `(foo *) or (bar * bana*)` | | `foo*,bar* bana*` | `(foo *) or (bar * bana*)` |
*/ */
module.exports = { module.exports = {
parse(input) { parse(input) {
let p = new MatchQueryParser() const p = new MatchQueryParser()
let v = p.parse(input) const v = p.parse(input)
let negated = v.negated const negated = v.negated
/* /*
* Since sqlite does not support top level negated MATCH queries * Since sqlite does not support top level negated MATCH queries
* calling function need to create negated sql query like * calling function need to create negated sql query like
* select * not in (select ... match) * select * not in (select ... match)
*/ */
if (negated) if (negated) {
v.negated = false v.negated = false
}
return { return {
negated, negated,
str: v.toString() str: v.toString()
@ -37,17 +36,15 @@ module.exports = {
} }
} }
class Token class Token {
{
constructor(type, value) { constructor(type, value) {
this.type = type this.type = type
this.value = value this.value = value
} }
} }
class Node class Node {
{ constructor({ type, value, negated = false, args, parNode = undefined, star = false }) {
constructor({type, value, negated = false, args, parNode = undefined, star = false}) {
this.type = type this.type = type
this.value = value this.value = value
this.negated = negated this.negated = negated
@ -61,92 +58,98 @@ class Node
toString() { toString() {
let s = '' let s = ''
if (this.type == 'id') { if (this.type === 'id') {
s = `"${this.value}"` s = `"${this.value}"`
if (this.star) if (this.star) {
s += '*' s += '*'
}
} else { } else {
let separator = '' let separator = ''
if (this.type == 'and') { if (this.type === 'and') {
separator = ' AND ' separator = ' AND '
} else if (this.type == 'or') { } else if (this.type === 'or') {
separator = ' OR ' separator = ' OR '
} else { } else {
throw new Error('should not reach') throw new Error('should not reach')
} }
if (this.args && this.args.length > 0) if (this.args && this.args.length > 0) {
this.args.forEach(item => { this.args.forEach(item => {
if (s != '') { if (s !== '') {
if (item.negated && this.type == 'and') if (item.negated && this.type === 'and') {
s += ' ' s += ' '
else } else {
s += separator s += separator
}
} }
s += item s += item
}) })
if (this.parNode !== undefined || this.negated) }
if (this.parNode !== undefined || this.negated) {
s = `(${s})` s = `(${s})`
}
} }
if (this.negated) if (this.negated) {
s = 'NOT ' + s s = 'NOT ' + s
}
return s return s
} }
} }
function negateNodeType(node) function negateNodeType(node) {
{ if (node.type === 'or') {
if (node.type == 'or') return 'and'
return 'and' } else if (node.type === 'and') {
else if (node.type == 'and') return 'or'
return 'or' } else {
else throw new Error('should not reach')
throw new Error('should not reach') }
} }
function negateNodes(lst) function negateNodes(lst) {
{ lst.forEach(item => {
lst.forEach(item => { if (!(item instanceof Node)) {
if (!(item instanceof Node)) throw new Error('should not reach')
throw new Error('should not reach') }
item.negated = !item.negated item.negated = !item.negated
}) })
} }
class MatchQueryParser class MatchQueryParser {
{
constructor() { constructor() {
this.tokenRegex = /^([",!*\(\)-])/ this.tokenRegex = /^([",!*()-])/
this.phraseSeparator = ' ' this.phraseSeparator = ' '
this.terms = /[ \t,!*\(\)-]/ this.terms = /[ \t,!*()-]/
this.knownLexemes = { this.knownLexemes = {
'-' : 'not', '!' : 'not', 'not' : 'not', '-': 'not', '!': 'not', 'not': 'not',
'&' : 'and', 'and' : 'and', '&': 'and', 'and': 'and',
',' : 'or', 'or' : 'or', '|' : 'or', ',': 'or', 'or': 'or', '|': 'or'
} }
} }
asKeywordToken(s) { asKeywordToken(s) {
const k = s.toLowerCase() const k = s.toLowerCase()
if (!this.knownLexemes.hasOwnProperty(k)) if (!_.has(this.knownLexemes, k)) {
return undefined return undefined
}
return new Token(this.knownLexemes[k], s) return new Token(this.knownLexemes[k], s)
} }
intNextToken() { intNextToken() {
let tail = this.input.substring(this.idx).trimStart() let tail = this.input.substring(this.idx).trimStart()
if (!tail) if (!tail) {
return undefined return undefined
}
tail = tail.trimStart() tail = tail.trimStart()
this.idx = this.input.length - tail.length this.idx = this.input.length - tail.length
let m = tail.match(this.tokenRegex) const m = tail.match(this.tokenRegex)
if (m) { if (m) {
if (m[0] == '"') { if (m[0] === '"') {
let idx = tail.indexOf('"', 1) const idx = tail.indexOf('"', 1)
if (idx == -1) { if (idx === -1) {
tail = tail.substring(1) tail = tail.substring(1)
this.idx = this.input.length this.idx = this.input.length
} else { } else {
@ -156,17 +159,18 @@ class MatchQueryParser
return new Token('id', tail) return new Token('id', tail)
} }
this.idx += m[0].length this.idx += m[0].length
let keyword = this.asKeywordToken(m[0]) const keyword = this.asKeywordToken(m[0])
return keyword || new Token(m[0], m[0]) return keyword || new Token(m[0], m[0])
} }
// this is literal string, find next valid token start // this is literal string, find next valid token start
let idx = tail.search(this.terms) const idx = tail.search(this.terms)
if (idx > 0) if (idx > 0) {
tail = tail.substring(0, idx) tail = tail.substring(0, idx)
}
this.idx += tail.length this.idx += tail.length
let keyword = this.asKeywordToken(tail) const keyword = this.asKeywordToken(tail)
return keyword || new Token('id', tail) return keyword || new Token('id', tail)
} }
@ -176,55 +180,65 @@ class MatchQueryParser
} }
match(v) { match(v) {
if (this.tok === undefined) if (this.tok === undefined) {
return false return false
return this.tok.type == v }
return this.tok.type === v
} }
eat(v) { eat(v) {
if (!this.match(v)) if (!this.match(v)) {
return false return false
}
this.nextToken() this.nextToken()
return true return true
} }
setParent(node, par) { setParent(node, par) {
if (node === undefined) if (node === undefined) {
return undefined return undefined
}
node.parNode = par node.parNode = par
if (!node.args) if (!node.args) {
return return
}
node.args.forEach(item => { node.args.forEach(item => {
if (item instanceof Node) if (item instanceof Node) {
this.setParent(item, node) this.setParent(item, node)
}
}) })
} }
/* /*
* Sqlite3 `NOT` operator is binary but our input search string * Sqlite3 `NOT` operator is binary but our input search string
* have unary not ('!', '-') operators so we need to preprocess request * have unary not ('!', '-') operators so we need to preprocess request
* and rearange some items to generate valid queries * and rearange some items to generate valid queries
*/ */
preprocess(node) { preprocess(node) {
if (node === undefined || node.args === undefined) if (node === undefined || node.args === undefined) {
return node return node
}
node.args.forEach(item => { node.args.forEach(item => {
if (item instanceof Node) if (item instanceof Node) {
this.preprocess(item) this.preprocess(item)
}
}) })
//try to rearrange items // try to rearrange items
let l = [], nl = [] const l = []
let nl = []
node.args.forEach(item => { node.args.forEach(item => {
if (item.negated) if (item.negated) {
nl.push(item) nl.push(item)
else } else {
l.push(item) l.push(item)
}
}) })
if (l.length == 0 && nl.length > 1) { if (l.length === 0 && nl.length > 1) {
/* invert node type if all children are negated */ /* invert node type if all children are negated */
node.negated = !node.negated node.negated = !node.negated
node.type = negateNodeType(node) node.type = negateNodeType(node)
@ -254,24 +268,26 @@ class MatchQueryParser
this.idx = 0 this.idx = 0
this.nextToken() this.nextToken()
let o = this.parseOr() const o = this.parseOr()
this.setParent(o, undefined) this.setParent(o, undefined)
return this.preprocess(o) return this.preprocess(o)
} }
parseOr() { parseOr() {
let o = this.parseAnd() let o = this.parseAnd()
if (!o) if (!o) {
return undefined return undefined
if (!this.match('or')) } else if (!this.match('or')) {
return o return o
}
let l = [o] const l = [o]
while (this.eat('or')) { while (this.eat('or')) {
o = this.parseAnd() o = this.parseAnd()
if (!o) if (!o) {
break break
}
l.push(o) l.push(o)
} }
return new Node({ return new Node({
@ -282,23 +298,26 @@ class MatchQueryParser
parseAnd() { parseAnd() {
let o = this.parseLit() let o = this.parseLit()
if (!o) if (!o) {
return undefined return undefined
}
let l = [o] const l = [o]
while (true) { while (true) {
this.eat('and') //optional this.eat('and') // optional 'and' keyword
o = this.parseLit() o = this.parseLit()
if (!o) if (!o) {
break break
}
l.push(o) l.push(o)
} }
if (l.length == 1) if (l.length === 1) {
return l[0] return l[0]
}
return new Node({ return new Node({
type: 'and', type: 'and',
args: l, args: l
}) })
} }
@ -307,26 +326,27 @@ class MatchQueryParser
let negated = false let negated = false
let star = false let star = false
if (o == undefined) if (o === undefined) {
return o return o
}
if (this.eat('not')) { if (this.eat('not')) {
if (this.tok == undefined) { if (this.tok === undefined) {
return new Node({ return new Node({
type: 'id', type: 'id',
negated: false, negated: false,
value: o.value, value: o.value
}) })
} }
negated = true negated = true
o = this.tok o = this.tok
} }
if (this.eat('(')) { if (this.eat('(')) {
let tail = this.input const n = this.parseOr()
let n = this.parseOr() if (!this.eat(')') || n === undefined) {
if (!this.eat(')') || n === undefined)
return undefined return undefined
}
n.negated = negated n.negated = negated
return n return n
} }
@ -335,15 +355,15 @@ class MatchQueryParser
} }
this.nextToken() this.nextToken()
if (this.eat('*')) if (this.eat('*')) {
star = true star = true
}
return new Node({ return new Node({
type: 'id', type: 'id',
negated, negated,
star, star,
value: o.value, value: o.value
}) })
} }
} }

Loading…
Cancel
Save