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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright Materialize, Inc. and contributors. All rights reserved.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0.

//! Contains traits and types to support inlining connection details.
//!
//! Because we ultimately want to support the ability to alter the details of a
//! connection, we cannot simply inline their state into structs--we instead
//! need a means of understanding which connection we're referring to and inline
//! its current state when sending the struct off to be used to handle a
//! connection to an external service.

use std::fmt::Debug;
use std::hash::Hash;

use mz_repr::GlobalId;
use proptest::prelude::Arbitrary;
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};

use crate::AlterCompatible;

use super::Connection;

/// Permits any struct to take a `GlobalId` into an inlined connection.
///
/// It is safe to assume that if this `id` does not refer to a catalog
/// connection, this function will panic.
pub trait ConnectionResolver {
    fn resolve_connection(&self, id: GlobalId) -> Connection<InlinedConnection>;
}

impl<R: ConnectionResolver + ?Sized> ConnectionResolver for &R {
    fn resolve_connection(&self, id: GlobalId) -> Connection<InlinedConnection> {
        (*self).resolve_connection(id)
    }
}

/// Takes ~`T<ReferencedConnection>` to ~`T<InlinedConnection>` by recursively
/// inlining connections and resolving any referenced connections into their
/// inlined version.
///
/// Note that this trait is overly generic.
// TODO: this trait could be derived for types that are generic over a type that
// implements `ConnectionAccess`, e.g. `derive(IntoInlineConnection)`.
pub trait IntoInlineConnection<T, R: ConnectionResolver + ?Sized> {
    fn into_inline_connection(self, connection_resolver: R) -> T;
}

/// Expresses how a struct/enum can access details about any connections it
/// uses. Meant to be used as a type constraint on structs that use connections.
pub trait ConnectionAccess:
    Arbitrary + Clone + Debug + Eq + PartialEq + Serialize + 'static
{
    type Kafka: Arbitrary
        + Clone
        + Debug
        + Eq
        + PartialEq
        + Hash
        + Serialize
        + for<'a> Deserialize<'a>
        + AlterCompatible;
    type Pg: Arbitrary
        + Clone
        + Debug
        + Eq
        + PartialEq
        + Hash
        + Serialize
        + for<'a> Deserialize<'a>
        + AlterCompatible;
    type Ssh: Arbitrary
        + Clone
        + Debug
        + Eq
        + PartialEq
        + Hash
        + Serialize
        + for<'a> Deserialize<'a>
        + AlterCompatible;
    type Csr: Arbitrary
        + Clone
        + Debug
        + Eq
        + PartialEq
        + Hash
        + Serialize
        + for<'a> Deserialize<'a>
        + AlterCompatible;
    type MySql: Arbitrary
        + Clone
        + Debug
        + Eq
        + PartialEq
        + Hash
        + Serialize
        + for<'a> Deserialize<'a>
        + AlterCompatible;
}

/// Expresses that the struct contains references to connections. Use a
/// combination of [`IntoInlineConnection`] and [`ConnectionResolver`] to take
/// this into [`InlinedConnection`].
#[derive(Arbitrary, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ReferencedConnection;

impl ConnectionAccess for ReferencedConnection {
    type Kafka = GlobalId;
    type Pg = GlobalId;
    type Ssh = GlobalId;
    type Csr = GlobalId;
    type MySql = GlobalId;
}

/// Expresses that the struct contains an inlined definition of a connection.
#[derive(Arbitrary, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct InlinedConnection;

impl ConnectionAccess for InlinedConnection {
    type Kafka = super::KafkaConnection;
    type Pg = super::PostgresConnection;
    type Ssh = super::SshConnection;
    type Csr = super::CsrConnection;
    type MySql = super::MySqlConnection;
}