Created
May 29, 2023 16:44
-
-
Save MartinMalinda/c77e1691f3e8839955bbe2f0653492d3 to your computer and use it in GitHub Desktop.
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
import { SupabaseClient } from "@supabase/supabase-js"; | |
import { GenericSchema } from "@supabase/supabase-js/dist/module/lib/types"; | |
import { supabase } from "/~/data/supabase"; | |
import { defineStore } from "pinia"; | |
export function defineSupaStore<Database, SchemaName extends string & keyof Database, Schema extends GenericSchema, TableName extends string & keyof Schema['Tables']>(supabase: SupabaseClient<Database, SchemaName, Schema>, tableName: TableName) { | |
const table = () => supabase.from(tableName); | |
type Row = Schema['Tables'][TableName]['Row']; | |
type Insert = Schema['Tables'][TableName]['Insert']; | |
type Update = Schema['Tables'][TableName]['Update']; | |
type FilterBuilder = ReturnType<ReturnType<typeof table>['select']>; | |
return defineStore(`supabase-${String(tableName)}`, { | |
state: () => { | |
const state = { | |
[tableName]: {} | |
} as { [K in TableName]: Record<string, Row> }; | |
return state; | |
}, | |
actions: { | |
add(entities: Row[]) { | |
return entities.map(entity => (this as any)[tableName][(entity as any).id] = entity) as Row[]; | |
}, | |
async select(key: '*' | undefined) { | |
const { data, error } = await table().select(key); | |
if (error) { | |
throw error; | |
} | |
return this.add(data); | |
}, | |
async update(id: Row['id'], data: Partial<Update>) { | |
const { data: items, error } = await table().update(data as any).eq('id', id).select('*'); | |
if (error) { | |
throw error; | |
} | |
const [item] = items; | |
if (!item) { | |
throw new Error(`Could not save ${tableName}:${id}. Perhaps a problem with RLS?`); | |
} | |
Object.assign(this[tableName as any][id], item); | |
return this[tableName as any][id] as Row; | |
}, | |
async delete(id: Row['id']) { | |
const { data: items, error } = await table().delete().eq('id', id).select('*'); | |
if (items?.length === 0) { | |
throw new Error(`Could not delete ${tableName}:${id}. Perhaps a problem with RLS?`); | |
} | |
if (Number(items?.length) > 1) { | |
console.error(`Deleting ${tableName}:${id}`) | |
throw new Error('Something went wrong'); | |
} | |
if (error) { | |
throw error; | |
} | |
delete this[tableName as any][id]; | |
return; | |
}, | |
async insert(data: Insert) { | |
const { data: items, error } = await table().insert(data as any).select('*'); | |
if (error) { | |
throw error; | |
} | |
if (!items?.[0]) { | |
throw new Error(`Could not insert into ${tableName}. Perhaps a problem with RLS?`); | |
} | |
return this.add(items)[0]; | |
}, | |
async save(data: Insert | Update) { | |
if (data.id) { | |
return this.update(data.id as any, data); | |
} | |
return this.insert(data); | |
}, | |
async query(cb: (filterBuilder: FilterBuilder) => FilterBuilder) { | |
const { data, error } = await cb(table().select('*')); | |
if (error) { | |
throw error; | |
} | |
return this.add(data as any[]); | |
}, | |
async find(id: Row['id'], options?: { reload?: boolean }) { | |
const localEntity = this[tableName as any][id]; | |
if (localEntity && !options?.reload) { | |
return localEntity as Row; | |
} | |
const { data, error } = await table().select('*').eq('id', id); | |
if (error) { | |
throw error; | |
} | |
if (!data[0]) { | |
throw new Error(`Could not find ${tableName}:${id}`); | |
} | |
return data[0]; | |
}, | |
peek(id: Row['id']) { | |
return this[tableName as any][id] as Row | undefined; | |
}, | |
peekAll() { | |
return Object.values(this[tableName as any]) as Row[]; | |
} | |
} | |
}) | |
} | |
const useResourceStore = defineSupaStore(supabase, 'learning_resources'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment