Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ts-client custom scalars #744

Closed
jasonkuhrt opened this issue Mar 30, 2024 · 0 comments · Fixed by #746
Closed

ts-client custom scalars #744

jasonkuhrt opened this issue Mar 30, 2024 · 0 comments · Fixed by #746

Comments

@jasonkuhrt
Copy link
Member

jasonkuhrt commented Mar 30, 2024

Perceived Problem

Custom scalars have no runtime codec.

Ideas / Proposed Solution(s)

Allow the generator to have custom scalar codecs specified. Maintain a runtime schema type map. Pass requests/responses through a middleware that uses the runtime schema type map to apply encoders/decoders to custom scalar fields.

Codecs

gr --codecs './customScalarCodecs.ts'

By default look for a a file at <outputDirPath>/customScalarCodecs.ts or <outputDirPath>/custom-scalar-codecs.ts.

The contract for the module is exported codecs whose names match a custom scalar in the schema.

Example:

import { createCodec } from 'graphql-request/alpha/scalars'


export const Date = createCodec({
  encode: (date) => date.getTime(),
  decode: (number) => new Date(number)
})

When a custom scalar has no defined codec then an error is thrown.

** Automatic Runtime codec application **

Use a type map that knows which parts of the schema are custom scalars. This runtime type map will be part of the code generation.

Example type map:

import * as CustomScalarCodecs from '...'

export const CustomScalarSchema = {
  query: {
    date: CustomScalarCodecs.Date
  }
}

An internal middleware will be used doing something like as follows.

const processCustomScalars = (grDocument) => {
  const encodedGrDocument = encode(typeMap, grDocument)
  const result = await send(typeMap, encodedGrDocument)
  const decodedResult = decode(result)
}

const encode = (typeMap, grDocument) => {
  return Object.fromEntries(Object.entries(grDocument).map(([key,value]) => {
    if (typeMap[key]) {
      if (typeMap[key].kind === 'Scalar') {
        return [key, typeMap[key].codec.encode(value)]
      } else {
        return [key, return encode(typeMap[key], value[key])]
      }
    } else {
     return [key, value]
    }
  }))
}

const decode = (typeMap, result) => {
  return Object.fromEntries(Object.entries(result).map(([key,value]) => {
    if (typeMap[key]) {
      if (typeMap[key].kind === 'Scalar') {
        return [key, typeMap[key].codec.decode(value)]
      } else {
        return [key, return decode(typeMap[key], value[key])]
      }
    } else {
     return [key, value]
    }
  }))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant