tf_provider/
data_source.rs

1// This file is part of the tf-provider project
2//
3// Copyright (C) ANEO, 2024-2024. All rights reserved.
4//
5// Licensed under the Apache License, Version 2.0 (the "License")
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9//     http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17//! [`DataSource`] module
18
19use crate::diagnostics::Diagnostics;
20use crate::raw::RawValue;
21use crate::schema::Schema;
22use crate::utils::OptionFactor;
23
24use async_trait::async_trait;
25use serde::{Deserialize, Serialize};
26
27#[async_trait]
28/// Trait for implementing a data source with automatic serialization/deserialization
29///
30/// See also: [`DynamicDataSource`]
31pub trait DataSource: Send + Sync {
32    /// State of the data source
33    ///
34    /// The state will be automatically serialized/deserialized at the border of the request.
35    type State<'a>: Serialize + Deserialize<'a> + Send;
36
37    /// State of the provider metadata
38    ///
39    /// The state will be automatically serialized/deserialized at the border of the request.
40    type ProviderMetaState<'a>: Serialize + Deserialize<'a> + Send;
41
42    /// Get the schema of the data source
43    ///
44    /// # Arguments
45    ///
46    /// * `diags` - Diagnostics to record warnings and errors that occured when getting back the schema
47    ///
48    /// # Remarks
49    ///
50    /// The return is ignored if there is an error in diagnostics.
51    /// If the return is [`None`], an ad-hoc error is added to diagnostics.
52    fn schema(&self, diags: &mut Diagnostics) -> Option<Schema>;
53
54    /// Validate the configuration of the data source
55    ///
56    /// # Arguments
57    ///
58    /// * `diags` - Diagnostics to record warnings and errors that occured during validation
59    /// * `config` - State as declared in the Terraform file
60    ///
61    /// # Remarks
62    ///
63    /// The return is ignored if there is an error in diagnostics.
64    /// If the return is [`None`], an ad-hoc error is added to diagnostics.
65    async fn validate<'a>(&self, diags: &mut Diagnostics, config: Self::State<'a>) -> Option<()> {
66        _ = diags;
67        _ = config;
68        Some(())
69    }
70
71    /// Read the state of the data source
72    ///
73    /// # Arguments
74    ///
75    /// * `diags` - Diagnostics to record warnings and errors that occured during the read
76    /// * `config` - State as declared in the Terraform file
77    /// * `provider_meta_state` - State of the provider metadata as declared in the Terraform file
78    ///
79    /// # Remarks
80    ///
81    /// The return is ignored if there is an error in diagnostics.
82    /// If the return is [`None`], an ad-hoc error is added to diagnostics.
83    async fn read<'a>(
84        &self,
85        diags: &mut Diagnostics,
86        config: Self::State<'a>,
87        provider_meta_state: Self::ProviderMetaState<'a>,
88    ) -> Option<Self::State<'a>>;
89}
90
91#[async_trait]
92/// Trait for implementing a data source *without* automatic serialization/deserialization
93///
94/// See also: [`DataSource`]
95pub trait DynamicDataSource: Send + Sync {
96    /// Get the schema of the data source
97    ///
98    /// # Arguments
99    ///
100    /// * `diags` - Diagnostics to record warnings and errors that occured when getting back the schema
101    ///
102    /// # Remarks
103    ///
104    /// The return is ignored if there is an error in diagnostics.
105    /// If the return is [`None`], an ad-hoc error is added to diagnostics.
106    fn schema(&self, diags: &mut Diagnostics) -> Option<Schema>;
107
108    /// Validate the configuration of the data source
109    ///
110    /// # Arguments
111    ///
112    /// * `diags` - Diagnostics to record warnings and errors that occured during validation
113    /// * `config` - State as declared in the Terraform file
114    ///
115    /// # Remarks
116    ///
117    /// The return is ignored if there is an error in diagnostics.
118    /// If the return is [`None`], an ad-hoc error is added to diagnostics.
119    async fn validate(&self, diags: &mut Diagnostics, config: RawValue) -> Option<()> {
120        _ = diags;
121        _ = config;
122        Some(())
123    }
124
125    /// Read the new state of the data source
126    ///
127    /// # Arguments
128    ///
129    /// * `diags` - Diagnostics to record warnings and errors that occured during the read
130    /// * `config` - State as declared in the Terraform file
131    /// * `provider_meta_state` - State of the provider metadata as declared in the Terraform file
132    ///
133    /// # Remarks
134    ///
135    /// The return is ignored if there is an error in diagnostics.
136    /// If the return is [`None`], an ad-hoc error is added to diagnostics.
137    async fn read(
138        &self,
139        diags: &mut Diagnostics,
140        config: RawValue,
141        provider_meta_state: RawValue,
142    ) -> Option<RawValue>;
143}
144
145#[async_trait]
146impl<T: DataSource> DynamicDataSource for T {
147    fn schema(&self, diags: &mut Diagnostics) -> Option<Schema> {
148        <T as DataSource>::schema(self, diags)
149    }
150    async fn validate(&self, diags: &mut Diagnostics, config: RawValue) -> Option<()> {
151        let config = config.deserialize(diags)?;
152        <T as DataSource>::validate(self, diags, config).await
153    }
154    async fn read(
155        &self,
156        diags: &mut Diagnostics,
157        config: RawValue,
158        provider_meta_state: RawValue,
159    ) -> Option<RawValue> {
160        let (config, provider_meta_state) = (
161            config.deserialize(diags),
162            provider_meta_state.deserialize(diags),
163        )
164            .factor()?;
165        let state = <T as DataSource>::read(self, diags, config, provider_meta_state).await?;
166        RawValue::serialize(diags, &state)
167    }
168}
169
170impl<T: DataSource + 'static> From<T> for Box<dyn DynamicDataSource> {
171    fn from(value: T) -> Self {
172        Box::new(value)
173    }
174}