Move the webapp into its own folder
This commit is contained in:
177
app/backend/src/tokenizer.ts
Normal file
177
app/backend/src/tokenizer.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
import Tokenizr from 'tokenizr'
|
||||
import { Op } from 'sequelize'
|
||||
|
||||
export { ParsingError } from 'tokenizr'
|
||||
|
||||
export class OrderByParser {
|
||||
lexer = new Tokenizr()
|
||||
|
||||
constructor() {
|
||||
this.lexer.rule(/,/, (ctx, m) => {
|
||||
ctx.accept('spacer')
|
||||
})
|
||||
|
||||
this.lexer.rule(/ASC|DESC/, (ctx, m) => {
|
||||
ctx.accept('direction', m[0])
|
||||
})
|
||||
|
||||
this.lexer.rule(/[a-zA-Z]+/, (ctx, m) => {
|
||||
ctx.accept('column', m[0])
|
||||
})
|
||||
|
||||
this.lexer.rule(/\s/, (ctx, m) => {
|
||||
ctx.ignore()
|
||||
})
|
||||
}
|
||||
|
||||
parse(orderBy: string) {
|
||||
const output = []
|
||||
let holding = []
|
||||
this.lexer
|
||||
.input(orderBy)
|
||||
.tokens()
|
||||
.forEach((token) => {
|
||||
switch (token.type) {
|
||||
case 'spacer':
|
||||
output.push(holding)
|
||||
holding = []
|
||||
break
|
||||
case 'column':
|
||||
case 'direction':
|
||||
holding.push(token.value)
|
||||
break
|
||||
}
|
||||
})
|
||||
if (holding) {
|
||||
output.push(holding)
|
||||
}
|
||||
return output
|
||||
}
|
||||
}
|
||||
|
||||
const openGroupRegex = /\(/
|
||||
const closeGroupRegex = /\)/
|
||||
const conjunctinoRegex = /AND|OR/
|
||||
const equalityRegex = /([a-zA-Z]+)\s?(=|!=|<|>|<=|>=|:)\s?([\d]+)/
|
||||
const stringEqualityRegex = /([a-zA-Z]+)\s?(=|!=|<|>|<=|>=|:)\s?\"([a-zA-Z'"\d\s]*)\"/
|
||||
const spacerRegex = /\s/
|
||||
|
||||
const opperatorMap = {
|
||||
'=': Op.eq,
|
||||
'!=': Op.ne,
|
||||
'<=': Op.lte,
|
||||
'>=': Op.gte,
|
||||
'>': Op.gt,
|
||||
'<': Op.lt,
|
||||
':': Op.like,
|
||||
AND: Op.and,
|
||||
OR: Op.or
|
||||
}
|
||||
|
||||
export class FilterParser {
|
||||
lexer: Tokenizr
|
||||
|
||||
constructor() {
|
||||
this.lexer = new Tokenizr()
|
||||
|
||||
this.lexer.rule(openGroupRegex, (ctx, m) => {
|
||||
ctx.accept('opengroup')
|
||||
})
|
||||
|
||||
this.lexer.rule(closeGroupRegex, (ctx, m) => {
|
||||
ctx.accept('closegroup')
|
||||
})
|
||||
|
||||
this.lexer.rule(conjunctinoRegex, (ctx, m) => {
|
||||
ctx.accept('conjunction', m[0])
|
||||
})
|
||||
|
||||
this.lexer.rule(stringEqualityRegex, (ctx, m) => {
|
||||
ctx.accept('column', m[1])
|
||||
ctx.accept('opperator', m[2])
|
||||
ctx.accept('value', m[3])
|
||||
})
|
||||
|
||||
this.lexer.rule(equalityRegex, (ctx, m) => {
|
||||
ctx.accept('column', m[1])
|
||||
ctx.accept('opperator', m[2])
|
||||
ctx.accept('value', m[3])
|
||||
})
|
||||
|
||||
this.lexer.rule(spacerRegex, (ctx, m) => {
|
||||
ctx.ignore()
|
||||
})
|
||||
}
|
||||
|
||||
parse(filter: string) {
|
||||
this.lexer.input(filter)
|
||||
let block = this.parseBlock('AND')
|
||||
this.lexer.consume('EOF')
|
||||
this.lexer.reset()
|
||||
return block
|
||||
}
|
||||
|
||||
private parseBlock(conjunciton: string) {
|
||||
let items = []
|
||||
let activeCon = conjunciton
|
||||
|
||||
for (;;) {
|
||||
let nextItem = this.lexer.alternatives(
|
||||
() => this.parseEquality(),
|
||||
() => this.parseGroup(),
|
||||
() => {
|
||||
let conToken = this.lexer.consume('conjunction')
|
||||
|
||||
if (items.length === 1) {
|
||||
activeCon = conToken.value
|
||||
}
|
||||
|
||||
if (conToken.value === activeCon) {
|
||||
return this.parseEquality()
|
||||
} else {
|
||||
return this.parseBlock(conToken.value)
|
||||
}
|
||||
},
|
||||
() => this.parseEmpty()
|
||||
)
|
||||
|
||||
if (nextItem === undefined) {
|
||||
break
|
||||
}
|
||||
|
||||
items.push(nextItem)
|
||||
}
|
||||
|
||||
return { [opperatorMap[activeCon]]: items }
|
||||
}
|
||||
|
||||
private parseEquality() {
|
||||
let columnToken = this.lexer.consume('column')
|
||||
let opperatorToken = this.lexer.consume('opperator')
|
||||
let valueToken = this.lexer.consume('value')
|
||||
|
||||
if (opperatorToken.value === ':') {
|
||||
return {
|
||||
[columnToken.value]: {
|
||||
[opperatorMap[opperatorToken.value]]: `%${valueToken.value.toString()}%`
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
[columnToken.value]: { [opperatorMap[opperatorToken.value]]: valueToken.value.toString() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private parseGroup() {
|
||||
this.lexer.consume('opengroup')
|
||||
let block = this.parseBlock('AND')
|
||||
this.lexer.consume('closegroup')
|
||||
|
||||
return block
|
||||
}
|
||||
|
||||
private parseEmpty() {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user