Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem to $persist #135

Open
phiny1 opened this issue Nov 19, 2019 · 7 comments
Open

Problem to $persist #135

phiny1 opened this issue Nov 19, 2019 · 7 comments

Comments

@phiny1
Copy link

phiny1 commented Nov 19, 2019

I dont know why I cant persist and object... I got:
fetch, push and destroy works well.

vuex-orm-graphql.es5.js?8eb2:1 Uncaught (in promise) TypeError: Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at Function.e.transformOutgoingData (vuex-orm-graphql.es5.js?8eb2:1)
    at Function.e.addRecordToArgs (vuex-orm-graphql.es5.js?8eb2:1)
    at Function.eval (vuex-orm-graphql.es5.js?8eb2:1)
    at eval (vuex-orm-graphql.es5.js?8eb2:1)
    at Object.eval [as next] (vuex-orm-graphql.es5.js?8eb2:1)
    at eval (vuex-orm-graphql.es5.js?8eb2:1)
    at new Promise (<anonymous>)
    at __awaiter (vuex-orm-graphql.es5.js?8eb2:1)
    at Function.t.call (vuex-orm-graphql.es5.js?8eb2:1)

Sector,js

import { Model } from '@vuex-orm/core'

export default class Sector extends Model {
  static entity = 'sectors'

  static fields () {
    return {
      id: this.number(null),
      name: this.string(''),
    }
  }
}

store/index.js

import Vue from 'vue';
import Vuex from 'vuex';
import VuexORM from '@vuex-orm/core';
import VuexORMGraphQL from '@vuex-orm/plugin-graphql';
import { AuthModule } from './auth-module';
import { HttpModule } from './http-module';
import { SettingsModule } from './settings-module';
import { CustomAdapter } from '@/plugins/graphql-adapter';
import ApolloClient from '@/plugins/apollo-client';

// Create a new instance of Database.
const database = new VuexORM.Database();

// Models
import User from '@/models/User';
import Sector from '@/models/Sector';
import Subsector from '@/models/Subsector';
import Segment from '@/models/Segment';

// Register Models to Database.
database.register(User);
database.register(Sector);
database.register(Subsector);
database.register(Segment);

VuexORM.use(VuexORMGraphQL, { 
	database,
	adapter: new CustomAdapter(),
	apolloClient: ApolloClient
});
Vue.use(Vuex);

export default new Vuex.Store({
  plugins: [VuexORM.install(database)],
  modules: {
    auth: AuthModule,
    http: HttpModule,
    settings: SettingsModule
  },
});

Sector.vue

<script>
import Sector from '@/models/Sector';

export default {
	data() {
		return {
			sector: {},
		}
	},
	async mounted() {
		await Sector.fetch();
	},
	computed: {
		sectors: () => Sector.all(),
	},
	methods: {
		newf() {
			this.sector = {};
		},
		edit(sector) {
			this.sector = sector;
		},
		async create() {
			await Sector.insert({data: this.sector});
			const sector = Sector.query().last();
			await sector.$persist();
		},
		async update() {
			await this.sector.$push();
		},
		async destroy(sector) {
			await sector.$deleteAndDestroy();
		}
	}
};
</script>
@phiny1
Copy link
Author

phiny1 commented Nov 20, 2019

For Vuex ORM the key of model is attribute "$id" as we can see in:

vuex-orm/query/Query.ts

private deleteById (id: string | number | (number | string)[]): Data.Item {
    const item = this.find(id)

    if (!item) {
      return null
    }

    return this.deleteByCondition(model => model.$id === item.$id)[0]
  }

When the model has increment id, its set to "$id" and "id" attributes the key value, but when the model doesnt have increment id , its set the fictitious key only to "$id" attribute.

Then, the plugin cant get data by "id" attribute on:

plugin-graphql/orm/model.ts

public getRecordWithId(id: number) {
    return this.baseModel
      .query()
      .withAllRecursive()
      .where("id", id)
      .first();
  }

In where should be "$id".

Another problem, its seems possible in Vuex ORM have more then one attribute as model key and plugin graphql is not prepered for this situation, as we can see in:

Vuex ORM/model/Model.ts

async $delete (): Promise<Item<this>> {
    const primaryKey = this.$primaryKey()

    if (!Array.isArray(primaryKey)) {
      return this.$dispatch('delete', this[primaryKey])
    }

    return this.$dispatch('delete', (model: this): boolean => {
      return primaryKey.every(id => model[id] === this[id])
    })
  }

@phiny1
Copy link
Author

phiny1 commented Nov 26, 2019

@vuex-orm/core 0.34 solves the problem of null id, because Uid generate to $id and id attributes. But the plugin still dont work with composite keys

@phortx
Copy link
Collaborator

phortx commented May 2, 2020

With the latest release, the plugin works with Vuex-ORM 0.36. Feel free to reopen the issue when the problem still exists :)

@phortx phortx closed this as completed May 2, 2020
@phiny1
Copy link
Author

phiny1 commented May 3, 2020

Thank you very much for the update =]

@M1chaelTran
Copy link

This is still an issue as it tries to convert a string id into a number before performing the search query.

.where("id", toNumber(id))

@phortx phortx reopened this May 25, 2020
@sysrun
Copy link

sysrun commented Oct 27, 2020

I am using string ids in many of my models. Hat to fork the Repo and remove all "toNumber" calls in the code. Hope it will be fixed soon

@Arsync
Copy link

Arsync commented Mar 21, 2021

With generated $id: "tyr13zqj"
I have the same error Uncaught (in promise) TypeError: Cannot convert undefined or null to object.

Seems that now (vuex-orm/core 0.36.3) it not prefixed with $uid in models:
id: this.uid(() => tempId()) // tempId returns 'tyr13zqj' value

But in plugin code we have

getRecordWithId(id) {
    return this.baseModel
        .query()
        .withAllRecursive()
        .where("id", toPrimaryKey(id))
        .first();
}

where toPrimaryKey is

function toPrimaryKey(input) {
    if (input === null)
        return 0;
    if (typeof input === "string" && (input.startsWith("$uid") || isGuid(input))) {
        return input;
    }
    return parseInt(input.toString(), 10);
}

Why you need that conversion in plugin? Just return string if that is string!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants