Skip to content

Releases: directus/rstore

v0.8.0

25 Oct 06:21

Choose a tag to compare

🚀 Enhancements

  • Revamped cache and layers for faster performance (2b59e9b)
  • nuxt: Newer nuxt dependency and related improvements (baa8497)
  • query: Use onServerPrefetch to allow SSR without awaiting the query in script setup (1f3394f)
  • drizzle: Realtime updates with websockets (1070ed5)
  • Offline (9556f2b)

🔥 Performance

  • Simpler relation lookup (1e0319f)

🩹 Fixes

  • Call plugin setup simultaneously so they have the Nuxt context, preventing errors (d0ec259)
  • directus: Import form #imports instead of nuxt/app (6c854e4)
  • drizzle: Use /api/rstore-realtime/ws as default websocket path (420ee34)

📖 Documentation

🏡 Chore

❤️ Contributors

v0.7.8

20 Oct 12:43

Choose a tag to compare

🩹 Fixes

  • drizzle: Dialect is wrong (491b3c4)
  • directus: Skip folder 'collections', closes #51 (#51)
  • Remove item relation cache (aa34b9a)

❤️ Contributors

v0.7.7

13 Oct 13:00

Choose a tag to compare

🚀 Enhancements

  • Many mutations added to collection hooks (9c229a1)
  • drizzle: Return deleted item (95c0391)

🔥 Performance

  • Shallow items in the cache (3c0b535)

🩹 Fixes

  • Improve item wrapping for fetchPolicy 'no-cache' (d0fbe6e)
  • Deduplicate wrapped items ownKeys (4673a1f)
  • Handle JSON stringifying wrapped items (d0158f3)
  • gc: Don't run a garbage collection on query unmount (f180d31)

❤️ Contributors

v0.7.6

05 Oct 16:48

Choose a tag to compare

🩹 Fixes

  • gc: Handle fetch skipped (abd8609)
  • Improve experimentalGarbageCollection query option (c66df81)
  • gc: Handle non wrapped items (73dda4c)

❤️ Contributors

v0.7.5

04 Oct 12:53

Choose a tag to compare

🚀 Enhancements

  • New garbage collector (2378647)
  • Expose useQueryTracking (42865ff)
  • Allow passing meta to find options (ed8e3d0)
  • AddToQueryTracking (cdfc3f8)

🩹 Fixes

  • devtools: Cache count per collection not working if no layer is selected (2a157a3)
  • More stable tracking query id (b1d8ae1)
  • Enumerate relations and computed so watch deep works (b737d9a)
  • Export setActiveStore (3484a28)

📖 Documentation

🌊 Types

  • New RstoreGlobal augmentable interface to apply custom store types to plugin hooks etc. (0bc5706)

❤️ Contributors

v0.7.4

23 Sep 11:01

Choose a tag to compare

🚀 Enhancements

  • form: ResetOnSuccess: false (787889d)
  • form: ValidateOnSubmit + pickOnlyChanged, closes #47 (#47)

🩹 Fixes

  • nuxt-drizzle: IsNull and similar where clause with no value not working (c19fd47)

🌊 Types

  • form: Allow void in submit (3372faa)

❤️ Contributors

v0.7.3

19 Sep 20:35

Choose a tag to compare

🚀 Enhancements

  • devtools: Improved filters (a3f59d3)
  • devtools: Cache layers (d7d1038)
  • devtools: Go to cache tab from collections (dd18099)
  • cache: Handle frozen items in writeItem (6586aec)
  • nuxt-drizzle: Extras in query transform (803a569)
  • CreateMany, updateMany, deleteMany (40aaa50)

🔥 Performance

  • cache: Iterate over state directly (7016950)
  • devtools: Considerably reduce overhead of adding history records (453f85a)

🩹 Fixes

  • Relations undefined if fetchPolicy is no-cache (9845539)
  • Use item as proxy target to improve dx in browser devtools (a11b218)
  • devtools: Local icon (35bcdc5)
  • nuxt-drizzle: Allow any field in where clauses (84301f1)
  • nuxt-drizzle: OrderBy allow any column name (b7d07b5)
  • cache: Handle existing frozen items in cache (f4bb64f)

❤️ Contributors

v0.7.2

17 Sep 09:43

Choose a tag to compare

🩹 Fixes

  • cache: Auto remove layer with same id (3f94499)
  • Always abort from collection hooks (9810cc7)

🌊 Types

  • Add TCollection generic to CustomCollectionMeta (ab1e8ed)

❤️ Contributors

v0.7.1

16 Sep 07:43

Choose a tag to compare

🚀 Enhancements

  • nuxt-drizzle: Expose filterWhere (e79683d)

