Skip to content

feat(adapter-notion): extract canonical Notion query helpers#27

Merged
khaliqgant merged 3 commits intomainfrom
feat/notion-queries-module
Apr 26, 2026
Merged

feat(adapter-notion): extract canonical Notion query helpers#27
khaliqgant merged 3 commits intomainfrom
feat/notion-queries-module

Conversation

@kjgbot
Copy link
Copy Markdown
Contributor

@kjgbot kjgbot commented Apr 26, 2026

Summary

Wave 1 extract PR for relayfile-adapters#24. Adds a canonical Notion REST operation builders + database filter helpers + response types module under .

Bump: minor -> 0.1.4.

What changed

  • New with operation builders for search pages/databases, query database, get page, and get block children.
  • Added for common Notion database filter shapes.
  • Re-exported from .
  • Tests in covering operation payloads, URL encoding, pagination, and filter builder behavior.

Sources

Live verification

Search helpers were run through the real Nango proxy using sage NANGO_SECRET_KEY, with the connection ID dynamically discovered via nango.listConnections(). Optional NOTION_VERIFY_DATABASE_ID, NOTION_VERIFY_PAGE_ID, and NOTION_VERIFY_BLOCK_ID extend live coverage for ID-specific helpers when available.

Follow-up PRs

After this PR merges and republishes:

  • cloud refactor: import shared query helpers, drop local copies in route.ts + api fallback
  • sage refactor: same for

Validation

  • [x]

@relayfile/adapter-notion@0.1.4 test
node --import tsx --test 'src/tests/*.test.ts'

TAP version 13

Subtest: block tree ingestion

# Subtest: recursively fetches nested block children
ok 1 - recursively fetches nested block children
  ---
  duration_ms: 1.489958
  type: 'test'
  ...
1..1

ok 1 - block tree ingestion

duration_ms: 1.825
type: 'suite'
...

Subtest: NotionApiClient

# Subtest: sends Notion-Version on direct requests
ok 1 - sends Notion-Version on direct requests
  ---
  duration_ms: 18.0685
  type: 'test'
  ...
# Subtest: paginates with start_cursor on subsequent requests
ok 2 - paginates with start_cursor on subsequent requests
  ---
  duration_ms: 0.407334
  type: 'test'
  ...
1..2

ok 2 - NotionApiClient

duration_ms: 18.825625
type: 'suite'
...

Subtest: content metadata discovery

# Subtest: uses the immediate child page as parentId for deeply nested child pages
ok 1 - uses the immediate child page as parentId for deeply nested child pages
  ---
  duration_ms: 2.523041
  type: 'test'
  ...
1..1

ok 3 - content metadata discovery

duration_ms: 3.000792
type: 'suite'
...

Subtest: path mapping

# Subtest: maps database metadata paths
ok 1 - maps database metadata paths
  ---
  duration_ms: 0.322375
  type: 'test'
  ...
# Subtest: maps database page paths
ok 2 - maps database page paths
  ---
  duration_ms: 0.061791
  type: 'test'
  ...
# Subtest: maps standalone page paths
ok 3 - maps standalone page paths
  ---
  duration_ms: 0.041334
  type: 'test'
  ...
1..3

ok 4 - path mapping

duration_ms: 0.843542
type: 'suite'
...

Subtest: property serialization

# Subtest: serializes each supported writeable property type
ok 1 - serializes each supported writeable property type
  ---
  duration_ms: 1.282959
  type: 'test'
  ...
# Subtest: rejects read-only properties on writeback
ok 2 - rejects read-only properties on writeback
  ---
  duration_ms: 0.395375
  type: 'test'
  ...
1..2

ok 5 - property serialization

duration_ms: 2.362458
type: 'suite'
...

Subtest: Notion query helpers

# Subtest: builds a page search operation without undefined payload keys
ok 1 - builds a page search operation without undefined payload keys
  ---
  duration_ms: 1.898084
  type: 'test'
  ...
# Subtest: builds a database search operation with pagination
ok 2 - builds a database search operation with pagination
  ---
  duration_ms: 0.13675
  type: 'test'
  ...
# Subtest: builds a database query operation with encoded ids and preserves filters, sorts, and pagination
ok 3 - builds a database query operation with encoded ids and preserves filters, sorts, and pagination
  ---
  duration_ms: 1.50775
  type: 'test'
  ...
# Subtest: builds a page fetch operation without a payload
ok 4 - builds a page fetch operation without a payload
  ---
  duration_ms: 0.152625
  type: 'test'
  ...
# Subtest: builds a block children operation with pagination in the query string
ok 5 - builds a block children operation with pagination in the query string
  ---
  duration_ms: 0.170875
  type: 'test'
  ...
