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}