Seeding Initial Data
The video demonstrates how to create seed data using a command directory with a dedicated main.go entry point. Seed articles are inserted through the model layer to ensure data validity, enabling the blog to display realistic content for development and UI work.
Motivation for Pagination
Loading all articles at once can harm performance and user experience. Pagination is introduced to limit the number of articles displayed per page, improving efficiency and scalability.
Page-Based vs Cursor-Based Pagination
Two pagination strategies are explained: page-based and cursor-based. Page-based uses page numbers with SQL OFFSET and LIMIT, while cursor-based uses record pointers for large datasets; the implementation focuses on the simpler page-based approach.
SQL Layer Implementation
A new query retrieves published articles using ORDER BY, OFFSET, and LIMIT. An additional count query calculates the total number of published articles to determine the total number of pages.
Model Layer Pagination Logic
A paginated response struct is introduced containing articles, next page, and previous page. The offset is calculated from the requested page, total pages are derived using a ceiling division, and navigation values are computed accordingly.
Controller Integration
The home controller reads the page query parameter from the URL and passes it to the pagination function. The returned paginated result replaces the previous non-paginated article list.
View Updates and Navigation Links
The home view is updated to conditionally display “Next” and “Previous” links based on available pages. Query parameters are appended to URLs to navigate between pages.
Result and Next Steps
Pagination successfully limits the homepage to nine articles per page with working navigation. Future work will focus on styling and improving the UI presentation.
All right, we are at a point now where the blog will only list the published articles in our database, but we have no articles in the database right now. So in this episode, I want to walk through two elements. I want to show you how we can utilize the command directory to create an easy seed entry or seed data option. And then I want to show you how we
We don't load all of our articles at once by paginating them. So typically you don't want to load like 50 or 100 articles all at once. That could potentially be a very bad performance and user experience. So we're going to implement something called page-based pagination. But first, let me quickly walk you through the seed data setup. And then we're going to implement the page-based pagination. All right.
Command directory, you have a seed directory and where I have a main.go entry point. In here, I have the config setup and our database connection setup. We just connected the same database. Then I have just created a bunch of article data here with completely random Go articles. Some of them will be published, some of them will be nuts.
And this will just give us some initial data to work with on the platform and the blog so we can see something that at least looks like real code or real blog posts on the site and then use that later on when we actually start to style it. So this I will make available in this episode's notes so you can just copy paste this code in. But this is a very handy and convenient way of creating seed data.
And notice that we are using our, I have to go to the bottom here, that's a lot of code, that we're simply using our models. So we always know we're working with valid data because everything goes through our model layer. So simple and easy way to get some seed data or dummy data where we want to call it into our application that we can start working with and build our UI around.
And to apply the seed data, we have this just command down here called seed. It simply just runs that main.go file. So if I go out here and say just seed, we create all these articles and we have one draft. So we only have what is 19 showing up on the page. And if we run the application now, we will actually see
19 articles in our home page. So let me just say just run and then jump into the browser. We can see we still have the empty page as before, but if I give this a refresh and now we can see we have all these articles here with me goes to the to the less articles and then the ID and then we can see we have all of the
the 19 published articles. And with the page-based pagination, we are gonna go down to only showing nine articles in here, and then give the option to navigate back and forth these pages. All right, so we have two kinds of pagination. You can either use page-based, or you can use cursor-based. Page-based is a simple one. You simply say, give me page one, give me page two, and then under the hood, we simply say skip,
X records and return Y records to me, that is between this limit and this offset. Cursor-based is a bit more advanced. Instead of using page numbers, we're using a pointer to a specific record. This works really, really well when you're dealing with large datasets or a lot of data at one point. For our case, we are simply going to be having a handful of articles. We never really going to be
We are potentially never going to have enough articles where this is going to be an issue. And you actually could need something like a cursor-based pagination. But it's there for you to explore. But we're just going to keep it simple. I'm going to be using page-based pagination. OK, we're going to start in the SQL layer. So in our curious articles, we're going to create a new one here. And it's going to be called CuriePopList.
articles in pages. It's gonna be returning many. And we're gonna say select star from articles where published ads is not null. Published, so we're gonna have an order by published ad descending and then we're gonna have an offset. And let me just break this up a little bit.
go, order by, order by, and then we have the offset here, argument one, and then a limit of argument two, there we go. So very similar to our query publish articles, we just add this offset and this limit to the query so that we can kind of tell where in the database that we are.
Offset simply tells Postgres how many rows to skip and limit defines how many pages to return is quite straightforward. If you're showing nine articles per page and we are on page three, we're going to be skipping the first 18 rows and then taking the next nine and then that is what gets returned to us at the end.
We also need account of how many published articles exist in total so that we can calculate the number of pages available to us so we can actually show the user to go to page one, two, three, or go to next page. There's no more pages because we don't get more than nine records back. So the final query that we need is this query. I'm just gonna grab this name right here and say query.
published articles count that is just gonna return one row. And we're gonna say select count staff and now S total count from articles where published at is not null. That looks good. And now let's jump out and say just generate curious.
And we are ready to actually implement this in the model layer. All right, so I'm in models.go now, sorry, models slash article.go. And we're gonna jump down to the bottom here. And then we're gonna create a new struct, pair g-nated articles. And in here, we're gonna have articles. That's just a slice of article. Then we're gonna have next page.
and int32, and then our previous page, that's int32 as well. And this is just what we're gonna be returning from our model function. So we're gonna create a function here called findPaginatedPublishedArticles. And we're gonna be accepting a context and a dbtx, as we always do,
And then we're gonna ask for a page which is in 32. We're gonna return patinated articles or an error. And we need to calculate the offset based on the page that we are currently on. So we're gonna create a variable called offset that's an int 32. Then we're gonna say if page is slashed in one, then we're gonna say offset page minus one, minus one.
times nine. And then we can do the typical set up. We're gonna say rows, error, we're gonna say curious, and we have to curious this published article in pages. We're gonna pass the context, the dbtx, and then our new params here. Just fill it out. And we pass the offset that we just calculated, and then we provide the limit, which is nine. Again,
We are not going to worry about errors in here. We are simply just going to be returning an empty struct and the error. And then we can actually grab what we have up here. There we go. So we just create the road to articles and then we have the article slice. Finally, we can say we need to also
tell the return values what next page and previous page are. So we need the article. Articles count. And we are gonna say query articles count, pass the context and the dbtx. Again, just return the error.
And now we can calculate total pages by saying total pages equals in 32. And then we're gonna have a math seal that's gonna take in a float, 64. And you're gonna say articles count. Yes, I'm gonna divide it by 9.0.
And this gives us our total articles. Again, let's say we have 27 articles. We will have now nine, so we have three pages. So we use MathSeal to round up so that if there's one left of article, this will count as a full page. So if we actually are at the, let's say we have 28 right, then the last page would be, we will have one more element on that final page. All right.
We next, we need the next page and the previous page. I mean, if page is less than total pages, then the next page will be page plus one. And if page is larger than one, we are gonna say previous page is negative one. And now,
Finally, we can say return, patinated articles. We add the articles and then pass in the articles that we queued earlier. We're gonna say next, next page is gonna be next page. And then our previous page is gonna be previous page and we return nil.
So this is how we paginate in pages. It's quite simple, very easy to set up. And now we can just form the controller pass in the page that we are on and we will do all the calculation in the model layer here. And we turn the correct articles and have less show up on our home page. All right, so we need to update our home controller now. So I'm in controllers slash controller.go.
And in the home controller method here, I'm gonna say page equals to one. And then we're gonna use a param. So we're gonna say if param and we can extract this from the echo context. So we have this query param that's gonna be called page and param does not equal empty string. Then we're gonna say p and then we use a string convert.
pair RAM, again return the error, and then we say page equals P. So in a minute, I'm gonna show you what a query program is, but it's simply something we can tag along to the URL that we sent to the controller. So it's a question mark, and then you will have a question mark page, and then an equal sign with the current page. And we can then grab that through this echo.
context and that is how we're gonna be telling the home controller about what page we are currently on and also what page we want next or previous depending on the button we click. Yes, so then we need to say find published articles. We don't have find paginated public articles, that's the right one.
and we simply pass in the page. All right, and we have an error here, and that's because this is an int, and we need an int32. And we no longer get back articles, we get back patchy-nated articles that we simply just now pass into the home view, and
we can update, we need to update the home view to accept this. But again, we rely on these things called security program, which is simply just a question mark and then a name and then something. And in this case, there's gonna be a number that indicates the page that we want to load. And then we find that page right. So let's update the home view quickly. And then we can actually see this working.
So we go into home here, and instead of articles, we're gonna be saying, patchy, patchy-nated articles. Articles, and we are not gonna be having a slice, and we're gonna see a patchy-nated articles. So we just need to add a small little component here. We're gonna be adding it in this section here for the latest articles, and we're gonna create a def, slash def,
And in here, oh, there we go. We're gonna say if patinated articles and pref page is larger than zero, then we will show an anchor tag. This is previous page. And copy paste this and say if next page,
slash it in zero, we're gonna say next page. And then we simply just need to grab our home route and tag on this query parameter at the end. So we're gonna say, temple, save URL. This is a temple method that we get, save URL, so we do some injection like we do here. And in here we say, FMT, sprint,
Spend F, give that a save, and we need to add FMT to the imports. And we have the homepage route. Then we have the question mark, which is the query program. The name is page. And finally, the page number. So we see a route, homepage. And in here, we are passing the paginated and the previous page.
And then we simply repeat this for the next page. So I can actually just grab everything in here. And then we pass in the next page instead. And this is our pagination for now. So again, a query program, tell the home controller what page we want. And then it does the calculation. And right now, maybe not the most user friendly right. Because if we have no next page, the button doesn't show up.
If you have no previous base, the button doesn't show up either. This we will fix in the next module when we start to do styling so that we just gray it out or make it disabled. But this requires CSS, and we haven't touched upon that yet. The final thing we need, we no longer have these articles variables. We need to, again, say, paginate articles and pass in articles. And if I jump out here and say, just run, we
Do we need to have an import? Let's just see what's this complaining about. That should be fine. We are complaining about nothing. Let's just try and run it one more time. And there we go. So let me just switch over to the browser and we can see what we have. We are in the home page. I'm gonna give this a refresh. We should hopefully see the scroll bar go down. It does, great. We still have the articles.
And now we have this next page. And you can see down in the bottom here that it goes to page two. So we click it, and we have articles. Do we have a next page? We do. We have one last article. And now we only have previous page. So we can go back. And finally, back to the home page. You can see if we refresh this, it stays consistent. So we're simply just offsetting and putting on a limit to show nine articles on each page if there are nine articles.
So our home page looking very ugly, but the functionality is there, right? So that is going to be it for now. For the home page, we're going to be dealing with the articles page in the next module. Once that is done, we are going to be applying some styling and make this look like a proper professional blog that people would actually want to visit and read.