Skip to content

Commit

Permalink
fix(examples): fix typescript compile issues in the react-native exam…
Browse files Browse the repository at this point in the history
…ple project
  • Loading branch information
jspizziri committed Jul 26, 2021
1 parent cd54bb3 commit 17b513b
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 111 deletions.
2 changes: 1 addition & 1 deletion examples/react-native/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const App = () => {
}, []);

if (!client) {
return <Text style={styles.heading}>Initializing app...</Text>;
return <Text>Initializing app...</Text>;
}

return (
Expand Down
3 changes: 2 additions & 1 deletion examples/react-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"dependencies": {
"@apollo/client": "^3.3.6",
"@react-native-async-storage/async-storage": "^1.13.2",
"apollo3-cache-persist": "^0.9.1",
"apollo3-cache-persist": "^0.10.0",
"graphql": "^15.4.0",
"react": "16.13.1",
"react-native": "0.63.4",
Expand All @@ -25,6 +25,7 @@
"@types/jest": "^25.2.3",
"@types/react-native": "^0.63.43",
"@types/react-test-renderer": "^16.9.2",
"@types/traverse": "^0.6.32",
"@typescript-eslint/eslint-plugin": "^2.27.0",
"@typescript-eslint/parser": "^2.27.0",
"babel-jest": "^25.1.0",
Expand Down
2 changes: 2 additions & 0 deletions examples/react-native/src/hooks/useApolloClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export const useApolloClient = () => {
const cache = new InMemoryCache();
let newPersistor = new CachePersistor({
cache,
// https://github.com/apollographql/apollo-cache-persist/issues/426
// @ts-ignore
storage: new AsyncStorageWrapper(AsyncStorage),
debug: __DEV__,
trigger: 'write',
Expand Down
48 changes: 16 additions & 32 deletions examples/react-native/src/utils/persistence/persistLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ import { visit } from 'graphql';
import { ApolloLink } from '@apollo/client';
import traverse from 'traverse';

import { extractPersistDirectivePaths, hasPersistDirective } from './transform';
import { extractPersistDirectivePaths } from './transform';

/**
* Given a data result object path, return the equivalent query selection path.
*
* @param {Array} path The data result object path. i.e.: ["a", 0, "b"]
* @return {String} the query selection path. i.e.: "a.b"
*/
const toQueryPath = path => path.filter(key => isNaN(Number(key))).join('.')
const toQueryPath = (path: any[]) => path.filter(key => isNaN(Number(key))).join('.')

/**
* Given a data result object, attach __persist values.
*/
const attachPersists = (paths, object) => {
const queryPaths = paths.map(toQueryPath)
const attachPersists = (paths: any[], object: any) => {
const queryPaths = paths.map(toQueryPath);

return traverse(object).map(function () {
if (
Expand All @@ -45,54 +45,38 @@ const attachPersists = (paths, object) => {
}

class PersistLink extends ApolloLink {
/**
* InStorageCache shouldPersist implementation for a __persist field validation.
*/
static shouldPersist (op, dataId, data) {
// console.log(dataId, data)
return dataId === 'ROOT_QUERY' || (!data || !!data.__persist)
}

/**
* InStorageCache addPersistField implementation to check for @perist directives.
*/
static addPersistField = doc => hasPersistDirective(doc)

constructor () {
super()
this.directive = 'persist'
}
public directive: string = 'persist';

/**
* Link query requester.
*/
request = (operation, forward) => {
request = (operation: any, forward: any) => {
const { query, paths } = extractPersistDirectivePaths(
operation.query,
this.directive
)
this.directive,
);
// Replace query with one without @persist directives.
operation.query = query
operation.query = query;

// Remove requesting __persist fields.
operation.query = visit(operation.query, {
Field: ({ name: { value: name } }, key, parent, path, ancestors) => {
Field: ({ name: { value: name } }: any): any => {
if (name === '__persist') {
return null
return null;
}
}
})

return forward(operation).map(result => {
return forward(operation).map((result: any) => {
if (result.data) {
result.data = attachPersists(paths, result.data)
result.data = attachPersists(paths, result.data);
}

return result
return result;
})
}
}

const createPersistLink = config => new PersistLink(config)
const createPersistLink = () => new PersistLink();

export { PersistLink, createPersistLink }
export { PersistLink, createPersistLink };
139 changes: 66 additions & 73 deletions examples/react-native/src/utils/persistence/transform.ts
Original file line number Diff line number Diff line change
@@ -1,108 +1,116 @@
/**
* Taken from https://github.com/TallerWebSolutions/apollo-cache-instorage
*/
import { visit, BREAK } from 'graphql';
import { checkDocument, cloneDeep } from '@apollo/client';
import { visit } from 'graphql';
import { checkDocument, cloneDeep } from '@apollo/client/utilities';

const PERSIST_FIELD = {
kind: 'Field',
name: {
kind: 'Name',
value: '__persist'
}
}
value: '__persist',
},
};

const addPersistFieldToSelectionSet = (selectionSet, isRoot = false) => {
const addPersistFieldToSelectionSet = (selectionSet: any, isRoot: boolean = false) => {
if (selectionSet.selections) {
if (!isRoot) {
const alreadyHasThisField = selectionSet.selections.some(selection => {
const alreadyHasThisField = selectionSet.selections.some((selection: any) => {
return (
selection.kind === 'Field' && selection.name.value === '__typename'
)
);
})

if (!alreadyHasThisField) {
selectionSet.selections.push(PERSIST_FIELD)
selectionSet.selections.push(PERSIST_FIELD);
}
}

selectionSet.selections.forEach(selection => {
selectionSet.selections.forEach((selection: any) => {
// Must not add __typename if we're inside an introspection query
if (selection.kind === 'Field') {
if (
selection.name.value.lastIndexOf('__', 0) !== 0 &&
selection.selectionSet
) {
addPersistFieldToSelectionSet(selection.selectionSet)
addPersistFieldToSelectionSet(selection.selectionSet);
}
}
else if (selection.kind === 'InlineFragment') {
if (selection.selectionSet) {
addPersistFieldToSelectionSet(selection.selectionSet)
addPersistFieldToSelectionSet(selection.selectionSet);
}
}
})
}
}

const addPersistFieldToDocument = doc => {
checkDocument(doc)
const docClone = cloneDeep(doc)
const addPersistFieldToDocument = (doc: any) => {
checkDocument(doc);
const docClone = cloneDeep(doc);

docClone.definitions.forEach(definition => {
docClone.definitions.forEach((definition: any) => {
const isRoot = definition.kind === 'OperationDefinition'
addPersistFieldToSelectionSet(definition.selectionSet, isRoot)
})
});

return docClone
return docClone;
}

const extractPersistDirectivePaths = (originalQuery, directive = 'persist') => {
const paths = []
const fragmentPaths = {}
const fragmentPersistPaths = {}
const extractPersistDirectivePaths = (originalQuery: any, directive: string = 'persist') => {
const paths: any[] = [];
const fragmentPaths: any = {};
const fragmentPersistPaths: any = {};

const query = visit(originalQuery, {
FragmentSpread: (
{ name: { value: name } },
key,
parent,
path,
ancestors
) => {
{ name: { value: name } }: any,
// ts complains about these not being used, however they're positional
// parameters, so we can't remove them due to ancestors being needed.
// @ts-ignore
key: any, parent: any, path: any,
ancestors: any,
): any => {
const root = ancestors.find(
({ kind }) =>
({ kind }: any) =>
kind === 'OperationDefinition' || kind === 'FragmentDefinition'
)
);

const rootKey =
root.kind === 'FragmentDefinition' ? root.name.value : '$ROOT'
root.kind === 'FragmentDefinition' ? root.name.value : '$ROOT';

const fieldPath = ancestors
.filter(({ kind }) => kind === 'Field')
.map(({ name: { value: name } }) => name)
.filter(({ kind }: any) => kind === 'Field')
.map(({ name: { value: name } }: any) => name);

fragmentPaths[name] = [rootKey].concat(fieldPath)
fragmentPaths[name] = [rootKey].concat(fieldPath);
},
Directive: ({ name: { value: name } }, key, parent, path, ancestors) => {
Directive: (
{ name: { value: name } }: any,
// ts complains about these not being used, however they're positional
// parameters, so we can't remove them due to ancestors being needed.
// @ts-ignore
key: any, parent: any, path: any,
ancestors: any,
): any => {
if (name === directive) {
const fieldPath = ancestors
.filter(({ kind }) => kind === 'Field')
.map(({ name: { value: name } }) => name)
.filter(({ kind }: any) => kind === 'Field')
.map(({ name: { value: name } }: any) => name);

const fragmentDefinition = ancestors.find(
({ kind }) => kind === 'FragmentDefinition'
)
({ kind }: any) => kind === 'FragmentDefinition'
);

// If we are inside a fragment, we must save the reference.
if (fragmentDefinition) {
fragmentPersistPaths[fragmentDefinition.name.value] = fieldPath
fragmentPersistPaths[fragmentDefinition.name.value] = fieldPath;
}
else if (fieldPath.length) {
paths.push(fieldPath)
paths.push(fieldPath);
}

return null
return null;
}
}
})
Expand All @@ -111,53 +119,38 @@ const extractPersistDirectivePaths = (originalQuery, directive = 'persist') => {
if (Object.keys(fragmentPersistPaths).length) {
visit(originalQuery, {
FragmentSpread: (
{ name: { value: name } },
key,
parent,
path,
ancestors
{ name: { value: name } }: any,
// ts complains about these not being used, however they're positional
// parameters, so we can't remove them due to ancestors being needed.
// @ts-ignore
key: any, parent: any, path: any,
ancestors: any
) => {
if (fragmentPersistPaths[name]) {
let fieldPath = ancestors
.filter(({ kind }) => kind === 'Field')
.map(({ name: { value: name } }) => name)
.filter(({ kind }: any) => kind === 'Field')
.map(({ name: { value: name } }: any) => name);

fieldPath = fieldPath.concat(fragmentPersistPaths[name])
fieldPath = fieldPath.concat(fragmentPersistPaths[name]);

let fragment = name
let parent = fragmentPaths[fragment][0]
let fragment = name;
let parent = fragmentPaths[fragment][0];

while (parent && parent !== '$ROOT' && fragmentPaths[parent]) {
fieldPath = fragmentPaths[parent].slice(1).concat(fieldPath)
parent = fragmentPaths[parent][0]
fieldPath = fragmentPaths[parent].slice(1).concat(fieldPath);
parent = fragmentPaths[parent][0];
}

paths.push(fieldPath)
paths.push(fieldPath);
}
}
})
});
}

return { query, paths }
}

const hasPersistDirective = doc => {
let hasDirective = false

visit(doc, {
Directive: ({ name: { value: name } }) => {
if (name === 'persist') {
hasDirective = true
return BREAK
}
}
})

return hasDirective
return { query, paths };
}

export {
addPersistFieldToDocument,
extractPersistDirectivePaths,
hasPersistDirective
}
18 changes: 14 additions & 4 deletions examples/react-native/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1306,6 +1306,11 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==

"@types/traverse@^0.6.32":
version "0.6.32"
resolved "https://registry.yarnpkg.com/@types/traverse/-/traverse-0.6.32.tgz#f9fdfa40cd4898deaa975a14511aec731de8235e"
integrity sha512-RBz2uRZVCXuMg93WD//aTS5B120QlT4lR/gL+935QtGsKHLS6sCtZBaKfWjIfk7ZXv/r8mtGbwjVIee6/3XTow==

"@types/ungap__global-this@^0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@types/ungap__global-this/-/ungap__global-this-0.3.1.tgz#18ce9f657da556037a29d50604335614ce703f4c"
Expand Down Expand Up @@ -1565,10 +1570,10 @@ anymatch@^3.0.3:
normalize-path "^3.0.0"
picomatch "^2.0.4"

apollo3-cache-persist@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/apollo3-cache-persist/-/apollo3-cache-persist-0.9.1.tgz#191d9d93666a31b8921cce1b2d61ac0b6578540f"
integrity sha512-A6/SdCJmGLMLrL+mlsIijP3G+V7NvyG6likhkmTQBibU/+69UWxVs2qb7peYGOdiPT5QsxcaujDVCEgLzqC2OA==
apollo3-cache-persist@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/apollo3-cache-persist/-/apollo3-cache-persist-0.10.0.tgz#8dd186818898bd433a9952fe4055adf3f4fb16a4"
integrity sha512-3W558cKQ9OymUaLMD3Mv8FuUmIDu/GP6aJA+5iLH6fw5MxG4dwF09fFz8NBHn/qfa/zrxv8AtDzKehZUPm107A==

argparse@^1.0.7:
version "1.0.10"
Expand Down Expand Up @@ -6750,6 +6755,11 @@ tr46@^1.0.1:
dependencies:
punycode "^2.1.0"

traverse@^0.6.6:
version "0.6.6"
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137"
integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=

ts-invariant@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.6.0.tgz#44066ecfeb7a806ff1c3b0b283408a337a885412"
Expand Down

0 comments on commit 17b513b

Please sign in to comment.