The Vuex plugin to enable Object-Relational Mapping access to the Vuex Store.

Overview

Vuex ORM

Vuex ORM

Travis CI codecov npm JavaScript Style Guide License


πŸ”₯ HEADS UP! Currently, Vuex ORM Next project is on going, and we are hoping it is going to be the foundation of the version 1.0.0 release. We're not planning to add features to current v0.36.3 due to focusing more on Vuex ORM Next development. If you're new to Vuex ORM, please try out Vuex ORM Next.


Vuex ORM is a plugin for Vuex to enable Object-Relational Mapping access to the Vuex Store. Vuex ORM lets you create "normalized" data schema within Vuex Store with relationships such as "Has One" and "Belongs To Many" like any other usual ORM library. It also provides fluent API to get, search and update Store state.

Vuex ORM is heavily inspired by Redux recipe of "Normalizing State Shape" and "Updating Normalized Data". Learn more about the concept and motivation of Vuex ORM at What is Vuex ORM?.

Sponsors

Vuex ORM is sponsored by awesome folks. Big love to all of them from whole Vuex ORM community πŸ’•

Super Love Sponsors

Peter TΓ³th Mario Kolli Cannikan Andy Koch Dylan Copeland

Big Love Sponsors

geraldbiggs Cue Kazuya Kawaguchi jShaf ibrainventures

A Love Sponsors

George Chaduneli bpuig John mean-cj Jeffrey Soong

Documentation

You can check out the full documentation for Vuex ORM at https://vuex-orm.org.

Questions & Discussions

Join us on our Slack Channel for any questions and discussions.

Although there is the Slack Channel, do not hesitate to open an issue for any question you might have. We're always more than happy to hear any feedback, and we don't care what kind of form they are.

Examples

You can find example applications built using Vuex ORM at;

Plugins

Vuex ORM can be extended via plugins to add additional features. Here is a list of available plugins.

Also, you can find a list of awesome things related to Vuex ORM at Awesome Vuex ORM.

Contribution

We are excited that you are interested in contributing to Vuex ORM! Anything from raising an issue, submitting an idea of a new feature, or making a pull request is welcome! Before submitting your contribution though, please make sure to take a moment and read through the following guidelines.

Pull Request Guidelines

When submitting a new pull request, please make sure to follow these guidelines:

  • For feature requests: Checkout a topic branch from dev branch, and merge back against dev branch.
  • For bug fixes: Checkout a topic branch from master branch, and merge back against master branch.

These rules also apply to the documentation. If you're submitting documentation about a new feature that isn't released yet, you must checkout the dev branch, but for non-functional updates, such as fixing a typo, you may checkout and commit to the master branch.

Scripts

There are several scripts to help with development.

$ yarn build

Compile files and generate bundles in dist directory.

$ yarn lint

Lint files using a rule of Standard JS.

$ yarn test

Run the test using Jest.

$ yarn test:watch

Run the test in watch mode.

$ yarn test:perf

Run the performance test.

$ yarn coverage

Generate test coverage in coverage directory.

$ yarn docs

Build and boot documentation server with VuePress.

License

The Vuex ORM is open-sourced software licensed under the MIT License.

