From 63ea433bb9479dc4d1053a9e16f6346abb855f57 Mon Sep 17 00:00:00 2001 From: 7487 <1042653432@qq.com> Date: Tue, 8 Sep 2026 11:19:03 +0800 Subject: [PATCH] docs(couchbase): cite code by name, not by line docs/providers/couchbase.md cited code by line number in 29 places on today's main (the 30th in #591, factory.ts:93, went with #629), plus one ConnectionModal.tsx:139 that the `.ts:` grep cannot see. Of the 29, only the six in introspect.ts and keyspace.ts still hold: the five that name a method beside the line all miss (connect() :335 -> :399, getCapabilities() :276 -> :299, getLabels() :293 -> :345, query() :408 -> :472, runMaintenance() :762 -> :869), and the unnamed ones land on closing braces, section banners and a comment in use-query-execution.ts. Every citation now names the declaration and links the file without a coordinate, the shape mongodb.md, postgres.md and clickhouse.md already use. No sentence changed meaning. The doc joins NAMED_CITATIONS with index.ts as its source and the 24 class members it cites, and that list's no-line-number test now reads `\.tsx?:\d` so the .tsx citation cannot come back either. Fixes #591 Co-Authored-By: Claude Fable 5.1 --- docs/providers/couchbase.md | 82 ++++++++++--------- ...provider-docs-monitoring-citations.test.ts | 36 +++++++- 2 files changed, 80 insertions(+), 38 deletions(-) diff --git a/docs/providers/couchbase.md b/docs/providers/couchbase.md index 6b1452e8..6d31410b 100644 --- a/docs/providers/couchbase.md +++ b/docs/providers/couchbase.md @@ -131,7 +131,7 @@ case 'couchbase': { } ``` -`connect()` ([index.ts:335](../../src/lib/db/providers/document/couchbase/index.ts)) proves +`connect()` ([`index.ts`](../../src/lib/db/providers/document/couchbase/index.ts)) proves reachability *and* credentials with one `GET /pools/default` — the cheapest call that needs no RBAC role beyond cluster read — then keeps the transport. `disconnect()` clears the transport's cached endpoint discovery; there are no sockets to close. API routes use `getOrCreateProvider()`, which @@ -172,7 +172,7 @@ operations. ### 3.2 The transport seam: one interface, one implementation Provider logic never calls `fetch`. It goes through `CouchbaseTransport` -([transport.ts:87](../../src/lib/db/providers/document/couchbase/transport.ts)), so adopting the SDK +([`transport.ts`](../../src/lib/db/providers/document/couchbase/transport.ts)), so adopting the SDK later would be one new file implementing the same contract rather than a rewrite: ```ts @@ -186,8 +186,8 @@ interface CouchbaseTransport { } ``` -The result type is deliberately **neutral** rather than the REST envelope -([transport.ts:45](../../src/lib/db/providers/document/couchbase/transport.ts)): +The result type, `CouchbaseQueryResult`, is deliberately **neutral** rather than the REST +envelope ([`transport.ts`](../../src/lib/db/providers/document/couchbase/transport.ts)): ```ts interface CouchbaseQueryResult { @@ -203,7 +203,7 @@ An interface shaped like `{ results, signature, status, metrics, errors }` would SDK adapter to fabricate fields only the REST API produces. Both sources produce the shape above without inventing anything. Errors follow the same rule: the transport throws a normalized `CouchbaseError { code, message, retriable }` -([transport.ts:105](../../src/lib/db/providers/document/couchbase/transport.ts)) whose `code` is a +([`transport.ts`](../../src/lib/db/providers/document/couchbase/transport.ts)) whose `code` is a single numeric space — SQL++ codes (3000, 4000, 13014, …) and HTTP codes (401, 403, 503) both land there, so provider-level mapping is one switch. @@ -221,18 +221,20 @@ are required for overview, performance and storage metrics under any transport. endpoint. Only the **management** port is stored (8091, or 18091 with TLS); the query endpoint comes from `GET /pools/default/nodeServices`, reading `nodesExt[].services.n1ql` (or `n1qlSSL` under TLS) and preferring `alternateAddresses.external` when present — which is what makes NAT, Docker port -mapping and Capella work -([http-transport.ts:445](../../src/lib/db/providers/document/couchbase/http-transport.ts)). With no +mapping and Capella work (`pickQueryEndpoint()`, +[`http-transport.ts`](../../src/lib/db/providers/document/couchbase/http-transport.ts)). With no `n1ql` entry anywhere the transport falls back to 8093 / 18093. Discovery is cached **as a promise**, so concurrent first queries share one round trip — but a *failed* discovery is not cached, or one unreachable moment would poison every later query on the -connection ([http-transport.ts:431](../../src/lib/db/providers/document/couchbase/http-transport.ts)). +connection (`getQueryEndpoint()`, +[`http-transport.ts`](../../src/lib/db/providers/document/couchbase/http-transport.ts)). Capella endpoints (`couchbases://cb..cloud.couchbase.com`) are SRV records, so a host given without an explicit port is resolved through `_couchbases._tcp.` first; a DNS failure or an empty answer falls back to treating the host as a plain A record, which is what every self-hosted -cluster needs anyway ([http-transport.ts:418](../../src/lib/db/providers/document/couchbase/http-transport.ts)). +cluster needs anyway (`resolveHost()`, +[`http-transport.ts`](../../src/lib/db/providers/document/couchbase/http-transport.ts)). ### 3.4 Keyspace flattening follows the PostgreSQL rule @@ -250,7 +252,7 @@ keyspacePath({ bucket: 'travel', scope: 'inventory', collection: 'hotel' }) **Quoting is a security boundary.** SQL++ has no bind parameter for identifiers, so keyspace paths are assembled by concatenation; `quoteIdentifier()` -([keyspace.ts:31](../../src/lib/db/providers/document/couchbase/keyspace.ts)) doubles embedded +([`keyspace.ts`](../../src/lib/db/providers/document/couchbase/keyspace.ts)) doubles embedded backticks so a hostile identifier cannot terminate its own quoting and have the remainder parsed as SQL++. Backticks are also required for a second, mundane reason: **`bucket` and `scope` are reserved words** in SQL++, and an unquoted projection over `system:keyspaces` fails with error 3000 (verified @@ -260,8 +262,9 @@ on Server 8.0.2). The Query Service returns syntax and semantic errors **inside a 200 response** with `status: "errors"`. The transport therefore inspects the payload *before* the HTTP code -([http-transport.ts:249](../../src/lib/db/providers/document/couchbase/http-transport.ts)); skipping -that check reports a failed statement as "0 rows". +(`throwIfFailed()`, +[`http-transport.ts`](../../src/lib/db/providers/document/couchbase/http-transport.ts)); +skipping that check reports a failed statement as "0 rows". ### 3.6 `SELECT *` nests documents, so generated queries project the key explicitly @@ -274,10 +277,11 @@ SELECT META(d).id AS __id, d.* FROM `travel`.`inventory`.`hotel` AS d LIMIT 50; ``` The alias `__id` matches `COUCHBASE_DOCUMENT_KEY_COLUMN` in the introspection module -([introspect.ts:58](../../src/lib/db/providers/document/couchbase/introspect.ts)), so the schema tree +([`introspect.ts`](../../src/lib/db/providers/document/couchbase/introspect.ts)), so the schema tree and the result grid name the key identically. A hand-written `SELECT *` still works; its columns are then derived from the rows, because a wildcard signature tells the transport nothing -([http-transport.ts:183](../../src/lib/db/providers/document/couchbase/http-transport.ts)). +(`fieldNamesFromSignature()`, +[`http-transport.ts`](../../src/lib/db/providers/document/couchbase/http-transport.ts)). ### 3.7 Read-your-writes: `scan_consistency` defaults to `request_plus` @@ -288,7 +292,8 @@ three, and the same `SELECT` returned three rows seconds later — a user insert sees nothing. The transport therefore sends `scan_consistency: "request_plus"` on **every** statement -([http-transport.ts:55](../../src/lib/db/providers/document/couchbase/http-transport.ts)), so a user +(`DEFAULT_SCAN_CONSISTENCY`, +[`http-transport.ts`](../../src/lib/db/providers/document/couchbase/http-transport.ts)), so a user always sees their own writes. Callers that prefer latency over freshness opt out per statement: ```ts @@ -322,7 +327,7 @@ prerequisite. **Server 7.0 to 7.2 — it fails with error 4000.** Sequential scan does not exist there, so the same statement returns "No index available on keyspace". The provider re-raises it as a `QueryError` carrying the runnable remedy, quoted for the exact keyspace the statement read from -([index.ts:473](../../src/lib/db/providers/document/couchbase/index.ts)): +(`primaryIndexRemedy()`, [`index.ts`](../../src/lib/db/providers/document/couchbase/index.ts)): ```text No index available on keyspace `travel`.`inventory`.`hotel` that matches your query. @@ -338,8 +343,8 @@ without any index on every supported version `system:completed_requests`, `system:active_requests` and the index-service statistics require the **Query System Catalog** RBAC role, so a denial is the *normal* case for a restricted user. Every -monitoring source funnels through one helper -([index.ts:189](../../src/lib/db/providers/document/couchbase/index.ts)): +monitoring source funnels through one helper, `degradeTo()` +([`index.ts`](../../src/lib/db/providers/document/couchbase/index.ts)): ```ts async function degradeTo(operation: () => Promise, fallback: T): Promise { @@ -350,7 +355,7 @@ async function degradeTo(operation: () => Promise, fallback: T): Promise *Collection*, row -> *document*, select -> *Select Documents*, analyze -> *Update Statistics* (the card text names the Enterprise-only restriction), vacuum -> @@ -730,7 +738,7 @@ would carry if it ever returns. The transport normalizes every failure into `CouchbaseError { code, message, retriable }`; the provider maps that one numeric space onto the shared classes from [`src/lib/db/errors.ts`](../../src/lib/db/errors.ts) -([index.ts:444](../../src/lib/db/providers/document/couchbase/index.ts)): +(`mapCouchbaseError()`, [`index.ts`](../../src/lib/db/providers/document/couchbase/index.ts)): | Code | Meaning | Error raised | |------|---------|--------------| diff --git a/tests/unit/provider-docs-monitoring-citations.test.ts b/tests/unit/provider-docs-monitoring-citations.test.ts index a34eda96..dba3239d 100644 --- a/tests/unit/provider-docs-monitoring-citations.test.ts +++ b/tests/unit/provider-docs-monitoring-citations.test.ts @@ -192,6 +192,39 @@ const NAMED_CITATIONS = [ "runMaintenance", ], }, + { + doc: "docs/providers/couchbase.md", + source: "src/lib/db/providers/document/couchbase/index.ts", + // Same rule as clickhouse: every `name(` the doc cites that index.ts declares as a class + // member, in declaration order. `degradeTo()` is module-level; the transport, introspection + // and keyspace names live in their own files. + methods: [ + "getCapabilities", + "getLabels", + "prepareQuery", + "validate", + "connect", + "disconnect", + "hostFromConnectionString", + "query", + "mapCouchbaseError", + "primaryIndexRemedy", + "getSchemaList", + "getSchemaRelations", + "getSchema", + "getOverview", + "getPerformanceMetrics", + "getSlowQueries", + "getActiveSessions", + "getTableStats", + "getIndexStats", + "getStorageStats", + "getHealth", + "runMaintenance", + "dispatchMaintenance", + "requireTarget", + ], + }, ] as const; const SEARCH_DOCS = ["docs/providers/elasticsearch.md", "docs/providers/opensearch.md"] as const; @@ -275,7 +308,8 @@ describe("redis provider doc", () => { describe("provider docs rewritten this round: code cited by name, whole file", () => { for (const { doc, source, methods } of NAMED_CITATIONS) { test(`${doc} cites no line number anywhere`, () => { - expect(read(doc)).not.toMatch(/\.ts:\d/); + // `.tsx` too: couchbase.md cited `ConnectionModal.tsx:139`, which `\.ts:` cannot see. + expect(read(doc)).not.toMatch(/\.tsx?:\d/); }); test(`${doc} names methods that ${source} really declares`, () => {