Skip to content

SurrealDB Query Engine Integration for blazing fast Ad4mModel operations#632

Merged
lucksus merged 87 commits intodevfrom
surreal-queries
Nov 28, 2025
Merged

SurrealDB Query Engine Integration for blazing fast Ad4mModel operations#632
lucksus merged 87 commits intodevfrom
surreal-queries

Conversation

@lucksus
Copy link
Member

@lucksus lucksus commented Nov 19, 2025

🚧 SurrealDB Query Engine Integration

This PR introduces a foundational SurrealDB-based query engine (in memory cache) for AD4M's data layer - as a faster alternative to Prolog for some simple but often used queries. This work enables efficient, structured queries over perspective links and lays the groundwork for improved data retrieval performance.

🎯 Key Changes

  1. SurrealDB Service Integration (rust-executor/src/surreal_service/)
    • Added new SurrealDBService with in-memory database for link storage
    • Implemented schema-full link table with indexed fields:
    ◦ perspective, source, predicate, target, author, timestamp
    • Created custom SurrealQL function fn::parse_literal() for handling AD4M literal URIs
    • Integrated service into PerspectiveInstance for real-time link synchronization

  2. Ad4mModel Query Builder (core/src/model/)
    • Implemented SurrealQL query generation from model metadata
    • Added ModelMetadata extraction system with support for:
    ◦ Property metadata (predicates, required fields, getters/setters)
    ◦ Collection metadata with WHERE clause support
    ◦ JSON Schema fallback for decorator-less models
    • Enhanced findAll() to utilize SurrealDB queries (WIP)
    • Added contains operator to WhereOps for flexible filtering
    • Implemented sophisticated WHERE clause injection with perspective context

  3. Testing & Infrastructure
    • Added extensive test coverage for SurrealDB query generation
    • Created Ad4mModel.test.ts with 1,163 lines of tests
    • Updated agent service tests to use real keys for SDNA validation
    • Improved test reliability by removing unnecessary sleeps

Summary by CodeRabbit

  • New Features

    • SurrealDB added as the default high-performance query engine with per‑perspective caching, live subscription lifecycle (subscribe / keep‑alive / dispose), per-query toggle to legacy backend, model metadata exposure, and a new "contains" filter.
  • Tests

    • Extensive test coverage for SurrealDB queries, subscriptions, metadata generation, result mapping, and parity with existing flows.
  • Docs

    • New and updated guides, examples, and migration tips showing SurrealDB-first usage and Prolog compatibility.
  • Chores

    • Service initialization made non‑fatal; startup sync and background cleanup added for the new query service.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 19, 2025

Walkthrough

Adds SurrealDB as a parallel query backend across TS and Rust: SurrealQL generation and mapping in Ad4mModel/ModelQueryBuilder, Perspective Surreal APIs and subscriptions, an in-process SurrealDB service with per‑perspective sync/subscribe/keepalive/dispose, GraphQL resolvers, and extensive tests and docs.

Changes

