Skip to content

Instantly share code, notes, and snippets.

@skulptur
Created August 4, 2020 01:38
Show Gist options
  • Save skulptur/992eeba2f6d0402c567b4f3cf3ec879f to your computer and use it in GitHub Desktop.
Save skulptur/992eeba2f6d0402c567b4f3cf3ec879f to your computer and use it in GitHub Desktop.
// https://medium.com/@reidev275/creating-a-type-safe-dsl-for-filtering-in-typescript-53fe68a7942e
export type Filter<A> =
| { kind: 'Equals'; field: keyof A; val: A[keyof A] }
| { kind: 'Greater'; field: keyof A; val: A[keyof A] }
| { kind: 'Less'; field: keyof A; val: A[keyof A] }
| { kind: 'And'; a: Filter<A>; b: Filter<A> }
| { kind: 'Or'; a: Filter<A>; b: Filter<A> }
export const equals = <A, K extends keyof A>(
field: K,
val: A[K]
): Filter<A> => ({
kind: 'Equals',
field,
val,
})
export const greater = <A, K extends keyof A>(
field: K,
val: A[K]
): Filter<A> => ({
kind: 'Greater',
field,
val,
})
export const less = <A, K extends keyof A>(field: K, val: A[K]): Filter<A> => ({
kind: 'Less',
field,
val,
})
export const and = <A>(a: Filter<A>, b: Filter<A>): Filter<A> => ({
kind: 'And',
a,
b,
})
export const or = <A>(a: Filter<A>, b: Filter<A>): Filter<A> => ({
kind: 'Or',
a,
b,
})
export const interpretToSql = <A>(dsl: Filter<A>): string => {
switch (dsl.kind) {
case 'Equals':
return `[${dsl.field}] = '${dsl.val}'`
case 'Greater':
return `[${dsl.field}] > '${dsl.val}'`
case 'Less':
return `[${dsl.field}] < '${dsl.val}'`
case 'And':
return `(${interpretToSql(dsl.a)} and ${interpretToSql(dsl.b)})`
case 'Or':
return `(${interpretToSql(dsl.a)} or ${interpretToSql(dsl.b)})`
}
}
type JobPosting = {
manager: string
salary: number
}
const query: Filter<JobPosting> = and(
equals('manager', 'Bob Slydell'),
greater('salary', 50000)
)
console.log(interpretToSql(query))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment