Skip to content

Commit f1e0af9

Browse files
authored
Merge pull request #73 from 5am-code/feature/better-pagination-handling
Feature/better pagination handling: add: better pagination handling
2 parents 461b1dd + 2451387 commit f1e0af9

File tree

6 files changed

+449
-2
lines changed

6 files changed

+449
-2
lines changed

src/Endpoints/Database.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace FiveamCode\LaravelNotionApi\Endpoints;
44

5+
use FiveamCode\LaravelNotionApi\Entities\Collections\EntityCollection;
56
use FiveamCode\LaravelNotionApi\Entities\Collections\PageCollection;
67
use FiveamCode\LaravelNotionApi\Notion;
78
use FiveamCode\LaravelNotionApi\Query\Filters\Filter;
@@ -66,7 +67,7 @@ public function query(): PageCollection
6667
} // TODO Compound filters!
6768

6869
if ($this->startCursor !== null) {
69-
$postData['start_cursor'] = $this->startCursor;
70+
$postData['start_cursor'] = $this->startCursor->__toString();
7071
}
7172

7273
if ($this->pageSize !== null) {
@@ -104,4 +105,15 @@ public function sortBy(Collection $sorts): Database
104105

105106
return $this;
106107
}
108+
109+
/**
110+
* @param EntityCollection $entityCollection
111+
* @return $this
112+
*/
113+
public function offsetByResponse(EntityCollection $entityCollection): Database
114+
{
115+
$this->offset($entityCollection->nextCursor());
116+
117+
return $this;
118+
}
107119
}

src/Entities/Collections/EntityCollection.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use FiveamCode\LaravelNotionApi\Entities\Page;
88
use FiveamCode\LaravelNotionApi\Exceptions\HandlingException;
99
use FiveamCode\LaravelNotionApi\Exceptions\NotionException;
10+
use FiveamCode\LaravelNotionApi\Query\StartCursor;
1011
use Illuminate\Support\Arr;
1112
use Illuminate\Support\Collection;
1213

@@ -25,6 +26,16 @@ class EntityCollection
2526
*/
2627
protected array $rawResults = [];
2728

29+
/**
30+
* @var bool
31+
*/
32+
protected bool $hasMore = false;
33+
34+
/**
35+
* @var string
36+
*/
37+
protected ?string $nextCursor = null;
38+
2839
/**
2940
* @var Collection
3041
*/
@@ -96,13 +107,24 @@ protected function collectChildren(): void
96107
protected function fillFromRaw()
97108
{
98109
$this->fillResult();
110+
$this->fillCursorInformation();
99111
}
100112

101113
protected function fillResult()
102114
{
103115
$this->rawResults = $this->responseData['results'];
104116
}
105117

118+
protected function fillCursorInformation()
119+
{
120+
if (Arr::exists($this->responseData, 'has_more')) {
121+
$this->hasMore = $this->responseData['has_more'];
122+
}
123+
if (Arr::exists($this->responseData, 'next_cursor')) {
124+
$this->nextCursor = $this->responseData['next_cursor'];
125+
}
126+
}
127+
106128
/**
107129
* @return array
108130
*/
@@ -111,6 +133,14 @@ public function getRawResponse(): array
111133
return $this->responseData;
112134
}
113135

136+
/**
137+
* @return string
138+
*/
139+
public function getRawNextCursor(): ?string
140+
{
141+
return $this->nextCursor;
142+
}
143+
114144
/**
115145
* @return Collection
116146
*/
@@ -128,4 +158,25 @@ public function asJson(): string
128158
return $item->toArray();
129159
});
130160
}
161+
162+
/**
163+
* @return bool
164+
*/
165+
public function hasMoreEntries(): bool
166+
{
167+
return $this->hasMore;
168+
}
169+
170+
/**
171+
* @return StartCursor
172+
*/
173+
public function nextCursor(): ?StartCursor
174+
{
175+
$rawNextCursor = $this->getRawNextCursor();
176+
if ($rawNextCursor === null) {
177+
return null;
178+
}
179+
180+
return new StartCursor($rawNextCursor);
181+
}
131182
}

