Setup
Main Setup
To instantiate Magnetar, you need to first instantiate the store plugins you will use:
- instantiate a plugin for a remote data store
- instantiate a plugin for a local cache data store
- then instantiate the Magnetar instance with those plugins
Example
This is a complete setup example which uses:
- the Firestore plugin for remote data store
- the Vue 3 plugin for local cache data store
Please note: in reality it's cleaner to have all imports at the top
import { initializeApp } from 'firebase/app'
import { getFirestore, collection, doc } from 'firebase/firestore'
import { Magnetar } from '@magnetarjs/core'
import { CreatePlugin as PluginFirestore } from '@magnetarjs/plugin-firestore'
import { CreatePlugin as PluginVue3 } from '@magnetarjs/plugin-vue3'
import { logger } from '@magnetarjs/utils'
// ---------------------------------------------
// 0. Initialise firebase
// ---------------------------------------------
const firebaseApp = initializeApp({ /* pass your config... */ })
const db = getFirestore(firebaseApp)
/**
* A helper function that generates a random Firestore ID
*/
function generateRandomId () { return doc(collection(db, 'random')).id }
// ---------------------------------------------
// 1. the plugin firestore for remote data store
// create the remote store plugin instance & pass your `db`:
// ---------------------------------------------
const remote = PluginFirestore.CreatePlugin({ db })
// ---------------------------------------
// 2. the plugin vue3 for cache data store
// create the cache store plugin instance & pass your `generateRandomId`:
// ---------------------------------------
const cache = PluginVue3.CreatePlugin({ generateRandomId })
// -----------------------------------------------------
// 3. instantiate the Magnetar instance with the store plugins
// -----------------------------------------------------
export const magnetar = Magnetar({
stores: { cache, remote },
executionOrder: {
read: ['cache', 'remote'],
write: ['cache', 'remote'],
delete: ['cache', 'remote'],
},
on: { success: logger }, // disable this on production builds
})
Some info on the main Magnetar instance props:
stores
⸺ an object with the store name as key and the store plugin instance as value, needs at least one plugin for thecache
key, the other keys you can choose the nameexecutionOrder
⸺ the execution order of your stores, this order is required for optimistic UI (but can be flipped)on
⸺ event listeners for anything that happens in Magnetar, see the Events chapter for more info
Working with Modules
You can access/create modules with a simple collection(path)
and doc(path)
syntax. The path will be interpreted by whichever store plugins you use.
Eg. Using the Firestore plugin, these module paths will point to the Firestore collection and document paths in our Firebase console.
// access the collection:
magnetar.collection('pokedex')
// access a sub-doc via its collection:
magnetar.collection('pokedex').doc('001')
// access a sub-doc via its path:
magnetar.doc('pokedex/001')
Ideally you want to create a separate file for the modules you intend to use (or one file per module). This way you can more easily add some documentation on how the data structure looks for your database documents. (for more info on this read Module Setup)
import { magnetar } from 'magnetarSetup.js'
export const pokedexModule = magnetar.collection('pokedex')
export const trainerModule = magnetar.doc('app-data/trainer')
Module Data & Methods
Using your collection or document modules, you can access the data
, id
and several methods.
Any data accessed is readonly! To "mutate" the data, you have to use the provided methods. This is good because any kind of mutation is supposed to go through a function so it can be synced to your local cache & remote stores.
Here we show some of the data and methods you can access on a module:
Collection Modules
You can access all documents in a collection via the data
property. data
is a Map ? with the document ids as key and the document data as value.
const pokedexModule = magnetar.collection('pokedex')
// accessing data
pokedexModule.data // Map<'001': { name: 'bulbasaur' }, /* etc...*/ >
pokedexModule.id // 'pokedex'
pokedexModule.path // 'pokedex' (the full path)
// methods to write data
pokedexModule.insert({ name: 'Squirtle' }) // inserts a new document
pokedexModule.delete('001') // deletes a document
// methods to read data
pokedexModule.fetch() // fetches documents from the remote store & caches them locally
pokedexModule.stream() // opens a database stream & caches incoming documents locally
Document Modules
You can access a document's data via the data
property. In this case it will be a single object, since a document module represents only a single object.
const pokemonModule = magnetar.doc('pokedex/001')
// or
const pokemonModule = magnetar.collection('pokedex').doc('001')
// accessing data
pokemonModule.data // { name: 'Bulbasaur', level: 1 }
pokemonModule.id // '001'
pokemonModule.path // 'pokedex/001'
// methods to write data
pokemonModule.replace({ name: 'Ivysaur', level: 16 }) // sets new data
pokemonModule.merge({ level: 17 }) // updates the document by deep merging the new data
pokemonModule.assign({ level: 17 }) // updates the document by shallow merging the new data
pokemonModule.deleteProp('name') // deletes a property from the document
pokemonModule.delete() // deletes the document
// methods to read data
pokemonModule.fetch() // fetches the document from the remote store & caches it locally
pokemonModule.stream() // opens a database stream & keeps the cached document up to date locally
Displaying Data in the DOM
- A Magnetar collection's
.data
is a Map ? - A document's
.data
is a plain object
Here we show to how make sure your DOM is updated reactively whenever this data changes.
Vue Example
In Vue you must make sure you use the Vue 2 or Vue 3 plugin as local cache store which will enable reactivity.
You can use a computed prop to show the data in your template like so:
<template>
<div>
<div v-for="p in pokemon" :key="p.id">{{ p.name }}</div>
</div>
</template>
export default {
computed: {
pokemon() {
return pokedexModule.data.values()
},
},
}
React Example
// todo
Svelte Example
// todo
Vanilla JS Example
// todo