From 38b934a9ef9dab89692d7253dcb332f4ce46f8f0 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 8 Dec 2016 14:51:00 +0000 Subject: core: Support pagination using page tokens from JSON MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on a patch by Milan Crha . This reworks how pagination is implemented so that multiple pagination mechanisms are supported explicitly, making the code a lot clearer. A lot of the new services use pageToken parameters, which we did not previously support — so this fixes support for pagination in the Google Tasks service, for example. This also means that we can drop the hacky pagination support from GDataDocumentsService. https://bugzilla.gnome.org/show_bug.cgi?id=775813 --- docs/reference/gdata-sections.txt | 1 + gdata/gdata-core.symbols | 1 + gdata/gdata-feed.c | 47 ++++- gdata/gdata-feed.h | 1 + gdata/gdata-private.h | 12 +- gdata/gdata-query.c | 201 +++++++++++++++------ gdata/gdata-service.c | 10 + gdata/services/calendar/gdata-calendar-query.c | 4 + gdata/services/contacts/gdata-contacts-query.c | 5 + gdata/services/documents/gdata-documents-query.c | 4 + gdata/services/documents/gdata-documents-service.c | 59 ------ gdata/services/freebase/gdata-freebase-query.c | 5 + gdata/services/picasaweb/gdata-picasaweb-query.c | 5 + gdata/services/tasks/gdata-tasks-query.c | 4 + gdata/services/youtube/gdata-youtube-query.c | 5 + 15 files changed, 245 insertions(+), 119 deletions(-) diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt index 441d67db..04b5e476 100644 --- a/docs/reference/gdata-sections.txt +++ b/docs/reference/gdata-sections.txt @@ -126,6 +126,7 @@ gdata_feed_get_rights gdata_feed_get_start_index gdata_feed_get_total_results gdata_feed_get_items_per_page +gdata_feed_get_next_page_token GDATA_FEED GDATA_FEED_CLASS diff --git a/gdata/gdata-core.symbols b/gdata/gdata-core.symbols index 7f5da8a5..e8c43777 100644 --- a/gdata/gdata-core.symbols +++ b/gdata/gdata-core.symbols @@ -45,6 +45,7 @@ gdata_feed_get_rights gdata_feed_get_items_per_page gdata_feed_get_start_index gdata_feed_get_total_results +gdata_feed_get_next_page_token gdata_service_get_type gdata_service_error_quark gdata_service_query diff --git a/gdata/gdata-feed.c b/gdata/gdata-feed.c index 14fe8a57..9085103c 100644 --- a/gdata/gdata-feed.c +++ b/gdata/gdata-feed.c @@ -78,6 +78,7 @@ struct _GDataFeedPrivate { guint start_index; guint total_results; gchar *rights; + gchar *next_page_token; }; enum { @@ -92,7 +93,8 @@ enum { PROP_ITEMS_PER_PAGE, PROP_START_INDEX, PROP_TOTAL_RESULTS, - PROP_RIGHTS + PROP_RIGHTS, + PROP_NEXT_PAGE_TOKEN, }; G_DEFINE_TYPE (GDataFeed, gdata_feed, GDATA_TYPE_PARSABLE) @@ -296,6 +298,22 @@ gdata_feed_class_init (GDataFeedClass *klass) "Total results", "The total number of results in the feed.", 0, 1000000, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + /** + * GDataFeed:next-page-token: + * + * The next page token for feeds. Pass this to + * gdata_query_set_page_token() to advance to the next page when + * querying APIs which use page tokens rather than page numbers or + * offsets. + * + * Since: UNRELEASED + */ + g_object_class_install_property (gobject_class, PROP_NEXT_PAGE_TOKEN, + g_param_spec_string ("next-page-token", + "Next page token", "The next page token for feeds.", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); } static void @@ -354,6 +372,7 @@ gdata_feed_finalize (GObject *object) g_free (priv->logo); g_free (priv->icon); g_free (priv->rights); + g_free (priv->next_page_token); /* Chain up to the parent class */ G_OBJECT_CLASS (gdata_feed_parent_class)->finalize (object); @@ -401,6 +420,9 @@ gdata_feed_get_property (GObject *object, guint property_id, GValue *value, GPar case PROP_TOTAL_RESULTS: g_value_set_uint (value, priv->total_results); break; + case PROP_NEXT_PAGE_TOKEN: + g_value_set_string (value, priv->next_page_token); + break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -643,6 +665,8 @@ parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GEr /* Ignore. */ } else if (g_strcmp0 (json_reader_get_member_name (reader), "etag") == 0) { GDATA_FEED (parsable)->priv->etag = g_strdup (json_reader_get_string_value (reader)); + } else if (g_strcmp0 (json_reader_get_member_name (reader), "nextPageToken") == 0) { + GDATA_FEED (parsable)->priv->next_page_token = g_strdup (json_reader_get_string_value (reader)); } else { return GDATA_PARSABLE_CLASS (gdata_feed_parent_class)->parse_json (parsable, reader, user_data, error); } @@ -1072,6 +1096,27 @@ gdata_feed_get_total_results (GDataFeed *self) return self->priv->total_results; } +/** + * gdata_feed_get_next_page_token: + * @self: a #GDataFeed + * + * Returns the next page token for a query result, or %NULL if not set. + * This is #GDataFeed:next-page-token. The page token might not be set if there + * is no next page, or if this service does not use token based paging (for + * example, if it uses page number or offset based paging instead). Most more + * recent services use token based paging. + * + * Return value: (nullable): the next page token + * + * Since: UNRELEASED + */ +const gchar * +gdata_feed_get_next_page_token (GDataFeed *self) +{ + g_return_val_if_fail (GDATA_IS_FEED (self), NULL); + return self->priv->next_page_token; +} + void _gdata_feed_add_entry (GDataFeed *self, GDataEntry *entry) { diff --git a/gdata/gdata-feed.h b/gdata/gdata-feed.h index 6a1e050a..7bd510b3 100644 --- a/gdata/gdata-feed.h +++ b/gdata/gdata-feed.h @@ -90,6 +90,7 @@ guint gdata_feed_get_items_per_page (GDataFeed *self) G_GNUC_PURE; guint gdata_feed_get_start_index (GDataFeed *self) G_GNUC_PURE; guint gdata_feed_get_total_results (GDataFeed *self) G_GNUC_PURE; const gchar *gdata_feed_get_icon (GDataFeed *self) G_GNUC_PURE; +const gchar *gdata_feed_get_next_page_token (GDataFeed *self) G_GNUC_PURE; G_END_DECLS diff --git a/gdata/gdata-private.h b/gdata/gdata-private.h index ecb4534e..4d65bdd7 100644 --- a/gdata/gdata-private.h +++ b/gdata/gdata-private.h @@ -71,13 +71,21 @@ G_GNUC_INTERNAL GDataSecureString _gdata_service_secure_strndup (const gchar *st G_GNUC_INTERNAL void _gdata_service_secure_strfree (GDataSecureString str); #include "gdata-query.h" +typedef enum { + GDATA_QUERY_PAGINATION_INDEXED, + GDATA_QUERY_PAGINATION_URIS, + GDATA_QUERY_PAGINATION_TOKENS, +} GDataQueryPaginationType; + G_GNUC_INTERNAL void _gdata_query_add_q_internal (GDataQuery *self, const gchar *q); G_GNUC_INTERNAL void _gdata_query_clear_q_internal (GDataQuery *self); +G_GNUC_INTERNAL void _gdata_query_clear_pagination (GDataQuery *self); +G_GNUC_INTERNAL void _gdata_query_set_pagination_type (GDataQuery *self, + GDataQueryPaginationType type); +G_GNUC_INTERNAL void _gdata_query_set_next_page_token (GDataQuery *self, const gchar *next_page_token); G_GNUC_INTERNAL void _gdata_query_set_next_uri (GDataQuery *self, const gchar *next_uri); -G_GNUC_INTERNAL void _gdata_query_set_next_uri_end (GDataQuery *self); G_GNUC_INTERNAL gboolean _gdata_query_is_finished (GDataQuery *self); G_GNUC_INTERNAL void _gdata_query_set_previous_uri (GDataQuery *self, const gchar *previous_uri); -G_GNUC_INTERNAL void _gdata_query_set_previous_uri_end (GDataQuery *self); #include "gdata-parsable.h" G_GNUC_INTERNAL GDataParsable *_gdata_parsable_new_from_xml (GType parsable_type, const gchar *xml, gint length, gpointer user_data, diff --git a/gdata/gdata-query.c b/gdata/gdata-query.c index e1f54468..ebddeac2 100644 --- a/gdata/gdata-query.c +++ b/gdata/gdata-query.c @@ -68,22 +68,37 @@ struct _GDataQueryPrivate { gboolean is_strict; guint max_results; - /* Pagination management. Supports three states: - * 1. (next_uri == NULL && !use_next_uri): - * Implement pagination by incrementing #GDataQuery:start-index - * internally with each call to gdata_query_next_page(). Stop - * when the returned #GDataFeed is empty. - * 2a. (next_uri != NULL && use_next_uri): - * Implement pagination with an explicit URI for the next page, - * which will be used when gdata_query_next_page() is called. - * 2b. (next_uri == NULL && use_next_uri): - * End of pagination using known URIs; return an empty - * #GDataFeed when gdata_query_next_page() is called. + /* Pagination management. The type of pagination is set as + * pagination_type, and should be set in the init() vfunc implementation + * of any class derived from GDataQuery. It defaults to + * %GDATA_QUERY_PAGINATION_INDEXED, which most subclasses will not want. + * + * The next_uri, previous_uri or next_page_token are set by + * #GDataService if a query returns a new #GDataFeed containing them. If + * the user then calls next_page() or previous_page(), use_next_page or + * use_previous_page are set as appopriate, and the next call to + * get_uri() will return a URI for the next or previous page. This might + * be next_uri, previous_uri, or a constructed URI which appends the + * next_page_token. + * + * Note that %GDATA_QUERY_PAGINATION_TOKENS does not support returning + * to the previous page. + * + * It is not invalid to have use_next_page set and to not have a + * next_uri for %GDATA_QUERY_PAGINATION_URIS; or to not have a + * next_page_token for %GDATA_QUERY_PAGINATION_TOKENS: this signifies + * that the current set of results are the last page. There are no + * further pages. Similarly for use_previous_page and a %NULL + * previous_page. */ + GDataQueryPaginationType pagination_type; + gchar *next_uri; gchar *previous_uri; - gboolean use_next_uri; - gboolean use_previous_uri; + gchar *next_page_token; + + gboolean use_next_page; + gboolean use_previous_page; gchar *etag; }; @@ -295,6 +310,8 @@ gdata_query_init (GDataQuery *self) self->priv->updated_max = -1; self->priv->published_min = -1; self->priv->published_max = -1; + + _gdata_query_set_pagination_type (self, GDATA_QUERY_PAGINATION_INDEXED); } static void @@ -309,6 +326,7 @@ gdata_query_finalize (GObject *object) g_free (priv->next_uri); g_free (priv->previous_uri); g_free (priv->etag); + g_free (priv->next_page_token); /* Chain up to the parent class */ G_OBJECT_CLASS (gdata_query_parent_class)->finalize (object); @@ -490,6 +508,13 @@ get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboo APPEND_SEP g_string_append_printf (query_uri, "max-results=%u", priv->max_results); } + + if (priv->pagination_type == GDATA_QUERY_PAGINATION_TOKENS && priv->use_next_page && + priv->next_page_token != NULL && *priv->next_page_token != '\0') { + APPEND_SEP + g_string_append (query_uri, "pageToken="); + g_string_append_uri_escaped (query_uri, priv->next_page_token, NULL, FALSE); + } } /** @@ -550,10 +575,12 @@ gdata_query_get_query_uri (GDataQuery *self, const gchar *feed_uri) g_return_val_if_fail (feed_uri != NULL, NULL); /* Check to see if we're paginating first */ - if (self->priv->use_next_uri == TRUE) - return g_strdup (self->priv->next_uri); - if (self->priv->use_previous_uri == TRUE) - return g_strdup (self->priv->previous_uri); + if (self->priv->pagination_type == GDATA_QUERY_PAGINATION_URIS) { + if (self->priv->use_next_page) + return g_strdup (self->priv->next_uri); + if (self->priv->use_previous_page) + return g_strdup (self->priv->previous_uri); + } klass = GDATA_QUERY_GET_CLASS (self); g_assert (klass->get_query_uri != NULL); @@ -1014,24 +1041,60 @@ gdata_query_set_etag (GDataQuery *self, const gchar *etag) } void -_gdata_query_set_next_uri (GDataQuery *self, const gchar *next_uri) +_gdata_query_clear_pagination (GDataQuery *self) { g_return_if_fail (GDATA_IS_QUERY (self)); - g_free (self->priv->next_uri); - self->priv->next_uri = g_strdup (next_uri); - self->priv->use_next_uri = FALSE; - self->priv->use_previous_uri = FALSE; + + switch (self->priv->pagination_type) { + case GDATA_QUERY_PAGINATION_INDEXED: + /* Nothing to do here: indexes can always be incremented. */ + break; + case GDATA_QUERY_PAGINATION_URIS: + g_clear_pointer (&self->priv->next_uri, g_free); + g_clear_pointer (&self->priv->previous_uri, g_free); + break; + case GDATA_QUERY_PAGINATION_TOKENS: + g_clear_pointer (&self->priv->next_page_token, g_free); + break; + default: + g_assert_not_reached (); + } + + self->priv->use_next_page = FALSE; + self->priv->use_previous_page = FALSE; } void -_gdata_query_set_next_uri_end (GDataQuery *self) +_gdata_query_set_pagination_type (GDataQuery *self, + GDataQueryPaginationType type) +{ + g_debug ("%s: Pagination type set to %u", G_STRFUNC, type); + + _gdata_query_clear_pagination (self); + self->priv->pagination_type = type; +} + +void +_gdata_query_set_next_page_token (GDataQuery *self, + const gchar *next_page_token) { g_return_if_fail (GDATA_IS_QUERY (self)); + g_return_if_fail (self->priv->pagination_type == + GDATA_QUERY_PAGINATION_TOKENS); + + g_free (self->priv->next_page_token); + self->priv->next_page_token = g_strdup (next_page_token); +} + +void +_gdata_query_set_next_uri (GDataQuery *self, const gchar *next_uri) +{ + g_return_if_fail (GDATA_IS_QUERY (self)); + g_return_if_fail (self->priv->pagination_type == + GDATA_QUERY_PAGINATION_URIS); g_free (self->priv->next_uri); - self->priv->next_uri = NULL; - self->priv->use_next_uri = TRUE; - self->priv->use_previous_uri = FALSE; + self->priv->next_uri = g_strdup (next_uri); } gboolean @@ -1039,28 +1102,27 @@ _gdata_query_is_finished (GDataQuery *self) { g_return_val_if_fail (GDATA_IS_QUERY (self), FALSE); - return (self->priv->next_uri == NULL && self->priv->use_next_uri); + switch (self->priv->pagination_type) { + case GDATA_QUERY_PAGINATION_INDEXED: + return FALSE; + case GDATA_QUERY_PAGINATION_URIS: + return (self->priv->next_uri == NULL && self->priv->use_next_page); + case GDATA_QUERY_PAGINATION_TOKENS: + return (self->priv->next_page_token == NULL && self->priv->use_next_page); + default: + g_assert_not_reached (); + } } void _gdata_query_set_previous_uri (GDataQuery *self, const gchar *previous_uri) { g_return_if_fail (GDATA_IS_QUERY (self)); - g_free (self->priv->previous_uri); - self->priv->previous_uri = g_strdup (previous_uri); - self->priv->use_next_uri = FALSE; - self->priv->use_previous_uri = FALSE; -} - -void -_gdata_query_set_previous_uri_end (GDataQuery *self) -{ - g_return_if_fail (GDATA_IS_QUERY (self)); + g_return_if_fail (self->priv->pagination_type == + GDATA_QUERY_PAGINATION_URIS); g_free (self->priv->previous_uri); - self->priv->previous_uri = NULL; - self->priv->use_next_uri = TRUE; - self->priv->use_previous_uri = FALSE; + self->priv->previous_uri = g_strdup (previous_uri); } /** @@ -1082,13 +1144,19 @@ gdata_query_next_page (GDataQuery *self) g_return_if_fail (GDATA_IS_QUERY (self)); - if (priv->next_uri != NULL) { - priv->use_next_uri = TRUE; - priv->use_previous_uri = FALSE; - } else { + switch (self->priv->pagination_type) { + case GDATA_QUERY_PAGINATION_INDEXED: if (priv->start_index == 0) priv->start_index++; priv->start_index += priv->max_results; + break; + case GDATA_QUERY_PAGINATION_URIS: + case GDATA_QUERY_PAGINATION_TOKENS: + priv->use_next_page = TRUE; + priv->use_previous_page = FALSE; + break; + default: + g_assert_not_reached (); } /* Our current ETag will no longer be relevant */ @@ -1110,23 +1178,42 @@ gboolean gdata_query_previous_page (GDataQuery *self) { GDataQueryPrivate *priv = self->priv; + gboolean retval; g_return_val_if_fail (GDATA_IS_QUERY (self), FALSE); - if (priv->previous_uri != NULL) { - priv->use_previous_uri = TRUE; - priv->use_next_uri = FALSE; - } else if (priv->start_index <= priv->max_results || - (priv->previous_uri == NULL && priv->use_previous_uri)) { - return FALSE; - } else { - priv->start_index -= priv->max_results; - if (priv->start_index == 1) - priv->start_index--; + switch (self->priv->pagination_type) { + case GDATA_QUERY_PAGINATION_INDEXED: + if (priv->start_index <= priv->max_results) { + retval = FALSE; + } else { + priv->start_index -= priv->max_results; + if (priv->start_index == 1) + priv->start_index--; + retval = TRUE; + } + break; + case GDATA_QUERY_PAGINATION_URIS: + if (priv->previous_uri != NULL) { + priv->use_next_page = FALSE; + priv->use_previous_page = TRUE; + retval = TRUE; + } else { + retval = FALSE; + } + break; + case GDATA_QUERY_PAGINATION_TOKENS: + /* There are no previous page tokens, unfortunately. */ + retval = FALSE; + break; + default: + g_assert_not_reached (); } - /* Our current ETag will no longer be relevant */ - gdata_query_set_etag (self, NULL); + if (retval) { + /* Our current ETag will no longer be relevant */ + gdata_query_set_etag (self, NULL); + } - return TRUE; + return retval; } diff --git a/gdata/gdata-service.c b/gdata/gdata-service.c index 1e6feebe..dfc46238 100644 --- a/gdata/gdata-service.c +++ b/gdata/gdata-service.c @@ -1035,13 +1035,23 @@ real_parse_feed (GDataService *self, /* Update the query with the next and previous URIs from the feed */ if (query != NULL && feed != NULL) { GDataLink *_link; + const gchar *token; + _gdata_query_clear_pagination (query); + + /* Atom-style next and previous page links. */ _link = gdata_feed_look_up_link (feed, "http://www.iana.org/assignments/relation/next"); if (_link != NULL) _gdata_query_set_next_uri (query, gdata_link_get_uri (_link)); _link = gdata_feed_look_up_link (feed, "http://www.iana.org/assignments/relation/previous"); if (_link != NULL) _gdata_query_set_previous_uri (query, gdata_link_get_uri (_link)); + + /* JSON-style next page token. (There is no previous page + * token.) */ + token = gdata_feed_get_next_page_token (feed); + if (token != NULL) + _gdata_query_set_next_page_token (query, token); } return feed; diff --git a/gdata/services/calendar/gdata-calendar-query.c b/gdata/services/calendar/gdata-calendar-query.c index 89597ae0..ea16dc8a 100644 --- a/gdata/services/calendar/gdata-calendar-query.c +++ b/gdata/services/calendar/gdata-calendar-query.c @@ -85,6 +85,7 @@ #include "gdata-calendar-query.h" #include "gdata-query.h" #include "gdata-parser.h" +#include "gdata-private.h" static void gdata_calendar_query_finalize (GObject *object); static void gdata_calendar_query_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); @@ -287,6 +288,9 @@ gdata_calendar_query_init (GDataCalendarQuery *self) self->priv->recurrence_expansion_end = -1; self->priv->start_min = -1; self->priv->start_max = -1; + + _gdata_query_set_pagination_type (GDATA_QUERY (self), + GDATA_QUERY_PAGINATION_TOKENS); } static void diff --git a/gdata/services/contacts/gdata-contacts-query.c b/gdata/services/contacts/gdata-contacts-query.c index 23f40bbf..69c8b0b5 100644 --- a/gdata/services/contacts/gdata-contacts-query.c +++ b/gdata/services/contacts/gdata-contacts-query.c @@ -84,6 +84,7 @@ #include "gdata-contacts-query.h" #include "gdata-query.h" +#include "gdata-private.h" static void gdata_contacts_query_finalize (GObject *object); static void gdata_contacts_query_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); @@ -180,6 +181,10 @@ static void gdata_contacts_query_init (GDataContactsQuery *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_CONTACTS_QUERY, GDataContactsQueryPrivate); + + /* https://developers.google.com/google-apps/contacts/v3/reference#contacts-query-parameters-reference */ + _gdata_query_set_pagination_type (GDATA_QUERY (self), + GDATA_QUERY_PAGINATION_INDEXED); } static void diff --git a/gdata/services/documents/gdata-documents-query.c b/gdata/services/documents/gdata-documents-query.c index 634e7a2e..6070c1b0 100644 --- a/gdata/services/documents/gdata-documents-query.c +++ b/gdata/services/documents/gdata-documents-query.c @@ -208,6 +208,10 @@ static void gdata_documents_query_init (GDataDocumentsQuery *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_DOCUMENTS_QUERY, GDataDocumentsQueryPrivate); + + /* https://developers.google.com/drive/v3/reference/files/list#q */ + _gdata_query_set_pagination_type (GDATA_QUERY (self), + GDATA_QUERY_PAGINATION_TOKENS); } static void diff --git a/gdata/services/documents/gdata-documents-service.c b/gdata/services/documents/gdata-documents-service.c index 0de0aec6..07c4062c 100644 --- a/gdata/services/documents/gdata-documents-service.c +++ b/gdata/services/documents/gdata-documents-service.c @@ -270,17 +270,6 @@ gdata_documents_service_error_quark (void) static void append_query_headers (GDataService *self, GDataAuthorizationDomain *domain, SoupMessage *message); static GList *get_authorization_domains (void); -static GDataFeed * -parse_feed (GDataService *self, - GDataAuthorizationDomain *domain, - GDataQuery *query, - GType entry_type, - SoupMessage *message, - GCancellable *cancellable, - GDataQueryProgressCallback progress_callback, - gpointer progress_user_data, - GError **error); - static gchar *_get_upload_uri_for_query_and_folder (GDataDocumentsUploadQuery *query, GDataDocumentsFolder *folder) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC; @@ -296,7 +285,6 @@ gdata_documents_service_class_init (GDataDocumentsServiceClass *klass) service_class->append_query_headers = append_query_headers; service_class->get_authorization_domains = get_authorization_domains; - service_class->parse_feed = parse_feed; service_class->api_version = "3"; } @@ -361,53 +349,6 @@ get_authorization_domains (void) return authorization_domains; } -static GDataFeed * -parse_feed (GDataService *self, - GDataAuthorizationDomain *domain, - GDataQuery *query, - GType entry_type, - SoupMessage *message, - GCancellable *cancellable, - GDataQueryProgressCallback progress_callback, - gpointer progress_user_data, - GError **error) -{ - GDataServiceClass *klass; /* unowned */ - GDataFeed *feed = NULL; /* owned */ - - klass = GDATA_SERVICE_CLASS (gdata_documents_service_parent_class); - - /* Parse the feed. */ - feed = klass->parse_feed (self, domain, query, entry_type, message, - cancellable, progress_callback, - progress_user_data, error); - - /* Update the query with the next and previous URIs from the feed. If - * they are not present, we are on the first or final page of the - * feed. (This behaviour is specific to Google Docs.) */ - if (query != NULL && feed != NULL) { - GDataLink *_link; - - _link = gdata_feed_look_up_link (feed, "http://www.iana.org/assignments/relation/next"); - - if (_link != NULL) { - _gdata_query_set_next_uri (query, gdata_link_get_uri (_link)); - } else { - _gdata_query_set_next_uri_end (query); - } - - _link = gdata_feed_look_up_link (feed, "http://www.iana.org/assignments/relation/previous"); - - if (_link != NULL) { - _gdata_query_set_previous_uri (query, gdata_link_get_uri (_link)); - } else { - _gdata_query_set_previous_uri_end (query); - } - } - - return feed; -} - /** * gdata_documents_service_new: * @authorizer: (allow-none): a #GDataAuthorizer to authorize the service's requests, or %NULL diff --git a/gdata/services/freebase/gdata-freebase-query.c b/gdata/services/freebase/gdata-freebase-query.c index 8e66de17..19f0b10b 100644 --- a/gdata/services/freebase/gdata-freebase-query.c +++ b/gdata/services/freebase/gdata-freebase-query.c @@ -42,6 +42,7 @@ #include "gdata-freebase-query.h" #include "gdata-query.h" #include "gdata-parser.h" +#include "gdata-private.h" static void gdata_freebase_query_finalize (GObject *self); static void gdata_freebase_query_set_property (GObject *self, guint prop_id, const GValue *value, GParamSpec *pspec); @@ -94,6 +95,10 @@ static void gdata_freebase_query_init (GDataFreebaseQuery *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_FREEBASE_QUERY, GDataFreebaseQueryPrivate); + + /* https://developers.google.com/freebase/v1/search#cursor */ + _gdata_query_set_pagination_type (GDATA_QUERY (self), + GDATA_QUERY_PAGINATION_INDEXED); } static void diff --git a/gdata/services/picasaweb/gdata-picasaweb-query.c b/gdata/services/picasaweb/gdata-picasaweb-query.c index d459748f..57851575 100644 --- a/gdata/services/picasaweb/gdata-picasaweb-query.c +++ b/gdata/services/picasaweb/gdata-picasaweb-query.c @@ -41,6 +41,7 @@ #include "gdata-picasaweb-query.h" #include "gdata-query.h" #include "gdata-picasaweb-enums.h" +#include "gdata-private.h" static void gdata_picasaweb_query_finalize (GObject *object); static void gdata_picasaweb_query_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); @@ -166,6 +167,10 @@ static void gdata_picasaweb_query_init (GDataPicasaWebQuery *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_PICASAWEB_QUERY, GDataPicasaWebQueryPrivate); + + /* https://developers.google.com/picasa-web/docs/3.0/reference#Parameters */ + _gdata_query_set_pagination_type (GDATA_QUERY (self), + GDATA_QUERY_PAGINATION_INDEXED); } static void diff --git a/gdata/services/tasks/gdata-tasks-query.c b/gdata/services/tasks/gdata-tasks-query.c index 9e6dbd95..f5666055 100644 --- a/gdata/services/tasks/gdata-tasks-query.c +++ b/gdata/services/tasks/gdata-tasks-query.c @@ -40,6 +40,7 @@ #include "gdata-tasks-query.h" #include "gdata-query.h" #include "gdata-parser.h" +#include "gdata-private.h" static void gdata_tasks_query_finalize (GObject *object); static void gdata_tasks_query_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); @@ -185,6 +186,9 @@ gdata_tasks_query_init (GDataTasksQuery *self) self->priv->completed_max = -1; self->priv->due_min = -1; self->priv->due_max = -1; + + _gdata_query_set_pagination_type (GDATA_QUERY (self), + GDATA_QUERY_PAGINATION_TOKENS); } static void diff --git a/gdata/services/youtube/gdata-youtube-query.c b/gdata/services/youtube/gdata-youtube-query.c index b15d01eb..99ae9961 100644 --- a/gdata/services/youtube/gdata-youtube-query.c +++ b/gdata/services/youtube/gdata-youtube-query.c @@ -45,6 +45,7 @@ #include "gdata-youtube-query.h" #include "gdata-query.h" #include "gdata-youtube-content.h" +#include "gdata-private.h" static void gdata_youtube_query_finalize (GObject *object); static void gdata_youtube_query_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); @@ -354,6 +355,10 @@ gdata_youtube_query_init (GDataYouTubeQuery *self) self->priv->latitude = G_MAXDOUBLE; self->priv->longitude = G_MAXDOUBLE; + + /* https://developers.google.com/youtube/v3/docs/search/list#pageToken */ + _gdata_query_set_pagination_type (GDATA_QUERY (self), + GDATA_QUERY_PAGINATION_TOKENS); } static void -- cgit v1.2.1