Skip to main content

heddle_object_model/object/
semantic_graph_query.rs

1// SPDX-License-Identifier: Apache-2.0
2//! Parse-free semantic graph query envelopes (heddle#1276).
3//!
4//! These types are the request/response body weft#451 Tier-2 will consume.
5//! They describe already-stored edges and importer rows; they never parse.
6
7use serde::{Deserialize, Serialize};
8
9use super::{ByteSpan, OccurrenceRole, SemanticEdgeKind, SymbolAnchor};
10
11/// Graph primitive selected by `heddle semantic refs` and the weft#451 wire.
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum SemanticGraphQueryKind {
15    /// Occurrences that resolve to a definition (`refs_of(state, anchor)`).
16    RefsOf,
17    /// Call-edge subset of [`Self::RefsOf`].
18    CallersOf,
19    /// Direct importers of a file (`importers_of(state, path)`).
20    ImportersOf,
21}
22
23/// One persisted reference to a definition, reconstructed without parsing.
24#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
25pub struct SemanticGraphRef {
26    pub source_path: String,
27    pub source_occurrence: u32,
28    pub name: String,
29    pub role: Option<OccurrenceRole>,
30    pub kind: SemanticEdgeKind,
31    pub span: Option<ByteSpan>,
32    pub target: SymbolAnchor,
33    pub target_definition: u32,
34}
35
36/// weft#451 Tier-2 request body. Hosted RPC names remain residual in weft.
37#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
38pub struct SemanticGraphQueryRequest {
39    pub state_id: String,
40    pub kind: SemanticGraphQueryKind,
41    pub anchor: Option<SymbolAnchor>,
42    pub path: Option<String>,
43}
44
45/// weft#451 Tier-2 response body. `index_present` is false when the state
46/// has no attached semantic index; the query then returns empty collections
47/// and never computes one.
48#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
49pub struct SemanticGraphQueryResponse {
50    pub state_id: String,
51    pub kind: SemanticGraphQueryKind,
52    pub anchor: Option<SymbolAnchor>,
53    pub path: Option<String>,
54    pub index_present: bool,
55    pub refs: Vec<SemanticGraphRef>,
56    pub importers: Vec<String>,
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn query_envelope_roundtrips_named_json() {
65        let request = SemanticGraphQueryRequest {
66            state_id: "hs-1".to_string(),
67            kind: SemanticGraphQueryKind::RefsOf,
68            anchor: Some(SymbolAnchor::new("src/api.rs", "greet")),
69            path: None,
70        };
71        let json = serde_json::to_string(&request).unwrap();
72        assert!(json.contains("\"refs_of\""));
73        assert_eq!(
74            serde_json::from_str::<SemanticGraphQueryRequest>(&json).unwrap(),
75            request
76        );
77    }
78}