Skip to content

Commit 02807bc

Browse files
Jonas Saabelclaude
andcommitted
feat: add unique_id property type support
Provides structured access to Notion's unique_id property (auto-incrementing IDs with optional prefixes) for tracking systems like tickets and invoices. Previously handled as Unknown type. Changes: - Add PageProperty.UniqueId with formattedId convenience property - Add UniqueIdValue data class (prefix, number) - Update PagePropertySerializer for unique_id deserialization - Add comprehensive unit tests (4 tests, all passing) - Update Unknown type tests to reflect unique_id now supported Testing: - 508 total tests passing (up from 503) - Tested with/without prefix, null values, mixed property types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 2fa9aa0 commit 02807bc

File tree

7 files changed

+400
-12
lines changed

7 files changed

+400
-12
lines changed

.claude/commands/catch-up.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
description: Review recent journals and commits and summarize current state
3+
---
4+
5+
Review recent journal files in journal/ directory, as well as recent git history:
6+
1. Read the most recent journal file completely
7+
2. List the 5-10 previous journal titles (by date, descending)
8+
3. Based on the latest journal's "Next Steps" and topic, identify which older journals seem relevant
9+
4. Read only those relevant journals (typically 1-3 more)
10+
5. Take a look at the latest commit messages
11+
12+
Provide a concise summary of:
13+
1. What was worked on most recently
14+
2. Key decisions that affect current work
15+
3. Open questions/blockers
16+
4. Recommended next steps
17+
18+
Prioritize continuity over completeness - focus on what's needed to resume work.
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Session: Unique ID Property Implementation
2+
3+
**Date:** 2025-11-04
4+
**Focus:** Implement proper support for unique_id property type
5+
6+
## Context
7+
8+
Following the Nov 3 investigation that added `PageProperty.Unknown` for forward compatibility, the `unique_id` property type was identified as a high-value candidate for proper implementation due to its utility in tracking systems (tickets, invoices, etc.).
9+
10+
## Implementation
11+
12+
### Changes Made
13+
14+
1. **PageRequests.kt**: Added `UniqueIdValue` data class
15+
- `prefix: String?` - Optional prefix (e.g., "TASK", "INV")
16+
- `number: Int` - Auto-incrementing number
17+
18+
2. **PageProperty.kt**: Added `PageProperty.UniqueId`
19+
- Structured access to prefix and number
20+
- Convenience property `formattedId` that returns "PREFIX-123" or "123"
21+
22+
3. **PagePropertySerializer.kt**: Updated serializer
23+
- Added "unique_id" to deserialization when block
24+
- Added serialization support
25+
- Updated documentation
26+
27+
4. **PagePropertyUniqueIdTest.kt**: Created comprehensive unit tests (4 tests)
28+
- With prefix: `"TEST-123"`
29+
- Without prefix (null): `"42"`
30+
- Alongside other properties
31+
- Null unique_id value
32+
33+
5. **PagePropertyUnknownTypeTest.kt**: Updated existing tests
34+
- Removed unique_id from unknown types examples
35+
36+
### Example Payloads
37+
38+
**With prefix:**
39+
```json
40+
{
41+
"id": "zapM",
42+
"type": "unique_id",
43+
"unique_id": {
44+
"prefix": "TEST",
45+
"number": 1
46+
}
47+
}
48+
```
49+
50+
**Without prefix:**
51+
```json
52+
{
53+
"id": "zapM",
54+
"type": "unique_id",
55+
"unique_id": {
56+
"prefix": null,
57+
"number": 1
58+
}
59+
}
60+
```
61+
62+
### Test Results
63+
64+
- Total tests: 508 (up from 503)
65+
- New tests: 4 unique_id tests
66+
- Status: ✅ All passing, no regressions
67+
- Build: ✅ Successful
68+
69+
## Outcome
70+
71+
**Complete**: Unique ID property type now fully supported with type-safe access
72+
73+
## Next Steps
74+
75+
### Place Property Implementation
76+
77+
The `place` property type is next for implementation. It provides structured location data:
78+
79+
**Example payload:**
80+
```json
81+
{
82+
"id": "%3FJG%7D",
83+
"type": "place",
84+
"place": {
85+
"lat": 60.19116,
86+
"lon": 11.10242,
87+
"name": "Oslo Airport",
88+
"address": "Oslo Airport, E16, 2060 Gardermoen, Norway",
89+
"aws_place_id": "AQAAAFUAJOZ89r-mb1SYL7-SoMdRt07f78RSAwxxWdEftbKanfZs-NqGy40xt67lWhjfJzRfiogmMr75O8PZ3b4T0PKbYS3OTBLMB8cgTubHqwS7sTFnIVYYShVzNMhVJtBKJPu03EeEWbfslnPMluRM9eImLnrMM_bz",
90+
"google_place_id": null
91+
}
92+
}
93+
```
94+
95+
**Utility**: High value for location-based applications, mapping, logistics, etc.
96+
97+
**Implementation approach**: Follow the same pattern as unique_id
98+
- Add `PlaceValue` data class to PageRequests.kt
99+
- Add `PageProperty.Place` to PageProperty.kt
100+
- Update PagePropertySerializer.kt
101+
- Create comprehensive unit tests
102+
- Update existing tests to remove place from unknown types

src/main/kotlin/it/saabel/kotlinnotionclient/models/pages/PageProperty.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,28 @@ sealed class PageProperty {
108108
@SerialName("phone_number") val phoneNumber: String?,
109109
) : PageProperty()
110110

111+
@Serializable
112+
@SerialName("unique_id")
113+
data class UniqueId(
114+
@SerialName("id") override val id: String,
115+
@SerialName("type") override val type: String,
116+
@SerialName("unique_id") val uniqueId: UniqueIdValue?,
117+
) : PageProperty() {
118+
/**
119+
* Returns the formatted unique ID string (e.g., "TEST-123" or "123" if no prefix).
120+
* Returns null if the unique_id value is not set.
121+
*/
122+
val formattedId: String?
123+
get() =
124+
uniqueId?.let {
125+
if (it.prefix != null) {
126+
"${it.prefix}-${it.number}"
127+
} else {
128+
it.number.toString()
129+
}
130+
}
131+
}
132+
111133
@Serializable
112134
@SerialName("select")
113135
data class Select(

src/main/kotlin/it/saabel/kotlinnotionclient/models/pages/PagePropertySerializer.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import kotlinx.serialization.json.jsonPrimitive
2525
* adds new property types (e.g., "button", "unique_id", "verification", etc.).
2626
*
2727
* ## Supported Property Types
28-
* - title, rich_text, number, checkbox, url, email, phone_number
28+
* - title, rich_text, number, checkbox, url, email, phone_number, unique_id
2929
* - select, multi_select, status
3030
* - date, people, files
3131
* - relation, formula, rollup
@@ -60,6 +60,7 @@ object PagePropertySerializer : KSerializer<PageProperty> {
6060
"url" -> decoder.json.decodeFromJsonElement(PageProperty.Url.serializer(), element)
6161
"email" -> decoder.json.decodeFromJsonElement(PageProperty.Email.serializer(), element)
6262
"phone_number" -> decoder.json.decodeFromJsonElement(PageProperty.PhoneNumber.serializer(), element)
63+
"unique_id" -> decoder.json.decodeFromJsonElement(PageProperty.UniqueId.serializer(), element)
6364
"select" -> decoder.json.decodeFromJsonElement(PageProperty.Select.serializer(), element)
6465
"multi_select" -> decoder.json.decodeFromJsonElement(PageProperty.MultiSelect.serializer(), element)
6566
"status" -> decoder.json.decodeFromJsonElement(PageProperty.Status.serializer(), element)
@@ -102,6 +103,7 @@ object PagePropertySerializer : KSerializer<PageProperty> {
102103
is PageProperty.Url -> encoder.encodeSerializableValue(PageProperty.Url.serializer(), value)
103104
is PageProperty.Email -> encoder.encodeSerializableValue(PageProperty.Email.serializer(), value)
104105
is PageProperty.PhoneNumber -> encoder.encodeSerializableValue(PageProperty.PhoneNumber.serializer(), value)
106+
is PageProperty.UniqueId -> encoder.encodeSerializableValue(PageProperty.UniqueId.serializer(), value)
105107
is PageProperty.Select -> encoder.encodeSerializableValue(PageProperty.Select.serializer(), value)
106108
is PageProperty.MultiSelect -> encoder.encodeSerializableValue(PageProperty.MultiSelect.serializer(), value)
107109
is PageProperty.Status -> encoder.encodeSerializableValue(PageProperty.Status.serializer(), value)

src/main/kotlin/it/saabel/kotlinnotionclient/models/pages/PageRequests.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,14 @@ data class PageReference(
386386
val id: String,
387387
)
388388

389+
@Serializable
390+
data class UniqueIdValue(
391+
@SerialName("prefix")
392+
val prefix: String?,
393+
@SerialName("number")
394+
val number: Int,
395+
)
396+
389397
@Serializable
390398
sealed class FileObject {
391399
@Serializable

0 commit comments

Comments
 (0)