Issues
  • Having http plugin – REST API backend support

    Having http plugin – REST API backend support

    Hi. Is it have sense to merge functionality from this repo https://github.com/aarondfrancis/vue-model ?

    I think it would be nice to extend the functionality of the orm, or should it be done in the form of a plug-in thanks to the 0.18 version?

    Or, if it develop as a plug-in, it will turn into dependency hell

    enhancement need discussion 
    opened by VRuzhentsov 40
  • WARN: Cannot stringify arbitrary non-POJOs

    WARN: Cannot stringify arbitrary non-POJOs

    Hi,

    I installed and run vuex-orm/vuex-orm-examples-nuxt and I got warnings on terminal for every page refresh:

     WARN  Cannot stringify arbitrary non-POJOs Todo
    
     WARN  Cannot stringify arbitrary non-POJOs User
    

    I get same warnings in my project, which uses latest Nuxt (v.2.3.2).

    Kind Regards,

    help wanted 
    opened by ozum 27
  • Roadmap To The Version 1.0.0

    Roadmap To The Version 1.0.0

    I think it’s time to consider bumping Vuex ORM version to 1.0.0. The biggest reason is that luckily, I hear many people using Vuex ORM to build their application, and there are already few plugins out there. Hence we should fix the API and make whole application more stable.

    But another reason is that Vuex ORM has almost all relationship types supported. We do have other feature requests as well, but I think some of them can be implemented after version 1.0.0.

    Here are things I would like to do before bumping to 1.0.0.

    • [x] Add Has Many Through relationship.
    • [x] #60 Add action methods to the Model class.
    • [x] #83 Add more complete lifecycle hooks.
    • [x] #90 Add feature to update primary key value with its related records.
    • [x] #98 Remove lodash from dependency.
    • [x] #104 Make nested relation loading work with same top level relation name.
    • [x] #110 Add specific type attributes such as string or number.
    • [x] #136 Define lifecycle hook at models.
    • [x] #143 Implement action to create a fresh record with default values.
    • [x] #150 Add save method to the model.
    • [x] #152 Deep relationship loading fails with morph relation.
    • [x] #164 0.25.1 forEach of null bug.
    • [x] #168 Auto increment the ID value when the value is null.
    • [x] #171 Add nullable chain to the attribute definitions.
    • [x] #231 Save class instances directly to the store.
    • [ ] Fix all issues labeled as bug.
    • [x] Refactor the documentation.

    I would really love to hear any ideas or request regarding this plan from the community. I didn’t think Vuex ORM would become like it’s today that many people use in their project. I get contacted almost every day about this library.

    I’m so thrilled, and I’m willing to make Vuex ORM even more powerful toward the future. Thank you all!

    help wanted need discussion 
    opened by kiaking 25
  • Add single table inheritance (STI) feature.

    Add single table inheritance (STI) feature.

    This doesn't seem possible currently, but is there any plan (or even ability: I'm not a JavaScript guy) to have inheritance mapping similar to Doctrine's single-table inheritance?

    I have a case where I have multiple types of tasks, each a subclass of Task. It seems that the polymorphic relationships that are currently implemented are for cases where multiple parent types may own Task objects. I have the opposite problem, where I have several types of tasks and need to have a parent entity own many (potentially differently typed) tasks.

    I've seen issues #50 and #192, but they both require a sub-key rather than taking advantage of inheritance. While this will work, it requires the creation of a separate entity when all of the required discriminator information is already present.

    It seems to me that it would be possible to have an inheritance mapping and factory method to properly instantiate the correct model type, but I'm not familiar with the code base or the normalizr library. What are your thoughts? I'm happy to help if there's anything I can do.

    enhancement resolved 
    opened by trevorpe 25
  • Why vuex-orm returns null in relationship field?

    Why vuex-orm returns null in relationship field?

    I followed the guide of Defining Relationships in Vuex ORM.

    I did everything like the guide, so why I get null value in the category field in Article Model?

    codesandbox

    This is how I defining my models (category on article is: hasOne/belongTo):

    export class Category extends Model {
      static entity = "categories";
    
      static primaryKey = "_id";
    
      static fields() {
        return {
          _id: this.attr(null),
          name: this.attr("")
        };
      }
    }
    
    
    export class Article extends Model {
      static entity = "articles";
    
      static primaryKey = "_id";
    
      static fields() {
        return {
          _id: this.attr(null),
          name: this.attr(""),
          category: this.hasOne(Category, "_id")
        };
      }
    

    Config Vuex-orm with vuex in main.js:

    import VuexORM from "@vuex-orm/core";
    import { Article, Category } from "./models";
    
    Vue.use(Vuex);
    
    const database = new VuexORM.Database();
    
    const Articles = {
      namespaced: true,
    
      actions: {
        test() {
          console.log(this);
        }
      }
    };
    
    const Categories = {
      namespaced: true,
    
      actions: {
        test() {
          console.log(this);
        }
      }
    };
    
    database.register(Article, Articles);
    database.register(Category, Categories);
    
    const store = new Vuex.Store({
      plugins: [VuexORM.install(database)]
    });
    

    Inside app component I have the data that I insert to vuex and get the values like so:

     const articleData = [
          {
            _id: "6ce9bae00000000000000000",
            name: "article-1",
            category: "5ce9acd00000000000000000"
          }
        ];
        const categoryData = [
          { _id: "5ce9acd00000000000000000", name: "category-1" }
        ];
    
        const x = await Article.insertOrUpdate({ data: articleData });
        const y = await Category.insertOrUpdate({ data: categoryData });
    
        const a = Article.query()
          .with("category")
          .first();
    
        console.log({ a });
        console.log({ type: a.category });
        console.log("why a.category is null???");
    

    I have been trying to understand this for several days without success. I would much appreciate any help.

    opened by wizardnet972 24
  • Convenience Methods

    Convenience Methods

    Many ORMs provide model methods like .find(), .create() or .save(). With Vuex-ORM we have to use rather long lines like this.$store.dispatch('entities/users/create', { data: { ... } }) or this.$store.getters['entities/users/query']().find().

    What do you think about convenience methods like .find(), .first(), .create() and so on on the model class, that dispatch those events against vuex?

    I think that would be a more comfortable way to work with vuex-orm :)

    enhancement 
    opened by phortx 21
  • Caching computed properties per item.

    Caching computed properties per item.

    Dear @kiaking

    I currently have an actual Todo list application that I've been building for over a year now. A very long time ago I had a problem after integrating Vuex that it was difficult to have getters or computed properties saved on a per item basis who's return values are all cached.

    Therefore I made my own solution by building one Vue instance per item.

    I am currently wondering if Vuex-ORM would be a good replacement or not, and especially in terms of keeping the computed properties per item cached.

    This is my solution:

    // imports
    import ItemComputedProperties from './ItemComputedProperties.js'
    
    window.cachedItems = {};
    export default function(id) {
      if (cachedItems[id]) { return cachedItems[id] }
      if (!store.state.nodes[id])
      {
        console.log(`couldn't create new Vue for item ${id} because the node doesn't exist!`);
        return false
      }
      console.log(`creating new Vue for item ${id}!`)
      return cachedItems[id] = new Vue({
        store,
        data: {
          item: store.state.nodes[id],
        },
        computed: ItemComputedProperties,
      });
    }
    

    At the bottom you can see the imported ItemComputedProperties. This is basically a list of about 30 computed properties per item. It contains things like: isDue(), hasParentDue(), visibleChildrenIds(), nextItemId(), isProject(), etc.

    I would make a call like so: itemGetters(48).isDue() which would let me know if item with id 48 is due or not, and this would be used inside Vue components to show/hide things and classes.

    Now I wonder, if I install vuex-orm, which would be more memory intensive. My current solution works fine. I'm wondering the benefits of vuex-orm. Please enlighten me!

    help wanted need discussion 
    opened by mesqueeb 20
  • Insert custom pivot Fields

    Insert custom pivot Fields

    Hi, First at all... awesome library!!! But i have a huge problem. How can i insert custom fields in my Many To Many Polimorphic Relation. This is my gist of relationships... https://gist.github.com/jpenaroche/16d289a97c2cedd889d7172ec41a92d4

    enhancement released 
    opened by jpenaroche 18
  • hasMany gives null array

    hasMany gives null array

    Hi,

    For nested data with array of object

    {
      "phones": [
        {
          "number": "12345678",
          "verified": true
        },
        {
          "number": "123456789",
          "verified": true
        }
      ],
      "emails": [
         {
           "address": "[email protected]",
           "verified": true
         }
      ]
    }
    

    In model field declare with hasMany(....) but it gives null array

    Can you suggest me proper field declaration for array of object?

    question 
    opened by kevadiya93 18
  • Backend API plugin discussion

    Backend API plugin discussion

    Issue continuing from https://github.com/vuex-orm/vuex-orm-graphql/issues/39.

    Related Issue: #44

    Let's see how it goes with the API design!

    /cc @phortx @madmike

    help wanted need discussion 
    opened by kiaking 17
  • build(deps): bump url-parse from 1.5.1 to 1.5.3

    build(deps): bump url-parse from 1.5.1 to 1.5.3

    Bumps url-parse from 1.5.1 to 1.5.3.

    Commits
    • ad44493 [dist] 1.5.3
    • c798461 [fix] Fix host parsing for file URLs (#210)
    • 201034b [dist] 1.5.2
    • 2d9ac2c [fix] Sanitize only special URLs (#209)
    • fb128af [fix] Use 'null' as origin for non special URLs
    • fed6d9e [fix] Add a leading slash only if the URL is special
    • 94872e7 [fix] Do not incorrectly set the slashes property to true
    • 81ab967 [fix] Ignore slashes after the protocol for special URLs
    • ee22050 [ci] Use GitHub Actions
    • d2979b5 [fix] Special case the file: protocol (#204)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • build(deps): bump tmpl from 1.0.4 to 1.0.5

    build(deps): bump tmpl from 1.0.4 to 1.0.5

    Bumps tmpl from 1.0.4 to 1.0.5.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • build(deps): bump prismjs from 1.23.0 to 1.25.0

    build(deps): bump prismjs from 1.23.0 to 1.25.0

    Bumps prismjs from 1.23.0 to 1.25.0.

    Release notes

    Sourced from prismjs's releases.

    v1.25.0

    Release 1.25.0

    v1.24.1

    Release 1.24.1

    v1.24.0

    Release 1.24.0

    Changelog

    Sourced from prismjs's changelog.

    1.25.0 (2021-09-16)

    New components

    Updated components

    ... (truncated)

    Commits
    Maintainer changes

    This version was pushed to npm by rundevelopment, a new releaser for prismjs since your current version.


    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Adding orHas and orHasNot query functions

    Adding orHas and orHasNot query functions

    Is your feature request related to a problem? Please describe...

    In our project we have a use case of needed a orHasNot. Our goal is to retrieve all work orders which are not planned (planned_start is null) OR don't have a users assigned to it so that we can show in a planning tool which work orders require an action (planning and/or assigning a user.

    Describe the solution you'd like

    WorkOrder
        .query()
        .with(...) // Left out for demo purposes
        .where((workOrder, query) => {
            query.where('planned_start', null)
                .orHasNot('users')
        })
        .orderBy(...) // Left out for demo purposes
        .get()
    

    Describe alternatives you've considered

    The alternative that we are forced to use now is (my opinion) ugly code and can be seen below:

    WorkOrder
        .query()
        .with(...) // Left out for demo purposes
        .where((workOrder, query) => {
            if (!workOrder.planned_start) {
                query.where('planned_start', null)
            } else {
                query.hasNot('users')
            }
        })
        .orderBy(...) // Left out for demo purposes
        .get()
    

    Additional context

    I'm looking for something like ->orHas(...) and/or ->orDoesntHave(...) in Laravel. Though considering Vuex's naming with relations I expect them to be called .orHas(...) and .orHasNot('...').

    It would also be highly appreciated if these function can accept a callback as 2nd argument just like has does to further determine which relationships should match.

    opened by rickgoemans 0
  • Question: How to Updating Relationship

    Question: How to Updating Relationship

    First of all, thanks for this amazing project. :) Secondly... yes... I searched a lot and I tried to solve my problem with the docs:

    • https://vuex-orm.org/guide/data/inserting-and-updating.html#updating-relationships
    • https://github.com/vuex-orm/vuex-orm-examples-nuxt

    At this point I'm really confused how it should work correctly. I'm just at the beginning. Using Models on its own are easy to understand, but when I try to add relationships I don't get anywhere.

    Here is my example:

    // Parent Model - Device.js:
    import { Model } from '@vuex-orm/core'
    import Uptime from '@/models/Uptime'
    
    export default class Device extends Model {
        static entity = 'devices'
    
        static primaryKey = ['id']
    
        static fields() {
            return {
                id: this.uid(),
                name: this.string(''),
                uptime: this.hasOne(Uptime, 'device_id')
            }
        }
    }
    
    // Child Model - Uptime.js:
    import { Model } from '@vuex-orm/core'
    
    export default class Uptime extends Model {
        static entity = 'uptimes'
    
        static primaryKey = ['id']
    
        static fields() {
            return {
                id: this.uid(),
                device_id: this.string(null),
                uptime: this.string('').nullable()
            }
        }
    }
    
    // database.js:
    import { Database } from '@vuex-orm/core'
    import Device from '@/models/Device'
    import Uptime from '@/models/Uptime'
    
    const database = new Database()
    
    // Registering Models
    database.register(Device)
    database.register(Uptime)
    
    export default database
    
    // Nuxt Plugin: vuex-orm.js:
    import VuexORM from '@vuex-orm/core'
    import database from '@/database'
    
    export default ({ store }) => {
        VuexORM.install(database)(store)
    }
    
    // Nuxt ~ default.vue layout:
    import Device from '@/models/Device'
    export default {
        async fetch() {
            const deviceName = 'test'
            const device = await Device.create({ data: { name: deviceName } })
            const deviceId = device.devices[0].id
            console.log('deviceId:', deviceId)
            this.setCurrentDeviceId(deviceId) // Vuex action: 'device/setCurrentDeviceId'
            console.log(this.getCurrentDeviceId) // Vuex getter: 'device/getCurrentDeviceId'
        },
        ...
    }
    

    This is where my real problem hides.

    // My component.vue where I try to update my uptime state:
    ...
    methods: {
        getUptime() {
            const url = '/device/uptime'
            this.loading = true
            this.$axios.get(url)
                .then(async(res) => {
                    const uptime = res.data.data.uptime // <- Uptime is just a string here
    
                    // Updating Device with new uptime
                    const check = await Device.update({                <-- Here is my problem
                        // where: this.getCurrentDeviceId, // does not work, because not allowed for relationships
                        data: {
                            id: this.getCurrentDeviceId,
                            uptime: { uptime }
                        }
                    })
                    console.log('check:', check)
                })
            ...
        }
    }
    

    At this point I think its in a very simple state. I want to add more models like Uptime to my parent model Device in the future.

    Many thanks in advance. :)

    Edit: Added the way how I register vuex-orm in nuxt.

    opened by borsTiHD 2
  • build(deps): bump path-parse from 1.0.6 to 1.0.7

    build(deps): bump path-parse from 1.0.6 to 1.0.7

    Bumps path-parse from 1.0.6 to 1.0.7.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Lifecycle Hooks: beforeSelect

    Lifecycle Hooks: beforeSelect

    I am trying to load model with data when empty

    I thought the beforeSelect lifecycle hook could be a good place to run the axios request but this lifecycle should ONLY return a collection and not a Promise. So, is it a good idea to approach the problem this way? If so, is it possible to have an alternative beforeSelect which returns a Promise?

    Thanks!

    question 
    opened by rbayley 1
  • Composite primary keys and null values

    Composite primary keys and null values

    Describe the bug

    When inserting models with composite primary keys, if one of the keys is null, it's inserted with "$uid123" instead of the null value

    Steps to reproduce the bug

    1. Create a model with a composite primary key, one of which is nullable
    2. Insert a model with a null primary key
    3. Notice how it's been inserted at ["1","$uid1"]

    Expected behaviour

    The models to be inserted with the $id containing null values and not $uid1

    Like this: ["1",null]

    Versions

    • Vuex ORM: 0.36.4
    • Vue: 2.6.14

    Link to minimal reproduction

    https://codesandbox.io/s/vuex-orm-crud-sample-forked-qyc8u?file=/src/post.js

    Additional context

    I tried using a mutator setting null, while it fixes the retrieving, it doesn't solve the insertion I also tried using user_id: this.uid(() => null), but it causes a different issue where the created $id is null (ignoring the fact that it's a composite key) if the value of that key is null

    opened by Tofandel 0
  • List rendering issue with keys

    List rendering issue with keys

    Describe the bug

    List rendering ignores the key attribute while rendering vuex-orm resources

    Steps to reproduce the bug

    https://codesandbox.io/s/nostalgic-raman-t2qo9?file=/src/components/App/App.js

    • you can try adding posts traditionally (with ref array)
    • switch with vuex resources
    • compare time / see that every children is re-rendered

    Expected behaviour

    Children should not be re-rendered as the key (uid) is set.

    Versions

    • Vuex ORM: 0.36.3
    • Vue: 3.0.0

    Link to minimal reproduction

    https://codesandbox.io/s/nostalgic-raman-t2qo9?file=/src/components/App/App.js

    opened by blaadje 1
  • Mutators are called multiple times with the outcome of the previous call as its next value

    Mutators are called multiple times with the outcome of the previous call as its next value

    Describe the bug

    Mutators are called multiple times with the outcome of the previous call as its next value.

    I want to create a mutator that transforms the timestamps returned from the API I'm consuming into a Moment variable. This doesn't seem to work with the normal way how mutators are defined. The first time when it mutates the value, I get a valid Moment variable, but it's mutating a second time and now uses the newly created Moment variable as its property. This shouldn't be the case.

    Steps to reproduce the bug

    1. Define a model with a mutator that returns an instance of Moment
    2. Create one or multiple instances of that model
    3. Retrieve the created model(s)
    4. See an error, saying: config._d.getTime is not a function

    It seems that it's calling the mutator multiple times instead of just once. The first time it's being called, the correct moment instance is returned, but then it's called again; now with the newly created moment instance.

    Expected behavior

    I would expect that the result is a valid Moment variable that I can use and that the mutator is being called once.

    Versions

    • Vuex ORM: 0.36.4
    • Vue: 2.6.11

    Link to minimal reproduction

    As you can see in the console, it calls the mutator twice. The first time with the correct value, but the second time it's using the moment variable instead of the previous value.

    opened by petervmeijgaard 1
