mswjs / data

Data modeling and relation library for testing JavaScript applications.

Home Page:https://npm.im/@mswjs/data

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support transient attributes

veih14 opened this issue · comments

commented

Hello,

How can I create the schema in a manyof relationship where the ID of one model matches the primary key of another table when the create method is used?
I use faker to generate the UUID.

For example SalesPerson has many Orders in a one to many relationship
How can the SalesPersonId column in the Orders table match the primary key of SalesPerson?

Hi, @veih14. Can you help me understand your requirement a little better?

The way to define the relationship you described is this:

import { factory, primaryKey, manyOf } from '@mswjs/data'

const db = factory({
  user: {
    id: primaryKey(faker.uuid),
    name: String,
    orders: manyOf('order')
  },
  order: {
    id: primaryKey(fake.uuid)
  }
})

db.user.create({
  name: 'John',
  orders: [
    db.order.create(),
    db.order.create()
  ]
})

I'm not sure what you mean about that ID relationship though. Each user and each order will have their own UUID since the primary key represents a unique identifier within that model. A user cannot share their primary key with their orders in any way because that'd imply that many orders have the same primary key, which is a no-op.

If you could give me a pseudo-code example of what you want to achieve, I'd be able to help you.

commented

Thank you for your reply @kettanaito !
yes to clarify basically from your code I need each order to have a property (userId) and value that matches the PK of the User. All of the orders in each user object would have the same userId.

An example of the object I’m trying to build:
const user = {userId: 1234, name: ‘Joe’, orders: [{orderId: 345, userId: 1234}, {orderId: 346, userId: 1234}]}

Thanks for elaborating on the expected behavior! Now it's clear to me.

This is a viable use case that we don't support at the moment. Even with the V1 refactoring I'm working on, you'd be able to achieve this only through new functionality that I haven't spec'ed out yet.

What I'm thinking, a combination of a relationship and something called a derivative property can work here:

factory({
  user: { id: id(Number) },
  order: {
    user: oneOf('user'),
    userId: derivative(({ user }) => user.id))
  }
})

This will work with V1 even in its current form but you will have the order.user property which you may not want to have.

Alternatively, if you're okay with that, you can declare that oneOf relationship even with the latest Data!

commented

Thank you @kettanaito for the suggestion. So as I understand it won't be supported until V1 is released (no timeline yet right?).
Hopefully there's options if we don't want the user property to be included. Rather the order would be manyOf and just the derivative.

Yes, that's correct.

It would great to have a selective syntax for relationship properties but then it becomes something else, not a relationship between models in its purest form. I think derivatives properties is the right choice here. It's also not uncommon to have "internal" model properties that are not present on the created entities. In the context of Factory Bot, those are called transient attributes and can help achieve the use-case you're after.

factory({
  user: { id: id(Number) },
  order: {
    user: transient(oneOf('user')),
    userId: derivative(({ user }) => user.id)
  }
})

Note for myself: transient properties can also have initial values to customize the resolved value of dependent properties.

This way order.user is always available in the model definition, like in the order.userId property definition, but is not set on the generated entity. This looks like a fun feature to add.