vuex-orm icon indicating copy to clipboard operation
vuex-orm copied to clipboard

[RFC] Enable inserting and retrieving custom relationships in STI

Open petertoth opened this issue 5 years ago • 12 comments

Type of PR:

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

Breaking changes:

  • [x] No
  • [ ] Yes

Details

Fixes https://github.com/vuex-orm/vuex-orm/issues/606, https://github.com/vuex-orm/vuex-orm/issues/581, https://github.com/vuex-orm/vuex-orm/issues/519, https://github.com/vuex-orm/vuex-orm/issues/606, https://github.com/vuex-orm/vuex-orm/issues/512, https://github.com/vuex-orm/vuex-orm/issues/443

TL;DR

This PR enables users to do something like:

await Person.insert({
  data: [
    { id: 1, name: 'John' },
    {
      id: 2,
      name: 'Jane',
      type: 'ADULT',
      jobs: [
        {
          id: 1,
          title: 'jack of all trades'
        },
        {
          id: 2,
          title: 'Software engineer',
          type: 'office',
          building: { id: 1, address: 'Park Avenue' }
        },
        {
          id: 3,
          title: 'Designer',
          type: 'remote',
          locations: [{ id: 1, lat: 12, lng: 34 }, { id: 2, lat: 56, lng: 78 }]
        }
      ]
    },
  ]
})

console.log(Person.query().withAllRecursive().get())

[ Person { '$id': '1', id: 1, name: 'John', type: '' },
  Adult { '$id': '2', id: 2, name: 'Jane', type: 'ADULT', title: '', jobs: [ 
    Job { '$id': '1', id: 1, type: null, title: 'jack of all trades', adult_id: 2 },
    OfficeJob { '$id': '2', id: 2, type: 'office', title: 'Software engineer', adult_id: 2, building:
      Building { '$id': '1', id: 1, address: 'Park Avenue', buildingable_id: 2, buildingable_type: 'job' } },
    RemoteJob { '$id': '3', id: 3, type: 'remote', title: 'Designer', adult_id: 2, locations: [ 
      Location {  '$id': '1', id: 1, lat: 12, lng: 34, locationable_id: 3, locationable_type: 'job' },
      Location { '$id': '2', id: 2, lat: 56, lng: 78, locationable_id: 3, locationable_type: 'job' } ] } ] } ]

I will clarify the specific refactors in separate comments. This is not a breaking change but will definitely need to be tested well before merging into master.

Please bear in mind I'm a noob when it comes to Typescript and contributing to vuex-orm so if there are any hiccups it would be nice if you guided me through them ❤️

petertoth avatar Jun 02 '20 01:06 petertoth

How it comes, that I always need features which are not quite ready yet...

Is this branch ok enough to test/develop with? I really would like to use it.

Fuzzyma avatar Jul 07 '20 12:07 Fuzzyma

Hey @Fuzzyma, I'm using this branch on my local dev environment but I'd not recommend to use that in production. Try it out and if you find something broken please let me know. @kiaking, I'm curious if this is going to be sorted out in vuex-orm-next? Looks like it's a complete rewrite so I think it's unlikely this PR will be relevant for 1.0.0 version.

Edit: Also make sure to build this this branch of vuex-orm before using it I'm using this https://github.com/petertoth/vuex-orm/tree/fix-custom-relationships-derived-models-dist

petertoth avatar Jul 07 '20 12:07 petertoth

I just tried to build it and got an error in Query.ts:

semantic error TS2698: Spread types may only be created from object types.

I cloned your given branch and npm installed all dependencies and run npm run build. Anything else I need to check?

Fuzzyma avatar Jul 07 '20 22:07 Fuzzyma

You actually don't need to build it again if you're using the branch I mentioned earlier. Just replace vuex-orm in your package.json like:

{
  "dependencies": {
     "@vuex-orm/core": "petertoth/vuex-orm#fix-custom-relationships-derived-models-dist"
  }
}

And do a fresh install

petertoth avatar Jul 07 '20 22:07 petertoth

Thanks for this PR @petertoth. Looks like an incredible amount of effort went into this and we really appreciate your time. It is unlikely this PR will be merged since all our efforts are focused on the @next repo.

I'm curious if this is going to be sorted out in vuex-orm-next? Looks like it's a complete rewrite so I think it's unlikely this PR will be relevant for 1.0.0 version.

While this PR would be incompatible with 1.0.0, we are keen to keep it open to provide insight and guidance when this feature is implemented in the @next repo. I'm sure we'll be picking at your brain in due course.

cuebit avatar Jul 07 '20 22:07 cuebit

@cuebit do you have a timeframe in mind when 1.0 will get released?

@petertoth branch seems to work as expected

Fuzzyma avatar Jul 08 '20 07:07 Fuzzyma

@cuebit do you have a timeframe in mind when 1.0 will get released?

Currently working to the timeline set out by Vue 3 and it’s release which will be around August time but I cannot guarantee a fixed date at this time.

cuebit avatar Jul 09 '20 11:07 cuebit

@cuebit does that mean, that 1.0 will be only compatible to Vue 3?

Fuzzyma avatar Jul 09 '20 13:07 Fuzzyma

@petertoth I found something that I would consider a bug but I am not sure if it is intended. When I create a new subclass of something, the type key is set to the default value I specified in the base class. It kinda makes sense to value the default property but I would have expected that the type is set correctly to the type of the subclass. I solved it by overwriting the type field in my subclass with the correct type as default value.

What do you think?

Fuzzyma avatar Jul 15 '20 10:07 Fuzzyma

@Fuzzyma Could you provide a code snippet with described behavior?

petertoth avatar Jul 15 '20 13:07 petertoth

class Animal extends Model {
  entity: 'animals'

  static fields () {
    return {
      id: this.attr(null),
      type: this.attr('animal')
    }
  }

  static types () {
    return {
      animal: Animal,
      dog: Dog
    }
  }
}

class Dog extends Animal{
  entity: 'dogs'
  baseEntity: 'animals'

  static fields () {
    return {
      ...super.fields(),
      type: this.attr('dog') // add this to make it work
    }
  }
}

// type is animal when the fix above isnt used
cost dog = new Dog()

PS: I wrote this on top of my head. But it should show the issue I am having

Fuzzyma avatar Jul 16 '20 05:07 Fuzzyma

I found one missing fix in the Model.commit method. It is giving you the entitys data instead of the baseEntitys one. And this is always empty.

e.g. Rect extends Shape Model:

store.state.entities.rects.data // empty
store.state.entities.shapes.data // all the shapes including rects

That's why the code should be something like this:

	    Model.commit = function (callback) {
	        this.store().commit(this.database().namespace + "/$mutate", {
	            entity: this.baseEntity || this.entity, // this is changed
	            callback: callback
	        });
	    };

Fuzzyma avatar Aug 07 '20 23:08 Fuzzyma