@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String source = req.getParameter("source"); ImagesService imagesService = ImagesServiceFactory.getImagesService(); DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); List<Filter> filters = new ArrayList<Filter>(); Query query = new Query(GAEFeedRepository.FEED_ITEM_KIND); filters.add(new Query.FilterPredicate("source", FilterOperator.EQUAL, source)); filters.add(new Query.FilterPredicate("img1A", FilterOperator.EQUAL, 1)); filters.add(new Query.FilterPredicate("img2A", FilterOperator.EQUAL, 1)); query.setFilter(CompositeFilterOperator.and(filters)); query.addSort("publishedDate", SortDirection.DESCENDING); PreparedQuery pq = datastore.prepare(query); int pageSize = 30; resp.setContentType("text/html"); resp.getWriter().println(" <ul>"); FetchOptions fetchOptions = FetchOptions.Builder.withLimit(pageSize); String startCursor = req.getParameter("cursor"); // If this servlet is passed a cursor parameter, let's use it if (startCursor != null) { fetchOptions.startCursor(Cursor.fromWebSafeString(startCursor)); } QueryResultList<Entity> results = pq.asQueryResultList(fetchOptions); for (Entity entity : results) { resp.getWriter() .println( "<li>" + entity.getProperty("imageLink") + " / " + imagesService.getServingUrl( ServingUrlOptions.Builder.withBlobKey((BlobKey) entity.getProperty("img2"))) + " / <img height=40 width=40 src=\"" + imagesService.getServingUrl( ServingUrlOptions.Builder.withBlobKey((BlobKey) entity.getProperty("img2"))) + "\" />"); } resp.getWriter().println("</li> </entity></ul> "); String cursor = results.getCursor().toWebSafeString(); // Assuming this servlet lives at '/people' resp.getWriter() .println( "<a href=\"/p8admin/ListFeedItems?cursor=" + cursor + "&source=" + source + "\">Next page</a>"); }
/** * This method lists all the entities inserted in datastore. It uses HTTP GET method and paging * support. * * @return A CollectionResponse class containing the list of all entities persisted and a cursor * to the next page. * @throws UnauthorizedException */ @ApiMethod( name = "findAll", scopes = {Config.EMAIL_SCOPE}, clientIds = {Config.CHROME_CLIENT_ID, Config.WEB_CLIENT_ID, Config.API_EXPLORER_CLIENT_ID}) public CollectionResponse<ServiceResponse> findAll( @Named("_name") String _name, @Nullable @Named("cursor") String cursorString, @Nullable @Named("limit") Integer limit, User user) throws UnauthorizedException { if (user == null) { throw new UnauthorizedException("UnauthorizedException # User is Null."); } DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); if (limit == null) { limit = 10; } FetchOptions fetchOptions = FetchOptions.Builder.withLimit(limit); if (cursorString != null) { fetchOptions.startCursor(Cursor.fromWebSafeString(cursorString)); } Query q = new Query(_name); q.addSort("_updatedAt", SortDirection.DESCENDING); PreparedQuery pq = datastore.prepare(q); QueryResultList<Entity> results = pq.asQueryResultList(fetchOptions); List<ServiceResponse> responses = new ArrayList<ServiceResponse>(); ServiceResponse res = null; for (Entity entity : results) { res = new ServiceResponse(); // TODO add properties from entity to service response res.set_id(entity.getKey().getId()); res.set_createdAt((Date) entity.getProperty(_createdAt)); res.set_createdBy((String) entity.getProperty(_createdBy)); res.set_upatedAt((Date) entity.getProperty(_updatedAt)); res.set_updatedBy((String) entity.getProperty(_updatedBy)); res.set_status((String) entity.getProperty(_status)); Text dataText = (Text) entity.getProperty(data); res.setData(dataText.getValue()); responses.add(res); } cursorString = results.getCursor().toWebSafeString(); return CollectionResponse.<ServiceResponse>builder() .setItems(responses) .setNextPageToken(cursorString) .build(); }
/* (non-Javadoc) * @see com.googlecode.objectify.Query#getKey() */ @Override public Key<T> getKey() { FetchOptions opts = FetchOptions.Builder.withLimit(1); if (this.offset > 0) opts = opts.offset(this.offset); Iterator<Entity> it = this.prepareKeysOnly().asIterator(opts); if (it.hasNext()) { Entity ent = it.next(); return this.factory.rawKeyToTypedKey(ent.getKey()); } else { return null; } }
/** * @return a set of fetch options for the current limit and offset, or null if there is no limit * or offset. */ private FetchOptions fetchOptions() { // The FetchOptions builder interface is really, really awful if (this.cursor != null) { FetchOptions opts = FetchOptions.Builder.withCursor(this.cursor); if (this.limit != 0) opts = opts.limit(this.limit); if (this.offset != 0) opts = opts.offset(this.offset); return opts; } else if (this.limit != 0) { FetchOptions opts = FetchOptions.Builder.withLimit(this.limit); if (this.offset != 0) opts = opts.offset(this.offset); return opts; } else if (this.offset != 0) { FetchOptions opts = FetchOptions.Builder.withOffset(this.offset); return opts; } else { return null; } }
/* (non-Javadoc) * @see com.googlecode.objectify.Query#get() */ @Override public T get() { // The underlying datastore is basically doing this for PreparedQuery.asSingleEntity(), // so let's do it ourselves and integrate offset() FetchOptions opts = FetchOptions.Builder.withLimit(1); if (this.offset > 0) opts = opts.offset(this.offset); if (this.cursor != null) opts = opts.cursor(this.cursor); Iterator<Entity> it = this.prepare().asIterator(opts); if (it.hasNext()) { Entity ent = it.next(); EntityMetadata<T> metadata = this.factory.getMetadata(ent.getKey()); return metadata.toObject(ent); } else { return null; } }
/** * @return a set of fetch options for the current limit, offset, and cursors, based on the default * fetch options. There will always be options even if default. */ private FetchOptions fetchOptions() { FetchOptions opts = FetchOptions.Builder.withDefaults(); if (this.startAt != null) opts = opts.startCursor(this.startAt); if (this.endAt != null) opts = opts.endCursor(this.endAt); if (this.limit != 0) opts = opts.limit(this.limit); if (this.offset != 0) opts = opts.offset(this.offset); if (this.chunk == null) opts = opts.chunkSize(DEFAULT_CHUNK_SIZE); else opts = opts.chunkSize(this.chunk); return opts; }
/** * Tests pagination of datastore entities. Verifies forward and backward paging returns entities * in the exact same order, even with duplicate values. * * @throws Exception */ public void test() throws Exception { // Initialize some test entities. final List<Entity> entities = initializeTestData(); // Add the entities to the datastore. DatastoreServiceFactory.getDatastoreService().put(entities); // Create a query to get the people, sorted by their initials. Query q = new Query(KIND); q.addSort(PROPERTY_NAME, SortDirection.ASCENDING); // This is to guarantee the order of duplicate initials. This is not // necessary if you are not concerned with the order of the duplicates. q.addSort(KEY, SortDirection.ASCENDING); // Fetch with a page size of 30 people. final FetchOptions options = FetchOptions.Builder.withDefaults(); options.limit(30); // Get first page. final Page page1 = getPage(q, options); System.out.println("Page 1"); System.out.println(page1); // Get the next page by setting the cursor to the "next" cursor // from the current page. options.startCursor(page1.next); final Page page2 = getPage(q, options); System.out.println("Page 2"); System.out.println(page2); // Make sure the next page starts after the previous page. assertTrue(page1.last().compareTo(page2.first()) < 0); // Get the next page by setting the cursor to the "next" cursor // from the current page. options.startCursor(page2.next); final Page page3 = getPage(q, options); System.out.println("Page 3"); System.out.println(page3); // Make sure the next page starts after the previous page. assertTrue(page1.last().compareTo(page2.first()) < 0); // For paging backward, create the same query in the reverse order. // Of course, each page will create a new query according to the // page direction desired. q = new Query(KIND); q.addSort(PROPERTY_NAME, SortDirection.DESCENDING); q.addSort(KEY, SortDirection.DESCENDING); // Get the previous page by setting the cursor to the "previous" // cursor from the current page. options.startCursor(page3.previous); final Page page2a = getPage(q, options); System.out.println("Page 2a"); // As the page will be returned in the reverse order because the // query is reversed, reverse the page for comparison with the // original. final Page reverse2a = page2a.reverse(); System.out.println(reverse2a); // Make sure this page 2 is exactly like the original. assertEquals(page2, reverse2a); // Get the previous page by setting the cursor to the "previous" // cursor from the current page. options.startCursor(page2a.next); final Page page1a = getPage(q, options); System.out.println("Page 1a"); // As the page will be returned in the reverse order because the // query is reversed, reverse the page for comparison with the // original. final Page reverse1a = page1a.reverse(); System.out.println(reverse1a); // Make sure this page 1 is exactly like the original. assertEquals(page1, reverse1a); }