Last active
February 22, 2023 12:03
-
-
Save intrnl/154fd41d6a7902bad88cf068d8f61860 to your computer and use it in GitHub Desktop.
Hasura v2 migration package for Apollo Client
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// NOTE: Hasura v1 to Hasura v2 conversion | |
/* eslint-disable import/export */ | |
import { | |
useQuery as useApolloQuery, | |
useSubscription as useApolloSubscription, | |
} from '@apollo/react-hooks-unpatched' | |
import gql from 'graphql-tag' | |
export * from '@apollo/react-hooks-unpatched' | |
const OPERATORS = [ | |
'_in', | |
'_nin', | |
'_eq', | |
'_gt', | |
'_lt', | |
'_gte', | |
'_lte', | |
'_like', | |
'_ilike', | |
'_contains', | |
'_not', | |
'_and', | |
'_or', | |
'_is_null', | |
] | |
const NULL_RE = /\bnull\b/ | |
const NULL_REPLACE_RE = new RegExp( | |
`\\b(${OPERATORS.join('|')}):\\s*null\\b`, | |
'g' | |
) | |
const removeEmpty = obj => { | |
const res = {} | |
for (const key in obj) { | |
const val = obj[key] | |
if (Array.isArray(val)) { | |
res[key] = val | |
} else if (typeof val === 'object') { | |
if (val !== null) { | |
const replaced = removeEmpty(val) | |
if (Object.keys(replaced).length > 0) { | |
res[key] = replaced | |
} | |
} | |
} else if (val !== undefined) { | |
res[key] = val | |
} | |
} | |
return res | |
} | |
const fixGqlDocument = (document, param) => { | |
const orig = document.loc.source.body | |
let modified = false | |
let str = orig | |
// Remove variable usage inside _eq or other equality conditions | |
const toPrune = [] | |
// Replace all variable usage with an empty object {} | |
const toObject = [] | |
for (const definition of document.definitions) { | |
for (const varDef of definition.variableDefinitions) { | |
const key = varDef.variable.name.value | |
const value = param && param[key] | |
if (varDef.type.kind === 'NonNullType') { | |
continue | |
} | |
if (value === null || value === undefined) { | |
if ( | |
varDef.type.kind === 'NamedType' && | |
varDef.type.name.value.endsWith('_comparison_exp') | |
) { | |
toObject.push(key) | |
} else { | |
toPrune.push(key) | |
} | |
} | |
} | |
} | |
if (toPrune.length > 0) { | |
const joined = toPrune.join('|') | |
const re = new RegExp( | |
`\\b(${OPERATORS.join('|')}):\\s*\\$(${joined})\\b`, | |
'g' | |
) | |
str = str.replace(re, '') | |
modified = true | |
} | |
if (toObject.length > 0) { | |
const joined = toObject.join('|') | |
const re = new RegExp(`:\\s*\\$(${joined})\\b`, 'g') | |
str = str.replace(re, ': {}') | |
modified = true | |
} | |
if (NULL_RE.test(str)) { | |
str = str.replace(NULL_REPLACE_RE, '') | |
modified = true | |
} | |
if (modified) { | |
try { | |
return gql(str) | |
} catch (error) { | |
if (process.env.NODE_ENV !== 'production') { | |
// eslint-disable-next-line no-console | |
console.log({original: orig, replaced: str, param}) | |
} | |
throw new Error(`Bad GraphQL query!`) | |
} | |
} | |
return document | |
} | |
export const useQuery = (query, options = {}) => { | |
const {variables, unstable_skipPatch = false, ...rest} = options | |
let _query = query | |
let _variables = variables | |
if (!unstable_skipPatch) { | |
_variables = variables ? removeEmpty(variables) : undefined | |
_query = fixGqlDocument(query, _variables) | |
} | |
return useApolloQuery(_query, { | |
...rest, | |
variables: _variables, | |
}) | |
} | |
export const useSubscription = (query, options = {}) => { | |
const {variables, unstable_skipPatch = false, ...rest} = options | |
let _query = query | |
let _variables = variables | |
if (!unstable_skipPatch) { | |
_variables = variables ? removeEmpty(variables) : undefined | |
_query = fixGqlDocument(query, _variables) | |
} | |
return useApolloSubscription(_query, { | |
...rest, | |
variables: _variables, | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment