Skip to content

Instantly share code, notes, and snippets.

View WimJongeneel's full-sized avatar
:octocat:

Wim Jongeneel WimJongeneel

:octocat:
View GitHub Profile
const runExpr = (e: Expr, i: any): any => {
if (e.kind == 'acs') return i[e.id]
if (e.kind == '==') return runExpr(e.left, i) == runExpr(e.right, i)
if (e.kind == 'includes') return runExpr(e.left, i).contains(runExpr(e.right, i))
if (e.kind == '&&') return runExpr(e.left, i) && runExpr(e.right, i)
if (e.kind == 'val') return e.value
}
odata<Blog>('Blog')
.where(b => b.Id.equals(1).and(b.Title.includes('hello')))
.toArray()
const odata = <T>(name: string, baseuri = '/odata'): IQueryable<T> => {
const exprs: Expr<T>[] = []
return {
where(e) {
exprs.push(e(builder()).getExpr())
return this
},
toArray: async () => {
const res = await fetch(`${baseuri}/${name}?$filter=${exprs.map(compileOdata).join(' and ')}`)
const compileOdata = (e: Expr): string => {
if (e.kind == 'acs') return e.id.toString()
if (e.kind == '==') return `${compileOdata(e.left)} eq ${compileOdata(e.right)}`
if (e.kind == 'includes') return `substringof( ${compileOdata(e.right)}, ${compileOdata(e.left)})`
if (e.kind == '&&') return `${compileOdata(e.left)} and ${compileOdata(e.right)}`
if (e.kind == 'val') return typeof e.value == 'string' ? `'${e.value}'` : e.value
}
interface IQueryable<T> {
where(e: Expr<T>): IQueryable<T>
toArray(): Promise<T[]>
}
type Fake<T extends object> = {
[k in keyof T]:
T[k] extends string ? StringExprBuilder :
T[k] extends number ? NumberExprBuilder :
BoolExprBuilder
}
interface StringExprBuilder {
equals(s: string | StringExprBuilder): BoolExprBuilder
includes(s: string | StringExprBuilder): BoolExprBuilder
getExpr(): Expr
}
interface BoolExprBuilder {
equals(s: boolean | BoolExprBuilder): BoolExprBuilder
and(e: BoolExprBuilder): BoolExprBuilder
getExpr(): Expr
const handler = {
get(_, name: string) => new ExprBuilder(createIndexExpression(name))
}
fakeBlog.Id.equals(1)
/**
{
kind: '==',
left: {
kind: 'index',
class ExprBuilder {
constructor(protected ast: Expr) { }
GetExpr = () => this.ast
equals(v: string | number | boolean | ExprBuilder) {
if (['string', 'number', 'boolean'].indexOf(typeof v) != -1) {
return new ExprBuilder(createBinaryExpression('==', this.ast, createValExpression(v)))
}
return new ExprBuilder(createBinaryExpression('==', this.ast, (v as ExprBuilder).GetExpr()))
class ExprBuilder {
constructor(protected currentAst: Expr) { }
equals(v: any) {
return new ExprBuilder((createBinaryExpression('==', this.currentAst, createValExpression(v))))
}
}