From 4a4db1ad2b416314930afa5cec805189d367b370 Mon Sep 17 00:00:00 2001 From: Daniel Chambers Date: Tue, 20 Feb 2024 15:16:57 +1100 Subject: [PATCH] Update to support latest SDK --- .editorconfig | 8 +- .github/workflows/docker.yml | 24 +- .gitignore | 1 + .vscode/launch.json | 30 ++ CHANGELOG.md | 4 + Cargo.lock | 520 ++++++++++++++----- Cargo.toml | 1 + Dockerfile | 20 +- README.md | 43 +- config.json | 1 - connector-definition/Makefile | 21 + connector-definition/connector-metadata.yaml | 11 + connector-definition/docker-compose.yaml | 7 + crates/ndc-sendgrid/Cargo.toml | 6 +- crates/ndc-sendgrid/src/configuration.rs | 39 +- crates/ndc-sendgrid/src/connector.rs | 97 ++-- crates/ndc-sendgrid/src/fields.rs | 93 ++++ crates/ndc-sendgrid/src/main.rs | 1 + crates/ndc-sendgrid/src/mutation.rs | 162 +----- crates/ndc-sendgrid/src/query.rs | 11 +- crates/ndc-sendgrid/src/schema.rs | 168 ++---- crates/ndc-sendgrid/src/sendgrid_api.rs | 2 - entrypoint.sh | 13 - 23 files changed, 722 insertions(+), 561 deletions(-) create mode 100644 .vscode/launch.json delete mode 100644 config.json create mode 100644 connector-definition/Makefile create mode 100644 connector-definition/connector-metadata.yaml create mode 100644 connector-definition/docker-compose.yaml create mode 100644 crates/ndc-sendgrid/src/fields.rs delete mode 100755 entrypoint.sh diff --git a/.editorconfig b/.editorconfig index bb53136..cd4872b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,4 +9,10 @@ indent_size = 4 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true -insert_final_newline = true \ No newline at end of file +insert_final_newline = true + +[Makefile] +indent_style = tab + +[*.{yaml,yml}] +indent_size = 2 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 9f10323..18af4e2 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -5,10 +5,10 @@ name: Create and publish a Docker image # Configures this workflow to run every time a change is pushed to selected tags and branches on: push: - branches: + branches: - main - test-ci/** - tags: + tags: - v** # Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. @@ -24,13 +24,12 @@ jobs: permissions: contents: read packages: write - # steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -38,16 +37,27 @@ jobs: # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. - name: Build and push Docker image - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + uses: docker/build-push-action@v5 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + - name: Build connector definition + run: | + set -e pipefail + export DOCKER_IMAGE=$(echo "$DOCKER_METADATA_OUTPUT_JSON" | jq -r '.tags[0]') + make build + working-directory: ./connector-definition + - uses: actions/upload-artifact@v4 + with: + name: connector-definition.tgz + path: ./connector-definition/dist/connector-definition.tgz + compression-level: 0 # Already compressed diff --git a/.gitignore b/.gitignore index 2f7896d..73b9c10 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ target/ +dist/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c77d985 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,30 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'ndc-sendgrid'", + "cargo": { + "args": [ + "build", + "--bin=ndc-sendgrid", + "--package=ndc-sendgrid" + ], + "filter": { + "name": "ndc-sendgrid", + "kind": "bin" + } + }, + "args": [ + "serve", + "--configuration", + "." + ], + "cwd": "${workspaceFolder}" + }, + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a39109..b9f8058 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ This changelog documents changes between release tags. Upcoming changes for the next versioned release. +## v0.3 + +* Updated with the latest NDC SDK version that supports NDC Spec v0.1.0-rc.16 +* send_mail procedure now takes the full send mail request type and uses nested objects ## v0.2 diff --git a/Cargo.lock b/Cargo.lock index 809efd6..2f283f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.5.0" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540" dependencies = [ "anstyle", "anstyle-parse", @@ -76,17 +76,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "anstyle-wincon" -version = "2.1.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -97,13 +97,13 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", ] [[package]] @@ -162,15 +162,24 @@ dependencies = [ ] [[package]] -name = "axum-macros" -version = "0.3.8" +name = "axum-extra" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62" +checksum = "4ab90e7b70bea63a153137162affb6a0bce26b584c24a4c7885509783e2cf30b" dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.36", + "axum", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "pin-project-lite", + "serde", + "tokio", + "tower", + "tower-layer", + "tower-service", ] [[package]] @@ -196,9 +205,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bit-set" @@ -233,12 +242,6 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "bytes" version = "1.5.0" @@ -270,14 +273,14 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] name = "clap" -version = "4.4.3" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" dependencies = [ "clap_builder", "clap_derive", @@ -285,33 +288,33 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.2" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.0", ] [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", ] [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" @@ -327,7 +330,7 @@ checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ "is-terminal", "lazy_static", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -365,14 +368,37 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -385,8 +411,19 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", - "syn 2.0.36", + "strsim 0.10.0", + "syn 2.0.49", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", ] [[package]] @@ -395,9 +432,9 @@ version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote", - "syn 2.0.36", + "syn 2.0.49", ] [[package]] @@ -444,7 +481,7 @@ checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -533,7 +570,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", ] [[package]] @@ -565,6 +602,19 @@ dependencies = [ "slab", ] +[[package]] +name = "gdc_rust_types" +version = "1.0.2" +source = "git+https://github.com/hasura/gdc_rust_types.git?rev=3273434#3273434068400f836cf12ea08c514505446821cb" +dependencies = [ + "indexmap 2.2.3", + "openapiv3", + "serde", + "serde-enum-str", + "serde_json", + "serde_with 3.6.1", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -609,9 +659,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" @@ -772,12 +822,13 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.3", + "serde", ] [[package]] @@ -794,7 +845,7 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -829,9 +880,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libm" @@ -909,13 +960,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -939,32 +990,39 @@ dependencies = [ [[package]] name = "ndc-client" version = "0.1.0" -source = "git+http://github.com/hasura/ndc-spec.git?tag=v0.1.0-rc.5#0842f61fc5e29d19994ff3439abb8d7eabc28449" +source = "git+http://github.com/hasura/ndc-spec.git?tag=v0.1.0-rc.16#608ecc4b6719753c186a37494bbe95ae26e64f45" dependencies = [ "async-trait", - "indexmap 1.9.3", + "indexmap 2.2.3", "opentelemetry", "reqwest", "schemars", "serde", "serde_derive", "serde_json", - "serde_with", + "serde_with 2.3.3", "url", ] [[package]] name = "ndc-sdk" version = "0.1.0" -source = "git+https://github.com/hasura/ndc-hub.git?rev=abfc255#abfc25587a81e28dab76b66a7b0bc34a38b368f3" +source = "git+https://github.com/hasura/ndc-hub.git?rev=660750a#660750a08e96d05535649ab1476746e4c2fd9437" dependencies = [ "async-trait", "axum", - "axum-macros", + "axum-extra", + "base64 0.21.7", + "bytes", "clap", + "gdc_rust_types", + "http", + "indexmap 2.2.3", + "mime", "ndc-client", "ndc-test", "opentelemetry", + "opentelemetry-http", "opentelemetry-otlp", "opentelemetry-semantic-conventions", "opentelemetry_api", @@ -981,7 +1039,6 @@ dependencies = [ "tracing-opentelemetry", "tracing-subscriber", "url", - "uuid", ] [[package]] @@ -989,7 +1046,7 @@ name = "ndc-sendgrid" version = "0.1.0" dependencies = [ "async-trait", - "indexmap 1.9.3", + "indexmap 2.2.3", "ndc-sdk", "prometheus", "reqwest", @@ -1003,16 +1060,17 @@ dependencies = [ [[package]] name = "ndc-test" version = "0.1.0" -source = "git+http://github.com/hasura/ndc-spec.git?tag=v0.1.0-rc.5#0842f61fc5e29d19994ff3439abb8d7eabc28449" +source = "git+http://github.com/hasura/ndc-spec.git?tag=v0.1.0-rc.16#608ecc4b6719753c186a37494bbe95ae26e64f45" dependencies = [ "async-trait", "clap", "colored", - "indexmap 1.9.3", + "indexmap 2.2.3", "ndc-client", "proptest", "reqwest", "semver", + "serde", "serde_json", "thiserror", "tokio", @@ -1063,6 +1121,17 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "openapiv3" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b83630305ecc3355e998ddd2f926f98aae8e105eb42652174a58757851ba47" +dependencies = [ + "indexmap 1.9.3", + "serde", + "serde_json", +] + [[package]] name = "openssl" version = "0.10.57" @@ -1086,7 +1155,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", ] [[package]] @@ -1246,7 +1315,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1272,7 +1341,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", ] [[package]] @@ -1301,9 +1370,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -1325,19 +1394,19 @@ dependencies = [ [[package]] name = "proptest" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bit-set", - "bitflags 1.3.2", - "byteorder", + "bit-vec", + "bitflags 2.4.0", "lazy_static", "num-traits", "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.6.29", + "regex-syntax 0.8.2", "rusty-fork", "tempfile", "unarray", @@ -1380,9 +1449,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1479,13 +1548,19 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -1504,9 +1579,12 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -1533,7 +1611,16 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", ] [[package]] @@ -1566,17 +1653,18 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "schemars" -version = "0.8.13" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" dependencies = [ "dyn-clone", "indexmap 1.9.3", + "indexmap 2.2.3", "schemars_derive", "serde", "serde_json", @@ -1585,9 +1673,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.13" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" dependencies = [ "proc-macro2", "quote", @@ -1626,28 +1714,58 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] +[[package]] +name = "serde-attributes" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eb8ec7724e4e524b2492b510e66957fe1a2c76c26a6975ec80823f2439da685" +dependencies = [ + "darling_core 0.14.4", + "serde-rename-rule", + "syn 1.0.109", +] + +[[package]] +name = "serde-enum-str" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26416dc95fcd46b0e4b12a3758043a229a6914050aaec2e8191949753ed4e9aa" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "serde-attributes", + "syn 1.0.109", +] + +[[package]] +name = "serde-rename-rule" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794e44574226fc701e3be5c651feb7939038fc67fb73f6f4dd5c4ba90fd3be70" + [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", ] [[package]] @@ -1663,11 +1781,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.2.3", "itoa", "ryu", "serde", @@ -1707,7 +1825,25 @@ dependencies = [ "indexmap 1.9.3", "serde", "serde_json", - "serde_with_macros", + "serde_with_macros 2.3.3", + "time", +] + +[[package]] +name = "serde_with" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" +dependencies = [ + "base64 0.21.7", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.2.3", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros 3.6.1", "time", ] @@ -1717,10 +1853,22 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", +] + +[[package]] +name = "serde_with_macros" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d" +dependencies = [ + "darling 0.20.3", + "proc-macro2", + "quote", + "syn 2.0.49", ] [[package]] @@ -1777,12 +1925,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1791,6 +1939,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "syn" version = "1.0.109" @@ -1804,9 +1958,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.36" +version = "2.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e02e55d62894af2a08aca894c6577281f76769ba47c94d5756bec8ac6e7373" +checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" dependencies = [ "proc-macro2", "quote", @@ -1819,6 +1973,27 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" version = "3.8.0" @@ -1829,27 +2004,27 @@ dependencies = [ "fastrand", "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", ] [[package]] @@ -1907,9 +2082,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.32.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", @@ -1919,9 +2094,9 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.4", + "socket2 0.5.5", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1936,13 +2111,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", ] [[package]] @@ -1988,7 +2163,7 @@ checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" dependencies = [ "async-trait", "axum", - "base64 0.21.4", + "base64 0.21.7", "bytes", "futures-core", "futures-util", @@ -2062,11 +2237,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -2075,20 +2249,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -2213,12 +2387,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" -[[package]] -name = "uuid" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" - [[package]] name = "valuable" version = "0.1.0" @@ -2282,7 +2450,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", "wasm-bindgen-shared", ] @@ -2316,7 +2484,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.49", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2365,7 +2533,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -2374,7 +2542,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -2383,13 +2560,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -2398,42 +2590,84 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winreg" version = "0.50.0" @@ -2441,5 +2675,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] diff --git a/Cargo.toml b/Cargo.toml index 149cec9..d72dad1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ version = "0.1.0" [workspace] +resolver = "2" members = [ "crates/ndc-sendgrid", ] diff --git a/Dockerfile b/Dockerfile index d6f2022..eda8f6a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.72-slim-buster AS build +FROM rust:1.76-slim-buster AS build WORKDIR /app @@ -10,20 +10,24 @@ RUN apt-get update \ ENV RUSTFLAGS="-C link-arg=-fuse-ld=lld" COPY ./crates ./crates -COPY ./Cargo.lock ./Cargo.lock +COPY ./Cargo.lock ./Cargo.lock COPY ./Cargo.toml ./Cargo.toml RUN cargo build --release --all-targets -FROM debian:buster-slim as ndc-deno -WORKDIR /app -COPY --from=build /app/target/release/ndc-sendgrid ./ndc-sendgrid + +FROM debian:buster-slim as ndc-sendgrid + RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive \ apt-get install --no-install-recommends --assume-yes \ libssl-dev ca-certificates -COPY ./entrypoint.sh ./entrypoint.sh +WORKDIR /app +COPY --from=build /app/target/release/ndc-sendgrid ./ndc-sendgrid + +RUN mkdir -p /etc/connector +ENV HASURA_CONFIGURATION_DIRECTORY=/etc/connector -ENTRYPOINT [ "./entrypoint.sh", "./ndc-sendgrid"] -CMD ["serve", "--configuration", "/etc/connector/config.json", "--port", "8080"] +ENTRYPOINT ["./ndc-sendgrid"] +CMD ["serve"] diff --git a/README.md b/README.md index a97e49c..4bd70dc 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # SendGrid Connector +> [!WARNING] +> This connector has been updated to support the Hasura DDN Beta, and will not work with the Alpha. + The SendGrid Native Data Connector allows for connecting to the SendGrid v3 API and exposing its functionality from your Hasura API. -While this is a functional implementation of the SendGrid API, -it also serves as a minimal example of an "Action" style connector using the -[Rust Data Connector SDK](https://github.com/hasura/ndc-hub#rusk-sdk). +While this is a functional implementation of the SendGrid API, it also serves as a minimal example of an "Action" style connector using the [Rust Data Connector SDK](https://github.com/hasura/ndc-hub#rusk-sdk). * [SendGrid Connector information in the Hasura Connectors directory](https://hasura.io/connectors/sendgrid) * [Hasura V3 Documentation](https://hasura.io/docs/3.0) @@ -25,37 +26,7 @@ This connector is a minimal implementation of the SendGrid v3 API functions: It also serves as an example of how an `Action` style connector can be implemented in Hasura V3. ## For Hasura Users - -If you wish to use this connector with your Hasura projects, the best instructions can be found on the [Hasura Hub SendGrid Connector listing](https://hasura.io/connectors/sendgrid). - -The following steps will allow you to deploy the connector and use it in a Hasura V3 project: - -* Create a Hasura V3 Project (or use an existing project) -* Ensure that you have a metadata definition -* Create a configuration for the SendGrid Connector referencing your credentials: - `sendgrid.connector.configuration.json` - ``` - {"version": 1, "sendgrid_api_key": "YOUR-API-KEY-HERE" } - ``` -* Run the following command to deploy the connector -* Ensure you are logged in to Hasura CLI - ``` - hasura3 cloud login --pat 'YOUR-HASURA-TOKEN' - ``` -* Deploy the connector - ``` - hasura3 connector create sendgrid:v1 \ - --github-repo-url https://github.com/hasura/ndc-sendgrid/tree/main \ - --config-file ./sendgrid.connector.configuration.json - ``` -* Ensure that your deployed connector is referenced from your metadata with the service token -* Edit your metadata using the LSP support to import the defined schema, functions, procedures -* Deploy or update your Hasura cloud project - ``` - hasura3 cloud build create --project-id my-project-id --metadata-file metadata.hml - ``` -* View in your cloud console, access via the graphql API - +TBD ## For Developers @@ -71,7 +42,7 @@ Commands: ``` cargo build -cargo run serve --configuration <(echo '{"version": 1, "sendgrid_api_key":"YOUR-API-KEY-HERE"}') +SENDGRID_API_KEY="YOUR-API-KEY-HERE" cargo run -- serve --configuration . ``` ### Docker @@ -80,5 +51,5 @@ The `Dockerfile` is used by the `connector create` command and can be tested as ``` docker build . --tag ndc-sendgrid -docker run -it --v ./sendgrid.connector.configuration.json:/config.json ndc-sendgrid +docker run -it -e SENDGRID_API_KEY="YOUR-API-KEY-HERE" ndc-sendgrid ``` diff --git a/config.json b/config.json deleted file mode 100644 index 263ea76..0000000 --- a/config.json +++ /dev/null @@ -1 +0,0 @@ -REPLACE ME diff --git a/connector-definition/Makefile b/connector-definition/Makefile new file mode 100644 index 0000000..413cb15 --- /dev/null +++ b/connector-definition/Makefile @@ -0,0 +1,21 @@ +.DEFAULT_GOAL := build +SHELL = /usr/bin/env bash + +.PHONY: build +build: dist/connector-definition.tgz + +.PHONY: clean +clean: + rm -rf dist + +dist dist/.hasura-connector: + mkdir dist + mkdir dist/.hasura-connector + +dist/.hasura-connector/connector-metadata.yaml: DOCKER_IMAGE ?= $(error The DOCKER_IMAGE variable must be defined) +dist/.hasura-connector/connector-metadata.yaml: connector-metadata.yaml dist/.hasura-connector + cp -f connector-metadata.yaml dist/.hasura-connector/ + yq -i '.packagingDefinition.dockerImage = "$(DOCKER_IMAGE)"' dist/.hasura-connector/connector-metadata.yaml + +dist/connector-definition.tgz: dist/.hasura-connector/connector-metadata.yaml + shopt -s dotglob && cd dist && tar -czvf connector-definition.tgz * diff --git a/connector-definition/connector-metadata.yaml b/connector-definition/connector-metadata.yaml new file mode 100644 index 0000000..7e0fb96 --- /dev/null +++ b/connector-definition/connector-metadata.yaml @@ -0,0 +1,11 @@ +packagingDefinition: + type: PrebuiltDockerImage + dockerImage: +supportedEnvironmentVariables: + - name: SENDGRID_API_KEY + description: The SendGrid API key to use +commands: {} +dockerComposeWatch: + - path: ./ + target: /etc/connector + action: sync+restart diff --git a/connector-definition/docker-compose.yaml b/connector-definition/docker-compose.yaml new file mode 100644 index 0000000..f14d8f9 --- /dev/null +++ b/connector-definition/docker-compose.yaml @@ -0,0 +1,7 @@ +services: + connector: + develop: + watch: + - path: ./ + target: /etc/connector + action: sync+restart diff --git a/crates/ndc-sendgrid/Cargo.toml b/crates/ndc-sendgrid/Cargo.toml index 9f21294..fdcfa5a 100644 --- a/crates/ndc-sendgrid/Cargo.toml +++ b/crates/ndc-sendgrid/Cargo.toml @@ -7,14 +7,14 @@ edition = "2021" [dependencies] # ndc-client = { git = "https://github.com/hasura/ndc-spec.git", tag = "v0.1.0-rc.4" } -ndc-sdk = { git = "https://github.com/hasura/ndc-hub.git", rev = "abfc255", package = "ndc-sdk" } +ndc-sdk = { git = "https://github.com/hasura/ndc-hub.git", rev = "660750a", package = "ndc-sdk" } async-trait = "0.1" prometheus = { version = "0.13" } -schemars = { version = "0.8", features = ["smol_str"] } +schemars = { version = "0.8.16", features = ["smol_str"] } serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } tokio = { version = "1", features = ["full"] } reqwest = { version = "0.11.19" } -indexmap = "^1" +indexmap = "^2" thiserror = { version = "*" } # Use the version from ndc-sdk diff --git a/crates/ndc-sendgrid/src/configuration.rs b/crates/ndc-sendgrid/src/configuration.rs index dff87b0..7901b9f 100644 --- a/crates/ndc-sendgrid/src/configuration.rs +++ b/crates/ndc-sendgrid/src/configuration.rs @@ -1,40 +1,21 @@ +use std::{env, path::Path}; use ndc_sdk::connector::{self, InvalidRange, KeyOrIndex}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use super::sendgrid_api::{ApiKeyError, SendGridApiKey}; -const CURRENT_VERSION: u32 = 1; - -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -pub struct RawSendGridConfiguration { - pub version: u32, - pub sendgrid_api_key: Option, -} - -impl Default for RawSendGridConfiguration { - fn default() -> RawSendGridConfiguration { - RawSendGridConfiguration { - version: CURRENT_VERSION, - sendgrid_api_key: None, - } - } -} - #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] pub struct SendGridConfiguration { pub sendgrid_api_key: SendGridApiKey, } -pub fn validate_raw_configuration( - raw_configuration: &RawSendGridConfiguration, +pub fn parse_configuration( + _configuration_dir: impl AsRef + Send ) -> Result { - if raw_configuration.version != CURRENT_VERSION { - return Err(mk_single_error("version", "Unknown configuration version")); - } - match &raw_configuration.sendgrid_api_key { - Some(key) => SendGridApiKey::new(key) + match env::var("SENDGRID_API_KEY") { + Ok(key) => SendGridApiKey::new(key.as_str()) .map(|api_key| SendGridConfiguration { sendgrid_api_key: api_key, }) @@ -43,9 +24,13 @@ pub fn validate_raw_configuration( mk_single_error("sendgrid_api_key", "sendgrid_api_key cannot be blank") } }), - None => Err(mk_single_error( - "sendgrid_api_key", - "sendgrid_api_key is required", + Err(env::VarError::NotPresent) => Err(mk_single_error( + "SENDGRID_API_KEY", + "The SENDGRID_API_KEY environment variable is required", + )), + Err(env::VarError::NotUnicode(_)) => Err(mk_single_error( + "SENDGRID_API_KEY", + "The SENDGRID_API_KEY environment variable value is not valid unicode", )), } } diff --git a/crates/ndc-sendgrid/src/connector.rs b/crates/ndc-sendgrid/src/connector.rs index f98295f..8800dff 100644 --- a/crates/ndc-sendgrid/src/connector.rs +++ b/crates/ndc-sendgrid/src/connector.rs @@ -1,5 +1,7 @@ +use std::path::Path; use async_trait::async_trait; use ndc_sdk::connector; +use ndc_sdk::json_response::JsonResponse; use ndc_sdk::models; use super::configuration; @@ -17,39 +19,17 @@ pub struct SendGridConnectorState { #[async_trait] impl connector::Connector for SendGridConnector { - /// RawConfiguration is what the user specifies as JSON - type RawConfiguration = configuration::RawSendGridConfiguration; /// The type of validated configuration type Configuration = configuration::SendGridConfiguration; /// The type of unserializable state type State = SendGridConnectorState; - fn make_empty_configuration() -> configuration::RawSendGridConfiguration { - configuration::RawSendGridConfiguration::default() - } - - fn get_read_regions(_conf: &Self::Configuration) -> std::vec::Vec { - vec!() - } - - fn get_write_regions(_conf: &Self::Configuration) -> std::vec::Vec { - vec!() - } - - /// Configure a configuration maybe? - async fn update_configuration( - args: &configuration::RawSendGridConfiguration, - ) -> Result { - Ok(args.clone()) - } - /// Validate the raw configuration provided by the user, /// returning a configuration error or a validated [`Connector::Configuration`]. - async fn validate_raw_configuration( - configuration: &configuration::RawSendGridConfiguration, - _regions: &std::collections::BTreeMap > + async fn parse_configuration( + configuration_dir: impl AsRef + Send, ) -> Result { - configuration::validate_raw_configuration(configuration) + configuration::parse_configuration(configuration_dir) } /// Initialize the connector's in-memory state. @@ -95,23 +75,24 @@ impl connector::Connector for SendGridConnector { /// /// This function implements the [capabilities endpoint](https://hasura.github.io/ndc-spec/specification/capabilities.html) /// from the NDC specification. - async fn get_capabilities() -> models::CapabilitiesResponse { - models::CapabilitiesResponse { - versions: String::from("^0.1.0"), - capabilities: models::Capabilities { - query: Some(models::QueryCapabilities { - relation_comparisons: None, - order_by_aggregate: None, - foreach: None, - }), - explain: None, - relationships: None, - mutations: Some(models::MutationCapabilities { - nested_inserts: None, - returning: None, - }), - }, - } + async fn get_capabilities() -> JsonResponse { + JsonResponse::Value( + models::CapabilitiesResponse { + version: String::from("0.1.0"), + capabilities: models::Capabilities { + query: models::QueryCapabilities { + aggregates: None, + variables: None, + explain: None, + }, + relationships: None, + mutation: models::MutationCapabilities { + transactional: None, + explain: None + }, + }, + } + ) } /// Get the connector's schema. @@ -120,20 +101,32 @@ impl connector::Connector for SendGridConnector { /// from the NDC specification. async fn get_schema( _configuation: &configuration::SendGridConfiguration, - ) -> Result { - Ok(schema::make_schema_response()) + ) -> Result, connector::SchemaError> { + Ok(JsonResponse::Value(schema::make_schema_response())) } /// Explain a query by creating an execution plan /// - /// This function implements the [explain endpoint](https://hasura.github.io/ndc-spec/specification/explain.html) + /// This function implements the [query/explain endpoint](https://hasura.github.io/ndc-spec/specification/explain.html) /// from the NDC specification. - async fn explain( + async fn query_explain( _configuration: &configuration::SendGridConfiguration, _state: &SendGridConnectorState, _query_request: models::QueryRequest, - ) -> Result { - Err(connector::ExplainError::UnsupportedOperation(String::from("explain is not supported"))) + ) -> Result, connector::ExplainError> { + Err(connector::ExplainError::UnsupportedOperation(String::from("query explain is not supported"))) + } + + /// Explain a mutation by creating an execution plan + /// + /// This function implements the [mutation/explain endpoint](https://hasura.github.io/ndc-spec/specification/explain.html) + /// from the NDC specification. + async fn mutation_explain( + _configuration: &Self::Configuration, + _state: &Self::State, + _request: models::MutationRequest, + ) -> Result, connector::ExplainError> { + Err(connector::ExplainError::UnsupportedOperation(String::from("mutation explain is not supported"))) } /// Execute a mutation @@ -144,8 +137,8 @@ impl connector::Connector for SendGridConnector { configuration: &configuration::SendGridConfiguration, state: &SendGridConnectorState, request: models::MutationRequest, - ) -> Result { - mutation::execute(&state.http_client, configuration, request).await + ) -> Result, connector::MutationError> { + mutation::execute(&state.http_client, configuration, request).await.map(JsonResponse::Value) } /// Execute a query @@ -156,7 +149,7 @@ impl connector::Connector for SendGridConnector { configuration: &configuration::SendGridConfiguration, state: &SendGridConnectorState, query_request: models::QueryRequest, - ) -> Result { - query::execute(&state.http_client, configuration, query_request).await + ) -> Result, connector::QueryError> { + query::execute(&state.http_client, configuration, query_request).await.map(JsonResponse::Value) } } diff --git a/crates/ndc-sendgrid/src/fields.rs b/crates/ndc-sendgrid/src/fields.rs new file mode 100644 index 0000000..09464f8 --- /dev/null +++ b/crates/ndc-sendgrid/src/fields.rs @@ -0,0 +1,93 @@ +use thiserror::Error; +use indexmap::IndexMap; +use ndc_sdk::{connector, models}; + +#[derive(Debug, Error)] +pub enum FieldsError { + /// The request was invalid or did not match the + /// requirements of the specification. This indicates + /// an error with the client. + #[error("invalid request: {0}")] + InvalidRequest(String), + #[error("unsupported operation: {0}")] + UnsupportedOperation(String), +} + +impl From for connector::QueryError { + fn from(value: FieldsError) -> Self { + match value { + FieldsError::InvalidRequest(err) => connector::QueryError::InvalidRequest(err), + FieldsError::UnsupportedOperation(err) => connector::QueryError::UnsupportedOperation(err) + } + } +} + +impl From for connector::MutationError { + fn from(value: FieldsError) -> Self { + match value { + FieldsError::InvalidRequest(err) => connector::MutationError::InvalidRequest(err), + FieldsError::UnsupportedOperation(err) => connector::MutationError::UnsupportedOperation(err) + } + } +} + +pub fn eval_row( + fields: &IndexMap, + item: &IndexMap, +) -> Result, FieldsError> { + let mut row = IndexMap::new(); + for (field_name, field) in fields.iter() { + row.insert( + field_name.clone(), + eval_field(field, item)?, + ); + } + Ok(row) +} + +fn eval_field( + field: &models::Field, + item: &IndexMap, +) -> Result { + match field { + models::Field::Column { column, fields } => { + let col_val = eval_column(item, column.as_str())?; + match fields { + None => Ok(models::RowFieldValue(col_val)), + Some(nested_field) => eval_nested_field( + col_val, + nested_field, + ), + } + } + models::Field::Relationship { .. } => { + Err(FieldsError::UnsupportedOperation("Relationship fields are not supported".into())) + } + } +} + +fn eval_column(row: &IndexMap, column_name: &str) -> Result { + row.get(column_name).cloned() + .ok_or(FieldsError::InvalidRequest(format!("invalid column name: {}", column_name))) +} + +pub fn eval_nested_field( + value: serde_json::Value, + nested_field: &models::NestedField, +) -> Result { + match nested_field { + models::NestedField::Object(models::NestedObject { fields }) => { + let full_row: IndexMap = serde_json::from_value(value).map_err(|_| FieldsError::InvalidRequest("Object expected".into()))?; + let row = eval_row(fields, &full_row)?; + Ok(models::RowFieldValue(serde_json::to_value(row).map_err(|_| FieldsError::InvalidRequest("Cannot encode rowset".into()))?)) + } + models::NestedField::Array(models::NestedArray { fields }) => { + let array: Vec = serde_json::from_value(value).map_err(|_| FieldsError::InvalidRequest("Array expected".into()))?; + let result_array = array + .into_iter() + .map(|value| eval_nested_field(value, fields)) + .collect::, FieldsError>>()?; + Ok(models::RowFieldValue(serde_json::to_value(result_array).map_err(|_| FieldsError::InvalidRequest("Cannot encode rowset".into()))?)) + } + } +} diff --git a/crates/ndc-sendgrid/src/main.rs b/crates/ndc-sendgrid/src/main.rs index 4be17b5..ba6f9ce 100644 --- a/crates/ndc-sendgrid/src/main.rs +++ b/crates/ndc-sendgrid/src/main.rs @@ -1,6 +1,7 @@ mod configuration; mod connector; mod schema; +mod fields; mod mutation; mod query; mod sendgrid_api; diff --git a/crates/ndc-sendgrid/src/mutation.rs b/crates/ndc-sendgrid/src/mutation.rs index 764ff87..b6556bd 100644 --- a/crates/ndc-sendgrid/src/mutation.rs +++ b/crates/ndc-sendgrid/src/mutation.rs @@ -1,14 +1,12 @@ -use indexmap::IndexMap; use ndc_sdk::connector::MutationError; use ndc_sdk::models::{ - Field, MutationOperation, MutationOperationResults, MutationRequest, MutationResponse, - RowFieldValue, + MutationOperation, MutationOperationResults, MutationRequest, MutationResponse, NestedField }; use serde_json::Value; use std::collections::BTreeMap; +use crate::fields::eval_nested_field; use crate::schema::SEND_MAIL; -use crate::sendgrid_api::{SimpleSendMailRequest, MailAddress, MailContent, MailPersonalization}; use super::configuration; use super::schema; @@ -47,44 +45,6 @@ async fn process_operation( "Unknown procedure: {unknown_procedure}" ))), }, - MutationOperation::Insert { .. } => Err(MutationError::UnsupportedOperation(String::from( - "Insert mutations currently not supported", - ))), - MutationOperation::Update { .. } => Err(MutationError::UnsupportedOperation(String::from( - "Update mutations currently not supported", - ))), - MutationOperation::Delete { .. } => Err(MutationError::UnsupportedOperation(String::from( - "Delete mutations currently not supported", - ))), - } -} - -fn complicate_request(simple_request: SimpleSendMailRequest) -> sendgrid_api::SendMailRequest { - - let personalization = MailPersonalization { - from: Some(simple_request.from.clone()), - to: vec!(simple_request.to), - cc: simple_request.cc.map(|x| vec!(x)), - bcc: simple_request.bcc.map(|x| vec!(x)), - subject: Some(simple_request.subject.clone()), - headers: None, - substitutions: None, - dynamic_template_data: None, - send_at: simple_request.send_at - }; - - sendgrid_api::SendMailRequest { - personalizations: vec!(personalization), - from: simple_request.from, - reply_to_list: vec!(), - subject: simple_request.subject, - content: vec!(simple_request.content), - attachments: simple_request.attachment.map(|a| vec!(a)), - template_id: simple_request.template_id, - headers: None, - send_at: simple_request.send_at, - batch_id: simple_request.batch_id, - asm: simple_request.asm } } @@ -92,121 +52,35 @@ async fn process_send_mail( http_client: &reqwest::Client, configuration: &configuration::SendGridConfiguration, arguments: BTreeMap, - fields: Option>, + fields: Option, ) -> Result { - let simple_request = parse_simple_send_mail_args(&arguments)?; - let request = complicate_request(simple_request); + let request = parse_send_mail_args(&arguments)?; sendgrid_api::invoke_send_mail(http_client, &configuration.sendgrid_api_key, &request) .await .map_err(|err| MutationError::Other(Box::new(err)))?; - let mut row = IndexMap::new(); - - if let Some(fields) = fields { - for (field_name, field) in fields { - match field { - Field::Column { column } => { - let field_value = match column.as_str() { - "batch_id" => RowFieldValue( - request - .batch_id - .clone() - .map_or(Value::Null, |id| Value::String(id)), - ), - other_column => { - return Err(MutationError::InvalidRequest(format!( - "Unknown column {other_column}" - ))) - } - }; - row.insert(field_name, field_value); - } - Field::Relationship { relationship, .. } => { - return Err(MutationError::InvalidRequest(format!( - "Unexpected relationship {relationship} in field {field_name}" - ))) - } - } - } - } - - Ok(MutationOperationResults { - affected_rows: 1, - returning: Some(vec![row]), - }) -} + let batch_id_value = request + .batch_id + .clone() + .map_or(Value::Null, |id| Value::String(id)); + let result_value = Value::Object(serde_json::Map::from_iter([("batch_id".to_string(), batch_id_value)])); -fn invalid_arg(err: &str) -> MutationError { - MutationError::InvalidRequest(format!("Couldn't find '{err}' field in arguments")) -} - -fn invalid_deserialize(arg: &str, err: serde_json::Error) -> MutationError { - MutationError::InvalidRequest(format!("Unable to deserialize argument '{arg}': {err}")) -} - -fn parse_simple_send_mail_args( - in_args: &BTreeMap, -) -> Result { - - let args_to = in_args.get("to").ok_or(invalid_arg("request"))?; - let args_cc = in_args.get("cc"); - let args_bcc = in_args.get("bcc"); - let args_from = in_args.get("from").ok_or(invalid_arg("from"))?; - let args_reply_to = in_args.get("reply_to"); - let args_subject = in_args.get("subject").ok_or(invalid_arg("subject"))?; - let args_content = in_args.get("content").ok_or(invalid_arg("content"))?; - let args_content_type = in_args.get("content_type").ok_or(invalid_arg("content_type"))?; - let args_attachment = in_args.get("attachment"); - let args_template_id = in_args.get("template_id"); - let args_send_at = in_args.get("send_at"); - let args_batch_id = in_args.get("batch_id"); - let args_asm = in_args.get("asm"); - - let to = serde_json::from_value(args_to.clone()).map_err(|err| invalid_deserialize("to", err))?; - let cc = args_cc.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("cc", err))).unwrap_or(Ok(None))?; - let bcc = args_bcc.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("bcc", err))).unwrap_or(Ok(None))?; - let from = serde_json::from_value(args_from.clone()).map_err(|err| invalid_deserialize("from", err))?; - let reply_to = args_reply_to.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("reply_to", err))).unwrap_or(Ok(None))?; - let subject = serde_json::from_value(args_subject.clone()).map_err(|err| invalid_deserialize("subject", err))?; - let content = serde_json::from_value(args_content.clone()).map_err(|err| invalid_deserialize("content", err))?; - let content_type = serde_json::from_value(args_content_type.clone()).map_err(|err| invalid_deserialize("content", err))?; - let attachment = args_attachment.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("attachment", err))).unwrap_or(Ok(None))?; - let template_id = args_template_id.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("template_id", err))).unwrap_or(Ok(None))?; - let send_at = args_send_at.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("send_at", err))).unwrap_or(Ok(None))?; - let batch_id = args_batch_id.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("batch_id", err))).unwrap_or(Ok(None))?; - let asm = args_asm.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("asm", err))).unwrap_or(Ok(None))?; - - let request = sendgrid_api::SimpleSendMailRequest { - to: MailAddress { email: to, name: None }, - cc: cc.map(|x| MailAddress { email: x, name: None }), - bcc: bcc.map(|x| MailAddress { email: x, name: None }), - from: MailAddress { email: from, name: None }, - reply_to: reply_to.map(|x| MailAddress { email: x, name: None }), - subject, - content: MailContent { r#type: content_type, value: content }, - attachment, - template_id, - send_at, - batch_id, - asm, + let projected_result_value = match fields { + Some(fields) => eval_nested_field(result_value, &fields)?.0, + None => result_value }; - Ok(request) + + Ok(MutationOperationResults::Procedure { result: projected_result_value }) } -fn _parse_send_mail_args( +fn parse_send_mail_args( in_args: &BTreeMap, ) -> Result { - let args_request = - in_args - .get("request") - .ok_or(MutationError::InvalidRequest(String::from( - "Couldn't find 'request' field in arguments", - )))?; - - let schema_request = serde_json::from_value::(args_request.clone()) + let args_request = serde_json::Value::Object(serde_json::Map::from_iter(in_args.clone())); + let schema_request = serde_json::from_value::(args_request) .map_err(|err| { - MutationError::InvalidRequest(format!("Unable to deserialize 'request': {err}")) + MutationError::InvalidRequest(format!("Unable to deserialize arguments: {err}")) })?; let request = sendgrid_api::SendMailRequest { diff --git a/crates/ndc-sendgrid/src/query.rs b/crates/ndc-sendgrid/src/query.rs index e977d89..6d60504 100644 --- a/crates/ndc-sendgrid/src/query.rs +++ b/crates/ndc-sendgrid/src/query.rs @@ -2,9 +2,11 @@ use std::collections::BTreeMap; use indexmap::IndexMap; use ndc_sdk::{ connector::QueryError, - models::{Argument, QueryRequest, QueryResponse, RowFieldValue, RowSet}, + models::{Argument, QueryRequest, QueryResponse, RowSet}, }; +use crate::fields::eval_row; + use super::configuration; use super::schema::LIST_TEMPLATES_FUNCTION_NAME; use super::sendgrid_api::{invoke_list_function_templates, ListTransactionalTemplatesParams}; @@ -70,10 +72,11 @@ pub async fn execute( Ok(list_response) => { let result = serde_json::to_value(list_response.result) .map_err(|err| QueryError::Other(Box::new(err)))?; - let response_row = - IndexMap::from([(String::from("__value"), RowFieldValue(result))]); + let result_row = + IndexMap::from([(String::from("__value"), result)]); + let projected_row = query_request.query.fields.map(|fields| eval_row(&fields, &result_row)).transpose()?; Ok(QueryResponse(vec![RowSet { - rows: Some(vec![response_row]), + rows: projected_row.map(|row| vec![row]), aggregates: None, }])) } diff --git a/crates/ndc-sendgrid/src/schema.rs b/crates/ndc-sendgrid/src/schema.rs index 0673796..0f8549f 100644 --- a/crates/ndc-sendgrid/src/schema.rs +++ b/crates/ndc-sendgrid/src/schema.rs @@ -18,7 +18,6 @@ pub fn make_schema_response() -> SchemaResponse { object_types: BTreeMap::from([ (String::from("list_template_item"), list_template_item()), (String::from("list_template_version"), list_template_version()), - (String::from("send_mail_request"), send_mail_request()), (String::from("mail_personalization"), mail_personalization()), (String::from("mail_address"), mail_address()), (String::from("header"), header()), @@ -40,19 +39,16 @@ pub fn make_schema_response() -> SchemaResponse { const STRING_SCALAR_TYPE: ScalarType = ScalarType { aggregate_functions: BTreeMap::new(), comparison_operators: BTreeMap::new(), - update_operators: BTreeMap::new(), }; const INT_SCALAR_TYPE: ScalarType = ScalarType { aggregate_functions: BTreeMap::new(), comparison_operators: BTreeMap::new(), - update_operators: BTreeMap::new(), }; const BOOL_SCALAR_TYPE: ScalarType = ScalarType { aggregate_functions: BTreeMap::new(), comparison_operators: BTreeMap::new(), - update_operators: BTreeMap::new(), }; fn list_template_item() -> ObjectType { @@ -196,56 +192,53 @@ pub struct SendMailRequest { pub asm: Option, } -fn send_mail_request() -> ObjectType { - ObjectType { - description: Some(String::from("The request properties for sending mail")), - fields: BTreeMap::from([ - (String::from("personalizations"), ObjectField { - r#type: array_of(named("mail_personalization")), - description: Some(String::from("An array of messages and their metadata. Each object within personalizations can be thought of as an envelope - it defines who should receive an individual message and how that message should be handled.")) - }), - (String::from("from"), ObjectField { - r#type: named("mail_address"), - description: Some(String::from("The 'From' email address used to deliver the message. This address should be a verified sender in your Twilio SendGrid account.")) - }), - (String::from("reply_to_list"), ObjectField { - r#type: array_of(named("mail_address")), - description: Some(String::from("An array of recipients who will receive replies.")) - }), - (String::from("subject"), ObjectField { - r#type: named("String"), - description: Some(String::from("The global or 'message level' subject of your email. This may be overridden by subject lines set in personalizations.")) - }), - (String::from("content"), ObjectField { - r#type: array_of(named("mail_content")), - description: Some(String::from("An array where you can specify the content of your email. You can include multiple MIME types of content, but you must specify at least one MIME type.")) - }), - (String::from("attachments"), ObjectField { - r#type: nullable(array_of(named("mail_attachment"))), - description: Some(String::from("An array of objects where you can specify any attachments you want to include.")) - }), - (String::from("template_id"), ObjectField { - r#type: nullable(named("Bool")), - description: Some(String::from("An email template ID. A template that contains a subject and content — either text or html — will override any subject and content values specified at the personalizations or message level.")) - }), - (String::from("headers"), ObjectField { - r#type: nullable(array_of(named("header"))), - description: Some(String::from("The headers to put on the mail. You must ensure these are properly encoded if they contain unicode characters. These headers cannot be one of the reserved headers.")) - }), - (String::from("send_at"), ObjectField { - r#type: nullable(named("Int")), - description: Some(String::from("A unix timestamp allowing you to specify when you want your email to be delivered. This may be overridden by the send_at parameter set at the personalizations level. Delivery cannot be scheduled more than 72 hours in advance.")) - }), - (String::from("batch_id"), ObjectField { - r#type: nullable(named("String")), - description: Some(String::from("An ID representing a batch of emails to be sent at the same time. Including a batch_id in your request allows you include this email in that batch. It also enables you to cancel or pause the delivery of that batch.")) - }), - (String::from("asm"), ObjectField { - r#type: nullable(named("unsubscription_settings")), - description: Some(String::from("An object allowing you to specify how to handle unsubscribes.")) - }), - ]), - } +fn send_mail_request_args() -> BTreeMap { + BTreeMap::from([ + (String::from("personalizations"), ArgumentInfo { + argument_type: array_of(named("mail_personalization")), + description: Some(String::from("An array of messages and their metadata. Each object within personalizations can be thought of as an envelope - it defines who should receive an individual message and how that message should be handled.")) + }), + (String::from("from"), ArgumentInfo { + argument_type: named("mail_address"), + description: Some(String::from("The 'From' email address used to deliver the message. This address should be a verified sender in your Twilio SendGrid account.")) + }), + (String::from("reply_to_list"), ArgumentInfo { + argument_type: array_of(named("mail_address")), + description: Some(String::from("An array of recipients who will receive replies.")) + }), + (String::from("subject"), ArgumentInfo { + argument_type: named("String"), + description: Some(String::from("The global or 'message level' subject of your email. This may be overridden by subject lines set in personalizations.")) + }), + (String::from("content"), ArgumentInfo { + argument_type: array_of(named("mail_content")), + description: Some(String::from("An array where you can specify the content of your email. You can include multiple MIME types of content, but you must specify at least one MIME type.")) + }), + (String::from("attachments"), ArgumentInfo { + argument_type: nullable(array_of(named("mail_attachment"))), + description: Some(String::from("An array of objects where you can specify any attachments you want to include.")) + }), + (String::from("template_id"), ArgumentInfo { + argument_type: nullable(named("Bool")), + description: Some(String::from("An email template ID. A template that contains a subject and content — either text or html — will override any subject and content values specified at the personalizations or message level.")) + }), + (String::from("headers"), ArgumentInfo { + argument_type: nullable(array_of(named("header"))), + description: Some(String::from("The headers to put on the mail. You must ensure these are properly encoded if they contain unicode characters. These headers cannot be one of the reserved headers.")) + }), + (String::from("send_at"), ArgumentInfo { + argument_type: nullable(named("Int")), + description: Some(String::from("A unix timestamp allowing you to specify when you want your email to be delivered. This may be overridden by the send_at parameter set at the personalizations level. Delivery cannot be scheduled more than 72 hours in advance.")) + }), + (String::from("batch_id"), ArgumentInfo { + argument_type: nullable(named("String")), + description: Some(String::from("An ID representing a batch of emails to be sent at the same time. Including a batch_id in your request allows you include this email in that batch. It also enables you to cancel or pause the delivery of that batch.")) + }), + (String::from("asm"), ArgumentInfo { + argument_type: nullable(named("unsubscription_settings")), + description: Some(String::from("An object allowing you to specify how to handle unsubscribes.")) + }), + ]) } #[derive(Deserialize, Clone, Debug)] @@ -489,72 +482,7 @@ fn send_mail() -> ProcedureInfo { ProcedureInfo { name: String::from(SEND_MAIL), description: Some(String::from("Allows you to send email")), - arguments: BTreeMap::from([ - (String::from("from"), - ArgumentInfo { - description: Some(String::from("An array of messages and their metadata. Each object within personalizations can be thought of as an envelope - it defines who should receive an individual message and how that message should be handled.")), - argument_type: named("String") }), - (String::from("to"), - ArgumentInfo { - description: Some(String::from("An address that will be sent the email.")), - argument_type: named("String") }), - (String::from("cc"), - ArgumentInfo { - description: Some(String::from("An address that will be cced the email.")), - argument_type: nullable(named("String")) }), - (String::from("bcc"), - ArgumentInfo { - description: Some(String::from("An address that will be bcced the email.")), - argument_type: nullable(named("String")) }), - (String::from("reply_to"), - ArgumentInfo { - description: Some(String::from("An array of recipients who will receive replies.")), - argument_type: nullable(named("String")) }), - (String::from("subject"), - ArgumentInfo { - description: Some(String::from("The subject of your email. See character length requirements according to RFC 2822.")), - argument_type: named("String") }), - // (String::from("content"), - // ArgumentInfo { - // description: Some(String::from("An array where you can specify the content of your email. You can include multiple MIME types of content, but you must specify at least one MIME type.")), - // argument_type: named("mail_content") }), - (String::from("content_type"), - ArgumentInfo { - description: Some(String::from("The MIME type of the content you are including in your email")), - argument_type: named("String") }), - (String::from("content"), - ArgumentInfo { - description: Some(String::from("The actual content of the specified MIME type that you are including in your email.")), - argument_type: named("String") }), - // (String::from("type"), ObjectField { - // r#type: named("String"), - // description: Some(String::from("The MIME type of the content you are including in your email")) - // }), - // (String::from("name"), ObjectField { - // r#type: named("String"), - // description: Some(String::from("The actual content of the specified MIME type that you are including in your email.")) - // }), - // (String::from("attachment"), - // ArgumentInfo { - // description: Some(String::from("An object where you can specify an attachment you want to include.")), - // argument_type: nullable(named("mail_attachment")) }), - (String::from("template_id"), - ArgumentInfo { - description: Some(String::from("An email template ID. A template that contains a subject and content — either text or html — will override any subject and content values specified at the personalizations or message level.")), - argument_type: nullable(named("String")) }), - (String::from("send_at"), - ArgumentInfo { - description: Some(String::from("A unix timestamp allowing you to specify when you want your email to be delivered. This may be overridden by the send_at parameter set at the personalizations level. Delivery cannot be scheduled more than 72 hours in advance.")), - argument_type: nullable(named("Int")) }), - (String::from("batch_id"), - ArgumentInfo { - description: Some(String::from("An ID representing a batch of emails to be sent at the same time. Including a batch_id in your request allows you include this email in that batch. It also enables you to cancel or pause the delivery of that batch.")), - argument_type: nullable(named("String")) }) //, - // (String::from("asm"), - // ArgumentInfo { - // description: Some(String::from("An object allowing you to specify how to handle unsubscribes.")), - // argument_type: nullable(named("unsubscription_settings")) }) - ]), + arguments: send_mail_request_args(), result_type: named("send_mail_response"), } } diff --git a/crates/ndc-sendgrid/src/sendgrid_api.rs b/crates/ndc-sendgrid/src/sendgrid_api.rs index a560215..e6c9c50 100644 --- a/crates/ndc-sendgrid/src/sendgrid_api.rs +++ b/crates/ndc-sendgrid/src/sendgrid_api.rs @@ -129,11 +129,9 @@ pub struct SimpleSendMailRequest { pub reply_to: Option, pub subject: String, pub content: MailContent, - pub attachment: Option, pub template_id: Option, pub send_at: Option, pub batch_id: Option, - pub asm: Option, } #[derive(Serialize, Clone, Debug)] diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100755 index 6bf174c..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# List requested command -echo "$@" - -# List environment - TODO: Remove as this will contain API Key -env - -# Write out config -echo "$CONFIG" > sendgrid.connector.configuration.json - -# Kick off the requested command -"$@" \ No newline at end of file