Skip to content

Conversation

@maparent
Copy link
Collaborator

@maparent maparent commented Nov 10, 2025

https://linear.app/discourse-graphs/issue/ENG-1044/experiments-with-different-datalog-query-modalities

This contains code that would allow to use the slow vs fast async catalog queries, if it turns out to have an impact in accuracy after we have a proper testing harness.

@linear
Copy link

linear bot commented Nov 10, 2025

@supabase
Copy link

supabase bot commented Nov 10, 2025

This pull request has been ignored for the connected project zytfjzqyijgagqxrzbmz because there are no changes detected in packages/database/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@maparent maparent marked this pull request as draft November 10, 2025 02:22
@maparent
Copy link
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 10, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 10, 2025

📝 Walkthrough

Walkthrough

Adds an optional local?: boolean to FireQueryArgs and implements a local query flow that detects namespaced property patterns, chooses between Roam async.q or fast.q based on conflicts, and optionally remaps namespaced property names back to originals in query results.

Changes

Cohort / File(s) Summary
FireQuery local mode
apps/roam/src/utils/fireQuery.ts
Added local?: boolean to FireQueryArgs; imported json type; added PROP_NAME_RE and PULL_RE regexes; implemented renamePropsInResult for recursive renaming; branched fireQuery to handle local flows with conflict detection, slow (async.q) vs fast (async.fast.q) paths, and result remapping.
Relation data propagation
apps/roam/src/utils/getRelationData.ts, apps/roam/src/utils/getExportTypes.ts
getRelationDataUtil signature changed to accept an options object { allRelations, nodeLabelByType, local? }; getRelationData now accepts local?: boolean and forwards it; getExportTypes updated to call relation utility with local: true.
Call-site update
apps/roam/src/utils/migrateRelations.ts
Call to getRelationData updated to pass true for the new local flag.

Sequence Diagram

sequenceDiagram
    autonumber
    participant Caller
    participant fireQuery
    participant PropScanner as "Prop Scanner\n(PROP_NAME_RE / PULL_RE)"
    participant ConflictCheck
    participant FastAPI as "window.roamAlphaAPI.data.fast.q"
    participant AsyncAPI as "window.roamAlphaAPI.data.async.q"
    participant Remapper as "renamePropsInResult"

    Caller->>fireQuery: fireQuery(query, { local: true })
    fireQuery->>PropScanner: scan query for namespaced props
    PropScanner-->>fireQuery: mapping info (namespaced → original)
    fireQuery->>ConflictCheck: check for name collisions in pull blocks
    alt no collisions (safe for slow path)
        ConflictCheck->>AsyncAPI: call async.q with namespaced query
        AsyncAPI-->>Remapper: returns namespaced results
        Remapper-->>fireQuery: remapped results (original prop names)
    else collisions (must avoid remap ambiguity)
        ConflictCheck->>FastAPI: call fast.q with original query
        FastAPI-->>fireQuery: returns results (no remapping)
    end
    fireQuery-->>Caller: return final results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'ENG-1044 Experiments with different datalog query modalities' accurately reflects the main changes—adding local-mode support with an optional local parameter to enable alternative datalog query execution paths (async.q vs async.fast.q).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
apps/roam/src/utils/fireQuery.ts (4)

34-34: Add documentation for the new local flag.

Consider adding a JSDoc comment to explain what the local flag does and how it changes query execution behavior (e.g., uses Roam's local async/fast APIs instead of backend API, with automatic property name remapping).


308-308: Simplify the RegExp declaration.

The RegExp constructor is redundant when using a regex literal.

Apply this diff:

-const PROP_NAME_RE = new RegExp(/\:\w+\/\w+\b/, "g");
+const PROP_NAME_RE = /\:\w+\/\w+\b/g;

353-353: Verify the naming conflict detection logic.

The conflict detection checks if the number of unique short names equals the number of namespaced properties: Object.keys(propNamesSub).length === propNames.size. This assumes that if all short names are unique (no hash collisions), it's safe to use async.q with property renaming.

However, consider these edge cases:

  1. Multiple properties with the same namespace could have the same short name: :ns1/prop and :ns2/prop both map to "prop"
  2. The current logic would correctly detect this as a conflict, but ensure this is the intended behavior

The logic appears correct, but it would benefit from a comment explaining the conflict detection strategy.


357-370: Consider extracting renameProps as a module-level helper function.

The renameProps function is defined inline within the query execution logic. Extracting it would improve:

  • Testability: The recursive property renaming logic could be unit tested independently
  • Maintainability: The function could be reused if needed elsewhere
  • Readability: Reduces nesting in the already complex query execution flow

Example extraction:

const renamePropsInResult = (
  result: json | null,
  mapping: Record<string, string>
): json | null => {
  const rename = (x: json | null): json | null => {
    if (Array.isArray(x)) return x.map(rename);
    if (x === null || x === undefined) return x;
    if (typeof x === "object") {
      return Object.fromEntries(
        Object.entries(x as object).map(([k, v]) => [
          mapping[k] || k,
          rename(v),
        ]),
      );
    }
    return x;
  };
  return rename(result);
};

Then use it as: queryResults = renamePropsInResult(queryResults as json, propNamesSub) as unknown[][];

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08113a9 and 0c8157c.

📒 Files selected for processing (1)
  • apps/roam/src/utils/fireQuery.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/main.mdc)

**/*.{ts,tsx}: Prefer type over interface
Use explicit return types for functions
Avoid any types when possible

Files:

  • apps/roam/src/utils/fireQuery.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/main.mdc)

**/*.{ts,tsx,js,jsx}: Prefer arrow functions over regular function declarations
Use named parameters (object destructuring) when a function has more than 2 parameters
Use Prettier with the project's configuration
Maintain consistent naming conventions: PascalCase for components and types
Maintain consistent naming conventions: camelCase for variables and functions
Maintain consistent naming conventions: UPPERCASE for constants

Files:

  • apps/roam/src/utils/fireQuery.ts
apps/roam/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

apps/roam/**/*.{js,jsx,ts,tsx}: Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension
Use the roamAlphaApi documentation from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when working with the Roam API
Use Roam Depot/Extension API documentation from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when working with the Roam Extension API

Files:

  • apps/roam/src/utils/fireQuery.ts
🧠 Learnings (1)
📚 Learning: 2025-06-22T10:40:52.752Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 232
File: apps/roam/src/utils/getAllDiscourseNodesSince.ts:18-31
Timestamp: 2025-06-22T10:40:52.752Z
Learning: In apps/roam/src/utils/getAllDiscourseNodesSince.ts, the user confirmed that querying for `?title` with `:node/title` and mapping it to the `text` field in the DiscourseGraphContent type is the correct implementation for retrieving discourse node content from Roam Research, despite it appearing to query page titles rather than block text content.

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
🔇 Additional comments (3)
apps/roam/src/utils/fireQuery.ts (3)

17-17: LGTM!

The type import is appropriate for typing the property renaming logic introduced in the local query path.


357-369: Add explicit return type to renameProps function.

The inline renameProps function lacks an explicit return type, which violates the coding guidelines for TypeScript functions.

Apply this diff:

