yt-graphql-react-event-booking-api icon indicating copy to clipboard operation
yt-graphql-react-event-booking-api copied to clipboard

Splitting resolvers into separate files, causes a circular dependency.

Open KennethJoris opened this issue 3 years ago • 0 comments

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;
		}
	}
};

KennethJoris avatar Jul 12 '21 23:07 KennethJoris