src/Query/StartCursor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function __construct(string $cursor)
2222
$this->cursor = $cursor;
2323
}
2424

25-
public function __toString()
25+
public function __toString(): string
2626
{
2727
return $this->cursor;
2828
}

tests/EndpointDatabaseTest.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use FiveamCode\LaravelNotionApi\Exceptions\NotionException;
99
use FiveamCode\LaravelNotionApi\Query\Filters\Filter;
1010
use FiveamCode\LaravelNotionApi\Query\Sorting;
11+
use FiveamCode\LaravelNotionApi\Query\StartCursor;
1112
use Illuminate\Support\Collection;
1213
use Illuminate\Support\Facades\Http;
1314
use Notion;
@@ -158,6 +159,63 @@ public function it_throws_a_notion_exception_bad_request()
158159
Notion::database('8284f3ff77e24d4a939d19459e4d6bdc')->query();
159160
}
160161

162+
/** @test */
163+
public function it_queries_a_database_with_and_without_offset_and_processes_result()
164+
{
165+
// success /v1/databases/DATABASE_DOES_EXIST/query
166+
Http::fake([
167+
'https://api.notion.com/v1/databases/8284f3ff77e24d4a939d19459e4d6bdc/query*' => Http::sequence()
168+
->push(
169+
json_decode(file_get_contents('tests/stubs/endpoints/databases/response_query_offset_start_200.json'), true),
170+
200,
171+
['Headers']
172+
)
173+
->push(
174+
json_decode(file_get_contents('tests/stubs/endpoints/databases/response_query_offset_end_200.json'), true),
175+
200,
176+
['Headers']
177+
),
178+
]);
179+
180+
$result = Notion::database('8284f3ff77e24d4a939d19459e4d6bdc')
181+
->query();
182+
183+
//check instance and offset
184+
$this->assertInstanceOf(PageCollection::class, $result);
185+
$this->assertEquals(true, $result->hasMoreEntries());
186+
$this->assertInstanceOf(StartCursor::class, $result->nextCursor());
187+
$this->assertEquals('1500b7c7-329f-4854-8912-4c6972a8743e', $result->nextCursor());
188+
$this->assertEquals('1500b7c7-329f-4854-8912-4c6972a8743e', $result->getRawNextCursor());
189+
190+
$resultCollection = $result->asCollection();
191+
192+
$this->assertIsIterable($resultCollection);
193+
$this->assertContainsOnly(Page::class, $resultCollection);
194+
195+
// check page object
196+
$page = $resultCollection->first();
197+
$this->assertEquals('Betty Holberton', $page->getTitle());
198+
199+
$resultWithOffset = Notion::database('8284f3ff77e24d4a939d19459e4d6bdc')
200+
->offsetByResponse($result)
201+
->query();
202+
203+
// check instance and offset
204+
$this->assertInstanceOf(PageCollection::class, $resultWithOffset);
205+
$this->assertEquals(false, $resultWithOffset->hasMoreEntries());
206+
$this->assertEquals(null, $resultWithOffset->nextCursor());
207+
$this->assertEquals(null, $resultWithOffset->getRawNextCursor());
208+
209+
$resultWithOffsetCollection = $resultWithOffset->asCollection();
210+
211+
$this->assertIsIterable($resultWithOffsetCollection);
212+
$this->assertContainsOnly(Page::class, $resultWithOffsetCollection);
213+
214+
// check page object
215+
$page = $resultWithOffsetCollection->first();
216+
$this->assertEquals('Betty Holberton', $page->getTitle());
217+
}
218+
161219
/**
162220
* @test
163221
* ! edge-case
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
{
2+
"object": "list",
3+
"results": [
4+
{
5+
"object": "page",
6+
"id": "1500b7c7-329f-4854-8912-4c6972a8743e",
7+
"created_time": "2021-05-24T11:03:00.000Z",
8+
"last_edited_time": "2021-05-24T11:13:00.000Z",
9+
"parent": {
10+
"type": "database_id",
11+
"database_id": "8284f3ff-77e2-4d4a-939d-19459e4d6bdc"
12+
},
13+
"archived": false,
14+
"properties": {
15+
"Birth year": {
16+
"id": "_f<<",
17+
"type": "rich_text",
18+
"rich_text": [
19+
{
20+
"type": "text",
21+
"text": {
22+
"content": "1917",
23+
"link": null
24+
},
25+
"annotations": {
26+
"bold": false,
27+
"italic": false,
28+
"strikethrough": false,
29+
"underline": false,
30+
"code": false,
31+
"color": "default"
32+
},
33+
"plain_text": "1917",
34+
"href": null
35+
}
36+
]
37+
},
38+
"Known for": {
39+
"id": "aUmo",
40+
"type": "multi_select",
41+
"multi_select": [
42+
{
43+
"id": "f55ee1a3-e67f-4793-ba3f-5dac02938a5f",
44+
"name": "ENIAC",
45+
"color": "purple"
46+
},
47+
{
48+
"id": "2016de6e-5325-4549-8e1a-60ee7570382a",
49+
"name": "UNIVAC",
50+
"color": "default"
51+
},
52+
{
53+
"id": "55c46053-f87e-40e9-8070-6c398939fed6",
54+
"name": "Breakpoints",
55+
"color": "red"
56+
}
57+
]
58+
},
59+
"Name": {
60+
"id": "title",
61+
"type": "title",
62+
"title": [
63+
{
64+
"type": "text",
65+
"text": {
66+
"content": "Betty Holberton",
67+
"link": null
68+
},
69+
"annotations": {
70+
"bold": false,
71+
"italic": false,
72+
"strikethrough": false,
73+
"underline": false,
74+
"code": false,
75+
"color": "default"
76+
},
77+
"plain_text": "Betty Holberton",
78+
"href": null
79+
}
80+
]
81+
}
82+
}
83+
},
84+
{
85+
"object": "page",
86+
"id": "ab2a7a85-08a1-4dfc-be89-0e30aeffc0f6",
87+
"created_time": "2021-05-24T11:03:02.464Z",
88+
"last_edited_time": "2021-05-24T11:12:00.000Z",
89+
"parent": {
90+
"type": "database_id",
91+
"database_id": "8284f3ff-77e2-4d4a-939d-19459e4d6bdc"
92+
},
93+
"archived": false,
94+
"properties": {
95+
"Birth year": {
96+
"id": "_f<<",
97+
"type": "rich_text",
98+
"rich_text": [
99+
{
100+
"type": "text",
101+
"text": {
102+
"content": "1906",
103+
"link": null
104+
},
105+
"annotations": {
106+
"bold": false,
107+
"italic": false,
108+
"strikethrough": false,
109+
"underline": false,
110+
"code": false,
111+
"color": "default"
112+
},
113+
"plain_text": "1906",
114+
"href": null
115+
}
116+
]
117+
},
118+
"Known for": {
119+
"id": "aUmo",
120+
"type": "multi_select",
121+
"multi_select": [
122+
{
123+
"id": "1ada9715-0139-4c1c-b1af-9d8d2fe80ea2",
124+
"name": "COBOL",
125+
"color": "orange"
126+
},
127+
{
128+
"id": "2016de6e-5325-4549-8e1a-60ee7570382a",
129+
"name": "UNIVAC",
130+
"color": "default"
131+
}
132+
]
133+
},
134+
"Name": {
135+
"id": "title",
136+
"type": "title",
137+
"title": [
138+
{
139+
"type": "text",
140+
"text": {
141+
"content": "Grace Hopper",
142+
"link": null
143+
},
144+
"annotations": {
145+
"bold": false,
146+
"italic": false,
147+
"strikethrough": false,
148+
"underline": false,
149+
"code": false,
150+
"color": "default"
151+
},
152+
"plain_text": "Grace Hopper",
153+
"href": null
154+
}
155+
]
156+
}
157+
}
158+
}
159+
],
160+
"next_cursor": null,
161+
"has_more": false
162+
}
163+

0 commit comments

Comments
 (0)