mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-08 22:22:52 +00:00
* feat(ingestion/routes): give Route nodes a (method, url) identity (#2289) Route node identity was URL-only, so a same-URL multi-verb pair (GET /x + POST /x) collapsed into a single node and the second verb's handler and execution flow were silently lost. Route identity is now (method, url) via routeNodeKey(method, url): a known, specific verb keys as "METHOD url", while a method-less route (filesystem routes — Next.js / Expo / PHP — and Laravel resource/apiResource) or a wildcard "*" route (e.g. Django function views) falls back to URL-only. The fallback is byte-identical to the previous URL-only ids, so only genuine declaration-style multi-verb routes split into separate nodes. The identity key is shared across the three phases that must agree on the Route node id: - routes phase: registry key + node id + handler-symbol lookup; the Route node still carries the bare URL as its display name. - call-processor: resolveRouteHandlerSymbols re-keyed by identity so each verb resolves its own handler; a verb-less fetch() consumer matches by URL and connects to every Route node at that URL (one per verb). - processes phase: ENTRY_POINT_OF targets the identity-keyed node id. Bumps INCREMENTAL_SCHEMA_VERSION 4 -> 5: persisted pre-v5 Route nodes use the old url-only ids, so an incremental top-up would strand them alongside new composite-keyed nodes — force a full re-analyze instead. Part of #2280. * fix(ingestion/routes): address PR #2302 review (P1/P2/P3) P1 — Schema v5 fast-path bypass (run-analyze.ts): Adds a schemaVersion-mismatch guard above the alreadyUpToDate early-return, mirroring the pdgModeMismatch slot. Without it, a same-commit re-analyze on a pre-v5 stamp returned alreadyUpToDate without ever reaching the isIncremental gate, defeating the v5 schema bump's migration intent. Regression test covers: analyze (stamps v5) → meta downgrade to v4 → same commit re-analyze must NOT early-return and meta restamps to v5. P2 — ENTRY_POINT_OF handler-aware linking (processes.ts): Pre-fix routesByFile fanned every same-file Route to every same-file process, cross-wiring same-file GET/POST handlers. Now reads handlerSymbolId off the Route graph node (the source of truth routes.ts stamps) into routesByHandlerId, with a routesWithoutHandlerByFile fallback — mirrors the Tool linking precedent 10 lines below. Two regression tests: weak form (only one handler has a process; sibling verb does not get spuriously attached) and strong form (both handlers form distinct processes; each Route links to exactly its own entryPoint, 2 edges not pre-fix 4). P2 — Roundtrip composite-id (route-{method,handler-symbol}-roundtrip): Both tests now seed the Route node with generateId('Route', routeNodeKey('POST', '/api/orders')) and run the Cypher MATCH against the composite id, exercising the literal-space-in-id through CSV→COPY→HANDLES_ROUTE_QUERY. A space-in-id escape regression would surface here instead of being silently swallowed by the extractor's catch. P3 — doc-drift + test if: - route-path.ts:4 — header updated to "(method, url) via routeNodeKey" - java.ts:684 — drop "Route nodes are URL-keyed"; #2289 closes that gap - manifest-extractor.ts:196 — explicit that Route node *id* is composite while route.name remains the bare URL - multi-verb-route-identity.test.ts:88 — forEachRelationship+if rewritten as a .filter().map() chain (no test-level conditional). New route-process-linking tests are also if-free. Validation: tsc clean, prettier clean, 9 touched suites / 43 tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(ingestion/routes): drop routes.ts re-export, fix CI fast-path tests Two follow-ups on PR #2302's CHANGES_REQUESTED review: 1. Drop `routes.ts` re-export of `normalizeExtractedRoutePath` / `normalizeRouteMethod` / `routeNodeKey` (per @magyargergo's inline comment at routes.ts:153 — the symbols already live in `route-extractors/route-path.ts` and consumers should import them from the source, not via a routes-phase indirection that was kept only as a compat shim during the #2289 refactor). Updated the two remaining callers (blade-template-routes / spring-route-extractor- parity tests) to import directly from `route-extractors/route-path.js`. `call-processor.ts` and `processes.ts` already import from the source. 2. Fix two `run-analyze.test.ts` fast-path tests that started failing on CI after the schema-version mismatch guard landed ( "creates .gitnexus/.gitignore on the already-up-to-date fast path" and "reports isPrimaryBranch false for an up-to-date non-primary branch"). The test fixtures hand-built a RepoMeta with NO schemaVersion field; with the guard now checking `existingMeta.schemaVersion !== INCREMENTAL_SCHEMA_VERSION`, that pre-versioning shape was treated as a mismatch and forced a rebuild, short-circuiting the fast path the tests exercise. Stamp the current schemaVersion on those fixtures so they reflect the post-#2289 meta shape production actually writes (`runFullAnalysis` always stamps the field on git repos — see meta save site). Validation: tsc clean, prettier clean, 11 touched suites / 80 tests pass. --------- Co-authored-by: henry <zhangwei2017@unipus.cn> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
94 lines
4.6 KiB
TypeScript
94 lines
4.6 KiB
TypeScript
/**
|
|
* Real-LadybugDB round trip for `Route.method` (issue #2138, Part 1).
|
|
*
|
|
* This is the test the mocked `http-route-graph-method.test.ts` could NOT
|
|
* provide: it persists a `Route` node carrying `method` through the actual
|
|
* CSV generator + `COPY` path into a real LadybugDB, then runs the exact
|
|
* production `HANDLES_ROUTE_QUERY` and asserts the verb comes back.
|
|
*
|
|
* Before the schema/CSV/COPY columns were added, `HANDLES_ROUTE_QUERY`'s
|
|
* `route.method AS routeMethod` failed to bind against the real schema
|
|
* (`Binder exception: Cannot find property method for r.`) and the
|
|
* extractor's `catch { return [] }` silently swallowed it — so this test
|
|
* would have failed (empty rows / throw), pinning the exact regression.
|
|
*
|
|
* Coverage spans all three persistence points touched by Part 1:
|
|
* - `ROUTE_SCHEMA` (schema.ts) — the `method` column must exist
|
|
* - the Route CSV row (csv-generator.ts) — the value must be written
|
|
* - `getCopyQuery('Route')` (lbug-adapter.ts) — the COPY must load it
|
|
*/
|
|
import { it, expect } from 'vitest';
|
|
import path from 'path';
|
|
import fs from 'fs/promises';
|
|
import { withTestLbugDB } from '../helpers/test-indexed-db.js';
|
|
import { buildTestGraph } from '../helpers/test-graph.js';
|
|
import { streamAllCSVsToDisk } from '../../src/core/lbug/csv-generator.js';
|
|
import { HANDLES_ROUTE_QUERY } from '../../src/core/group/extractors/http-route-extractor.js';
|
|
import { generateId } from '../../src/lib/utils.js';
|
|
import { routeNodeKey } from '../../src/core/ingestion/route-extractors/route-path.js';
|
|
|
|
// Composite Route id — what the routes phase emits post-#2289 for a
|
|
// method-bearing declarative route. Hand-pinning the pre-#2289 URL-only
|
|
// `Route:/api/orders` shape would no longer cover the production
|
|
// CSV→COPY→`HANDLES_ROUTE_QUERY` path the COPY query has to load.
|
|
const ROUTE_ID = generateId('Route', routeNodeKey('POST', '/api/orders'));
|
|
|
|
withTestLbugDB('route-method-roundtrip', (handle) => {
|
|
it('persists Route.method through CSV→COPY and HANDLES_ROUTE_QUERY returns it', async () => {
|
|
const adapter = await import('../../src/core/lbug/lbug-adapter.js');
|
|
|
|
// 1. Build a graph with a single framework Route node carrying `method`,
|
|
// keyed by the composite `(method, url)` id the routes phase now emits
|
|
// so the CSV row + COPY load exercise the post-#2289 id shape (a value
|
|
// containing a literal space — `Route:POST /api/orders`).
|
|
const graph = buildTestGraph([
|
|
{
|
|
id: ROUTE_ID,
|
|
label: 'Route',
|
|
name: '/api/orders',
|
|
filePath: 'OrderController.java',
|
|
extra: {
|
|
method: 'POST',
|
|
responseKeys: [],
|
|
errorKeys: [],
|
|
middleware: [],
|
|
},
|
|
},
|
|
]);
|
|
|
|
// 2. Generate CSVs through the real generator (exercises the new
|
|
// `method` column in the Route CSV row).
|
|
const csvDir = path.join(handle.tmpHandle.dbPath, 'csv-roundtrip');
|
|
const repoDir = path.join(handle.tmpHandle.dbPath, 'repo-roundtrip');
|
|
await fs.mkdir(repoDir, { recursive: true });
|
|
await streamAllCSVsToDisk(graph, repoDir, csvDir);
|
|
|
|
// Sanity: the generated route.csv header + row include the method column,
|
|
// and the composite id (with its literal space) round-trips into the CSV
|
|
// — a space-in-id COPY failure on the new id format would surface here.
|
|
const routeCsv = await fs.readFile(path.join(csvDir, 'route.csv'), 'utf-8');
|
|
expect(routeCsv.split('\n')[0]).toContain('method');
|
|
expect(routeCsv).toContain('POST');
|
|
expect(routeCsv).toContain(ROUTE_ID);
|
|
|
|
// 3. COPY the Route node into the real DB via the production COPY query
|
|
// (exercises the new `method` column in getCopyQuery('Route')).
|
|
const routeCsvPath = path.join(csvDir, 'route.csv').replace(/\\/g, '/');
|
|
await adapter.executeQuery(adapter.getCopyQuery('Route', routeCsvPath));
|
|
|
|
// 4. Seed the handler File node + HANDLES_ROUTE edge via Cypher.
|
|
await adapter.executeQuery(
|
|
`CREATE (:File {id: 'File:OrderController.java', name: 'OrderController.java', filePath: 'OrderController.java'})`,
|
|
);
|
|
await adapter.executeQuery(
|
|
`MATCH (f:File {id: 'File:OrderController.java'}), (r:Route {id: '${ROUTE_ID}'})
|
|
CREATE (f)-[:CodeRelation {type: 'HANDLES_ROUTE', confidence: 1.0, reason: 'framework-route', step: 0}]->(r)`,
|
|
);
|
|
|
|
// 5. Run the EXACT production query and assert the verb round-trips.
|
|
const rows = (await adapter.executeQuery(HANDLES_ROUTE_QUERY)) as Record<string, unknown>[];
|
|
const row = rows.find((r) => String(r.routePath) === '/api/orders');
|
|
expect(row, 'HANDLES_ROUTE_QUERY returned no row for the seeded route').toBeTruthy();
|
|
expect(row!.routeMethod).toBe('POST');
|
|
});
|
|
});
|