import { PostgrestBuilder } from './types.ts'import { PostgrestFilterBuilder } from './PostgrestFilterBuilder.ts'
export class PostgrestQueryBuilder<T> extends PostgrestBuilder<T> { constructor( url: string, { headers = {}, schema }: { headers?: { [key: string]: string }; schema?: string } = {} ) { super({} as PostgrestBuilder<T>) this.url = new URL(url) this.headers = { ...headers } this.schema = schema }
select( columns = '*', { head = false, count = null, }: { head?: boolean count?: null | 'exact' | 'planned' | 'estimated' } = {} ): PostgrestFilterBuilder<T> { this.method = 'GET' let quoted = false const cleanedColumns = columns .split('') .map((c) => { if (/\s/.test(c) && !quoted) { return '' } if (c === '"') { quoted = !quoted } return c }) .join('') this.url.searchParams.set('select', cleanedColumns) if (count) { this.headers['Prefer'] = `count=${count}` } if (head) { this.method = 'HEAD' } return new PostgrestFilterBuilder(this) }
insert( values: Partial<T> | Partial<T>[], options?: { returning?: 'minimal' | 'representation' count?: null | 'exact' | 'planned' | 'estimated' } ): PostgrestFilterBuilder<T> insert( values: Partial<T> | Partial<T>[], options?: { upsert?: boolean onConflict?: string returning?: 'minimal' | 'representation' count?: null | 'exact' | 'planned' | 'estimated' } ): PostgrestFilterBuilder<T> insert( values: Partial<T> | Partial<T>[], { upsert = false, onConflict, returning = 'representation', count = null, }: { upsert?: boolean onConflict?: string returning?: 'minimal' | 'representation' count?: null | 'exact' | 'planned' | 'estimated' } = {} ): PostgrestFilterBuilder<T> { this.method = 'POST'
const prefersHeaders = [`return=${returning}`] if (upsert) prefersHeaders.push('resolution=merge-duplicates')
if (upsert && onConflict !== undefined) this.url.searchParams.set('on_conflict', onConflict) this.body = values if (count) { prefersHeaders.push(`count=${count}`) }
this.headers['Prefer'] = prefersHeaders.join(',')
if (Array.isArray(values)) { const columns = values.reduce((acc, x) => acc.concat(Object.keys(x)), [] as string[]) if (columns.length > 0) { const uniqueColumns = [...new Set(columns)].map((column) => `"${column}"`) this.url.searchParams.set('columns', uniqueColumns.join(',')) } }
return new PostgrestFilterBuilder(this) }
upsert( values: Partial<T> | Partial<T>[], { onConflict, returning = 'representation', count = null, ignoreDuplicates = false, }: { onConflict?: string returning?: 'minimal' | 'representation' count?: null | 'exact' | 'planned' | 'estimated' ignoreDuplicates?: boolean } = {} ): PostgrestFilterBuilder<T> { this.method = 'POST'
const prefersHeaders = [ `resolution=${ignoreDuplicates ? 'ignore' : 'merge'}-duplicates`, `return=${returning}`, ]
if (onConflict !== undefined) this.url.searchParams.set('on_conflict', onConflict) this.body = values if (count) { prefersHeaders.push(`count=${count}`) }
this.headers['Prefer'] = prefersHeaders.join(',')
return new PostgrestFilterBuilder(this) }
update( values: Partial<T>, { returning = 'representation', count = null, }: { returning?: 'minimal' | 'representation' count?: null | 'exact' | 'planned' | 'estimated' } = {} ): PostgrestFilterBuilder<T> { this.method = 'PATCH' const prefersHeaders = [`return=${returning}`] this.body = values if (count) { prefersHeaders.push(`count=${count}`) } this.headers['Prefer'] = prefersHeaders.join(',') return new PostgrestFilterBuilder(this) }
delete({ returning = 'representation', count = null, }: { returning?: 'minimal' | 'representation' count?: null | 'exact' | 'planned' | 'estimated' } = {}): PostgrestFilterBuilder<T> { this.method = 'DELETE' const prefersHeaders = [`return=${returning}`] if (count) { prefersHeaders.push(`count=${count}`) } this.headers['Prefer'] = prefersHeaders.join(',') return new PostgrestFilterBuilder(this) }}