Cohort / File(s) Change Summary
Model & Querying (TS)
core/src/model/Ad4mModel.ts, core/src/model/Ad4mModel.test.ts
Add metadata interfaces (PropertyMetadata, CollectionMetadata, ModelMetadata) and getModelMetadata(); extend WhereOps with contains; implement SurrealQL builders (queryToSurrealQL, countQueryToSurrealQL), result mapping (instancesFromSurrealResult), value/field formatting and where/field helpers; comprehensive tests for metadata, JSON‑schema mapping, query generation, and SurrealDB result handling.
ModelQueryBuilder (TS)
core/src/model/...ModelQueryBuilder*, core/src/model/Ad4mModel.ts
Add useSurrealDB flag and propagation through fluent API; branch get/subscribe/count/paginate between SurrealQL and Prolog backends; update findAll/findAllAndCount/paginate/count signatures to accept backend choice.
Perspective Client / Proxy / Resolver (TS)
core/src/perspectives/PerspectiveClient.ts, core/src/perspectives/PerspectiveProxy.ts, core/src/perspectives/PerspectiveResolver.ts
Add Surreal-specific client methods (querySurrealDB, perspectiveSubscribeSurrealQuery, perspectiveKeepAliveSurrealQuery, perspectiveDisposeSurrealQuerySubscription); add querySurrealDB/subscribeSurrealDB on proxy and isSurrealDB flag on subscription proxies; branch init/keepalive/dispose flows; add GraphQL query stub.
Rust SurrealDB service & API
rust-executor/src/surreal_service/mod.rs, rust-executor/Cargo.toml
Add in-process SurrealDBService with graph schema (nodes/links), add_link/remove_link/query_links/clear_perspective/reload_perspective, read-only query validation, unwrap helpers for Surreal JSON, global init/get helpers and tests; add surrealdb dependency.
Perspective instance & lifecycle (Rust)
rust-executor/src/perspectives/perspective_instance.rs, rust-executor/src/perspectives/mod.rs
Add per‑perspective Surreal subscription cache (SurrealSubscribedQuery), public APIs surreal_query, subscribe_and_query_surreal, keepalive_surreal_query, dispose_surreal_query_subscription, sync_existing_links_to_surreal, update_surreal_cache integration, background cleanup loop; ensure initial sync before spawning background tasks.
GraphQL resolvers & runtime init (Rust)
rust-executor/src/graphql/query_resolvers.rs, rust-executor/src/graphql/mutation_resolvers.rs, rust-executor/src/lib.rs, rust-executor/src/agent/mod.rs
Add GraphQL resolvers/mutations for Surreal queries/subscriptions; wire surreal_service::init_surreal_service() into startup (non-fatal on failure); adjust test agent keypair initialization.
JS Tests & Prolog test adjustments
tests/js/tests/perspective.ts, tests/js/tests/prolog-and-literals.test.ts
Add SurrealDB query test suites and Surreal vs Prolog subscription parity tests; move setup to beforeEach for isolation; add per-test SDNA registration and deterministic ordering adjustments.
Docs & Site
docs/pages/**/*.mdx, docs/pages/developer-guides/_meta.json, docs/pages/developer-guides/surreal-queries.mdx
Add SurrealDB-focused docs and examples; mark SurrealDB as default engine in docs; document API usage (useSurrealDB, querySurrealDB), migration guidance and Prolog fallback examples.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ModelQueryBuilder
    participant PerspectiveProxy
    participant PerspectiveInstance
    participant SurrealDBService
    participant PrologBackend

    Client->>ModelQueryBuilder: findAll / subscribe (useSurrealDB=true)
    ModelQueryBuilder->>PerspectiveProxy: querySurrealDB / subscribeSurrealDB(query)
    PerspectiveProxy->>PerspectiveInstance: surreal_query / subscribe_and_query_surreal
    PerspectiveInstance->>SurrealDBService: query_links(perspective_uuid, query)
    SurrealDBService->>SurrealDBService: execute SurrealQL
    SurrealDBService-->>PerspectiveInstance: JSON results
    PerspectiveInstance-->>PerspectiveProxy: parsed results / subscription id + init
    PerspectiveProxy-->>Client: results / subscription proxy (isSurrealDB=true)

    alt useSurrealDB=false
        Client->>ModelQueryBuilder: findAll / subscribe (useSurrealDB=false)
        ModelQueryBuilder->>PerspectiveProxy: query / subscribeQuery(query)
        PerspectiveProxy->>PerspectiveInstance: query (Prolog)
        PerspectiveInstance->>PrologBackend: execute prolog query
        PrologBackend-->>PerspectiveInstance: results
        PerspectiveInstance-->>PerspectiveProxy: results
        PerspectiveProxy-->>Client: results
    end
Loading
sequenceDiagram
    participant Client
    participant PerspectiveProxy
    participant PerspectiveInstance
    participant SurrealDBService

    Client->>PerspectiveProxy: subscribeSurrealDB(query)
    PerspectiveProxy->>PerspectiveInstance: subscribe_and_query_surreal(query)
    PerspectiveInstance->>SurrealDBService: start subscription (poll/keepalive)
    SurrealDBService-->>PerspectiveInstance: initial result
    PerspectiveInstance-->>PerspectiveProxy: subscription ready (init)
    PerspectiveProxy-->>Client: deliver initial result

    rect rgb(230,245,255)
    Client->>PerspectiveProxy: keepalive()
    PerspectiveProxy->>PerspectiveInstance: keepalive_surreal_query(subscriptionId)
    PerspectiveInstance->>SurrealDBService: fetch latest
    SurrealDBService-->>PerspectiveInstance: updated results
    PerspectiveInstance-->>PerspectiveProxy: emit update
    PerspectiveProxy-->>Client: emit update
    end

    Client->>PerspectiveProxy: dispose()
    PerspectiveProxy->>PerspectiveInstance: dispose_surreal_query_subscription(subscriptionId)
    PerspectiveInstance->>SurrealDBService: cleanup subscription
    SurrealDBService-->>PerspectiveInstance: done
    PerspectiveInstance-->>PerspectiveProxy: disposed
    PerspectiveProxy-->>Client: subscription closed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas needing extra attention:
    • SurrealQL generation, operator mapping, escaping and aggregation in Ad4mModel.ts.
    • Correct propagation, defaults and per-query overrides of useSurrealDB across ModelQueryBuilder.
    • SurrealDBService schema, RELATE usage, read-only validation, timeout/transaction behavior and unwrap_surreal_json.
    • Subscription lifecycle, keepalive semantics, cleanup loop and concurrency around surreal_subscribed_queries in perspective_instance.rs.
    • Startup sequencing: sync_existing_links_to_surreal() before background tasks and graceful error handling.

Possibly related PRs

Suggested reviewers

  • jhweir

Poem

🐇 I hopped the code and found a stream,

Surreal joins Prolog in a dual‑engine dream.
Queries race, subscriptions hum, keep‑alives cheer,
Sync and seed and tidy — the rabbit hops near.
🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: integrating SurrealDB as a query engine for Ad4mModel operations.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch surreal-queries

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.

jhweir
jhweir previously approved these changes Nov 28, 2025
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

♻️ Duplicate comments (1)
tests/js/tests/prolog-and-literals.test.ts (1)

1171-1179: Avoid parseInt on timestamp strings; use Date for ordering

Using parseInt on a non-numeric timestamp (e.g. ISO string) will produce garbage values ("2025-11-25T..."2025), breaking both sorting and the boundary you derive for subsequent </<=/> tests. You already handle string timestamps with new Date(...).getTime() in the later count test; this block should match that pattern.

-                    // Sort recipes by timestamp to ensure consistent ordering
-                    const sortedRecipes = [...allRecipes].sort((a, b) => {
-                        const aTime = typeof a.timestamp === 'number' ? a.timestamp : parseInt(a.timestamp);
-                        const bTime = typeof b.timestamp === 'number' ? b.timestamp : parseInt(b.timestamp);
-                        return aTime - bTime;
-                    });
-                    const recipe2timestamp = typeof sortedRecipes[1].timestamp === 'number' 
-                        ? sortedRecipes[1].timestamp 
-                        : parseInt(sortedRecipes[1].timestamp); // Second recipe by timestamp
+                    // Sort recipes by timestamp to ensure consistent ordering
+                    const sortedRecipes = [...allRecipes].sort((a, b) => {
+                        const aTime = typeof a.timestamp === 'number'
+                            ? a.timestamp
+                            : new Date(a.timestamp as any).getTime();
+                        const bTime = typeof b.timestamp === 'number'
+                            ? b.timestamp
+                            : new Date(b.timestamp as any).getTime();
+                        return aTime - bTime;
+                    });
+                    const recipe2timestamp = typeof sortedRecipes[1].timestamp === 'number' 
+                        ? sortedRecipes[1].timestamp 
+                        : new Date(sortedRecipes[1].timestamp as any).getTime(); // Second recipe by timestamp

Optionally, you could also assert Number.isFinite(recipe2timestamp) to fail fast if a non-date string sneaks in.

🧹 Nitpick comments (5)
rust-executor/src/surreal_service/mod.rs (2)

50-63: Consider defensive handling for Thing ID formatting to prevent invalid record ID strings.

