wick_config/config/components/
sql.rs

1#![allow(missing_docs)]
2use std::borrow::Cow;
3
4// delete when we move away from the `property` crate.
5use wick_interface_types::{Field, OperationSignatures};
6
7use super::{ComponentConfig, OperationConfig};
8use crate::config::bindings::BoundIdentifier;
9use crate::config::{self, ErrorBehavior};
10use crate::utils::impl_from_for;
11
12#[derive(
13  Debug,
14  Clone,
15  derive_builder::Builder,
16  PartialEq,
17  derive_asset_container::AssetManager,
18  property::Property,
19  serde::Serialize,
20)]
21#[property(get(public), set(public), mut(public, suffix = "_mut"))]
22#[asset(asset(config::AssetReference))]
23#[builder(setter(into))]
24/// A component made out of other components
25pub struct SqlComponentConfig {
26  /// The TcpPort reference to listen on for connections.
27  #[asset(skip)]
28  pub(crate) resource: BoundIdentifier,
29
30  /// Whether or not to use TLS.
31  #[asset(skip)]
32  #[builder(default)]
33  pub(crate) tls: bool,
34
35  /// The configuration for the component.
36  #[asset(skip)]
37  #[builder(default)]
38  #[serde(skip_serializing_if = "Vec::is_empty")]
39  pub(crate) config: Vec<Field>,
40
41  /// A list of operations to expose on this component.
42  #[asset(skip)]
43  #[builder(default)]
44  #[property(skip)]
45  #[serde(skip_serializing_if = "Vec::is_empty")]
46  pub(crate) operations: Vec<SqlOperationDefinition>,
47}
48
49impl SqlComponentConfig {}
50
51impl OperationSignatures for SqlComponentConfig {
52  fn operation_signatures(&self) -> Vec<wick_interface_types::OperationSignature> {
53    self.operations.clone().into_iter().map(Into::into).collect()
54  }
55}
56
57impl_from_for!(SqlOperationDefinition, Query, SqlQueryOperationDefinition);
58impl_from_for!(SqlOperationDefinition, Exec, SqlExecOperationDefinition);
59
60impl From<SqlOperationDefinition> for wick_interface_types::OperationSignature {
61  fn from(value: SqlOperationDefinition) -> Self {
62    match value {
63      SqlOperationDefinition::Query(v) => v.into(),
64      SqlOperationDefinition::Exec(v) => v.into(),
65    }
66  }
67}
68
69impl ComponentConfig for SqlComponentConfig {
70  type Operation = SqlOperationDefinition;
71
72  fn operations(&self) -> &[Self::Operation] {
73    &self.operations
74  }
75
76  fn operations_mut(&mut self) -> &mut Vec<Self::Operation> {
77    &mut self.operations
78  }
79}
80
81#[derive(Debug, Clone, PartialEq, serde::Serialize)]
82#[serde(rename_all = "kebab-case")]
83pub enum SqlOperationDefinition {
84  Query(SqlQueryOperationDefinition),
85  Exec(SqlExecOperationDefinition),
86}
87
88#[derive(Debug, Clone, Copy)]
89pub enum SqlOperationKind {
90  Query,
91  Exec,
92}
93
94impl std::fmt::Display for SqlOperationKind {
95  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96    match self {
97      SqlOperationKind::Query => write!(f, "sql query operation"),
98      SqlOperationKind::Exec => write!(f, "sql exec operation"),
99    }
100  }
101}
102
103impl SqlOperationDefinition {
104  #[must_use]
105  pub const fn on_error(&self) -> ErrorBehavior {
106    match self {
107      SqlOperationDefinition::Query(v) => v.on_error,
108      SqlOperationDefinition::Exec(v) => v.on_error,
109    }
110  }
111
112  #[must_use]
113  pub fn arguments(&self) -> &[String] {
114    match self {
115      SqlOperationDefinition::Query(v) => &v.arguments,
116      SqlOperationDefinition::Exec(v) => &v.arguments,
117    }
118  }
119
120  #[must_use]
121  pub fn query(&self) -> &str {
122    match self {
123      SqlOperationDefinition::Query(v) => &v.query,
124      SqlOperationDefinition::Exec(v) => &v.exec,
125    }
126  }
127
128  #[must_use]
129  pub const fn kind(&self) -> SqlOperationKind {
130    match self {
131      SqlOperationDefinition::Query(_) => SqlOperationKind::Query,
132      SqlOperationDefinition::Exec(_) => SqlOperationKind::Exec,
133    }
134  }
135}
136
137impl OperationConfig for SqlOperationDefinition {
138  fn name(&self) -> &str {
139    match self {
140      SqlOperationDefinition::Query(v) => &v.name,
141      SqlOperationDefinition::Exec(v) => &v.name,
142    }
143  }
144
145  fn inputs(&self) -> Cow<Vec<Field>> {
146    match self {
147      SqlOperationDefinition::Query(v) => v.inputs(),
148      SqlOperationDefinition::Exec(v) => v.inputs(),
149    }
150  }
151
152  fn outputs(&self) -> Cow<Vec<Field>> {
153    match self {
154      SqlOperationDefinition::Query(v) => v.outputs(),
155      SqlOperationDefinition::Exec(v) => v.outputs(),
156    }
157  }
158}
159
160impl OperationConfig for SqlQueryOperationDefinition {
161  fn name(&self) -> &str {
162    &self.name
163  }
164
165  fn inputs(&self) -> Cow<Vec<Field>> {
166    Cow::Borrowed(&self.inputs)
167  }
168
169  fn outputs(&self) -> Cow<Vec<Field>> {
170    Cow::Borrowed(&self.outputs)
171  }
172}
173
174impl OperationConfig for SqlExecOperationDefinition {
175  fn name(&self) -> &str {
176    &self.name
177  }
178
179  fn inputs(&self) -> Cow<Vec<Field>> {
180    Cow::Borrowed(&self.inputs)
181  }
182
183  fn outputs(&self) -> Cow<Vec<Field>> {
184    Cow::Borrowed(&self.outputs)
185  }
186}
187
188impl From<SqlQueryOperationDefinition> for wick_interface_types::OperationSignature {
189  fn from(operation: SqlQueryOperationDefinition) -> Self {
190    // TODO: Properly use configured outputs here.
191    // Forcing SQL components to have a single object output called "output" is a temporary
192    // limitation
193    let outputs = vec![Field::new("output", wick_interface_types::Type::Object)];
194
195    Self::new(operation.name, operation.inputs, outputs, operation.config)
196  }
197}
198
199impl From<SqlExecOperationDefinition> for wick_interface_types::OperationSignature {
200  fn from(operation: SqlExecOperationDefinition) -> Self {
201    let outputs = vec![Field::new("output", wick_interface_types::Type::U32)];
202
203    Self::new(operation.name, operation.inputs, outputs, operation.config)
204  }
205}
206#[derive(
207  Debug,
208  Clone,
209  derive_builder::Builder,
210  PartialEq,
211  derive_asset_container::AssetManager,
212  property::Property,
213  serde::Serialize,
214)]
215#[property(get(public), set(public), mut(public, suffix = "_mut"))]
216#[asset(asset(config::AssetReference))]
217#[builder(setter(into))]
218/// An operation whose implementation is a SQL query to execute on a database.
219pub struct SqlQueryOperationDefinition {
220  /// The name of the operation.
221  #[asset(skip)]
222  #[property(skip)]
223  pub(crate) name: String,
224
225  /// Types of the inputs to the operation.
226  #[asset(skip)]
227  #[property(skip)]
228  #[builder(default)]
229  #[serde(skip_serializing_if = "Vec::is_empty")]
230  pub(crate) inputs: Vec<Field>,
231
232  /// Types of the outputs to the operation.
233  #[asset(skip)]
234  #[property(skip)]
235  #[builder(default)]
236  #[serde(skip_serializing_if = "Vec::is_empty")]
237  pub(crate) outputs: Vec<Field>,
238
239  /// The configuration the operation needs.
240  #[asset(skip)]
241  #[builder(default)]
242  #[serde(skip_serializing_if = "Vec::is_empty")]
243  pub(crate) config: Vec<Field>,
244
245  /// The query to execute.
246  #[asset(skip)]
247  pub(crate) query: String,
248
249  /// The arguments to the query, defined as a list of input names.
250  #[asset(skip)]
251  #[builder(default)]
252  #[serde(skip_serializing_if = "Vec::is_empty")]
253  pub(crate) arguments: Vec<String>,
254
255  /// The query to execute.
256  #[asset(skip)]
257  #[builder(default)]
258  pub(crate) on_error: ErrorBehavior,
259}
260
261#[derive(
262  Debug,
263  Clone,
264  derive_builder::Builder,
265  PartialEq,
266  derive_asset_container::AssetManager,
267  property::Property,
268  serde::Serialize,
269)]
270#[property(get(public), set(public), mut(public, suffix = "_mut"))]
271#[asset(asset(config::AssetReference))]
272#[builder(setter(into))]
273/// An operation whose implementation is a SQL query to execute on a database and returns the number of rows affected or failure.
274pub struct SqlExecOperationDefinition {
275  /// The name of the operation.
276  #[asset(skip)]
277  #[property(skip)]
278  pub(crate) name: String,
279
280  /// Types of the inputs to the operation.
281  #[asset(skip)]
282  #[property(skip)]
283  #[builder(default)]
284  #[serde(skip_serializing_if = "Vec::is_empty")]
285  pub(crate) inputs: Vec<Field>,
286
287  /// Types of the outputs to the operation.
288  #[asset(skip)]
289  #[property(skip)]
290  #[builder(default)]
291  #[serde(skip_serializing_if = "Vec::is_empty")]
292  pub(crate) outputs: Vec<Field>,
293
294  /// The configuration the operation needs.
295  #[asset(skip)]
296  #[builder(default)]
297  #[serde(skip_serializing_if = "Vec::is_empty")]
298  pub(crate) config: Vec<Field>,
299
300  /// The query to execute.
301  #[asset(skip)]
302  pub(crate) exec: String,
303
304  /// The arguments to the query, defined as a list of input names.
305  #[asset(skip)]
306  #[builder(default)]
307  #[serde(skip_serializing_if = "Vec::is_empty")]
308  pub(crate) arguments: Vec<String>,
309
310  /// The query to execute.
311  #[asset(skip)]
312  #[builder(default)]
313  pub(crate) on_error: ErrorBehavior,
314}