Releases(v0.36.4)
  • v0.36.4(May 7, 2021)

    BREAKING CHANGES

    • As of this release, Vuex ORM no longer exposes internals in @vuex-orm/core/lib. Types should now be imported from @vuex-orm/core/dist/src.

    Bug Fixes

    • database: improve performance with entity lookup (#718) (8b5f104)
    • withAll should observe constraints (f3fdf02)
    Source code(tar.gz)
    Source code(zip)
  • v0.36.3(Mar 12, 2020)

    Fixes

    • #455 $update function not working with a composite primary key.
    • #596 Fix persist methods failing to create an array of records in the Nuxt server-side environment.

    Improvements

    • #590 Add support for composite primary keys in whereId and whereIdIn clause.
    Source code(tar.gz)
    Source code(zip)
  • v0.36.2(Mar 8, 2020)

    Fixes

    • #516 Preserve original data when passing it to persistent methods.
    • #571 Fix Many-to-many relations orderBy constraint does not resolve correctly.
    • #588 Fix findIn not resolving child relations.

    Improvements

    • #553 Update Nprmalizr to the latest version.
    Source code(tar.gz)
    Source code(zip)
  • v0.36.1(Mar 4, 2020)

  • v0.36.0(Mar 3, 2020)

    New Features

    Access intermediate model through relationships.

    Issue: #527

    You may now access the intermediate model through customizable pivot attribute on the relationships.

    class User extends Model {
      static entity = 'users'
    ​
      static fields () {
        return {
          id: this.attr(null),
          podcasts: this.belongsToMany(
            Podcast,
            Subscription,
            'user_id',
            'podcast_id'
          ).as('subscription')
        }
      }
    }
    ​
    const user = User.query().with('podcasts').first()
    ​
    user.podcasts.forEach((podcast) => {
      // Access to pivot model!
      console.log(podcast.subscription)
    })
    

    Please refer to the documentation for more details.

    New exists method available in query chain.

    Isseu: #486

    The exists method allows you to check wether a query chain would return any records. The method will return either true or false.

    // Check whether the user store contains any data.
    const resultExists = User.exists()
    
    // Check whether an user with id 5 exists.
    const resultExists = User.query().where('id', 5).exists()
    

    Expose Database object to the plugin components

    Issue: #557

    Now Database object is also passed to the plugin component options.

    It adds as method to many-to-many relationship attribute to let users customize pivot key name.

    Source code(tar.gz)
    Source code(zip)
  • v0.35.2(Feb 1, 2020)

  • v0.35.1(Jan 28, 2020)

  • v0.35.0(Jan 27, 2020)

    New Features

    Context based model access.

    You can get model objects through store instance. Please refer to issue #514 for the reason why we needed this.

    Now you can access models like this.

    // String base access.
    const User = store.$db.model('users')
    
    // Type base access.
    import User from '@/models/User'
    
    const UserModel = store.$db.model(User)
    

    To be able to add this feature, there're few internal breaking changes. It shouldn't affect most of the users.

    • The Query now must receive database instance as the first argument.
    • The Query's get methods such as getModel are now an instance method.
    • The Container now holds store instance instead of a database.

    Please refer to the documentation for more details.

    Register models at runtime.

    Issue #187

    Now you can register a new model after you've installed Vuex ORM to Vuex. All you need to do is to call database.register.

    Thanks to @SzNagyMisu for this wonderful PR! πŸŽ‰

    Fixes

    • #513 Make Model.fields().attribute.value correctly typed.
    • #526 Exclude $id from toJson() method.
    • #536 Now the pivot table composite key can be in any order.
    Source code(tar.gz)
    Source code(zip)
  • v0.34.1(Nov 26, 2019)

    Improvements

    Passing a function to the 1st argument of orderBy method.

    Now you can pass a function as the 1st argument of orderBy. The function will accept a record that is being sorted, and it should return value to be sorted by.

    // Sort user name by its 3rd character.
    const users = User.query().orderBy(user => user.name[2]).get()
    
    /*
      [
        { id: 4, name: 'Andy' },
        { id: 2, name: 'Roger' },
        { id: 1, name: 'John' }
      ]
    */
    

    Thanks to @leearaneta for this wonderful PR! πŸŽ‰

    Fixes

    • #344 Fixed where lifecycle hook defined at model was not bound to the model object.
    • #504 Fixed where first and last method was returning undefined instead of null when data is empty.
    Source code(tar.gz)
    Source code(zip)
  • v0.34.0(Nov 25, 2019)

    New Features

    New UID attribute.

    Now you can use the new this.uid attribute for the model fields. This attribute will generate a unique ID if the field is not present when inserting a record.

    class User extends Model {
      static entity = 'users'
    
      static fields () {
        return {
          id: this.uid(),
          name: this.string('')
        }
      }
    }
    

    This attribute will generate a unique string value that looks like this.

    const user = new User()
    
    user.id // <- '$uid32'
    

    The default UID generation is a really simple one. It will have an incremented number with $uid prefix. It's going to be unique for single client usage, but it's not a Universally Unique ID (UUID).

    If you need stronger ID generation (like UUID or CID), you can pass your desired function that returns the ID.

    class User extends Model {
      static entity = 'users'
    
      static fields () {
        return {
          id: this.uid(() => uuid())
        }
      }
    }
    

    Increment attribute is now deprecated

    The increment attribute is now deprecated and will be removed at v2.0.0. Also, the Increment field will now work as an alias to the new UID attribute. Sorry for the inconcinience, though UID is a much simpler approach, and we thought having increment ID is really not that useful in front-end anyway.

    Fixes

    • #458 Fixed where the type of whereHas constraint argument was not assignable to type parameter of type 'Constraint'. Thanks to @Emily-RoseSteyn for the PR!
    Source code(tar.gz)
    Source code(zip)
  • v0.33.0(Oct 30, 2019)

    Breaking Changes

    How Vuex ORM handles the composite primary key has changed. Previously, Vuex ORM stored records with composite primary keys by joining primary key values with an underscore, for example, like 2_1. So it looked like this inside Vuex Store.

    {
      subscriptions: {
        '1_1': { ... },
        '1_2': { ... },
        '2_1': { ... }
      }
    }
    

    Now, Vuex ORM will store index ID as a stringified array. Like this.

    {
      subscriptions: {
        '[1,1]': { ... },
        '[1,2]': { ... },
        '[2,1]': { ... }
      }
    }
    

    With this change, now you can query record with composite primary key by passing an array of ids, for example, to find method.

    Subscription.find([1, 2])
    

    Please see more details below on what method got updated.

    Improvements

    Better Composite Primary Key support

    Issue #261

    Now, you may pass an array of ids to retrieve records with a composite primary key.

    Let's say you have a Subscription model defined like this.

    import { Model } from '@vuex-orm/core'
    
    class Subscription extends Model {
      static entity = 'users'
    
      static primaryKey = ['video_id', 'user_id']
    
      static fields () {
        return {
          video_id: this.attr(null),
          user_id: this.attr(null)
        }
      }
    }
    

    Then, you can retrieve Subscription records as below. Remember that the value order in the array is the same as the order you defined in your Model's primary key property. In this case it's ['video_id', 'user_id'].

    // Get a subscription with video_id 1 and user_id 2.
    const subscription = User.find([1, 2])
    
    // { video_id: 1, user_id: 2 }
    

    You can also delete records in the same way.

    // Delete subscription with video_id 1 and user_id 2.
    Subscription.delete([1, 2])
    

    Thanks to @lucasbiguet for this wonderful PR!

    Source code(tar.gz)
    Source code(zip)
  • v0.32.5(Oct 21, 2019)

  • v0.32.4(Oct 8, 2019)

    Fixes

    • #460 Fixed STI models not being instantiated correctly when instantiating a model directly (not through Vuex Getters).

    Thanks to @SzNagyMisu for the awesome fix! πŸŽ‰

    Source code(tar.gz)
    Source code(zip)
  • v0.32.3(Oct 2, 2019)

    Fixes

    • #442 Fixed typing error on delete method.
    • #444 Fixed belongsTo and hasOne relationship throwing error when inserting data with the related field of a primitive value.

    Thanks to @2-5, @wizardnet972, and @eldomagan for reporting issues and submitting the excellent PR! πŸ‘

    Source code(tar.gz)
    Source code(zip)
  • v0.32.2(Sep 2, 2019)

    Fixes

    • #391 Fix unexpected error when loading relationships by withAll and withRecursive.
    • #410 Fix hasManyThrough returns [undefined] when trying to load empty relationship.
    Source code(tar.gz)
    Source code(zip)
  • v0.32.1(Jul 23, 2019)

    Fixes

    • #319 Fixed where toJSON was not compatible with JSON.stringify. The method is now going to return every property of the model instance (not only field that is defined in static fields).
    Source code(tar.gz)
    Source code(zip)
  • v0.32.0(Jul 10, 2019)

    New Features

    Single Table Inheritance (STI) support.

    Issue: #310

    Vuex ORM now supports Single Table Inheritance (STI) or Sub-classing through ES6 extension (use of the class ... extends ... syntax). STI is a way to emulate object-oriented inheritance in a relational database. If you're coming from Ruby on Rails land, you might be familiar with it.

    Basically, it will allow you to get different Model instance based on types of records in the same entity. For example, you might have users entity, and you could have a field called type and it could be Person, Adult, or Child. Now, when you fetch these records, sometime it's useful if we can get each type in its own Model instance. Here is where STI comes in to play nicely.

    Please take a look at the documentation for more details.

    Huge thanks to @tvillaren for this wonderful PR! πŸŽ‰

    Source code(tar.gz)
    Source code(zip)
  • v0.31.13(Jul 8, 2019)

    Fixes

    • #397 Fix Belongs To Many relationship returning empty model object when the record does not have id.

    Thanks @kkyouhei for the awesome fix! πŸ”₯

    Source code(tar.gz)
    Source code(zip)
  • v0.31.12(May 23, 2019)

    Fixes

    • #304 Fix issue when creating a record with the id value of null sometimes cause an error.
    • #367 Fix where creating morph to many records with incremented id not working correctly.
    • #349 Fix normalizr package not found error on TypeScript.
    • #370 Fix inconsistent typing at with query method.
    Source code(tar.gz)
    Source code(zip)
  • v0.31.11(May 14, 2019)

    Fixes

    • #303 Fix where combining increment id and relationship which requires "pivot" table not generating correct pivot table when inserting records.

    Thanks @nagwan and @phortx for the report! πŸ”₯

    Source code(tar.gz)
    Source code(zip)
  • v0.31.10(Apr 23, 2019)

    Improvements

    • #341 Now you can add closure as the first argument for the attr attribute.

      class User extends Model {
        static fields () {
          return {
            id: this.attr(null),
            name: this.attr('John Doe'),
            rand: this.attr(() => Math.random())
          }
        }
      }
      

    Fixes

    • #320 Fix where some times inserting model with composite keys generating wrong value.
    • #332 Fix Vuex ORM was not working on IE11 because of lack of ownKeys support.

    Thanks to @tvillaren, @kkyouhei and @SebastianSmolorz for the awesome PR! πŸ”₯

    Source code(tar.gz)
    Source code(zip)
  • v0.31.9(Apr 16, 2019)

  • v0.31.8(Apr 8, 2019)

    Fixes

    • #317 Fixed where it was not working on IE11 because usage of Object.assign is not polyfilled properly.

    Thanks to @dtkahl for the report and thanks @kkyouhei for the fix πŸŽ‰

    Source code(tar.gz)
    Source code(zip)
  • v0.31.7(Mar 26, 2019)

    Fixes

    • #294 Fixed when updating belongs to many relations not populating correct field at pivot entity.
    • #318 Fixed typo in error message.

    Thanks to @kkyouhei and @bertBruynooghe for the awesome PR! πŸŽ‰

    Source code(tar.gz)
    Source code(zip)
  • v0.31.6(Feb 25, 2019)

    Fixes

    • Fix where "many" type relation returning undefined instead of null when there's nothing to reference.
    • #299 Fix where hasMany was ignoring localKey argument.

    Thanks to @kkyouhei as always for the lovely fix! πŸŽ‰

    Source code(tar.gz)
    Source code(zip)
  • v0.31.5(Feb 19, 2019)

    Improvements

    Introducing beforeRelations & afterRelations hooks.

    PR: #293

    Now you can use beforeRelations & afterRelations as a select hook.

    Thanks @killix for this wonderful PR! πŸŽ‰

    Fixes

    • #282 Fix where belongsToMany relation is returning undefined instead of empty array when there're no reference records.
    • #290 Fix withAllRecursive() retrieving empty relations and sub relations when key is null.

    Thanks so much to @kkyouhei and @rkolpakov for the fixes! 🀝

    Source code(tar.gz)
    Source code(zip)
  • v0.31.4(Feb 12, 2019)

    Fixes

    • #258 Fixes where morphToMany relation duplicates the pivot records when used with increment field type.
    • Bring back IE11 support by adding Object.values polifyll.

    Thanks @kkyouhei for the wonderful PR! πŸŽ‰

    Source code(tar.gz)
    Source code(zip)
  • v0.31.3(Feb 3, 2019)

    Improvements

    Update state key when a user updates the primary key for the record.

    Issue: #90

    When trying to update the primary key, for example, id for the record, now it will update the state key as well.

    Fixes

    • #255 Fix non-POJP warning when using Vuex ORM with Nuxt SSR.
    Source code(tar.gz)
    Source code(zip)
  • v0.31.2(Dec 25, 2018)

    Improvements

    Better TypeScript support

    Previously user defined models were not protected/checked by TypeScript. Now it does! For the TS users, you can now define your models as below to get types for your model properties.

    class Person extends Model {
      static entity = 'persons'
    
      static fields (): Fields {
        return {
          id: this.number(0),
          name: this.string(''),
          note: this.string('').nullable(),
          options: this.hasMany(Option, 'personId')
        }
      }
    
      id!: number
      name!: string
      note?: string
      options!: Option[]
    }
    

    Exports Fields Interface for TypeScript

    TypeScript requires for some models (but not all) static fields method has Fields as return type. Now you can use it by importing it from @vuex-orm/core.

    import { Fields, Model } from "@vuex-orm/core";
    
    export default class OptionGroup extends Model {
      static fields(): Fields { ... }
    }
    

    Fixes findIn Return Value

    Now it doesn't allow findIn result array to have undefined or null. Correct its TypeScript return type as well.

    // For data { 1: { id: 1 }, 2: { id: 2 } }
    findIn([1, 3]);  // It was returning [{ id: 1 }, undefined] before, now [{ id: 1}].
    

    Thanks @ozum so much for this wonderful PR πŸŽ‰

    Source code(tar.gz)
    Source code(zip)
  • v0.31.1(Dec 4, 2018)

    Improvements

    Direct index key look support for where clause

    PR: #262

    Now where clause is going to look up the record directly by the key of the store state instead of full scanning the records if the specified field is the primary key

    User.query().where('id', 1).get()          // Uses id key lookup
    User.query().where('other', 'abc').get()   // Uses full scan as previous.
    User.query().whereIdIn('id', [1, 2]).get() // Uses id key lookup
    

    Id intersection for whereId and whereIdIn

    PR: #262

    Previously when whereId and whereIdIn called more than once, they return the union of ids instead of an intersection of ids. This was not compliant and intuitive with the rest of the library.

    Option.where("id", [1, 2]).where("id", [3, 4)]; // Returns []
    Option.whereIdIn([1, 2]).whereIdIn([3, 4)]; // Previously was returning [1, 2, 3, 4], now []
    

    Thanks so much to @ozum for this beautiful PR! πŸŽ‰

    Source code(tar.gz)
    Source code(zip)
Owner
Vuex ORM
The Vuex plugin to enable Object-Relational Mapping access to the Vuex Store.
Vuex ORM
A Vuex plugin to persist the store. (Fully Typescript enabled)

vuex-persist A Typescript-ready Vuex plugin that enables you to save the state of your app to a persisted storage like Cookies or localStorage. Info :

Arnav Gupta 1.5k Oct 19, 2021
cache vuex action when dispatch

vuex-cache Cache dispatched actions and prevent repeated requests and heavy actions. Compatibility Map and Promise are required (you can use polyfills

superwf 502 Oct 16, 2021
πŸ’Ύ Persist and rehydrate your Vuex state between page reloads.

vuex-persistedstate Persist and rehydrate your Vuex state between page reloads. Install npm install --save vuex-persistedstate The UMD build is also a

Robin van der Vleuten 5.5k Oct 12, 2021
Lightweight Vue 3 composition API-compatible store pattern library with built-in undo/redo functionality.

vue-store Lightweight Vue 3 composition API-compatible store pattern library. Offers a simple alternative that is on par with VueX in terms of feature

Korijn van Golen 16 Sep 4, 2021
Vuex binding for client-side search with indexers and Web Workers :green_book::mag:

Vuex Search is a plugin for searching collections of objects. Search algorithms powered by js-worker-search. See working example here. Installation: n

Albert Lucianto 152 Aug 31, 2021
The Vuex plugin to enable Object-Relational Mapping access to the Vuex Store.

Vuex ORM ?? HEADS UP! Currently, Vuex ORM Next project is on going, and we are hoping it is going to be the foundation of the version 1.0.0 release. W

Vuex ORM 2.3k Oct 16, 2021
πŸ“¦ Fast, Simple, and Lightweight State Manager for Vue 3.0 built with composition API, inspired by Vuex.

v-bucket NPM STATUS: ?? Fast, Simple, and Lightweight State Management for Vue 3.0 built with composition API, inspired by Vuex. Table of Contents Mai

mehdi 41 Sep 24, 2021
Universal Model for Vue

Universal Model for Vue Universal model is a model which can be used with any of following UI frameworks: Angular 2+ universal-model-angular React 16.

Universal Model 24 Sep 22, 2021
A util package to use Vuex with Composition API easily.

vuex-composition-helpers A util package to use Vuex with Composition API easily. Installation $ npm install vuex-composition-helpers This library is n

Greenpress 210 Oct 18, 2021
Vue plugin for using Microsoft Authentication Library (MSAL)

vue-msal Wrapper of MSAL.js (Microsoft Authentication Library) for usage in Vue. The vue-msal library enables client-side vue applications, running in

null 101 Oct 6, 2021
Easily share reactive data between your Vue components.

vue-stash A Vue.js plugin that makes it easy to share reactive data between components. This plugin is best suited for the rapid development of protot

Cody Mercer 413 Sep 26, 2021
MobX integration for Vue.js.

Movue MobX integration for Vue.js, inspired by vue-rx. Movue aims for providing simple and reliable integration between Mobx and Vue.js, which sometim

Hanxing Yang 59 May 13, 2021
Vuex state persistance and synchronization between tabs/windows.

vuex-basement Vuex state persistance and synchronization between tabs/windows. Tested to work with Vue2. One Shortcomming (please read before use). Th

Rashad Saleh 66 May 31, 2021
Binding Solutions for Vue & Redux

vuedeux Full Documentation https://vueduex.gitbooks.io/vuedeux-documentation/content/ Synopsis Vuedeux is a lightweight open-source utility layer for

null 72 Oct 1, 2021
Vuex plugin for redux-saga

vuex-coolstory Use redux-saga with Vuex. Overview redux-saga is an awesome library that aims to make side effects (i.e. asynchronous things like data

Nikita Lvov 21 May 17, 2021
Use paginated resources in your Vue/Vuex app with ease

vuex-pagination Note: This library only works with Vue 2. For Vue 3, take a look at vue-use-pagination. Library that makes it magnitudes easier to int

cyon GmbH 104 Oct 18, 2021
Simple, unopinionated, lightweight and extensible state management for Vue 3

Simple, unopinionated, lightweight and extensible state management for Vue 3

Andrew Courtice 254 Oct 15, 2021
Flexible binding between Vue and Redux

vuejs-redux Description Flexible binding between Vue and Redux, allowing use of multiple stores. It works, in the same way, like render props does in

Titouan CREACH 54 Sep 19, 2021
πŸ’ΎπŸ”—πŸ–₯️ Share, synchronize and persist state between multiple tabs with this plugin for Vuex. TypeScript types included.

vuex-multi-tab-state This Vuex plugin allows you to sync and share the status of your Vue application across multiple tabs or windows using the local

Gabriel MartΓ­n BlΓ‘zquez 120 Oct 11, 2021