Skip to content

Commit

Permalink
Merge pull request #439 from convoyinc/mocampo/migrate-copy-from-path
Browse files Browse the repository at this point in the history
Adds ability to migrate parametrized field by copying from same path
  • Loading branch information
manuelconvoy authored Jun 29, 2020
2 parents 7cd65f2 + 38d0a01 commit 3d44bd1
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 5 deletions.
25 changes: 21 additions & 4 deletions src/operations/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export type ParameterizedMigrationEntry = {
path: PathPart[],
args: JsonObject | undefined,
defaultReturn: any,
copyFrom?: {
path: PathPart[],
args: JsonObject | undefined,
},
};
export type ParameterizedMigrations = {
// typename is the typename of the container
Expand All @@ -48,13 +52,14 @@ function migrateEntity(
snapshot: EntitySnapshot,
nodesToAdd: NodeSnapshotMap,
migrationMap?: MigrationMap,
allNodes?: NodeSnapshotMap
): EntitySnapshot {

// Only if object and if valid MigrationMap is provided
if (!isObject(snapshot.data)) return snapshot;

const entityMigrations = deepGet(migrationMap, ['_entities']);
const parameterizedMigrations = deepGet(migrationMap, ['_parameterized']);
const entityMigrations = deepGet(migrationMap, ['_entities']) as EntityMigrations;
const parameterizedMigrations = deepGet(migrationMap, ['_parameterized']) as ParameterizedMigrations;

const typeName = snapshot.data.__typename as string || 'Query';

Expand All @@ -72,7 +77,19 @@ function migrateEntity(
// create a parameterized value snapshot if container doesn't know of the
// parameterized field we expect
if (!snapshot.outbound || !snapshot.outbound.find(s => s.id === fieldId)) {
const newNode = new ParameterizedValueSnapshot(parameterized.defaultReturn);
let newData = parameterized.defaultReturn;
if (allNodes && parameterized.copyFrom) {
const { path, args } = parameterized.copyFrom;
const copyFromFieldId = nodeIdForParameterizedValue(id, path, args);
const copyFromNode = allNodes[copyFromFieldId];
if (copyFromNode) {
newData = copyFromNode.data;
} else {
// If copyFrom doesn't exist added so we can retrieve it on read
nodesToAdd[copyFromFieldId] = new ParameterizedValueSnapshot(newData);
}
}
const newNode = new ParameterizedValueSnapshot(newData);
nodesToAdd[fieldId] = newNode;

// update the reference for the new node in the container
Expand All @@ -97,7 +114,7 @@ export function migrate(cacheSnapshot: CacheSnapshot, migrationMap?: MigrationMa
for (const nodeId in nodes) {
const nodeSnapshot = nodes[nodeId];
if (nodeSnapshot instanceof EntitySnapshot) {
migrateEntity(nodeId, nodeSnapshot, nodesToAdd, migrationMap);
migrateEntity(nodeId, nodeSnapshot, nodesToAdd, migrationMap, nodes);
}
}

Expand Down
101 changes: 100 additions & 1 deletion test/unit/operations/migrate/entitiesWithParameterizedFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as _ from 'lodash';

import { CacheSnapshot } from '../../../../src/CacheSnapshot';
import { CacheContext } from '../../../../src/context/CacheContext';
import { migrate, read, MigrationMap } from '../../../../src/operations';
import { migrate, read, MigrationMap, QueryResult } from '../../../../src/operations';
import { OptimisticUpdateQueue } from '../../../../src/OptimisticUpdateQueue';
import { createGraphSnapshot, strictConfig, query } from '../../../helpers';

Expand Down Expand Up @@ -293,4 +293,103 @@ describe(`operations.migrate`, () => {
jestExpect(_.get(result, ['viewer', 'friends'])).toEqual([]);
});

it(`can copy from path`, () => {
const copyFrom = { path: ['friends'], args: { circle: 'elementary' } };
const { result, complete } = copyFromPath(cacheContext, copyFrom);

jestExpect(complete).toBeTruthy();
jestExpect(_.get(result, ['viewer', 'friends'])).toEqual([{
id: 'friend-1',
first: 'Bob',
last: 'Breaker',
}, {
id: 'friend-2',
first: 'Susan',
last: 'Fixer',
}]);
});

it(`defaults to defaultReturn if can't copy from path`, () => {
const copyFrom = { path: ['friends'], args: { circle: 'foo' } };
const { result, complete } = copyFromPath(cacheContext, copyFrom);

jestExpect(complete).toBeTruthy();
jestExpect(_.get(result, ['viewer', 'friends'])).toEqual([]);
});

it(`defaults to defaultReturn if copyFrom is undefined`, () => {
const copyFrom = undefined;
const { result, complete } = copyFromPath(cacheContext, copyFrom);

jestExpect(complete).toBeTruthy();
jestExpect(_.get(result, ['viewer', 'friends'])).toEqual([]);
});

it(`defaults to defaultReturn if copyFrom.args is undefined`, () => {
const copyFrom = { path: ['friends'] };
const { result, complete } = copyFromPath(cacheContext, copyFrom);

jestExpect(complete).toBeTruthy();
jestExpect(_.get(result, ['viewer', 'friends'])).toEqual([]);
});

it(`can complete when parameterized entity is undefined`, () => {
const migrationMap: MigrationMap = {
_parameterized: {
Viewer: [{
path: ['friends'],
args: { circle: 'elementary' },
defaultReturn: null,
copyFrom: { path: ['friends'], args: { circle: 'elementary', stillFriends: true } },
}],
},
};

const snapshot = createNewCacheSnapshot2(cacheContext);
const migrated = migrate(snapshot, migrationMap);
const { complete, result } = read(
cacheContext,
query(parameterizedQuery, { circle: 'elementary', stillFriends: true }),
migrated.baseline
);

jestExpect(complete).toBeTruthy();
jestExpect(_.get(result, ['viewer', 'friends'])).toEqual(null);
});
});

const parameterizedQuery = `
query dummy($circle: String, $stillFriends: Boolean) {
foo
bar
viewer {
id
friends(circle: $circle, stillFriends: $stillFriends) {
id
first
last
}
}
}
`;

function copyFromPath(cacheContext: CacheContext, copyFrom?: any): QueryResult {
const migrationMap: MigrationMap = {
_parameterized: {
Viewer: [{
path: ['friends'],
args: { circle: 'elementary', stillFriends: true },
defaultReturn: [],
copyFrom,
}],
},
};

const snapshot = createNewCacheSnapshot3(cacheContext);
const migrated = migrate(snapshot, migrationMap);
return read(
cacheContext,
query(parameterizedQuery, { circle: 'elementary', stillFriends: true }),
migrated.baseline,
);
}

0 comments on commit 3d44bd1

Please sign in to comment.