diff --git a/plugins/notion/src/api.ts b/plugins/notion/src/api.ts index f542ab766..24aa81984 100644 --- a/plugins/notion/src/api.ts +++ b/plugins/notion/src/api.ts @@ -405,6 +405,29 @@ export async function getPageBlocksAsRichText(pageId: string) { return blocksToHtml(blocks) } +const RELATION_PROPERTY_PAGE_SIZE = 100 + +/** + * Loads up to {@link RELATION_PROPERTY_PAGE_SIZE} related page ids when the relation is truncated on + * retrieve-page / query (has_more). Does not paginate past the first page. + */ +export async function fetchRelationIdsForPageProperty(pageId: string, propertyId: string): Promise { + const notion = getNotionClient() + const response = await notion.pages.properties.retrieve({ + page_id: pageId, + property_id: propertyId, + page_size: RELATION_PROPERTY_PAGE_SIZE, + }) + + if (response.object === "list") { + return response.results.map(item => (item.type === "relation" ? item.relation.id : "")).filter(id => id !== "") + } + if (response.type === "relation") { + return [response.relation.id] + } + return [] +} + export async function getDatabaseItems( database: GetDatabaseResponse, onProgress?: (progress: { current: number; total: number; hasFinishedLoading: boolean }) => void diff --git a/plugins/notion/src/data.ts b/plugins/notion/src/data.ts index 039470991..1f3ff7304 100644 --- a/plugins/notion/src/data.ts +++ b/plugins/notion/src/data.ts @@ -13,6 +13,7 @@ import { alwaysSyncedPropertyTypes, assertFieldTypeMatchesPropertyType, type FieldInfo, + fetchRelationIdsForPageProperty, getDatabase, getDatabaseFieldsInfo, getDatabaseItems, @@ -241,7 +242,7 @@ export async function syncCollection( continue } - const fieldEntry = getFieldDataEntryForProperty(property, field) + const fieldEntry = await getFieldDataEntryForProperty(property, field, item.id) if (fieldEntry) { fieldData[field.id] = fieldEntry } else { @@ -624,10 +625,11 @@ export function fieldsInfoToCollectionFields( return fields } -export function getFieldDataEntryForProperty( +async function getFieldDataEntryForProperty( property: PageObjectResponse["properties"][string], - field: ManagedCollectionFieldInput -): FieldDataEntryInput | null { + field: ManagedCollectionFieldInput, + itemId: string +): Promise { switch (property.type) { case "checkbox": { return { type: "boolean", value: property.checkbox } @@ -691,7 +693,14 @@ export function getFieldDataEntryForProperty( } case "relation": { if (field.type === "multiCollectionReference") { - return { type: "multiCollectionReference", value: property.relation.map(({ id }) => id) } + let relationItemIds: string[] = [] + if ("has_more" in property && property.has_more) { + relationItemIds = await fetchRelationIdsForPageProperty(itemId, property.id) + } else { + relationItemIds = property.relation.map(({ id }) => id) + } + + return { type: "multiCollectionReference", value: relationItemIds } } else if (field.type === "collectionReference") { return { type: "collectionReference", value: property.relation[0]?.id ?? null } }