Skip to content

Commit 5269aa0

Browse files
xav-dbishaksebsib
andcommitted
Integrate PR #667: Add .id() method to ID struct for borrowed ID support
This integrates the fix from PR #667 (#667) which adds an .id() method to the ID struct to resolve compilation errors when using AddE with borrowed IDs in FOR loops. Changes: - Added ID.id() method returning u128 in helix-db/src/utils/id.rs - Added test case for AddE with borrowed IDs from FOR loop destructuring The helixc code generator consistently uses .id() to access ID values. Before this change, calling .id() on &ID (borrowed ID) would fail. The new method leverages Rust's auto-deref so both ID.id() and &ID.id() work seamlessly. This fixes queries like: FOR {from_id, to_id, ...} IN edges { AddE<MyEdge>::From(from_id)::To(to_id) } Co-Authored-By: ishaksebsib <[email protected]>
1 parent b146b83 commit 5269aa0

File tree

6 files changed

+225
-0
lines changed

6 files changed

+225
-0
lines changed

helix-db/src/utils/id.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ impl ID {
2525
self.0
2626
}
2727

28+
pub fn id(&self) -> u128 {
29+
self.0
30+
}
31+
2832
pub fn stringify(&self) -> String {
2933
uuid::Uuid::from_u128(self.0).to_string()
3034
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"vector_config": {
3+
"m": 16,
4+
"ef_construction": 128,
5+
"ef_search": 768,
6+
"db_max_size": 20
7+
},
8+
"graph_config": {
9+
"secondary_indices": []
10+
},
11+
"db_max_size_gb": 20,
12+
"mcp": false,
13+
"bm25": false
14+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[project]
2+
name = "add_e_borrowed_ids"
3+
queries = "."
4+
5+
[local.dev]
6+
port = 6969
7+
build_mode = "debug"
8+
9+
[cloud]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
QUERY AddEdges(edges: [{from_id: ID, to_id: ID, since: String}]) =>
2+
FOR {from_id, to_id, since} IN edges {
3+
AddE<Knows>({since: since})::From(from_id)::To(to_id)
4+
}
5+
RETURN "Edges added successfully"
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
2+
// DEFAULT CODE
3+
// use helix_db::helix_engine::traversal_core::config::Config;
4+
5+
// pub fn config() -> Option<Config> {
6+
// None
7+
// }
8+
9+
10+
11+
use bumpalo::Bump;
12+
use heed3::RoTxn;
13+
use helix_macros::{handler, tool_call, mcp_handler, migration};
14+
use helix_db::{
15+
helix_engine::{
16+
traversal_core::{
17+
config::{Config, GraphConfig, VectorConfig},
18+
ops::{
19+
bm25::search_bm25::SearchBM25Adapter,
20+
g::G,
21+
in_::{in_::InAdapter, in_e::InEdgesAdapter, to_n::ToNAdapter, to_v::ToVAdapter},
22+
out::{
23+
from_n::FromNAdapter, from_v::FromVAdapter, out::OutAdapter, out_e::OutEdgesAdapter,
24+
},
25+
source::{
26+
add_e::AddEAdapter,
27+
add_n::AddNAdapter,
28+
e_from_id::EFromIdAdapter,
29+
e_from_type::EFromTypeAdapter,
30+
n_from_id::NFromIdAdapter,
31+
n_from_index::NFromIndexAdapter,
32+
n_from_type::NFromTypeAdapter,
33+
v_from_id::VFromIdAdapter,
34+
v_from_type::VFromTypeAdapter
35+
},
36+
util::{
37+
dedup::DedupAdapter, drop::Drop, exist::Exist, filter_mut::FilterMut,
38+
filter_ref::FilterRefAdapter, map::MapAdapter, paths::{PathAlgorithm, ShortestPathAdapter},
39+
range::RangeAdapter, update::UpdateAdapter, order::OrderByAdapter,
40+
aggregate::AggregateAdapter, group_by::GroupByAdapter, count::CountAdapter,
41+
},
42+
vectors::{
43+
brute_force_search::BruteForceSearchVAdapter, insert::InsertVAdapter,
44+
search::SearchVAdapter,
45+
},
46+
},
47+
traversal_value::TraversalValue,
48+
},
49+
types::GraphError,
50+
vector_core::vector::HVector,
51+
},
52+
helix_gateway::{
53+
embedding_providers::{EmbeddingModel, get_embedding_model},
54+
router::router::{HandlerInput, IoContFn},
55+
mcp::mcp::{MCPHandlerSubmission, MCPToolInput, MCPHandler}
56+
},
57+
node_matches, props, embed, embed_async,
58+
field_addition_from_old_field, field_type_cast, field_addition_from_value,
59+
protocol::{
60+
response::Response,
61+
value::{casting::{cast, CastType}, Value},
62+
format::Format,
63+
},
64+
utils::{
65+
count::Count,
66+
id::{ID, uuid_str},
67+
items::{Edge, Node},
68+
properties::ImmutablePropertiesMap,
69+
},
70+
};
71+
use sonic_rs::{Deserialize, Serialize, json};
72+
use std::collections::{HashMap, HashSet};
73+
use std::sync::Arc;
74+
use std::time::Instant;
75+
use chrono::{DateTime, Utc};
76+
77+
// Re-export scalar types for generated code
78+
type I8 = i8;
79+
type I16 = i16;
80+
type I32 = i32;
81+
type I64 = i64;
82+
type U8 = u8;
83+
type U16 = u16;
84+
type U32 = u32;
85+
type U64 = u64;
86+
type U128 = u128;
87+
type F32 = f32;
88+
type F64 = f64;
89+
90+
pub fn config() -> Option<Config> {
91+
return Some(Config {
92+
vector_config: Some(VectorConfig {
93+
m: Some(16),
94+
ef_construction: Some(128),
95+
ef_search: Some(768),
96+
}),
97+
graph_config: Some(GraphConfig {
98+
secondary_indices: Some(vec![]),
99+
}),
100+
db_max_size_gb: Some(10),
101+
mcp: Some(true),
102+
bm25: Some(true),
103+
schema: Some(r#"{
104+
"schema": {
105+
"nodes": [
106+
{
107+
"name": "Person",
108+
"properties": {
109+
"id": "ID",
110+
"label": "String",
111+
"name": "String"
112+
}
113+
}
114+
],
115+
"vectors": [],
116+
"edges": [
117+
{
118+
"name": "Knows",
119+
"from": "Person",
120+
"to": "Person",
121+
"properties": {
122+
"since": "String"
123+
}
124+
}
125+
]
126+
},
127+
"queries": [
128+
{
129+
"name": "AddEdges",
130+
"parameters": {
131+
"edges": "Array({to_id: IDsince: Stringfrom_id: ID})"
132+
},
133+
"returns": []
134+
}
135+
]
136+
}"#.to_string()),
137+
embedding_model: Some("text-embedding-ada-002".to_string()),
138+
graphvis_node_label: None,
139+
})
140+
}
141+
142+
pub struct Person {
143+
pub name: String,
144+
}
145+
146+
pub struct Knows {
147+
pub from: Person,
148+
pub to: Person,
149+
pub since: String,
150+
}
151+
152+
153+
#[derive(Serialize, Deserialize, Clone)]
154+
pub struct AddEdgesInput {
155+
156+
pub edges: Vec<edgesData>
157+
}
158+
#[derive(Serialize, Deserialize, Clone)]
159+
pub struct edgesData {
160+
pub to_id: ID,
161+
pub since: String,
162+
pub from_id: ID,
163+
}
164+
#[handler]
165+
pub fn AddEdges (input: HandlerInput) -> Result<Response, GraphError> {
166+
let db = Arc::clone(&input.graph.storage);
167+
let data = input.request.in_fmt.deserialize::<AddEdgesInput>(&input.request.body)?;
168+
let arena = Bump::new();
169+
let mut txn = db.graph_env.write_txn().map_err(|e| GraphError::New(format!("Failed to start write transaction: {:?}", e)))?;
170+
for edgesData { from_id, to_id, since } in &data.edges {
171+
G::new_mut(&db, &arena, &mut txn)
172+
.add_edge("Knows", Some(ImmutablePropertiesMap::new(1, vec![("since", Value::from(since.clone()))].into_iter(), &arena)), from_id.id(), to_id.id(), false).collect_to_obj();
173+
}
174+
;
175+
let response = json!({
176+
"data": "Edges added successfully"
177+
});
178+
txn.commit().map_err(|e| GraphError::New(format!("Failed to commit transaction: {:?}", e)))?;
179+
Ok(input.request.out_fmt.create_response(&response))
180+
}
181+
182+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
N::Person {
2+
name: String
3+
}
4+
5+
E::Knows {
6+
From: Person,
7+
To: Person,
8+
Properties: {
9+
since: String
10+
}
11+
}

0 commit comments

Comments
 (0)