1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
pub mod extract;

use std::fmt::{Debug, Formatter};
use std::sync::Arc;
use key_path::KeyPath;
use crate::object::Object;
use crate::model;
use crate::pipeline::pipeline::Pipeline;
use crate::request;
use teo_result::{Result, ResultExt};
use crate::action::Action;
use crate::connection::transaction;

#[derive(Clone)]
pub struct Ctx {
    inner: Arc<CtxInner>,
}

unsafe impl Send for Ctx { }
unsafe impl Sync for Ctx { }

#[derive(Debug)]
struct CtxInner {
    value: Object,
    object: model::Object,
    path: KeyPath,
    action: Action,
    transaction_ctx: transaction::Ctx,
    request_ctx: Option<request::Ctx>,
}

impl Ctx {

    pub fn new(value: Object, object: model::Object, path: KeyPath, action: Action, transaction_ctx: transaction::Ctx, request_ctx: Option<request::Ctx>) -> Self {
        Self {
            inner: Arc::new(CtxInner { value, object, path, action, transaction_ctx, request_ctx })
        }
    }

    pub fn value(&self) -> &Object {
        &self.inner.value
    }

    pub fn object(&self) -> &model::Object {
        &self.inner.object
    }

    pub fn path(&self) -> &KeyPath {
        &self.inner.path
    }

    pub fn action(&self) -> Action {
        self.inner.action
    }

    pub fn transaction_ctx(&self) -> transaction::Ctx {
        self.inner.transaction_ctx.clone()
    }

    pub fn request_ctx(&self) -> Option<request::Ctx> {
        self.inner.request_ctx.clone()
    }

    pub async fn resolve_pipeline(&self, object: Object, err_prefix: impl AsRef<str>) -> Result<Object> {
        if let Some(pipeline) = object.as_pipeline() {
            self.run_pipeline_with_err_prefix(pipeline, err_prefix).await
        } else {
            Ok(object)
        }
    }

    pub async fn run_pipeline_with_err_prefix(&self, pipeline: &Pipeline, err_prefix: impl AsRef<str>) -> Result<Object> {
        self.run_pipeline(pipeline).await.err_prefix(err_prefix)
    }

    pub async fn run_pipeline(&self, pipeline: &Pipeline) -> Result<Object> {
        let mut ctx = self.clone();
        for item in &pipeline.items {
            ctx = ctx.alter_value(item.call(item.arguments.clone(), ctx.clone()).await?.cast(item.cast_output_type.as_ref(), self.transaction_ctx().namespace()));
        }
        Ok(ctx.value().clone())
    }

    pub async fn run_pipeline_into_path_value_error(&self, pipeline: &Pipeline) -> crate::path::Result<Object> {
        match self.run_pipeline(pipeline).await {
            Ok(object) => Ok(object),
            Err(e) => Err(crate::path::Error::value_error(self.path().clone(), e.message))
        }
    }

    pub async fn run_pipeline_into_path_unauthorized_error(&self, pipeline: &Pipeline) -> crate::path::Result<Object> {
        match self.run_pipeline(pipeline).await {
            Ok(object) => Ok(object),
            Err(e) => Err(crate::path::Error::unauthorized_error(self.path().clone(), e.message))
        }
    }

    pub fn alter_value(&self, value: Object) -> Self {
        Self {
            inner: Arc::new(CtxInner {
                value,
                object: self.inner.object.clone(),
                path: self.inner.path.clone(),
                action: self.inner.action,
                transaction_ctx: self.inner.transaction_ctx.clone(),
                request_ctx: self.inner.request_ctx.clone(),
            })
        }
    }
}

impl<'a> Debug for Ctx {

    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        Debug::fmt(self.inner.as_ref(), f)
    }
}