🔥 Performance

  • Fast path for getStateForCollection (c7a8831)
  • Cache relations for one tick (04ac3fa)

🩹 Fixes

  • nuxt-drizzle: Key from primary keys adding up numbers (cffbef7)
  • nuxt-drizzle: Multi primary key update (e91be9c)

📖 Documentation

❤️ Contributors

v0.7.0

12 Sep 15:07

Choose a tag to compare

Breaking changes

Throughout the codebase, the term Model was changed to Collection to prevent confusion with Vue's own model API. A lot of APIs also were simplified and cleaned up, or changed to improve type checking with TypeScript.

Read the Migration Guide

New Features

Collection Hooks

To make it easier to get started, you can now directly define some functions on the collections themselves to implement logic for fetching and mutating the data.

import { defineCollection } from '@rstore/vue'

export const todoCollection = defineCollection({
  name: 'todos',
  // Interact with a REST/GraphQL/etc. API
  hooks: {
    fetchFirst: ({ key }) => fetch(`/api/todos/${key}`).then(r => r.json()),
    fetchMany: ({ params }) => fetch('/api/todos').then(r => r.json()),
    create: ({ item }) => { /* ... */ },
    update: ({ key, item }) => { /* ... */ },
    delete: ({ key }) => { /* ... */ },
  },
})

New Relations API

You should now use defineRelations instead of the collection relations option, to enjoy better typechecking. The syntax has also changed to be less error-prone, allow matching on multiple fields and with a custom filter function.

import { createStore, defineCollection, defineRelations } from '@rstore/vue'

const collection1 = defineCollection({ name: 'collection1' })
const collection2 = defineCollection({ name: 'collection2' })

const collection1Relations = defineRelations(collection1, ({ collection }) => ({
  relatedItems: {
    to: collection(collection2, {
      on: {
        'collection2.foreignKey': 'collection1.id', // Type checked!
      },
      // filter: (itemCol1, itemCol2) => true
    }),
    many: true, // One-to-many relation
  },
}))

const store = await createStore({
  schema: [
    collection1,
    collection2,
    collection1Relations,
  ],
})

Simplified Nuxt setup

You can remove the export default [...] array and instead directly export the collections from the schema files in Nuxt projects, which is much simpler and less error-prone.

export const users = RStoreSchema.withItemType<User>().defineCollection({
  name: 'users',
})

export const bots = RStoreSchema.withItemType<Bot>().defineCollection({
  name: 'bots',
})

New Query API

The new query and liveQuery methods replace queryFirst, queryMany, liveQueryFirst and liveQueryMany to provide improved TypeScript checking (see the Migration Guide for more details).

const { data: todo } = store.Todo.query(q => q.first('some-key'))

const email = ref('@acme.com')
const { data: someUsers } = store.User.query(q => q.many({
  filter: item => item.email.endsWith(email.value),
  params: {
    email: {
      $like: `%${email.value}`,
    },
  },
}))

Simplified Modules API

The syntax to define Modules has been greatly simplified (see the Migration Guide for more details).

import { defineModule } from '@rstore/vue'

export const useAuth = defineModule('auth', ({ store, defineState, defineMutation, onResolve }) => {
  const state = defineState({
    // Create some state here
    currentUserKey: null as string | null,
  })

  return {
    // Expose things here
  }
})

The mutation state also got simplified, without the need for .value:

<script setup lang="ts">
const auth = useAuth() // A module defined with defineModule
</script>

<template>
  <UAlert
    v-if="auth.login.$error"
    :description="auth.login.$error.message"
    color="error"
  />
  <UButton
    type="submit"
    :loading="auth.login.$loading"
  />
</template>

Optimistic updates

Mutations automatically apply the changes without waiting for server responses, making the UI feel more responsive. You can disable optimistic updates by passing the optimistic: false option to the mutation method.

const newTodo = await store.todos.create({
  title: 'New Todo',
  completed: false,
}, {
  optimistic: false,
})

You can customize the expected result of the mutation by passing an object to the optimistic option. It will be merged with the data you pass to the mutation method but can override it.

const newTodo = await store.todos.create({
  title: 'New Todo',
  completed: false,
}, {
  optimistic: {
    id: 'temp-id',
    createdAt: new Date().toISOString(),
  },
})

/*
The optimistic object will be:
{
  id: 'temp-id', // added
  title: 'New Todo',
  completed: false,
  createdAt: '2024-06-01T12:00:00.000Z', // added
}
*/

To know if a record is optimistic, you can check the $isOptimistic property on the record.

const todo = await store.todos.findFirst('some-id')

if (todo.$isOptimistic) {
  console.log('This record is optimistic')
}

