So now we want to improve our calendar, we want it to when we were looking at a given month, if there
is a block, if the owner is closed, the room for, say, these three dates for the generals quarters
for the seventh, eighth and ninth of December, these should show up checked.
And if there's a reservation, say, on the second and third, we shouldn't see checkboxes at all.
We should see some indication that there is a reservation for those dates and clicking on it should
take us to that reservation.
So let's get started.
So right now in our handler over here, let's find our handlers right here.
So I'm inside the handlers file looking at the admin reservations calendar method or function.
And right now I have the rooms.
I have the room stored in this variable rooms.
And what I want to do is to somehow store information about the current blocks and the current reservations
in a data structure that I can pass to my template so I can use that to determine how to render the
calendar.
So if you look back at the calendar, there's a couple of ways you might do this.
You could say write a function and add it to our render package that says every time you're about to
render this particular cell, say, call a function to say, is there a reservation for this date?
If so, do something.
And then if there's not called another function to say, is there a block for this date and if so,
do something, and if not, just display an empty checkbox.
But if you think that through, that would mean since there are 31 days in this month and two rooms,
that's a total of 62 dates to check and two function calls on each of those dates.
So that be two times, 31 times two, which is a big number.
That's an awful lot of database queries to perform.
And it's really not that efficient.
It might be much more useful if we could get all of that information and stored in some data structure,
say, a map, for example, and use that to determine how to render a given cell for a given date,
for a given room.
And I think that's a far more efficient method.
So let's get started doing that.
I'm going to go back here and I'm going to range through this room's variable that I have.
So for and I'm going to ignore the index and just call the variable.
I'm going to look at X range rooms.
And inside of that I'm going to create two maps.
And the very first map I'm going to create is for reservations and the next one will be for the actual
blocks.
So let's create two maps, create maps.
The first one is going to be called reservation map and it will be assigned the value of make map string.
And that's how we'll look it up and I'll just store in there and it and let's duplicate this line and
create a block map.
OK, so now that I have these created, how am I going to get the information for you in this map useful?
Well, the first thing I need to do is make sure that there's one entry for every single day in the
current month in both the reservation map and the block map.
That means I need to somehow loop over all the days of the month.
Well, if you recall, we already know what the first day of the month is.
We have it here and we know what the last day of the month is.
We have it here.
So let's just do a for loop and we'll do this, not looping through INTs, but instead looping through
dates, which we haven't done yet.
But isn't that hurt?
So for my variable will be called D, and that's going to be equal to the first of the month.
And I want to go until I'm not after the last day of the month.
So since it's a date, I can just say dot after and I can use my variable last of month if that's equal
defaults.
While that's while we're not after the last day of the month, keep going.
And every time you iterate through the through the loop, add one to the current day.
Didn't add date.
Zero years, zero months and one day and what I'm going through, this just put a default value in in
both the reservation map, reservation map for the current day.
And I'm going to use this as a string.
This is how we're going to look things up.
So current is D format and my format string will be a four digit year, a two digit month and a one
or two digit day.
And that's going to be equal to zero, which will say this room is available and don't do the same thing
for the block map.
OK, so now I've initialized both of these reservation maps, each of these maps has an entry for every
day of the current month and the value is zero and the lookup is a string.
That would be the four digit year, followed by a hyphen, followed by a two digit month, followed
by a hyphen followed by a one or two digit day.
So that will be how we look things up, which is extremely convenient, because on this calendar, I
know what the current year is.
I have a value that I'm storing in the string map called current year, and I have another one for the
current month so I can actually build the date as I'm iterating through my range.
That gives me this table in the first place.
So that's how we're going to look things up.
Now that we have this done, we need next to get all the restrictions for the current ramp and that
means we need a database function to do that and we don't have one that does that yet, but we can do
it really, really easily.
So let's go over to our postgrads Dongo.
And at the very bottom of this file, I will create a new function, which I will call func.
It'll have the receiver of Postgres DB Repo.
And I'll call it get restrictions for room by day, and it will have to have three parameters.
First of all, what room are we dealing with the remedy?
And that's an end and then the start date we want to look at and the end date we want to look at, both
of those will be of type time, time.
And I'm going to return a slice of model's room restriction.
And potentially an error.
OK, so as I always do, I'm going to copy the context code so I don't have to retype it pasted in here.
And now we need to write the query.
Well, we need some to store the information first.
So let's create a variable called restrictions of type slice models, dot room restriction.
And now let's write our query.
And this is a really easy query.
It's pretty much the same syntax that we've used for other lookups or queries that deal with the reservations
and blocks and so forth, availability queries, in other words.
So I'm going to select I will select ID and then I need the reservation ID.
If it exists and it might be null and I'm going to talk about that in a moment, and we need the restriction
ID and we need the remedy and we need the start date and we need the end date and we're going to get
all of that from room restrictions.
Where and this is the same logic we used before, so our start date is less than the end date and our
end date is greater than or equal to the start date.
And the remedy is equal to whatever we're passing it.
So that's our query.
OK, now let's get our Rose.
Rose Air is a sign the value of IMDB dot query context handed the context and did our query, handed
our start, handed our end and our remedy.
If error is not equal to nil, then just return nil and the error otherwise answer it.
So we've got to defer our rose close here.
And for Rose next.
We create an empty variable to hold the restrictions of our hour is of type models, room restriction.
And scan error is a sign the value of rose dot scan and will scan into that variable we just created
and we're going to put in to the variable error ID and I'll just duplicate this a few times, as I usually
do.
And our second value was the reservation ID.
Now that might be a problem and I'll talk about that in a moment.
And the restriction ID and the remedy.
And the start date and the Endi.
OK, so here's the problem, if you think about what's in the room restrictions table, we don't always
have a value for reservation.
So let me go look at post code and show you what I'm talking about.
So make sure I'm on the right database, go to bookings, look at room restrictions.
And here we have room restrictions.
It's not the right one.
Yes, it is reservation, if you look at this, all of these ones have a null for a value and they should
because they're blocks, they're not actual reservations.
Those are dates and rooms where the property owner has decided not to rent the room for that particular
date range.
So they're all null it back here in my query when I try to get reservation ID, if it's in.
No, I'm trying to store a null value into this very this field of this variable reservation ID of the
variable hour, which is of type models, room restriction and go will not let you do that because a
null is not an int and it wants an int.
So I need to make some determination as to what to do with that null value.
Unfortunately it's really, really easy.
There's a couple of ways of doing it.
Go has a null int type that I can use, but I find that a real pain and tend to avoid it whenever I
possibly can.
I find this approach works really well.
I use one of the built-In features that's available in sequel.
It's called Coalesce.
And what I'm going to do.
Is change my query as follows?
I say, if reservation ID has a value and that value is not null, use it, otherwise use zero.
And that's perfect for my purposes because I can store zero, which is an entry down here.
No problem.
And if it has, he actually has a reservation.
I'll store the ID for that reservation instead and that solves my problem.
All right.
So let's check for an error.
I'll just copy this if areacode paste it here.
If there is no error, I will take, which is are not error.
If I get past that, there's no air, so I can just say restrictions equals append restrictions and
earn.
And that will take care of that and then, of course, as I always do, I'll check to make sure one
last time if error is equal to.
If error equals Rove's error.
And air is not equal to nil.
Then something went wrong, so I'll just return nil and error, otherwise return the data that we just
got, return restrictions and nil.
OK, so I've created this.
Let's give it its comment as it should have, and then add it to the repository and added to our DNA
testing be rebuilt returns, restrictions
for a room by date range.
And let's copy the whole thing.
And open up our test repo.
And paste it in here and make it as simple as possible.
So our application will compile.
Give it the correct receiver.
And now add this entire string to a repository.
Right here.
OK, let's make sure the application compiles so we don't have any typos anywhere and we have X to clear
but not used.
OK, so that's to be expected because we haven't actually done anything with that X yet.
So let's get our restrictions.
Restrictions and potentially an error are equal to IMDB dot get restrictions for room by date are variable
called X, so we get a remedy from X.
We want all the restrictions for this room for the current month so we can use our first month as our
start and our last month as the end.
And that will get me all of the restrictions for this room for the current month, which is exactly
what I need.
So we've got a check for an error.
If error is not equal to nil, we'll just say helper's dot server error W and the error and return.
Otherwise we can now do something with our restrictions.
So what we're going to do is loop through those restrictions one at a time and determine whether it's
a reservation or it's a block.
If it's a reservation, we'll put the appropriate entry in our reservation map if it's a block will
put the appropriate entry in our block map.
So this is pretty straightforward for underscore or ignore the index and I'll use Y, which is a variable
I've not used yet that's going to range through restrictions.
And we just checked to see is it a reservation?
How do I know it's a reservation?
If reservation ID is greater than zero than it's a reservation, otherwise it's a block.
So if we got DOT reservation, it is greater than zero.
It's a reservation otherwise.
It's a block, so reservations can be one day long or they can be ninety nine days long, so we need
to actually loop through the dates for the current reservation and put one entry for each of the dates
into our reservation map.
Unfortunately, that's pretty easy.
We can use exactly the same logic we did up here for D is assigned the value of and the the first index
will be the reservation start date.
So we're going to start at the start date and we want to go until we're not after.
It's not D it's a yes it is after until we're after the end date for the reservation that has to be
equal to faults in order to keep going through the loop.
And we need to add one to the date.
D is equal to dot add date.
No years, no months one day and we're going to loop through that.
So get our parentheses in there.
And what we're going to do is put a value in the reservation map.
So reservation map and here we need to actually build the string appropriately and we're just going
to use the same format we did up here.
DOT format and the layout will be a four digit year, a two digit month and a one or two digit digit
day.
And we don't want that to be equal to zero or one.
We need it to be equal to the reservation ID, reservation ID.
So now our map will have for all of the days of the current reservation and entry that is equal to the
date that the rise that we're dealing with and the reservation ID.
And we can use that to build a link to the reservation in our map.
Now if it's a block, it's even easier.
We just need to put because all blocks are one day long, we can just say block map.
Not or why not start date?
That format and used the same syntax, zero, one two, and that will be equal to and we'll put in the
restriction in.
So that gives me the actual restriction ID itself, the one that I can use to link to the restriction
that I need to close, and that's pretty straightforward.
So as long as it's not zero and it won't be zero, this will be a restriction, a block for that current
date.
So now I have these things built after this for loop is finished.
What am I going to do with them?
Well, I need to put them somewhere so I can pull them out in the template and use them as I need to.
And that's pretty straightforward.
We use our data variable data and I'll give it a look up and I want to be able to look it up for an
individual room, both the reservation map and the block map.
So I'll just give it a meaningful name using format dot as print f.
And I'll call it reservation map, underscore, map, underscore and present deals, and I'll replace
that with the idea of the room.
So that will be Eckstut ID.
And that's going to be equal to my reservation man, and I'll duplicate this and change this to block.
And then I'll store the block map in there, so that gives me one reservation map for every room and
one block map for every room, and the reservation map will have an empty default values of zero if
there is no reservation for for a given day or will have the ID of the reservation for a given day if
one exists.
And the same thing with a block map zero if there's no block and the ID of the block if it does exist.
Now, there's one other thing I'm going to do here.
I'm actually going to store the block map for this room in this session and I'm going to do that for
a reason which may not be immediately apparent.
But let's get it in there and then I'll tell you why I'm doing it.
Amde App Session put.
Our context and I will call this format formatter, sprint f block, underscore, map, underscore D
ID for the substitution and I'm going to store in the block map the current block map for the current
round.
So there will be one entry put in the session for every room that I'm dealing with.
So there'll be two to put in here every time I come through.
And this is important and the reason it's important is not immediately apparent, but will be shortly.
Let me give you the the short version of it.
When the map is when the calendar is first rendered to the screen, I need to store the block map as
it existed at the moment it was rendered and before the user does anything to the reservation calendar.
And the reason is once they post that, my post handler will pull this map out of the session and use
that to compare what we currently have with what we used to have.
So I'll be able to determine things like which blocks am I getting rid of and which ones are new.
And I need to have this information in order to do that.
And the other thing to bear in mind is I just put a map of type string int into the session, but I
haven't actually told my application that I'm going to be storing things like that in the session.
So let's open our mango and do that ghab register right here in the run function on mango.
I need to register a type of map string.
Int.
There, so I've now got this information, let's make sure everything renders the way our runs the way
it should.
So let's try compiling the application.
Let's go back to our screen here and make sure everything works, so look at new reservations and now
look at our reservation calendar.
Perfect.
So at this moment, I have everything I need a pass to my template in one form or another in order to
be able to render the dates appropriately.
I think I do.
Anyway, let's go make sure.
So back in my template.
I'm going to look and make sure that I'm pulling everything out of there, I have the current date,
I have the current rims, I know the days in the month.
Now, there's two other pieces of information that I stored that I need to get here as well.
So let's go back to our handlers and have a look here.
So I stored at some point in the string.
Yes, here I have this month and this year, which I need to be able to have access to in the next lecture.
So let's grab that information right now.
So let's go back here and say.
Per month is a sign the value of index dot, string map.
And what did I call it back in my handlers?
I called it this month.
And then I'll duplicate this line year and Curre year and let's make sure that that still renders appropriately
reservation calendar.
Yes, it does.
OK, so at this point, I know that I have everything I need pass to this template.
I have a total of four maps with respect to restrictions, a block map for generals quarters, a block
map for major suite.
I have a reservation map for generals quarters and a reservation map for four major suite.
And I know the current month and I know the current year.
So this is all the information I need in order to render the information on the screen.
And that's what we'll take care of in the next lecture.