Skip to content

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

@KennethJoris

Description

@KennethJoris

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions