roam-research-mcp
Version:
MCP server and CLI for Roam Research
101 lines (100 loc) • 4.51 kB
JavaScript
import { q } from '@roam-research/roam-api-sdk';
import { BaseSearchHandler } from './types.js';
import { SearchUtils } from './utils.js';
export class BlockRefSearchHandler extends BaseSearchHandler {
constructor(graph, params) {
super(graph);
this.params = params;
}
async execute() {
const { block_uid, title, page_title_uid } = this.params;
// Get target page UID if provided
let targetPageUid;
if (page_title_uid) {
targetPageUid = await SearchUtils.findPageByTitleOrUid(this.graph, page_title_uid);
}
// Build query based on whether we're searching for references to a specific block,
// a page title, or all block references within a page/graph
let queryStr;
let queryParams;
if (title) {
// Search for references to a page by title using :block/refs
if (targetPageUid) {
queryStr = `[:find ?block-uid ?block-str
:in $ ?target-title ?page-uid
:where [?target :node/title ?target-title]
[?p :block/uid ?page-uid]
[?b :block/page ?p]
[?b :block/refs ?target]
[?b :block/string ?block-str]
[?b :block/uid ?block-uid]]`;
queryParams = [title, targetPageUid];
}
else {
queryStr = `[:find ?block-uid ?block-str ?page-title
:in $ ?target-title
:where [?target :node/title ?target-title]
[?b :block/refs ?target]
[?b :block/string ?block-str]
[?b :block/uid ?block-uid]
[?b :block/page ?p]
[?p :node/title ?page-title]]`;
queryParams = [title];
}
}
else if (block_uid) {
// Search for references to a specific block
if (targetPageUid) {
queryStr = `[:find ?block-uid ?block-str
:in $ ?ref-uid ?page-uid
:where [?p :block/uid ?page-uid]
[?b :block/page ?p]
[?b :block/string ?block-str]
[?b :block/uid ?block-uid]
[(clojure.string/includes? ?block-str ?ref-uid)]]`;
queryParams = [`((${block_uid}))`, targetPageUid];
}
else {
queryStr = `[:find ?block-uid ?block-str ?page-title
:in $ ?ref-uid
:where [?b :block/string ?block-str]
[?b :block/uid ?block-uid]
[?b :block/page ?p]
[?p :node/title ?page-title]
[(clojure.string/includes? ?block-str ?ref-uid)]]`;
queryParams = [`((${block_uid}))`];
}
}
else {
// Search for any block references
if (targetPageUid) {
queryStr = `[:find ?block-uid ?block-str
:in $ ?page-uid
:where [?p :block/uid ?page-uid]
[?b :block/page ?p]
[?b :block/string ?block-str]
[?b :block/uid ?block-uid]
[(re-find
queryParams = [targetPageUid];
}
else {
queryStr = `[:find ?block-uid ?block-str ?page-title
:where [?b :block/string ?block-str]
[?b :block/uid ?block-uid]
[?b :block/page ?p]
[?p :node/title ?page-title]
[(re-find
queryParams = [];
}
}
const rawResults = await q(this.graph, queryStr, queryParams);
// Resolve block references in content
const resolvedResults = await this.resolveBlockRefs(rawResults);
const searchDescription = title
? `referencing [[${title}]]`
: block_uid
? `referencing block ((${block_uid}))`
: 'containing block references';
return SearchUtils.formatSearchResults(resolvedResults, searchDescription, !targetPageUid);
}
}