Experimental Garbage Collection

You can enable a new experimental experimentalGarbageCollection option so rstore will automatically purge the cache from items that are not returned by queries (usually when they are deleted on the servers).

createStore({
  experimentalGarbageCollection: true,
})

For nuxt:

// nuxt.config.ts
export default defineNuxtConfig({
	rstore: {
		experimentalGarbageCollection: true,
	},
});

Layered Plugins

Several new Plugins features allow handling complex layered data flows:

  • Plugin Categories to automatically sort the call order of plugins: 'virtual', 'local', 'remote', 'processing'.
  • Sorting overrides in the plugin definitions.
  • Abort API to prevent calling further plugin callbacks for a hook.
  • Auto-aborting of fetchFirst, fetchMany, createItem and updateItem when calling setResult with a non-empty result.
import { definePlugin } from '@rstore/vue'

export default definePlugin({
  name: 'my-plugin',

  // Will be after 'virtual' and 'local' plugins and before 'processing' plugins
  category: 'remote',

  // Override sorting
  before: {
    plugins: ['another-plugin'],
    categories: ['remote'],
  },
  // after: { ... },

  setup({ hook }) {
    hook('deleteItem', ({ abort }) => {
      // ...
      abort()
    })
  },
})

Drizzle Hooks

The Nuxt+Drizzle module received a host of new features around hooking into the generated API.

import * as tables from 'path-to-your-drizzle-schema'

export default defineNitroPlugin(() => {
  // Deny access to all the other tables
  allowTables([
    tables.todos,
  ])

  // Implement permissions or other logic
  hooksForTable(tables.todos, {
    'index.get.before': async (payload) => {
      console.log('Specific hook for todos - index.get.before', payload.collection, payload.query, payload.params)
    },
    'index.get.after': async (payload) => {
      console.log('Specific hook for todos - index.get.after', payload.collection, payload.result.map(r => r.id))
    },
    'item.patch.after': async (payload) => {
      console.log('Specific hook for todos - item.patch.after', payload.collection, payload.result.id)
    },
  })
})

Devtools improvements

  • New Cache Tab
image
  • Improved Plugins Tab
image
  • Many other improvements and fixes

Detailed changelog

🚀 Enhancements

  • New schema and relation declarations (844635b)
  • devtools: New cache tab (5be73c2)
  • New query API (04c4e34)
  • cache: ReadItems new limit option (bc7d1fa)
  • Experimental garbage collection (a119680)
  • devtools: Auto update cache (e7326da)
  • Cache layers (43519e0)
  • Optimistic updates (04a5c63)
  • devtools: Gc + cache layer events in history (9a1ccef)
  • UseStore + new setup docs (cbd97d6)
  • New module API (07c2c9c)
  • SetActiveStore for tests (d32cc67)
  • nuxt-drizzle: Remove deprecated option drizzleImport.default (2e737ba)
  • nuxt-drizzle: Drizzle hooks (c7cb660)
  • nuxt-drizzle: Adapt to new relations syntax (f2a5088)
  • nuxt-drizzle: Use new define model syntax (3edb432)
  • Use nuxt module dependencies (9be4ab5)
  • nuxt: Simpler schema syntax with export const (b6aa3fa)
  • nuxt-drizzle: HooksForTable (6e9f3d0)
  • nuxt-drizzle: AllowTables (c8361d3)
  • Sort plugins (b727f31)
  • plugin: Auto abort fetchFirst & fetchMany (7ce07ae)
  • plugin: Category (ec1a41b)
  • Collection hooks (c6824b1)
  • module: $loading, $error, $time no longer Refs (d98f1c2)
  • plugin: Abort API (541d41d)
  • plugin: Abort API for fetchRelations (b72474a)
  • plugin: Auto abort createItem and updateItem (0d8218a)

🔥 Performance

  • Faster relation lookup (#44)
  • Normalize relations eagerly (1a25f54)

🩹 Fixes

  • devtools: Cache model item height (12b5ee9)
  • Disallow excess properties in withItemType().defineModel() (c7c2f1f)
  • Always wrap items out of find methods (f7cc489)
  • Store.$getModel should use item.$model (2383304)
  • devtools: Automatically update cache filtering (52c6da2)
  • devtools: Sort models (a50c7de)
  • Clone properties for mutations (c1d614d)
  • Optimistic updates using serialized item (8f21f2f)
  • Don't always clone properties in pickNonSpecialProps (86ceeff)
  • devtools: Cache model item height (276b3c5)
  • Lower minimum dep version of @nuxt/kit (8503aa5)
  • nuxt-drizzle: Missing getQuery import (39d613e)
  • **nuxt-drizzl...
Read more