If the Thing structure from SurrealDB is malformed or missing expected fields, lines 54–61 could produce invalid record ID strings like ":" or "table:". While this is unlikely with well-formed SurrealDB responses, adding a validation check would prevent potential downstream errors:

                     "Thing" => {
                         if let Some(Value::Object(thing_obj)) = obj.remove(&key) {
                             // Format as "table:id"
                             let tb = thing_obj.get("tb").and_then(|v| v.as_str()).unwrap_or("");
                             let id = thing_obj
                                 .get("id")
                                 .and_then(|v| {
                                     unwrap_surreal_json(v.clone()).as_str().map(String::from)
                                 })
                                 .unwrap_or_default();
+                            // Validate we have both parts before formatting
+                            if !tb.is_empty() && !id.is_empty() {
                             return Value::String(format!("{}:{}", tb, id));
+                            }
+                            // Fallback to the original Thing object if malformed
+                            return Value::Object([(key, Value::Object(thing_obj))].into_iter().collect());
                         }
                     }

669-672: Consider bulk operations for better performance at scale.

The current implementation calls add_link sequentially for each link, which means O(n * 3) individual operations (2× ensure_node + 1× RELATE per link). While tests verify this works with 1,000 links, very large perspectives (10k+ links) may experience slow reload times.

For better performance, consider batching node creation and RELATE operations:

// Pseudocode approach:
// 1. Collect unique URIs from all links
// 2. Bulk ensure all nodes in one transaction
// 3. Batch RELATE operations (SurrealDB supports this)

This optimization can be deferred since the current implementation is functional and reload/sync operations are not on the hot path.

tests/js/tests/prolog-and-literals.test.ts (3)

1615-1709: Strong operator and timestamp coverage for count / query builder

This new test exercises count vs findAll parity for gt, lt, lte, gte, and between, both via the static API and the query builder, and then extends that to timestamp-based filtering. The pattern of checking count(...) === findAll(...).length is an excellent guardrail for backend consistency.

Minor optional robustness: after computing recipe3Timestamp via new Date(...).getTime() for string timestamps, you could assert it’s finite to catch unexpected formats early:

expect(Number.isFinite(recipe3Timestamp)).to.be.true;

But the current code is reasonable if you control timestamp formats.


2205-2315: SurrealDB vs Prolog subscription parity & perf tests look solid

The new SubscriptionTestModel block:

  • Uses its own per-test perspective lifecycle and SDNA registration, avoiding interference with the rest of the suite.
  • Compares SurrealDB (default) vs explicit Prolog subscriptions off the same where({ status: "active" }) builder and checks final result parity by sorted name/status, which is exactly what you want here.
  • Adds a perf-oriented test with a 5s timeout loop, ensuring at least one subscription update arrives and logging latencies without baking in brittle perf thresholds.

If you run into CI flakiness later, you might consider replacing the fixed sleep(2000) in the parity test with a loop similar to the perf test (waiting until both callbacks have count items or timing out), but it’s fine as-is for now.


2521-2544: Emoji tests: per-test SDNA registration and cleanup, legacy before commented out

Switching from the old (now commented-out) before to a beforeEach that:

  • calls ensureSDNASubjectClass(EmojiMessage), and
  • clears any existing EmojiMessage instances

gives these emoji/special-character tests strong isolation and keeps them compatible with changing backends. Based on learnings about per-call perspective isolation, reusing the same perspective name here is safe.

You could optionally delete the commented-out before block entirely to reduce noise, but that’s purely cosmetic.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c0cf4a and 8cd28a2.

