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

Composable/extendable traits #1101

Open
TSenter opened this issue Mar 21, 2024 · 0 comments
Open

Composable/extendable traits #1101

TSenter opened this issue Mar 21, 2024 · 0 comments

Comments

@TSenter
Copy link

TSenter commented Mar 21, 2024

While working on a new workflow-based app, I've come into a scenario where a workflow instance can be in one of many states. I'm going to create traits to represent each state in the workflow, but I'll be duplicating a lot of code. For a workflow instance to be in state C, it must have progressed past states A and B. I can currently create my model with the following:

server.create('instance', 'stateA', 'stateB', 'stateC');

However, I would much prefer to specify in the definition of trait stateC that it extends the behavior from stateA and stateB; more concisely, stateB extends stateA, and stateC extends stateB. I believe this can be accomplished in one of two ways: a function named applyTraits that takes the model, server, and list of trait names to apply; alternatively, the trait function can take a separate argument that includes the list of trait names this new trait extends. I imagine these two solutions would look something like this:

New function:

export default Factory.extend({
  status: 'Pending',

  stateA: trait({
    status: 'State A',
    afterCreate(instance, server) {
      // Do something for state A
    }),
  }),

  stateB: trait({
    status: 'State B',
    afterCreate(instance, server) {
      applyTraits(instance, server, 'stateA');
      // Do something for state B
    }),
  }),

  stateA: trait({
    status: 'State C',
    afterCreate(instance, server) {
      applyTraits(instance, server, 'stateB');
      // Do something for state C
    }),
  }),
});

Composability:

export default Factory.extend({
  status: 'Pending',

  stateA: trait({
    status: 'State A',
    afterCreate(instance, server) {
      // Do something for state A
    }),
  }),

  stateB: trait({
    status: 'State B',
    afterCreate(instance, server) {
      // Do something for state B
    }),
  }, {
    composes: ['stateA'],
  }),

  stateA: trait({
    status: 'State C',
    afterCreate(instance, server) {
      // Do something for state C
    }),
  }, {
    composes: ['stateB'],
  }),
});

I believe between the two, I prefer the new function. This allows you to explicitly define the order you want these additional traits to be executed/applied, despite being a little more verbose.

Lastly, I am happy to work on this implementation myself. I already have a hacky implementation for the functional solution in my local app, which I am going to use in the meantime. I would like some feedback on if this would be a useful feature before I begin integrating it into the Mirage.js codebase.

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

1 participant