use crate::executor::streaming::query_registry::CancelToken;
use linkrs_core::types::{CharsetInfo, SpaceInfo, SpaceSummary, Timestamp};
use linkrs_core::IdGenerator;
use std::sync::Arc;
use super::{QueryContext, QueryRequestContext};
#[derive(Default)]
pub struct QueryContextBuilder {
rctx: Option<Arc<QueryRequestContext>>,
id_gen: Option<IdGenerator>,
space_info: Option<SpaceInfo>,
charset_info: Option<Box<CharsetInfo>>,
snapshot_ts: Option<Timestamp>,
isolation_level: Option<linkrs_core::types::TransactionIsolationLevel>,
arena_enabled: bool,
password_history_depth: usize,
}
impl QueryContextBuilder {
pub fn new(rctx: Arc<QueryRequestContext>) -> Self {
Self {
rctx: Some(rctx),
id_gen: None,
space_info: None,
charset_info: None,
snapshot_ts: None,
isolation_level: None,
arena_enabled: false,
password_history_depth: 0,
}
}
pub fn from_session(rctx: Arc<QueryRequestContext>, space: Option<SpaceSummary>) -> Self {
Self {
rctx: Some(rctx),
id_gen: None,
space_info: space.map(SpaceInfo::from),
charset_info: None,
snapshot_ts: None,
isolation_level: None,
arena_enabled: false,
password_history_depth: 0,
}
}
pub fn with_space_info(mut self, space_info: SpaceInfo) -> Self {
self.space_info = Some(space_info);
self
}
pub fn with_charset_info(mut self, charset_info: CharsetInfo) -> Self {
self.charset_info = Some(Box::new(charset_info));
self
}
pub fn with_start_id(mut self, start_id: i64) -> Self {
self.id_gen = Some(IdGenerator::new(start_id));
self
}
pub fn with_arena(mut self) -> Self {
self.arena_enabled = true;
self
}
pub fn with_snapshot_ts(mut self, snapshot_ts: Timestamp) -> Self {
self.snapshot_ts = Some(snapshot_ts);
self
}
pub fn snapshot_ts(&self) -> Option<Timestamp> {
self.snapshot_ts
}
pub fn with_isolation_level(
mut self,
isolation_level: linkrs_core::types::TransactionIsolationLevel,
) -> Self {
self.isolation_level = Some(isolation_level);
self
}
pub fn isolation_level(&self) -> Option<linkrs_core::types::TransactionIsolationLevel> {
self.isolation_level
}
pub fn with_password_history_depth(mut self, depth: usize) -> Self {
self.password_history_depth = depth;
self
}
pub fn build(self) -> QueryContext {
let rctx = self.rctx.expect("QueryRequestContext is required");
let id_gen = self.id_gen.unwrap_or_else(|| IdGenerator::new(0));
QueryContext::from_builder(
rctx,
super::query_context::ContextParams {
cancel_token: CancelToken::new(),
id_gen,
space_info: self.space_info,
charset_info: self.charset_info,
snapshot_ts: self.snapshot_ts,
isolation_level: self.isolation_level,
arena_enabled: self.arena_enabled,
password_history_depth: self.password_history_depth,
},
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use linkrs_core::types::{DataType, EngineType, IsolationLevel, MetadataVersion, SpaceStatus};
use std::collections::HashMap;
#[test]
fn test_builder_basic() {
let rctx = Arc::new(QueryRequestContext {
session_id: None,
user_name: None,
space_name: None,
query: "MATCH (n) RETURN n".to_string(),
parameters: HashMap::new(),
..Default::default()
});
let query_context = QueryContextBuilder::new(rctx).build();
assert_eq!(query_context.query(), "MATCH (n) RETURN n");
}
#[test]
fn test_builder_with_space_info() {
let rctx = Arc::new(QueryRequestContext {
session_id: None,
user_name: None,
space_name: None,
query: "MATCH (n) RETURN n".to_string(),
parameters: HashMap::new(),
..Default::default()
});
let space_info = SpaceInfo {
space_id: 1,
space_name: "test_space".to_string(),
vid_type: DataType::BigInt,
tags: Vec::new(),
edge_types: Vec::new(),
version: MetadataVersion::default(),
comment: None,
storage_path: None,
isolation_level: IsolationLevel::default(),
partition_num: 100,
replica_factor: 1,
engine_type: EngineType::default(),
status: SpaceStatus::Online,
};
let query_context = QueryContextBuilder::new(rctx)
.with_space_info(space_info)
.build();
assert_eq!(query_context.space_id(), Some(1));
assert_eq!(query_context.space_name(), Some("test_space".to_string()));
}
#[test]
fn test_builder_with_start_id() {
let rctx = Arc::new(QueryRequestContext {
session_id: None,
user_name: None,
space_name: None,
query: "MATCH (n) RETURN n".to_string(),
parameters: HashMap::new(),
..Default::default()
});
let query_context = QueryContextBuilder::new(rctx).with_start_id(100).build();
assert_eq!(query_context.current_id(), 100);
}
#[test]
fn test_builder_with_arena() {
let rctx = Arc::new(QueryRequestContext {
session_id: None,
user_name: None,
space_name: None,
query: "MATCH (n) RETURN n".to_string(),
parameters: HashMap::new(),
..Default::default()
});
let query_context = QueryContextBuilder::new(rctx).with_arena().build();
assert!(query_context.has_arena());
}
#[test]
fn test_builder_with_snapshot_ts() {
let rctx = Arc::new(QueryRequestContext {
session_id: None,
user_name: None,
space_name: None,
query: "MATCH (n) RETURN n".to_string(),
parameters: HashMap::new(),
..Default::default()
});
let builder = QueryContextBuilder::new(rctx.clone());
assert_eq!(builder.snapshot_ts(), None);
let query_context = builder.with_snapshot_ts(42).build();
assert_eq!(query_context.snapshot_ts(), Some(42));
let default_context = QueryContextBuilder::new(rctx).build();
assert_eq!(default_context.snapshot_ts(), None);
}
#[test]
fn test_builder_chaining() {
let rctx = Arc::new(QueryRequestContext {
session_id: None,
user_name: None,
space_name: None,
query: "MATCH (n) RETURN n".to_string(),
parameters: HashMap::new(),
..Default::default()
});
let space_info = SpaceInfo {
space_id: 1,
space_name: "test_space".to_string(),
vid_type: DataType::BigInt,
tags: Vec::new(),
edge_types: Vec::new(),
version: MetadataVersion::default(),
comment: None,
storage_path: None,
isolation_level: IsolationLevel::default(),
partition_num: 100,
replica_factor: 1,
engine_type: EngineType::default(),
status: SpaceStatus::Online,
};
let query_context = QueryContextBuilder::new(rctx)
.with_space_info(space_info)
.with_start_id(100)
.with_arena()
.build();
assert_eq!(query_context.space_id(), Some(1));
assert_eq!(query_context.current_id(), 100);
assert!(query_context.has_arena());
}
}