Last active
June 10, 2021 18:57
-
-
Save SandroMaglione/efb5b261bf10f3bc47c54a286a5af930 to your computer and use it in GitHub Desktop.
Utility to simplify the API of supabase-js and make the response fully functional using TaskEither and Option from fp-ts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // fp_ts | |
| import * as O from 'fp-ts/Option'; | |
| import * as TE from 'fp-ts/TaskEither'; | |
| import { pipe } from 'fp-ts/lib/function'; | |
| import { head } from 'fp-ts/lib/Array'; | |
| // Supabase | |
| import { PostgrestFilterBuilder } from '@supabase/postgrest-js'; | |
| import { SupabaseQueryBuilder } from '@supabase/supabase-js/dist/main/lib/SupabaseQueryBuilder'; | |
| import { SupabaseClient } from '@supabase/supabase-js'; | |
| // List of all the tables in your database | |
| // No risk of misspelling the name of the table | |
| type SupabaseTable = 'social'; | |
| // Generic error message with payload | |
| interface ErrorMessage<Extra = unknown> { | |
| title: string; | |
| message: string; | |
| extra: O.Option<Extra>; | |
| } | |
| interface PostgrestError { | |
| message: string; | |
| details: string; | |
| hint: string; | |
| code: string; | |
| } | |
| const _supabaseRequest = <ReturnType, ErrorType = unknown>( | |
| query: PostgrestFilterBuilder<ReturnType>, | |
| { | |
| noDataErrorMessage, | |
| onRequestErrorMessage, | |
| extraError, | |
| }: { | |
| noDataErrorMessage: string; | |
| onRequestErrorMessage: (error: PostgrestError) => string; | |
| extraError?: ErrorType; | |
| } | |
| ): TE.TaskEither<ErrorMessage<ErrorType>, ReturnType[]> => | |
| TE.tryCatch<ErrorMessage<ErrorType>, ReturnType[]>( | |
| () => | |
| new Promise((resolve, reject) => | |
| query.then(({ error, data }) => | |
| error == null | |
| ? data != null | |
| ? resolve(data) | |
| : reject(noDataErrorMessage) | |
| : reject(onRequestErrorMessage(error)) | |
| ) | |
| ), | |
| (reason) => ({ | |
| title: `Data request error`, | |
| message: `${reason}`, | |
| extra: O.fromNullable(extraError), | |
| }) | |
| ); | |
| // Request a list of rows | |
| export const supabaseRequestList = | |
| <ReturnType, ErrorType = unknown>( | |
| table: SupabaseTable, | |
| execute: ( | |
| query: SupabaseQueryBuilder<ReturnType> | |
| ) => PostgrestFilterBuilder<ReturnType>, | |
| extra?: { extraError?: ErrorType } | |
| ) => | |
| ( | |
| source: SupabaseClient | |
| ): TE.TaskEither<ErrorMessage<ErrorType>, ReturnType[]> => | |
| _supabaseRequest(execute(source.from<ReturnType>(table)), { | |
| noDataErrorMessage: `No data list is available (in table ${table})`, | |
| onRequestErrorMessage: ({ message }) => | |
| `Request list error (in table ${table}): ${message}`, | |
| extraError: extra?.extraError, | |
| }); | |
| // Request only a single row | |
| export const supabaseRequestSingle = | |
| <ReturnType, ErrorType = unknown>( | |
| table: SupabaseTable, | |
| execute: ( | |
| query: SupabaseQueryBuilder<ReturnType> | |
| ) => PostgrestFilterBuilder<ReturnType>, | |
| extra?: { extraError?: ErrorType } | |
| ) => | |
| ( | |
| source: SupabaseClient | |
| ): TE.TaskEither<ErrorMessage<ErrorType>, ReturnType> => | |
| pipe( | |
| _supabaseRequest(execute(source.from<ReturnType>(table)).limit(1), { | |
| noDataErrorMessage: `No data is available (in table ${table})`, | |
| onRequestErrorMessage: ({ message }) => | |
| `Request error (in table ${table}): ${message}`, | |
| extraError: extra?.extraError, | |
| }), | |
| TE.chain((dataList) => | |
| pipe( | |
| dataList, | |
| head, | |
| O.fold( | |
| (): TE.TaskEither<ErrorMessage<ErrorType>, ReturnType> => | |
| TE.left({ | |
| title: 'Request error', | |
| message: `Data requested is missing (in table ${table})`, | |
| extra: O.none, | |
| }), | |
| (data) => TE.of(data) | |
| ) | |
| ) | |
| ) | |
| ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment