Skip to content

Commit 9ee2d93

Browse files
Merge pull request #635 from rimonhanna/fix/support-multi-relation-property
2 parents 36e4943 + 0566267 commit 9ee2d93

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

examples/full/lib/notion.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ if (useOfficialNotionAPI) {
2121
}
2222

2323
export async function getPage(pageId: string): Promise<ExtendedRecordMap> {
24-
const recordMap = await notion.getPage(pageId)
24+
const recordMap = await notion.getPage(pageId, { fetchRelationPages: true })
2525

2626
if (previewImagesEnabled) {
2727
const previewImageMap = await getPreviewImageMap(recordMap)

packages/notion-client/src/notion-api.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export class NotionAPI {
5353
chunkNumber = 0,
5454
throwOnCollectionErrors = false,
5555
collectionReducerLimit = 999,
56+
fetchRelationPages = false,
5657
kyOptions
5758
}: {
5859
concurrency?: number
@@ -63,6 +64,7 @@ export class NotionAPI {
6364
chunkNumber?: number
6465
throwOnCollectionErrors?: boolean
6566
collectionReducerLimit?: number
67+
fetchRelationPages?: boolean
6668
kyOptions?: KyOptions
6769
} = {}
6870
): Promise<notion.ExtendedRecordMap> {
@@ -220,9 +222,97 @@ export class NotionAPI {
220222
await this.addSignedUrls({ recordMap, contentBlockIds, kyOptions })
221223
}
222224

225+
if (fetchRelationPages) {
226+
const newBlocks = await this.fetchRelationPages(recordMap, kyOptions)
227+
recordMap.block = { ...recordMap.block, ...newBlocks }
228+
}
229+
223230
return recordMap
224231
}
225232

233+
fetchRelationPages = async (
234+
recordMap: notion.ExtendedRecordMap,
235+
kyOptions: KyOptions | undefined
236+
): Promise<notion.BlockMap> => {
237+
const maxIterations = 10
238+
239+
for (let i = 0; i < maxIterations; ++i) {
240+
const relationPageIdsThisIteration = new Set<string>()
241+
242+
for (const blockId of Object.keys(recordMap.block)) {
243+
const blockValue = recordMap.block[blockId]?.value
244+
if (
245+
blockValue?.parent_table === 'collection' &&
246+
blockValue?.parent_id
247+
) {
248+
const collection = recordMap.collection[blockValue.parent_id]?.value
249+
if (collection?.schema) {
250+
const ids = this.extractRelationPageIdsFromBlock(
251+
blockValue,
252+
collection.schema
253+
)
254+
for (const id of ids) relationPageIdsThisIteration.add(id)
255+
}
256+
}
257+
}
258+
259+
const missingRelationPageIds = Array.from(
260+
relationPageIdsThisIteration
261+
).filter((id) => !recordMap.block[id]?.value)
262+
263+
if (!missingRelationPageIds.length) break
264+
265+
try {
266+
const newBlocks = await this.getBlocks(
267+
missingRelationPageIds,
268+
kyOptions
269+
).then((res) => res.recordMap.block)
270+
recordMap.block = { ...recordMap.block, ...newBlocks }
271+
} catch (err: any) {
272+
console.warn(
273+
'NotionAPI getBlocks error during fetchRelationPages:',
274+
err
275+
)
276+
// consider break or delay/retry here
277+
}
278+
}
279+
280+
return recordMap.block
281+
}
282+
283+
extractRelationPageIdsFromBlock = (
284+
blockValue: any,
285+
collectionSchema: any
286+
): Set<string> => {
287+
const pageIds = new Set<string>()
288+
289+
for (const propertyId of Object.keys(blockValue.properties || {})) {
290+
const schema = collectionSchema[propertyId]
291+
if (schema?.type === 'relation') {
292+
const decorations = blockValue.properties[propertyId]
293+
if (Array.isArray(decorations)) {
294+
for (const decoration of decorations) {
295+
if (
296+
Array.isArray(decoration) &&
297+
decoration.length > 1 &&
298+
decoration[0] === '‣'
299+
) {
300+
const pagePointer = decoration[1]?.[0]
301+
if (
302+
Array.isArray(pagePointer) &&
303+
pagePointer.length > 1 &&
304+
pagePointer[0] === 'p'
305+
) {
306+
pageIds.add(pagePointer[1])
307+
}
308+
}
309+
}
310+
}
311+
}
312+
}
313+
return pageIds
314+
}
315+
226316
public async addSignedUrls({
227317
recordMap,
228318
contentBlockIds,

0 commit comments

Comments
 (0)