maoosi / prisma-appsync

⚡ Turns your ◭ Prisma Schema into a fully-featured GraphQL API, tailored for AWS AppSync.

Home Page:https://prisma-appsync.vercel.app

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature: Add support for custom GraphQL scalars `@gql(scalars: { website: "AWSURL" })`

Tenrys opened this issue · comments

commented

Right now it seems like only fields that are named url or email have been hardcoded to use the AWSURL and AWSEmail scalar types from AWS, however I would like to be able to use these types on fields like urlPhoto or something like secondaryEmail.

As seen here:

if (type === 'String') {
switch (field.name.toLocaleLowerCase()) {
case 'email':
type = 'AWSEmail'
break
case 'url':
type = 'AWSURL'
break
}
}

Would it be possible to use triple slash comments in the Prisma schema to define which fields turn up as what scalar types in the GraphQL schema?

Possibly yes, but would need to find the right syntax...

There is already a custom notation in place (not documented yet) that allows customising the generated GraphQL schema.

/// @gql(queries: { list: null, count: "countyPosts" }, fields: { text: null }, subscriptions: null)
model Post {
    text  String?
    urlPhoto  String?
}

The above notation equals to:

  • Remove listPosts
  • Rename countPosts to countyPosts
  • Remove text field
  • Remove all subscriptions

One option could be:

/// @gql(scalars: { urlPhoto: "AWSURL" })
model Post {
    urlPhoto  String?
}

Implementing the above would be quite simple, as the code to read the @gql directive is already in place.

What do you think?

commented

I think that makes sense yes! Until documentation gets written, is there a way to know where exactly the code involving that custom notation is in place?

Parsing the @gql directive as a JSON object is done here:

const gqlDirectives = directives.match(gqlRegex)
if (gqlDirectives) {
for (let i = 0; i < gqlDirectives.length; i++) {
const str = replaceAll(gqlDirectives[i].replace(gqlRegex, '$1'), find, replace)
// eslint-disable-next-line no-new-func
gql = merge({}, gql, new Function(`return ({${str}})`)())
}
}

The following is the config object where to add _scalars: gqlObject?.scalars || {}:

const gqlOutput: {
_model: boolean
_fields: any
_usesQueries: boolean
_usesMutations: boolean
_usesSubscriptions: boolean
[key: string]: any
} = {
_model: gqlObject?.model !== null,
_fields: gqlObject?.fields || {},
_usesQueries: false,
_usesMutations: false,
_usesSubscriptions: false,
}

Here is where the check to ignore fields is done:

const isFieldIgnored = gqlConfig?._fields?.[field.name] === null
if (!field.isGenerated && !isFieldIgnored) {
fields.push({
name: field.name,
type: field.type,
scalar: this.getFieldScalar(field),
isRequired: this.isFieldRequired(field),
isList: this.isFieldList(field),
isEnum: this.isFieldEnum(field),
isEditable: !this.isFieldGeneratedRelation(field, model),
isUnique: this.isFieldUnique(field),
...(field.relationName && {
relation: {
name: this.getFieldRelationName(field, model),
kind: this.getFieldRelationKind(field),
type: this.getFieldScalar(field),
},
}),
directives,
sample: this.getFieldSample(field),
})
}
})

For example, we could do:

const scalar = gqlConfig?._scalars?.[field.name] || this.getFieldScalar(field)

@Tenrys do you want to work on a PR for this feature?

Will be released as part of 1.0.0-rc.6 (you can also try it now with prisma-appsync@1.0.0-preview.6.6).