2022-06-27 19:32:25 +03:00
|
|
|
module Hasura.Metadata.DTO.Metadata (MetadataDTO (..)) where
|
|
|
|
|
|
|
|
import Autodocodec
|
|
|
|
( Autodocodec (Autodocodec),
|
|
|
|
HasCodec (codec),
|
|
|
|
dimapCodec,
|
|
|
|
disjointEitherCodec,
|
|
|
|
named,
|
|
|
|
(<?>),
|
|
|
|
)
|
|
|
|
import Autodocodec.OpenAPI ()
|
|
|
|
import Data.Aeson (FromJSON, ToJSON)
|
|
|
|
import Data.OpenApi qualified as OpenApi
|
|
|
|
import Hasura.Metadata.DTO.MetadataV1 (MetadataV1)
|
|
|
|
import Hasura.Metadata.DTO.MetadataV2 (MetadataV2)
|
|
|
|
import Hasura.Metadata.DTO.MetadataV3 (MetadataV3)
|
|
|
|
import Hasura.Prelude
|
|
|
|
|
|
|
|
-- | Exported representation of the GraphQL Engine metadata configuration
|
|
|
|
-- format.
|
|
|
|
--
|
|
|
|
-- The OpenAPI specification for metadata is experimental and incomplete. Please
|
|
|
|
-- do not incorporate it into essential workflows at this time.
|
|
|
|
data MetadataDTO = V1 MetadataV1 | V2 MetadataV2 | V3 MetadataV3
|
|
|
|
deriving stock (Show, Eq, Generic)
|
|
|
|
deriving (FromJSON, ToJSON, OpenApi.ToSchema) via (Autodocodec MetadataDTO)
|
|
|
|
|
|
|
|
-- | Sum types translate to union types in OpenApi documents via
|
|
|
|
-- `disjointEitherCodec` (or via `eitherCodec` if the encoded JSON is not
|
|
|
|
-- necessarily disjoint). In this case we ensure that the encodings of
|
|
|
|
-- 'MetadataV1', 'MetadataV2', and 'MetadataV3' are disjoint by using
|
|
|
|
-- 'versionField' in the codec for each variant which injects a field into the
|
|
|
|
-- JSON representation that requires a specific number to parse successfully.
|
|
|
|
-- ('MetadataV1' is the only variant where the version field is optional.)
|
|
|
|
--
|
|
|
|
-- A codec that represents more than two variants of different types requires
|
|
|
|
-- nesting `disjointEitherCodec`. Thankfully in the generated OpenApi
|
|
|
|
-- documentation these three variants are flattened into a single @oneOf@ list
|
|
|
|
-- of allowed schemas.
|
|
|
|
instance HasCodec MetadataDTO where
|
|
|
|
codec =
|
|
|
|
named "Metadata" $
|
|
|
|
dimapCodec decode encode $
|
|
|
|
disjointEitherCodec
|
server: polymorphic codec for metadata sources
This PR expands the OpenAPI specification generated for metadata to include separate definitions for `SourceMetadata` for each native database type, and for DataConnector.
For the most part the changes add `HasCodec` implementations, and don't modify existing code otherwise.
The generated OpenAPI spec can be used to generate TypeScript definitions that distinguish different source metadata types based on the value of the `kind` properly. There is a problem: because the specified `kind` value for a data connector source is any string, when TypeScript gets a source with a `kind` value of, say, `"postgres"`, it cannot unambiguously determine whether the source is postgres, or a data connector. For example,
```ts
function consumeSourceMetadata(source: SourceMetadata) {
if (source.kind === "postgres" || source.kind === "pg") {
// At this point TypeScript infers that `source` is either an instance
// of `PostgresSourceMetadata`, or `DataconnectorSourceMetadata`. It
// can't narrow further.
source
}
if (source.kind === "something else") {
// TypeScript infers that this `source` must be an instance of
// `DataconnectorSourceMetadata` because `source.kind` does not match
// any of the other options.
source
}
}
```
The simplest way I can think of to fix this would be to add a boolean property to the `SourceMetadata` type along the lines of `isNative` or `isDataConnector`. This could be a field that only exists in serialized data, like the metadata version field. The combination of one of the native database names for `kind`, and a true value for `isNative` would be enough for TypeScript to unambiguously distinguish the source kinds.
But note that in the current state TypeScript is able to reference the short `"pg"` name correctly!
~~Tests are not passing yet due to some discrepancies in DTO serialization vs existing Metadata serialization. I'm working on that.~~
The placeholders that I used for table and function metadata are not compatible with the ordered JSON serialization in use. I think the best solution is to write compatible codecs for those types in another PR. For now I have disabled some DTO tests for this PR.
Here are the generated [OpenAPI spec](https://github.com/hasura/graphql-engine-mono/files/9397333/openapi.tar.gz) based on these changes, and the generated [TypeScript client code](https://github.com/hasura/graphql-engine-mono/files/9397339/client-typescript.tar.gz) based on that spec.
Ticket: [MM-66](https://hasurahq.atlassian.net/browse/MM-66)
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5582
GitOrigin-RevId: e1446191c6c832879db04f129daa397a3be03f62
2022-08-25 21:34:44 +03:00
|
|
|
(codec @MetadataV1)
|
2022-06-27 19:32:25 +03:00
|
|
|
( disjointEitherCodec
|
server: polymorphic codec for metadata sources
This PR expands the OpenAPI specification generated for metadata to include separate definitions for `SourceMetadata` for each native database type, and for DataConnector.
For the most part the changes add `HasCodec` implementations, and don't modify existing code otherwise.
The generated OpenAPI spec can be used to generate TypeScript definitions that distinguish different source metadata types based on the value of the `kind` properly. There is a problem: because the specified `kind` value for a data connector source is any string, when TypeScript gets a source with a `kind` value of, say, `"postgres"`, it cannot unambiguously determine whether the source is postgres, or a data connector. For example,
```ts
function consumeSourceMetadata(source: SourceMetadata) {
if (source.kind === "postgres" || source.kind === "pg") {
// At this point TypeScript infers that `source` is either an instance
// of `PostgresSourceMetadata`, or `DataconnectorSourceMetadata`. It
// can't narrow further.
source
}
if (source.kind === "something else") {
// TypeScript infers that this `source` must be an instance of
// `DataconnectorSourceMetadata` because `source.kind` does not match
// any of the other options.
source
}
}
```
The simplest way I can think of to fix this would be to add a boolean property to the `SourceMetadata` type along the lines of `isNative` or `isDataConnector`. This could be a field that only exists in serialized data, like the metadata version field. The combination of one of the native database names for `kind`, and a true value for `isNative` would be enough for TypeScript to unambiguously distinguish the source kinds.
But note that in the current state TypeScript is able to reference the short `"pg"` name correctly!
~~Tests are not passing yet due to some discrepancies in DTO serialization vs existing Metadata serialization. I'm working on that.~~
The placeholders that I used for table and function metadata are not compatible with the ordered JSON serialization in use. I think the best solution is to write compatible codecs for those types in another PR. For now I have disabled some DTO tests for this PR.
Here are the generated [OpenAPI spec](https://github.com/hasura/graphql-engine-mono/files/9397333/openapi.tar.gz) based on these changes, and the generated [TypeScript client code](https://github.com/hasura/graphql-engine-mono/files/9397339/client-typescript.tar.gz) based on that spec.
Ticket: [MM-66](https://hasurahq.atlassian.net/browse/MM-66)
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5582
GitOrigin-RevId: e1446191c6c832879db04f129daa397a3be03f62
2022-08-25 21:34:44 +03:00
|
|
|
(codec @MetadataV2)
|
|
|
|
(codec @MetadataV3)
|
2022-06-27 19:32:25 +03:00
|
|
|
)
|
|
|
|
<?> "configuration format for the Hasura GraphQL Engine"
|
|
|
|
where
|
|
|
|
decode = either V1 $ either V2 V3
|
|
|
|
encode = \case
|
|
|
|
V1 v1 -> Left v1
|
|
|
|
V2 v2 -> Right $ Left v2
|
|
|
|
V3 v3 -> Right $ Right v3
|