Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions DEPRECATIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Deprecations

## varsMap (since 0.0.9)

This option has been renamed to `argsMap` and now explicitly provides support
for custom mapping of *argument* names in filters and mutations (rather than
*variable* names).
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ You may pass in options when creating a request handler. The options take the fo

1. The table from Mirage's database that corresponds to the return
type of the mutation.
2. The mutation variables. These will be mapped per the varsMap
2. The mutation arguments. These will be mapped per the argsMap
option, by the return type, if appropriate.
3. Mirage's database.

Expand All @@ -113,28 +113,29 @@ You may pass in options when creating a request handler. The options take the fo
functionality, if feasible.
*/
mutations: {
updatePerson: (people, vars, db) => {
let { id, personAttributes } = vars;
updatePerson: (people, args, db) => {
let { id, personAttributes } = args;

return [ people.update(id, personAttributes) ];
}
},
/*
varsMap is used if you need to map request variables defined
in your GraphQL queries. The value you specify in the map can
be a string or a function.
argsMap is used if you need to map arguments defined in your GraphQL
queries to something other than the corresponding field name on the
mirage record. The value you specify in the map can be a string or a
function.

The addon uses the variables to filter records of the given
type from Mirage's database.

String values will be used to map variable names to field names
in case the variable name differs.
String values will be used to map argument names to field names
in case the argument name differs.

Function values will be used to filter records. The function
will be passed an array of records, the variable name (key)
and the variable value.
will be passed an array of records, the argument name (key)
and the argument value.
*/
varsMap: {
argsMap: {
Person: { // variables are mapped on a per-type basis
pageSize: (records, _, pageSize) => records.slice(0, pageSize)
}
Expand Down
9 changes: 7 additions & 2 deletions addon/fields/args.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
export const getArgsForField = (field) =>
field.arguments.map(({ name, value }) => ({
kind: value.kind,
name: value.name && value.name.value || name.value,
value: value.value
name: name.value,
value: value.value,
variableName: value.name && value.name.value
}));


export const resolveArgName = (name, argsMap = {}) =>
name in argsMap ? argsMap[name] : name;
31 changes: 15 additions & 16 deletions addon/filter/create.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,37 @@
import Filter from './model';
import sortFilters from './sort';
import { isFunction, partial } from '../utils';
import { resolveVarName } from './vars';
import { resolveArgName } from '../fields/args';
import { set, setProperties } from '@ember/object';
import { spliceRelayFilters } from '../relay/filters';

export const composeMapArgsToFilters = (resolveVarName) =>
(vars, varsMapForType = {}, { kind, name, value }) => {
export const composeMapArgsToFilters = (resolveArgName) =>
(vars, argsMapForType = {}, { kind, name, value, variableName }) => {
let filter = Filter.create({ name, value });
let resolvedName = resolveArgName(name, argsMapForType);

if (kind === 'Variable') {
let resolvedName = resolveVarName(name, varsMapForType);

filter.set('value', vars[name]);
isFunction(resolvedName)
? setProperties(filter, { hasFnValue: true, fn: resolvedName })
: set(filter, 'resolvedName', resolvedName);

isFunction(resolvedName)
? setProperties(filter, { hasFnValue: true, fn: resolvedName })
: set(filter, 'resolvedName', resolvedName);
if (kind === 'Variable') {
filter.set('value', vars[variableName]);
}

return filter;
};

const mapArgsToFilters = composeMapArgsToFilters(resolveVarName);
const mapArgsToFilters = composeMapArgsToFilters(resolveArgName);

const createFiltersByArgs = (args, vars, varsMap) =>
args.map(partial(mapArgsToFilters, vars, varsMap));
const createFiltersByArgs = (args, vars, argsMap) =>
args.map(partial(mapArgsToFilters, vars, argsMap));

export const composeCreateFilters =
(createFiltersByArgs, sortFilters, spliceRelayFilters) =>
(field, vars, { varsMap = {} } = {}) => {
(field, vars, { argsMap = {} } = {}) => {
let { args, type } = field;
let varsMapForType = varsMap[type.name];
let filters = createFiltersByArgs(args, vars, varsMapForType)
let argsMapForType = argsMap[type.name];
let filters = createFiltersByArgs(args, vars, argsMapForType)
.sort(sortFilters);

if (field.isRelayEdges) {
Expand Down
2 changes: 0 additions & 2 deletions addon/filter/vars.js

This file was deleted.

15 changes: 15 additions & 0 deletions addon/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
addInterfaceTypeResolversToSchema,
createSchema
} from './schema';
import { deprecate } from '@ember/debug';
import { graphql } from 'graphql';

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

if (options.varsMap) {
deprecate('ember-cli-mirage-graphql varsMap is deprecated, please use argsMap instead', false, {
id: 'ember-cli-mirage-graphql.vars-map',
until: '1.0.0',
url: 'https://github.com/kloeckner-i/ember-cli-mirage-graphql/blob/master/DEPRECATIONS.md'
});

if (!options.argsMap) {
options.argsMap = options.varsMap;
}

delete options.varsMap;
}

addMocksToSchema(schema, db, options);
addInterfaceTypeResolversToSchema(schema);

Expand Down
24 changes: 12 additions & 12 deletions addon/mocks/mutation.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
import { contextSet, isFunction, reduceKeys, unwrapNonNull } from '../utils';
import { getRecords } from '../db';
import { resolveVarName } from '../filter/vars';
import { resolveArgName } from '../fields/args';

export const composeMapVars = (resolveVarName) =>
(vars, varsMap = {}) =>
reduceKeys(vars, (mappedVars, key) =>
contextSet(mappedVars, resolveVarName(key, varsMap), vars[key]), {});
export const composeMapArgs = (resolveArgName) =>
(args, argsMap = {}) =>
reduceKeys(args, (mappedArgs, key) =>
contextSet(mappedArgs, resolveArgName(key, argsMap), args[key]), {});

const mapVars = composeMapVars(resolveVarName);
const mapArgs = composeMapArgs(resolveArgName);

export const composeMockMutation = (getRecords, mapVars) =>
(db, options = {}, _, vars, __, { fieldName, returnType }) => {
export const composeMockMutation = (getRecords, mapArgs) =>
(db, options = {}, _, args, __, { fieldName, returnType }) => {
returnType = unwrapNonNull(returnType);

let { mutations = {}, varsMap = {} } = options;
let { mutations = {}, argsMap = {} } = options;
let mutation = mutations[fieldName];
let records = getRecords(db, returnType.name);

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

records = mutation(records, mappedVars, db);
records = mutation(records, mappedArgs, db);
}

return records;
};

const mockMutation = composeMockMutation(getRecords, mapVars);
const mockMutation = composeMockMutation(getRecords, mapArgs);

export default mockMutation;
6 changes: 4 additions & 2 deletions addon/mocks/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import { partial } from '../utils';

export const composeMockQuery =
(getTypeForField, getFieldNameAndAlias, createFieldInfo, resolveFieldInfo, getIsInterface, logError) =>
(db, options, _, vars, __, { fieldNodes, fragments, returnType, schema }) => {
(db, options, _, __, ___, info) => {
const { fieldNodes, fragments, returnType, schema, variableValues } = info;

try {
let getType = partial(getTypeForField, schema._typeMap);
let [rootField] = fieldNodes;
Expand All @@ -19,7 +21,7 @@ export const composeMockQuery =
[rootFieldName]: createFieldInfo(rootField, fieldInfoName, returnType,
fragments, getType)
};
let records = resolveFieldInfo(fieldInfo, db, vars, options);
let records = resolveFieldInfo(fieldInfo, db, variableValues, options);

return isInterface ? records : records[fieldName];
} catch(ex) {
Expand Down
20 changes: 20 additions & 0 deletions tests/acceptance/variables-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { visit } from '@ember/test-helpers';

module('Acceptance | variables', function(hooks) {
setupApplicationTest(hooks);

test('variable values are passed correctly at multiple depths', async function(assert) {
let person = this.server.create('person', { firstName: 'Alice', surname: 'Example' });

this.server.create('animal', { person, type: 'dog', name: 'Bob' });
this.server.create('animal', { person, type: 'dog', name: 'Alice' });

await visit('/people/same-name-as-pets');

assert.dom('h2').containsText('Alice');
assert.dom('li').containsText('Alice');
assert.dom('li').doesNotContainText('Bob');
});
});
9 changes: 9 additions & 0 deletions tests/dummy/app/gql/queries/people-same-name-as-pets.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
query PeopleSameNameAsPets($name: String!) {
people(firstName: $name) {
firstName
lastName
pets(name: $name) {
name
}
}
}
2 changes: 1 addition & 1 deletion tests/dummy/app/gql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type Person {
age: Int!
firstName: String!
lastName: String!
pets: [Pet]
pets(name: String): [Pet]
}

input PersonAttributes {
Expand Down
1 change: 1 addition & 0 deletions tests/dummy/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Router.map(function() {
this.route('customer', { path: '/customer/:customer_id' });
this.route('people', function() {
this.route('same-age-as-dog-years');
this.route('same-name-as-pets');
});
this.route('person', { path: '/person/:person_id' }, function() {
this.route('edit');
Expand Down
15 changes: 15 additions & 0 deletions tests/dummy/app/routes/people/same-name-as-pets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Route from '@ember/routing/route';
import query from 'dummy/gql/queries/people-same-name-as-pets';
import { inject as service } from '@ember/service';

export default Route.extend({
apollo: service(),

async model() {

let variables = { name: 'Alice' };
let model = await this.get('apollo').watchQuery({ query, variables });

return model;
}
});
8 changes: 8 additions & 0 deletions tests/dummy/app/templates/people/same-name-as-pets.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{{#each this.model.people as |person|}}
<h2>{{person.firstName}} {{person.lastName}}</h2>
<ul>
{{#each person.pets as |pet|}}
<li>{{pet.name}}</li>
{{/each}}
</ul>
{{/each}}
2 changes: 1 addition & 1 deletion tests/dummy/mirage/handlers/graphql.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const OPTIONS = {
updatePerson: (people, { id, personAttributes }) =>
people.update(id, adaptPersonAttrs(personAttributes))
},
varsMap: {
argsMap: {
Person: {
pageSize: (people, variableName, pageSize) => people.slice(0, pageSize),
lastName: 'surname'
Expand Down
18 changes: 15 additions & 3 deletions tests/unit/fields/args-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getArgsForField } from 'ember-cli-mirage-graphql/fields/args';
import { getArgsForField, resolveArgName } from 'ember-cli-mirage-graphql/fields/args';
import { module, test } from 'qunit';

module('Unit | Fields | args', function() {
Expand All @@ -11,6 +11,7 @@ module('Unit | Fields | args', function() {
};
let fieldWithVariableArgs = {
arguments: [{
name: { value: 'foo' },
value: { kind: 'Variable', name: { value: 'bar' } }
}]
};
Expand All @@ -19,10 +20,21 @@ module('Unit | Fields | args', function() {
assert.deepEqual(getArgsForField(noArgsField), [],
'It can handle a field with no args');
assert.deepEqual(getArgsForField(fieldWithStaticArgs),
[{ kind: 'Int', name: 'foo', value: 1 }],
[{ kind: 'Int', name: 'foo', value: 1, variableName: undefined }],
'It works with static value args');
assert.deepEqual(getArgsForField(fieldWithVariableArgs),
[{ kind: 'Variable', name: 'bar', value: undefined }],
[{ kind: 'Variable', name: 'foo', value: undefined, variableName: 'bar' }],
'It works with variable value args');
});

test('it can get a mapped arg name', function(assert) {
let argsMap = { foo: 'bar' };

assert.equal(resolveArgName('foo', argsMap), argsMap.foo,
'It resolved the mapped name');
});

test('it resolves arg name, if not mapped', function(assert) {
assert.equal(resolveArgName('foo'), 'foo', 'It resolved the name');
});
});
4 changes: 2 additions & 2 deletions tests/unit/filter/create-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ module('Unit | Filter | create', function() {
module('args', function() {
test('it creates a filter', function(assert) {
let arg = { name: 'foo', value: 'bar' };
let mapArgsToFilters = composeMapArgsToFilters();
let mapArgsToFilters = composeMapArgsToFilters(x => x);
let filter = mapArgsToFilters(null, null, arg);

assert.equal(filter.name, arg.name, 'It mapped the name');
assert.equal(filter.value, arg.value, 'It mapped the value');
});

test('it creates a filter with a function value', function(assert) {
let arg = { kind: 'Variable', name: 'foo' };
let arg = { kind: 'Variable', name: 'foo', variableName: 'foo' };
let fn = () => {};
let mapArgsToFilters = composeMapArgsToFilters(() => fn);
let vars = { foo: 'bar' };
Expand Down
15 changes: 0 additions & 15 deletions tests/unit/filter/vars-test.js

This file was deleted.

6 changes: 3 additions & 3 deletions tests/unit/mocks/mutation-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { composeMapVars, composeMockMutation } from
import { composeMapArgs, composeMockMutation } from
'ember-cli-mirage-graphql/mocks/mutation';
import { module, test } from 'qunit';

Expand Down Expand Up @@ -37,8 +37,8 @@ module('Unit | Mocks | mutation', function() {
let mappedKey = 'bar';
let value = 'baz';
let vars = { [key]: value };
let resolveVarName = () => mappedKey;
let mapVars = composeMapVars(resolveVarName);
let resolveArgName = () => mappedKey;
let mapVars = composeMapArgs(resolveArgName);
let mappedVars = mapVars(vars);

assert.deepEqual(mappedVars, { [mappedKey]: value }, 'It mapped the vars');
Expand Down