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
1024 #[test]
1025 fn test_module_compiles() {
1026 }
1028}