Instructor: All right, and now just to finish this part,
let's create some factories for getting documents.
And let's start with getOne here, okay?
Exports.getOne, but this one is actually a bit trickier,
and that's because we have a populate
in the getTour handler.
So, let's take a look at that.
So, right here, in this one, we have this populate here,
which is different from all the other get handlers
in the other resources, right?
But, well, this is not really a problem
because we will simply allow ourselves to pass in
a populate options object into our getOne function, okay?
So, instead of simply passing in the model,
we will also have populate, so options, all right.
And so, from here we will then return
the normal handler function.
So, let's go ahead and again copy all of this,
all right.
So, we don't need this one here.
Then here, as always, it is model,
and here it is doc.
Well, actually here, document,
and here, once again, data equal to doc.
Now, we also need to make some changes here now
because of this populate,
so basically, we will first create the query,
and then, if there is the populate options object,
we will then add that to the query,
and then by the end, await that query, okay?
Make sense?
So, let's translate what I just said.
So, the query is simply equal to Model.findById,
like this, right?
Then, if there is a populate options object,
well, then in that case,
query is gonna be
query.populate with the populate options, okay?
And then, finally we await our query,
and save it in the document.
So, await query just like this, all right.
And so, that's actually it.
So, this logic that we have here
with not awaiting the query right away,
but instead just saving it into a variable,
so that we can then, in the next step, manipulate it.
We actually already did this kind of stuff before
when we were building our API features, right?
So, only in the end, when the entire query is ready,
we will then await it and store it somewhere in a variable.
Now, let's go ahead and actually use this one everywhere,
starting of course with the Tour.
So, getTour will now be
factory.getOne,
and pass in the Tour
and populate options object, remember that?
And so, what we're gonna do is to say path and reviews.
Right, so remember that the path property is basically
the field that we want to populate,
and then we can also specify select,
so remember this one, where we specify
which of the fields we actually want to get, right?
But in this case,
we don't have any of that,
and so let's just leave it like this.
And now, we can actually go ahead and delete all of this.
So, great.
And, just to make sure, let's actually quickly test this.
So, we'll gt a certain Tour,
and, indeed, it still works.
Let's see if this one had some reviews.
Oh, yeah, actually it does, and you see
that the population process is also still working.
So, that was successful, I would say.
And so, now lets also use this getOne
in all the other resources.
So, the user controller here where we have,
let's see where it is, ah, down here.
So, let's say factory.getOne,
but only with the user model,
and no populate options object.
Okay, and since we're here,
let's actually just change the error message
here for create user,
so this route is not defined, it never will be,
and please use signup instead.
Next up, and finally,
the same thing for the reviews basically.
So, exports.getReview
is equal factory.getOne review,
and I think we don't have (mumbles) our routes just yet.
And, indeed, we don't, so adding this real quick here,
reviewController.getReview, okay?
Let's just quickly test this one as well,
just because I also want to then add it
here to Postman, okay?
So, just copying this one because it's similar,
and then, indeed, it is get.
And, yep, works perfectly fine, store it here in reviews,
and getReview.
All right, an now all that's missing is
basically a getAll factory function, right?
So, basically, to replace
this getAllTours, getAllUsers,
which we should also have somewhere here,
so getAllUsers, and also getAllReviews,
so let's again copy it here from the Tour controller
because actually this is the one that is really complete
because it has all these API features,
and so, after creating our getAll factory function,
all of the three resources will then get these API features.
So again, copying all of this,
exports.getAll,
and so now, we will actually have to require
these API features here,
and in fact we can actually remove it from here
because we will no longer need it
because we now transfer this to the handler factory, right?
Now, here all we need to do is then to replace, as always,
with model, and then here,
doc and data.
Now, okay, perfect.
So, let's see if this works,
getAll with Tour.
And now, I really want to see if this still works
with all these features,
and so it's here, getAll Tours,
and so, let's add our query string here,
and let's say duration greater or equal than let's say a 10,
and sort by price.
Okay, and so we get two results here.
Okay, it's not working.
Anyway, we get the two (chuckles) results here,
and they both have a duration greater than 10,
and the price is 1497,
and the second one is higher, okay?
Let's put it here like to seven,
so we get a bit more results.
Okay, and now we get five.
Okay, anyway, let's now do the same for the reviews
because I'm really excited to test out these API features
on the reviews as well.
Now, one problem that we have here is
that this route handler actually has these two lines of code
that all the other getAll handlers do not have, okay?
But, what we're going to do here is to simply copy this code
into our handler factory as well, okay?
That's kind of a hack
because we really only need this one for getAll reviews,
but to get around this would be a bit too much work
here in this situation, and once more,
I simply want to keep it simple here, all right.
So, let's copy this here,
and I'm adding a comment here to allow
for nested getReviews on Tour, okay?
And so this filter, we will then also pass it in here, okay?
So again, this is a small hack,
but I'm gonna leave it here like this
because I think it is reasonable, all right.
Anyway, let's now get rid of this,
so factory.getAll and review, okay?
Let's actually put this down here next to all the others.
And now, as you see,
we actually do not even need this catchAsync here anymore,
so I'm gonna comment it out here
because, who knows, maybe in the future we're gonna need it
for some other Middleware function here, all right.
So, that looks nice and clean,
and let's now test out the getAll reviews.
All right, so let's actually just save changes here as well.
These ones we don't need,
but I actually want to get all the reviews.
So, right now we have four reviews,
and so let's now try to filter for reviews
only with a rating of four, let's say.
So, query string, rating equal four.
Oh, and it actually works,
so nice, that's really nice.
So, just like this, we get access to all these API features
like filtering, sorting, pagination, and all that good stuff
that we implemented (chuckles)
a long time ago in the course, right?
And, I also want to make sure
that this getAll reviews on Tour also still works.
So, let's check that,
and, yeah, you see that it actually does.
So, the Tour ID that we have here is
exactly the one right here and right here.
So, that one is also still working,
and so let's finally also use getAll
for the user controller, all right.
So, basically replacing simply this,
so factory.getAll user, all right.
And, let's actually put this one
here close to the other ones, all right.
And, then this one as well,
so basically having all of these ones generated
by factory functions together,
and then all the others simply above them.
All right, let's do the same here,
this one is already nice and clean,
and the same for the Tour controller,
so what else do we have here?
This one we can get rid of,
and, okay, I think it looks nice like this.
Again, we can comment out this piece of code
because, for now at least, we don't need it anymore.
And so, just to test it again here with the users,
let's get all of them together,
and, indeed, here they are.
We can now also say that we only want the ones
with the role of user,
and, indeed, that works as well.
Great, and that actually wraps up this part
of creating handler factory functions,
and this really was a huge step forwards in our project,
so remember that, a bit later,
we will also create a booking resource,
and so you see that probably we're gonna be able to create
the main API for these bookings
in like five seconds or something,
simply using these five factory functions, all right.
Anyway, good work, great job,
and I'll see you in the next one.