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

Splitting resolvers into separate files, causes a circular dependency. #17

Open
KennethJoris opened this issue Jul 12, 2021 · 0 comments

Comments

@KennethJoris
Copy link

KennethJoris commented Jul 12, 2021

Thanks a lot for the free course.

Splitting up the resolvers index.js from branch/video #6, into folders like user.js and event.js causes a circular dependency, since users requires logic from events, and visa versa.

How do you solve these kind of circular dependency issues when different models and their "Polulators" require one another?
(getUserById => getEventsById => getUserById => getEventsById => ...)

file: user.js
Warning: Accessing non-existent property 'getEventsById' of module exports inside circular dependency
createdEvents: getEventsById(createdEvents) => TypeError: getEventsById is not a function

// @ts-check
const { User } = require('../models');
const { hash } = require('bcryptjs');
const { getEventsById } = require('./event');

module.exports = {
	// Poplulators
	getUserById: async (userID) => {
		try {
			const {
				_doc: { createdEvents, ...rest }
			} = await User.findById(userID);
			return {
				createdEvents: getEventsById(createdEvents),
				...rest
			};
		} catch (error) {
			throw error;
		}
	},

	// Resolvers
	users: async () => {
		try {
			const users = await User.find();
			return users.map(({ _doc: { password, createdEvents, ...rest } }) => {
				return {
					password: null, // Security: Hide user password in result
					createdEvents: getEventsById(createdEvents), // populate the user.createdEvents field with Event data
					...rest
				};
			});
		} catch (error) {
			throw error;
		}
	},
	user: async ({ email }) => {
		try {
			const {
				_doc: { password, createdEvents, ...rest }
			} = await User.findOne({ email: email });
			return {
				password: null,
				createdEvents: getEventsById(createdEvents),
				...rest
			};
		} catch (error) {
			throw error;
		}
	},
	createUser: async ({ userInput: { email, password } }) => {
		try {
			// Check if user already exists
			const foundUser = await User.findOne({ email: email });

			// User with email found
			if (foundUser) {
				throw new Error('User already exists');
			}

			// New user
			// Security: Hash user password
			const hashedPassword = await hash(password, 12);

			// Create a new MongoDB user model with data
			const user = new User({
				email: email,
				password: hashedPassword
			});

			// Save user to MongoDB and return result
			const { email: userEmail, password: userPassword } = await user.save();

			// Security: Hide user password in result
			return { email: userEmail, password: null };
		} catch (error) {
			throw error;
		}
	}
};

file: event.js
Warning: Accessing non-existent property 'getUserById' of module exports inside circular dependency
creator: getUserById(creator) => TypeError: getUserById is not a function

// @ts-check
const { User, Event } = require('../models');
const { getUserById } = require('./user');

module.exports = {
	// Poplulators
	getEventsById: async (eventIDs) => {
		try {
			const events = await Event.find({ _id: { $in: eventIDs } });
			return events.map(({ _doc: { creator, date, ...rest } }) => {
				return {
					date: new Date(date).toISOString(),
					creator: getUserById(creator),
					...rest
				};
			});
		} catch (error) {
			throw error;
		}
	},

	// Resolvers
	events: async () => {
		try {
			const events = await Event.find();
			return events.map(({ _doc: { creator, date, ...rest } }) => {
				return {
					date: new Date(date).toISOString(),
					creator: getUserById(creator),
					...rest
				};
			});
		} catch (error) {
			throw error;
		}
	},
	createEvent: async ({ eventInput: { title, description, price, date } }) => {
		// Create a new MongoDB event model with data
		const event = new Event({
			title: title,
			description: description,
			price: +price,
			date: new Date(date),
			creator: '60ecc8c9b01258b09dc23aa8'
		});

		// eventDate temp store
		let storedEvent;

		// Save event to MongoDB and return result
		// Add event to user.createdEvents
		try {
			const { _doc: eventData } = await event.save();

			// Store even data
			// Reference Event creator to User
			storedEvent = {
				...eventData,
				date: new Date(eventData.date).toISOString(),
				creator: getUserById(eventData.creator)
			};

			// Find creator
			// To add event to user.createdEvents
			const foundUser = await User.findById(eventData.creator);

			// no User found
			if (!foundUser) {
				throw new Error('No user found');
			}

			// Add event _id to user.createdEVents
			foundUser.createdEvents.push(eventData._id);
			// Save (same as update) user
			await foundUser.save();

			// return the stored event
			return storedEvent;
		} catch (error) {
			throw error;
		}
	}
};
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