Files
Compass/backend/shared/src/supabase/sql-builder.ts

121 lines
3.3 KiB
TypeScript

import { last } from 'lodash'
import { buildArray } from 'common/util/array'
import { pgp } from './init'
export type SqlBuilder = {
with: string[]
select: string[]
from: string | undefined
join: string[]
leftJoin: string[]
where: string[]
orderBy: string[]
groupBy: string[]
limit: number | undefined
offset: number | undefined
}
export type SqlParts = {
with?: string
select?: string
from?: string
join?: string
leftJoin?: string
groupBy?: string
where?: string
orderBy?: string
limit?: number
offset?: number
}
type Args = (Args | SqlParts | SqlBuilder | undefined | false | 0 | '')[]
export function buildSql(...parts: Args): SqlBuilder {
const definedParts = buildArray(parts)
return {
with: definedParts.flatMap((part) => part.with || []),
select: definedParts.flatMap((part) => part.select || []),
from: last(definedParts.filter((part) => part.from))?.from,
join: definedParts.flatMap((part) => part.join || []),
leftJoin: definedParts.flatMap((part) => part.leftJoin || []),
where: definedParts.flatMap((part) => part.where || []),
orderBy: definedParts.flatMap((part) => part.orderBy || []),
groupBy: definedParts.flatMap((part) => part.groupBy || []),
limit: last(definedParts.filter((part) => part.limit))?.limit,
offset: last(definedParts.filter((part) => part.offset))?.offset,
}
}
export function withClause(clause: string, formatValues?: any) {
const formattedWith = pgp.as.format(clause, formatValues)
return buildSql({ with: formattedWith })
}
export function select(clause: string) {
return buildSql({ select: clause })
}
export function from(clause: string, formatValues?: any) {
const from = pgp.as.format(clause, formatValues)
return buildSql({ from })
}
export function join(clause: string, formatValues?: any) {
const join = pgp.as.format(clause, formatValues)
return buildSql({ join })
}
export function leftJoin(clause: string, formatValues?: any) {
const leftJoin = pgp.as.format(clause, formatValues)
return buildSql({ leftJoin })
}
export function groupBy(clause: string) {
return buildSql({ groupBy: clause })
}
export function where(clause: string, formatValues?: any) {
const where = pgp.as.format(clause, formatValues)
return buildSql({ where })
}
export function orderBy(clause: string, formatValues?: any) {
const orderBy = pgp.as.format(clause, formatValues)
return buildSql({ orderBy })
}
export function limit(limit: number, offset?: number) {
return buildSql({ limit, offset })
}
export function renderSql(...args: Args) {
const builder = buildSql(...args)
const {
with: withClause,
select,
from,
join,
where,
orderBy,
limit,
offset,
leftJoin,
groupBy,
} = builder
return buildArray(
withClause.length && `with ${withClause.join(', ')}`,
select.length && `select ${select.join(', ')}`,
from && `from ${from}`,
join.length && `join ${join.join(' join ')}`,
leftJoin.length && `left join ${leftJoin.join(' left join ')}`,
where.length &&
`where ${where.map((clause) => `(${clause})`).join(' and ')}`,
groupBy.length && `group by ${groupBy.join(', ')}`,
orderBy.length && `order by ${orderBy.join(', ')}`,
limit && `limit ${limit}`,
limit && offset && `offset ${offset}`
).join('\n')
}