orchestra_toolkit/session/api/avial/
features.rs

1/* Copyright 2024-2025 LEDR Technologies Inc.
2* This file is part of the Orchestra library, which helps developer use our Orchestra technology which is based on AvesTerra, owned and developped by Georgetown University, under license agreement with LEDR Technologies Inc.
3*
4* The Orchestra library is a free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
5*
6* The Orchestra library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
7*
8* You should have received a copy of the GNU Lesser General Public License along with the Orchestra library. If not, see <https://www.gnu.org/licenses/>.
9*
10* If you have any questions, feedback or issues about the Orchestra library, you can contact us at support@ledr.io.
11*/
12
13use std::{
14    future::{Future, IntoFuture},
15    pin::Pin,
16};
17
18use num_enum::TryFromPrimitive;
19
20use crate::{
21    taxonomy::*, CallError, Entity, InvalidResponse, Session, SessionAsync, SessionTrait,
22    String255, Token, Value,
23};
24
25use crate::session::api::macros::*;
26
27// ------------------------
28// -- Indexed operations --
29// ------------------------
30
31decl_call! {
32    InsertFeature(entity: Entity, attribute: Attribute, key: String255, name: String255, value: Value, authorization: Token) -> (),
33    {
34        index: i64,
35        instance: i32,
36        deferred: bool,
37    }
38}
39impl<T: SessionTrait> InsertFeature<T> {
40    async fn call_async(self) -> Result<(), CallError> {
41        let _ = self
42            .session
43            .get_async_session()
44            .invoke_entity(self.entity, Method::Insert, self.authorization)
45            .with_aspect(Aspect::Feature)
46            .with_attribute(self.attribute)
47            .with_name(self.name)
48            .with_key(self.key)
49            .with_value(&self.value)
50            .with_index(self.index)
51            .with_instance(self.instance)
52            .with_parameter(self.deferred as i64)
53            .await?;
54        Ok(())
55    }
56}
57
58decl_call! {
59    RemoveFeature(entity: Entity, attribute: Attribute, index: i64, authorization: Token) -> (),
60    {
61        instance: i32,
62        deferred: bool,
63    }
64}
65impl<T: SessionTrait> RemoveFeature<T> {
66    async fn call_async(self) -> Result<(), CallError> {
67        let _ = self
68            .session
69            .get_async_session()
70            .invoke_entity(self.entity, Method::Remove, self.authorization)
71            .with_aspect(Aspect::Feature)
72            .with_attribute(self.attribute)
73            .with_index(self.index)
74            .with_instance(self.instance)
75            .with_parameter(self.deferred as i64)
76            .await?;
77        Ok(())
78    }
79}
80
81decl_call! {
82    ReplaceFeature(entity: Entity, attribute: Attribute, key: String255, name: String255, value: Value, authorization: Token) -> (),
83    {
84        index: i64,
85        instance: i32,
86        deferred: bool,
87    }
88}
89impl<T: SessionTrait> ReplaceFeature<T> {
90    async fn call_async(self) -> Result<(), CallError> {
91        let _ = self
92            .session
93            .get_async_session()
94            .invoke_entity(self.entity, Method::Replace, self.authorization)
95            .with_aspect(Aspect::Feature)
96            .with_attribute(self.attribute)
97            .with_name(self.name)
98            .with_key(self.key)
99            .with_value(&self.value)
100            .with_index(self.index)
101            .with_instance(self.instance)
102            .with_parameter(self.deferred as i64)
103            .await?;
104        Ok(())
105    }
106}
107
108decl_call! {
109    FindFeature(entity: Entity, attribute: Attribute, authorization: Token) -> i64,
110    {
111        instance: i32,
112        index: i64,
113
114        // Search either name or value. If both are given, search by value first.
115        name: String255,
116        value: Value,
117    }
118}
119impl<T: SessionTrait> FindFeature<T> {
120    async fn call_async(self) -> Result<i64, CallError> {
121        let res = self
122            .session
123            .get_async_session()
124            .invoke_entity(self.entity, Method::Find, self.authorization)
125            .with_aspect(Aspect::Feature)
126            .with_attribute(self.attribute)
127            .with_name(self.name)
128            .with_value(&self.value)
129            .with_index(self.index)
130            .with_instance(self.instance)
131            .await?;
132        Ok(res.integer()?)
133    }
134}
135
136// -----------------------
137// -- Mapped operations --
138// -----------------------
139
140decl_call! {
141    IncludeFeature(entity: Entity, attribute: Attribute, key: String255, name: String255, value: Value, authorization: Token) -> (),
142    {
143        deferred: bool,
144    }
145}
146impl<T: SessionTrait> IncludeFeature<T> {
147    async fn call_async(self) -> Result<(), CallError> {
148        let _ = self
149            .session
150            .get_async_session()
151            .invoke_entity(self.entity, Method::Include, self.authorization)
152            .with_aspect(Aspect::Feature)
153            .with_attribute(self.attribute)
154            .with_name(self.name)
155            .with_key(self.key)
156            .with_value(&self.value)
157            .with_parameter(self.deferred as i64)
158            .await?;
159        Ok(())
160    }
161}
162
163decl_call! {
164    ExcludeFeature(entity: Entity, attribute: Attribute, key: String255, authorization: Token) -> (),
165    {
166        deferred: bool,
167    }
168}
169impl<T: SessionTrait> ExcludeFeature<T> {
170    async fn call_async(self) -> Result<(), CallError> {
171        let _ = self
172            .session
173            .get_async_session()
174            .invoke_entity(self.entity, Method::Exclude, self.authorization)
175            .with_aspect(Aspect::Feature)
176            .with_attribute(self.attribute)
177            .with_key(self.key)
178            .with_parameter(self.deferred as i64)
179            .await?;
180        Ok(())
181    }
182}
183
184// -----------------------
185// -- Hybrid operations --
186// -----------------------
187
188decl_call! {
189    SetFeature(entity: Entity, attribute: Attribute, key: String255, name: String255, value: Value, authorization: Token) -> (),
190    {
191        deferred: bool,
192    }
193}
194impl<T: SessionTrait> SetFeature<T> {
195    async fn call_async(self) -> Result<(), CallError> {
196        let _ = self
197            .session
198            .get_async_session()
199            .invoke_entity(self.entity, Method::Set, self.authorization)
200            .with_aspect(Aspect::Feature)
201            .with_attribute(self.attribute)
202            .with_name(self.name)
203            .with_key(self.key)
204            .with_value(&self.value)
205            .with_parameter(self.deferred as i64)
206            .await?;
207        Ok(())
208    }
209}
210
211decl_call! {
212    GetFeature(entity: Entity, attribute: Attribute, key: String255, authorization: Token) -> Value,
213    {
214    }
215}
216impl<T: SessionTrait> GetFeature<T> {
217    async fn call_async(self) -> Result<Value, CallError> {
218        self.session
219            .get_async_session()
220            .invoke_entity(self.entity, Method::Get, self.authorization)
221            .with_aspect(Aspect::Feature)
222            .with_attribute(self.attribute)
223            .with_key(self.key)
224            .await
225    }
226}
227
228decl_call! {
229    ClearFeature(entity: Entity, attribute: Attribute, key: String255, authorization: Token) -> (),
230    {
231        deferred: bool,
232    }
233}
234impl<T: SessionTrait> ClearFeature<T> {
235    async fn call_async(self) -> Result<(), CallError> {
236        let _ = self
237            .session
238            .get_async_session()
239            .invoke_entity(self.entity, Method::Clear, self.authorization)
240            .with_aspect(Aspect::Feature)
241            .with_attribute(self.attribute)
242            .with_key(self.key)
243            .with_parameter(self.deferred as i64)
244            .await?;
245        Ok(())
246    }
247}
248
249// -----------------------
250// -- Utility functions --
251// -----------------------
252
253decl_call! {
254    FeatureCount(entity: Entity, attribute: Attribute, authorization: Token) -> i64,
255    {
256        instance: i32,
257    }
258}
259impl<T: SessionTrait> FeatureCount<T> {
260    async fn call_async(self) -> Result<i64, CallError> {
261        let res = self
262            .session
263            .get_async_session()
264            .invoke_entity(self.entity, Method::Count, self.authorization)
265            .with_aspect(Aspect::Feature)
266            .with_attribute(self.attribute)
267            .with_instance(self.instance)
268            .await?;
269        Ok(res.integer()?)
270    }
271}
272
273decl_call! {
274    FeatureMember(entity: Entity, attribute: Attribute, key: String255, authorization: Token) -> bool,
275    {
276        instance: i32,
277    }
278}
279impl<T: SessionTrait> FeatureMember<T> {
280    async fn call_async(self) -> Result<bool, CallError> {
281        let res = self
282            .session
283            .get_async_session()
284            .invoke_entity(self.entity, Method::Member, self.authorization)
285            .with_aspect(Aspect::Feature)
286            .with_attribute(self.attribute)
287            .with_key(self.key)
288            .with_instance(self.instance)
289            .await?;
290        Ok(res.boolean()?)
291    }
292}
293
294decl_call! {
295    FeatureName(entity: Entity, attribute: Attribute, key: String255, authorization: Token) -> String255,
296    {
297        index: i64,
298        instance: i32,
299    }
300}
301impl<T: SessionTrait> FeatureName<T> {
302    async fn call_async(self) -> Result<String255, CallError> {
303        let res = self
304            .session
305            .get_async_session()
306            .invoke_entity(self.entity, Method::Name, self.authorization)
307            .with_aspect(Aspect::Feature)
308            .with_attribute(self.attribute)
309            .with_key(self.key)
310            .with_index(self.index)
311            .with_instance(self.instance)
312            .await?;
313        Ok(res
314            .string()?
315            .try_into()
316            .map_err(|e| CallError::InvalidResponse(InvalidResponse::Name(e)))?)
317    }
318}
319
320decl_call! {
321    FeatureKey(entity: Entity, attribute: Attribute, index: i64, authorization: Token) -> String255,
322    {
323        instance: i32,
324    }
325}
326impl<T: SessionTrait> FeatureKey<T> {
327    async fn call_async(self) -> Result<String255, CallError> {
328        let res = self
329            .session
330            .get_async_session()
331            .invoke_entity(self.entity, Method::Key, self.authorization)
332            .with_aspect(Aspect::Feature)
333            .with_attribute(self.attribute)
334            .with_index(self.index)
335            .with_instance(self.instance)
336            .await?;
337        Ok(res
338            .string()?
339            .try_into()
340            .map_err(|e| CallError::InvalidResponse(InvalidResponse::Key(e)))?)
341    }
342}
343
344decl_call! {
345    FeatureValue(entity: Entity, attribute: Attribute, key: String255, authorization: Token) -> Value,
346    {
347        index: i64,
348        instance: i32,
349    }
350}
351impl<T: SessionTrait> FeatureValue<T> {
352    async fn call_async(self) -> Result<Value, CallError> {
353        self.session
354            .get_async_session()
355            .invoke_entity(self.entity, Method::Value, self.authorization)
356            .with_aspect(Aspect::Feature)
357            .with_attribute(self.attribute)
358            .with_key(self.key)
359            .with_index(self.index)
360            .with_instance(self.instance)
361            .await
362    }
363}
364
365decl_call! {
366    FeatureIndex(entity: Entity, attribute: Attribute, key: String255, authorization: Token) -> i64,
367    {
368        instance: i32,
369    }
370}
371impl<T: SessionTrait> FeatureIndex<T> {
372    async fn call_async(self) -> Result<i64, CallError> {
373        let res = self
374            .session
375            .get_async_session()
376            .invoke_entity(self.entity, Method::Index, self.authorization)
377            .with_aspect(Aspect::Feature)
378            .with_attribute(self.attribute)
379            .with_key(self.key)
380            .with_instance(self.instance)
381            .await?;
382        Ok(res.integer()?)
383    }
384}
385
386decl_call! {
387    // Just use FactAttribute
388    FeatureAttribute(entity: Entity, authorization: Token) -> Attribute,
389    {
390        key: String255,
391        index: i64,
392        instance: i32,
393    }
394}
395impl<T: SessionTrait> FeatureAttribute<T> {
396    async fn call_async(self) -> Result<Attribute, CallError> {
397        let res = self
398            .session
399            .get_async_session()
400            .invoke_entity(self.entity, Method::Attribute, self.authorization)
401            .with_aspect(Aspect::Feature)
402            .with_key(self.key)
403            .with_index(self.index)
404            .with_instance(self.instance)
405            .await?;
406        let num64 = res.integer()?;
407        let num16 = u16::try_from(num64).map_err(|_| InvalidResponse::Attribute(num64))?;
408        let attr =
409            Attribute::try_from_primitive(num16).map_err(|_| InvalidResponse::Attribute(num64))?;
410        Ok(attr)
411    }
412}
413
414// --------------------------
415// -- Plurality operations --
416// --------------------------
417
418decl_call! {
419    SortFeatures(entity: Entity, attribute: Attribute, authorization: Token) -> (),
420    {
421        instance: i32,
422        deferred: bool,
423    }
424}
425impl<T: SessionTrait> SortFeatures<T> {
426    async fn call_async(self) -> Result<(), CallError> {
427        let _ = self
428            .session
429            .get_async_session()
430            .invoke_entity(self.entity, Method::Sort, self.authorization)
431            .with_aspect(Aspect::Feature)
432            .with_attribute(self.attribute)
433            .with_instance(self.instance)
434            .with_parameter(self.deferred as i64)
435            .await?;
436        Ok(())
437    }
438}
439
440decl_call! {
441    PurgeFeatures(entity: Entity, attribute: Attribute, authorization: Token) -> (),
442    {
443        instance: i32,
444        deferred: bool,
445    }
446}
447impl<T: SessionTrait> PurgeFeatures<T> {
448    async fn call_async(self) -> Result<(), CallError> {
449        let _ = self
450            .session
451            .get_async_session()
452            .invoke_entity(self.entity, Method::Purge, self.authorization)
453            .with_aspect(Aspect::Feature)
454            .with_attribute(self.attribute)
455            .with_instance(self.instance)
456            .with_parameter(self.deferred as i64)
457            .await?;
458        Ok(())
459    }
460}
461
462decl_call! {
463    RetrieveFeatures(entity: Entity, attribute: Attribute, authorization: Token) -> String,
464    {
465        instance: i32,
466    }
467}
468impl<T: SessionTrait> RetrieveFeatures<T> {
469    async fn call_async(self) -> Result<String, CallError> {
470        let res = self
471            .session
472            .get_async_session()
473            .invoke_entity(self.entity, Method::Retrieve, self.authorization)
474            .with_aspect(Aspect::Feature)
475            .with_attribute(self.attribute)
476            .with_instance(self.instance)
477            .await?;
478        Ok(res.interchange()?)
479        // TODO: return Vec<Feature> ?
480    }
481}