@supabase/postgrest-js
Version:
Isomorphic PostgREST client
202 lines (179 loc) • 7.1 kB
text/typescript
import PostgrestError from './PostgrestError'
import { ContainsNull } from './select-query-parser/types'
import { IsAny, SelectQueryError } from './select-query-parser/utils'
export type Fetch = typeof fetch
/**
* Response format
*
* {@link https://github.com/supabase/supabase-js/issues/32}
*/
interface PostgrestResponseBase {
status: number
statusText: string
}
export interface PostgrestResponseSuccess<T> extends PostgrestResponseBase {
error: null
data: T
count: number | null
}
export interface PostgrestResponseFailure extends PostgrestResponseBase {
error: PostgrestError
data: null
count: null
}
// TODO: in v3:
// - remove PostgrestResponse and PostgrestMaybeSingleResponse
// - rename PostgrestSingleResponse to PostgrestResponse
export type PostgrestSingleResponse<T> = PostgrestResponseSuccess<T> | PostgrestResponseFailure
export type PostgrestMaybeSingleResponse<T> = PostgrestSingleResponse<T | null>
export type PostgrestResponse<T> = PostgrestSingleResponse<T[]>
export type GenericRelationship = {
foreignKeyName: string
columns: string[]
isOneToOne?: boolean
referencedRelation: string
referencedColumns: string[]
}
export type GenericTable = {
Row: Record<string, unknown>
Insert: Record<string, unknown>
Update: Record<string, unknown>
Relationships: GenericRelationship[]
}
export type GenericUpdatableView = {
Row: Record<string, unknown>
Insert: Record<string, unknown>
Update: Record<string, unknown>
Relationships: GenericRelationship[]
}
export type GenericNonUpdatableView = {
Row: Record<string, unknown>
Relationships: GenericRelationship[]
}
export type GenericView = GenericUpdatableView | GenericNonUpdatableView
export type GenericFunction = {
Args: Record<string, unknown>
Returns: unknown
}
export type GenericSchema = {
Tables: Record<string, GenericTable>
Views: Record<string, GenericView>
Functions: Record<string, GenericFunction>
}
export type ClientServerOptions = {
PostgrestVersion?: string
}
export type DatabaseWithOptions<Database, Options extends ClientServerOptions> = {
db: Database
options: Options
}
export type MaxAffectedEnabled<PostgrestVersion extends string | undefined> =
PostgrestVersion extends `13${string}` ? true : false
// https://twitter.com/mattpocockuk/status/1622730173446557697
export type Prettify<T> = { [K in keyof T]: T[K] } & {}
// https://github.com/sindresorhus/type-fest
export type SimplifyDeep<Type, ExcludeType = never> = ConditionalSimplifyDeep<
Type,
ExcludeType | NonRecursiveType | Set<unknown> | Map<unknown, unknown>,
object
>
type ConditionalSimplifyDeep<
Type,
ExcludeType = never,
IncludeType = unknown
> = Type extends ExcludeType
? Type
: Type extends IncludeType
? { [TypeKey in keyof Type]: ConditionalSimplifyDeep<Type[TypeKey], ExcludeType, IncludeType> }
: Type
type NonRecursiveType = BuiltIns | Function | (new (...arguments_: any[]) => unknown)
type BuiltIns = Primitive | void | Date | RegExp
type Primitive = null | undefined | string | number | boolean | symbol | bigint
export type IsValidResultOverride<Result, NewResult, ErrorResult, ErrorNewResult> =
Result extends any[]
? NewResult extends any[]
? // Both are arrays - valid
true
: ErrorResult
: NewResult extends any[]
? ErrorNewResult
: // Neither are arrays - valid
true
/**
* Utility type to check if array types match between Result and NewResult.
* Returns either the valid NewResult type or an error message type.
*/
export type CheckMatchingArrayTypes<Result, NewResult> =
// If the result is a QueryError we allow the user to override anyway
Result extends SelectQueryError<string>
? NewResult
: IsValidResultOverride<
Result,
NewResult,
{
Error: 'Type mismatch: Cannot cast array result to a single object. Use .overrideTypes<Array<YourType>> or .returns<Array<YourType>> (deprecated) for array results or .single() to convert the result to a single object'
},
{
Error: 'Type mismatch: Cannot cast single object to array type. Remove Array wrapper from return type or make sure you are not using .single() up in the calling chain'
}
> extends infer ValidationResult
? ValidationResult extends true
? // Preserve the optionality of the result if the overriden type is an object (case of chaining with `maybeSingle`)
ContainsNull<Result> extends true
? NewResult | null
: NewResult
: // contains the error
ValidationResult
: never
type Simplify<T> = T extends object ? { [K in keyof T]: T[K] } : T
// Extract only explicit (non-index-signature) keys.
type ExplicitKeys<T> = {
[K in keyof T]: string extends K ? never : K
}[keyof T]
type MergeExplicit<New, Row> = {
// We merge all the explicit keys which allows merge and override of types like
// { [key: string]: unknown } and { someSpecificKey: boolean }
[K in ExplicitKeys<New> | ExplicitKeys<Row>]: K extends keyof New
? K extends keyof Row
? Row[K] extends SelectQueryError<string>
? New[K]
: // Check if the override is on a embedded relation (array)
New[K] extends any[]
? Row[K] extends any[]
? Array<Simplify<MergeDeep<NonNullable<New[K][number]>, NonNullable<Row[K][number]>>>>
: New[K]
: // Check if both properties are objects omitting a potential null union
IsPlainObject<NonNullable<New[K]>> extends true
? IsPlainObject<NonNullable<Row[K]>> extends true
? // If they are, use the new override as source of truth for the optionality
ContainsNull<New[K]> extends true
? // If the override wants to preserve optionality
Simplify<MergeDeep<NonNullable<New[K]>, NonNullable<Row[K]>>> | null
: // If the override wants to enforce non-null result
Simplify<MergeDeep<New[K], NonNullable<Row[K]>>>
: New[K] // Override with New type if Row isn't an object
: New[K] // Override primitives with New type
: New[K] // Add new properties from New
: K extends keyof Row
? Row[K] // Keep existing properties not in New
: never
}
type MergeDeep<New, Row> = Simplify<
MergeExplicit<New, Row> &
// Intersection here is to restore dynamic keys into the merging result
// eg:
// {[key: number]: string}
// or Record<string, number | null>
(string extends keyof Row ? { [K: string]: Row[string] } : {})
>
// Helper to check if a type is a plain object (not an array)
type IsPlainObject<T> = T extends any[] ? false : T extends object ? true : false
// Merge the new result with the original (Result) when merge option is true.
// If NewResult is an array, merge each element.
export type MergePartialResult<NewResult, Result, Options> = Options extends { merge: true }
? Result extends any[]
? NewResult extends any[]
? Array<Simplify<MergeDeep<NewResult[number], Result[number]>>>
: never
: Simplify<MergeDeep<NewResult, Result>>
: NewResult