mswjs / data

Data modeling and relation library for testing JavaScript applications.
https://npm.im/@mswjs/data
MIT License
829 stars 52 forks source link

Polymorphic relationships #124

Open lavoscore opened 3 years ago

lavoscore commented 3 years ago

Any chance of having support for polymorphic relations? Like:

export const db = factory({
  comment: {
    // ...
    commentable: oneOf('commentable', { polymorphic: true })
  },

  post: {
    // ...
    comments: manyOf('comment', { as: 'commentable' })
  },

  image: {
    // ...
    comments: manyOf('comment', { as: 'commentable' })
  }
})

db.comment.create({ commentable: db.post.create(...) })
kettanaito commented 3 years ago

Hey, @lavoscore. Thank you for mentioning this.

We should add support for polymorphic relationships (associations) to the library. Before we do that, I'd like to clarify the expected behavior and supposed API.

Declaration

const db = factory({
  comment: {
    commentable: polymorphic()
  },
  post: {
    comments: manyOf('comment')
  },
  image: {
    comments: manyOf('comment')
  }
})

Creating a polymorphic relationship

// Create a comment for a post.
db.comment.create({
  commentable: db.post.findOne({/*...*/})
})

// Create a comment for a user.
db.comment.create({
  commentable: db.user.findOne({/*...*/})
})

Querying polymorphic relationships

// Query all comments for all posts.
db.comment.findMany({
  where: {
    commentable: {
      type: {
        // The type strictly equals the model name
        // listed in the model dictionary.
        equals: 'post'
      }
    }
  }
})
// Query all comments for a single image.
db.comment.findMany({
  where: {
    commentable: {
      type: { equal: 'image' },
      id: { equal: someImage.id }
    }
  }
})

// Get comments for a particular post
// from the queried post entity.
const { comments } = db.post.findOne({/*...*/})
lavoscore commented 3 years ago

Looks much better! Loving the project, but currently I'm struggling with this as I need to work with polymorphic models. My workaround is to work with several exclusive properties, which is very cumbersome. Something like this:

const db = factory({
  comment: {
    commentable: String,
    commentableAsPost: oneOf('post'),
    commentableAsImage: oneOf('image'),
    // ... every new polymorphic goes here :'(
  },
})

And then writing helpers to detect which property has data and JSON.stringify it into commentable. And later JSON.parse commentable into the final object. Handling polymorphism would allow me to get rid of all that.

NuktukDev commented 11 months ago

What's the verdict on this?

kettanaito commented 11 months ago

@NuktukDev, polymorphic relationships will land eventually but not before the 2.0 rewrite of Data. They are too much work and I'd rather them not block the rewrite. I would love to make it happen sometime next year.