-        const renameProps = (x: json | null): json | null => {
+        const renameProps = (x: json | null): json | null => {

Wait, looking at the code again, it already seems to have the return type. Let me re-check... Actually, line 357 shows: const renameProps = (x: json | null): json | null => {. This already has an explicit return type, so this is fine.


345-374: Behavioral differences between async.q and fast.q cannot be verified—recommend manual testing.

The web search found no official Roam documentation explicitly describing these APIs. The differences are inferred from community code patterns only.

Beyond the lack of official documentation, the code itself reveals a potential inconsistency: results from async.q are passed through renameProps() to restore namespaced property names, but fast.q results skip this transformation entirely. This means the two code paths return objects with different property naming conventions, which could break downstream code expecting namespaced names.

Before merging, verify:

  • Whether both APIs return compatible data structures
  • Whether the fast.q branch intentionally skips property renaming or if this is a bug
  • Whether the caller expects consistent property naming regardless of which path executes

@maparent maparent force-pushed the eng-1044-experiments-with-datalog-query-modalities branch from 0c8157c to 11e54c0 Compare November 27, 2025 21:13
@maparent maparent force-pushed the eng-1044-experiments-with-datalog-query-modalities branch from 11e54c0 to d0580a0 Compare December 10, 2025 16:41
@maparent maparent force-pushed the eng-1044-experiments-with-datalog-query-modalities branch from 204b73b to 4f30769 Compare December 22, 2025 20:08
@maparent
Copy link
Collaborator Author

maparent commented Dec 22, 2025

Copying linear comment:

I think this could go as-is, but I can think of two things you may want:

Copy in the migration panel to tell people to wait, and expect an unresponsive UI

We could even have a progression bar, as in the export?

Right now I'm using the local async function, and as I said did not run into issues. You seemed to expect issues in that case, may be worth digging into where you saw them, since right now cannot reproduce.

Not fully related: when the backend query fails and it retries locally… it is internal to Roam, but it would be nice to capture this and send it to posthog. We could substitute for the error handler, but that's invasive. Can you see a way I cannot?

@maparent maparent marked this pull request as ready for review December 22, 2025 20:47
@maparent maparent requested a review from mdroidian December 22, 2025 20:48
@maparent
Copy link
Collaborator Author

Loom video showing that local queries work fine (on test-plugin-akamatsulab2):
https://www.loom.com/share/f2ddf64a9d964027ada08980cc9a5dcc

@mdroidian
Copy link
Contributor

Not fully related: when the backend query fails and it retries locally… it is internal to Roam, but it would be nice to capture this and send it to posthog. We could substitute for the error handler, but that's invasive. Can you see a way I cannot?

Sorry, I don't follow. We could substitute what for the error handler?

@mdroidian
Copy link
Contributor

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 23, 2025

✅ Actions performed

Full review triggered.

@mdroidian
Copy link
Contributor

Copy in the migration panel to tell people to wait, and expect an unresponsive UI

Yes. But this can be a separate task/PR

We could even have a progression bar, as in the export?

Probably not worth the effort

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/roam/src/utils/fireQuery.ts (1)

375-398: Local query implementation with property remapping strategy.

The implementation introduces two query paths when local is enabled:

  1. async.q with remapping (lines 383-390): When property names don't conflict, uses async query and remaps non-namespaced results back
  2. fast.q fallback (lines 391-394): When conflicts exist, uses synchronous query

Observations:

  1. Type assertions (lines 387-390): Casting to json and back to unknown[][] relies on runtime structure matching the type, which is reasonable given the controlled query context.

  2. Conflict detection clarity: The logic Object.keys(propNamesSub).length === propNames.size checks for duplicate non-namespaced property names (e.g., both :block/uid and :node/uid would conflict on "uid"). A comment explaining this would improve maintainability.

  3. Comment on line 376 acknowledges a potential optimization to scan only pull patterns rather than the entire query string.

Given the experimental nature of this feature (per PR objectives), this implementation provides a solid foundation for exploring local query modalities.

Optional: Add clarifying comment for the conflict detection logic
+      // Check if all non-namespaced names are unique (e.g., no conflict between :block/uid and :node/uid)
       if (Object.keys(propNamesSub).length === propNames.size) {
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 670fe22 and ede4f13.

📒 Files selected for processing (4)
  • apps/roam/src/utils/fireQuery.ts
  • apps/roam/src/utils/getExportTypes.ts
  • apps/roam/src/utils/getRelationData.ts
  • apps/roam/src/utils/migrateRelations.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/main.mdc)

**/*.{ts,tsx}: Use Tailwind CSS for styling where possible
When refactoring inline styles, use tailwind classes
Prefer type over interface in TypeScript
Use explicit return types for functions
Avoid any types when possible
Prefer arrow functions over regular function declarations
Use named parameters (object destructuring) when a function has more than 2 parameters
Use PascalCase for components and types
Use camelCase for variables and functions
Use UPPERCASE for constants
Function names should describe their purpose clearly
Prefer early returns over nested conditionals for better readability

Files:

  • apps/roam/src/utils/fireQuery.ts
  • apps/roam/src/utils/getRelationData.ts
  • apps/roam/src/utils/getExportTypes.ts
  • apps/roam/src/utils/migrateRelations.ts
apps/roam/**/*.{js,ts,tsx,jsx,json}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Prefer existing dependencies from package.json when working on the Roam Research extension

Files:

  • apps/roam/src/utils/fireQuery.ts
  • apps/roam/src/utils/getRelationData.ts
  • apps/roam/src/utils/getExportTypes.ts
  • apps/roam/src/utils/migrateRelations.ts
apps/roam/**/*.{ts,tsx,jsx,js,css,scss}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension

Files:

  • apps/roam/src/utils/fireQuery.ts
  • apps/roam/src/utils/getRelationData.ts
  • apps/roam/src/utils/getExportTypes.ts
  • apps/roam/src/utils/migrateRelations.ts
apps/roam/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

apps/roam/**/*.{ts,tsx,js,jsx}: Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality
Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Files:

  • apps/roam/src/utils/fireQuery.ts
  • apps/roam/src/utils/getRelationData.ts
  • apps/roam/src/utils/getExportTypes.ts
  • apps/roam/src/utils/migrateRelations.ts
apps/roam/**

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Implement the Discourse Graph protocol in the Roam Research extension

Files:

  • apps/roam/src/utils/fireQuery.ts
  • apps/roam/src/utils/getRelationData.ts
  • apps/roam/src/utils/getExportTypes.ts
  • apps/roam/src/utils/migrateRelations.ts
🧠 Learnings (3)
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,js,jsx} : Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
📚 Learning: 2025-06-22T10:40:52.752Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 232
File: apps/roam/src/utils/getAllDiscourseNodesSince.ts:18-31
Timestamp: 2025-06-22T10:40:52.752Z
Learning: In apps/roam/src/utils/getAllDiscourseNodesSince.ts, the user confirmed that querying for `?title` with `:node/title` and mapping it to the `text` field in the DiscourseGraphContent type is the correct implementation for retrieving discourse node content from Roam Research, despite it appearing to query page titles rather than block text content.

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
📚 Learning: 2025-12-19T16:59:40.640Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 0
File: :0-0
Timestamp: 2025-12-19T16:59:40.640Z
Learning: In this codebase, type assertions at system boundaries (e.g., Roam datalog queries) are acceptable when the output shape is known from the query structure, such as when using `as Array<[string, string]>` after datalog queries with `:find ?uid ?title` clauses.

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
🧬 Code graph analysis (2)
apps/roam/src/utils/fireQuery.ts (1)
apps/roam/src/utils/getBlockProps.ts (1)
  • json (1-7)
apps/roam/src/utils/getExportTypes.ts (1)
apps/roam/src/utils/getRelationData.ts (1)
  • getRelationDataUtil (9-67)
🔇 Additional comments (6)
apps/roam/src/utils/migrateRelations.ts (1)

23-23: LGTM - Local mode enabled for migration.

The change enables local query mode for relation data retrieval during migration. This aligns with the PR's objective to experiment with different datalog query modalities.

apps/roam/src/utils/getExportTypes.ts (1)

377-378: LGTM - Consistent local mode integration for exports.

The addition of local: true properly propagates the local query flag through the export data flow, enabling local query execution for relation data during exports.

apps/roam/src/utils/getRelationData.ts (2)

9-17: LGTM - Well-structured options object refactoring.

The refactoring from positional parameters to an options object with the optional local flag improves maintainability and follows TypeScript best practices.


32-32: LGTM - Proper flag propagation through call chain.

The local flag is correctly threaded through getRelationDatagetRelationDataUtilfireQuery, maintaining type safety and API consistency.

Also applies to: 69-76

apps/roam/src/utils/fireQuery.ts (2)

17-17: LGTM - Appropriate type import.

The type-only import of json from getBlockProps properly supports the typing of the property renaming logic.


31-40: LGTM - Type extension for local flag.

The addition of local?: boolean to FireQueryArgs is properly typed and maintains backward compatibility.

Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few clarifying questions. Also, I ran coderabbit to check the new changes, could you please address it's comment?

@maparent maparent force-pushed the eng-1044-experiments-with-datalog-query-modalities branch from e20bcb9 to 0ae0f52 Compare December 24, 2025 15:02
@maparent maparent requested review from mdroidian and removed request for mdroidian December 24, 2025 15:03
@maparent
Copy link
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 24, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/roam/src/utils/fireQuery.ts (1)

378-408: Consider simplifying or documenting the disabled slow path.

The preferSlow = false flag on line 378 makes lines 382-398 and 400-408 effectively unreachable. While the past review comments indicate this is intentionally preserved for future comprehensive testing, the code could be clearer for maintainability:

  • Option 1: Add a more prominent comment explaining why this code is preserved but disabled
  • Option 2: Remove the dead code and restore it from git history when global query testing is ready
  • Option 3: Wrap it in a feature flag or environment variable if you expect to enable it soon

The propNamesSub !== undefined check on line 404 is also misleading since propNamesSub can only be set inside the if (preferSlow) block.

Example: More explicit preservation comment
-    // for now assume fast results are equivalent to slow.
-    // We have seen some errors in (fast) backend queries, but not so far in local fast ones.
-    const preferSlow = false;
+    // NOTE: The slow path (async.q with property remapping) is intentionally disabled
+    // but preserved for potential future use pending comprehensive query testing.
+    // See discussion: https://github.com/DiscourseGraphs/discourse-graph/pull/539
+    // When enabled, it handles name conflicts in pull clauses by remapping properties.
+    const preferSlow = false;
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ede4f13 and 0ae0f52.

📒 Files selected for processing (4)
  • apps/roam/src/utils/fireQuery.ts
  • apps/roam/src/utils/getExportTypes.ts
  • apps/roam/src/utils/getRelationData.ts
  • apps/roam/src/utils/migrateRelations.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/roam/src/utils/getExportTypes.ts
  • apps/roam/src/utils/getRelationData.ts
  • apps/roam/src/utils/migrateRelations.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/main.mdc)

**/*.{ts,tsx}: Use Tailwind CSS for styling where possible
When refactoring inline styles, use tailwind classes
Prefer type over interface in TypeScript
Use explicit return types for functions
Avoid any types when possible
Prefer arrow functions over regular function declarations
Use named parameters (object destructuring) when a function has more than 2 parameters
Use PascalCase for components and types
Use camelCase for variables and functions
Use UPPERCASE for constants
Function names should describe their purpose clearly
Prefer early returns over nested conditionals for better readability

Files:

  • apps/roam/src/utils/fireQuery.ts
apps/roam/**/*.{js,ts,tsx,jsx,json}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Prefer existing dependencies from package.json when working on the Roam Research extension

Files:

  • apps/roam/src/utils/fireQuery.ts
apps/roam/**/*.{ts,tsx,jsx,js,css,scss}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension

Files:

  • apps/roam/src/utils/fireQuery.ts
apps/roam/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

apps/roam/**/*.{ts,tsx,js,jsx}: Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality
Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Files:

  • apps/roam/src/utils/fireQuery.ts
apps/roam/**

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Implement the Discourse Graph protocol in the Roam Research extension

Files:

  • apps/roam/src/utils/fireQuery.ts
🧠 Learnings (9)
📚 Learning: 2025-11-06T13:48:35.007Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 0
File: :0-0
Timestamp: 2025-11-06T13:48:35.007Z
Learning: In apps/roam/src/utils/createReifiedBlock.ts, the `setBlockProps` function does not need await as it is synchronous or fire-and-forget.

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
📚 Learning: 2025-08-25T15:53:21.799Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 372
File: apps/roam/src/components/DiscourseNodeMenu.tsx:116-116
Timestamp: 2025-08-25T15:53:21.799Z
Learning: In apps/roam/src/components/DiscourseNodeMenu.tsx, when handling tag insertion, multiple leading hashtags (like ##foo) should be preserved as they represent user intent, not normalized to a single hashtag. The current regex /^#/ is correct as it only removes one leading # before adding one back, maintaining any additional hashtags the user intended.

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
📚 Learning: 2025-11-23T23:53:43.094Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 0
File: :0-0
Timestamp: 2025-11-23T23:53:43.094Z
Learning: In `apps/roam/src/utils/supabaseContext.ts`, the Roam URL normalization uses a targeted string replacement `url.replace("/?server-port=3333#/", "/#/")` rather than URL parsing to avoid impacting unforeseen URL patterns. This conservative approach is intentional to handle only the specific known case.

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
📚 Learning: 2025-06-22T10:40:52.752Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 232
File: apps/roam/src/utils/getAllDiscourseNodesSince.ts:18-31
Timestamp: 2025-06-22T10:40:52.752Z
Learning: In apps/roam/src/utils/getAllDiscourseNodesSince.ts, the user confirmed that querying for `?title` with `:node/title` and mapping it to the `text` field in the DiscourseGraphContent type is the correct implementation for retrieving discourse node content from Roam Research, despite it appearing to query page titles rather than block text content.

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
📚 Learning: 2025-11-25T00:52:27.779Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/main.mdc:0-0
Timestamp: 2025-11-25T00:52:27.779Z
Learning: Applies to **/*.{ts,tsx} : Avoid `any` types when possible

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
📚 Learning: 2025-09-01T19:09:07.052Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 0
File: :0-0
Timestamp: 2025-09-01T19:09:07.052Z
Learning: User prefers to avoid making types explicit in each require statement due to anti-DRY concerns when working with module imports in TypeScript.

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
📚 Learning: 2025-11-25T00:52:27.779Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/main.mdc:0-0
Timestamp: 2025-11-25T00:52:27.779Z
Learning: Applies to **/*.{ts,tsx} : Use explicit return types for functions

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
📚 Learning: 2025-11-25T00:52:27.779Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/main.mdc:0-0
Timestamp: 2025-11-25T00:52:27.779Z
Learning: Applies to **/*.{ts,tsx} : Prefer `type` over `interface` in TypeScript

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
📚 Learning: 2025-12-19T16:59:40.640Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 0
File: :0-0
Timestamp: 2025-12-19T16:59:40.640Z
Learning: In this codebase, type assertions at system boundaries (e.g., Roam datalog queries) are acceptable when the output shape is known from the query structure, such as when using `as Array<[string, string]>` after datalog queries with `:find ?uid ?title` clauses.

Applied to files:

  • apps/roam/src/utils/fireQuery.ts
🧬 Code graph analysis (1)
apps/roam/src/utils/fireQuery.ts (1)
apps/roam/src/utils/getBlockProps.ts (1)
  • json (1-7)
🔇 Additional comments (4)
apps/roam/src/utils/fireQuery.ts (4)

17-17: LGTM: Clean type additions for local query support.

The import of the json type and the addition of the local?: boolean flag to FireQueryArgs are well-integrated and support the new local query functionality without breaking existing code.

Also applies to: 34-34


319-320: LGTM: Regex patterns correctly handle hyphenated properties.

The PROP_NAME_RE pattern now correctly matches hyphenated property names (e.g., :block/text-align, :user/display-name) as recommended in the previous review. The patterns are appropriate for extracting namespace/property patterns and pull expressions from datalog queries.


322-340: LGTM: Well-structured recursive property renaming.

The renamePropsInResult helper correctly handles all JSON value types with proper recursion. The explicit return type and clean implementation follow the coding guidelines.


379-417: Local query implementation is functional and correct.

The local query path correctly uses async.fast.q for local execution and preserves the existing backend.q path for non-local queries. The branching logic works as intended.

@maparent maparent requested a review from mdroidian December 24, 2025 15:14
Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to clarify intent here, since I think there was some understandable misalignment.

This PR originally proposed broader query changes, which were out of scope at the time. In the recent product meeting, when the reified relations migration came up and we discussed a local flag, what I meant specifically was:

we can add a local flag so the reified-relations migration can run local queries instead of backend queries

I did not mean to reopen the broader query refactor or introduce additional execution paths.


What needs to change in this PR

For this PR to land, it needs to be reduced to a very narrow scope:

  • Add local?: boolean

  • When local === true, use:

    roamAlphaAPI.data.async.fast.q
  • Otherwise, preserve existing backend behavior

Everything else (slow paths, property renaming, regex inspection, future fallbacks, commented logic) should be removed.


Why this matters

The additional logic introduces:

  • dead or disabled paths
  • speculative future handling
  • unnecessary cognitive overhead for reviewers and maintainers

If we later find real issues with fast.q, we can address them in a separate, focused PR with concrete evidence.


Summary

I’m aligned on the use case, and I acknowledge my wording in the meeting may have been ambiguous. That said, this PR still needs to be significantly narrowed before merge.

Please cut this down to the minimal local flag + async.fast.q change (≈10–20 LOC), then re-request review.

Alternatively, if you’d like to keep this as an experimental or exploratory effort, please leave this PR as draft and open a separate ticket specifically for introducing a local flag for the reified relations migration use case.

Copy link
Collaborator Author

I knew that's what you want. I'm pushing back in this case. We have bugs we don't understand yet, we can't track them that well, and until we do, we have actually reasons to believe that this currently dead code might turn out to be useful. You've said a few times it's just something that can live in git, but with our policy of squashing and killing branches, if I don't leave it in the code it's gone from git. (I could keep the code privately, but that means nobody else can discover that code.) I'm aware it's making your life a bit more difficult, but we shared the decision to delay the testing infrastructure, and until it exists there are decisions we do not know enough to take, and I think they include killing that code.

Copy link
Collaborator Author

That said… I agree that I can leave this as a draft in a separate PR.

@maparent maparent marked this pull request as draft December 24, 2025 21:28
@maparent maparent force-pushed the eng-1044-experiments-with-datalog-query-modalities branch from e70c60e to f3637d0 Compare December 24, 2025 21:29
@maparent maparent changed the base branch from main to eng-1208-add-local-flag-to-firequery December 24, 2025 21:29
Copy link
Collaborator Author

Made it into a separate PR as requested; I agree it's a cleaner separation of concerns. I will keep the branch around.

Base automatically changed from eng-1208-add-local-flag-to-firequery to main December 24, 2025 21:50
@maparent maparent force-pushed the eng-1044-experiments-with-datalog-query-modalities branch from f3637d0 to 4db72af Compare December 24, 2025 21:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

No open projects
Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants