tokenizer works

This commit is contained in:
jmosrael@gmail.com
2024-05-17 19:59:17 -07:00
parent 3094ae3a08
commit 401330d842
2 changed files with 55 additions and 85 deletions

View File

@@ -2,10 +2,12 @@ import express from 'express'
import { json } from 'body-parser' import { json } from 'body-parser'
import { Sequelize, Op } from 'sequelize' import { Sequelize, Op } from 'sequelize'
import { database, Character, Game, Pick, App } from './db' import { database, Character, Game, Pick, App } from './db'
import { lexr, parseOrderByString, FilterParser } from './tokenizer' import { OrderByParser, FilterParser } from './tokenizer'
const app = express() const app = express()
const jsonParser = json() const jsonParser = json()
const fp = new FilterParser()
const obp = new OrderByParser()
const port = 3001 const port = 3001
app.get('/', (req, res) => { app.get('/', (req, res) => {
@@ -36,34 +38,19 @@ app.get('/api/game/:gameId', async (req, res) => {
}) })
app.post('/api/game', jsonParser, async (req, res) => { app.post('/api/game', jsonParser, async (req, res) => {
console.log(req.body)
const page = req.body.page || 0 const page = req.body.page || 0
const orderBy = req.body.orderBy ? parseOrderByString(req.body.orderBy) : ['id'] const orderBy = req.body.orderBy ? obp.parse(req.body.orderBy) : ['id']
const count = req.body.count || 10 const count = req.body.count || 10
const filter = req.body.filter || '' const filter = req.body.filter ? fp.parse(req.body.filter) : {}
const gameData = await Game.findAll({ const gameData = await Game.findAll({
offset: page * count, offset: page * count,
limit: count, limit: count,
order: orderBy, order: orderBy,
where: { where: filter
id: { [Op.eq]: 2 }
}
}) })
const pageCount = Math.ceil((await Character.count()) / count) const pageCount = Math.ceil((await Character.count()) / count)
let fp = new FilterParser()
fp.lexer
.input(filter)
.tokens()
.forEach((t) => {
console.log(t)
})
console.log(fp.parseFilter(filter))
res.setHeader('Content-Type', 'application/json') res.setHeader('Content-Type', 'application/json')
res.send({ gameData, pageCount }) res.send({ gameData, pageCount })
}) })

View File

@@ -1,35 +1,31 @@
import Tokenizr from 'tokenizr' import Tokenizr from 'tokenizr'
import ASTY from 'asty'
import { Op } from 'sequelize' import { Op } from 'sequelize'
export const lexr = new Tokenizr() export class OrderByParser {
lexer = new Tokenizr()
lexr.rule(/[AND|OR]/, (ctx, m) => { constructor() {
ctx.accept('conjunction', m[0]) this.lexer.rule(/,/, (ctx, m) => {
})
export const orderByLexr = new Tokenizr()
orderByLexr.rule(/,/, (ctx, m) => {
ctx.accept('spacer') ctx.accept('spacer')
}) })
orderByLexr.rule(/ASC|DESC/, (ctx, m) => { this.lexer.rule(/ASC|DESC/, (ctx, m) => {
ctx.accept('direction', m[0]) ctx.accept('direction', m[0])
}) })
orderByLexr.rule(/[a-zA-Z]+/, (ctx, m) => { this.lexer.rule(/[a-zA-Z]+/, (ctx, m) => {
ctx.accept('column', m[0]) ctx.accept('column', m[0])
}) })
orderByLexr.rule(/\s/, (ctx, m) => { this.lexer.rule(/\s/, (ctx, m) => {
ctx.ignore() ctx.ignore()
}) })
}
export function parseOrderByString(orderBy: string) { parse(orderBy: string) {
const output = [] const output = []
let holding = [] let holding = []
orderByLexr this.lexer
.input(orderBy) .input(orderBy)
.tokens() .tokens()
.forEach((token) => { .forEach((token) => {
@@ -48,6 +44,7 @@ export function parseOrderByString(orderBy: string) {
output.push(holding) output.push(holding)
} }
return output return output
}
} }
const openGroupRegex = /\(/ const openGroupRegex = /\(/
@@ -61,55 +58,47 @@ const opperatorMap = {
'!=': Op.ne, '!=': Op.ne,
'<=': Op.lte, '<=': Op.lte,
'>=': Op.gte, '>=': Op.gte,
':': Op.like '>': Op.gt,
'<': Op.lt,
':': Op.like,
AND: Op.and,
OR: Op.or
} }
export class FilterParser { export class FilterParser {
asty: ASTY = new ASTY() lexer: Tokenizr
lexer: Tokenizr = this.createLexer()
constructor() {} constructor() {
this.lexer = new Tokenizr()
private createLexer(): Tokenizr { this.lexer.rule(openGroupRegex, (ctx, m) => {
const tkz = new Tokenizr()
tkz.rule(openGroupRegex, (ctx, m) => {
ctx.accept('opengroup') ctx.accept('opengroup')
}) })
tkz.rule(closeGroupRegex, (ctx, m) => { this.lexer.rule(closeGroupRegex, (ctx, m) => {
ctx.accept('closegroup') ctx.accept('closegroup')
}) })
tkz.rule(conjunctinoRegex, (ctx, m) => { this.lexer.rule(conjunctinoRegex, (ctx, m) => {
ctx.accept('conjunction', m[0]) ctx.accept('conjunction', m[0])
}) })
tkz.rule(equalityRegex, (ctx, m) => { this.lexer.rule(equalityRegex, (ctx, m) => {
ctx.accept('column', m[1]) ctx.accept('column', m[1])
ctx.accept('opperator', m[2]) ctx.accept('opperator', m[2])
ctx.accept('value', m[3]) ctx.accept('value', m[3])
}) })
tkz.rule(spacerRegex, (ctx, m) => { this.lexer.rule(spacerRegex, (ctx, m) => {
ctx.ignore() ctx.ignore()
}) })
return tkz
} }
parseFilter(filter: string) { parse(filter: string) {
this.lexer.input(filter) this.lexer.input(filter)
console.log(`parsing ${filter}`)
this.lexer.begin()
this.lexer.tokens().forEach((token) => {
console.log(token)
})
this.lexer.rollback()
let block = this.parseBlock('AND') let block = this.parseBlock('AND')
this.lexer.consume('EOF') this.lexer.consume('EOF')
this.lexer.reset() this.lexer.reset()
return block return block
} }
@@ -122,12 +111,8 @@ export class FilterParser {
() => this.parseEquality(), () => this.parseEquality(),
() => this.parseGroup(), () => this.parseGroup(),
() => { () => {
console.log("Conjunct")
let conToken = this.lexer.consume('conjunction') let conToken = this.lexer.consume('conjunction')
console.log("potato")
if (items.length === 1) { if (items.length === 1) {
activeCon = conToken.value activeCon = conToken.value
} }
@@ -137,42 +122,36 @@ export class FilterParser {
} else { } else {
return this.parseBlock(conToken.value) return this.parseBlock(conToken.value)
} }
}, () => {} },
() => this.parseEmpty()
) )
if (nextItem === undefined) { if (nextItem === undefined) {
console.log("breaking")
break break
} }
items.push(nextItem) items.push(nextItem)
} }
return this.asty.create('conjunction').set('type', activeCon).add(items) return { [opperatorMap[activeCon]]: items }
} }
private parseConjunction() {}
private parseEquality() { private parseEquality() {
console.log("doing an equality")
let columnToken = this.lexer.consume('column') let columnToken = this.lexer.consume('column')
let opperatorToken = this.lexer.consume('opperator') let opperatorToken = this.lexer.consume('opperator')
let valueToken = this.lexer.consume('value') let valueToken = this.lexer.consume('value')
let node = this.asty.create('equality') if (opperatorToken.value === ":") {
node.pos(columnToken.line, columnToken.column, columnToken.pos) return {
[columnToken.value]: { [opperatorMap[opperatorToken.value]]: `%${valueToken.value.toString()}%` }
node.set(columnToken.type, columnToken.value)
node.set(opperatorToken.type, opperatorToken.value)
node.set(valueToken.type, valueToken.value)
node.set('expression', {
[columnToken.value]: {
[opperatorMap[opperatorToken.value]]: valueToken.value
} }
}) } else {
return node return {
[columnToken.value]: { [opperatorMap[opperatorToken.value]]: valueToken.value.toString() }
}
}
} }
private parseGroup() { private parseGroup() {
@@ -182,4 +161,8 @@ export class FilterParser {
return block return block
} }
private parseEmpty() {
return undefined
}
} }