Skip to content

Commit ffb1593

Browse files
Jonas Saabelclaude
andcommitted
docs: update property access patterns and add file uploads notebook
- Update notebooks 02 and 03 to use recommended extension function pattern for property access (getTitleAsPlainText, getSelectPropertyName, etc.) - Add comprehensive file uploads notebook (07-file-uploads.ipynb) with examples for uploading files, external imports, and media blocks - Update docs/pages.md with all three property access patterns and recommendations - Update docs/data-sources.md and docs/pagination.md to show extension functions - Update README.md to reference new notebook 07 and increase example count to 55+ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent a39f8db commit ffb1593

File tree

7 files changed

+397
-148
lines changed

7 files changed

+397
-148
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ See [docs/databases.md](docs/databases.md) and [docs/data-sources.md](docs/data-
128128
| **Search** | ✅ Complete | [docs/search.md](docs/search.md) |
129129
| **Users** | ✅ Complete | [docs/users.md](docs/users.md) |
130130
| **Comments** | ✅ Complete | [docs/comments.md](docs/comments.md) |
131-
| **File Uploads** | ✅ Complete | Integrated with blocks/pages |
131+
| **File Uploads** | ✅ Complete | [docs/file-uploads.md](docs/file-uploads.md) |
132132

133133
### Feature Highlights
134134

@@ -144,7 +144,7 @@ See [docs/databases.md](docs/databases.md) and [docs/data-sources.md](docs/data-
144144
## Documentation
145145

146146
- **[Quick Start Guide](QUICKSTART.md)** - Get up and running in 5 minutes
147-
- **[Kotlin Notebooks](notebooks/)** - Interactive Jupyter notebooks with 50+ examples (recommended for learning)
147+
- **[Kotlin Notebooks](notebooks/)** - Interactive Jupyter notebooks with 55+ examples (recommended for learning)
148148
- **[API Documentation](docs/)** - Detailed guides for each API category
149149
- **[Rich Text DSL](docs/rich-text-dsl.md)** - Working with formatted text
150150
- **[Error Handling](docs/error-handling.md)** - Understanding and handling errors
@@ -159,6 +159,7 @@ The **[Kotlin Notebooks](notebooks/)** are the best way to learn the library:
159159
4. [Working with Blocks](notebooks/04-working-with-blocks.ipynb) - All block types and operations
160160
5. [Rich Text DSL](notebooks/05-rich-text-dsl.ipynb) - Formatting, colors, links, dates, equations
161161
6. [Advanced Queries](notebooks/06-advanced-queries.ipynb) - Complex filtering, AND/OR logic, pagination
162+
7. [File Uploads](notebooks/07-file-uploads.ipynb) - Uploading files, external imports, media blocks
162163

163164
All notebooks use live Notion API and can be run in IntelliJ IDEA or Jupyter.
164165

docs/data-sources.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,13 +271,24 @@ val results = notion.dataSources.query("data-source-id") {
271271

272272
### Working with Properties
273273

274-
After querying, access page properties:
274+
After querying, access page properties using extension functions (recommended):
275275

276276
```kotlin
277277
val pages = notion.dataSources.query("data-source-id") {}
278278

279279
pages.forEach { page ->
280-
// Access different property types
280+
// Use extension functions for clean access
281+
val title = page.getTitleAsPlainText("Task Name")
282+
val status = page.getSelectPropertyName("Status")
283+
284+
println("$title - $status")
285+
}
286+
```
287+
288+
Alternatively, use type-safe casting for more control:
289+
290+
```kotlin
291+
pages.forEach { page ->
281292
val titleProp = page.properties["Task Name"] as? PageProperty.Title
282293
val title = titleProp?.plainText
283294

@@ -288,6 +299,8 @@ pages.forEach { page ->
288299
}
289300
```
290301

302+
See [Pages API - Working with Properties](pages.md#working-with-page-properties) for all access patterns.
303+
291304
### Best Practices
292305

293306
1. **Use filters** - Don't query all pages if you only need some

docs/pages.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,45 @@ notion.pages.create {
259259

260260
### Accessing Properties from Retrieved Pages
261261

262+
The library provides three patterns for accessing page properties:
263+
264+
#### Pattern 1: Extension Functions
265+
266+
The cleanest and most convenient approach - use extension functions for direct access to property values:
267+
268+
```kotlin
269+
val page = notion.pages.retrieve("page-id")
270+
271+
// Simple value access
272+
val title = page.getTitleAsPlainText("Name") ?: "Untitled"
273+
val status = page.getSelectPropertyName("Status") ?: "No status"
274+
val priority = page.getNumberProperty("Priority") ?: 0.0
275+
val dueDate = page.getDateProperty("Due Date")?.start
276+
val assignees = page.getPeopleProperty("Assignee")
277+
278+
// Rich text access (preserves formatting)
279+
val descriptionRichText = page.getRichTextProperty("Description")
280+
val descriptionPlainText = page.getRichTextAsPlainText("Description")
281+
282+
// Other convenience methods
283+
val checkboxValue = page.getCheckboxProperty("Is Complete")
284+
val url = page.getUrlProperty("Link")
285+
val email = page.getEmailProperty("Contact")
286+
val phoneNumber = page.getPhoneNumberProperty("Phone")
287+
val multiSelectNames = page.getMultiSelectPropertyNames("Tags")
288+
val relatedPages = page.getRelationProperty("Related Items")
289+
```
290+
291+
**Use when:** You want clean, concise code and only need the property value (recommended for most cases).
292+
293+
#### Pattern 2: Type-Safe Casting (Full Control)
294+
295+
Cast to the specific property type for explicit control:
296+
262297
```kotlin
263298
val page = notion.pages.retrieve("page-id")
264299

265-
// Type-safe property access
300+
// Access specific property types
266301
val titleProp = page.properties["Name"] as? PageProperty.Title
267302
val title = titleProp?.plainText ?: "Untitled"
268303

@@ -279,6 +314,25 @@ val peopleProp = page.properties["Assignee"] as? PageProperty.People
279314
val assignees = peopleProp?.people ?: emptyList()
280315
```
281316

317+
**Use when:** You need full control over the property object or want to access multiple fields from the same property.
318+
319+
#### Pattern 3: Generic Plain Text Extractor
320+
321+
For cases where you just need a string representation of any property:
322+
323+
```kotlin
324+
val page = notion.pages.retrieve("page-id")
325+
326+
// Works with any property type
327+
val title = page.getPlainTextForProperty("Name") // "My Page"
328+
val status = page.getPlainTextForProperty("Status") // "In Progress"
329+
val priority = page.getPlainTextForProperty("Priority") // "8.0"
330+
val tags = page.getPlainTextForProperty("Tags") // "urgent, bug"
331+
val relations = page.getPlainTextForProperty("Related") // "3 relation(s)"
332+
```
333+
334+
**Use when:** Writing tests, debugging, or when you need a quick string representation without caring about the specific type.
335+
282336
### Property Type Reference
283337

284338
Common property types you can set when creating/updating pages:

docs/pagination.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,10 @@ notion.dataSources.queryAsFlow("data-source-id") {
240240
### Early Termination
241241

242242
```kotlin
243-
// Stop after finding what you need
243+
// Stop after finding what you need (using extension functions)
244244
val targetPage = notion.dataSources.queryAsFlow("data-source-id") {}
245245
.firstOrNull { page ->
246-
// Find first page matching condition
247-
page.properties["Name"]?.let {
248-
(it as? PageProperty.Title)?.plainText == "Target Page"
249-
} ?: false
246+
page.getTitleAsPlainText("Name") == "Target Page"
250247
}
251248
```
252249

@@ -257,14 +254,13 @@ val targetPage = notion.dataSources.queryAsFlow("data-source-id") {}
257254
notion.dataSources.queryAsFlow("data-source-id") {}
258255
.filter { page ->
259256
// Only process pages with status "Active"
260-
val status = page.properties["Status"] as? PageProperty.Select
261-
status?.select?.name == "Active"
257+
page.getSelectPropertyName("Status") == "Active"
262258
}
263259
.map { page ->
264260
// Transform to simpler representation
265261
PageSummary(
266262
id = page.id,
267-
name = (page.properties["Name"] as? PageProperty.Title)?.plainText ?: ""
263+
name = page.getTitleAsPlainText("Name") ?: ""
268264
)
269265
}
270266
.take(10) // Limit to first 10 matching items

0 commit comments

Comments
 (0)