NicolasReibnitz/vuemodel-supabase
I updated Luke's fine @vuemodel/supabase package to work with @supabase/supabase-js ^2.13.1.
# npm
npm install 'git@github.com:NicolasReibnitz/vuemodel-supabase.git'
# or yarn
yarn add 'git@github.com:NicolasReibnitz/vuemodel-supabase.git'
Import it just like the original package as @vuemodel/supabase
.
Or even better, use the Quasar App Extension @vuemodel/supabase.
You will also need the fork of Luke's @vueauth/supabase package for supabase v2.
You can find that here: NicolasReibnitz/vueauth.
useModel
, useModelCollection
and useModelAPI
now require the user ID to be passed in as the second argument. This is because the synchronous supabase.auth.user()
is no longer available in the new version of the Supabase client. The new supabase.auth.getUser()
is asynchronous, so the user ID must be passed in manually for this to work well with the Vue composition API and <script setup />
.
Here is an example of how to use this with VueAuth:
import { useAuthState } from '@vueauth/core';
import { useModel, useModelCollection, useModelAPI } from '@vuemodel/supabase/src/main';
const authState = useAuthState();
const userID = authState?.user?.value?.id;
const service = useModel(model, userID);
const serviceCollection = useModelCollection(model, userID);
const serviceAPI = useModelAPI(model, userID);
ApiError
was renamed toAuthError
Nicolas
Currently, this package is a bit of an experiment! If you'd like to use these concepts in production that's okay, yet I'd recommend forking this repo and making it your own. At least until these concepts standardize.
Enough preamble. Let's dive in! 🤿
import { SupabasePlugin } from '@vuemodel/supabase';
Vue.install(SupabasePlugin, {
credentials: {
supabaseUrl: 'your-supabase-url',
supabaseKey: 'your-supabase-key'
}
});
import { useModel } from '@vuemodel/supabase'
export default class Todo extends Model {
static entity = 'todos'
static fields () {
return {
id: this.uid(),
title: this.string(''),
done: this.boolean(false),
}
}
}
const todoService = useModel(Todo)
/**
* 🤿 When finding, upating, or deleting a model
* You first need to set the id
*/
todoService.id.value = 7
todoService.find()
todoService.remove()
/**
* 🤿 When creating/updating a new model, the form is
* already generated for you!
*/
// Creating
todoService.form.value {
title: 'buy shoes',
done: false
}
todoService.create()
// Updating
todoService.form.value {
done: true
}
todoService.update()
/**
* Of course, we have access to the model
*/
todoService.id.value = 7
console.log(todoService.model.value)
/**
* Need to reset the form? Gotcha covered!
*/
todoService.resetForm()
/**
* You don't even have to deal with errors!
*/
todoService.form.value {
done: 'this should be a boolean 😱'
}
await todoService.update()
console.log(todoService.error.value)
/**
* We have access to all of the models
* possible loading states...
*/
todoService.creating.value
todoService.finding.value
todoService.updating.value
todoService.removing.value
todoService.loading.value
useModelCollection hasn't been fleshed out yet! More to come :)
import { useModelCollection } from '@vuemodel/supabase';
export default class Todo extends Model {
static entity = 'todos';
static fields() {
return {
id: this.uid(),
title: this.string(''),
done: this.boolean(false)
};
}
}
const todoCollectionService = useModel(Todo);
/**
* 🤿 Let's go get some models from the backend!
*/
todoCollectionService.index();
/**
* 🤿 Filter models by ids
*/
todoCollectionService.ids.value = [1, 3, 5];
/**
* 🤿 Of course, you'll want access to the collection...
*/
todoCollectionService.collection.value;
/**
* 🤿 Want to add in a loading spinner?
*/
todoCollectionService.indexing.value;
/**
* 🤿 And finally, let's take a look at error handling
*/
await todoCollectionService.index();
console.log(todoCollectionService.error.value);
Note that in the real world, you'll probably want to use destructuring. For example:
<script setup>
const { form, create, creating, error } = useModel(Todo);
</script>
<template>
<input v-model="form.title" />
<button :disabled="creating" @click="create">create</button>
<span v-if="creating">creating...</span>
<span v-if="error">{{ error.message }}</span>
</template>
I'll likely add:
- Scoping
- Filtering
- Batch operations As the Supabase API makes this possible! So stay tuned for that 😄