Ver código fonte

Allow to paginate from any post and add previousURL field

sbkwgh 8 anos atrás
pai
commit
aa06e1c531
4 arquivos alterados com 106 adições e 46 exclusões
  1. 13 18
      lib/pagination.js
  2. 13 3
      models/thread.js
  3. 53 10
      routes/thread.js
  4. 27 15
      test/thread_post.js

+ 13 - 18
lib/pagination.js

@@ -19,26 +19,10 @@ async function getPreviousId(Model, where, items, limit) {
 		let minId = await Model.min('id', { where })
 		let firstItem = items[0]
 
-		let lteVal
-
-		if(firstItem.id - limit) {
-			lteVal = firstItem.id - limit
-		} else {
-			minId
-		}
-
 		if(!firstItem || minId === firstItem.id) {
 			return null
 		} else {
-			let instance = await Model.findOne({
-				where: Object.assign({}, {
-					id: {
-						$lte: lteVal
-					}
-				}, where)
-			})
-
-			return instance.id
+			return firstItem.id
 		}
 	} catch (e) {
 		console.log(e)
@@ -49,12 +33,23 @@ async function getPreviousId(Model, where, items, limit) {
 
 function getPaginationProps(query) {
 	let lastId = 0
+	let previousId = null
 	let limit = 10
 
 	if(+query.lastId > 0) lastId = +query.lastId
 	if(+query.limit > 0) limit = +query.limit
 
-	return { lastId, limit }
+	if(query.previousId) {
+		lastId = null
+
+		if(+query.previousId > 0) {
+			previousId = +query.previousId
+		} else {
+			previousId = 0
+		}
+	}
+
+	return { lastId, limit, previousId }
 }
 
 module.exports = {

+ 13 - 3
models/thread.js

@@ -17,17 +17,27 @@ module.exports = (sequelize, DataTypes) => {
 				Thread.belongsTo(models.Category)
 				Thread.hasMany(models.Post)
 			},
-			includeOptions (lastId, limit) {
+			includeOptions (lastId, limit, previousId) {
 				let models = sequelize.models
 
+				let where = {}
+				let order = [['id', 'ASC']]
+
+				if(lastId !== null) {
+					where.id = { $gt: lastId }
+				} else {
+					where.id = { $lt: previousId }
+					order = [['id', 'DESC']]
+				}
+
 				return [
 					{ model: models.User, attributes: ['username', 'createdAt', 'color', 'updatedAt', 'id'] }, 
 					models.Category,
 					{ 
 						model: models.Post, 
-						where: { id: { $gt: lastId } },
+						where,
+						order,
 						limit: limit,
-						order: [['id', 'ASC']],
 						include: [
 							{ model: models.User, attributes: ['username', 'createdAt', 'id', 'color'] }, 
 							{

+ 53 - 10
routes/thread.js

@@ -7,24 +7,67 @@ let pagination = require('../lib/pagination.js')
 
 router.get('/:thread_id', async (req, res) => {
 	try {
-		let { lastId, limit } = pagination.getPaginationProps(req.query)
+		let { lastId, limit, previousId } = pagination.getPaginationProps(req.query)
+		let thread, resThread
+
+		if(+req.query.postId) {
+			let findObj = {
+				limit: Math.floor(limit / 2),
+				order: [['id', 'ASC']],
+				include: Post.includeOptions()
+			}
+
+			thread = await Thread.findById(req.params.thread_id, {
+				include: [
+					{ model: User, attributes: ['username', 'createdAt', 'color', 'updatedAt', 'id'] }, 
+					Category,
+				]
+			})
+			if(!thread) throw Errors.invalidParameter('id', 'thread does not exist')
+			resThread = thread.toJSON()
+
+			let postsAfter = await Post.findAll(Object.assign({}, findObj, {
+				where: {
+					id: { $gt: +req.query.postId },
+					threadId: req.params.thread_id,
+				},
+			}))
+
+			let postsBefore = await Post.findAll(Object.assign({}, findObj, {
+				where: {
+					id: { $lte: +req.query.postId },
+					threadId: req.params.thread_id,
+				},
+				order: [['id', 'DESC']],
+			}))
+
+			resThread.Posts = postsBefore
+				.concat(postsAfter)
+				.map(p => p.toJSON())
+				.sort((a, b) => a.id - b.id)
 
-		let thread = await Thread.findById(req.params.thread_id, {
-			include: Thread.includeOptions(lastId, limit)
-		})
+		} else {
+			thread = await Thread.findById(req.params.thread_id, {
+				include: Thread.includeOptions(lastId, limit, previousId)
+			})
 
-		if(!thread) throw Errors.invalidParameter('id', 'thread does not exist')
+			if(!thread) throw Errors.invalidParameter('id', 'thread does not exist')
+			resThread = thread.toJSON()
 
-		let resThread = thread.toJSON()
-		resThread.meta = {}
+			if(previousId) {
+				resThread.Posts = resThread.Posts.sort((a, b) => a.id - b.id)
+			}
+		}
 
+		resThread.meta = {}
+	
 		let nextId = await pagination.getNextId(
 			Post,
 			{ threadId: +req.params.thread_id },
 			resThread.Posts
 		)
 
-		let previousId = await pagination.getPreviousId(
+		let beforeId = await pagination.getPreviousId(
 			Post,
 			{ threadId: +req.params.thread_id },
 			resThread.Posts,
@@ -38,9 +81,9 @@ router.get('/:thread_id', async (req, res) => {
 			resThread.meta.nextURL = null
 		}
 
-		if(previousId) {
+		if(beforeId) {
 			resThread.meta.previousURL =
-				`/api/v1/thread/${thread.id}?limit=${limit}&lastId=${previousId}`
+				`/api/v1/thread/${thread.id}?limit=${limit}&previousId=${beforeId}`
 		} else {
 			resThread.meta.previousURL = null
 		}

+ 27 - 15
test/thread_post.js

@@ -51,7 +51,7 @@ describe('Thread and post', () => {
 	})
 
 	//Delete all rows in table after
-	//tests completed
+	//tess completed
 	after(() => {
 		sequelize.sync({ force: true })
 	})
@@ -367,6 +367,11 @@ describe('Thread and post', () => {
 				.set('content-type', 'application/json')
 				.send({ category: 'category_name', name: 'pagination' })
 
+			let threadOther = await userAgent
+				.post('/api/v1/thread')
+				.set('content-type', 'application/json')
+				.send({ category: 'category_name', name: 'pagination_other' })
+
 			PAGINATION_THREAD_ID = thread.body.id
 
 			for(var i = 0; i < 30; i++) {
@@ -375,6 +380,13 @@ describe('Thread and post', () => {
 					.set('content-type', 'application/json')
 					.send({ threadId: thread.body.id, content: `POST ${i}` })
 
+				if(i === 3) {
+					await userAgent
+						.post('/api/v1/post')
+						.set('content-type', 'application/json')
+						.send({ threadId: threadOther.body.id, content: `POST OTHER ${i}` })
+				}
+
 				if(i === 15) MID_PAGINATION_POST_ID = post.body.id
 			}
 
@@ -389,10 +401,7 @@ describe('Thread and post', () => {
 
 			pageTwo.body.Posts.should.have.length(10)
 			pageTwo.body.Posts[0].should.have.property('content', '<p>POST 10</p>\n')
-			pageTwo.body.meta.should.have.property(
-				'previousURL',
-				`/api/v1/thread/${thread.body.id}?limit=10&lastId=${pageOne.body.Posts[0].id}`
-			)
+			pageTwo.body.meta.should.have.property('previousURL')
 
 			pageThree.body.Posts.should.have.length(10)
 			pageThree.body.Posts[0].should.have.property('content', '<p>POST 20</p>\n')
@@ -408,20 +417,23 @@ describe('Thread and post', () => {
 			let pageZero = await http.get(pageOne.body.meta.previousURL)
 			let pageTwo = await http.get(pageOne.body.meta.nextURL)
 
-			pageOne.body.Posts.should.have.length(11)
-			pageOne.body.Posts[0].should.have.property('content', '<p>POST 10</p>\n')
-			pageOne.body.Posts[5].should.have.property('content', '<p>POST 15</p>\n')
-			pageOne.body.Posts[10].should.have.property('content', '<p>POST 20</p>\n')
+			pageOne.body.Posts.should.have.length(10)
+			pageOne.body.Posts[0].should.have.property('content', '<p>POST 11</p>\n')
+			pageOne.body.Posts[4].should.have.property('content', '<p>POST 15</p>\n')
+			pageOne.body.Posts[9].should.have.property('content', '<p>POST 20</p>\n')
 
-			pageTwo.body.Posts.should.have.length(10)
+			pageTwo.body.Posts.should.have.length(9)
 			pageTwo.body.Posts[0].should.have.property('content', '<p>POST 21</p>\n')
-			pageTwo.body.Posts[9].should.have.property('content', '<p>POST 30</p>\n')
+			pageTwo.body.Posts[8].should.have.property('content', '<p>POST 29</p>\n')
 			pageTwo.body.meta.should.have.property('nextURL', null)
-
+			
 			pageZero.body.Posts.should.have.length(10)
-			pageZero.body.Posts[0].should.have.property('content', '<p>POST 0</p>\n')
-			pageZero.body.Posts[9].should.have.property('content', '<p>POST 9</p>\n')
-			pageZero.body.meta.should.have.property('previousURL', null)
+			pageZero.body.Posts[0].should.have.property('content', '<p>POST 1</p>\n')
+			pageZero.body.Posts[9].should.have.property('content', '<p>POST 10</p>\n')
+
+			let pageFirst = await http.get(pageZero.body.meta.previousURL)
+			pageFirst.body.Posts[0].should.have.property('content', '<p>POST 0</p>\n')
+			pageFirst.body.meta.should.have.property('previousURL', null)
 
 		})
 		it('should return an error if :id is invalid', async () => {