Skip to content

Commit

Permalink
proof of concept?
Browse files Browse the repository at this point in the history
  • Loading branch information
yaacovCR committed Aug 7, 2020
1 parent a3066a3 commit c46531c
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 6 deletions.
5 changes: 5 additions & 0 deletions packages/batch-delegate/tests/typeMerging.example.test.ts
Expand Up @@ -241,6 +241,11 @@ describe('merging using type merging', () => {
merge: {
Product: {
selectionSet: '{ upc }',
fields: {
shippingEstimate: {
selectionSet: '{ price weight }',
},
},
fieldName: '_productByRepresentation',
args: ({ upc, weight, price }) => ({ product: { upc, weight, price } }),
}
Expand Down
69 changes: 69 additions & 0 deletions packages/delegate/src/memoize.ts
Expand Up @@ -53,6 +53,75 @@ export function memoizeInfoAnd2Objects<
return memoized;
}

export function memoize4<
T1 extends Record<string, any>,
T2 extends Record<string, any>,
T3 extends Record<string, any>,
T4 extends Record<string, any>,
R extends any
>(fn: (A1: T1, A2: T2, A3: T3, A4: T4) => R): (A1: T1, A2: T2, A3: T3, A4: T4) => R {
let cache1: WeakMap<T1, WeakMap<T2, WeakMap<T3, WeakMap<T4, R>>>>;

function memoized(a1: T1, a2: T2, a3: T3, a4: T4) {
if (!cache1) {
cache1 = new WeakMap();
const cache2: WeakMap<T2, WeakMap<T3, WeakMap<T4, R>>> = new WeakMap();
cache1.set(a1, cache2);
const cache3: WeakMap<T3, WeakMap<T4, R>> = new WeakMap();
cache2.set(a2, cache3);
const cache4: WeakMap<T4, R> = new WeakMap();
cache3.set(a3, cache4);
const newValue = fn(a1, a2, a3, a4);
cache4.set(a4, newValue);
return newValue;
}

let cache2 = cache1.get(a1);
if (!cache2) {
cache2 = new WeakMap();
cache1.set(a1, cache2);
const cache3: WeakMap<T3, WeakMap<T4, R>> = new WeakMap();
cache2.set(a2, cache3);
const cache4: WeakMap<T4, R> = new WeakMap();
cache3.set(a3, cache4);
const newValue = fn(a1, a2, a3, a4);
cache4.set(a4, newValue);
return newValue;
}

let cache3 = cache2.get(a2);
if (!cache3) {
cache3 = new WeakMap();
cache2.set(a2, cache3);
const cache4: WeakMap<T4, R> = new WeakMap();
cache3.set(a3, cache4);
const newValue = fn(a1, a2, a3, a4);
cache4.set(a4, newValue);
return newValue;
}

const cache4 = cache3.get(a3);
if (!cache4) {
const cache4: WeakMap<T4, R> = new WeakMap();
cache3.set(a3, cache4);
const newValue = fn(a1, a2, a3, a4);
cache4.set(a4, newValue);
return newValue;
}

const cachedValue = cache4.get(a4);
if (cachedValue === undefined) {
const newValue = fn(a1, a2, a3, a4);
cache4.set(a4, newValue);
return newValue;
}

return cachedValue;
}

return memoized;
}

export function memoize3<
T1 extends Record<string, any>,
T2 extends Record<string, any>,
Expand Down
23 changes: 18 additions & 5 deletions packages/delegate/src/results/mergeFields.ts
Expand Up @@ -3,14 +3,15 @@ import { FieldNode, SelectionNode, Kind, GraphQLResolveInfo, SelectionSetNode, G
import { typesContainSelectionSet } from '@graphql-tools/utils';

import { MergedTypeInfo, SubschemaConfig } from '../types';
import { memoize3, memoize2 } from '../memoize';
import { memoize4, memoize3, memoize2 } from '../memoize';

import { mergeProxiedResults } from './mergeProxiedResults';

const sortSubschemasByProxiability = memoize3(function (
const sortSubschemasByProxiability = memoize4(function (
mergedTypeInfo: MergedTypeInfo,
sourceSubschemaOrSourceSubschemas: SubschemaConfig | Array<SubschemaConfig>,
targetSubschemas: Array<SubschemaConfig>
targetSubschemas: Array<SubschemaConfig>,
fieldNodes: Array<FieldNode>
): {
proxiableSubschemas: Array<SubschemaConfig>;
nonProxiableSubschemas: Array<SubschemaConfig>;
Expand All @@ -29,7 +30,18 @@ const sortSubschemasByProxiability = memoize3(function (

targetSubschemas.forEach(t => {
const selectionSet = mergedTypeInfo.selectionSets.get(t);
if (typesContainSelectionSet(types, selectionSet)) {
const fieldSelectionSets = mergedTypeInfo.fieldSelectionSets.get(t);
if (!typesContainSelectionSet(types, selectionSet)) {
nonProxiableSubschemas.push(t);
} else if (fieldSelectionSets == null) {
proxiableSubschemas.push(t);
} else if (
fieldNodes.every(fieldNode => {
const fieldName = fieldNode.name.value;
const fieldSelectionSet = fieldSelectionSets[fieldName];
return fieldSelectionSet == null || typesContainSelectionSet(types, fieldSelectionSet);
})
) {
proxiableSubschemas.push(t);
} else {
nonProxiableSubschemas.push(t);
Expand Down Expand Up @@ -145,7 +157,8 @@ export function mergeFields(
const { proxiableSubschemas, nonProxiableSubschemas } = sortSubschemasByProxiability(
mergedTypeInfo,
sourceSubschemaOrSourceSubschemas,
targetSubschemas
targetSubschemas,
fieldNodes
);

const { delegationMap, unproxiableFieldNodes } = buildDelegationPlan(mergedTypeInfo, fieldNodes, proxiableSubschemas);
Expand Down
3 changes: 2 additions & 1 deletion packages/delegate/src/types.ts
Expand Up @@ -83,11 +83,11 @@ export interface ICreateRequest {
export interface MergedTypeInfo {
typeName: string;
targetSubschemas: Map<SubschemaConfig, Array<SubschemaConfig>>;
selectionSet?: SelectionSetNode;
uniqueFields: Record<string, SubschemaConfig>;
nonUniqueFields: Record<string, Array<SubschemaConfig>>;
typeMaps: Map<SubschemaConfig, TypeMap>;
selectionSets: Map<SubschemaConfig, SelectionSetNode>;
fieldSelectionSets: Map<SubschemaConfig, Record<string, SelectionSetNode>>;
}

export interface ExecutionParams<TArgs = Record<string, any>, TContext = any> {
Expand Down Expand Up @@ -134,6 +134,7 @@ export interface SubschemaConfig {

export interface MergedTypeConfig {
selectionSet?: string;
fields?: Record<string, { selectionSet?: string }>;
fieldName?: string;
args?: (source: any) => Record<string, any>;
key?: (originalResult: any) => any;
Expand Down
13 changes: 13 additions & 0 deletions packages/stitch/src/stitchingInfo.ts
Expand Up @@ -94,6 +94,7 @@ function createMergedTypes(
const supportedBySubschemas: Record<string, Array<SubschemaConfig>> = Object.create({});
const typeMaps: Map<SubschemaConfig, TypeMap> = new Map();
const selectionSets: Map<SubschemaConfig, SelectionSetNode> = new Map();
const fieldSelectionSets: Map<SubschemaConfig, Record<string, SelectionSetNode>> = new Map();

mergedTypeCandidates.forEach(typeCandidate => {
const subschemaConfig = typeCandidate.subschema as SubschemaConfig;
Expand All @@ -115,6 +116,17 @@ function createMergedTypes(
selectionSets.set(subschemaConfig, selectionSet);
}

if (mergedTypeConfig.fields) {
const parsedFieldSelectionSets = Object.create(null);
Object.keys(mergedTypeConfig.fields).forEach(fieldName => {
const rawFieldSelectionSet = mergedTypeConfig.fields[fieldName].selectionSet;
if (rawFieldSelectionSet) {
parsedFieldSelectionSets[fieldName] = parseSelectionSet(rawFieldSelectionSet);
}
});
fieldSelectionSets.set(subschemaConfig, parsedFieldSelectionSets);
}

if (!mergedTypeConfig.resolve) {
if (mergedTypeConfig.key != null) {
const batchDelegateToSubschema = createBatchDelegateFn(
Expand Down Expand Up @@ -170,6 +182,7 @@ function createMergedTypes(
targetSubschemas,
typeMaps,
selectionSets,
fieldSelectionSets,
uniqueFields: Object.create({}),
nonUniqueFields: Object.create({}),
};
Expand Down
1 change: 1 addition & 0 deletions packages/stitch/src/types.ts
Expand Up @@ -26,6 +26,7 @@ export interface MergedTypeInfo {
nonUniqueFields: Record<string, Array<SubschemaConfig>>;
typeMaps: Map<SubschemaConfig, TypeMap>;
selectionSets: Map<SubschemaConfig, SelectionSetNode>;
fieldSelectionSets: Map<SubschemaConfig, Record<string, SelectionSetNode>>;
}

export interface StitchingInfo {
Expand Down

0 comments on commit c46531c

Please sign in to comment.