Skip to content

Commit

Permalink
refactor masking typenames
Browse files Browse the repository at this point in the history
  • Loading branch information
JoviDeCroock committed Feb 12, 2020
1 parent 8327ae2 commit fda2582
Show file tree
Hide file tree
Showing 11 changed files with 37 additions and 27 deletions.
6 changes: 2 additions & 4 deletions .changeset/modern-queens-run.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
---
'@urql/core': minor
'@urql/preact': minor
'urql': minor
---

Add the `stripTypename` export to `@urql/core` to make all `__typename` fields non-enumerable.
In `@urql/preact` and `urql` this is applied to all `data` results.
Add the `maskTypename` export to `@urql/core` to make all `__typename` fields non-enumerable.
Add the possibility of masking `__typename` from result through the `client.maskTypename` option.
19 changes: 17 additions & 2 deletions packages/core/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
switchMap,
publish,
subscribe,
map,
} from 'wonka';

import {
Expand All @@ -35,7 +36,7 @@ import {
PromisifiedSource,
} from './types';

import { createRequest, toSuspenseSource, withPromise } from './utils';
import { createRequest, toSuspenseSource, withPromise, maskTypename } from './utils';
import { DocumentNode } from 'graphql';

/** Options for configuring the URQL [client]{@link Client}. */
Expand All @@ -54,6 +55,8 @@ export interface ClientOptions {
requestPolicy?: RequestPolicy;
/** Use HTTP GET for queries. */
preferGetMethod?: boolean;
/** Mask __typename from results. */
maskTypename?: boolean;
}

interface ActiveOperations {
Expand All @@ -72,6 +75,7 @@ export class Client {
suspense: boolean;
preferGetMethod: boolean;
requestPolicy: RequestPolicy;
maskTypename: boolean;

// These are internals to be used to keep track of operations
dispatchOperation: (operation: Operation) => void;
Expand All @@ -90,6 +94,7 @@ export class Client {
this.suspense = !!opts.suspense;
this.requestPolicy = opts.requestPolicy || 'cache-first';
this.preferGetMethod = !!opts.preferGetMethod;
this.maskTypename = !!opts.maskTypename;

// This subject forms the input of operations; executeOperation may be
// called to dispatch a new operation on the subject
Expand Down Expand Up @@ -182,11 +187,21 @@ export class Client {
/** Executes an Operation by sending it through the exchange pipeline It returns an observable that emits all related exchange results and keeps track of this observable's subscribers. A teardown signal will be emitted when no subscribers are listening anymore. */
executeRequestOperation(operation: Operation): Source<OperationResult> {
const { key, operationName } = operation;
const operationResults$ = pipe(
let operationResults$ = pipe(
this.results$,
filter((res: OperationResult) => res.operation.key === key)
);

if (this.maskTypename) {
operationResults$ = pipe(
operationResults$,
map(res => {
res.data = maskTypename(res.data);
return res;
}),
);
}

if (operationName === 'mutation') {
// A mutation is always limited to just a single result and is never shared
return pipe(
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export * from './result';
export * from './typenames';
export * from './toSuspenseSource';
export * from './stringifyVariables';
export * from './stripTypename';
export * from './maskTypename';
export * from './withPromise';

export const noop = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { stripTypename } from './stripTypename';
import { maskTypename } from './maskTypename';

it('strips typename from flat objects', () => {
expect(
stripTypename({ __typename: 'Todo', id: 1 })
maskTypename({ __typename: 'Todo', id: 1 })
).toEqual({ id: 1 });
});

it('strips typename from flat objects containing dates', () => {
const date = new Date();
expect(
stripTypename({ __typename: 'Todo', id: 1, date })
maskTypename({ __typename: 'Todo', id: 1, date })
).toEqual({ id: 1, date });
});

it('strips typename from nested objects', () => {
expect(
stripTypename({
maskTypename({
__typename: 'Todo',
id: 1,
author: {
Expand All @@ -28,7 +28,7 @@ it('strips typename from nested objects', () => {

it('strips typename from nested objects with arrays', () => {
expect(
stripTypename({
maskTypename({
__typename: 'Todo',
id: 1,
author: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const stripTypename = (data: any): any => {
export const maskTypename = (data: any): any => {
if (!data || typeof data !== 'object') return data;

return Object.keys(data).reduce((acc, key: string) => {
Expand All @@ -9,9 +9,9 @@ export const stripTypename = (data: any): any => {
value,
});
} else if (Array.isArray(value)) {
acc[key] = value.map(stripTypename);
acc[key] = value.map(maskTypename);
} else if (typeof value === 'object' && '__typename' in value) {
acc[key] = stripTypename(value);
acc[key] = maskTypename(value);
} else {
acc[key] = value;
}
Expand Down
3 changes: 1 addition & 2 deletions packages/preact-urql/src/hooks/useMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
OperationContext,
CombinedError,
createRequest,
stripTypename,
} from '@urql/core';
import { useClient } from '../context';
import { useImmediateState } from './useImmediateState';
Expand Down Expand Up @@ -54,7 +53,7 @@ export const useMutation = <T = any, V = object>(
setState({
fetching: false,
stale: !!result.stale,
data: stripTypename(result.data),
data: result.data,
error: result.error,
extensions: result.extensions,
});
Expand Down
4 changes: 2 additions & 2 deletions packages/preact-urql/src/hooks/useQuery.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DocumentNode } from 'graphql';
import { pipe, subscribe, onEnd } from 'wonka';
import { useRef, useCallback } from 'preact/hooks';
import { OperationContext, RequestPolicy, CombinedError, stripTypename } from '@urql/core';
import { OperationContext, RequestPolicy, CombinedError } from '@urql/core';

import { useClient } from '../context';
import { useRequest } from './useRequest';
Expand Down Expand Up @@ -71,7 +71,7 @@ export const useQuery = <T = any, V = object>(
subscribe(result => {
setState({
fetching: false,
data: stripTypename(result.data),
data: result.data,
error: result.error,
extensions: result.extensions,
stale: !!result.stale,
Expand Down
3 changes: 1 addition & 2 deletions packages/preact-urql/src/hooks/useSubscription.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DocumentNode } from 'graphql';
import { useCallback, useRef } from 'preact/hooks';
import { pipe, onEnd, subscribe } from 'wonka';
import { CombinedError, OperationContext, stripTypename } from '@urql/core';
import { CombinedError, OperationContext } from '@urql/core';
import { useClient } from '../context';
import { useRequest } from './useRequest';
import { noop, initialState } from './useQuery';
Expand Down Expand Up @@ -63,7 +63,6 @@ export const useSubscription = <T = any, R = T, V = object>(
}),
onEnd(() => setState(s => ({ ...s, fetching: false }))),
subscribe(result => {
result.data = stripTypename(result.data);
setState(s => ({
fetching: true,
data:
Expand Down
3 changes: 1 addition & 2 deletions packages/react-urql/src/hooks/useMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
OperationContext,
CombinedError,
createRequest,
stripTypename,
} from '@urql/core';

import { useClient } from '../context';
Expand Down Expand Up @@ -50,7 +49,7 @@ export const useMutation = <T = any, V = object>(
setState({
fetching: false,
stale: !!result.stale,
data: stripTypename(result.data),
data: result.data,
error: result.error,
extensions: result.extensions,
});
Expand Down
4 changes: 2 additions & 2 deletions packages/react-urql/src/hooks/useQuery.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DocumentNode } from 'graphql';
import { useCallback, useMemo } from 'react';
import { pipe, concat, fromValue, switchMap, map, scan } from 'wonka';
import { CombinedError, OperationContext, RequestPolicy, stripTypename } from '@urql/core';
import { CombinedError, OperationContext, RequestPolicy } from '@urql/core';

import { useClient } from '../context';
import { useSource, useBehaviourSubject } from './useSource';
Expand Down Expand Up @@ -71,7 +71,7 @@ export const useQuery = <T = any, V = object>(
map(({ stale, data, error, extensions }) => ({
fetching: false,
stale: !!stale,
data: stripTypename(data),
data,
error,
extensions,
}))
Expand Down
4 changes: 2 additions & 2 deletions packages/react-urql/src/hooks/useSubscription.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DocumentNode } from 'graphql';
import { useCallback, useRef, useMemo } from 'react';
import { pipe, concat, fromValue, switchMap, map, scan } from 'wonka';
import { CombinedError, OperationContext, stripTypename } from '@urql/core';
import { CombinedError, OperationContext } from '@urql/core';

import { useClient } from '../context';
import { useSource, useBehaviourSubject } from './useSource';
Expand Down Expand Up @@ -75,7 +75,7 @@ export const useSubscription = <T = any, R = T, V = object>(
map(({ stale, data, error, extensions }) => ({
fetching: true,
stale: !!stale,
data: stripTypename(data),
data,
error,
extensions,
}))
Expand Down

0 comments on commit fda2582

Please sign in to comment.