📒 Files selected for processing (2)
  • rust-executor/src/surreal_service/mod.rs (1 hunks)
  • tests/js/tests/prolog-and-literals.test.ts (13 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-03T15:16:29.623Z
Learnt from: lucksus
Repo: coasys/ad4m PR: 619
File: rust-executor/src/perspectives/perspective_instance.rs:639-641
Timestamp: 2025-09-03T15:16:29.623Z
Learning: In the AD4M codebase, database operations like `add_many_links` during critical synchronization processes (such as `diff_from_link_language`) should use `.expect()` rather than error logging, as failures indicate severe system issues where fail-fast behavior is preferred over continuing with potentially corrupted state.

Applied to files:

  • rust-executor/src/surreal_service/mod.rs
📚 Learning: 2025-09-24T14:26:44.307Z
Learnt from: lucksus
Repo: coasys/ad4m PR: 628
File: tests/js/tests/prolog-and-literals.test.ts:2726-2729
Timestamp: 2025-09-24T14:26:44.307Z
Learning: In AD4M, perspectives have names but are uniquely identified by UUIDs. Creating a new perspective with the same name in consecutive calls will create a fresh perspective each time, so there's no risk of state leakage between tests based on perspective names.

Applied to files:

  • tests/js/tests/prolog-and-literals.test.ts
🔇 Additional comments (15)
rust-executor/src/surreal_service/mod.rs (7)

122-193: LGTM!

The read-only query validation is comprehensive and correctly enforces word boundaries to prevent false positives. The case-insensitive matching and warning for unexpected query patterns provide good defense-in-depth for the query interface.


195-244: LGTM!

The error handling in ensure_node correctly distinguishes between expected duplicate-record errors (which are safely ignored) and unexpected database failures (which are logged and propagated). This addresses the integrity concerns from previous reviews.


246-333: LGTM!

The initialization logic properly sets up the graph schema with appropriate indexes for query optimization. The custom fn::parse_literal() function provides domain-specific literal URI parsing, and the use of IF NOT EXISTS ensures idempotent schema definitions.


335-396: LGTM!

Both add_link and remove_link correctly use graph operations (RELATE and DELETE with type::thing() matching) and properly propagate errors from ensure_node. Parameter binding is used throughout to prevent injection attacks.


398-637: LGTM!

The query_links implementation correctly addresses previous review concerns about perspective isolation:

  • Original WHERE conditions are now wrapped in parentheses (line 492) to preserve operator precedence with OR clauses.
  • Aliased queries now receive perspective filtering (lines 502-510) instead of bypassing it.

The 60-second timeout with periodic logging provides good observability for long-running queries without blocking indefinitely.


678-693: LGTM!

The global service lifecycle uses a standard lazy_static singleton pattern with RwLock for thread-safe access. The .expect() in get_surreal_service provides fail-fast behavior if called before initialization, which aligns with the codebase's approach to critical system components (as noted in learnings).


695-2073: LGTM!

The test suite is exceptionally comprehensive, covering:

  • All CRUD operations and perspective isolation
  • Graph traversal queries after reload (critical for Ad4mModel integration)
  • Performance at scale (1,000 links)
  • Concurrent operations and thread safety
  • Security validation (read-only enforcement)

This level of test coverage provides strong confidence in the implementation's correctness and robustness.

tests/js/tests/prolog-and-literals.test.ts (8)

617-625: Per-test perspective reset for Active Record tests improves isolation

Recreating/removing the perspective in beforeEach makes the Active Record tests self-contained and prevents cross-test leakage, while still using the same name safely thanks to UUID-based identity. Based on learnings, this pattern is correct and desirable.


664-671: find() test now seeds its own fixture

Creating and saving recipe1 inside this test before calling findAll() removes any reliance on prior tests and aligns well with the new per-test perspective setup.


717-740: delete() test correctly constructs its own dataset

Explicitly creating three recipes and asserting the length transitions 3 → 2 after delete() makes this test robust under the new isolation model and independent of earlier Active Record tests.


899-904: Order-agnostic checks for comments collections

Switching to .include(...) instead of relying on array ordering makes the findAll() collection assertions tolerant to backend-specific ordering differences (Prolog vs SurrealDB) while still verifying the right elements are present.


1330-1363: Limit/offset pagination test is clear and sufficient

The test now cleanly exercises limit, offset, and their combination against a simple, ordered dataset of "Recipe 1" ... "Recipe 6". Assertions line up with expected paging semantics; nothing to change here.


1414-1466: Good coverage for multi-property where AND semantics

This test nicely validates that:

  • multiple scalar constraints in a single where are AND-ed,
  • mixed operator/equality constraints (number: { gt: 5 } + booleanTest: true) behave as expected,
  • and impossible combinations return zero results.

This is valuable coverage for the query builder’s composed predicates.


1855-1858: Adjusted expectations for SurrealDB subscription update count

Documenting and commenting out the strict updateCount assertion acknowledges the extra raw-result updates you get when filtering happens client-side under SurrealDB, while still asserting on the final notifications.length. This keeps the test meaningful without making it backend-fragile.


2143-2175: Using .have.members for batch ingredients avoids order dependence

For both the post-commit and pre-update checks you now assert ingredients via .have.members([...]), which is the right choice for collections whose ordering isn’t semantically important and may differ between Prolog/SurrealDB or across implementations.

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)
docs/pages/index.mdx (1)

