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 26
  • 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
  • Retrieve and manipulate sub resources

    Retrieve and manipulate sub resources

    Hey! I got a question about the way to retrieve sub models.

    I got 2 models, TaskedDays & Tasks which allows me to sort my tasks by days & retrieve tasks quickly (vs filtering big tasks array by day)

    I'm coming from https://redux-orm.github.io/redux-orm/basics/selectors so I thought retrieving tasks would be pretty straightforward e.g

    // models/TaskedDay.js
    
    export default class TaskedDay extends Model {
      static entity = 'taskedDays'
    
      static findByDate(date) {
        return TaskedDay.query().where('date', (value) =>
          areDatesEqual(new Date(value), new Date(date)),
        )
      }
    
      static fields() {
          return {
            id: this.uid(() => uuid()),
            date: this.attr(() => new Date().toISOString()),
            tasks: this.hasMany(Task, 'taskedDayId'),
          }
        }
    }
    
    
    // useTaskManager.js
    
    const coolTasks = computed(() =>
        TaskedDay.findByDate(date)
          .tasks.orderBy(...sort)
          .where(filterTasks)
          .get(),
      )
    

    However the way to retrieve tasks atm looks like :

    const tasks = computed(() => {
      const { tasks = [] } =
        TaskedDay.findByDate(date)
          .with('tasks', (query) => {
            query.orderBy(...sort).where(filter)
          })
          .first() || {}
    
      return tasks
    })
    
    1. Question: Does the coolTasks way to retrieve submodels could be relevant to implement as a new feature ? IMO it would be more natural to manipulate resource as so.

    2. Question: Otherwise I want to have in TaskedDay a getTasksByDate method which would take care about this by also being able to orderBy / where from the outside of model, would you have an idea on how to do that in a clean way (TaskedDay .getTasksByDate(date).orderBy(...sort)) ?

    Thanks!

    opened by blaadje 0
  • build(deps): bump ws from 6.2.1 to 6.2.2

    build(deps): bump ws from 6.2.1 to 6.2.2

    Bumps ws from 6.2.1 to 6.2.2.

    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] 1
  • Add a orWhereHas query method

    Add a orWhereHas query method

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

    I would like to be able to do the following:

    Project.query()
      .with('emails', query => (
        query.with(['to', 'from'])
          .where('subject', searchQuery)
          .orWhere('body', searchQuery)
          .orWhereHas('to', query => (
            query
              .where('address', searchQuery)
              .orWhere('name', searchQuery)
          )
          .orWhereHas('from', query => (
            query
              .where('address', searchQuery)
              .orWhere('name', searchQuery)
          )
      ))
    

    (I'm actually using the Vuex ORM Search plugin for this, but for the sake of keeping it Vuex ORM oriented, I've rewritten the .search(...) queries to where statements)

    By executing this statement, I get a result if there's:

    • An email with a subject or a message that matches the searchQuery
    • An email with a to-relationship where the to email address has an address or a name that matches the searchQuery
    • An email with a from-relationship where the from email address has an address or a name that matches the searchQuery

    Describe the solution you'd like

    I would like to have the same functionality as the orWhereHas method from Laravel Eloquent

    Describe alternatives you've considered

    I've considered using a orWhere statement and place the whereHas query inside the callback, but I couldn't manage to get that working. I've also tried to fix it myself by forking the repo and adding the method, but I was a bit overwhelmed by the Rollcaller class

    opened by petervmeijgaard 1
  • feat: add when query helper

    feat: add when query helper

    First of all, I want to thank y'all for this amazing package. It solved a lot of problems with the project I'm currently working on.

    However, I felt that one helper function was missing; when. This PR will add the when helper method, which will take a conditional and, if the conditional is true, will wrap this inside the callback. More details below.

    Type of PR:

    • [ ] Bugfix
    • [x] Feature
    • [ ] Code style update
    • [ ] Refactor
    • [ ] Build-related changes
    • [ ] Documentation
    • [ ] Other, please describe:

    Breaking changes:

    • [x] No
    • [ ] Yes

    Details

    On my current project, I have to filter multiple entities and search each one of them as well. Right now, I have to add a few conditionals to make it work like this:

    const myModel = computed(() => {
        const query = MyModel.query();
    
        if (toggleOne.isActive) {
            query.with('one', oneQuery => {
                if (searchQuery.value) {
                    oneQuery.search(searchQuery.value);
                }
            });
        }
    
        if (toggleTwo.isActive) {
            query.with('two', twoQuery => {
                if (searchQuery.value) {
                    twoQuery.search(searchQuery.value);
                }
            });
        }
    
        if (toggleThree.isActive) {
            query.with('three', threeQuery => {
                if (searchQuery.value) {
                    threeQuery.search(searchQuery.value);
                }
            });
        }
        
        return query.find(id);
    });
    

    With a bit of refactoring, this could be rewritten to something like this:

    const myModel = computed(() => {
        const query = MyModel.query();
    
        if (toggleOne.isActive) {
            withOneQuery(query);
        }
    
        if (toggleTwo.isActive) {
            withTwoQuery(query);
        }
    
        if (toggleThree.isActive) {
            withThreeQuery(query);
        }
    
        return query.find(id);
    });
    

    I haven't included the with[...]Query methods in the previous example, as I think it's pretty obvious what each method will do.

    So with a when helper (just like with Laravel), you will get something like this, which looks a lot cleaner to me:

    const myModel = computed(() => MyModel.query()
        .when(toggleOne.isActive, withOneQuery)
        .when(toggleTwo.isActive, withTwoQuery)
        .when(toggleThree.isActive, withThreeQuery)
        .find(id)
    );
    

    This would also allow for a default callback when the conditional results in something falsy. The conditional itself, is added as the second parameter in the callback.

    MyModel.query().when(
        isTrueOrFalse,
        (query, conditional) => console.log(query, conditional),
        (query, conditional) => console.log(query, conditional)
    )
    

    Todo

    • [x] Add UnitTests (?)
    • [ ] Add documentation (?)
    opened by petervmeijgaard 1
  • undefined field values with typescript 4.3.x

    undefined field values with typescript 4.3.x

    Describe the bug

    Using typescript 4.3.x results in undefined field values after creating, inserting or dispatching data to a model

    Steps to reproduce the bug

    1. Checkout the TS example https://github.com/vuex-orm/vuex-orm-examples-ts
    2. update the typescript from 3.9.x to latest
    3. npm run serve
    4. See undefined fields in both lists

    Expected behaviour

    See the created or inserted data in both lists

    Versions

    • Vuex ORM: ^0.36.4
    • Vue: ^2.6.12
    • Vuex: ^3.6.2

    Link to minimal reproduction

    https://github.com/vuex-orm/vuex-orm-examples-ts

    Additional context

    Downgrading to typescript 4.2.x seems to solves this issue with the TS example

    need more info 
    opened by nowrap 1
  • build(deps): bump dns-packet from 1.3.1 to 1.3.4

    build(deps): bump dns-packet from 1.3.1 to 1.3.4

    Bumps dns-packet from 1.3.1 to 1.3.4.

    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] 1
  • Version 0.36.4 breaks importing internal tools

    Version 0.36.4 breaks importing internal tools

    Describe the bug

    Since tag 0.36.4 it's impossible to import internally used functions from the src folder as it's not included in the build anymore.

    In this case I'm specifically referring to Serialize's toJson() function, imported as:

    import { toJson } from '@vuex-orm/core/lib/model/Serialize'
    

    This code was used as a work-around for the model.$toJson() not allowing to create an object without its relations attached, as the $toJson() does not seem to accept the options the internal function call does allow me to pass.

    Steps to reproduce the bug

    1. Define any model
    2. Add the previously mentioned import
    3. Let webpack build
    4. Error will be thrown as webpack cannot find the function.

    Expected behaviour

    Either

    To be able to import toJson in the same manner as in 0.36.3 and before

    Or

    To be able to pass the { relations: false } option along to a model.$toJson() call so a plain object can be generated (for API POSTing) without relations. Unsetting relations after having them included with $toJson() is not a decent solution I think.

    Versions

    • Vuex ORM: 0.36.4
    • Vue: 2.6.12

    Link to minimal reproduction

    Impossible to re-produce in a JSFiddle or such as it's an error triggered on build.

    Additional context

    Example model for my usage:

    import { toJson } from '@vuex-orm/core/lib/model/Serialize' // This causes the compile error on 0.36.4
    
    /**
     * Item Model
     *
     * @class Item
     *
     * @property {number} id
     * @property {string} name
     * @property {hasOne} property
     */
    export default class Item extends BaseModel {
      /**
       * Entity name
       * @type {String}
       */
      static entity = 'item'
    
      /**
       * Primary Key
       * @type {String}
       */
      static primaryKey = 'id'
    
      /**
       * Model field defenitions
       * @returns {Object}
       */
      static fields = () => ({
        id: this.number(null),
        name: this.string(null),
        properties: this.hasMany(Property, 'properties')
      })
    
      /**
       * Transform the order data
       * @param {Model} model
       * @return {Object} The transformed object
       */
      static toObject = model => toJson(model, { relations: false })
    }
    
    wontfix 
    opened by ZeroThe2nd 1
  • build(deps): bump ssri from 6.0.1 to 6.0.2

    build(deps): bump ssri from 6.0.1 to 6.0.2

    Bumps ssri from 6.0.1 to 6.0.2.

    Changelog

    Sourced from ssri's changelog.

    6.0.2 (2021-04-07)

    Bug Fixes

    • backport regex change from 8.0.1 (b30dfdb), closes #19

    Commits
    Maintainer changes

    This version was pushed to npm by nlf, a new releaser for ssri 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] 1
  • Cross-request state pollution with Nuxtjs SSR

    Cross-request state pollution with Nuxtjs SSR

    Describe the bug

    First of all, thank you for this awesome library.

    The bug seems to be some kind of cross-request state pollution when using Vuex-ORM on Nuxtjs with SSR. Its kinda hard to reproduce. I made an example with a fresh Nuxt project repository and also catch the behavior on video (see Additional context below).

    Steps to reproduce the bug

    1. Clone repo
    2. Install dependencies (yarn install)
    3. Build project (yarn build)
    4. Open 2-3 browser windows each one using a different slug.

    For example:

    • http://localhost:3000/question/first-question
    • http://localhost:3000/question/second-question
    • http://localhost:3000/question/third-question
    1. Reload the page of each window one by one before they all finished loading to simulate multiple requests going on simultaneously.

    Expected behaviour

    Expected all browser windows to have their respective title related to the slug in the url parameter.

    Versions

    • Vuex ORM: 0.36.3
    • Nuxt: 2.15.3

    Link to minimal reproduction

    Repo: https://github.com/jayrchamp/vuex-orm-nuxtjs-cross-request-state-pollution

    Additional context

    Video: https://storage.googleapis.com/ayourp-examples/vuex-orm-nuxtjs-cross-request-state-pollution.mp4

    opened by jayrchamp 2
  • One To Many (Polymorphic) relationship is not working with custom primaryKey

    One To Many (Polymorphic) relationship is not working with custom primaryKey

    Describe the bug

    Just imagine 2 models, Product and Attribute.

    Product have One to Many (Polymorphic) relationship. Product model has own custom primaryKey (for example - uid).

    The issue is that those attributes are inserted with wrong reference_id which is product.id, should be product.uid.

    image

    Steps to reproduce the bug

    Product model

    import { Model } from "@vuex-orm/core";
    import Attribute from "./Attribute";
    
    export default class Product extends Model {
      static entity = "cart_products";
    
      static primaryKey = 'uid';
    
      static fields() {
        return {
          uid: this.uid(),
          id: this.attr(null),
          sku: this.attr(""),
          name: this.string(""),
          attributes: this.morphMany(Attribute, "reference_id", "reference_type")
        };
      }
    }
    
    

    Attribute model

    import { Model } from "@vuex-orm/core";
    
    export default class Attribute extends Model {
      static entity = "cart_attributes";
    
      static fields() {
        return {
          id: this.attr(null),
          name: this.attr(""),
          value: this.attr(""),
          reference_id: this.attr(null),
          reference_type: this.attr(null),
          reference: this.morphTo("reference_id", "reference_type")
        };
      }
    }
    
    
    

    Insert data

    const productObject = {
          id: 1001,
          sku: "QWERTY",
          name: "Product name",
          attributes: [
            {
              name: "attribute1",
              value: 50,
            },
            {
              name: "attribute2",
              value: 500,
            },
          ],
        };
    
        Product.insert({
          data: productObject,
        });
    

    Get data

    const products = Product.query().with("attributes").get();
    console.log('products', products);
    

    Expected behaviour

    const products = Product.query().with("attributes").get(); console.log('products', products);

    This part of code should return product object with all attributes and each attribute should contain product.uid value as reference_id, but in this case its always product.id (1001).

    Versions

    • Vuex: 3.6.2
    • Vuex ORM: 0.36.3
    • Vue: 2.6.12

    Link to minimal reproduction

    Codesandbox: https://codesandbox.io/s/happy-dream-qbi0e?fontsize=14&hidenavigation=1&theme=dark

    bug 
    opened by LG0012 2
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 20, 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
Enable two-way data binding for form fields saved in a Vuex store

vuex-map-fields Enable two-way data binding for form fields saved in a Vuex store. Install npm install --save vuex-map-fields Basic example The follow

Markus Oberlehner 1.3k Jun 3, 2021
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.4k Jun 12, 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 500 Jun 1, 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.2k Jun 13, 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 12 May 16, 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 150 Jun 1, 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.2k Jun 14, 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 May 13, 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 May 28, 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 165 May 26, 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 414 May 29, 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 95 May 13, 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 12, 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