# Subtest: uses the expected default operators for common database filter types
ok 6 - uses the expected default operators for common database filter types
  ---
  duration_ms: 0.136292
  type: 'test'
  ...
# Subtest: lets an explicit operator override the default when supported
ok 7 - lets an explicit operator override the default when supported
  ---
  duration_ms: 0.08275
  type: 'test'
  ...
# Subtest: keeps exported response types assignable
ok 8 - keeps exported response types assignable
  ---
  duration_ms: 0.149666
  type: 'test'
  ...
1..8

ok 6 - Notion query helpers

duration_ms: 5.626625
type: 'suite'
...

Subtest: database query builder

# Subtest: builds compound filters and sorts
ok 1 - builds compound filters and sorts
  ---
  duration_ms: 1.757833
  type: 'test'
  ...
1..1

ok 7 - database query builder

duration_ms: 2.087375
type: 'suite'
...

Subtest: blocks to markdown renderer

# Subtest: renders headings, lists, code, and nested children
ok 1 - renders headings, lists, code, and nested children
  ---
  duration_ms: 0.517334
  type: 'test'
  ...
# Subtest: renders media, tables, equations, and page links
ok 2 - renders media, tables, equations, and page links
  ---
  duration_ms: 0.244458
  type: 'test'
  ...
1..2

ok 8 - blocks to markdown renderer

duration_ms: 1.127042
type: 'suite'
...

Subtest: sync change detection

# Subtest: builds a last_edited_time filter payload
ok 1 - builds a last_edited_time filter payload
  ---
  duration_ms: 1.056667
  type: 'test'
  ...
# Subtest: advances the watermark to the newest page edit time
ok 2 - advances the watermark to the newest page edit time
  ---
  duration_ms: 0.0635
  type: 'test'
  ...
# Subtest: queries database changes with a last_edited_time filter
ok 3 - queries database changes with a last_edited_time filter
  ---
  duration_ms: 0.272583
  type: 'test'
  ...
# Subtest: paginates standalone search results before filtering by watermark
ok 4 - paginates standalone search results before filtering by watermark
  ---
  duration_ms: 0.122625
  type: 'test'
  ...
1..4

ok 9 - sync change detection

duration_ms: 1.9265
type: 'suite'
...

Subtest: writeback rule matching

# Subtest: maps page JSON to PATCH /v1/pages/{id}
ok 1 - maps page JSON to PATCH /v1/pages/{id}
  ---
  duration_ms: 0.853334
  type: 'test'
  ...
# Subtest: maps markdown and comments writeback paths
ok 2 - maps markdown and comments writeback paths
  ---
  duration_ms: 0.206333
  type: 'test'
  ...
1..2

ok 10 - writeback rule matching

duration_ms: 1.379084
type: 'suite'
...
1..10

tests 26

suites 10

pass 26

fail 0

cancelled 0

skipped 0

todo 0

duration_ms 375.335458 green

  • clean
  • Live Nango proxy verification passed for search helpers
  • Self-reviewed against cloud + sage consumers (UNION of request/response shapes)
  • Peer-reviewed by Claude Opus

Generated with agent-relay.

RelayFile Adapters Bot and others added 3 commits April 26, 2026 20:38
Tracks relayfile-adapters#24 - one canonical home for Notion API request
knowledge so cloud route.ts, cloud api fallback, and sage
nango-integrations syncs all consume the same operation builders instead
of holding duplicate request-shape logic.

New exports under @relayfile/adapter-notion:
  - searchPages(), searchDatabases(), queryDatabase()
  - getPage(), getBlockChildren()
  - buildDatabaseFilter() for Notion database query filters
  - Response types for Notion list, page, database, block, and generic objects

Operation payloads are the UNION of what cloud + sage consumers need.
Validated against:
  1. Nango integration-templates for Notion (canonical baseline)
  2. sage nango-integrations/notion-sage/syncs/*.ts (production-proven)
  3. cloud packages/web/app/api/v1/notion/query/route.ts + api fallback

Live verification:
  Search helpers were POSTed through the real Nango proxy using sage
  NANGO_SECRET_KEY, with connection IDs dynamically discovered via
  nango.listConnections(). Optional env-provided page/database/block IDs
  verify the ID-specific helpers when available.

Version: minor bump (additive - new exports, no breaking changes).

Follow-up PRs (tracked in relayfile-adapters#24):
  - cloud refactor: import from @relayfile/adapter-notion, drop local copies
  - sage refactor: same for nango-integrations/notion-sage/syncs/*

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant khaliqgant merged commit 6fa7f25 into main Apr 26, 2026
1 check passed
@khaliqgant khaliqgant deleted the feat/notion-queries-module branch April 26, 2026 22:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants