Spaces:
Running
Running
File size: 5,122 Bytes
5c05829 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | import PostgrestQueryBuilder from './PostgrestQueryBuilder'
import PostgrestFilterBuilder from './PostgrestFilterBuilder'
import PostgrestBuilder from './PostgrestBuilder'
import { DEFAULT_HEADERS } from './constants'
import { Fetch, GenericSchema } from './types'
/**
* PostgREST client.
*
* @typeParam Database - Types for the schema from the [type
* generator](https://supabase.com/docs/reference/javascript/next/typescript-support)
*
* @typeParam SchemaName - Postgres schema to switch to. Must be a string
* literal, the same one passed to the constructor. If the schema is not
* `"public"`, this must be supplied manually.
*/
export default class PostgrestClient<
Database = any,
SchemaName extends string & keyof Database = 'public' extends keyof Database
? 'public'
: string & keyof Database,
Schema extends GenericSchema = Database[SchemaName] extends GenericSchema
? Database[SchemaName]
: any
> {
url: string
headers: Record<string, string>
schemaName?: SchemaName
fetch?: Fetch
// TODO: Add back shouldThrowOnError once we figure out the typings
/**
* Creates a PostgREST client.
*
* @param url - URL of the PostgREST endpoint
* @param options - Named parameters
* @param options.headers - Custom headers
* @param options.schema - Postgres schema to switch to
* @param options.fetch - Custom fetch
*/
constructor(
url: string,
{
headers = {},
schema,
fetch,
}: {
headers?: Record<string, string>
schema?: SchemaName
fetch?: Fetch
} = {}
) {
this.url = url
this.headers = { ...DEFAULT_HEADERS, ...headers }
this.schemaName = schema
this.fetch = fetch
}
from<
TableName extends string & keyof Schema['Tables'],
Table extends Schema['Tables'][TableName]
>(relation: TableName): PostgrestQueryBuilder<Schema, Table, TableName>
from<ViewName extends string & keyof Schema['Views'], View extends Schema['Views'][ViewName]>(
relation: ViewName
): PostgrestQueryBuilder<Schema, View, ViewName>
from(relation: string): PostgrestQueryBuilder<Schema, any, any>
/**
* Perform a query on a table or a view.
*
* @param relation - The table or view name to query
*/
from(relation: string): PostgrestQueryBuilder<Schema, any, any> {
const url = new URL(`${this.url}/${relation}`)
return new PostgrestQueryBuilder(url, {
headers: { ...this.headers },
schema: this.schemaName,
fetch: this.fetch,
})
}
/**
* Select a schema to query or perform an function (rpc) call.
*
* The schema needs to be on the list of exposed schemas inside Supabase.
*
* @param schema - The schema to query
*/
schema<DynamicSchema extends string & keyof Database>(
schema: DynamicSchema
): PostgrestClient<
Database,
DynamicSchema,
Database[DynamicSchema] extends GenericSchema ? Database[DynamicSchema] : any
> {
return new PostgrestClient(this.url, {
headers: this.headers,
schema,
fetch: this.fetch,
})
}
/**
* Perform a function call.
*
* @param fn - The function name to call
* @param args - The arguments to pass to the function call
* @param options - Named parameters
* @param options.head - When set to `true`, `data` will not be returned.
* Useful if you only need the count.
* @param options.count - Count algorithm to use to count rows returned by the
* function. Only applicable for [set-returning
* functions](https://www.postgresql.org/docs/current/functions-srf.html).
*
* `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the
* hood.
*
* `"planned"`: Approximated but fast count algorithm. Uses the Postgres
* statistics under the hood.
*
* `"estimated"`: Uses exact count for low numbers and planned count for high
* numbers.
*/
rpc<
FunctionName extends string & keyof Schema['Functions'],
Function_ extends Schema['Functions'][FunctionName]
>(
fn: FunctionName,
args: Function_['Args'] = {},
{
head = false,
count,
}: {
head?: boolean
count?: 'exact' | 'planned' | 'estimated'
} = {}
): PostgrestFilterBuilder<
Schema,
Function_['Returns'] extends any[]
? Function_['Returns'][number] extends Record<string, unknown>
? Function_['Returns'][number]
: never
: never,
Function_['Returns']
> {
let method: 'HEAD' | 'POST'
const url = new URL(`${this.url}/rpc/${fn}`)
let body: unknown | undefined
if (head) {
method = 'HEAD'
Object.entries(args).forEach(([name, value]) => {
url.searchParams.append(name, `${value}`)
})
} else {
method = 'POST'
body = args
}
const headers = { ...this.headers }
if (count) {
headers['Prefer'] = `count=${count}`
}
return new PostgrestFilterBuilder({
method,
url,
headers,
schema: this.schemaName,
body,
fetch: this.fetch,
allowEmpty: false,
} as unknown as PostgrestBuilder<Function_['Returns']>)
}
}
|