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

Factory extensions should provide generatorOptions as a parameter #76

Open
JohnKulp opened this issue Sep 17, 2021 · 1 comment
Open

Comments

@JohnKulp
Copy link

JohnKulp commented Sep 17, 2021

This would be extremely helpful for building a shared factory passed between an objection-using client and a non-objection using client. The database one would have certain associations or transient params relating to the relational properties defined by its objection model and used within create hooks that tell the database how to save the built object.

For example, say you have a rectangle factory and a canvasFactory that contains rectangles. This factory takes max and min values for its boundaries.

const rectangleFactory = Factory.define<Rectangle, RectangleTransientParams>(({transientParams, associations}) => {
	const min = transientParams.min || 0;
	const max = transientParams.max || 5;
	const x = faker.datatype.number({min, max});
	const y = faker.datatype.number({min, max});
	const x2 = faker.datatype.number({min, max});
	const y2 = faker.datatype.number({min, max});
	return {
		x: Math.min(x, x2),
		y: Math.min(y, y2),
		w: Math.abs(x2 - x),
		h: Math.abs(y2 - y),
		canvasId: associations.canvas ? associations.canvas.id : undefined,
	}
});

Now, lets say that a rectangle has a canvasId that references its parent canvas. It must have a parent canvas. However, some things that utilize this rectangle don't have database access to save these values for the test runner. For those, we extend the factory with a nice .withFakeDatabaseValues() hook that fills in those values, and we're good to go.

However, in database land, we have an issue. We want to extend the factory like this to allow us to create rectangles with their dependency trees in tact without having to create every member of the dependency tree explicitly beforehand. So, we want something like this:

rectangleFactory.onCreate(async rect => {
	if(!rect.canvasId){
		const newCanvas = await canvasFactory.create({transientParams: {max: transientParams.max, min: Math.max(rect.x+rect.w, rect.y+rect.h)}});
		rect.canvasId = newCanvas.id;
	}
	return await Rectangle.query().insert(rect).returning('*');
})

Our canvas has transient params for a maximum dimension size and for a minimum dimension size just like the rect does. The minimum size is determined by the rect, since it has to contain the rect, but we don't want it always wrapping exactly at the edge of the rect. So the maximum is based on the original maximum fed to the rect.

Currently, there's no way to get that transientParam outside of the original define() call for rectangle factory, making this database code have to be dependency injected into a factory generator function that ends up being really weird and ugly. I personally think that the generatorOptions that are given to define should just be passed to the extensions.

rectangleFactory.onCreate(async (rect, {transientParams}) => {
	if(!rect.canvasId){
		const newCanvas = await canvasFactory.create({transientParams: {max: transientParams.max, min: Math.max(rect.x+rect.w, rect.y+rect.h)}});
		rect.canvasId = newCanvas.id;
	}
	return await Rectangle.query().insert(rect).returning('*');
})
@carmanchris31
Copy link

I was also surprised today that transientParams were not available in onCreate. 😞

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

No branches or pull requests

3 participants