docs: extend ENS Unigraph examples#2264
Conversation
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
|
Worried about impact? Review this PR in Change Stack to explore blast radius before you approve or request changes. Warning Review limit reached
More reviews will be available in 53 minutes and 49 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR consolidates Unigraph SQL example documentation by extracting code snippets and expected results from individual MDX files into shared TypeScript data modules, centralizing the example definitions, updating the documentation pages to reference these shared modules, and adding new example documentation pages with navigation links. ChangesUnigraph Example Documentation System
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryThis PR extends the ENS Unigraph documentation by adding six new example pages (Domain Events, Fuzzy Search, Subdomains, Account Domains, Latest Registrations, Expiring Registrations) and refactors existing examples to move inline code snippets and results into dedicated TypeScript data files, simplifying the MDX pages.
Confidence Score: 3/5Two example data files ship with results that contradict the accompanying code snippet, which would mislead developers reading the docs. The fuzzy-search example shows 'reverse' query results under SDK code that searches for 'vitalik', and the subdomains example lists different domain types for the same name across the SQL and SDK tabs. Both are incorrect example outputs visible to any developer reading the docs pages. docs/ensnode.io/src/data/unigraph-examples/domains-fuzzy-search-by-name.ts and docs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.ts need their result fixtures corrected before merge. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[MDX Example Page] -->|imports| B[unigraph-examples/*.ts]
B -->|exports QueryExample| C{sql / sdk}
C -->|sql.codeSnippet\nsql.result\nsql.resultNote| D[UnigraphStaticExample.astro]
C -->|sdk.codeSnippet\nsdk.result\nsdk.resultNote| D
D --> E[UnigraphExampleSQLTab\ncode + SqlResultTable + set:html note]
D --> F[UnigraphExampleEnsDbSdkTab\ncode + SqlResultTable + set:html note]
G[utils.outputSource] -->|HTML string with link| B
Reviews (4): Last reviewed commit: "Apply AI PR feedback" | Re-trigger Greptile |
There was a problem hiding this comment.
Pull request overview
This PR expands the ENS Unigraph SQL examples in the docs by moving example payloads into dedicated data modules and adding several new example pages that import those modules for rendering.
Changes:
- Introduced a small
QueryExample/CodeExampletype contract and added multiple new Unigraph example data files (SQL +ensdb-sdksnippets + static results). - Added new MDX pages for each example and refactored existing pages to import examples from
@data/unigraph-examples/.... - Updated the Integrate sidebar to include the expanded Unigraph examples navigation.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/ensnode.io/src/data/unigraph-examples/types.ts | Adds shared TS types for example payloads. |
| docs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.ts | Adds subdomains-by-parent SQL/SDK example + result fixture. |
| docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts | Adds latest-registrations SQL/SDK example + result fixture. |
| docs/ensnode.io/src/data/unigraph-examples/indexing-status.ts | Adds indexing-status SQL/SDK example + result fixture. |
| docs/ensnode.io/src/data/unigraph-examples/expiring-registrations.ts | Adds expiring-registrations SQL/SDK example + result fixture. |
| docs/ensnode.io/src/data/unigraph-examples/domains-fuzzy-search-by-name.ts | Adds pg_trgm-based fuzzy name search example + result fixture. |
| docs/ensnode.io/src/data/unigraph-examples/domain-events.ts | Adds domain events join example + result fixture. |
| docs/ensnode.io/src/data/unigraph-examples/domain-by-name.ts | Adds canonical-name lookup example + result fixture. |
| docs/ensnode.io/src/data/unigraph-examples/account-domains.ts | Adds “domains owned by address” example + result fixture. |
| docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/subdomains-by-parent-name.mdx | New example page wiring the data module into the UI component. |
| docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/latest-registrations.mdx | New example page wiring the data module into the UI component. |
| docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/indexing-status.mdx | Refactors existing page to import the new data module. |
| docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/expiring-registrations.mdx | New example page wiring the data module into the UI component. |
| docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domains-fuzzy-search-by-name.mdx | New example page wiring the data module into the UI component. |
| docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-events.mdx | New example page wiring the data module into the UI component. |
| docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-by-name.mdx | Refactors existing page to import the new data module. |
| docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdx | Refactors existing page to import the new data module. |
| docs/ensnode.io/src/content/docs/docs/integrate/index.mdx | Updates integration option descriptions. |
| docs/ensnode.io/src/components/molecules/EnsDbReaderIntro.astro | Minor copy tweak referencing the “Connect” example. |
| docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.ts | Adds sidebar links for the expanded Unigraph example set. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.ts`:
- Around line 206-207: Correct the typo in the sidebar entry by changing the
label string "Exipring Registrations" to "Expiring Registrations"; locate the
object where label: "Exipring Registrations" appears (the same entry with link:
"/docs/integrate/unigraph/examples/expiring-registrations") and update the label
value to the spelled-correct form.
In
`@docs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-events.mdx`:
- Line 17: The description paragraph starting with "Fetch recent events for a
Domain by its canonical name..." is missing the consistent setup reference;
update that paragraph (in the content of domain-events.mdx) to append the
sentence "See [Connect](/docs/integrate/unigraph/examples) for setup." so it
matches the other example pages (search for the exact paragraph text or the
file's title/section to locate where to insert this reference).
In `@docs/ensnode.io/src/data/unigraph-examples/account-domains.ts`:
- Around line 98-119: The example uses asc(...) in orderBy but never imports it;
update the import line in the codeSnippet to include asc (i.e., import { and,
eq, asc } from "drizzle-orm") so the call to asc in the accountDomains query
resolves correctly—modify the import near the top of the snippet where and and
eq are imported.
In `@docs/ensnode.io/src/data/unigraph-examples/expiring-registrations.ts`:
- Around line 3-5: Update the module JSDoc to describe expiring registrations
rather than recent events; replace the current summary line ("Example query for
fetching recent events for a Domain by its canonical name.") with a concise
description matching the file intent such as "Example query for fetching
expiring registrations for a Domain" (or similar phrasing) in the top comment of
expiring-registrations.ts so the documentation matches the query implemented in
this module.
In `@docs/ensnode.io/src/data/unigraph-examples/indexing-status.ts`:
- Around line 119-130: The example outputs incorrectly nest indexingStatus one
level too deep; update the result objects so they use
indexingStatusSnapshot.indexingStatus instead of { indexingStatus:
indexingStatusSnapshot } (i.e., set result to { indexingStatus:
indexingStatusSnapshot.indexingStatus }) for both occurrences referenced around
indexingStatusSnapshot and the SDK snippet constants to match the SQL/SDK
examples.
In `@docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts`:
- Around line 8-24: The SQL in the codeSnippet currently selects five columns
(d.canonical_name, r.start, r.expiry, d.owner_id, d.id AS domain_id) with LIMIT
15 but the documented result payload contains additional registration columns
and only five rows; make them consistent by either (A) expanding the SELECT in
the codeSnippet to include the extra registration fields shown in the result
(e.g., add r.transaction_hash, r.registration_index, r.type, etc.) and keep
LIMIT 5 if the example intends five rows, or (B) update the result block to
match the current SQL (only the five selected columns and 15 rows); locate the
codeSnippet string in latest-registrations.ts and change the SELECT column list
and LIMIT (or the result block) accordingly so both the query and the documented
result match exactly.
- Around line 89-127: The code snippet is missing the desc import and the SQL
example's selected columns and LIMIT don't match the shown result objects;
update the drizzle import to include desc (alongside and, asc, eq, ne, lte, sql)
so the call to desc(ensIndexerSchema.registration.start) is valid, and then make
the SELECT and LIMIT in the SQL example consistent with the JavaScript query and
example output—either change the SQL SELECT to return the same fields as
recentRegistrations (canonicalName, expiry, start,
registrationType/registration.type, ownerId, domainId) and set LIMIT 5, or alter
the JS select to include grace_period/base/premium/registration_type and use
LIMIT 15 to match the displayed result—ensure recentRegistrations, desc, and the
SQL SELECT/LIMIT are aligned.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 246d12cd-2c73-4f09-9279-aed3c5020bc8
📒 Files selected for processing (20)
docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.tsdocs/ensnode.io/src/components/molecules/EnsDbReaderIntro.astrodocs/ensnode.io/src/content/docs/docs/integrate/index.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-by-name.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-events.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domains-fuzzy-search-by-name.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/expiring-registrations.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/indexing-status.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/latest-registrations.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/subdomains-by-parent-name.mdxdocs/ensnode.io/src/data/unigraph-examples/account-domains.tsdocs/ensnode.io/src/data/unigraph-examples/domain-by-name.tsdocs/ensnode.io/src/data/unigraph-examples/domain-events.tsdocs/ensnode.io/src/data/unigraph-examples/domains-fuzzy-search-by-name.tsdocs/ensnode.io/src/data/unigraph-examples/expiring-registrations.tsdocs/ensnode.io/src/data/unigraph-examples/indexing-status.tsdocs/ensnode.io/src/data/unigraph-examples/latest-registrations.tsdocs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.tsdocs/ensnode.io/src/data/unigraph-examples/types.ts
66e5135 to
2b41753
Compare
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts (1)
98-104: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winAlign SDK field selection with the SQL example.
The SQL snippet (lines 8-17) selects
grace_period,base, andpremiumfrom the registration table, but the SDK.select()block omits these fields. This creates an inconsistency between the two examples—users comparing SQL vs SDK approaches will see different output shapes.🔄 Suggested alignment
const recentRegistrations = await ensDb .select({ canonicalName: ensIndexerSchema.domain.canonicalName, expiry: ensIndexerSchema.registration.expiry, start: ensIndexerSchema.registration.start, + gracePeriod: ensIndexerSchema.registration.gracePeriod, + base: ensIndexerSchema.registration.base, + premium: ensIndexerSchema.registration.premium, registrationType: ensIndexerSchema.registration.type, ownerId: ensIndexerSchema.domain.ownerId, domainId: ensIndexerSchema.domain.id, })Then update the SDK result array (lines 135-181) to include
gracePeriod,base, andpremiumin each row to match the SQL result payload.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts` around lines 98 - 104, The SDK .select(...) call currently selects canonicalName, expiry, start, registrationType, ownerId, and domainId but omits the registration fields selected in the SQL example; update the .select invocation to also include ensIndexerSchema.registration.grace_period, ensIndexerSchema.registration.base, and ensIndexerSchema.registration.premium (mapped to SDK names like gracePeriod, base, premium as needed) so the SDK projection matches the SQL example, and then update the example SDK result array (the result rows shown later) to add gracePeriod, base, and premium to each row so the returned payload shape mirrors the SQL output.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/ensapi/src/handlers/api/test/test-queries-api.ts`:
- Around line 165-207: The /fuzzy-search route handler lacks input validation
and error handling; add a Zod schema and apply the validate() middleware to
parse/validate query params (q as non-empty string and limit as a positive
integer with a sensible default) for the app.get("/fuzzy-search", ...) route,
then wrap the database calls that use di.context.ensDb (the sqlResult and
drizzleResult queries) in a try-catch and call the existing errorResponse helper
in the catch to return a formatted error and avoid throwing raw errors to the
client.
- Around line 211-285: The /expiring route handler (app.get("/expiring")) lacks
input validation and error handling: create a Zod schema for start, end, and
limit and apply the validate() middleware to the route (use the same param names
used in the handler), then wrap the database calls that use ensDb and
ensIndexerSchema in a try-catch and return errors via the errorResponse helper;
on validation success parse and pass the validated start/end/limit into the
query and keep returning jsonBigInt on success.
- Around line 60-122: The /subdomains handler lacks input validation, error
handling, explicit missing-parent responses, and contains a debug console.log;
update the app.get("/subdomains", async (c) => { ... }) route to: validate query
params using a Zod schema (name:string, limit:number) via the validate()
middleware, wrap the database work that uses ensDb and ensIndexerSchema in a
try-catch and return errors using the errorResponse helper on catch, remove the
console.log(subdomains) call, and when parentDomain or
parentDomain.subregistryId is falsy return a clear errorResponse (e.g., 404 or
validation-style error) instead of falling through to an implicit undefined
return. Ensure you reference the existing symbols parentDomain and subdomains
when implementing these checks.
- Around line 392-445: The /domain-events route handler is missing input
validation and error handling; add a Zod schema for the query params (validate
name as string and limit as optional positive integer with a max), apply the
validate() middleware to this route so the handler uses the validated values
instead of raw c.req.query, and wrap the DB calls (the RAW SQL block and the
DRIZZLE select chain) in a try-catch that returns the standardized
errorResponse(...) on failure (use the same errorResponse helper used elsewhere
in this app); refer to the route handler for "/domain-events", the local
variables name and limit, and the DB usage via ensDb, ensIndexerSchema to locate
where to apply the validate() middleware and try-catch.
- Around line 26-57: The GET /domain-by-name handler is missing input
validation, lacks error handling, and contains a debug console.log; add a Zod
schema for the "name" query param and call the existing validate() middleware
(from apps/ensapi/src/lib/handlers/validate.ts) to validate c.req.query before
running DB logic, wrap the DB calls in a try-catch and on error return the
shared errorResponse(...) helper (from
apps/ensapi/src/lib/handlers/error-response.ts) with the caught error, and
remove the console.log(vitalik) statement; keep using the same
functions/variables in the handler (app.get("/domain-by-name"), ensDb,
ensIndexerSchema, jsonBigInt) but ensure validation runs first and DB errors are
caught and mapped to errorResponse.
- Around line 125-162: Replace the hardcoded owner and limit in the
app.get("/account-domains", async (c) => { ... }) handler by reading
c.req.query("owner") and c.req.query("limit"), add a Zod schema for those query
params and apply the existing validate() middleware for this route, wrap the
database calls (ensDb.execute and ensDb.select(...) usages referencing
ensIndexerSchema) in a try-catch and call the shared errorResponse helper on
failure, and ensure the successful response still returns jsonBigInt({ owner,
sql: sqlResult.rows, drizzle: drizzleResult }) after parsing/normalizing the
validated limit to a number.
- Around line 288-355: The /recent-registrations route handler is missing input
validation and error handling; add a Zod schema for the query param (limit) and
apply the validate() middleware before this handler, and wrap the DB calls
(ensDb.execute and the Drizzle query producing sqlResult and drizzleResult) in a
try-catch that returns the centralized errorResponse helper on failure; ensure
the validated limit is used (instead of raw parseInt) and that any caught error
is passed to errorResponse so the route fails gracefully.
- Around line 358-389: The /permissions handler returns inconsistent data and
lacks validation/error handling: validate the incoming user query using the
project's Zod schema via the validate() middleware, wrap the DB calls (the raw
SQL execute returning sqlResult and the Drizzle select producing drizzleResult)
in a try-catch and call the errorResponse helper on failure, and return
sqlResult.rows (not sqlResult) alongside drizzleResult in the jsonBigInt
response; update the app.get("/permissions") handler to perform these changes
around the existing ensDb/ensIndexerSchema usage so consumers always receive the
same array format and errors are handled.
---
Outside diff comments:
In `@docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts`:
- Around line 98-104: The SDK .select(...) call currently selects canonicalName,
expiry, start, registrationType, ownerId, and domainId but omits the
registration fields selected in the SQL example; update the .select invocation
to also include ensIndexerSchema.registration.grace_period,
ensIndexerSchema.registration.base, and ensIndexerSchema.registration.premium
(mapped to SDK names like gracePeriod, base, premium as needed) so the SDK
projection matches the SQL example, and then update the example SDK result array
(the result rows shown later) to add gracePeriod, base, and premium to each row
so the returned payload shape mirrors the SQL output.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 829bd0dd-5833-4726-892a-6bdd6fa62b2f
📒 Files selected for processing (11)
apps/ensapi/src/handlers/api/router.tsapps/ensapi/src/handlers/api/test/test-queries-api.tsdocs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.tsdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-by-name.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-events.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/expiring-registrations.mdxdocs/ensnode.io/src/data/unigraph-examples/account-domains.tsdocs/ensnode.io/src/data/unigraph-examples/expiring-registrations.tsdocs/ensnode.io/src/data/unigraph-examples/indexing-status.tsdocs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts
| app.get("/domain-by-name", async (c) => { | ||
| const name = c.req.query("name") || "vitalik.eth"; | ||
| const { ensDb, ensIndexerSchema } = di.context; | ||
|
|
||
| // RAW SQL | ||
| const sqlResult = await ensDb.execute(sql` | ||
| SELECT | ||
| id, | ||
| type, | ||
| canonical_name, | ||
| canonical_node, | ||
| owner_id | ||
| FROM ${ensIndexerSchema.domain} d | ||
| WHERE d.canonical_name = ${name} AND d.canonical = true; | ||
| `); | ||
|
|
||
| // DRIZZLE | ||
| const [vitalik] = await ensDb | ||
| .select({ | ||
| id: ensIndexerSchema.domain.id, | ||
| type: ensIndexerSchema.domain.type, | ||
| canonicalName: ensIndexerSchema.domain.canonicalName, | ||
| canonicalNode: ensIndexerSchema.domain.canonicalNode, | ||
| ownerId: ensIndexerSchema.domain.ownerId, | ||
| }) | ||
| .from(ensIndexerSchema.domain) | ||
| .where(sql`${ensIndexerSchema.domain.canonicalName} = ${name}`); | ||
|
|
||
| console.log(vitalik); | ||
|
|
||
| return jsonBigInt({ name, sql: sqlResult.rows[0], drizzle: vitalik }); | ||
| }); |
There was a problem hiding this comment.
Add input validation and error handling; remove debug logging.
This endpoint has three critical issues:
-
Missing input validation: As per coding guidelines, use existing Hono validation middleware (Zod schemas +
validate()fromapps/ensapi/src/lib/handlers/validate.ts) for validating API requests. Thenameparameter should be validated. -
No error handling: Database queries can fail but there's no try-catch block or error handling. Use the shared
errorResponsehelper fromapps/ensapi/src/lib/handlers/error-response.tsfor error responses. -
Debug logging: Remove the
console.log(vitalik)statement on line 54.
As per coding guidelines for apps/ensapi/**/*.ts files: validation middleware and errorResponse helper should be used.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/ensapi/src/handlers/api/test/test-queries-api.ts` around lines 26 - 57,
The GET /domain-by-name handler is missing input validation, lacks error
handling, and contains a debug console.log; add a Zod schema for the "name"
query param and call the existing validate() middleware (from
apps/ensapi/src/lib/handlers/validate.ts) to validate c.req.query before running
DB logic, wrap the DB calls in a try-catch and on error return the shared
errorResponse(...) helper (from apps/ensapi/src/lib/handlers/error-response.ts)
with the caught error, and remove the console.log(vitalik) statement; keep using
the same functions/variables in the handler (app.get("/domain-by-name"), ensDb,
ensIndexerSchema, jsonBigInt) but ensure validation runs first and DB errors are
caught and mapped to errorResponse.
| app.get("/subdomains", async (c) => { | ||
| const name = c.req.query("name") || "eth"; | ||
| const limit = parseInt(c.req.query("limit") || "5", 10); | ||
| const { ensDb, ensIndexerSchema } = di.context; | ||
|
|
||
| // RAW SQL | ||
| const sqlResult = await ensDb.execute(sql` | ||
| WITH parent AS ( | ||
| SELECT subregistry_id | ||
| FROM ${ensIndexerSchema.domain} | ||
| WHERE canonical_name = ${name} | ||
| AND canonical = true | ||
| ) | ||
| SELECT | ||
| d.type, | ||
| d.canonical_name, | ||
| d.canonical_node, | ||
| d.id | ||
| FROM ${ensIndexerSchema.domain} d | ||
| JOIN parent p ON d.registry_id = p.subregistry_id | ||
| WHERE d.canonical = true | ||
| ORDER BY d.canonical_name | ||
| LIMIT ${limit}; | ||
| `); | ||
|
|
||
| // DRIZZLE - two-step approach (find parent, then children) | ||
|
|
||
| // Two-step: | ||
| // 1) find parent domain, | ||
| // 2) query children by parent domain's subregistryId. | ||
| const [parentDomain] = await ensDb | ||
| .select({ subregistryId: ensIndexerSchema.domain.subregistryId }) | ||
| .from(ensIndexerSchema.domain) | ||
| .where( | ||
| and( | ||
| sql`${ensIndexerSchema.domain.canonicalName} = ${name}`, | ||
| eq(ensIndexerSchema.domain.canonical, true), | ||
| ), | ||
| ); | ||
|
|
||
| if (parentDomain?.subregistryId) { | ||
| const subdomains = await ensDb | ||
| .select({ | ||
| type: ensIndexerSchema.domain.type, | ||
| canonicalName: ensIndexerSchema.domain.canonicalName, | ||
| canonicalNode: ensIndexerSchema.domain.canonicalNode, | ||
| id: ensIndexerSchema.domain.id, | ||
| }) | ||
| .from(ensIndexerSchema.domain) | ||
| .where( | ||
| and( | ||
| eq(ensIndexerSchema.domain.registryId, parentDomain.subregistryId), | ||
| eq(ensIndexerSchema.domain.canonical, true), | ||
| ), | ||
| ) | ||
| .orderBy(asc(ensIndexerSchema.domain.canonicalName)) | ||
| .limit(limit); | ||
|
|
||
| console.log(subdomains); | ||
|
|
||
| return jsonBigInt({ name, sql: sqlResult.rows, drizzle: subdomains }); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Add input validation, error handling, and explicit error response for missing parent.
Multiple issues:
-
Missing input validation: Use Zod schemas with
validate()middleware to validatenameandlimitparameters as per coding guidelines. -
No error handling: Wrap database queries in try-catch and use
errorResponsehelper. -
Debug logging: Remove
console.log(subdomains)on line 118. -
Implicit undefined return: When
parentDomain?.subregistryIdis falsy (lines 100-122), the endpoint returnsundefinedimplicitly. Return an explicit error response instead.
As per coding guidelines for apps/ensapi/**/*.ts files: validation middleware and errorResponse helper should be used.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/ensapi/src/handlers/api/test/test-queries-api.ts` around lines 60 - 122,
The /subdomains handler lacks input validation, error handling, explicit
missing-parent responses, and contains a debug console.log; update the
app.get("/subdomains", async (c) => { ... }) route to: validate query params
using a Zod schema (name:string, limit:number) via the validate() middleware,
wrap the database work that uses ensDb and ensIndexerSchema in a try-catch and
return errors using the errorResponse helper on catch, remove the
console.log(subdomains) call, and when parentDomain or
parentDomain.subregistryId is falsy return a clear errorResponse (e.g., 404 or
validation-style error) instead of falling through to an implicit undefined
return. Ensure you reference the existing symbols parentDomain and subdomains
when implementing these checks.
| app.get("/account-domains", async (c) => { | ||
| const { ensDb, ensIndexerSchema } = di.context; | ||
| const owner = "0xffffffffff52d316b7bd028358089bc8066b8f80"; | ||
| const limit = 10; | ||
|
|
||
| // RAW SQL | ||
| const sqlResult = await ensDb.execute(sql` | ||
| SELECT | ||
| d.type, | ||
| d.canonical_name, | ||
| d.canonical_node, | ||
| d.id, | ||
| d.owner_id | ||
| FROM ${ensIndexerSchema.domain} d | ||
| WHERE d.canonical = true | ||
| AND d.owner_id = ${owner} | ||
| ORDER BY d.canonical_name | ||
| LIMIT ${limit} | ||
| `); | ||
|
|
||
| // DRIZZLE | ||
| const drizzleResult = await ensDb | ||
| .select({ | ||
| type: ensIndexerSchema.domain.type, | ||
| canonicalName: ensIndexerSchema.domain.canonicalName, | ||
| canonicalNode: ensIndexerSchema.domain.canonicalNode, | ||
| id: ensIndexerSchema.domain.id, | ||
| ownerId: ensIndexerSchema.domain.ownerId, | ||
| }) | ||
| .from(ensIndexerSchema.domain) | ||
| .where( | ||
| and(eq(ensIndexerSchema.domain.ownerId, owner), eq(ensIndexerSchema.domain.canonical, true)), | ||
| ) | ||
| .orderBy(asc(ensIndexerSchema.domain.canonicalName)) | ||
| .limit(limit); | ||
|
|
||
| return jsonBigInt({ owner, sql: sqlResult.rows, drizzle: drizzleResult }); | ||
| }); |
There was a problem hiding this comment.
Use query parameters instead of hardcoded values; add validation and error handling.
Multiple issues:
-
Hardcoded values: Lines 127-128 hardcode
ownerandlimitinstead of reading from query parameters as suggested by the comment on line 124. Usec.req.query("owner")andc.req.query("limit")like other endpoints. -
Missing input validation: Use Zod schemas with
validate()middleware to validate query parameters as per coding guidelines. -
No error handling: Wrap database queries in try-catch and use
errorResponsehelper.
As per coding guidelines for apps/ensapi/**/*.ts files: validation middleware and errorResponse helper should be used.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/ensapi/src/handlers/api/test/test-queries-api.ts` around lines 125 -
162, Replace the hardcoded owner and limit in the app.get("/account-domains",
async (c) => { ... }) handler by reading c.req.query("owner") and
c.req.query("limit"), add a Zod schema for those query params and apply the
existing validate() middleware for this route, wrap the database calls
(ensDb.execute and ensDb.select(...) usages referencing ensIndexerSchema) in a
try-catch and call the shared errorResponse helper on failure, and ensure the
successful response still returns jsonBigInt({ owner, sql: sqlResult.rows,
drizzle: drizzleResult }) after parsing/normalizing the validated limit to a
number.
| app.get("/fuzzy-search", async (c) => { | ||
| const q = c.req.query("q") || "vitalik"; | ||
| const limit = parseInt(c.req.query("limit") || "5", 10); | ||
| const { ensDb, ensIndexerSchema } = di.context; | ||
|
|
||
| // RAW SQL - pg_trgm similarity operator (%) and similarity() ranking | ||
| const sqlResult = await ensDb.execute(sql`SELECT | ||
| id, | ||
| type, | ||
| canonical_name, | ||
| canonical_node, | ||
| owner_id, | ||
| similarity(canonical_name, ${q}) as name_similarity | ||
| FROM ${ensIndexerSchema.domain} | ||
| WHERE canonical_name % ${q} | ||
| AND canonical = true | ||
| ORDER BY name_similarity DESC | ||
| LIMIT ${limit}; | ||
| `); | ||
|
|
||
| // DRIZZLE - same pg_trgm query using inline SQL expressions | ||
| const drizzleResult = await ensDb | ||
| .select({ | ||
| canonicalName: ensIndexerSchema.domain.canonicalName, | ||
| canonicalDepth: ensIndexerSchema.domain.canonicalDepth, | ||
| ownerId: ensIndexerSchema.domain.ownerId, | ||
| nameSimilarity: sql<number>`similarity(${ensIndexerSchema.domain.canonicalName}, ${q})`.as( | ||
| "name_similarity", | ||
| ), | ||
| id: ensIndexerSchema.domain.id, | ||
| }) | ||
| .from(ensIndexerSchema.domain) | ||
| .where( | ||
| and( | ||
| sql`${ensIndexerSchema.domain.canonicalName} % ${q}`, | ||
| eq(ensIndexerSchema.domain.canonical, true), | ||
| ), | ||
| ) | ||
| .orderBy(sql`name_similarity DESC`) | ||
| .limit(limit); | ||
|
|
||
| return jsonBigInt({ q, sql: sqlResult.rows, drizzle: drizzleResult }); | ||
| }); |
There was a problem hiding this comment.
Add input validation and error handling.
Missing:
-
Input validation: Use Zod schemas with
validate()middleware to validateqandlimitparameters as per coding guidelines. -
Error handling: Wrap database queries in try-catch and use
errorResponsehelper.
As per coding guidelines for apps/ensapi/**/*.ts files: validation middleware and errorResponse helper should be used.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/ensapi/src/handlers/api/test/test-queries-api.ts` around lines 165 -
207, The /fuzzy-search route handler lacks input validation and error handling;
add a Zod schema and apply the validate() middleware to parse/validate query
params (q as non-empty string and limit as a positive integer with a sensible
default) for the app.get("/fuzzy-search", ...) route, then wrap the database
calls that use di.context.ensDb (the sqlResult and drizzleResult queries) in a
try-catch and call the existing errorResponse helper in the catch to return a
formatted error and avoid throwing raw errors to the client.
| app.get("/expiring", async (c) => { | ||
| const start = parseInt(c.req.query("start") || "0", 10); | ||
| const end = parseInt( | ||
| c.req.query("end") || String(Math.floor(Date.now() / 1000) + 86400 * 90), | ||
| 10, | ||
| ); | ||
| const limit = parseInt(c.req.query("limit") || "5", 10); | ||
| const { ensDb, ensIndexerSchema } = di.context; | ||
|
|
||
| // ── RAW SQL ── | ||
| // Use explicit >= / <= instead of BETWEEN for clarity. | ||
|
|
||
| const sqlResult = await ensDb.execute(sql`SELECT | ||
| d.canonical_name, | ||
| r.start, | ||
| r.expiry, | ||
| r.grace_period, | ||
| d.owner_id, | ||
| d.id as domain_id | ||
| FROM ${ensIndexerSchema.registration} r | ||
| JOIN ${ensIndexerSchema.latestRegistrationIndex} lri | ||
| ON r.domain_id = lri.domain_id | ||
| AND r.registration_index = lri.registration_index | ||
| JOIN ${ensIndexerSchema.domain} d ON r.domain_id = d.id | ||
| WHERE r.expiry >= EXTRACT(EPOCH FROM NOW()) | ||
| AND r.expiry <= EXTRACT(EPOCH FROM NOW() + INTERVAL '3 days') | ||
| AND d.canonical = true | ||
| ORDER BY r.expiry ASC | ||
| LIMIT ${limit}; | ||
| `); | ||
|
|
||
| // ── DRIZZLE ORM ── | ||
| // gte / lte are the idiomatic Drizzle equivalent of >= / <=. | ||
| const drizzleResult = await ensDb | ||
| .select({ | ||
| canonicalName: ensIndexerSchema.domain.canonicalName, | ||
| expiry: ensIndexerSchema.registration.expiry, | ||
| start: ensIndexerSchema.registration.start, | ||
| gracePeriod: ensIndexerSchema.registration.gracePeriod, | ||
| ownerId: ensIndexerSchema.domain.ownerId, | ||
| domainId: ensIndexerSchema.domain.id, | ||
| }) | ||
| .from(ensIndexerSchema.registration) | ||
| .innerJoin( | ||
| ensIndexerSchema.latestRegistrationIndex, | ||
| and( | ||
| eq( | ||
| ensIndexerSchema.registration.domainId, | ||
| ensIndexerSchema.latestRegistrationIndex.domainId, | ||
| ), | ||
| eq( | ||
| ensIndexerSchema.registration.registrationIndex, | ||
| ensIndexerSchema.latestRegistrationIndex.registrationIndex, | ||
| ), | ||
| ), | ||
| ) | ||
| .innerJoin( | ||
| ensIndexerSchema.domain, | ||
| eq(ensIndexerSchema.registration.domainId, ensIndexerSchema.domain.id), | ||
| ) | ||
| .where( | ||
| and( | ||
| gte(ensIndexerSchema.registration.expiry, sql`EXTRACT(EPOCH FROM NOW())`), | ||
| lte( | ||
| ensIndexerSchema.registration.expiry, | ||
| sql`EXTRACT(EPOCH FROM NOW() + INTERVAL '3 days')`, | ||
| ), | ||
| eq(ensIndexerSchema.domain.canonical, true), | ||
| ), | ||
| ) | ||
| .orderBy(asc(ensIndexerSchema.registration.expiry)) | ||
| .limit(limit); | ||
|
|
||
| return jsonBigInt({ start, end, sql: sqlResult.rows, drizzle: drizzleResult }); | ||
| }); |
There was a problem hiding this comment.
Add input validation and error handling.
Missing:
-
Input validation: Use Zod schemas with
validate()middleware to validatestart,end, andlimitparameters as per coding guidelines. -
Error handling: Wrap database queries in try-catch and use
errorResponsehelper.
As per coding guidelines for apps/ensapi/**/*.ts files: validation middleware and errorResponse helper should be used.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/ensapi/src/handlers/api/test/test-queries-api.ts` around lines 211 -
285, The /expiring route handler (app.get("/expiring")) lacks input validation
and error handling: create a Zod schema for start, end, and limit and apply the
validate() middleware to the route (use the same param names used in the
handler), then wrap the database calls that use ensDb and ensIndexerSchema in a
try-catch and return errors via the errorResponse helper; on validation success
parse and pass the validated start/end/limit into the query and keep returning
jsonBigInt on success.
| app.get("/recent-registrations", async (c) => { | ||
| const limit = parseInt(c.req.query("limit") || "50", 10); | ||
| const { ensDb, ensIndexerSchema } = di.context; | ||
|
|
||
| // RAW SQL | ||
| const sqlResult = await ensDb.execute(sql` | ||
| SELECT | ||
| d.canonical_name, | ||
| r.start, | ||
| r.expiry, | ||
| r.grace_period, | ||
| r.base, | ||
| r.premium, | ||
| r.type as registration_type, | ||
| d.owner_id, | ||
| d.id as domain_id | ||
| FROM ${ensIndexerSchema.registration} r | ||
| JOIN ${ensIndexerSchema.latestRegistrationIndex} lri | ||
| ON r.domain_id = lri.domain_id | ||
| AND r.registration_index = lri.registration_index | ||
| JOIN ${ensIndexerSchema.domain} d ON r.domain_id = d.id | ||
| WHERE r.start <= EXTRACT(EPOCH FROM NOW()) | ||
| AND d.canonical = true | ||
| AND r.type <> 'NameWrapper' | ||
| ORDER BY r.start DESC | ||
| LIMIT ${limit}; | ||
| `); | ||
|
|
||
| // DRIZZLE | ||
| const drizzleResult = await ensDb | ||
| .select({ | ||
| canonicalName: ensIndexerSchema.domain.canonicalName, | ||
| expiry: ensIndexerSchema.registration.expiry, | ||
| start: ensIndexerSchema.registration.start, | ||
| registrationType: ensIndexerSchema.registration.type, | ||
| ownerId: ensIndexerSchema.domain.ownerId, | ||
| domainId: ensIndexerSchema.domain.id, | ||
| }) | ||
| .from(ensIndexerSchema.registration) | ||
| .innerJoin( | ||
| ensIndexerSchema.latestRegistrationIndex, | ||
| and( | ||
| eq( | ||
| ensIndexerSchema.registration.domainId, | ||
| ensIndexerSchema.latestRegistrationIndex.domainId, | ||
| ), | ||
| eq( | ||
| ensIndexerSchema.registration.registrationIndex, | ||
| ensIndexerSchema.latestRegistrationIndex.registrationIndex, | ||
| ), | ||
| ), | ||
| ) | ||
| .innerJoin( | ||
| ensIndexerSchema.domain, | ||
| eq(ensIndexerSchema.registration.domainId, ensIndexerSchema.domain.id), | ||
| ) | ||
| .where( | ||
| and( | ||
| lte(ensIndexerSchema.registration.start, sql`EXTRACT(EPOCH FROM NOW())`), | ||
| eq(ensIndexerSchema.domain.canonical, true), | ||
| ne(ensIndexerSchema.registration.type, "NameWrapper"), | ||
| ), | ||
| ) | ||
| .orderBy(desc(ensIndexerSchema.registration.start)) | ||
| .limit(limit); | ||
|
|
||
| return jsonBigInt({ limit, sql: sqlResult.rows, drizzle: drizzleResult }); | ||
| }); |
There was a problem hiding this comment.
Add input validation and error handling.
Missing:
-
Input validation: Use Zod schemas with
validate()middleware to validatelimitparameter as per coding guidelines. -
Error handling: Wrap database queries in try-catch and use
errorResponsehelper.
As per coding guidelines for apps/ensapi/**/*.ts files: validation middleware and errorResponse helper should be used.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/ensapi/src/handlers/api/test/test-queries-api.ts` around lines 288 -
355, The /recent-registrations route handler is missing input validation and
error handling; add a Zod schema for the query param (limit) and apply the
validate() middleware before this handler, and wrap the DB calls (ensDb.execute
and the Drizzle query producing sqlResult and drizzleResult) in a try-catch that
returns the centralized errorResponse helper on failure; ensure the validated
limit is used (instead of raw parseInt) and that any caught error is passed to
errorResponse so the route fails gracefully.
| app.get("/permissions", async (c) => { | ||
| const user = c.req.query("user") || "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"; | ||
| const { ensDb, ensIndexerSchema } = di.context; | ||
|
|
||
| // RAW SQL | ||
| const sqlResult = await ensDb.execute(sql` | ||
| SELECT pu.id, pu.chain_id, pu.address as contract_address, | ||
| pu.resource, pu.roles | ||
| FROM ${ensIndexerSchema.permissionsUser} pu | ||
| WHERE pu.user = ${user} | ||
| ORDER BY pu.chain_id, pu.address, pu.resource | ||
| `); | ||
|
|
||
| // DRIZZLE | ||
| const drizzleResult = await ensDb | ||
| .select({ | ||
| id: ensIndexerSchema.permissionsUser.id, | ||
| chainId: ensIndexerSchema.permissionsUser.chainId, | ||
| contractAddress: ensIndexerSchema.permissionsUser.address, | ||
| resource: ensIndexerSchema.permissionsUser.resource, | ||
| roles: ensIndexerSchema.permissionsUser.roles, | ||
| }) | ||
| .from(ensIndexerSchema.permissionsUser) | ||
| .where(sql`${ensIndexerSchema.permissionsUser.user} = ${user}`) | ||
| .orderBy( | ||
| asc(ensIndexerSchema.permissionsUser.chainId), | ||
| asc(ensIndexerSchema.permissionsUser.address), | ||
| asc(ensIndexerSchema.permissionsUser.resource), | ||
| ); | ||
|
|
||
| return jsonBigInt({ user, sql: sqlResult, drizzle: drizzleResult }); | ||
| }); |
There was a problem hiding this comment.
Fix inconsistent response format; add input validation and error handling.
Multiple issues:
-
Inconsistent response format: Line 388 returns
sqlResultinstead ofsqlResult.rows. All other endpoints return.rowsto extract the result array. This inconsistency could confuse API consumers. -
Missing input validation: Use Zod schemas with
validate()middleware to validateuserparameter as per coding guidelines. -
No error handling: Wrap database queries in try-catch and use
errorResponsehelper.
🔧 Proposed fix for response format
- return jsonBigInt({ user, sql: sqlResult, drizzle: drizzleResult });
+ return jsonBigInt({ user, sql: sqlResult.rows, drizzle: drizzleResult });As per coding guidelines for apps/ensapi/**/*.ts files: validation middleware and errorResponse helper should be used.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/ensapi/src/handlers/api/test/test-queries-api.ts` around lines 358 -
389, The /permissions handler returns inconsistent data and lacks
validation/error handling: validate the incoming user query using the project's
Zod schema via the validate() middleware, wrap the DB calls (the raw SQL execute
returning sqlResult and the Drizzle select producing drizzleResult) in a
try-catch and call the errorResponse helper on failure, and return
sqlResult.rows (not sqlResult) alongside drizzleResult in the jsonBigInt
response; update the app.get("/permissions") handler to perform these changes
around the existing ensDb/ensIndexerSchema usage so consumers always receive the
same array format and errors are handled.
| <SqlResultTable rows={sql.result} /> | ||
|
|
||
| <StaticExampleNote class="px-5 pb-5">{sql.resultNote ?? defaultResultNote}</StaticExampleNote> | ||
| <StaticExampleNote class="px-5 pb-5" set:html={sql.resultNote ?? defaultResultNote} /> |
| <StaticExampleNote class="px-5 pb-5"> | ||
| {ensDbSdk.resultNote ?? defaultResultNote} | ||
| </StaticExampleNote> | ||
| <StaticExampleNote class="px-5 pb-5" set:html={ensDbSdk.resultNote ?? defaultResultNote} /> |
| export interface CodeExample { | ||
| codeSnippet: string; | ||
| result: unknown; | ||
| resultNote?: string; | ||
| } |
| FROM "ensindexer_0".domains | ||
| WHERE __canonicalNamePrefix % 'reverse' | ||
| AND canonical = true | ||
| ORDER BY name_similarity DESC |
| const q = "vitalik"; | ||
| const limit = 5; |
| Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration) | ||
| ::: | ||
|
|
||
| Fetch recent events for a Domain by its canonical name. This example joins the `events`, `domain_events`, and `domains` tables to retrieve domain events associated with the `vitalik.eth` name. See [Connect](/docs/integrate/unigraph/examples) for setup. |
| JOIN parent p ON d.registry_id = p.subregistry_id | ||
| WHERE d.canonical = true | ||
| ORDER BY d.canonical_name | ||
| LIMIT 5; |
| FROM "ensindexer_0".domains d | ||
| WHERE d.canonical = true | ||
| AND d.owner_id = '0xffffffffff52d316b7bd028358089bc8066b8f80' | ||
| ORDER BY d.canonical_name | ||
| LIMIT 10;`, |
| ), | ||
| ) | ||
| .orderBy(asc(ensIndexerSchema.domain.canonicalName)) | ||
| .limit(limit); |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts (1)
102-108: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueConsider aligning SQL and SDK field selections for consistency.
The SQL example selects
grace_period,base, andpremium(lines 15-17), but the SDK example omits these fields. While each variant is internally consistent with its result, documentation examples are clearer when both SQL and SDK demonstrate the same fields.📋 Optional enhancement to match SQL fields
.select({ canonicalName: ensIndexerSchema.domain.canonicalName, expiry: ensIndexerSchema.registration.expiry, start: ensIndexerSchema.registration.start, + gracePeriod: ensIndexerSchema.registration.gracePeriod, + base: ensIndexerSchema.registration.base, + premium: ensIndexerSchema.registration.premium, registrationType: ensIndexerSchema.registration.type, ownerId: ensIndexerSchema.domain.ownerId, domainId: ensIndexerSchema.domain.id, })Then update the SDK result array to include those fields.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts` around lines 102 - 108, The SDK .select block should include the same registration pricing fields as the SQL example: add ensIndexerSchema.registration.grace_period, ensIndexerSchema.registration.base, and ensIndexerSchema.registration.premium to the .select call (alongside expiry, start, and type), then update the SDK result array/object in the example to include the corresponding grace_period, base, and premium entries so both SQL and SDK examples present the same fields.docs/ensnode.io/src/data/unigraph-examples/domains-fuzzy-search-by-name.ts (1)
55-55:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winFix the SDK query parameter to match the SQL example.
The SDK snippet declares
const q = "vitalik";on line 55, but the SQL example searches for'reverse'(lines 16, 19) and both result arrays show domains matching "reverse" (e.g., "reverse", "addr.reverse"). Users copying the SDK snippet will query for "vitalik" but expect "reverse" results, making the example non-reproducible.🔧 Proposed fix
-const q = "vitalik"; +const q = "reverse";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/ensnode.io/src/data/unigraph-examples/domains-fuzzy-search-by-name.ts` at line 55, The SDK example defines const q = "vitalik" which doesn't match the SQL example that searches for "reverse"; update the SDK query parameter (the const q variable in this file) to use "reverse" so the SDK snippet returns the same results as the SQL example and the shown result arrays like "reverse" and "addr.reverse" are reproducible.docs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.ts (1)
28-135: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueMinor data inconsistency between SQL and SDK result snapshots.
The 5th result row differs between SQL and SDK examples for domain "sfmpfv44d0mig.eth":
- SQL result (lines 54-58):
type: "ENSv1Domain", ID ending with...0xb6fb...- SDK result (lines 129-134):
type: "ENSv2Domain", ID ending with...0x64c8...While both may be valid domain records (if the name exists in both v1 and v2), documentation examples are more reliable when SQL and SDK variants return identical result sets for the same query. This discrepancy could stem from snapshots captured at different times or a subtle ordering difference (
canonical_namevs__canonicalNamePrefix).Consider re-capturing both snapshots from the same database state, or explicitly note in the documentation that result ordering for tied names may vary.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.ts` around lines 28 - 135, The SQL vs SDK example snapshots diverge for the "sfmpfv44d0mig.eth" row (fields canonical_name/canonicalName and type/id mismatch); re-run both the SQL and SDK queries from the same database state, ensure the same ordering key (use __canonicalNamePrefix in both examples or explicitly sort by canonical_name) and then update the two result snapshots so the type and id for "sfmpfv44d0mig.eth" match (or add a short note explaining that tied names may yield different domain versions); update the result arrays (result in SQL block and result in SDK block) to be identical after re-capture.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@docs/ensnode.io/src/data/unigraph-examples/domains-fuzzy-search-by-name.ts`:
- Line 55: The SDK example defines const q = "vitalik" which doesn't match the
SQL example that searches for "reverse"; update the SDK query parameter (the
const q variable in this file) to use "reverse" so the SDK snippet returns the
same results as the SQL example and the shown result arrays like "reverse" and
"addr.reverse" are reproducible.
In `@docs/ensnode.io/src/data/unigraph-examples/latest-registrations.ts`:
- Around line 102-108: The SDK .select block should include the same
registration pricing fields as the SQL example: add
ensIndexerSchema.registration.grace_period, ensIndexerSchema.registration.base,
and ensIndexerSchema.registration.premium to the .select call (alongside expiry,
start, and type), then update the SDK result array/object in the example to
include the corresponding grace_period, base, and premium entries so both SQL
and SDK examples present the same fields.
In `@docs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.ts`:
- Around line 28-135: The SQL vs SDK example snapshots diverge for the
"sfmpfv44d0mig.eth" row (fields canonical_name/canonicalName and type/id
mismatch); re-run both the SQL and SDK queries from the same database state,
ensure the same ordering key (use __canonicalNamePrefix in both examples or
explicitly sort by canonical_name) and then update the two result snapshots so
the type and id for "sfmpfv44d0mig.eth" match (or add a short note explaining
that tied names may yield different domain versions); update the result arrays
(result in SQL block and result in SDK block) to be identical after re-capture.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 743b3c13-bdbf-4902-9e63-34fb17a09917
📒 Files selected for processing (15)
docs/ensnode.io/config/integrations/starlight/sidebar-topics/integrate.tsdocs/ensnode.io/src/components/molecules/unigraph-static-example/UnigraphStaticExample.astrodocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/account-domains.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/domain-events.mdxdocs/ensnode.io/src/content/docs/docs/integrate/unigraph/examples/expiring-registrations.mdxdocs/ensnode.io/src/data/unigraph-examples/account-domains.tsdocs/ensnode.io/src/data/unigraph-examples/domain-by-name.tsdocs/ensnode.io/src/data/unigraph-examples/domain-events.tsdocs/ensnode.io/src/data/unigraph-examples/domains-fuzzy-search-by-name.tsdocs/ensnode.io/src/data/unigraph-examples/expiring-registrations.tsdocs/ensnode.io/src/data/unigraph-examples/indexing-status.tsdocs/ensnode.io/src/data/unigraph-examples/latest-registrations.tsdocs/ensnode.io/src/data/unigraph-examples/subdomains-by-parent-name.tsdocs/ensnode.io/src/data/unigraph-examples/types.tsdocs/ensnode.io/src/data/unigraph-examples/utils.ts
| <SqlResultTable rows={sql.result} /> | ||
|
|
||
| <StaticExampleNote class="px-5 pb-5">{sql.resultNote ?? defaultResultNote}</StaticExampleNote> | ||
| <StaticExampleNote class="px-5 pb-5" set:html={sql.resultNote ?? defaultResultNote} /> |
| sdk: { | ||
| codeSnippet: `import { and, eq, sql } from "drizzle-orm"; | ||
|
|
||
| const q = "vitalik"; |
| FROM "ensindexer_0".domains d | ||
| WHERE d.canonical = true | ||
| AND d.owner_id = '0xffffffffff52d316b7bd028358089bc8066b8f80' | ||
| ORDER BY d.canonical_name |
| FROM "ensindexer_0".domains d | ||
| JOIN parent p ON d.registry_id = p.subregistry_id | ||
| WHERE d.canonical = true | ||
| ORDER BY d.canonical_name |
| @@ -0,0 +1,10 @@ | |||
| export interface CodeExample { | |||
| codeSnippet: string; | |||
| result: unknown; | |||
| similarity(canonical_name, 'reverse') as name_similarity, | ||
| id | ||
| FROM "ensindexer_0".domains | ||
| WHERE __canonicalNamePrefix % 'reverse' |
| Performing SQL queries on the ENS Unigraph requires that you have the `unigraph` plugin activated in your ENSNode instance. [Learn more](/docs/services/ensindexer/usage/configuration) | ||
| ::: | ||
|
|
||
| Fetch recent events for a Domain by its canonical name. This example joins the `events`, `domain_events`, and `domains` tables to retrieve domain events associated with the `vitalik.eth` name. See [Connect](/docs/integrate/unigraph/examples) for setup. |
There was a problem hiding this comment.
| Fetch recent events for a Domain by its canonical name. This example joins the `events`, `domain_events`, and `domains` tables to retrieve domain events associated with the `vitalik.eth` name. See [Connect](/docs/integrate/unigraph/examples) for setup. | |
| Fetch recent events for a Domain by its canonical name. This example joins the `events`, `domain_events`, and `domains` tables to retrieve domain events associated with the `wrapnation.eth` name. See [Connect](/docs/integrate/unigraph/examples) for setup. |
Documentation text mentions "vitalik.eth" but the actual example code uses "wrapnation.eth"
Lite PR
Tip: Review docs on the ENSNode PR process
Summary
Why
Testing
Notes for Reviewer (Optional)
Pre-Review Checklist (Blocking)