199-228: Clarify performance claims and add proper caveats for SurrealDB recommendations.

Lines 205 and 223–227 claim "10-100x faster performance" for SurrealDB without context or benchmarking data. This is a strong claim that should either cite performance benchmarks or be qualified (e.g., "in typical scenarios" or "compared to unindexed Prolog queries"). Additionally, line 223's performance tip warns against subqueries but doesn't explain why or suggest alternatives.

Consider adding:

  • A note referencing performance benchmarks or test results (if available)
  • Guidance on when Prolog might still be preferable (complex logic, smaller datasets)
  • Alternative patterns instead of subqueries, or links to the SurrealDB queries guide for more details
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8cd28a2 and deec6a4.

📒 Files selected for processing (1)
  • docs/pages/index.mdx (6 hunks)
🔇 Additional comments (4)
docs/pages/index.mdx (4)

250-254: Confirm past review fix: infer() method is now correctly documented (resolves earlier queryProlog() issue).

The Prolog example now correctly uses perspective.infer() instead of the private perspective.queryProlog() method, aligning with the canonical API. This resolves the issue flagged in the previous review.


262-307: The documented Ad4mModel decorator examples are correct and match the actual implementation.

Verification confirms both syntax patterns are valid:

  • @readonly getter (line 283): The getter parameter is supported by PropertyOptions interface and correctly documented as a custom Prolog expression for retrieving property values.
  • @Collection where clause (line 292): The where parameter with condition property is supported by WhereOptions interface and correctly documented for filtering collection values.

No changes to the documentation are needed.


213-221: No issues found - querySurrealDB() API method exists and query syntax is accurate.

Verification confirms:

  • The querySurrealDB() method is properly implemented in PerspectiveProxy.ts (line 554) and PerspectiveClient.ts (line 167)
  • Query syntax examples in docs/pages/index.mdx match the SurrealQL patterns documented in the source code
  • Field names (in.uri, out.uri, target, predicate) are consistently referenced across both source documentation and the mdx file
  • Examples extend the source code patterns but remain consistent (docs show indexed graph queries while source examples show basic filtering)

The code snippet at lines 213-221 in docs/pages/index.mdx is accurate and reflects the actual API surface.


258-318: Perfect! I have verified all the claims in the review comment against the actual Ad4mModel implementation. Here are my findings:

Verification Results:

  1. SurrealDB is the default ✓ - Confirmed at line 1630: useSurrealDB: boolean = true
  2. useSurrealDB: false toggle exists ✓ - Confirmed; when false, routes to Prolog via queryToProlog() (line 1638)
  3. Query method signatures match documentation ✓ - All query methods (findAll, findAllAndCount, paginate, count) follow the documented pattern with the useSurrealDB parameter defaulting to true

The implementation confirms:

  • Line 1632-1639: Conditional logic correctly routes to SurrealDB or Prolog based on the flag
  • All documented examples with Recipe.findAll(perspective, {}, false) for backward compatibility are supported
  • Performance claims and backward compatibility documentation are accurate

All claims in the review comment are accurate and verified against the codebase. No inaccuracies, discrepancies, or implementation issues were found.

@triska
Copy link

triska commented Dec 12, 2025

Could the Prolog engine be improved to handle the required cases more efficiently?

If possible, would you please consider posting a benchmark of cases where you would benefit from faster performance of Scryer?

For example, @Yordando recently did this, leading to a 10-fold speed improvement in the same month:

mthom/scryer-prolog#3150

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.

3 participants