Skip to content

Commit 30e6b8a

Browse files
jgwhitechadian
authored andcommitted
Rename varsMap to argsMap (#23)
* Pass variableValues into the query handler (rather than root args) Previously the `vars` that were being passed down from the query mock were in fact the args for the root query selection and therefore already massaged by the GraphQL executor to have the correct names. This means that variables to be used further down the graph could either be missing or have the wrong names. This is tricky to explain succintly, please see the test case for a concrete example. In the test case, we are dealing with a scenario where the variable is used in both the root of the query *and* further down with a different name. If it were used further down and *not* in the root query then the variable would simply be absent prior to this patch. Co-authored-by: Chad Carbert <chadcarbert@me.com> * Rename varsMap to argsMap and clarify behavior Previously this option worked with variable names rather than argument names. We believe mapping argument names is more useful and more likely to be the expected behavior. This patch removes any notion of mapping variable names and focuses strictly on argument names whilst also renaming the option to make it clearer what is being mapped. Closes #22 Co-authored-by: Chad Carbert <chadcarbert@me.com>
1 parent 4620c3f commit 30e6b8a

19 files changed

Lines changed: 147 additions & 70 deletions

File tree

DEPRECATIONS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Deprecations
2+
3+
## varsMap (since 0.0.9)
4+
5+
This option has been renamed to `argsMap` and now explicitly provides support
6+
for custom mapping of *argument* names in filters and mutations (rather than
7+
*variable* names).

README.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ You may pass in options when creating a request handler. The options take the fo
104104
105105
1. The table from Mirage's database that corresponds to the return
106106
type of the mutation.
107-
2. The mutation variables. These will be mapped per the varsMap
107+
2. The mutation arguments. These will be mapped per the argsMap
108108
option, by the return type, if appropriate.
109109
3. Mirage's database.
110110
@@ -113,28 +113,29 @@ You may pass in options when creating a request handler. The options take the fo
113113
functionality, if feasible.
114114
*/
115115
mutations: {
116-
updatePerson: (people, vars, db) => {
117-
let { id, personAttributes } = vars;
116+
updatePerson: (people, args, db) => {
117+
let { id, personAttributes } = args;
118118

119119
return [ people.update(id, personAttributes) ];
120120
}
121121
},
122122
/*
123-
varsMap is used if you need to map request variables defined
124-
in your GraphQL queries. The value you specify in the map can
125-
be a string or a function.
123+
argsMap is used if you need to map arguments defined in your GraphQL
124+
queries to something other than the corresponding field name on the
125+
mirage record. The value you specify in the map can be a string or a
126+
function.
126127
127128
The addon uses the variables to filter records of the given
128129
type from Mirage's database.
129130
130-
String values will be used to map variable names to field names
131-
in case the variable name differs.
131+
String values will be used to map argument names to field names
132+
in case the argument name differs.
132133
133134
Function values will be used to filter records. The function
134-
will be passed an array of records, the variable name (key)
135-
and the variable value.
135+
will be passed an array of records, the argument name (key)
136+
and the argument value.
136137
*/
137-
varsMap: {
138+
argsMap: {
138139
Person: { // variables are mapped on a per-type basis
139140
pageSize: (records, _, pageSize) => records.slice(0, pageSize)
140141
}

addon/fields/args.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
export const getArgsForField = (field) =>
22
field.arguments.map(({ name, value }) => ({
33
kind: value.kind,
4-
name: value.name && value.name.value || name.value,
5-
value: value.value
4+
name: name.value,
5+
value: value.value,
6+
variableName: value.name && value.name.value
67
}));
8+
9+
10+
export const resolveArgName = (name, argsMap = {}) =>
11+
name in argsMap ? argsMap[name] : name;

addon/filter/create.js

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,37 @@
11
import Filter from './model';
22
import sortFilters from './sort';
33
import { isFunction, partial } from '../utils';
4-
import { resolveVarName } from './vars';
4+
import { resolveArgName } from '../fields/args';
55
import { set, setProperties } from '@ember/object';
66
import { spliceRelayFilters } from '../relay/filters';
77

8-
export const composeMapArgsToFilters = (resolveVarName) =>
9-
(vars, varsMapForType = {}, { kind, name, value }) => {
8+
export const composeMapArgsToFilters = (resolveArgName) =>
9+
(vars, argsMapForType = {}, { kind, name, value, variableName }) => {
1010
let filter = Filter.create({ name, value });
11+
let resolvedName = resolveArgName(name, argsMapForType);
1112

12-
if (kind === 'Variable') {
13-
let resolvedName = resolveVarName(name, varsMapForType);
14-
15-
filter.set('value', vars[name]);
13+
isFunction(resolvedName)
14+
? setProperties(filter, { hasFnValue: true, fn: resolvedName })
15+
: set(filter, 'resolvedName', resolvedName);
1616

17-
isFunction(resolvedName)
18-
? setProperties(filter, { hasFnValue: true, fn: resolvedName })
19-
: set(filter, 'resolvedName', resolvedName);
17+
if (kind === 'Variable') {
18+
filter.set('value', vars[variableName]);
2019
}
2120

2221
return filter;
2322
};
2423

25-
const mapArgsToFilters = composeMapArgsToFilters(resolveVarName);
24+
const mapArgsToFilters = composeMapArgsToFilters(resolveArgName);
2625

27-
const createFiltersByArgs = (args, vars, varsMap) =>
28-
args.map(partial(mapArgsToFilters, vars, varsMap));
26+
const createFiltersByArgs = (args, vars, argsMap) =>
27+
args.map(partial(mapArgsToFilters, vars, argsMap));
2928

3029
export const composeCreateFilters =
3130
(createFiltersByArgs, sortFilters, spliceRelayFilters) =>
32-
(field, vars, { varsMap = {} } = {}) => {
31+
(field, vars, { argsMap = {} } = {}) => {
3332
let { args, type } = field;
34-
let varsMapForType = varsMap[type.name];
35-
let filters = createFiltersByArgs(args, vars, varsMapForType)
33+
let argsMapForType = argsMap[type.name];
34+
let filters = createFiltersByArgs(args, vars, argsMapForType)
3635
.sort(sortFilters);
3736

3837
if (field.isRelayEdges) {

addon/filter/vars.js

Lines changed: 0 additions & 2 deletions
This file was deleted.

addon/handler.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
addInterfaceTypeResolversToSchema,
44
createSchema
55
} from './schema';
6+
import { deprecate } from '@ember/debug';
67
import { graphql } from 'graphql';
78

89
export const composeCreateGraphQLHandler =
@@ -12,6 +13,20 @@ export const composeCreateGraphQLHandler =
1213
let { query, variables } = parseRequest(request.requestBody);
1314
let schema = createSchema(rawSchema);
1415

16+
if (options.varsMap) {
17+
deprecate('ember-cli-mirage-graphql varsMap is deprecated, please use argsMap instead', false, {
18+
id: 'ember-cli-mirage-graphql.vars-map',
19+
until: '1.0.0',
20+
url: 'https://github.com/kloeckner-i/ember-cli-mirage-graphql/blob/master/DEPRECATIONS.md'
21+
});
22+
23+
if (!options.argsMap) {
24+
options.argsMap = options.varsMap;
25+
}
26+
27+
delete options.varsMap;
28+
}
29+
1530
addMocksToSchema(schema, db, options);
1631
addInterfaceTypeResolversToSchema(schema);
1732

addon/mocks/mutation.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
import { contextSet, isFunction, reduceKeys, unwrapNonNull } from '../utils';
22
import { getRecords } from '../db';
3-
import { resolveVarName } from '../filter/vars';
3+
import { resolveArgName } from '../fields/args';
44

5-
export const composeMapVars = (resolveVarName) =>
6-
(vars, varsMap = {}) =>
7-
reduceKeys(vars, (mappedVars, key) =>
8-
contextSet(mappedVars, resolveVarName(key, varsMap), vars[key]), {});
5+
export const composeMapArgs = (resolveArgName) =>
6+
(args, argsMap = {}) =>
7+
reduceKeys(args, (mappedArgs, key) =>
8+
contextSet(mappedArgs, resolveArgName(key, argsMap), args[key]), {});
99

10-
const mapVars = composeMapVars(resolveVarName);
10+
const mapArgs = composeMapArgs(resolveArgName);
1111

12-
export const composeMockMutation = (getRecords, mapVars) =>
13-
(db, options = {}, _, vars, __, { fieldName, returnType }) => {
12+
export const composeMockMutation = (getRecords, mapArgs) =>
13+
(db, options = {}, _, args, __, { fieldName, returnType }) => {
1414
returnType = unwrapNonNull(returnType);
1515

16-
let { mutations = {}, varsMap = {} } = options;
16+
let { mutations = {}, argsMap = {} } = options;
1717
let mutation = mutations[fieldName];
1818
let records = getRecords(db, returnType.name);
1919

2020
if (isFunction(mutation)) {
21-
let mappedVars = mapVars(vars, varsMap[returnType.name]);
21+
let mappedArgs = mapArgs(args, argsMap[returnType.name]);
2222

23-
records = mutation(records, mappedVars, db);
23+
records = mutation(records, mappedArgs, db);
2424
}
2525

2626
return records;
2727
};
2828

29-
const mockMutation = composeMockMutation(getRecords, mapVars);
29+
const mockMutation = composeMockMutation(getRecords, mapArgs);
3030

3131
export default mockMutation;

addon/mocks/query.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import { partial } from '../utils';
77

88
export const composeMockQuery =
99
(getTypeForField, getFieldNameAndAlias, createFieldInfo, resolveFieldInfo, getIsInterface, logError) =>
10-
(db, options, _, vars, __, { fieldNodes, fragments, returnType, schema }) => {
10+
(db, options, _, __, ___, info) => {
11+
const { fieldNodes, fragments, returnType, schema, variableValues } = info;
12+
1113
try {
1214
let getType = partial(getTypeForField, schema._typeMap);
1315
let [rootField] = fieldNodes;
@@ -19,7 +21,7 @@ export const composeMockQuery =
1921
[rootFieldName]: createFieldInfo(rootField, fieldInfoName, returnType,
2022
fragments, getType)
2123
};
22-
let records = resolveFieldInfo(fieldInfo, db, vars, options);
24+
let records = resolveFieldInfo(fieldInfo, db, variableValues, options);
2325

2426
return isInterface ? records : records[fieldName];
2527
} catch(ex) {

tests/acceptance/variables-test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { module, test } from 'qunit';
2+
import { setupApplicationTest } from 'ember-qunit';
3+
import { visit } from '@ember/test-helpers';
4+
5+
module('Acceptance | variables', function(hooks) {
6+
setupApplicationTest(hooks);
7+
8+
test('variable values are passed correctly at multiple depths', async function(assert) {
9+
let person = this.server.create('person', { firstName: 'Alice', surname: 'Example' });
10+
11+
this.server.create('animal', { person, type: 'dog', name: 'Bob' });
12+
this.server.create('animal', { person, type: 'dog', name: 'Alice' });
13+
14+
await visit('/people/same-name-as-pets');
15+
16+
assert.dom('h2').containsText('Alice');
17+
assert.dom('li').containsText('Alice');
18+
assert.dom('li').doesNotContainText('Bob');
19+
});
20+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
query PeopleSameNameAsPets($name: String!) {
2+
people(firstName: $name) {
3+
firstName
4+
lastName
5+
pets(name: $name) {
6+
name
7+
}
8+
}
9+
}

0 commit comments

Comments
 (0)