Filtering系统与AST的应用
2023-04-26
分享个我在项目里用ast的案例
restful api 经常会需要支持filter
jsx
filter[id]=10
filter[type]=normal
代码里面设计了这样的一个东西:
jsx
const allowedFilter = {
id: true,
type: true
}
如果需要默认值的话:
jsx
const allowedFilter = {
id: true,
type: 'default:normal'
}
如果复杂查询的话,用函数:
jsx
const allowedFilter = {
id: true,
type: (subQuery, value) => subQuery.where('type', value)
}
如果复杂查询,并且支持默认值的话:
jsx
const allowedFilter = {
id: true,
type: (subQuery, value = 'normal') => subQuery.where('type', value)
}
那么这个filter就需要推断当前给定的函数,其参数是否包含默认值,即:
- 输入filter[type], 调用函数
- 无输入filter[type], 推断第二个参数value有默认值,调用函数
- 无输入filter[type], 推断第二个参数value无默认值,不调用函数
部分实现
jsx
// 分词
function paramsHasDefaultValue(fnStr){
const nameTokens = [...acorn.tokenizer(fnStr, {ecmaVersion: 2020})]
let nameCount = 0;
let step = 0;
let hasEqualSympol = false;
let hasValueSympol = false
nameTokens.forEach(token => {
if(token.type.label === 'name'){
nameCount += 1;
}
if(nameCount === 2){
step += 1
}
if(step === 2 && token.type.label === '='){
hasEqualSympol = true;
}
if(step === 3 && ['string'].includes(token.type.label)){
hasValueSympol = true
}
})
return hasEqualSympol && hasValueSympol
}
// 应用
(allowedFilters, queryBuilder) => {
Object.entries(allowedFilters).forEach(([k,v]) => {
if(typeof v === 'function'){
if(filter[k]) {
v(queryBuilder, filter[k])
}else{
if(paramsHasDefaultValue(v)){
v(queryBuilder)
}
}
}
})
}