1#![allow(non_snake_case)]
2
3mod concept;
4pub use concept::*;
5mod endpoints;
6pub use endpoints::*;
7
8#[macro_export]
9macro_rules! register_ast_nodes {
10 ($name:ident, $($variant: ident,)+) => {
11
12 #[derive(Clone)]
13 pub enum $name {
14 $(
15 $variant(Arc<RwLock<$variant>>),
16 )+
17 }
18 impl $name {
19 pub fn clone_without_ancestors(&self) -> Self {
20 match &self {
21 $(
22 Self::$variant(x) => Self::$variant(Arc::new(RwLock::new(x.read().unwrap().clone_without_ancestors()))),
23 )+
24 }
25 }
26 pub fn set_ancestors(&self, ancestors: Vec<AncestorRecord>) {
27 match &self {
28 $(
29 Self::$variant(x) => x.write().unwrap().set_ancestors(ancestors),
30 )+
31 }
32 }
33 pub fn get_ancestors(&self) -> Option<Vec<AncestorRecord>> {
34 match &self {
35 $(
36 Self::$variant(x) => x.read().unwrap().get_ancestors(),
37 )+
38 }
39 }
40 pub fn get_descendants(&self) -> Vec<AST> {
41 let mut queue = VecDeque::new();
42 queue.push_back(self.clone());
43 let mut current = queue.pop_front();
44 let mut v: Vec<AST> = Vec::new();
45 while let Some(elem) = current {
46 let direct_descendants = match &elem {
47 $(
48 Self::$variant(x) => {
49 let read = x.read().unwrap();
50 read.get_direct_descendants()
51 }
52 )+
53 };
54 for desc in direct_descendants.into_iter() {
55 queue.push_back(desc);
56 }
57 v.push(elem);
58 current = queue.pop_front();
59 }
60 v
61 }
62 pub fn name(&self) -> String {
63 match &self {
64 $(
65 Self::$variant(..) => stringify!($variant),
66 )+
67 }
68 .to_string()
69 }
70 pub fn optimize_fields(&self) {
71 match &self {
72 $(
73 Self::$variant(rw) => rw.write().unwrap().optimize_fields(),
74 )+
75 }
76 }
77 pub fn to_python_ast_node<'a>(
78 &self,
79 py: Python,
80 ast_module: &'a PyModule,
81 depth: usize,
82 ) -> PyResult<&'a PyAny> {
83 match &self {
84 $(
85 Self::$variant(x) => x.read().unwrap().to_python_ast_node(
86 py,
87 ast_module,
88 depth,
89 ),
90 )+
91 }
92 }
93 pub fn to_r_ast_node(
94 &self,
95 depth: usize,
96 ) -> Robj {
97 match &self {
98 $(
99 Self::$variant(x) => x.read().unwrap().to_r_ast_node(
100 depth,
101 ),
102 )+
103 }
104 }
105 }
106 impl PartialEq for $name {
107 fn eq(&self, other: &Self) -> bool {
108 match (&self, other) {
109 $(
110 (Self::$variant(v1), Self::$variant(v2)) => {
111 v1.read().unwrap().eq(&v2.read().unwrap())
112 },
113 )+
114 (_, _) => false,
115 }
116 }
117 }
118 impl Eq for $name {}
119 impl Hash for $name {
120 fn hash<H: Hasher>(&self, state: &mut H) {
121 match &self {
122 $(
123 Self::$variant(x) => x.read().unwrap().hash(state),
124 )+
125 }
126 }
127 }
128 }
129}
130
131#[macro_export]
132macro_rules! define_task_node {
133 ($name:ident,
134 $descendants:expr,
135 $py_ast_closure:expr,
136 $import_closure:expr,
137 $import_type:ty,
138 $($field: ident : $field_type: ty,)*) => {
139 #[derive(Hash, PartialEq, Clone)]
140 pub struct $name {
141 $(
142 $field: $field_type,
143 )*
144 }
145 impl $name {
146 pub fn new_wrapped($(
147 $field: $field_type,
148 )*) -> Arc<RwLock<Self>> {
149 Arc::new(RwLock::new(Self::new($($field, )*)))
150 }
151 pub fn get_statements<'a>(
152 &self,
153 ) -> Vec<AST> {
154 ($py_ast_closure)(self)
155 }
156 pub fn new($(
157 $field: $field_type,
158 )*) -> Self {
159 Self {
160 $($field,)*
161 }
162 }
163 $(
164 pub fn $field(&self) -> $field_type {
165 self.$field.clone()
166 }
167 )*
168 pub fn get_direct_descendants(&self) -> Vec<AST> {
169 $descendants(self)
170 }
171 pub fn get_imports(&self) -> Vec<$import_type> {
172 $import_closure(self)
173 }
174 }
175 };
176}
177
178#[macro_export]
179macro_rules! register_task_nodes {
180 ($name:ident, $import_type: ty, $($variant: ident,)+) => {
181
182 #[derive(Clone)]
183 pub enum $name {
184 $(
185 $variant(Arc<RwLock<$variant>>),
186 )+
187 }
188 impl $name {
189 pub fn get_imports(&self) -> Vec<$import_type>{
190 match &self {
191 $(
192 Self::$variant(x) => x.read().unwrap().get_imports(),
193 )+
194 }
195 }
196 pub fn get_statements(&self) -> Vec<AST> {
197 match &self {
198 $(
199 Self::$variant(x) => x.read().unwrap().get_statements(),
200 )+
201 }
202 }
203 }
204 impl PartialEq for $name {
205 fn eq(&self, other: &Self) -> bool {
206 match (&self, other) {
207 $(
208 (Self::$variant(v1), Self::$variant(v2)) => {
209 v1.read().unwrap().eq(&v2.read().unwrap())
210 },
211 )+
212 (_, _) => false,
213 }
214 }
215 }
216 impl Eq for $name {}
217 impl Hash for $name {
218 fn hash<H: Hasher>(&self, state: &mut H) {
219 match &self {
220 $(
221 Self::$variant(x) => x.read().unwrap().hash(state),
222 )+
223 }
224 }
225 }
226 }
227}
228
229#[macro_export]
230macro_rules! define_ast_node {
231 ($name:ident,
232 $descendants:expr,
233 $py_ast_closure:expr,
234 $r_ast_closure:expr,
235 $($field: ident : $field_type: ty,)*) => {
236 #[derive(Hash, PartialEq, Eq, Clone, Optimizable)]
237 pub struct $name {
238 $(
239 $field: $field_type,
240 )*
241 ancestors: Option<Vec<AncestorRecord>>,
242 }
243 impl $name {
244 pub fn new_wrapped($(
245 $field: $field_type,
246 )*) -> Arc<RwLock<Self>> {
247 Arc::new(RwLock::new(Self::new($($field, )*)))
248 }
249 pub fn to_python_ast_node<'a>(
250 &self,
251 py: Python,
252 ast_module: &'a PyModule,
253 depth: usize,
254 ) -> PyResult<&'a PyAny> {
255 ($py_ast_closure)(self, py, ast_module, depth)
256 }
257 pub fn to_r_ast_node(&self, depth: usize) -> Robj {
258 ($r_ast_closure)(self, depth)
259 }
260 pub fn new($(
261 $field: $field_type,
262 )*) -> Self {
263 Self {
264 $($field,)*
265 ancestors: None,
266 }
267 }
268 pub fn clone_without_ancestors(&self) -> Self {
269 Self {
270 $($field: self.$field.clone(),)*
271 ancestors: None,
272 }
273 }
274 pub fn set_ancestors(&mut self, ancestors: Vec<AncestorRecord>) {
275 assert!(self.ancestors.is_none());
276 self.ancestors = Some(ancestors);
277 }
278 pub fn get_ancestors(&self) -> Option<Vec<AncestorRecord>> {
279 self.ancestors.clone()
280 }
281 $(
282 pub fn $field(&self) -> $field_type {
283 self.$field.clone()
284 }
285 )*
286 pub fn get_direct_descendants(&self) -> Vec<AST> {
287 $descendants(self)
288 }
289 }
290 };
291}
292
293#[macro_export]
294macro_rules! define_program {
295 ($name:ident, $root:ident, $constraint:ident, $satisfy_type:ident,
296 $lt: lifetime, $clt: lifetime,
297 $dialect:ident,
298 $preamble:expr, $call:expr, $tuple_call: expr, $dialect_call: expr) => {
299 pub struct $name {}
300 impl<$lt, $clt> ConstraintSatisfactionBase<$lt, $clt> for $name
301 where
302 $lt: $clt,
303 {
304 type RootType = $root;
305 type ConstraintType = $constraint;
306 type Outer = Constraint;
307 }
308 impl<$lt, $clt> $satisfy_type<$lt, $clt> for $name
309 where
310 $lt: $clt,
311 {
312 type Dialect = $dialect;
313 fn compute_parameter_tuple(
314 uuid: Uuid,
315 c: Concept<'a>,
316 ancestry: Arc<ConceptAncestry<'a>>,
317 ) -> ParameterTuple {
318 $tuple_call(uuid, c, ancestry)
319 }
320 fn get_preamble() -> String {
321 $preamble.to_string()
322 }
323 fn get_call() -> String {
324 $call.to_string()
325 }
326 fn get_dialect() -> Dialect {
327 Dialect::$dialect($dialect_call())
328 }
329 }
330 };
331}
332
333#[macro_export]
334macro_rules! register_programs_for_constraint {
335 ($constraint:ident, $root: ident, $lt: lifetime, $clt: lifetime, $ancestry: ty,
336 $($dialect:ident, $element: ident),+) => {
337 impl<$lt, $clt> SatisfiableConstraint<$lt, $clt> for $constraint where $lt : $clt {
338 type TAncestry = $ancestry;
339 fn satisfy(
340 &mut self,
341 c: Concept<$lt>,
342 d: &Dialect,
343 ancestry: Arc<$ancestry>,
344 ) -> Result<Option<(String, String, ParameterTuple, Dialect)>> {
345 match d {
346 $(
347 Dialect::$dialect{..} => Ok(Some((
348 $element::get_preamble(),
349 $element::get_call(),
350 $element::compute_parameter_tuple(
351 self.get_uuid()?.clone(),
352 c.clone(),
353 ancestry,
354 ),
355 $element::get_dialect(),
356 ))),
357 )+
358 _ => Ok(None),
359 }
360 }
361 fn satisfy_given_preference_ordering(
362 &mut self,
363 c: Concept<$lt>,
364 preferences: &Vec<Dialect>,
365 ancestry: Arc<$ancestry>,
366 ) -> Result<(String, String, ParameterTuple, Dialect)> {
367 match c {
368 Concept::$root{..} => {
369 for d in preferences {
370 if let Some((preamble, call, params, dialect))
371 = self.satisfy(c.clone(), &d, ancestry.clone())? {
372 return Ok((preamble, call, params, dialect));
373 }
374 }
375 bail!("Cannot satisfy preference ordering for {}", c.get_uuid())
376 },
377 _ => bail!("Wrong type of concept provided: {}", c.get_type())
378 }
379 }
380 }
381 };
382}
383
384#[macro_export]
385macro_rules! register_satisfiable_constraints {
386
387 ($outer: ident, $($constraint:ident),+) => {
388 impl <'a> SatisfiableOuterConstraint<'a> for $outer {
389 fn satisfy_given_preference_ordering(
390 &mut self,
391 c: AoristRef<Concept>,
392 preferences: &Vec<Dialect>,
393 ancestry: Arc<ConceptAncestry>,
394 ) -> Result<(String, String, ParameterTuple, Dialect)> {
395 match &mut self.inner {
396 $(
397 Some(AoristConstraint::$constraint(ref mut x)) =>
398 x.satisfy_given_preference_ordering(
399 c, preferences,
400 ancestry,
401 ),
402 )+
403 _ => bail!("Constraint {} is not satisfiable (no program provided).", self.inner.as_ref().unwrap().get_name())
404 }
405 }
406 }
407 }
408}
409
410#[macro_export]
411macro_rules! define_attribute {
412 (
413 $element:ident,
414 $presto_type:ident,
415 $orc_type:ident,
416 $sql_type:ident,
417 $sqlite_type:ident,
418 $postgres_type:ident,
419 $bigquery_type:ident,
420 $value:ident
421 ) => {
422 aorist_paste::item! {
423 #[cfg_attr(feature = "python", pyclass(module = "aorist"))]
424 #[derive(
425 Hash,
426 PartialEq,
427 Eq,
428 Debug,
429 Serialize,
430 Deserialize,
431 Clone,
432 $presto_type,
433 $orc_type,
434 $sqlite_type,
435 $postgres_type,
436 $bigquery_type,
437 )]
438 #[cfg_attr(feature = "sql", derive($sql_type))]
439 pub struct $element {
440 pub name: String,
441 pub comment: Option<String>,
442 pub nullable: bool,
443 }
444 impl TAttribute for $element {
445 type Value = $value;
446
447 fn get_name(&self) -> &String {
448 &self.name
449 }
450 fn get_comment(&self) -> &Option<String> {
451 &self.comment
452 }
453 fn is_nullable(&self) -> bool {
454 self.nullable
455 }
456 }
457 #[cfg(feature = "python")]
458 #[pymethods]
459 impl $element {
460 #[new]
461 #[args(comment = "None")]
462 #[args(nullable = "false")]
463 pub fn new(
464 name: String,
465 comment: Option<String>,
466 nullable: bool
467 ) -> Self {
468 Self { name, comment, nullable }
469 }
470 #[getter]
471 pub fn name(&self) -> PyResult<String> {
472 Ok(self.name.clone())
473 }
474
475 }
476 #[cfg(feature = "python")]
477 #[pyo3::prelude::pyproto]
478 impl pyo3::PyObjectProtocol for $element {
479 fn __repr__(&self) -> pyo3::PyResult<String> {
480 Ok(format!(
481 "{} {}",
482 stringify!($element),
483 serde_json::to_string_pretty(self).unwrap()
484 ))
485 }
486 fn __str__(&self) -> pyo3::PyResult<String> {
487 Ok(format!(
488 "{} {}",
489 stringify!($element),
490 serde_json::to_string_pretty(self).unwrap()
491 ))
492 }
493 }
494 }
495 };
496}
497
498#[macro_export]
499macro_rules! define_constraint {
500 ($element:ident, $requires_program:expr, $satisfy_type:ident, $root:ident, $outer:ident,
501 $title:expr, $body:expr, $should_add:expr, $get_required:expr $(, $required:ident)*) => {
502 aorist_paste::item! {
503 #[cfg_attr(feature = "python", pyclass(module = "aorist"))]
504 #[derive(Clone)]
505 pub struct $element {
506 id: Uuid,
507 root_uuid: Uuid,
508 $([<$required:snake:lower>] : Vec<Arc<RwLock<$outer>>>,)*
509 }
510 #[cfg(feature = "python")]
511 #[pymethods]
512 impl $element {
513 #[classattr]
514 pub fn name() -> String {
515 stringify!($element).to_string()
516 }
517 }
518 pub trait $satisfy_type<'a> : ConstraintSatisfactionBase<'a, ConstraintType=$element, RootType=$root> {
519 type Dialect;
520
521 fn compute_parameter_tuple(
524 uuid: Uuid,
525 root: Concept,
526 ancestry: Arc<ConceptAncestry>,
527 ) -> ParameterTuple;
528 fn get_preamble() -> String;
529 fn get_call() -> String;
530 fn get_dialect() -> Dialect;
531 }
532
533 #[cfg_attr(feature = "python", pyclass(module = "aorist"))]
534 #[derive(Clone)]
535 pub struct [<$element Program>] {
536 pub dialect: Dialect,
537 pub code: String,
538 pub entrypoint: String,
539 pub arg_functions: Vec<(Vec<String>, String)>,
540 pub kwarg_functions: LinkedHashMap<String, (Vec<String>, String)>,
541 }
542 #[cfg(feature = "python")]
543 #[pymethods]
544 impl $element {
545 #[staticmethod]
546 pub fn register_python_program(
547 code: &str,
548 entrypoint: &str,
549 arg_functions: Vec<(Vec<&str>, &str)>,
550 kwarg_functions: HashMap<&str, (Vec<&str>, &str)>,
551 pip_requirements: Vec<String>,
552 ) -> PyResult<[<$element Program>]> {
553
554 let mut funs: LinkedHashMap<String, (Vec<String>, String)> = LinkedHashMap::new();
555 for (k, (v1, v2)) in kwarg_functions.iter() {
556 funs.insert(k.to_string(), (v1.iter().map(|x| x.to_string()).collect(), v2.to_string()));
557 }
558 Ok([<$element Program>]{
559 code: code.to_string(),
560 entrypoint: entrypoint.to_string(),
561 arg_functions: arg_functions.iter().map(|(x, y)| (x.iter().map(|x| x.to_string()).collect(), y.to_string())).collect(),
562 kwarg_functions: funs,
563 dialect: Dialect::Python(aorist_core::Python::new(pip_requirements))
564 })
565 }
566 #[staticmethod]
567 pub fn register_r_program(
568 code: &str,
569 entrypoint: &str,
570 arg_functions: Vec<(Vec<&str>, &str)>,
571 kwarg_functions: HashMap<&str, (Vec<&str>, &str)>,
572 ) -> PyResult<[<$element Program>]> {
573
574 let mut funs: LinkedHashMap<String, (Vec<String>, String)> = LinkedHashMap::new();
575 for (k, (v1, v2)) in kwarg_functions.iter() {
576 funs.insert(k.to_string(), (v1.iter().map(|x| x.to_string()).collect(), v2.to_string()));
577 }
578 Ok([<$element Program>]{
579 code: code.to_string(),
580 entrypoint: entrypoint.to_string(),
581 arg_functions: arg_functions.iter().map(|(x, y)| (x.iter().map(|x| x.to_string()).collect(), y.to_string())).collect(),
582 kwarg_functions: funs,
583 dialect: Dialect::R(aorist_core::R::new())
584 })
585 }
586 #[staticmethod]
587 pub fn register_presto_program(
588 code: &str,
589 entrypoint: &str,
590 arg_functions: Vec<(Vec<&str>, &str)>,
591 kwarg_functions: HashMap<&str, (Vec<&str>, &str)>,
592 ) -> PyResult<[<$element Program>]> {
593
594 let mut funs: LinkedHashMap<String, (Vec<String>, String)> = LinkedHashMap::new();
595 for (k, (v1, v2)) in kwarg_functions.iter() {
596 funs.insert(k.to_string(), (v1.iter().map(|x| x.to_string()).collect(), v2.to_string()));
597 }
598 Ok([<$element Program>]{
599 code: code.to_string(),
600 entrypoint: entrypoint.to_string(),
601 arg_functions: arg_functions.iter().map(|(x, y)| (x.iter().map(|x| x.to_string()).collect(), y.to_string())).collect(),
602 kwarg_functions: funs,
603 dialect: Dialect::Presto(aorist_core::Presto::new())
604 })
605 }
606 #[staticmethod]
607 pub fn register_bash_program(
608 code: &str,
609 entrypoint: &str,
610 arg_functions: Vec<(Vec<&str>, &str)>,
611 kwarg_functions: HashMap<&str, (Vec<&str>, &str)>,
612 ) -> PyResult<[<$element Program>]> {
613
614 let mut funs: LinkedHashMap<String, (Vec<String>, String)> = LinkedHashMap::new();
615 for (k, (v1, v2)) in kwarg_functions.iter() {
616 funs.insert(k.to_string(), (v1.iter().map(|x| x.to_string()).collect(), v2.to_string()));
617 }
618 Ok([<$element Program>]{
619 code: code.to_string(),
620 entrypoint: entrypoint.to_string(),
621 arg_functions: arg_functions.iter().map(|(x, y)| (x.iter().map(|x| x.to_string()).collect(), y.to_string())).collect(),
622 kwarg_functions: funs,
623 dialect: Dialect::Bash(aorist_core::Bash::new())
624 })
625 }
626 }
627 impl <'a> TProgram<'a, $element> for [<$element Program>] {
628 fn new(
629 code: String,
630 entrypoint: String,
631 arg_functions: Vec<(Vec<String>, String)>,
632 kwarg_functions: LinkedHashMap<String, (Vec<String>, String)>,
633 dialect: Dialect,
634 ) -> Self {
635 Self { code, entrypoint, arg_functions, kwarg_functions, dialect }
636 }
637 fn get_arg_functions(&self) -> Vec<(Vec<String>, String)> {
638 self.arg_functions.clone()
639 }
640 fn get_code(&self) -> String {
641 self.code.clone()
642 }
643 fn get_dialect(&self) -> Dialect {
644 self.dialect.clone()
645 }
646 fn get_entrypoint(&self) -> String {
647 self.entrypoint.clone()
648 }
649 fn get_kwarg_functions(&self) -> LinkedHashMap<String, (Vec<String>, String)> {
650 self.kwarg_functions.clone()
651 }
652 }
653 impl $element {
654 fn get_uuid(&self) -> Result<Uuid> {
657 Ok(self.id.clone())
658 }
659 fn _should_add(root: AoristRef<Concept>, ancestry: &ConceptAncestry) -> bool {
660 $should_add(root, ancestry)
661 }
662 fn get_required(root: AoristRef<Concept>, ancestry: &ConceptAncestry) -> Vec<Uuid> {
663 $get_required(root, ancestry)
664 }
665 fn get_root_uuid(&self) -> Result<Uuid> {
666 Ok(self.root_uuid.clone())
667 }
668 fn requires_program(&self) -> Result<bool> {
669 Ok($requires_program)
670 }
671 fn get_downstream_constraints(&self) -> Result<Vec<Arc<RwLock<Constraint>>>> {
673 let mut downstream: Vec<Arc<RwLock<Constraint>>> = Vec::new();
674 $(
675 for arc in &self.[<$required:snake:lower>] {
676 downstream.push(arc.clone());
677 }
678 )*
679 Ok(downstream)
680 }
681 fn get_title() -> Option<String> {
682 $title
683 }
684 fn get_body() -> Option<String> {
685 $body
686 }
687 }
688 impl <'a> TConstraint<'a> for $element {
689 type Root = AoristRef<$root>;
690 type Outer = $outer;
691 type Ancestry = ConceptAncestry;
692
693 fn get_root_type_name() -> Result<String> {
694 Ok(stringify!($root).into())
695 }
696 fn get_required_constraint_names() -> Vec<String> {
697 vec![$(
698 stringify!($required).into()
699 ),*]
700 }
701 fn should_add(root: AoristRef<Concept>, ancestry: &ConceptAncestry) -> bool {
702 let read = root.0.read().unwrap();
703 match *read {
704 Concept::$root((_, _, _)) => Self::_should_add(root.clone(), ancestry),
705 _ => panic!("should_add called with unexpected concept."),
706 }
707 }
708 fn new(root_uuid: Uuid,
709 potential_child_constraints: Vec<Arc<RwLock<Constraint>>>) -> Result<Self> {
710 $(
712 let mut [<$required:snake:lower>]: Vec<Arc<RwLock<Constraint>>> =
713 Vec::new();
714 )*
715 let mut by_uuid: HashMap<Uuid, Arc<RwLock<Constraint>>> = HashMap::new();
716 for constraint in &potential_child_constraints {
717 $(
718 if let Some(AoristConstraint::$required{..}) =
719 &constraint.read().unwrap().inner
720 {
721 by_uuid.insert(
722 constraint.read().unwrap().get_uuid()?,
723 constraint.clone()
724 );
725 }
726 )*
727 }
728 for constraint in by_uuid.values() {
729 $(
730 if let Some(AoristConstraint::$required{..}) =
731 &constraint.read().unwrap().inner {
732 [<$required:snake:lower>].push(constraint.clone());
733 }
734 )*
735 }
736 Ok(Self{
737 id: Uuid::new_v4(),
738 root_uuid,
739 $([<$required:snake:lower>],)*
740 })
741 }
742 }
743 }
744 };
745}
746
747#[macro_export]
748macro_rules! register_attribute_new {
749 ( $name:ident, $($element: ident),+ ) => { paste! {
750 #[derive(Hash, PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
751 pub enum [<$name Enum>] {
752 $(
753 $element($element),
754 )+
755 }
756 #[cfg(feature = "python")]
757 impl <'a> FromPyObject<'a> for [<$name Enum>] {
758 fn extract(obj: &'a PyAny) -> PyResult<Self> {
759 $(
760 if let Ok(x) = $element::extract(obj) {
761 return Ok(Self::$element(x));
762 }
763 )+
764 Err(PyValueError::new_err("could not convert enum arm."))
765 }
766 }
767 #[cfg(feature = "python")]
768 impl IntoPy<PyObject> for [<$name Enum>] {
769 fn into_py(self, py: Python) -> PyObject {
770 match self {
771 $(
772 [<$name Enum>]::$element(x) => x.into_py(py),
773 )+
774 }
775 }
776 }
777 impl [<$name Enum>] {
778 pub fn get_name(&self) -> &String {
779 match self {
780 $(
781 [<$name Enum>]::$element(x) => x.get_name(),
782 )+
783 }
784 }
785 pub fn get_type(&self) -> String {
786 match self {
787 $(
788 [<$name Enum>]::$element(x) => stringify!($element).to_string(),
789 )+
790 }
791 }
792 pub fn is_nullable(&self) -> bool {
793 match self {
794 $(
795 [<$name Enum>]::$element(x) => x.is_nullable(),
796 )+
797 }
798 }
799
800 pub fn as_predicted_objective(&self) -> Self {
801 match self {
802 $(
803 [<$name Enum>]::$element(x) => [<$name Enum>]::$element($element {
804 name: format!("predicted_{}", x.get_name()).to_string(),
805 comment: x.get_comment().clone(),
806 nullable: false,
807 }),
808 )+
809 }
810 }
811 pub fn get_comment(&self) -> &Option<String> {
812 match self {
813 $(
814 [<$name Enum>]::$element(x) => x.get_comment(),
815 )+
816 }
817 }
818 #[cfg(feature = "sql")]
819 pub fn get_sql_type(&self) -> sqlparser::ast::DataType {
820 match self {
821 $(
822 [<$name Enum>]::$element(x) => x.get_sql_type(),
823 )+
824 }
825 }
826 pub fn get_presto_type(&self) -> String {
827 match self {
828 $(
829 [<$name Enum>]::$element(x) => x.get_presto_type(),
830 )+
831 }
832 }
833 pub fn get_sqlite_type(&self) -> String {
834 match self {
835 $(
836 [<$name Enum>]::$element(x) => x.get_sqlite_type(),
837 )+
838 }
839 }
840 pub fn get_postgres_type(&self) -> String {
841 match self {
842 $(
843 [<$name Enum>]::$element(x) => x.get_postgres_type(),
844 )+
845 }
846 }
847 pub fn psycopg2_value_json_serializable(&self) -> bool {
848 match self {
849 $(
850 [<$name Enum>]::$element(x) => x.psycopg2_value_json_serializable(),
851 )+
852 }
853 }
854 pub fn get_bigquery_type(&self) -> String {
855 match self {
856 $(
857 [<$name Enum>]::$element(x) => x.get_bigquery_type(),
858 )+
859 }
860 }
861 pub fn get_orc_type(&self) -> String {
862 match self {
863 $(
864 [<$name Enum>]::$element(x) => x.get_orc_type(),
865 )+
866 }
867 }
868 }
869 #[aorist(derivative(Hash))]
870 pub struct $name {
871 pub inner: AttributeOrTransform,
872 }
873 impl $name {
881 pub fn get_name(&self) -> &String {
882 self.inner.get_name()
883 }
884 pub fn psycopg2_value_json_serializable(&self) -> bool {
885 self.inner.psycopg2_value_json_serializable()
886 }
887 pub fn get_type(&self) -> String {
888 self.inner.get_type()
889 }
890 pub fn is_nullable(&self) -> bool {
891 self.inner.is_nullable()
892 }
893 pub fn get_comment(&self) -> &Option<String> {
894 self.inner.get_comment()
895 }
896 #[cfg(feature = "sql")]
897 pub fn get_sql_type(&self) -> DataType {
898 self.inner.get_sql_type()
899 }
900 pub fn get_presto_type(&self) -> String {
901 self.inner.get_presto_type()
902 }
903 pub fn get_sqlite_type(&self) -> String {
904 self.inner.get_sqlite_type()
905 }
906 pub fn get_postgres_type(&self) -> String {
907 self.inner.get_postgres_type()
908 }
909 pub fn get_bigquery_type(&self) -> String {
910 self.inner.get_bigquery_type()
911 }
912 pub fn get_orc_type(&self) -> String {
913 self.inner.get_orc_type()
914 }
915 }
916 #[cfg(feature = "python")]
917 aorist_paste::item!(
918 pub fn [<$name:snake:lower>] (m: &PyModule) -> PyResult<()> {
919 $(
920 m.add_class::<$element>()?;
921 )+
922 Ok(())
923 }
924 );
925 #[cfg(feature = "python")]
926 #[pyo3::prelude::pymethods]
927 impl [<Py $name>] {
928 #[getter]
929 pub fn name(&self) -> pyo3::prelude::PyResult<String> {
930 Ok(self.inner.0.read().unwrap().get_name().clone())
931 }
932 #[getter]
933 pub fn aorist_type(&self) -> pyo3::prelude::PyResult<String> {
934 Ok(self.inner.0.read().unwrap().get_type().clone())
935 }
936 #[getter]
937 pub fn comment(&self) -> pyo3::prelude::PyResult<Option<String>> {
938 Ok(self.inner.0.read().unwrap().get_comment().clone())
939 }
940 #[getter]
941 pub fn orc_type(&self) -> pyo3::prelude::PyResult<String> {
942 Ok(self.inner.0.read().unwrap().get_orc_type().clone())
943 }
944 #[getter]
945 pub fn presto_type(&self) -> pyo3::prelude::PyResult<String> {
946 Ok(self.inner.0.read().unwrap().get_presto_type().clone())
947 }
948 #[getter]
949 pub fn bigquery_type(&self) -> pyo3::prelude::PyResult<String> {
950 Ok(self.inner.0.read().unwrap().get_bigquery_type().clone())
951 }
952 #[getter]
953 pub fn is_nullable(&self) -> pyo3::prelude::PyResult<bool> {
954 Ok(self.inner.0.read().unwrap().is_nullable().clone())
955 }
956 #[getter]
957 pub fn psycopg2_value_json_serializable(&self) -> pyo3::prelude::PyResult<bool> {
958 Ok(self.inner.0.read().unwrap().psycopg2_value_json_serializable().clone())
959 }
960 #[getter]
961 pub fn postgres_type(&self) -> pyo3::prelude::PyResult<String> {
962 Ok(self.inner.0.read().unwrap().get_postgres_type().clone())
963 }
964 }
965 }}
966}
967
968#[macro_export]
969macro_rules! register_attribute {
970 ( $name:ident, $($element: ident),+ ) => { paste! {
971 #[derive(Hash, PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
972 pub enum [<$name Enum>] {
973 $(
974 $element($element),
975 )+
976 }
977 impl <'a> FromPyObject<'a> for [<$name Enum>] {
978 fn extract(obj: &'a PyAny) -> PyResult<Self> {
979 $(
980 if let Ok(x) = $element::extract(obj) {
981 return Ok(Self::$element(x));
982 }
983 )+
984 Err(PyValueError::new_err("could not convert enum arm."))
985 }
986 }
987 impl [<$name Enum>] {
988 pub fn get_name(&self) -> &String {
989 match self {
990 $(
991 [<$name Enum>]::$element(x) => x.get_name(),
992 )+
993 }
994 }
995 pub fn get_type(&self) -> String {
996 match self {
997 $(
998 [<$name Enum>]::$element(x) => stringify!($element).to_string(),
999 )+
1000 }
1001 }
1002 pub fn is_nullable(&self) -> bool {
1003 match self {
1004 $(
1005 [<$name Enum>]::$element(x) => x.is_nullable(),
1006 )+
1007 }
1008 }
1009
1010 pub fn as_predicted_objective(&self) -> Self {
1011 match self {
1012 $(
1013 [<$name Enum>]::$element(x) => [<$name Enum>]::$element($element {
1014 name: format!("predicted_{}", x.get_name()).to_string(),
1015 comment: x.get_comment().clone(),
1016 nullable: false,
1017 }),
1018 )+
1019 }
1020 }
1021 pub fn get_comment(&self) -> &Option<String> {
1022 match self {
1023 $(
1024 [<$name Enum>]::$element(x) => x.get_comment(),
1025 )+
1026 }
1027 }
1028 pub fn get_sql_type(&self) -> DataType {
1029 match self {
1030 $(
1031 [<$name Enum>]::$element(x) => x.get_sql_type(),
1032 )+
1033 }
1034 }
1035 pub fn get_presto_type(&self) -> String {
1036 match self {
1037 $(
1038 [<$name Enum>]::$element(x) => x.get_presto_type(),
1039 )+
1040 }
1041 }
1042 pub fn get_sqlite_type(&self) -> String {
1043 match self {
1044 $(
1045 [<$name Enum>]::$element(x) => x.get_sqlite_type(),
1046 )+
1047 }
1048 }
1049 pub fn get_postgres_type(&self) -> String {
1050 match self {
1051 $(
1052 [<$name Enum>]::$element(x) => x.get_postgres_type(),
1053 )+
1054 }
1055 }
1056 pub fn psycopg2_value_json_serializable(&self) -> bool {
1057 match self {
1058 $(
1059 [<$name Enum>]::$element(x) => x.psycopg2_value_json_serializable(),
1060 )+
1061 }
1062 }
1063 pub fn get_bigquery_type(&self) -> String {
1064 match self {
1065 $(
1066 [<$name Enum>]::$element(x) => x.get_bigquery_type(),
1067 )+
1068 }
1069 }
1070 pub fn get_orc_type(&self) -> String {
1071 match self {
1072 $(
1073 [<$name Enum>]::$element(x) => x.get_orc_type(),
1074 )+
1075 }
1076 }
1077 }
1078 #[aorist_concept(derivative(Hash))]
1079 pub struct $name {
1080 pub inner: AttributeOrTransform,
1081 }
1082 impl<'a> FromPyObject<'a> for $name {
1083 fn extract(ob: &'a PyAny) -> PyResult<Self> {
1084 let inner = AttributeOrTransform::extract(ob)?;
1085 Ok(Self{ inner, constraints: Vec::new(), tag: None, uuid: None })
1086 }
1087 }
1088 impl $name {
1089 pub fn get_name(&self) -> &String {
1090 self.inner.get_name()
1091 }
1092 pub fn psycopg2_value_json_serializable(&self) -> bool {
1093 self.inner.psycopg2_value_json_serializable()
1094 }
1095 pub fn get_type(&self) -> String {
1096 self.inner.get_type()
1097 }
1098 pub fn is_nullable(&self) -> bool {
1099 self.inner.is_nullable()
1100 }
1101 pub fn get_comment(&self) -> &Option<String> {
1102 self.inner.get_comment()
1103 }
1104 pub fn get_sql_type(&self) -> DataType {
1105 self.inner.get_sql_type()
1106 }
1107 pub fn get_presto_type(&self) -> String {
1108 self.inner.get_presto_type()
1109 }
1110 pub fn get_sqlite_type(&self) -> String {
1111 self.inner.get_sqlite_type()
1112 }
1113 pub fn get_postgres_type(&self) -> String {
1114 self.inner.get_postgres_type()
1115 }
1116 pub fn get_bigquery_type(&self) -> String {
1117 self.inner.get_bigquery_type()
1118 }
1119 pub fn get_orc_type(&self) -> String {
1120 self.inner.get_orc_type()
1121 }
1122 }
1123 aorist_paste::item!(
1124 pub fn [<$name:snake:lower>] (m: &PyModule) -> PyResult<()> {
1125 $(
1126 m.add_class::<$element>()?;
1127 )+
1128 Ok(())
1129 }
1130 );
1131 }}
1132}
1133
1134#[macro_export]
1135macro_rules! register_concept {
1136 ( $name:ident, $ancestry:ident, $($element: ident ),* ) => { aorist_paste::item! {
1137 #[derive(Clone, Debug, Serialize, PartialEq)]
1138 pub enum $name {
1139 $(
1140 $element((AoristRef<$element>, usize, Option<(Uuid, String)>)),
1141 )+
1142 }
1143 impl AoristUniverse for AoristRef<Universe> {
1145 type TEndpoints = EndpointConfig;
1146 fn get_endpoints(&self) -> Self::TEndpoints {
1147 (*self.0.read().unwrap()).endpoints.0.read().unwrap().clone()
1148 }
1149 }
1150 $(
1151 impl [<CanBe $element>] for $name {
1152 fn [<construct_ $element:snake:lower>](
1153 obj_ref: AoristRef<$element>,
1154 ix: Option<usize>,
1155 id: Option<(Uuid, String)>
1156 ) -> AoristRef<Self> {
1157 AoristRef(Arc::new(RwLock::new($name::$element((
1158 obj_ref.clone(),
1159 match ix {
1160 Some(i) => i,
1161 None => 0,
1162 },
1163 id,
1164 )))))
1165 }
1166 }
1167 )+
1168
1169 pub trait [<$name Descendants>] {
1170 fn get_descendants(&self) -> Vec<AoristRef<$name>>;
1171 }
1172
1173 $(
1174 impl [<$name Descendants>] for AoristRef<$element> {
1175 fn get_descendants(&self) -> Vec<AoristRef<$name>> {
1176 let mut concepts = Vec::new();
1177 for tpl in self.get_children() {
1178 let wrapped_concept = WrappedConcept::from(tpl);
1179 concepts.push(wrapped_concept.inner);
1180 }
1181 concepts
1182 }
1183 }
1184 )+
1185
1186
1187 impl ConceptEnum for $name {}
1188 impl ConceptEnum for AoristRef<$name> {}
1189
1190 $(
1191 impl TryFrom<AoristRef<$name>> for AoristRef<$element> {
1192 type Error = String;
1193 fn try_from(x: AoristRef<$name>) -> Result<Self, String> {
1194 let read = x.0.read();
1195 match read {
1196 Ok(elem) => match *elem {
1197 $name::$element((ref y, _, _)) => Ok(y.clone()),
1198 _ => Err("Cannot convert.".into()),
1199 },
1200 _ => Err("Cannot read.".into()),
1201 }
1202 }
1203 }
1204 )+
1205
1206 #[cfg_attr(feature = "python", pyclass(module = "aorist"))]
1207 pub struct $ancestry {
1208 pub parents: Arc<RwLock<HashMap<(Uuid, String), AoristRef<$name>>>>,
1209 }
1210 impl Ancestry for $ancestry {
1211 type TConcept = AoristRef<$name>;
1212 fn new(parents: Arc<RwLock<HashMap<(Uuid, String), AoristRef<$name>>>>) -> Self {
1213 Self { parents }
1214 }
1215
1216 }
1217 impl $ancestry {
1218 $(
1219 pub fn [<$element:snake:lower>](
1220 &self,
1221 root: AoristRef<$name>,
1222 ) -> Result<AoristRef<$element>, String> {
1223 if root.get_type() == stringify!($element).to_string(){
1224 return(Ok(AoristRef::<$element>::try_from(root.clone()).unwrap()));
1225 }
1226 let parent_id = root.get_parent_id();
1227 match parent_id {
1228 None => Err(
1229 format!(
1230 "Cannot find ancestor of type {} for root {}.",
1231 stringify!($element),
1232 root.get_type(),
1233 )
1234 ),
1235 Some(id) => {
1236 let guard = self.parents.read().unwrap();
1237 let parent = guard.get(&id).unwrap().clone();
1238 self.[<$element:snake:lower>](parent)
1239 }
1240 }
1241 }
1242 )+
1243 }
1244 #[cfg(feature = "python")]
1245 impl $ancestry {
1246 pub fn py_object(&self, ancestor: &str, root: AoristRef<$name>, py: Python) -> PyResult<PyObject> {
1247 match ancestor {
1248 $(
1249 stringify!([<$element:snake:lower>]) => match self.[<$element:snake:lower>](root) {
1250 Ok(x) => x.py_object(py),
1251 Err(err) => Err(pyo3::exceptions::PyTypeError::new_err(err.clone())),
1252 }
1253 )+
1254 _ => panic!("Unknown ancestor type: {}", ancestor),
1255 }
1256 }
1257 }
1258 #[cfg(feature = "python")]
1259 impl $name {
1260 pub fn py_object(&self, py: Python) -> PyObject {
1261 let object = match self {
1262 $(
1263 $name::$element((x, _, _)) => PyObject::from(PyCell::new(py, [<Py $element>] {
1264 inner: x.clone(),
1265 }).unwrap()),
1266 )+
1267 };
1268 object
1269 }
1270 }
1271 impl TConceptEnum for AoristRef<$name> {
1272 type TUniverse = AoristRef<Universe>;
1273 fn get_parent_id(&self) -> Option<(Uuid, String)> {
1274 let read = self.0.read().unwrap();
1275 match *read {
1276 $(
1277 $name::$element((_, _, ref id)) => id.clone(),
1278 )+
1279 }
1280 }
1281 fn from_universe(universe: AoristRef<Universe>) -> Self {
1282 AoristRef(Arc::new(RwLock::new($name::Universe((universe, 0, None)))))
1283 }
1284 fn get_type(&self) -> String {
1285 let read = self.0.read().unwrap();
1286 match *read {
1287 $(
1288 $name::$element((ref x, _, _)) => stringify!($element).to_string(),
1289 )*
1290 }
1291 }
1292 fn get_uuid(&self) -> Uuid {
1293 let read = self.0.read().unwrap();
1294 match *read {
1295 $(
1296 $name::$element((ref x, _, _)) => x.get_uuid().unwrap(),
1297 )*
1298 }
1299 }
1300 fn get_tag(&self) -> Option<String> {
1301 let read = self.0.read().unwrap();
1302 match *read {
1303 $(
1304 $name::$element((ref x, _, _)) => x.get_tag(),
1305 )*
1306 }
1307 }
1308 fn get_index_as_child(&self) -> usize {
1309 let read = self.0.read().unwrap();
1310 match *read {
1311 $(
1312 $name::$element((_, idx, _)) => idx,
1313 )*
1314 }
1315 }
1316 fn get_child_concepts(&self) -> Vec<Self> {
1317 let read = self.0.read().unwrap();
1318 match *read {
1319 $(
1320 $name::$element((ref x, _, _)) => x.get_descendants(),
1321 )*
1322 }
1323 }
1324 fn populate_child_concept_map(&self, concept_map: &mut HashMap<(Uuid, String), Self>) {
1325 let read = self.0.read().unwrap();
1326 match *read {
1327 $(
1328 $name::$element((ref x, idx, ref parent)) => {
1329 debug!("Visiting concept {}: {}", stringify!($element), x.get_uuid().unwrap());
1330 for child in x.get_descendants() {
1331 child.populate_child_concept_map(concept_map);
1332 }
1333 concept_map.insert(
1334 (
1335 x.get_uuid().unwrap(),
1336 stringify!($element).to_string()
1337 ),
1338 AoristRef(Arc::new(RwLock::new(
1339 $name::$element((x.clone(), idx, parent.clone()))
1340 ))),
1341 );
1342 }
1343 )*
1344 }
1345 }
1346 }
1347 }
1348 }
1349}
1350#[macro_export]
1351macro_rules! register_constraint_new {
1352 ( $name:ident, $lt: lifetime, $($element: ident),+ ) => { aorist_paste::item! {
1353 #[derive(Clone)]
1354 pub enum $name {
1355 $(
1356 $element($element),
1357 )+
1358 }
1359 #[cfg_attr(feature = "python", pyclass(module = "aorist"))]
1360 #[derive(Clone)]
1361 pub struct [<$name Program>] {
1362 inner: [<$name ProgramEnum>],
1363 }
1364
1365 #[cfg(feature = "python")]
1366 #[pymethods]
1367 impl [<$name Program>] {
1368 #[new]
1369 fn new(inner: [<$name ProgramEnum>]) -> Self {
1370 Self { inner }
1371 }
1372 }
1373 #[cfg(feature = "python")]
1374 impl TOuterProgram for [<$name Program>] {
1375 type TAncestry = ConceptAncestry;
1376 fn get_dialect(&self) -> Dialect {
1377 self.inner.get_dialect()
1378 }
1379 fn compute_args(
1380 &self,
1381 root: <Self::TAncestry as Ancestry>::TConcept,
1382 ancestry: &Self::TAncestry,
1383 context: &mut aorist_core::Context,
1384 ) -> (String, String, ParameterTuple, Dialect) {
1385 let gil = Python::acquire_gil();
1386 let py = gil.python();
1387 let dill: &PyModule = PyModule::import(py, "dill").unwrap();
1389 let mut args = Vec::new();
1390 let mut kwargs = LinkedHashMap::new();
1391 for (input_types, serialized) in &self.inner.get_arg_functions() {
1392 let py_arg = PyString::new(py, &serialized);
1393 let deserialized = dill.getattr("loads").unwrap().call1((py_arg,)).unwrap();
1394 let mut objects = Vec::new();
1395 let mut context_pos = None;
1396 for (i, x) in input_types.iter().enumerate() {
1397 if x == "context" {
1398 assert!(context_pos.is_none());
1399 context_pos = Some(i);
1400 } else {
1401 objects.push(
1402 ancestry.py_object(x, root.clone(), py).unwrap().to_object(py)
1403 );
1404 }
1405 }
1406 let extracted;
1407 if let Some(pos) = context_pos {
1408 let obj = PyObject::from(PyCell::new(py, context.clone()).unwrap());
1409 objects.insert(pos, obj.to_object(py));
1410 let returned = deserialized.call1((objects,)).unwrap();
1411 let (
1412 extracted_string, extracted_context
1413 ) : (String, aorist_core::Context) = returned.extract().unwrap();
1414 context.insert(&extracted_context);
1415 extracted = extracted_string;
1416 } else {
1417 let arg = deserialized.call1((objects,)).unwrap();
1418 extracted = arg.extract().unwrap();
1420 }
1421 let ast = AST::StringLiteral(StringLiteral::new_wrapped(extracted, false));
1422 args.push(ast);
1423 }
1424 for (key, (input_types, serialized)) in &self.inner.get_kwarg_functions() {
1425 let py_arg = PyString::new(py, &serialized);
1426 let py_arg = py_arg.call_method1("encode", ("latin-1",)).unwrap();
1427 let deserialized = dill.getattr("loads").unwrap().call1((py_arg,)).unwrap();
1428
1429
1430 let mut objects = Vec::new();
1431 let mut context_pos = None;
1432 for (i, x) in input_types.iter().enumerate() {
1433 if x == "context" {
1434 assert!(context_pos.is_none());
1435 context_pos = Some(i);
1436 } else {
1437 match ancestry.py_object(x, root.clone(), py) {
1438 Ok(x) => objects.push(x.to_object(py)),
1439 Err(err) => panic!(
1440 "Error when running program for key {} input_type {} # {}:\n{}",
1441 key, i, x, err,
1442 ),
1443 }
1444 }
1445 }
1446 let extracted;
1447 if let Some(pos) = context_pos {
1448 let obj = PyObject::from(PyCell::new(py, context.clone()).unwrap());
1449 objects.insert(pos, obj.to_object(py));
1450 let returned = deserialized.call1((objects,)).unwrap();
1451 let (
1452 extracted_string, extracted_context
1453 ) : (String, aorist_core::Context) = returned.extract().unwrap();
1454 context.insert(&extracted_context);
1455 extracted = extracted_string;
1456 } else {
1457 extracted = match deserialized.call1((objects,)) {
1458 Ok(arg) => arg.extract().unwrap(),
1459 Err(err) => {
1460 err.print(py);
1461 panic!("Problem when extracting object. See traceback above");
1462 }
1463 };
1464 }
1465
1466 let ast = AST::StringLiteral(StringLiteral::new_wrapped(extracted, false));
1467 kwargs.insert(key.to_string(), ast);
1468 }
1469 (
1470 self.inner.get_code(),
1471 self.inner.get_entrypoint(),
1472 ParameterTuple { args, kwargs },
1473 self.inner.get_dialect(),
1475 )
1476 }
1477 }
1478 #[cfg_attr(feature = "python", derive(pyo3::prelude::FromPyObject))]
1479 #[derive(Clone)]
1480 pub enum [<$name ProgramEnum>] {
1481 $(
1482 $element([<$element Program>]),
1483 )+
1484 }
1485 impl [<$name ProgramEnum>] {
1486 #[cfg(feature = "python")]
1487 pub fn get_arg_functions(&self) -> Vec<(Vec<String>, String)> {
1488 match self {
1489 $(
1490 [<$name ProgramEnum>]::$element(x) => x.get_arg_functions(),
1491 )+
1492 }
1493 }
1494 pub fn get_dialect(&self) -> Dialect {
1495 match self {
1496 $(
1497 [<$name ProgramEnum>]::$element(x) => x.get_dialect(),
1498 )+
1499 }
1500 }
1501 pub fn get_code(&self) -> String {
1502 match self {
1503 $(
1504 [<$name ProgramEnum>]::$element(x) => x.get_code(),
1505 )+
1506 }
1507 }
1508 pub fn get_entrypoint(&self) -> String {
1509 match self {
1510 $(
1511 [<$name ProgramEnum>]::$element(x) => x.get_entrypoint(),
1512 )+
1513 }
1514 }
1515 pub fn get_kwarg_functions(&self) -> LinkedHashMap<String, (Vec<String>, String)> {
1516 match self {
1517 $(
1518 [<$name ProgramEnum>]::$element(x) => x.get_kwarg_functions(),
1519 )+
1520 }
1521 }
1522 }
1523 pub enum [<$name Builder>]<$lt> {
1524 $(
1525 $element(ConstraintBuilder<$lt, $element>),
1526 )+
1527 }
1528 #[cfg(feature = "python")]
1529 #[pymodule]
1530 fn libaorist_constraint(py: Python, m: &PyModule) -> PyResult<()> {
1531 init_logging();
1532 $(
1533 m.add_class::<$element>()?;
1534 m.add_class::<[<$name Program>]>()?;
1535 )+
1536 Ok(())
1537 }
1538 impl <$lt> TBuilder<$lt> for [<$name Builder>]<$lt> {
1539 type OuterType = Constraint;
1540 type TEnum = AoristRef<Concept>;
1541 type TAncestry = ConceptAncestry;
1542 fn builders() -> Vec<[<$name Builder>]<$lt>> where Self : Sized {
1543 vec![
1544 $(
1545 [<$name Builder>]::$element(
1546 ConstraintBuilder::<$lt, $element>{
1547 _phantom: std::marker::PhantomData,
1548 _phantom_lt: std::marker::PhantomData,
1549 }
1550 ),
1551 )+
1552 ]
1553 }
1554 fn get_constraint_name(&self) -> String {
1555 match &self {
1556 $(
1557 [<$name Builder>]::$element(_) => stringify!($element).to_string(),
1558 )+
1559 }
1560 }
1561 fn get_required_constraint_names(&self) -> Vec<String> {
1562 match &self {
1563 $(
1564 [<$name Builder>]::$element(_) => $element::get_required_constraint_names(),
1565 )+
1566 }
1567 }
1568 fn build_constraint(
1569 &self,
1570 root_uuid: Uuid,
1571 potential_child_constraints: Vec<Arc<RwLock<Self::OuterType>>>,
1572 ) -> Result<Self::OuterType> {
1573 match &self {
1574 $(
1575 [<$name Builder>]::$element(x) => Ok(Constraint {
1576 name: self.get_constraint_name(),
1577 root: self.get_root_type_name()?,
1578 requires: Some(self.get_required_constraint_names()),
1579 inner: Some(
1580 $name::$element(x.build_constraint(
1581 root_uuid,
1582 potential_child_constraints,
1583 )?)
1584 ),
1585 }),
1586 )+
1587 }
1588 }
1589 fn get_root_type_name(&self) -> Result<String> {
1590 match &self {
1591 $(
1592 [<$name Builder>]::$element(_) => $element::get_root_type_name(),
1593 )+
1594 }
1595 }
1596 fn get_required(&self, root: AoristRef<Concept>, ancestry:&ConceptAncestry) -> Vec<Uuid> {
1597 match &self {
1598 $(
1599 [<$name Builder>]::$element(_) =>
1600 $element::get_required(root, ancestry),
1601 )+
1602 }
1603 }
1604 fn should_add(&self, root: AoristRef<Concept>, ancestry:&ConceptAncestry) -> bool {
1605 match &self {
1606 $(
1607 [<$name Builder>]::$element(_) =>
1608 $element::should_add(root, ancestry),
1609 )+
1610 }
1611 }
1612 }
1613 impl <$lt> TConstraintEnum<$lt> for $name {
1614 fn get_required_constraint_names() -> HashMap<String, Vec<String>> {
1615 hashmap! {
1616 $(
1617 stringify!($element).to_string() => $element::get_required_constraint_names(),
1618 )+
1619 }
1620 }
1621 fn get_explanations() -> HashMap<String, (Option<String>, Option<String>)> {
1622 hashmap! {
1623 $(
1624 stringify!($element).to_string() => (
1625 $element::get_title(),
1626 $element::get_body(),
1627 ),
1628 )+
1629 }
1630 }
1631 }
1632 impl <$lt> $name {
1633 pub fn get_root_type_name(&self) -> Result<String> {
1634 match self {
1635 $(
1636 Self::$element(_) => $element::get_root_type_name(),
1637 )+
1638 }
1639 }
1640 pub fn get_downstream_constraints(&self) -> Result<Vec<Arc<RwLock<Constraint>>>> {
1641 match self {
1642 $(
1643 Self::$element(x) => x.get_downstream_constraints(),
1644 )+
1645 }
1646 }
1647 pub fn requires_program(&self) -> Result<bool> {
1648 match self {
1649 $(
1650 Self::$element(x) => x.requires_program(),
1651 )+
1652 }
1653 }
1654 pub fn get_uuid(&self) -> Result<Uuid> {
1655 match self {
1656 $(
1657 Self::$element(x) => x.get_uuid(),
1658 )+
1659 }
1660 }
1661 pub fn get_title(&self) -> Option<String> {
1662 match self {
1663 $(
1664 Self::$element(_) => $element::get_title(),
1665 )+
1666 }
1667 }
1668 pub fn get_body(&self) -> Option<String> {
1669 match self {
1670 $(
1671 Self::$element(_) => $element::get_body(),
1672 )+
1673 }
1674 }
1675 pub fn get_root_uuid(&self) -> Result<Uuid> {
1676 match self {
1677 $(
1678 Self::$element(x) => x.get_root_uuid(),
1679 )+
1680 }
1681 }
1682 fn get_root_type_names() -> Result<HashMap<String, String>> {
1683 Ok(hashmap! {
1684 $(
1685 stringify!($element).to_string() => $element::get_root_type_name()?,
1686 )+
1687 })
1688 }
1689 pub fn get_name(&self) -> String {
1690 match self {
1691 $(
1692 Self::$element(x) => stringify!($element).to_string(),
1693 )+
1694 }
1695 }
1696 pub fn should_add(
1697 &self,
1698 root: AoristRef<Concept>,
1699 ancestry: &ConceptAncestry,
1700 ) -> bool {
1701 match &self {
1702 $(
1703 Self::$element(_) => $element::should_add(root,
1704 ancestry),
1705 )+
1706 }
1707 }
1708 }}
1709 }
1710}