Skip to content

Add 'objectValues' JS util function #1209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 27, 2018
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
18 changes: 18 additions & 0 deletions src/jsutils/objectValues.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import type { ObjMap } from './ObjMap';

declare function objectValues<T>(obj: ObjMap<T>): Array<T>;

/* eslint-disable no-redeclare */
// $FlowFixMe workaround for: https://github.com/facebook/flow/issues/2221
const objectValues =
Object.values || (obj => Object.keys(obj).map(key => obj[key]));
export default objectValues;
12 changes: 4 additions & 8 deletions src/type/introspection.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import isInvalid from '../jsutils/isInvalid';
import objectValues from '../jsutils/objectValues';
import { astFromValue } from '../utilities/astFromValue';
import { print } from '../language/printer';
import {
Expand Down Expand Up @@ -41,8 +42,7 @@ export const __Schema = new GraphQLObjectType({
description: 'A list of all types supported by this server.',
type: GraphQLNonNull(GraphQLList(GraphQLNonNull(__Type))),
resolve(schema) {
const typeMap = schema.getTypeMap();
return Object.keys(typeMap).map(key => typeMap[key]);
return objectValues(schema.getTypeMap());
},
},
queryType: {
Expand Down Expand Up @@ -245,10 +245,7 @@ export const __Type = new GraphQLObjectType({
},
resolve(type, { includeDeprecated }) {
if (isObjectType(type) || isInterfaceType(type)) {
const fieldMap = type.getFields();
let fields = Object.keys(fieldMap).map(
fieldName => fieldMap[fieldName],
);
let fields = objectValues(type.getFields());
if (!includeDeprecated) {
fields = fields.filter(field => !field.deprecationReason);
}
Expand Down Expand Up @@ -292,8 +289,7 @@ export const __Type = new GraphQLObjectType({
type: GraphQLList(GraphQLNonNull(__InputValue)),
resolve(type) {
if (isInputObjectType(type)) {
const fieldMap = type.getFields();
return Object.keys(fieldMap).map(fieldName => fieldMap[fieldName]);
return objectValues(type.getFields());
}
},
},
Expand Down
10 changes: 3 additions & 7 deletions src/type/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { __Schema } from './introspection';
import find from '../jsutils/find';
import instanceOf from '../jsutils/instanceOf';
import invariant from '../jsutils/invariant';
import objectValues from '../jsutils/objectValues';
import type { ObjMap } from '../jsutils/ObjMap';

/**
Expand Down Expand Up @@ -275,10 +276,7 @@ function typeMapReducer(map: TypeMap, type: ?GraphQLType): TypeMap {
}

if (isObjectType(type) || isInterfaceType(type)) {
const fieldMap = type.getFields();
Object.keys(fieldMap).forEach(fieldName => {
const field = fieldMap[fieldName];

objectValues(type.getFields()).forEach(field => {
if (field.args) {
const fieldArgTypes = field.args.map(arg => arg.type);
reducedMap = fieldArgTypes.reduce(typeMapReducer, reducedMap);
Expand All @@ -288,9 +286,7 @@ function typeMapReducer(map: TypeMap, type: ?GraphQLType): TypeMap {
}

if (isInputObjectType(type)) {
const fieldMap = type.getFields();
Object.keys(fieldMap).forEach(fieldName => {
const field = fieldMap[fieldName];
objectValues(type.getFields()).forEach(field => {
reducedMap = typeMapReducer(reducedMap, field.type);
});
}
Expand Down
41 changes: 17 additions & 24 deletions src/type/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { isSchema } from './schema';
import type { GraphQLSchema } from './schema';
import find from '../jsutils/find';
import invariant from '../jsutils/invariant';
import objectValues from '../jsutils/objectValues';
import { GraphQLError } from '../error/GraphQLError';
import type {
ASTNode,
Expand Down Expand Up @@ -232,9 +233,7 @@ function validateName(

function validateTypes(context: SchemaValidationContext): void {
const typeMap = context.schema.getTypeMap();
Object.keys(typeMap).forEach(typeName => {
const type = typeMap[typeName];

objectValues(typeMap).forEach(type => {
// Ensure all provided types are in fact GraphQL type.
if (!isNamedType(type)) {
context.reportError(
Expand Down Expand Up @@ -275,28 +274,25 @@ function validateFields(
context: SchemaValidationContext,
type: GraphQLObjectType | GraphQLInterfaceType,
): void {
const fieldMap = type.getFields();
const fieldNames = Object.keys(fieldMap);
const fields = objectValues(type.getFields());

// Objects and Interfaces both must define one or more fields.
if (fieldNames.length === 0) {
if (fields.length === 0) {
context.reportError(
`Type ${type.name} must define one or more fields.`,
getAllObjectOrInterfaceNodes(type),
);
}

fieldNames.forEach(fieldName => {
const field = fieldMap[fieldName];

fields.forEach(field => {
// Ensure they are named correctly.
validateName(context, field);

// Ensure they were defined at most once.
const fieldNodes = getAllFieldNodes(type, fieldName);
const fieldNodes = getAllFieldNodes(type, field.name);
if (fieldNodes.length > 1) {
context.reportError(
`Field ${type.name}.${fieldName} can only be defined once.`,
`Field ${type.name}.${field.name} can only be defined once.`,
fieldNodes,
);
return; // continue loop
Expand All @@ -305,9 +301,9 @@ function validateFields(
// Ensure the type is an output type
if (!isOutputType(field.type)) {
context.reportError(
`The type of ${type.name}.${fieldName} must be Output Type ` +
`The type of ${type.name}.${field.name} must be Output Type ` +
`but got: ${String(field.type)}.`,
getFieldTypeNode(type, fieldName),
getFieldTypeNode(type, field.name),
);
}

Expand All @@ -322,19 +318,19 @@ function validateFields(
// Ensure they are unique per field.
if (argNames[argName]) {
context.reportError(
`Field argument ${type.name}.${fieldName}(${argName}:) can only ` +
`Field argument ${type.name}.${field.name}(${argName}:) can only ` +
'be defined once.',
getAllFieldArgNodes(type, fieldName, argName),
getAllFieldArgNodes(type, field.name, argName),
);
}
argNames[argName] = true;

// Ensure the type is an input type
if (!isInputType(arg.type)) {
context.reportError(
`The type of ${type.name}.${fieldName}(${argName}:) must be Input ` +
`The type of ${type.name}.${field.name}(${argName}:) must be Input ` +
`Type but got: ${String(arg.type)}.`,
getFieldArgTypeNode(type, fieldName, argName),
getFieldArgTypeNode(type, field.name, argName),
);
}
});
Expand Down Expand Up @@ -537,20 +533,17 @@ function validateInputFields(
context: SchemaValidationContext,
inputObj: GraphQLInputObjectType,
): void {
const fieldMap = inputObj.getFields();
const fieldNames = Object.keys(fieldMap);
const fields = objectValues(inputObj.getFields());

if (fieldNames.length === 0) {
if (fields.length === 0) {
context.reportError(
`Input Object type ${inputObj.name} must define one or more fields.`,
inputObj.astNode,
);
}

// Ensure the arguments are valid
fieldNames.forEach(fieldName => {
const field = fieldMap[fieldName];

fields.forEach(field => {
// Ensure they are named correctly.
validateName(context, field);

Expand All @@ -559,7 +552,7 @@ function validateInputFields(
// Ensure the type is an input type
if (!isInputType(field.type)) {
context.reportError(
`The type of ${inputObj.name}.${fieldName} must be Input Type ` +
`The type of ${inputObj.name}.${field.name} must be Input Type ` +
`but got: ${String(field.type)}.`,
field.astNode && field.astNode.type,
);
Expand Down
10 changes: 5 additions & 5 deletions src/utilities/astFromValue.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { forEach, isCollection } from 'iterall';

import isNullish from '../jsutils/isNullish';
import isInvalid from '../jsutils/isInvalid';
import objectValues from '../jsutils/objectValues';
import type { ValueNode } from '../language/ast';
import { Kind } from '../language/kinds';
import type { GraphQLInputType } from '../type/definition';
Expand Down Expand Up @@ -85,15 +86,14 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode {
if (_value === null || typeof _value !== 'object') {
return null;
}
const fields = type.getFields();
const fields = objectValues(type.getFields());
const fieldNodes = [];
Object.keys(fields).forEach(fieldName => {
const fieldType = fields[fieldName].type;
const fieldValue = astFromValue(_value[fieldName], fieldType);
fields.forEach(field => {
const fieldValue = astFromValue(_value[field.name], field.type);
if (fieldValue) {
fieldNodes.push({
kind: Kind.OBJECT_FIELD,
name: { kind: Kind.NAME, value: fieldName },
name: { kind: Kind.NAME, value: field.name },
value: fieldValue,
});
}
Expand Down
12 changes: 5 additions & 7 deletions src/utilities/schemaPrinter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import isNullish from '../jsutils/isNullish';
import isInvalid from '../jsutils/isInvalid';
import objectValues from '../jsutils/objectValues';
import { astFromValue } from '../utilities/astFromValue';
import { print } from '../language/printer';
import type { GraphQLSchema } from '../type/schema';
Expand Down Expand Up @@ -79,9 +80,8 @@ function printFilteredSchema(
): string {
const directives = schema.getDirectives().filter(directiveFilter);
const typeMap = schema.getTypeMap();
const types = Object.keys(typeMap)
.sort((name1, name2) => name1.localeCompare(name2))
.map(typeName => typeMap[typeName])
const types = objectValues(typeMap)
.sort((type1, type2) => type1.name.localeCompare(type2.name))
.filter(typeFilter);

return (
Expand Down Expand Up @@ -227,8 +227,7 @@ function printEnumValues(values, options): string {
}

function printInputObject(type: GraphQLInputObjectType, options): string {
const fieldMap = type.getFields();
const fields = Object.keys(fieldMap).map(fieldName => fieldMap[fieldName]);
const fields = objectValues(type.getFields());
return (
printDescription(options, type) +
`input ${type.name} {\n` +
Expand All @@ -244,8 +243,7 @@ function printInputObject(type: GraphQLInputObjectType, options): string {
}

function printFields(options, type) {
const fieldMap = type.getFields();
const fields = Object.keys(fieldMap).map(fieldName => fieldMap[fieldName]);
const fields = objectValues(type.getFields());
return fields
.map(
(f, i) =>
Expand Down
15 changes: 7 additions & 8 deletions src/utilities/valueFromAST.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import keyMap from '../jsutils/keyMap';
import isInvalid from '../jsutils/isInvalid';
import objectValues from '../jsutils/objectValues';
import type { ObjMap } from '../jsutils/ObjMap';
import { Kind } from '../language/kinds';
import {
Expand Down Expand Up @@ -116,19 +117,17 @@ export function valueFromAST(
return; // Invalid: intentionally return no value.
}
const coercedObj = Object.create(null);
const fields = type.getFields();
const fieldNodes = keyMap(
(valueNode: ObjectValueNode).fields,
field => field.name.value,
);
const fieldNames = Object.keys(fields);
for (let i = 0; i < fieldNames.length; i++) {
const fieldName = fieldNames[i];
const field = fields[fieldName];
const fieldNode = fieldNodes[fieldName];
const fields = objectValues(type.getFields());
for (let i = 0; i < fields.length; i++) {
const field = fields[i];
const fieldNode = fieldNodes[field.name];
if (!fieldNode || isMissingVariable(fieldNode.value, variables)) {
if (!isInvalid(field.defaultValue)) {
coercedObj[fieldName] = field.defaultValue;
coercedObj[field.name] = field.defaultValue;
} else if (isNonNullType(field.type)) {
return; // Invalid: intentionally return no value.
}
Expand All @@ -138,7 +137,7 @@ export function valueFromAST(
if (isInvalid(fieldValue)) {
return; // Invalid: intentionally return no value.
}
coercedObj[fieldName] = fieldValue;
coercedObj[field.name] = fieldValue;
}
return coercedObj;
}
Expand Down