graphql-constraint-directive
Advanced tools
Comparing version 2.0.3 to 2.1.0
12
index.js
@@ -11,5 +11,10 @@ const { GraphQLFloat, GraphQLInt, GraphQLString, GraphQLNonNull, isNonNullType, isScalarType } = require('graphql') | ||
// Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ as per graphql-js | ||
const uniqueTypeName = `${fieldName}_${type.name}_${notNull ? 'NotNull_' : ''}` + Object.entries(directiveArgumentMap) | ||
.map(([key, value]) => `${key}_${value.toString().replace(/\W/g, '')}`) | ||
.join('_') | ||
let uniqueTypeName | ||
if (directiveArgumentMap.uniqueTypeName) { | ||
uniqueTypeName = directiveArgumentMap.uniqueTypeName.replace(/\W/g, '') | ||
} else { | ||
uniqueTypeName = `${fieldName}_${type.name}_${notNull ? 'NotNull_' : ''}` + Object.entries(directiveArgumentMap) | ||
.map(([key, value]) => `${key}_${value.toString().replace(/\W/g, '')}`) | ||
.join('_') | ||
} | ||
const key = Symbol.for(uniqueTypeName) | ||
@@ -90,4 +95,5 @@ let constraintType = constraintTypes[key] | ||
multipleOf: Int | ||
uniqueTypeName: String | ||
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION` | ||
module.exports = { constraintDirective, constraintDirectiveTypeDefs } |
{ | ||
"name": "graphql-constraint-directive", | ||
"version": "2.0.3", | ||
"version": "2.1.0", | ||
"description": "Validate GraphQL fields", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -132,1 +132,4 @@ # graphql-constraint-directive | ||
``` | ||
### uniqueTypeName | ||
```@constraint(uniqueTypeName: "Unique_Type_Name")``` | ||
Override the unique type name generate by the library to the one passed as an argument |
@@ -358,2 +358,61 @@ const { deepStrictEqual, strictEqual } = require('assert') | ||
}) | ||
describe('#uniqueTypeName', function () { | ||
before(function () { | ||
this.typeDefs = ` | ||
type Query { | ||
books: [Book] | ||
} | ||
type Book { | ||
title: String | ||
} | ||
type Mutation { | ||
createBook(input: BookInput): Book | ||
} | ||
input BookInput { | ||
title: Int! @constraint(min: 3, uniqueTypeName: "BookInput_Title") | ||
}` | ||
this.request = setup(this.typeDefs) | ||
}) | ||
it('should pass', async function () { | ||
const { body, statusCode } = await this.request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query, variables: { input: { title: 3 } } | ||
}) | ||
strictEqual(statusCode, 200) | ||
deepStrictEqual(body, { data: { createBook: null } }) | ||
}) | ||
it('should fail', async function () { | ||
const { body, statusCode } = await this.request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query, variables: { input: { title: 2 } } | ||
}) | ||
strictEqual(statusCode, 400) | ||
strictEqual(body.errors[0].message, | ||
'Variable "$input" got invalid value 2 at "input.title"; Expected type "BookInput_Title". Must be at least 3') | ||
}) | ||
it('should throw custom error', async function () { | ||
const request = setup(this.typeDefs, formatError) | ||
const { body, statusCode } = await request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query, variables: { input: { title: 2 } } }) | ||
strictEqual(statusCode, 400) | ||
deepStrictEqual(body.errors[0], { | ||
message: 'Must be at least 3', | ||
code: 'ERR_GRAPHQL_CONSTRAINT_VALIDATION', | ||
fieldName: 'title', | ||
context: [{ arg: 'min', value: 3 }] | ||
}) | ||
}) | ||
}) | ||
}) | ||
@@ -794,2 +853,56 @@ | ||
}) | ||
describe('#uniqueTypeName', function () { | ||
before(function () { | ||
this.typeDefs = ` | ||
type Query { | ||
books: [Book] | ||
} | ||
type Book { | ||
title: Int @constraint(min: 2, uniqueTypeName: "Book_Title") | ||
} | ||
` | ||
}) | ||
it('should pass', async function () { | ||
const mockData = [{title: 2}, {title: 3}] | ||
const request = setup(this.typeDefs, formatError, resolvers(mockData)) | ||
const { body, statusCode } = await request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query }) | ||
strictEqual(statusCode, 200) | ||
deepStrictEqual(body, { data: { books: mockData } }) | ||
}) | ||
it('should fail', async function () { | ||
const mockData = [{title: 1}, {title: 2}] | ||
const request = setup(this.typeDefs, formatError, resolvers(mockData)) | ||
const { body, statusCode } = await request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query }) | ||
strictEqual(statusCode, 200) | ||
strictEqual(body.errors[0].message, 'Must be at least 2') | ||
}) | ||
it('should throw custom error', async function () { | ||
const mockData = [{title: 1}, {title: 2}] | ||
const request = setup(this.typeDefs, formatError, resolvers(mockData)) | ||
const { body, statusCode } = await request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query }) | ||
strictEqual(statusCode, 200) | ||
deepStrictEqual(body.errors[0], { | ||
message: 'Must be at least 2', | ||
code: 'ERR_GRAPHQL_CONSTRAINT_VALIDATION', | ||
fieldName: 'title', | ||
context: [{ arg: 'min', value: 2 }] | ||
}) | ||
}) | ||
}) | ||
}) |
@@ -1,2 +0,2 @@ | ||
const { strictEqual } = require('assert') | ||
const { strictEqual, notEqual } = require('assert') | ||
const { getIntrospectionQuery } = require('graphql') | ||
@@ -19,3 +19,3 @@ const setup = require('./setup') | ||
title: String! @constraint(minLength: 3 maxLength: 5) | ||
subTitle: Int! @constraint(max: 3) | ||
subTitle: Int! @constraint(max: 3, uniqueTypeName: "BookInput_subTitle") | ||
}` | ||
@@ -33,7 +33,17 @@ | ||
strictEqual(statusCode, 200) | ||
const directive = body.data.__schema.directives.find(v => v.name === 'constraint') | ||
strictEqual(directive.args.length, 14) | ||
strictEqual(directive.args.length, 13) | ||
const type = body.data.__schema.types.find(t => t.name === 'BookInput_subTitle') | ||
notEqual(type, null) | ||
}) | ||
it('should allow unique type names to be added', async function () { | ||
const { body } = await this.request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query: getIntrospectionQuery() }) | ||
const type = body.data.__schema.types.find(t => t.name === 'BookInput_subTitle') | ||
notEqual(type, null) | ||
}) | ||
}) |
@@ -1010,2 +1010,61 @@ const { deepStrictEqual, strictEqual } = require('assert') | ||
}) | ||
describe('#uniqueTypeName', function () { | ||
before(function () { | ||
this.typeDefs = ` | ||
type Query { | ||
books: [Book] | ||
} | ||
type Book { | ||
title: String | ||
} | ||
type Mutation { | ||
createBook(input: BookInput): Book | ||
} | ||
input BookInput { | ||
title: String! @constraint(minLength: 3, uniqueTypeName: "BookInput_Title") | ||
}` | ||
this.request = setup(this.typeDefs) | ||
}) | ||
it('should pass', async function () { | ||
const { body, statusCode } = await this.request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query, variables: { input: { title: 'he💩' } } | ||
}) | ||
strictEqual(statusCode, 200) | ||
deepStrictEqual(body, { data: { createBook: null } }) | ||
}) | ||
it('should fail', async function () { | ||
const { body, statusCode } = await this.request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query, variables: { input: { title: 'a💩' } } | ||
}) | ||
strictEqual(statusCode, 400) | ||
strictEqual(body.errors[0].message, | ||
'Variable "$input" got invalid value "a💩" at "input.title"; Expected type "BookInput_Title". Must be at least 3 characters in length') | ||
}) | ||
it('should throw custom error', async function () { | ||
const request = setup(this.typeDefs, formatError) | ||
const { body, statusCode } = await request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query, variables: { input: { title: 'a💩' } } }) | ||
strictEqual(statusCode, 400) | ||
deepStrictEqual(body.errors[0], { | ||
message: 'Must be at least 3 characters in length', | ||
code: 'ERR_GRAPHQL_CONSTRAINT_VALIDATION', | ||
fieldName: 'title', | ||
context: [{ arg: 'minLength', value: 3 }] | ||
}) | ||
}) | ||
}) | ||
}) | ||
@@ -1866,2 +1925,55 @@ | ||
}) | ||
describe('#uniqueTypeName', function () { | ||
before(function () { | ||
this.typeDefs = ` | ||
type Query { | ||
books: [Book] | ||
} | ||
type Book { | ||
title: String @constraint(minLength: 3, uniqueTypeName: "Book_Title") | ||
}` | ||
}) | ||
it('should pass', async function () { | ||
const mockData = [{title: 'foo'}, {title: 'foobar'}] | ||
const request = setup(this.typeDefs, formatError, resolvers(mockData)) | ||
const { body, statusCode } = await request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query }) | ||
strictEqual(statusCode, 200) | ||
deepStrictEqual(body, { data: { books: mockData } }) | ||
}) | ||
it('should fail', async function () { | ||
const mockData = [{title: 'fo'}, {title: 'foo'}] | ||
const request = setup(this.typeDefs, formatError, resolvers(mockData)) | ||
const { body, statusCode } = await request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query }) | ||
strictEqual(statusCode, 200) | ||
strictEqual(body.errors[0].message, 'Must be at least 3 characters in length') | ||
}) | ||
it('should throw custom error', async function () { | ||
const mockData = [{title: 'fo'}, {title: 'foo'}] | ||
const request = setup(this.typeDefs, formatError, resolvers(mockData)) | ||
const { body, statusCode } = await request | ||
.post('/graphql') | ||
.set('Accept', 'application/json') | ||
.send({ query }) | ||
strictEqual(statusCode, 200) | ||
deepStrictEqual(body.errors[0], { | ||
message: 'Must be at least 3 characters in length', | ||
code: 'ERR_GRAPHQL_CONSTRAINT_VALIDATION', | ||
fieldName: 'title', | ||
context: [{ arg: 'minLength', value: 3 }] | ||
}) | ||
}) | ||
}) | ||
}) |
107224
2844
135