Skip to content

Commit 8b12b0f

Browse files
committed
feat: improve documentation
1 parent b60a456 commit 8b12b0f

File tree

1 file changed

+147
-11
lines changed

1 file changed

+147
-11
lines changed

docs/docs-main/hooks-and-events/index.md

Lines changed: 147 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -203,28 +203,164 @@ pokedexModule.stream()
203203

204204
### Prevent Doc Removal During Stream
205205

206-
> documentation below is still WIP
206+
When using Firestore streams with `where` clauses, documents can be removed from your local cache if they no longer match the query filters. This happens when a document's data changes and no longer satisfies the stream's conditions.
207207

208-
> hint: returning `undefined` will discard the document change and do nothing with the local cache store
208+
You can prevent this automatic removal by returning `undefined` from the `removed` hook. This keeps the document in your local cache even when it no longer matches the stream's where clause.
209+
210+
**Real-world example**: In a Pokemon game, you might have a stream showing only Pokemon that are "available for battle" (not fainted, not in the PC, etc.). But you want to keep legendary Pokemon visible in the UI even if they temporarily become unavailable, so players can see their stats and plan their team.
211+
212+
```js
213+
const pokedexModule = magnetar.collection('pokedex')
214+
215+
// Stream only Pokemon available for battle, but keep ALL in cache when they faint
216+
pokedexModule
217+
.where('status', '==', 'available')
218+
.where('hp', '>', 0)
219+
.orderBy('level', 'desc')
220+
.stream(undefined, {
221+
modifyReadResponseOn: {
222+
removed: (payload) => {
223+
// Keep ALL Pokemon in cache even if they become unavailable
224+
// This allows us to see their stats and plan our team
225+
return undefined // This prevents removal from local cache
226+
},
227+
},
228+
})
229+
230+
// Later, when any Pokemon faints (hp becomes 0):
231+
// - Firestore removes it from the stream because hp <= 0
232+
// - Our removed hook prevents it from being removed from local cache
233+
// - The Pokemon stays visible in the UI for reference and team planning
234+
// - We can still see their stats, moves, and other information
235+
```
209236

210237
### Accessing Metadata when Reading Data
211238

212-
> documentation WIP
239+
When reading data from your remote store, you can access metadata as a second parameter in your `modifyReadResponseOn` functions. This metadata contains the full Firestore DocumentSnapshot, which includes the document ID and other server-side information.
213240

214-
> hint: you can access the metadata as second param
241+
**Real-world example**: You might want to add the document ID to your data in the frontend cache, but not store it as a field in the Firestore document itself. This is useful when you want to keep your database documents clean while still having easy access to the ID in your frontend code.
242+
243+
```js
244+
const pokedexModule = magnetar.collection('pokedex', {
245+
modifyReadResponseOn: {
246+
added: (payload, metadata) => {
247+
// Add the document ID to the data for frontend use
248+
return {
249+
...payload,
250+
id: metadata.id, // Add ID from metadata to the document data
251+
}
252+
},
253+
modified: (payload, metadata) => {
254+
// Ensure the ID is always present when documents are modified
255+
return {
256+
...payload,
257+
id: metadata.id,
258+
}
259+
},
260+
},
261+
})
262+
263+
// Now when you access the data in your frontend:
264+
// pokedexModule.doc('001').data // { name: 'Bulbasaur', type: 'grass', id: '001' }
265+
//
266+
// Instead of having to do:
267+
// const pokemon = pokedexModule.doc('001').data
268+
// const pokemonWithId = { ...pokemon, id: '001' }
269+
```
215270

216271
## Events
217272

218-
> documentation WIP
273+
Magnetar provides a global event system that you can use to listen to various actions happening throughout your app. This is useful for showing toasts, logging, analytics, or any other side effects.
219274

220-
on
275+
### Global Events
221276

222-
> hint: use case: toasts
277+
You can set up global events when you instantiate Magnetar. These events will be triggered for all modules and actions.
223278

224-
> hint: use case: developer logging (see setup for now)
279+
```js
280+
import { logger } from '@magnetarjs/utils'
281+
282+
export const magnetar = Magnetar({
283+
stores: { cache, remote },
284+
executionOrder: {
285+
read: ['cache', 'remote'],
286+
write: ['cache', 'remote'],
287+
delete: ['cache', 'remote'],
288+
},
289+
on: {
290+
// Log all successful actions
291+
success: (event) => {
292+
console.log('✅ Success:', event.actionName, event.path)
293+
},
294+
// Show toast for errors
295+
error: (event) => {
296+
showToast(`Error: ${event.error.message}`, 'error')
297+
},
298+
// Track analytics for writes
299+
before: (event) => {
300+
if (
301+
event.actionName === 'insert' ||
302+
event.actionName === 'merge' ||
303+
event.actionName === 'replace'
304+
) {
305+
analytics.track('data_written', {
306+
action: event.actionName,
307+
path: event.path,
308+
store: event.storeName,
309+
})
310+
}
311+
},
312+
},
313+
})
314+
```
225315

226-
### Global Events
316+
### Available Events
317+
318+
The following events are available:
319+
320+
- `before` — triggered before any action starts
321+
- `success` — triggered when any action completes successfully
322+
- `error` — triggered when any action fails
323+
- `revert` — triggered when an action is reverted due to an error
324+
325+
Each event object contains:
326+
327+
- `actionName` — the action that was performed (fetch, insert, merge, etc.)
328+
- `path` — the module path where the action occurred
329+
- `storeName` — the store name where the action occurred
330+
- `payload` — the data involved in the action
331+
- `collectionPath` — the collection path
332+
- `docId` — the document ID (if applicable)
333+
- `pluginModuleConfig` — the module configuration
334+
- `error` — error details (for error events only)
335+
- `result` — the result of the action (for success events)
336+
- `abort` — function to abort the action (for before events)
337+
338+
### Debug Logging
339+
340+
Magnetar provides a built-in logger for debugging database operations. Enable it by adding the logger to your success events:
341+
342+
```js
343+
import { logger } from '@magnetarjs/utils'
227344

228-
> documentation WIP
345+
export const magnetar = Magnetar({
346+
stores: { cache, remote },
347+
on: {
348+
success: logger, // Logs all successful operations
349+
},
350+
})
351+
```
229352

230-
> hint: you can setup global events when you instantiate magnetar
353+
The logger outputs formatted messages like:
354+
355+
```
356+
💫 [magnetar] db.collection('pokedex').where('type', '==', 'fire').fetch() fetch()
357+
💫 [magnetar] db.collection('pokedex').doc('006').insert({ name: 'Charizard' }) insert()
358+
```
359+
360+
**Important**: Disable logging in production:
361+
362+
```js
363+
on: {
364+
success: import.meta.env.DEV ? logger : undefined,
365+
}
366+
```

0 commit comments

Comments
 (0)