Skip to content

Commit 72dbd2a

Browse files
Introduce configuration version 2 (#208)
### What This PR adds a new version (`"2"`) of the deployment configuration data format. This version of the configuration is capable of expressing array types in collections and arguments. Since this is the first time a new version is introduced there are a lot of changes the only purpose of which is to distinguish between versions. Only the infrastructure-related shell of the connector is aware of different versions of deployment configurations existing. The core of the connector only works with a single internal version. This PR is also the one to introduce tests of array types. In hindsight this ought to have been possible in the previous PR that introduced the internal types and transformations (#191). Note that there is not yet any automated way to upgrade a configuration to a newer version, but this will be introduced shortly. This PR also adds a changelog entry. ### How The file `version2.rs` is a duplicate of `version1.rs`, which has been adapted to use the new data types (incidentally these are just the ones of the internal model). `configuration.sql` now exists as `version1.sql` and `version2.sql` respectively, since these have different capabilities. This is because `version2.sql` introduces the ability to introspect array types. `configuration.rs` now exposes `RawConfiguration` and `Configuration` types which are enums of all the supported versions (currently 1 and "2"). One big wart on the implementation is that serde and schemars are unable to derive trait implementations for these types correctly, since they only support strings as enum tags, and we used a number literal for version 1. Once we drop support of version 1 completely we can remove the manually implemented instances. The various `Connector` trait implementations now explicitly work on the internal representation of a configuration, `RuntimeConfiguration`. --------- Co-authored-by: Daniel Harvey <[email protected]>
1 parent a04bb82 commit 72dbd2a

File tree

78 files changed

+26017
-655
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+26017
-655
lines changed

.github/test-configuration.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
},
1616
"ndc-postgres-12": {
1717
"feature": "postgres",
18-
"filter": "not test(configure_initial_configuration_is_unchanged) and not test(configure_is_idempotent)",
18+
"filter": "not test(postgres_current_only)",
1919
"services": "postgres",
2020
"env": {
2121
"POSTGRESQL_CONNECTION_STRING": "postgresql://postgres:password@localhost:64002",
@@ -24,7 +24,7 @@
2424
},
2525
"ndc-postgres-13": {
2626
"feature": "postgres",
27-
"filter": "not test(configure_initial_configuration_is_unchanged) and not test(configure_is_idempotent)",
27+
"filter": "not test(postgres_current_only)",
2828
"services": "postgres",
2929
"env": {
3030
"POSTGRESQL_CONNECTION_STRING": "postgresql://postgres:password@localhost:64002",
@@ -33,7 +33,7 @@
3333
},
3434
"ndc-postgres-14": {
3535
"feature": "postgres",
36-
"filter": "not test(configure_initial_configuration_is_unchanged) and not test(configure_is_idempotent)",
36+
"filter": "not test(postgres_current_only)",
3737
"services": "postgres",
3838
"env": {
3939
"POSTGRESQL_CONNECTION_STRING": "postgresql://postgres:password@localhost:64002",
@@ -42,7 +42,7 @@
4242
},
4343
"ndc-postgres-15": {
4444
"feature": "postgres",
45-
"filter": "not test(configure_initial_configuration_is_unchanged) and not test(configure_is_idempotent)",
45+
"filter": "not test(postgres_current_only)",
4646
"services": "postgres",
4747
"env": {
4848
"POSTGRESQL_CONNECTION_STRING": "postgresql://postgres:password@localhost:64002",

.github/workflows/cargo-test.yaml

+6-2
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,13 @@ jobs:
127127
AURORA_CONNECTION_STRING: ${{ secrets.AURORA_CONNECTION_STRING }}
128128
run: |
129129
# take connection string from env, create deployment file with it
130-
cat static/aurora/chinook-deployment-template.json \
130+
cat static/aurora/v1-chinook-deployment-template.json \
131131
| jq '.connectionUri={"uri":{"value":(env | .AURORA_CONNECTION_STRING)}}' \
132-
> static/aurora/chinook-deployment.json
132+
> static/aurora/v1-chinook-deployment.json
133+
134+
cat static/aurora/v2-chinook-deployment-template.json \
135+
| jq '.connectionUri={"uri":{"value":(env | .AURORA_CONNECTION_STRING)}}' \
136+
> static/aurora/v2-chinook-deployment.json
133137
134138
- name: install tools
135139
run: |

changelog.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Added
66

7+
- Introduce version 2 of connector deployment configuration. ([#208](https://github.com/hasura/ndc-postgres/pull/208))
78
- Support array types ([#191](https://github.com/hasura/ndc-postgres/pull/191), ...)
89
- Support Native Query Mutations ([#189](https://github.com/hasura/ndc-postgres/pull/189), [#198](https://github.com/hasura/ndc-postgres/pull/198))
910

Original file line numberDiff line numberDiff line change
@@ -1,17 +1,70 @@
11
//! Configuration for the connector.
22
3-
mod version1;
4-
5-
use std::collections::BTreeSet;
3+
mod custom_trait_implementations;
4+
pub mod version1;
5+
pub mod version2;
66

7+
use custom_trait_implementations::RawConfigurationCompat;
8+
use ndc_sdk::connector;
79
use query_engine_metadata::metadata;
10+
use schemars::JsonSchema;
11+
use serde::{Deserialize, Serialize};
12+
13+
pub use version2::{occurring_scalar_types, ConnectionUri, PoolSettings, ResolvedSecret};
814

9-
pub use version1::{
10-
configure, metadata_to_current, validate_raw_configuration, Configuration, ConnectionUri,
11-
PoolSettings, RawConfiguration, ResolvedSecret,
12-
};
15+
/// Initial configuration, just enough to connect to a database and elaborate a full
16+
/// 'Configuration'.
17+
#[derive(Clone, Debug, Deserialize, Serialize)]
18+
#[serde(tag = "version")]
19+
#[serde(try_from = "RawConfigurationCompat")]
20+
#[serde(into = "RawConfigurationCompat")]
21+
// NOTE: Any changes to this data type will need follow-up changes to the
22+
// 'custom_trait_implementations' module.
23+
pub enum RawConfiguration {
24+
// Until https://github.com/serde-rs/serde/pull/2525 is merged enum tags have to be strings.
25+
#[serde(rename = "1")]
26+
Version1(version1::RawConfiguration),
27+
#[serde(rename = "2")]
28+
Version2(version2::RawConfiguration),
29+
}
30+
31+
impl RawConfiguration {
32+
pub fn empty() -> Self {
33+
RawConfiguration::Version2(version2::RawConfiguration::empty())
34+
}
35+
}
1336

14-
pub const CURRENT_VERSION: u32 = 1;
37+
/// User configuration, elaborated from a 'RawConfiguration'.
38+
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
39+
#[serde(rename_all = "camelCase")]
40+
pub struct Configuration {
41+
pub config: RawConfiguration,
42+
}
43+
44+
pub async fn configure(
45+
args: RawConfiguration,
46+
) -> Result<RawConfiguration, connector::UpdateConfigurationError> {
47+
match args {
48+
RawConfiguration::Version1(v1) => {
49+
Ok(RawConfiguration::Version1(version1::configure(v1).await?))
50+
}
51+
RawConfiguration::Version2(v2) => {
52+
Ok(RawConfiguration::Version2(version2::configure(v2).await?))
53+
}
54+
}
55+
}
56+
pub async fn validate_raw_configuration(
57+
config: RawConfiguration,
58+
) -> Result<Configuration, connector::ValidateError> {
59+
match config {
60+
RawConfiguration::Version1(v1) => Ok(Configuration {
61+
config: RawConfiguration::Version1(version1::validate_raw_configuration(v1).await?),
62+
}),
63+
RawConfiguration::Version2(v2) => Ok(Configuration {
64+
config: RawConfiguration::Version2(version2::validate_raw_configuration(v2).await?),
65+
}),
66+
}
67+
}
1568

1669
/// A configuration type, tailored to the needs of the query/mutation/explain methods (i.e., those
1770
/// not to do with configuration management).
@@ -25,54 +78,41 @@ pub const CURRENT_VERSION: u32 = 1;
2578
#[derive(Debug)]
2679
pub struct RuntimeConfiguration {
2780
pub metadata: metadata::Metadata,
81+
pub pool_settings: version1::PoolSettings,
82+
pub connection_uri: String,
2883
}
2984

30-
impl<'a> version1::Configuration {
31-
/// Apply the common interpretations on the Configuration API type into an RuntimeConfiguration.
32-
pub fn as_runtime_configuration(self: &'a Configuration) -> RuntimeConfiguration {
33-
RuntimeConfiguration {
34-
metadata: metadata_to_current(&self.config.metadata),
35-
}
85+
/// Apply the common interpretations on the Configuration API type into an RuntimeConfiguration.
86+
pub fn as_runtime_configuration(config: &Configuration) -> RuntimeConfiguration {
87+
match &config.config {
88+
RawConfiguration::Version1(v1_config) => RuntimeConfiguration {
89+
metadata: version1::metadata_to_current(&v1_config.metadata),
90+
pool_settings: v1_config.pool_settings.clone(),
91+
connection_uri: match &v1_config.connection_uri {
92+
ConnectionUri::Uri(ResolvedSecret(uri)) => uri.clone(),
93+
},
94+
},
95+
RawConfiguration::Version2(v2_config) => RuntimeConfiguration {
96+
metadata: v2_config.metadata.clone(),
97+
pool_settings: v2_config.pool_settings.clone(),
98+
connection_uri: match &v2_config.connection_uri {
99+
ConnectionUri::Uri(ResolvedSecret(uri)) => uri.clone(),
100+
},
101+
},
36102
}
37103
}
38104

39-
/// Collect all the types that can occur in the metadata. This is a bit circumstantial. A better
40-
/// approach is likely to record scalar type names directly in the metadata via configuration.sql.
41-
pub fn occurring_scalar_types(
42-
tables: &metadata::TablesInfo,
43-
native_queries: &metadata::NativeQueries,
44-
) -> BTreeSet<metadata::ScalarType> {
45-
let tables_column_types = tables.0.values().flat_map(|v| {
46-
v.columns
47-
.values()
48-
.map(|c| c.r#type.clone())
49-
.filter_map(some_scalar_type)
50-
});
51-
52-
let native_queries_column_types = native_queries.0.values().flat_map(|v| {
53-
v.columns
54-
.values()
55-
.map(|c| c.r#type.clone())
56-
.filter_map(some_scalar_type)
57-
});
58-
59-
let native_queries_arguments_types = native_queries.0.values().flat_map(|v| {
60-
v.arguments
61-
.values()
62-
.map(|c| c.r#type.clone())
63-
.filter_map(some_scalar_type)
64-
});
65-
66-
tables_column_types
67-
.chain(native_queries_column_types)
68-
.chain(native_queries_arguments_types)
69-
.collect::<BTreeSet<metadata::ScalarType>>()
70-
}
105+
// for tests
71106

72-
/// Filter predicate that only keeps scalar types.
73-
fn some_scalar_type(typ: metadata::Type) -> Option<metadata::ScalarType> {
74-
match typ {
75-
metadata::Type::ArrayType(_) => None,
76-
metadata::Type::ScalarType(t) => Some(t),
107+
pub fn set_connection_uri(config: RawConfiguration, connection_uri: String) -> RawConfiguration {
108+
match config {
109+
RawConfiguration::Version1(v1) => RawConfiguration::Version1(version1::RawConfiguration {
110+
connection_uri: ConnectionUri::Uri(ResolvedSecret(connection_uri)),
111+
..v1
112+
}),
113+
RawConfiguration::Version2(v2) => RawConfiguration::Version2(version2::RawConfiguration {
114+
connection_uri: ConnectionUri::Uri(ResolvedSecret(connection_uri)),
115+
..v2
116+
}),
77117
}
78118
}

0 commit comments

Comments
 (0)