ad4m_client/
subject_proxy.rs1use anyhow::{anyhow, Result};
2use maplit::btreemap;
3use serde_json::Value;
4use std::collections::BTreeMap;
5
6use crate::perspective_proxy::PerspectiveProxy;
7
8fn prolog_list_to_array(list: &Value) -> Vec<String> {
9 if let Some(Value::String(head)) = list.get("head") {
10 let mut values = vec![head.clone()];
11 if let Some(tail) = list.get("tail") {
12 values.extend(prolog_list_to_array(tail));
13 }
14 values
15 } else {
16 vec![]
17 }
18}
19
20pub struct SubjectProxy<'a> {
21 perspective: &'a PerspectiveProxy,
22 subject_class: String,
23 base: String,
24}
25
26impl<'a> SubjectProxy<'a> {
27 pub fn new(perspective: &'a PerspectiveProxy, subject_class: String, base: String) -> Self {
28 Self {
29 perspective,
30 subject_class,
31 base,
32 }
33 }
34
35 async fn query_to_array(&self, query: String) -> Result<Vec<String>> {
36 let result = self.perspective.infer(query.clone()).await?;
37 let mut values = Vec::new();
38 if let Some(result_array) = result.as_array() {
39 for p in result_array {
40 if let Some(Value::String(p)) = p.get("Value") {
41 values.push(p.clone());
42 }
43 }
44 Ok(values)
45 } else {
46 Err(anyhow!("No results found running query: {}", query))
47 }
48 }
49
50 pub async fn property_names(&self) -> Result<Vec<String>> {
51 self.query_to_array(format!(
52 r#"subject_class("{}", C), property(C, Value)"#,
53 self.subject_class
54 ))
55 .await
56 .or_else(|_| Ok(Vec::new()))
57 }
58
59 pub async fn get_property_values(&self) -> Result<BTreeMap<String, String>> {
60 let mut values = BTreeMap::new();
61 let properties = self.property_names().await?;
62 for p in properties {
63 let query = format!(
64 r#"subject_class("{}", C), property_getter(C, "{}", "{}", Value)"#,
65 self.subject_class, self.base, p
66 );
67 let result = self.perspective.infer(query).await?;
68
69 if let Some(result_array) = result.as_array() {
70 match result_array[0].get("Value") {
71 Some(Value::String(value)) => values.insert(p.clone(), value.clone()),
72 Some(Value::Number(value)) => values.insert(p.clone(), value.to_string()),
73 _ => None,
74 };
75 }
76 }
77 Ok(values)
78 }
79
80 pub async fn collection_names(&self) -> Result<Vec<String>> {
81 self.query_to_array(format!(
82 r#"subject_class("{}", C), collection(C, Value)"#,
83 self.subject_class
84 ))
85 .await
86 .or_else(|_| Ok(Vec::new()))
87 }
88
89 pub async fn get_collection_values(&self) -> Result<BTreeMap<String, Vec<String>>> {
90 let mut values = BTreeMap::new();
91 let collections = self.collection_names().await?;
92 for c in collections {
93 let query = format!(
94 r#"subject_class("{}", C), collection_getter(C, "{}", "{}", Value)"#,
95 self.subject_class, self.base, c
96 );
97 let result = self.perspective.infer(query).await?;
98
99 if let Some(result_array) = result.as_array() {
100 let mut collection_values = Vec::new();
101 for p in result_array {
102 println!("{:?}", p.get("Value"));
103 let value = p.get("Value");
104 match value {
105 Some(Value::String(value)) => {
106 collection_values.push(value.clone());
107 }
108 Some(Value::Object(_)) => {
109 collection_values.extend(prolog_list_to_array(value.as_ref().unwrap()));
110 }
111 Some(Value::Array(value)) => {
112 collection_values.extend(
113 value
114 .iter()
115 .map(|v| v.as_str().unwrap().to_string())
116 .collect::<Vec<String>>(),
117 );
118 }
119 _ => {}
120 }
121 }
122 values.insert(c, collection_values);
123 }
124 }
125 Ok(values)
126 }
127
128 pub async fn set_property(&self, property: &String, value: &String) -> Result<()> {
129 let query = format!(
130 r#"subject_class("{}", C), property_setter(C, "{}", Action)"#,
131 self.subject_class, property,
132 );
133 let result = self.perspective.infer(query).await?;
134 if let Some(result_array) = result.as_array() {
135 if let Some(Value::String(action)) = result_array[0].get("Action") {
136 self.perspective
137 .execute_action(action, &self.base, Some(btreemap! {"value" => value}))
138 .await?;
139 }
140 } else {
141 return Err(anyhow!(
142 r#"No property_setter found for property "{}" on class "{}""#,
143 property,
144 self.subject_class
145 ));
146 }
147 Ok(())
148 }
149
150 pub async fn add_collection(&self, collection: &String, new_element: &String) -> Result<()> {
151 let query = format!(
152 r#"subject_class("{}", C), collection_adder(C, "{}", Action)"#,
153 self.subject_class, collection,
154 );
155 let result = self.perspective.infer(query).await?;
156 if let Some(result_array) = result.as_array() {
157 if let Some(Value::String(action)) = result_array[0].get("Action") {
158 self.perspective
159 .execute_action(action, &self.base, Some(btreemap! {"value" => new_element}))
160 .await?;
161 }
162 } else {
163 return Err(anyhow!(
164 r#"No collection_adder found for collection "{}" on class "{}""#,
165 collection,
166 self.subject_class
167 ));
168 }
169 Ok(())
170 }
171}