1use crate::{PluginCapabilities, PluginContext, PluginResult, Result};
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10use std::collections::HashMap;
11
12#[async_trait::async_trait]
18pub trait DataSourcePlugin: Send + Sync {
19 fn capabilities(&self) -> PluginCapabilities;
21
22 async fn initialize(&self, config: &DataSourcePluginConfig) -> Result<()>;
24
25 async fn connect(
37 &self,
38 context: &PluginContext,
39 config: &DataSourcePluginConfig,
40 ) -> Result<PluginResult<DataConnection>>;
41
42 async fn query(
55 &self,
56 context: &PluginContext,
57 connection: &DataConnection,
58 query: &DataQuery,
59 config: &DataSourcePluginConfig,
60 ) -> Result<PluginResult<DataResult>>;
61
62 async fn get_schema(
75 &self,
76 context: &PluginContext,
77 connection: &DataConnection,
78 config: &DataSourcePluginConfig,
79 ) -> Result<PluginResult<Schema>>;
80
81 async fn test_connection(
93 &self,
94 context: &PluginContext,
95 config: &DataSourcePluginConfig,
96 ) -> Result<PluginResult<ConnectionTestResult>>;
97
98 fn validate_config(&self, config: &DataSourcePluginConfig) -> Result<()>;
100
101 fn supported_types(&self) -> Vec<String>;
103
104 async fn cleanup(&self) -> Result<()>;
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct DataSourcePluginConfig {
111 pub config: HashMap<String, serde_json::Value>,
113 pub enabled: bool,
115 pub data_source_type: String,
117 pub connection_string: Option<String>,
119 pub connection_timeout_secs: u64,
121 pub query_timeout_secs: u64,
123 pub max_connections: u32,
125 pub credentials: Option<DataSourceCredentials>,
127 pub ssl_config: Option<SslConfig>,
129 pub settings: HashMap<String, serde_json::Value>,
131}
132
133impl Default for DataSourcePluginConfig {
134 fn default() -> Self {
135 Self {
136 config: HashMap::new(),
137 enabled: true,
138 data_source_type: "unknown".to_string(),
139 connection_string: None,
140 connection_timeout_secs: 30,
141 query_timeout_secs: 30,
142 max_connections: 10,
143 credentials: None,
144 ssl_config: None,
145 settings: HashMap::new(),
146 }
147 }
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize)]
152pub struct DataSourceCredentials {
153 pub username: Option<String>,
155 pub password: Option<String>,
157 pub api_key: Option<String>,
159 pub bearer_token: Option<String>,
161 pub custom: HashMap<String, String>,
163}
164
165impl DataSourceCredentials {
166 pub fn user_pass<S: Into<String>>(username: S, password: S) -> Self {
168 Self {
169 username: Some(username.into()),
170 password: Some(password.into()),
171 api_key: None,
172 bearer_token: None,
173 custom: HashMap::new(),
174 }
175 }
176
177 pub fn api_key<S: Into<String>>(api_key: S) -> Self {
179 Self {
180 username: None,
181 password: None,
182 api_key: Some(api_key.into()),
183 bearer_token: None,
184 custom: HashMap::new(),
185 }
186 }
187
188 pub fn bearer_token<S: Into<String>>(token: S) -> Self {
190 Self {
191 username: None,
192 password: None,
193 api_key: None,
194 bearer_token: Some(token.into()),
195 custom: HashMap::new(),
196 }
197 }
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize, Default)]
202pub struct SslConfig {
203 pub enabled: bool,
205 pub ca_cert_path: Option<String>,
207 pub client_cert_path: Option<String>,
209 pub client_key_path: Option<String>,
211 pub skip_verify: bool,
213 pub custom: HashMap<String, serde_json::Value>,
215}
216
217#[derive(Debug, Clone)]
219pub struct DataConnection {
220 pub id: String,
222 pub connection_type: String,
224 pub metadata: HashMap<String, Value>,
226 pub created_at: chrono::DateTime<chrono::Utc>,
228 pub last_used: chrono::DateTime<chrono::Utc>,
230 pub handle: Value,
232}
233
234impl DataConnection {
235 pub fn new<S: Into<String>>(connection_type: S, handle: Value) -> Self {
237 let now = chrono::Utc::now();
238 Self {
239 id: uuid::Uuid::new_v4().to_string(),
240 connection_type: connection_type.into(),
241 metadata: HashMap::new(),
242 created_at: now,
243 last_used: now,
244 handle,
245 }
246 }
247
248 pub fn mark_used(&mut self) {
250 self.last_used = chrono::Utc::now();
251 }
252
253 pub fn with_metadata<S: Into<String>>(mut self, key: S, value: Value) -> Self {
255 self.metadata.insert(key.into(), value);
256 self
257 }
258
259 pub fn metadata(&self, key: &str) -> Option<&Value> {
261 self.metadata.get(key)
262 }
263
264 pub fn is_stale(&self, max_age: chrono::Duration) -> bool {
266 chrono::Utc::now().signed_duration_since(self.last_used) > max_age
267 }
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
272pub struct DataQuery {
273 pub query_type: QueryType,
275 pub query: String,
277 pub parameters: HashMap<String, Value>,
279 pub limit: Option<usize>,
281 pub offset: Option<usize>,
283 pub sort: Option<Vec<SortField>>,
285 pub filters: Vec<QueryFilter>,
287 pub options: HashMap<String, Value>,
289}
290
291impl DataQuery {
292 pub fn select<S: Into<String>>(query: S) -> Self {
294 Self {
295 query_type: QueryType::Select,
296 query: query.into(),
297 parameters: HashMap::new(),
298 limit: None,
299 offset: None,
300 sort: None,
301 filters: Vec::new(),
302 options: HashMap::new(),
303 }
304 }
305
306 pub fn insert<S: Into<String>>(query: S) -> Self {
308 Self {
309 query_type: QueryType::Insert,
310 query: query.into(),
311 parameters: HashMap::new(),
312 limit: None,
313 offset: None,
314 sort: None,
315 filters: Vec::new(),
316 options: HashMap::new(),
317 }
318 }
319
320 pub fn update<S: Into<String>>(query: S) -> Self {
322 Self {
323 query_type: QueryType::Update,
324 query: query.into(),
325 parameters: HashMap::new(),
326 limit: None,
327 offset: None,
328 sort: None,
329 filters: Vec::new(),
330 options: HashMap::new(),
331 }
332 }
333
334 pub fn delete<S: Into<String>>(query: S) -> Self {
336 Self {
337 query_type: QueryType::Delete,
338 query: query.into(),
339 parameters: HashMap::new(),
340 limit: None,
341 offset: None,
342 sort: None,
343 filters: Vec::new(),
344 options: HashMap::new(),
345 }
346 }
347
348 pub fn with_parameter<S: Into<String>>(mut self, key: S, value: Value) -> Self {
350 self.parameters.insert(key.into(), value);
351 self
352 }
353
354 pub fn with_limit(mut self, limit: usize) -> Self {
356 self.limit = Some(limit);
357 self
358 }
359
360 pub fn with_offset(mut self, offset: usize) -> Self {
362 self.offset = Some(offset);
363 self
364 }
365
366 pub fn with_sort(mut self, field: SortField) -> Self {
368 self.sort.get_or_insert_with(Vec::new).push(field);
369 self
370 }
371
372 pub fn with_filter(mut self, filter: QueryFilter) -> Self {
374 self.filters.push(filter);
375 self
376 }
377
378 pub fn with_option<S: Into<String>>(mut self, key: S, value: Value) -> Self {
380 self.options.insert(key.into(), value);
381 self
382 }
383}
384
385#[derive(Debug, Clone, Serialize, Deserialize)]
387pub enum QueryType {
388 Select,
390 Insert,
392 Update,
394 Delete,
396 Custom(String),
398}
399
400impl fmt::Display for QueryType {
401 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
402 match self {
403 QueryType::Select => write!(f, "SELECT"),
404 QueryType::Insert => write!(f, "INSERT"),
405 QueryType::Update => write!(f, "UPDATE"),
406 QueryType::Delete => write!(f, "DELETE"),
407 QueryType::Custom(custom) => write!(f, "{}", custom),
408 }
409 }
410}
411
412use std::fmt;
413
414#[derive(Debug, Clone, Serialize, Deserialize)]
416pub struct SortField {
417 pub field: String,
419 pub direction: SortDirection,
421}
422
423impl SortField {
424 pub fn asc<S: Into<String>>(field: S) -> Self {
426 Self {
427 field: field.into(),
428 direction: SortDirection::Ascending,
429 }
430 }
431
432 pub fn desc<S: Into<String>>(field: S) -> Self {
434 Self {
435 field: field.into(),
436 direction: SortDirection::Descending,
437 }
438 }
439}
440
441#[derive(Debug, Clone, Serialize, Deserialize)]
443pub enum SortDirection {
444 Ascending,
446 Descending,
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize)]
452pub struct QueryFilter {
453 pub field: String,
455 pub operator: FilterOperator,
457 pub value: Value,
459 pub logical_op: Option<LogicalOperator>,
461}
462
463impl QueryFilter {
464 pub fn equals<S: Into<String>>(field: S, value: Value) -> Self {
466 Self {
467 field: field.into(),
468 operator: FilterOperator::Equals,
469 value,
470 logical_op: None,
471 }
472 }
473
474 pub fn greater_than<S: Into<String>>(field: S, value: Value) -> Self {
476 Self {
477 field: field.into(),
478 operator: FilterOperator::GreaterThan,
479 value,
480 logical_op: None,
481 }
482 }
483
484 pub fn less_than<S: Into<String>>(field: S, value: Value) -> Self {
486 Self {
487 field: field.into(),
488 operator: FilterOperator::LessThan,
489 value,
490 logical_op: None,
491 }
492 }
493
494 pub fn contains<S: Into<String>>(field: S, value: Value) -> Self {
496 Self {
497 field: field.into(),
498 operator: FilterOperator::Contains,
499 value,
500 logical_op: None,
501 }
502 }
503
504 pub fn and(mut self) -> Self {
506 self.logical_op = Some(LogicalOperator::And);
507 self
508 }
509
510 pub fn or(mut self) -> Self {
512 self.logical_op = Some(LogicalOperator::Or);
513 self
514 }
515}
516
517#[derive(Debug, Clone, Serialize, Deserialize)]
519pub enum FilterOperator {
520 Equals,
522 NotEquals,
524 GreaterThan,
526 GreaterThanOrEqual,
528 LessThan,
530 LessThanOrEqual,
532 Contains,
534 StartsWith,
536 EndsWith,
538 In,
540 NotIn,
542 IsNull,
544 IsNotNull,
546}
547
548#[derive(Debug, Clone, Serialize, Deserialize)]
550pub enum LogicalOperator {
551 And,
553 Or,
555}
556
557#[derive(Debug, Clone, Serialize, Deserialize)]
559pub struct DataResult {
560 pub rows: Vec<DataRow>,
562 pub columns: Vec<ColumnInfo>,
564 pub total_count: Option<usize>,
566 pub execution_time_ms: u64,
568 pub metadata: HashMap<String, Value>,
570}
571
572impl DataResult {
573 pub fn empty() -> Self {
575 Self {
576 rows: Vec::new(),
577 columns: Vec::new(),
578 total_count: Some(0),
579 execution_time_ms: 0,
580 metadata: HashMap::new(),
581 }
582 }
583
584 pub fn with_rows(rows: Vec<DataRow>, columns: Vec<ColumnInfo>) -> Self {
586 let row_count = rows.len();
587 Self {
588 rows,
589 columns,
590 total_count: Some(row_count),
591 execution_time_ms: 0,
592 metadata: HashMap::new(),
593 }
594 }
595
596 pub fn with_metadata<S: Into<String>>(mut self, key: S, value: Value) -> Self {
598 self.metadata.insert(key.into(), value);
599 self
600 }
601
602 pub fn with_execution_time(mut self, time_ms: u64) -> Self {
604 self.execution_time_ms = time_ms;
605 self
606 }
607
608 pub fn row_count(&self) -> usize {
610 self.rows.len()
611 }
612
613 pub fn column_count(&self) -> usize {
615 self.columns.len()
616 }
617
618 pub fn to_json_array(&self) -> Result<Value> {
620 let mut json_rows = Vec::new();
621 for row in &self.rows {
622 json_rows.push(row.to_json(&self.columns)?);
623 }
624 Ok(Value::Array(json_rows))
625 }
626}
627
628#[derive(Debug, Clone, Serialize, Deserialize)]
630pub struct DataRow {
631 pub values: Vec<Value>,
633 pub metadata: HashMap<String, Value>,
635}
636
637impl DataRow {
638 pub fn new(values: Vec<Value>) -> Self {
640 Self {
641 values,
642 metadata: HashMap::new(),
643 }
644 }
645
646 pub fn get(&self, index: usize) -> Option<&Value> {
648 self.values.get(index)
649 }
650
651 pub fn get_by_name(&self, name: &str, columns: &[ColumnInfo]) -> Option<&Value> {
653 columns
654 .iter()
655 .position(|col| col.name == name)
656 .and_then(|index| self.get(index))
657 }
658
659 pub fn to_json(&self, columns: &[ColumnInfo]) -> Result<Value> {
661 let mut obj = serde_json::Map::new();
662 for (i, value) in self.values.iter().enumerate() {
663 if let Some(column) = columns.get(i) {
664 obj.insert(column.name.clone(), value.clone());
665 }
666 }
667 Ok(Value::Object(obj))
668 }
669}
670
671#[derive(Debug, Clone, Serialize, Deserialize)]
673pub struct ColumnInfo {
674 pub name: String,
676 pub data_type: DataType,
678 pub nullable: bool,
680 pub description: Option<String>,
682 pub metadata: HashMap<String, Value>,
684}
685
686impl ColumnInfo {
687 pub fn new<S: Into<String>>(name: S, data_type: DataType) -> Self {
689 Self {
690 name: name.into(),
691 data_type,
692 nullable: true,
693 description: None,
694 metadata: HashMap::new(),
695 }
696 }
697
698 pub fn nullable(mut self, nullable: bool) -> Self {
700 self.nullable = nullable;
701 self
702 }
703
704 pub fn description<S: Into<String>>(mut self, description: S) -> Self {
706 self.description = Some(description.into());
707 self
708 }
709
710 pub fn with_metadata<S: Into<String>>(mut self, key: S, value: Value) -> Self {
712 self.metadata.insert(key.into(), value);
713 self
714 }
715}
716
717#[derive(Debug, Clone, Serialize, Deserialize)]
719pub enum DataType {
720 Text,
722 Integer,
724 Float,
726 Boolean,
728 DateTime,
730 Binary,
732 Json,
734 Uuid,
736 Custom(String),
738}
739
740impl fmt::Display for DataType {
741 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
742 match self {
743 DataType::Text => write!(f, "TEXT"),
744 DataType::Integer => write!(f, "INTEGER"),
745 DataType::Float => write!(f, "FLOAT"),
746 DataType::Boolean => write!(f, "BOOLEAN"),
747 DataType::DateTime => write!(f, "DATETIME"),
748 DataType::Binary => write!(f, "BINARY"),
749 DataType::Json => write!(f, "JSON"),
750 DataType::Uuid => write!(f, "UUID"),
751 DataType::Custom(custom) => write!(f, "{}", custom),
752 }
753 }
754}
755
756#[derive(Debug, Clone, Serialize, Deserialize)]
758pub struct Schema {
759 pub name: Option<String>,
761 pub tables: Vec<TableInfo>,
763 pub metadata: HashMap<String, Value>,
765}
766
767impl Default for Schema {
768 fn default() -> Self {
769 Self::new()
770 }
771}
772
773impl Schema {
774 pub fn new() -> Self {
776 Self {
777 name: None,
778 tables: Vec::new(),
779 metadata: HashMap::new(),
780 }
781 }
782
783 pub fn with_table(mut self, table: TableInfo) -> Self {
785 self.tables.push(table);
786 self
787 }
788
789 pub fn get_table(&self, name: &str) -> Option<&TableInfo> {
791 self.tables.iter().find(|t| t.name == name)
792 }
793
794 pub fn table_names(&self) -> Vec<&str> {
796 self.tables.iter().map(|t| t.name.as_str()).collect()
797 }
798}
799
800#[derive(Debug, Clone, Serialize, Deserialize)]
802pub struct TableInfo {
803 pub name: String,
805 pub columns: Vec<ColumnInfo>,
807 pub primary_keys: Vec<String>,
809 pub foreign_keys: Vec<ForeignKey>,
811 pub description: Option<String>,
813 pub row_count: Option<usize>,
815 pub metadata: HashMap<String, Value>,
817}
818
819impl TableInfo {
820 pub fn new<S: Into<String>>(name: S) -> Self {
822 Self {
823 name: name.into(),
824 columns: Vec::new(),
825 primary_keys: Vec::new(),
826 foreign_keys: Vec::new(),
827 description: None,
828 row_count: None,
829 metadata: HashMap::new(),
830 }
831 }
832
833 pub fn with_column(mut self, column: ColumnInfo) -> Self {
835 self.columns.push(column);
836 self
837 }
838
839 pub fn with_primary_key<S: Into<String>>(mut self, column: S) -> Self {
841 self.primary_keys.push(column.into());
842 self
843 }
844
845 pub fn with_foreign_key(mut self, fk: ForeignKey) -> Self {
847 self.foreign_keys.push(fk);
848 self
849 }
850
851 pub fn description<S: Into<String>>(mut self, description: S) -> Self {
853 self.description = Some(description.into());
854 self
855 }
856
857 pub fn row_count(mut self, count: usize) -> Self {
859 self.row_count = Some(count);
860 self
861 }
862
863 pub fn get_column(&self, name: &str) -> Option<&ColumnInfo> {
865 self.columns.iter().find(|c| c.name == name)
866 }
867
868 pub fn is_primary_key(&self, column: &str) -> bool {
870 self.primary_keys.contains(&column.to_string())
871 }
872}
873
874#[derive(Debug, Clone, Serialize, Deserialize)]
876pub struct ForeignKey {
877 pub column: String,
879 pub referenced_table: String,
881 pub referenced_column: String,
883 pub name: Option<String>,
885}
886
887#[derive(Debug, Clone, Serialize, Deserialize)]
889pub struct ConnectionTestResult {
890 pub success: bool,
892 pub message: String,
894 pub latency_ms: Option<u64>,
896 pub metadata: HashMap<String, Value>,
898}
899
900impl ConnectionTestResult {
901 pub fn success<S: Into<String>>(message: S) -> Self {
903 Self {
904 success: true,
905 message: message.into(),
906 latency_ms: None,
907 metadata: HashMap::new(),
908 }
909 }
910
911 pub fn failure<S: Into<String>>(message: S) -> Self {
913 Self {
914 success: false,
915 message: message.into(),
916 latency_ms: None,
917 metadata: HashMap::new(),
918 }
919 }
920
921 pub fn with_latency(mut self, latency_ms: u64) -> Self {
923 self.latency_ms = Some(latency_ms);
924 self
925 }
926
927 pub fn with_metadata<S: Into<String>>(mut self, key: S, value: Value) -> Self {
929 self.metadata.insert(key.into(), value);
930 self
931 }
932}
933
934pub struct DataSourcePluginEntry {
936 pub plugin_id: crate::PluginId,
938 pub plugin: std::sync::Arc<dyn DataSourcePlugin>,
940 pub config: DataSourcePluginConfig,
942 pub capabilities: PluginCapabilities,
944}
945
946impl DataSourcePluginEntry {
947 pub fn new(
949 plugin_id: crate::PluginId,
950 plugin: std::sync::Arc<dyn DataSourcePlugin>,
951 config: DataSourcePluginConfig,
952 ) -> Self {
953 let capabilities = plugin.capabilities();
954 Self {
955 plugin_id,
956 plugin,
957 config,
958 capabilities,
959 }
960 }
961
962 pub fn is_enabled(&self) -> bool {
964 self.config.enabled
965 }
966
967 pub fn supports_type(&self, data_type: &str) -> bool {
969 self.config.data_source_type == data_type
970 }
971}
972
973pub trait DataSourcePluginFactory: Send + Sync {
975 fn create_plugin(&self) -> Result<Box<dyn DataSourcePlugin>>;
977}
978
979pub mod helpers {
981 use super::*;
982
983 pub fn create_memory_data_source() -> Vec<DataRow> {
985 vec![
986 DataRow::new(vec![
987 Value::String("John".to_string()),
988 Value::String("Doe".to_string()),
989 Value::Number(30.into()),
990 ]),
991 DataRow::new(vec![
992 Value::String("Jane".to_string()),
993 Value::String("Smith".to_string()),
994 Value::Number(25.into()),
995 ]),
996 ]
997 }
998
999 pub fn create_sample_columns() -> Vec<ColumnInfo> {
1001 vec![
1002 ColumnInfo::new("first_name", DataType::Text).nullable(false),
1003 ColumnInfo::new("last_name", DataType::Text).nullable(false),
1004 ColumnInfo::new("age", DataType::Integer).nullable(false),
1005 ]
1006 }
1007
1008 pub fn create_sample_schema() -> Schema {
1010 let table = TableInfo::new("users")
1011 .with_column(ColumnInfo::new("id", DataType::Integer).nullable(false))
1012 .with_column(ColumnInfo::new("first_name", DataType::Text).nullable(false))
1013 .with_column(ColumnInfo::new("last_name", DataType::Text).nullable(false))
1014 .with_column(ColumnInfo::new("email", DataType::Text).nullable(false))
1015 .with_primary_key("id");
1016
1017 Schema::new().with_table(table)
1018 }
1019}
1020
1021#[cfg(test)]
1022mod tests {
1023 use super::*;
1024
1025 #[test]
1028 fn test_data_source_plugin_config_default() {
1029 let config = DataSourcePluginConfig::default();
1030
1031 assert!(config.config.is_empty());
1032 assert!(config.enabled);
1033 assert_eq!(config.data_source_type, "unknown");
1034 assert!(config.connection_string.is_none());
1035 assert_eq!(config.connection_timeout_secs, 30);
1036 assert_eq!(config.query_timeout_secs, 30);
1037 assert_eq!(config.max_connections, 10);
1038 assert!(config.credentials.is_none());
1039 assert!(config.ssl_config.is_none());
1040 assert!(config.settings.is_empty());
1041 }
1042
1043 #[test]
1044 fn test_data_source_plugin_config_custom() {
1045 let config = DataSourcePluginConfig {
1046 config: HashMap::from([("key".to_string(), Value::String("value".to_string()))]),
1047 enabled: false,
1048 data_source_type: "postgresql".to_string(),
1049 connection_string: Some("postgres://localhost:5432".to_string()),
1050 connection_timeout_secs: 60,
1051 query_timeout_secs: 120,
1052 max_connections: 20,
1053 credentials: Some(DataSourceCredentials::user_pass("user", "pass")),
1054 ssl_config: Some(SslConfig::default()),
1055 settings: HashMap::new(),
1056 };
1057
1058 assert!(!config.config.is_empty());
1059 assert!(!config.enabled);
1060 assert_eq!(config.data_source_type, "postgresql");
1061 assert!(config.connection_string.is_some());
1062 }
1063
1064 #[test]
1065 fn test_data_source_plugin_config_clone() {
1066 let config = DataSourcePluginConfig::default();
1067 let cloned = config.clone();
1068
1069 assert_eq!(cloned.data_source_type, config.data_source_type);
1070 assert_eq!(cloned.enabled, config.enabled);
1071 }
1072
1073 #[test]
1074 fn test_data_source_plugin_config_serialization() {
1075 let config = DataSourcePluginConfig::default();
1076 let json = serde_json::to_string(&config).unwrap();
1077 let deserialized: DataSourcePluginConfig = serde_json::from_str(&json).unwrap();
1078
1079 assert_eq!(deserialized.data_source_type, config.data_source_type);
1080 }
1081
1082 #[test]
1085 fn test_credentials_user_pass() {
1086 let creds = DataSourceCredentials::user_pass("admin", "secret123");
1087
1088 assert_eq!(creds.username.as_deref(), Some("admin"));
1089 assert_eq!(creds.password.as_deref(), Some("secret123"));
1090 assert!(creds.api_key.is_none());
1091 assert!(creds.bearer_token.is_none());
1092 }
1093
1094 #[test]
1095 fn test_credentials_api_key() {
1096 let creds = DataSourceCredentials::api_key("my-api-key-12345");
1097
1098 assert!(creds.username.is_none());
1099 assert!(creds.password.is_none());
1100 assert_eq!(creds.api_key.as_deref(), Some("my-api-key-12345"));
1101 assert!(creds.bearer_token.is_none());
1102 }
1103
1104 #[test]
1105 fn test_credentials_bearer_token() {
1106 let creds = DataSourceCredentials::bearer_token("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9");
1107
1108 assert!(creds.username.is_none());
1109 assert!(creds.password.is_none());
1110 assert!(creds.api_key.is_none());
1111 assert_eq!(creds.bearer_token.as_deref(), Some("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"));
1112 }
1113
1114 #[test]
1115 fn test_credentials_clone() {
1116 let creds = DataSourceCredentials::api_key("test");
1117 let cloned = creds.clone();
1118
1119 assert_eq!(cloned.api_key, creds.api_key);
1120 }
1121
1122 #[test]
1125 fn test_ssl_config_default() {
1126 let config = SslConfig::default();
1127
1128 assert!(!config.enabled);
1129 assert!(config.ca_cert_path.is_none());
1130 assert!(config.client_cert_path.is_none());
1131 assert!(config.client_key_path.is_none());
1132 assert!(!config.skip_verify);
1133 assert!(config.custom.is_empty());
1134 }
1135
1136 #[test]
1137 fn test_ssl_config_custom() {
1138 let config = SslConfig {
1139 enabled: true,
1140 ca_cert_path: Some("/certs/ca.pem".to_string()),
1141 client_cert_path: Some("/certs/client.pem".to_string()),
1142 client_key_path: Some("/certs/client.key".to_string()),
1143 skip_verify: false,
1144 custom: HashMap::new(),
1145 };
1146
1147 assert!(config.enabled);
1148 assert_eq!(config.ca_cert_path.as_deref(), Some("/certs/ca.pem"));
1149 }
1150
1151 #[test]
1154 fn test_data_connection_new() {
1155 let conn = DataConnection::new("postgresql", Value::Null);
1156
1157 assert!(!conn.id.is_empty());
1158 assert_eq!(conn.connection_type, "postgresql");
1159 assert!(conn.metadata.is_empty());
1160 }
1161
1162 #[test]
1163 fn test_data_connection_mark_used() {
1164 let mut conn = DataConnection::new("mysql", Value::Null);
1165 let original_last_used = conn.last_used;
1166
1167 std::thread::sleep(std::time::Duration::from_millis(10));
1168 conn.mark_used();
1169
1170 assert!(conn.last_used >= original_last_used);
1171 }
1172
1173 #[test]
1174 fn test_data_connection_with_metadata() {
1175 let conn = DataConnection::new("api", Value::Null)
1176 .with_metadata("version", Value::String("v1".to_string()));
1177
1178 assert!(conn.metadata("version").is_some());
1179 assert!(conn.metadata("nonexistent").is_none());
1180 }
1181
1182 #[test]
1183 fn test_data_connection_is_stale() {
1184 let conn = DataConnection::new("test", Value::Null);
1185
1186 assert!(!conn.is_stale(chrono::Duration::hours(1)));
1188
1189 assert!(conn.is_stale(chrono::Duration::zero()));
1191 }
1192
1193 #[test]
1194 fn test_data_connection_clone() {
1195 let conn = DataConnection::new("sqlite", Value::Null);
1196 let cloned = conn.clone();
1197
1198 assert_eq!(cloned.id, conn.id);
1199 assert_eq!(cloned.connection_type, conn.connection_type);
1200 }
1201
1202 #[test]
1205 fn test_data_query_select() {
1206 let query = DataQuery::select("SELECT * FROM users");
1207
1208 assert!(matches!(query.query_type, QueryType::Select));
1209 assert_eq!(query.query, "SELECT * FROM users");
1210 }
1211
1212 #[test]
1213 fn test_data_query_insert() {
1214 let query = DataQuery::insert("INSERT INTO users VALUES (?)");
1215
1216 assert!(matches!(query.query_type, QueryType::Insert));
1217 }
1218
1219 #[test]
1220 fn test_data_query_update() {
1221 let query = DataQuery::update("UPDATE users SET name = ?");
1222
1223 assert!(matches!(query.query_type, QueryType::Update));
1224 }
1225
1226 #[test]
1227 fn test_data_query_delete() {
1228 let query = DataQuery::delete("DELETE FROM users WHERE id = ?");
1229
1230 assert!(matches!(query.query_type, QueryType::Delete));
1231 }
1232
1233 #[test]
1234 fn test_data_query_with_parameter() {
1235 let query = DataQuery::select("SELECT * FROM users WHERE id = :id")
1236 .with_parameter("id", Value::Number(42.into()));
1237
1238 assert!(query.parameters.contains_key("id"));
1239 }
1240
1241 #[test]
1242 fn test_data_query_with_limit() {
1243 let query = DataQuery::select("SELECT * FROM users").with_limit(10);
1244
1245 assert_eq!(query.limit, Some(10));
1246 }
1247
1248 #[test]
1249 fn test_data_query_with_offset() {
1250 let query = DataQuery::select("SELECT * FROM users").with_offset(20);
1251
1252 assert_eq!(query.offset, Some(20));
1253 }
1254
1255 #[test]
1256 fn test_data_query_with_sort() {
1257 let query = DataQuery::select("SELECT * FROM users").with_sort(SortField::asc("name"));
1258
1259 assert!(query.sort.is_some());
1260 assert_eq!(query.sort.as_ref().unwrap().len(), 1);
1261 }
1262
1263 #[test]
1264 fn test_data_query_with_filter() {
1265 let query = DataQuery::select("SELECT * FROM users")
1266 .with_filter(QueryFilter::equals("status", Value::String("active".to_string())));
1267
1268 assert_eq!(query.filters.len(), 1);
1269 }
1270
1271 #[test]
1272 fn test_data_query_with_option() {
1273 let query = DataQuery::select("SELECT * FROM users")
1274 .with_option("timeout", Value::Number(30.into()));
1275
1276 assert!(query.options.contains_key("timeout"));
1277 }
1278
1279 #[test]
1280 fn test_data_query_chained() {
1281 let query = DataQuery::select("SELECT * FROM users")
1282 .with_parameter("status", Value::String("active".to_string()))
1283 .with_limit(50)
1284 .with_offset(0)
1285 .with_sort(SortField::desc("created_at"));
1286
1287 assert!(!query.parameters.is_empty());
1288 assert_eq!(query.limit, Some(50));
1289 assert_eq!(query.offset, Some(0));
1290 assert!(query.sort.is_some());
1291 }
1292
1293 #[test]
1296 fn test_query_type_display_select() {
1297 assert_eq!(format!("{}", QueryType::Select), "SELECT");
1298 }
1299
1300 #[test]
1301 fn test_query_type_display_insert() {
1302 assert_eq!(format!("{}", QueryType::Insert), "INSERT");
1303 }
1304
1305 #[test]
1306 fn test_query_type_display_update() {
1307 assert_eq!(format!("{}", QueryType::Update), "UPDATE");
1308 }
1309
1310 #[test]
1311 fn test_query_type_display_delete() {
1312 assert_eq!(format!("{}", QueryType::Delete), "DELETE");
1313 }
1314
1315 #[test]
1316 fn test_query_type_display_custom() {
1317 assert_eq!(format!("{}", QueryType::Custom("MERGE".to_string())), "MERGE");
1318 }
1319
1320 #[test]
1323 fn test_sort_field_asc() {
1324 let sort = SortField::asc("name");
1325
1326 assert_eq!(sort.field, "name");
1327 assert!(matches!(sort.direction, SortDirection::Ascending));
1328 }
1329
1330 #[test]
1331 fn test_sort_field_desc() {
1332 let sort = SortField::desc("created_at");
1333
1334 assert_eq!(sort.field, "created_at");
1335 assert!(matches!(sort.direction, SortDirection::Descending));
1336 }
1337
1338 #[test]
1341 fn test_query_filter_equals() {
1342 let filter = QueryFilter::equals("status", Value::String("active".to_string()));
1343
1344 assert_eq!(filter.field, "status");
1345 assert!(matches!(filter.operator, FilterOperator::Equals));
1346 }
1347
1348 #[test]
1349 fn test_query_filter_greater_than() {
1350 let filter = QueryFilter::greater_than("age", Value::Number(18.into()));
1351
1352 assert!(matches!(filter.operator, FilterOperator::GreaterThan));
1353 }
1354
1355 #[test]
1356 fn test_query_filter_less_than() {
1357 let filter = QueryFilter::less_than("price", Value::Number(100.into()));
1358
1359 assert!(matches!(filter.operator, FilterOperator::LessThan));
1360 }
1361
1362 #[test]
1363 fn test_query_filter_contains() {
1364 let filter = QueryFilter::contains("name", Value::String("test".to_string()));
1365
1366 assert!(matches!(filter.operator, FilterOperator::Contains));
1367 }
1368
1369 #[test]
1370 fn test_query_filter_and() {
1371 let filter = QueryFilter::equals("status", Value::String("active".to_string())).and();
1372
1373 assert!(matches!(filter.logical_op, Some(LogicalOperator::And)));
1374 }
1375
1376 #[test]
1377 fn test_query_filter_or() {
1378 let filter = QueryFilter::equals("status", Value::String("pending".to_string())).or();
1379
1380 assert!(matches!(filter.logical_op, Some(LogicalOperator::Or)));
1381 }
1382
1383 #[test]
1386 fn test_data_result_empty() {
1387 let result = DataResult::empty();
1388
1389 assert!(result.rows.is_empty());
1390 assert!(result.columns.is_empty());
1391 assert_eq!(result.total_count, Some(0));
1392 assert_eq!(result.execution_time_ms, 0);
1393 }
1394
1395 #[test]
1396 fn test_data_result_with_rows() {
1397 let rows = vec![
1398 DataRow::new(vec![Value::String("test".to_string())]),
1399 DataRow::new(vec![Value::String("test2".to_string())]),
1400 ];
1401 let columns = vec![ColumnInfo::new("name", DataType::Text)];
1402
1403 let result = DataResult::with_rows(rows, columns);
1404
1405 assert_eq!(result.row_count(), 2);
1406 assert_eq!(result.column_count(), 1);
1407 }
1408
1409 #[test]
1410 fn test_data_result_with_metadata() {
1411 let result = DataResult::empty().with_metadata("source", Value::String("test".to_string()));
1412
1413 assert!(result.metadata.contains_key("source"));
1414 }
1415
1416 #[test]
1417 fn test_data_result_with_execution_time() {
1418 let result = DataResult::empty().with_execution_time(150);
1419
1420 assert_eq!(result.execution_time_ms, 150);
1421 }
1422
1423 #[test]
1424 fn test_data_result_to_json_array() {
1425 let rows = vec![DataRow::new(vec![Value::String("John".to_string())])];
1426 let columns = vec![ColumnInfo::new("name", DataType::Text)];
1427 let result = DataResult::with_rows(rows, columns);
1428
1429 let json = result.to_json_array().unwrap();
1430 assert!(json.is_array());
1431 }
1432
1433 #[test]
1436 fn test_data_row_new() {
1437 let row = DataRow::new(vec![Value::Number(1.into()), Value::String("test".to_string())]);
1438
1439 assert_eq!(row.values.len(), 2);
1440 assert!(row.metadata.is_empty());
1441 }
1442
1443 #[test]
1444 fn test_data_row_get() {
1445 let row = DataRow::new(vec![Value::Number(42.into())]);
1446
1447 assert!(row.get(0).is_some());
1448 assert!(row.get(1).is_none());
1449 }
1450
1451 #[test]
1452 fn test_data_row_get_by_name() {
1453 let row = DataRow::new(vec![Value::String("John".to_string())]);
1454 let columns = vec![ColumnInfo::new("name", DataType::Text)];
1455
1456 assert!(row.get_by_name("name", &columns).is_some());
1457 assert!(row.get_by_name("nonexistent", &columns).is_none());
1458 }
1459
1460 #[test]
1461 fn test_data_row_to_json() {
1462 let row = DataRow::new(vec![Value::String("John".to_string()), Value::Number(30.into())]);
1463 let columns = vec![
1464 ColumnInfo::new("name", DataType::Text),
1465 ColumnInfo::new("age", DataType::Integer),
1466 ];
1467
1468 let json = row.to_json(&columns).unwrap();
1469 assert!(json.is_object());
1470 }
1471
1472 #[test]
1475 fn test_column_info_new() {
1476 let col = ColumnInfo::new("id", DataType::Integer);
1477
1478 assert_eq!(col.name, "id");
1479 assert!(col.nullable);
1480 assert!(col.description.is_none());
1481 }
1482
1483 #[test]
1484 fn test_column_info_nullable() {
1485 let col = ColumnInfo::new("id", DataType::Integer).nullable(false);
1486
1487 assert!(!col.nullable);
1488 }
1489
1490 #[test]
1491 fn test_column_info_description() {
1492 let col = ColumnInfo::new("id", DataType::Integer).description("Primary key");
1493
1494 assert_eq!(col.description.as_deref(), Some("Primary key"));
1495 }
1496
1497 #[test]
1498 fn test_column_info_with_metadata() {
1499 let col =
1500 ColumnInfo::new("id", DataType::Integer).with_metadata("index", Value::Bool(true));
1501
1502 assert!(col.metadata.contains_key("index"));
1503 }
1504
1505 #[test]
1508 fn test_data_type_display_text() {
1509 assert_eq!(format!("{}", DataType::Text), "TEXT");
1510 }
1511
1512 #[test]
1513 fn test_data_type_display_integer() {
1514 assert_eq!(format!("{}", DataType::Integer), "INTEGER");
1515 }
1516
1517 #[test]
1518 fn test_data_type_display_float() {
1519 assert_eq!(format!("{}", DataType::Float), "FLOAT");
1520 }
1521
1522 #[test]
1523 fn test_data_type_display_boolean() {
1524 assert_eq!(format!("{}", DataType::Boolean), "BOOLEAN");
1525 }
1526
1527 #[test]
1528 fn test_data_type_display_datetime() {
1529 assert_eq!(format!("{}", DataType::DateTime), "DATETIME");
1530 }
1531
1532 #[test]
1533 fn test_data_type_display_custom() {
1534 assert_eq!(format!("{}", DataType::Custom("MONEY".to_string())), "MONEY");
1535 }
1536
1537 #[test]
1540 fn test_schema_default() {
1541 let schema = Schema::default();
1542
1543 assert!(schema.name.is_none());
1544 assert!(schema.tables.is_empty());
1545 }
1546
1547 #[test]
1548 fn test_schema_new() {
1549 let schema = Schema::new();
1550
1551 assert!(schema.tables.is_empty());
1552 }
1553
1554 #[test]
1555 fn test_schema_with_table() {
1556 let schema = Schema::new().with_table(TableInfo::new("users"));
1557
1558 assert_eq!(schema.tables.len(), 1);
1559 }
1560
1561 #[test]
1562 fn test_schema_get_table() {
1563 let schema = Schema::new().with_table(TableInfo::new("users"));
1564
1565 assert!(schema.get_table("users").is_some());
1566 assert!(schema.get_table("nonexistent").is_none());
1567 }
1568
1569 #[test]
1570 fn test_schema_table_names() {
1571 let schema = Schema::new()
1572 .with_table(TableInfo::new("users"))
1573 .with_table(TableInfo::new("orders"));
1574
1575 let names = schema.table_names();
1576 assert!(names.contains(&"users"));
1577 assert!(names.contains(&"orders"));
1578 }
1579
1580 #[test]
1583 fn test_table_info_new() {
1584 let table = TableInfo::new("users");
1585
1586 assert_eq!(table.name, "users");
1587 assert!(table.columns.is_empty());
1588 assert!(table.primary_keys.is_empty());
1589 }
1590
1591 #[test]
1592 fn test_table_info_with_column() {
1593 let table = TableInfo::new("users").with_column(ColumnInfo::new("id", DataType::Integer));
1594
1595 assert_eq!(table.columns.len(), 1);
1596 }
1597
1598 #[test]
1599 fn test_table_info_with_primary_key() {
1600 let table = TableInfo::new("users").with_primary_key("id");
1601
1602 assert!(table.is_primary_key("id"));
1603 assert!(!table.is_primary_key("name"));
1604 }
1605
1606 #[test]
1607 fn test_table_info_with_foreign_key() {
1608 let fk = ForeignKey {
1609 column: "user_id".to_string(),
1610 referenced_table: "users".to_string(),
1611 referenced_column: "id".to_string(),
1612 name: Some("fk_orders_user".to_string()),
1613 };
1614
1615 let table = TableInfo::new("orders").with_foreign_key(fk);
1616
1617 assert_eq!(table.foreign_keys.len(), 1);
1618 }
1619
1620 #[test]
1621 fn test_table_info_description() {
1622 let table = TableInfo::new("users").description("Stores user information");
1623
1624 assert_eq!(table.description.as_deref(), Some("Stores user information"));
1625 }
1626
1627 #[test]
1628 fn test_table_info_row_count() {
1629 let table = TableInfo::new("users").row_count(1000);
1630
1631 assert_eq!(table.row_count, Some(1000));
1632 }
1633
1634 #[test]
1635 fn test_table_info_get_column() {
1636 let table = TableInfo::new("users")
1637 .with_column(ColumnInfo::new("id", DataType::Integer))
1638 .with_column(ColumnInfo::new("name", DataType::Text));
1639
1640 assert!(table.get_column("id").is_some());
1641 assert!(table.get_column("nonexistent").is_none());
1642 }
1643
1644 #[test]
1647 fn test_foreign_key_creation() {
1648 let fk = ForeignKey {
1649 column: "user_id".to_string(),
1650 referenced_table: "users".to_string(),
1651 referenced_column: "id".to_string(),
1652 name: None,
1653 };
1654
1655 assert_eq!(fk.column, "user_id");
1656 assert_eq!(fk.referenced_table, "users");
1657 }
1658
1659 #[test]
1662 fn test_connection_test_result_success() {
1663 let result = ConnectionTestResult::success("Connection successful");
1664
1665 assert!(result.success);
1666 assert_eq!(result.message, "Connection successful");
1667 }
1668
1669 #[test]
1670 fn test_connection_test_result_failure() {
1671 let result = ConnectionTestResult::failure("Connection refused");
1672
1673 assert!(!result.success);
1674 assert_eq!(result.message, "Connection refused");
1675 }
1676
1677 #[test]
1678 fn test_connection_test_result_with_latency() {
1679 let result = ConnectionTestResult::success("OK").with_latency(50);
1680
1681 assert_eq!(result.latency_ms, Some(50));
1682 }
1683
1684 #[test]
1685 fn test_connection_test_result_with_metadata() {
1686 let result = ConnectionTestResult::success("OK")
1687 .with_metadata("version", Value::String("5.7".to_string()));
1688
1689 assert!(result.metadata.contains_key("version"));
1690 }
1691
1692 #[test]
1695 fn test_helpers_create_memory_data_source() {
1696 let rows = helpers::create_memory_data_source();
1697
1698 assert_eq!(rows.len(), 2);
1699 assert_eq!(rows[0].values.len(), 3);
1700 }
1701
1702 #[test]
1703 fn test_helpers_create_sample_columns() {
1704 let columns = helpers::create_sample_columns();
1705
1706 assert_eq!(columns.len(), 3);
1707 assert_eq!(columns[0].name, "first_name");
1708 }
1709
1710 #[test]
1711 fn test_helpers_create_sample_schema() {
1712 let schema = helpers::create_sample_schema();
1713
1714 assert!(schema.get_table("users").is_some());
1715 let users = schema.get_table("users").unwrap();
1716 assert!(users.is_primary_key("id"));
1717 }
1718}