commercetools-jvm-sdk icon indicating copy to clipboard operation
commercetools-jvm-sdk copied to clipboard

Add helpers for prev/next like functionality (products)

Open emmenko opened this issue 10 years ago • 11 comments

@schleichardt it would be good to provide some helpers like

  • [ ] hasPrev()
  • [ ] hasNext()
  • [ ] prev()
  • [ ] next() which will calculate what would be the prev / next product based on the products list (PagedQueryResult) I pass to those helpers.

Do you know what I mean?

emmenko avatar Jul 11 '14 08:07 emmenko

The interesting part in it is to keep the context, like reference expansion.

schleichardt avatar Jul 11 '14 08:07 schleichardt

I don't know if it is possible, but it would be nice to have something like iterable, hasNext(): boolean, next(): Query<Product>

schleichardt avatar Jul 11 '14 08:07 schleichardt

Well, my idea was that the helper should just do the calculation and accept only a PagedQueryResult. So the client has to keep track of the list (cache, session, ...) and use the helper to get something like a product or the prev/next query. The question is then, if the client has to fetch the next "page", should the helper do the async/sync request or let the client take care of it?

emmenko avatar Jul 11 '14 09:07 emmenko

The "models" can't do actual http requests, you need to go through the client.

schleichardt avatar Jul 11 '14 09:07 schleichardt

The client does not see play http related stuff.

schleichardt avatar Jul 11 '14 09:07 schleichardt

For client I mean the shop (play application), not the java-client :)

emmenko avatar Jul 11 '14 09:07 emmenko

Yes, this is an important issue, I think I will sit together with Laura to design this.

schleichardt avatar Jul 11 '14 09:07 schleichardt

Cool

emmenko avatar Jul 11 '14 09:07 emmenko

@schleichardt I did some research regarding this topic and it's actually simpler then it looks. Let me explain it a bit as it might give you some ideas how to implement this.

So products are a collection of documents and they have some indexes (_id, createdAt, ...). If you just query without any sorting criteria, mongo returns documents in a so called natural order which it's not reliable as it might change (e.g.: update operation). Providing a sorting criteria assures that you will always get reliable results. So far nothing new.

So how to get the previous / next document? It turns out you just need to query for greater / less value and sort by that value asc / desc (respectively), and then limit the result to 1. That means getting the prev / next document works if you use sorting and query for the same value, and if the value is unique and hopefully has an index.

// example: get first 5 products sorted by createdAt.asc
db.products.find().sort({createdAt: 1}).limit(5).forEach(function(doc){
    var o = {}
    o.id = doc._id
    o.createdAt = doc.createdAt
    print(o)
})
// =>
/* 0 */
{
    "id" : JUUID("8c574527-a160-4eec-99d3-7af8b0f99421"),
    "createdAt" : "2014-08-03T09:27:02.690Z"
}
/* 1 */
{
    "id" : JUUID("98f1006e-6338-4fbb-8683-492c68c7ba5c"),
    "createdAt" : "2014-08-03T09:27:02.714Z"
}
/* 2 */
{
    "id" : JUUID("1fb4147d-8b5f-4033-839d-3e0011d229fc"),
    "createdAt" : "2014-08-03T09:27:02.740Z"
}
/* 3 */
{
    "id" : JUUID("8a94097e-c394-46b5-b311-fbb3729bac0e"),
    "createdAt" : "2014-08-03T09:27:02.771Z"
}
/* 4 */
{
    "id" : JUUID("f7591242-2205-43b2-87ac-bdecf9952caf"),
    "createdAt" : "2014-08-03T09:27:02.793Z"
}

// now let's find prev / next of second document
{
    "id" : JUUID("98f1006e-6338-4fbb-8683-492c68c7ba5c"),
    "createdAt" : "2014-08-03T09:27:02.714Z"
}

// previous document
db.products.find({createdAt: {$lt: "2014-08-03T09:27:02.714Z"}}).sort({createdAt: -1}).limit(1)
// =>
{
    "id" : JUUID("8c574527-a160-4eec-99d3-7af8b0f99421"),
    "createdAt" : "2014-08-03T09:27:02.690Z"
}

// next document
db.products.find({createdAt: {$gt: "2014-08-03T09:27:02.714Z"}}).sort({createdAt: 1}).limit(1)
// =>
{
    "id" : JUUID("1fb4147d-8b5f-4033-839d-3e0011d229fc"),
    "createdAt" : "2014-08-03T09:27:02.740Z"
}

This is what I discovered so far. If you have any suggestions or ideas I'll be happy to discuss them with you :)

emmenko avatar Aug 03 '14 11:08 emmenko

@lauraluiz do we need that, how should it look like?

schleichardt avatar Feb 23 '16 09:02 schleichardt

I think we need to put a bit more of helpers related to pages. In the end, we have a "Paged..." class. What I use to handle pagination are:

private static long calculateTotalPages(final PagedResult<?> result, final int pageSize) {
    final Double totalPages = Math.ceil((float) result.getTotal() / pageSize);
    return totalPages.longValue();
}

hasPrev and hasNext are the negated aliases from isFirst and isLast. We can also put them to make the code more semantically correct.

The next and prev versions I wouldn't use in my case because I don't have the previous search request by the time I need them, just a page.

lauraluiz avatar Feb 23 '16 17:02 lauraluiz