-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement details queries for vertex and edges (#761)
* Add EdgeRef * Extract function to create stable keys in queries * Add scaffold for explorer functions * Implement in Gremlin * Implement in openCypher * Implement SPARQL * Add cache updates * Add hooks for details queries * Fix log message * Use existing response typing logic
- Loading branch information
Showing
21 changed files
with
740 additions
and
19 deletions.
There are no files selected for viewing
49 changes: 49 additions & 0 deletions
49
packages/graph-explorer/src/connector/gremlin/edgeDetails.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { logger, query } from "@/utils"; | ||
import { | ||
EdgeDetailsRequest, | ||
EdgeDetailsResponse, | ||
ErrorResponse, | ||
} from "../useGEFetchTypes"; | ||
import { GEdge, GremlinFetch } from "./types"; | ||
import { mapResults } from "./mappers/mapResults"; | ||
import isErrorResponse from "../utils/isErrorResponse"; | ||
import { idParam } from "./idParam"; | ||
|
||
type Response = { | ||
requestId: string; | ||
status: { | ||
message: string; | ||
code: number; | ||
}; | ||
result: { | ||
data: { | ||
"@type": "g:List"; | ||
"@value": Array<GEdge>; | ||
}; | ||
}; | ||
}; | ||
|
||
export async function edgeDetails( | ||
gremlinFetch: GremlinFetch, | ||
request: EdgeDetailsRequest | ||
): Promise<EdgeDetailsResponse> { | ||
const template = query` | ||
g.E(${idParam(request.edge)}) | ||
`; | ||
|
||
// Fetch the vertex details | ||
const data = await gremlinFetch<Response | ErrorResponse>(template); | ||
if (isErrorResponse(data)) { | ||
logger.error(data.detailedMessage); | ||
throw new Error(data.detailedMessage); | ||
} | ||
|
||
// Map the results | ||
const entities = mapResults(data.result.data); | ||
const edge = entities.edges.length > 0 ? entities.edges[0] : null; | ||
if (!edge) { | ||
logger.warn("Edge not found", request.edge); | ||
} | ||
|
||
return { edge }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { EdgeRef, VertexRef } from "../useGEFetchTypes"; | ||
|
||
/** Formats the ID parameter for a gremlin query based on the ID type. */ | ||
export function idParam(entity: VertexRef | EdgeRef) { | ||
return entity.idType === "number" ? `${entity.id}L` : `"${entity.id}"`; | ||
} |
48 changes: 48 additions & 0 deletions
48
packages/graph-explorer/src/connector/gremlin/vertexDetails.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { logger, query } from "@/utils"; | ||
import { | ||
ErrorResponse, | ||
VertexDetailsRequest, | ||
VertexDetailsResponse, | ||
} from "../useGEFetchTypes"; | ||
import { GremlinFetch, GVertex } from "./types"; | ||
import { mapResults } from "./mappers/mapResults"; | ||
import isErrorResponse from "../utils/isErrorResponse"; | ||
import { idParam } from "./idParam"; | ||
|
||
type Response = { | ||
requestId: string; | ||
status: { | ||
message: string; | ||
code: number; | ||
}; | ||
result: { | ||
data: { | ||
"@type": "g:List"; | ||
"@value": Array<GVertex>; | ||
}; | ||
}; | ||
}; | ||
|
||
export async function vertexDetails( | ||
gremlinFetch: GremlinFetch, | ||
request: VertexDetailsRequest | ||
): Promise<VertexDetailsResponse> { | ||
const template = query` | ||
g.V(${idParam(request.vertex)}) | ||
`; | ||
|
||
// Fetch the vertex details | ||
const data = await gremlinFetch<Response | ErrorResponse>(template); | ||
if (isErrorResponse(data)) { | ||
throw new Error(data.detailedMessage); | ||
} | ||
|
||
// Map the results | ||
const entities = mapResults(data.result.data); | ||
const vertex = entities.vertices.length > 0 ? entities.vertices[0] : null; | ||
if (!vertex) { | ||
logger.warn("Vertex not found", request.vertex); | ||
} | ||
|
||
return { vertex }; | ||
} |
54 changes: 54 additions & 0 deletions
54
packages/graph-explorer/src/connector/openCypher/edgeDetails.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { | ||
EdgeDetailsRequest, | ||
EdgeDetailsResponse, | ||
ErrorResponse, | ||
} from "@/connector/useGEFetchTypes"; | ||
import { OCEdge, OpenCypherFetch } from "./types"; | ||
import isErrorResponse from "@/connector/utils/isErrorResponse"; | ||
import { logger, query } from "@/utils"; | ||
import mapApiEdge from "./mappers/mapApiEdge"; | ||
|
||
type Response = { | ||
results: [ | ||
{ | ||
edge: OCEdge; | ||
sourceLabels: Array<string>; | ||
targetLabels: Array<string>; | ||
}, | ||
]; | ||
}; | ||
|
||
export async function edgeDetails( | ||
openCypherFetch: OpenCypherFetch, | ||
req: EdgeDetailsRequest | ||
): Promise<EdgeDetailsResponse> { | ||
const template = query` | ||
MATCH ()-[edge]-() | ||
WHERE ID(edge) = "${String(req.edge.id)}" | ||
RETURN edge, labels(startNode(edge)) as sourceLabels, labels(endNode(edge)) as targetLabels | ||
`; | ||
const data = await openCypherFetch<Response | ErrorResponse>(template); | ||
|
||
if (isErrorResponse(data)) { | ||
logger.error( | ||
"Failed to fetch edge details", | ||
req.edge, | ||
data.detailedMessage | ||
); | ||
throw new Error(data.detailedMessage); | ||
} | ||
|
||
const value = data.results[0]; | ||
|
||
if (!value) { | ||
console.warn("Edge not found", req.edge); | ||
return { edge: null }; | ||
} | ||
|
||
const sourceLabels = value.sourceLabels.join("::"); | ||
const targetLabels = value.targetLabels.join("::"); | ||
|
||
const edge = mapApiEdge(value.edge, sourceLabels, targetLabels); | ||
|
||
return { edge }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
packages/graph-explorer/src/connector/openCypher/vertexDetails.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { | ||
ErrorResponse, | ||
VertexDetailsRequest, | ||
VertexDetailsResponse, | ||
} from "@/connector/useGEFetchTypes"; | ||
import { OCVertex, OpenCypherFetch } from "./types"; | ||
import isErrorResponse from "@/connector/utils/isErrorResponse"; | ||
import mapApiVertex from "./mappers/mapApiVertex"; | ||
import { query } from "@/utils"; | ||
|
||
type Response = { | ||
results: [ | ||
{ | ||
vertex: OCVertex; | ||
}, | ||
]; | ||
}; | ||
|
||
export async function vertexDetails( | ||
openCypherFetch: OpenCypherFetch, | ||
req: VertexDetailsRequest | ||
): Promise<VertexDetailsResponse> { | ||
const idTemplate = `"${String(req.vertex.id)}"`; | ||
const template = query` | ||
MATCH (vertex) WHERE ID(vertex) = ${idTemplate} RETURN vertex | ||
`; | ||
|
||
// Fetch the vertex details | ||
const data = await openCypherFetch<Response | ErrorResponse>(template); | ||
if (isErrorResponse(data)) { | ||
throw new Error(data.detailedMessage); | ||
} | ||
|
||
// Map the results | ||
const ocVertex = data.results[0]?.vertex; | ||
|
||
if (!ocVertex) { | ||
console.warn("Vertex not found", req.vertex); | ||
return { vertex: null }; | ||
} | ||
|
||
const vertex = mapApiVertex(ocVertex); | ||
return { vertex }; | ||
} |
Oops, something went wrong.