diff --git a/src/schema/typeDefs/breed.graphql b/src/schema/typeDefs/breed.graphql index 6dd6b16..75911d0 100644 --- a/src/schema/typeDefs/breed.graphql +++ b/src/schema/typeDefs/breed.graphql @@ -8,10 +8,10 @@ extend type Query { """ breeds( "breed species" - species: String! + species: String "language code" language: String! - ): [Breed] + ): [BreedWithSpecies] } "Represents a breed." @@ -23,3 +23,17 @@ type Breed { "Breed name" value: String! } + +"Represents a breed with species." +type BreedWithSpecies { + "Breed id" + id: Int! + "Breed abbreviation" + abbreviation: String! + "Breed name" + value: String! + "Species id" + speciesId: Int! + "Species name" + speciesValue: String! +} diff --git a/src/sql-queries/breed.ts b/src/sql-queries/breed.ts index 8afb09e..6458632 100644 --- a/src/sql-queries/breed.ts +++ b/src/sql-queries/breed.ts @@ -1,24 +1,28 @@ import { QueryConfig } from 'pg'; +import { select } from 'sql-bricks-postgres'; export const getBreedsQuery = ( - species: string, + species: string | null | undefined, language: string ): QueryConfig => { - const text = ` - SELECT - id, - abbreviation, - translation as value - FROM breed b - LEFT JOIN (SELECT * FROM breed_translation WHERE language = $2) bt - ON bt.breed = b.id - WHERE species = $1; - `; - return { - text, - values: [ species, language ] - }; + let filteredBreedsQuery = select().from('breed'); + filteredBreedsQuery = species ? filteredBreedsQuery.where({ species }) + : filteredBreedsQuery; + + const query = select(` + b.id, + b.abbreviation, + bt.translation as value, + b.species as species_id, + st.translation as species_value`) + .from(`(${filteredBreedsQuery}) as b`) + .leftJoin(`(${select().from('breed_translation').where({ language })}) AS bt`) + .on('b.id', 'bt.breed') + .leftJoin(`(${select().from('species_translation').where({ language })}) AS st`) + .on('b.species', 'st.species'); + + return query.toParams(); }; export const getBreedQuery = ( @@ -38,6 +42,6 @@ export const getBreedQuery = ( return { text, - values: [ breed_id, language, defaultLanguage ] - } + values: [breed_id, language, defaultLanguage] + }; }; diff --git a/test/animal.graphql.test.ts b/test/animal.graphql.test.ts index f29363d..8b63e8d 100644 --- a/test/animal.graphql.test.ts +++ b/test/animal.graphql.test.ts @@ -9,7 +9,6 @@ import validateAnimalConnection import requests from './utils/requests'; - const animalFields = ` { id diff --git a/test/breed.graphql.test.ts b/test/breed.graphql.test.ts index d1cbfd2..08740cb 100644 --- a/test/breed.graphql.test.ts +++ b/test/breed.graphql.test.ts @@ -1,36 +1,40 @@ import { expect } from 'chai'; -import supertest from 'supertest'; -import validate from './validators/breed.interface.validator'; - -require('dotenv').config({ path: './test/.env' }); - -const url = process.env.TEST_URL || 'http://localhost:8081'; -const request = supertest(url); +import validate from './validators/breedWithSpecies.interface.validator'; +import requests from './utils/requests'; const breedFields = ` { id abbreviation value + speciesId + speciesValue } `; describe('GraphQL breed integration tests', () => { - it('Returns all breeds translation in "lt" with all fields', (done) => { - let req = request - .post('/graphql') - .send({ - query: `{ breeds(species: "2", language: "lt") + it('Returns breeds translation in "lt" with all fields filtered by species ', (done) => { + const req = requests(`{ breeds(species: "2", language: "lt") ${breedFields} - }`, + }`); + req.expect(200) + .end((err, res) => { + if (err) return done(err); + const { body: { data: { breeds } } } = res; + expect(breeds).to.be.an('array'); + validate(breeds[0]); + return done(); }); - if (process.env.BEARER_TOKEN) { - req = req.set('authorization', `Bearer ${process.env.BEARER_TOKEN}`) - } + }); + + it('Returns all breeds translation in "lt" with all fields', (done) => { + const req = requests(`{ breeds(language: "lt") + ${breedFields} + }`); req.expect(200) .end((err, res) => { if (err) return done(err); - const { body: {data: { breeds } } } = res; + const { body: { data: { breeds } } } = res; expect(breeds).to.be.an('array'); validate(breeds[0]); return done(); diff --git a/test/interfaces/breedWithSpecies.interface.ts b/test/interfaces/breedWithSpecies.interface.ts new file mode 100644 index 0000000..ffa40f7 --- /dev/null +++ b/test/interfaces/breedWithSpecies.interface.ts @@ -0,0 +1,7 @@ +export default interface BreedWithSpecies { + id: number; + abbreviation: string; + value: string; + speciesId: number; + speciesValue: string; +} diff --git a/test/validators/breed.interface.validator.ts b/test/validators/breed.interface.validator.ts index 9a0e1dc..019f823 100644 --- a/test/validators/breed.interface.validator.ts +++ b/test/validators/breed.interface.validator.ts @@ -1,8 +1,9 @@ /* tslint:disable */ // generated by typescript-json-validator -import {inspect} from 'util'; -import Ajv = require('ajv'); +import { inspect } from 'util'; import Breed from '../interfaces/breed.interface'; +import Ajv = require('ajv'); + export const ajv = new Ajv({"allErrors":true,"coerceTypes":false,"format":"fast","nullable":true,"unicode":true,"uniqueItems":true,"useDefaults":true}); ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json')); diff --git a/test/validators/breedWithSpecies.interface.validator.ts b/test/validators/breedWithSpecies.interface.validator.ts new file mode 100644 index 0000000..2dcb7db --- /dev/null +++ b/test/validators/breedWithSpecies.interface.validator.ts @@ -0,0 +1,54 @@ +/* tslint:disable */ +// generated by typescript-json-validator +import { inspect } from 'util'; +import BreedWithSpecies from '../interfaces/breedWithSpecies.interface'; +import Ajv = require('ajv'); + +export const ajv = new Ajv({"allErrors":true,"coerceTypes":false,"format":"fast","nullable":true,"unicode":true,"uniqueItems":true,"useDefaults":true}); + +ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json')); + +export {BreedWithSpecies}; +export const BreedWithSpeciesSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "defaultProperties": [ + ], + "properties": { + "abbreviation": { + "type": "string" + }, + "id": { + "type": "number" + }, + "speciesId": { + "type": "number" + }, + "speciesValue": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "abbreviation", + "id", + "speciesId", + "speciesValue", + "value" + ], + "type": "object" +}; +export type ValidateFunction = ((data: unknown) => data is T) & Pick +export const isBreedWithSpecies = ajv.compile(BreedWithSpeciesSchema) as ValidateFunction; +export default function validate(value: unknown): BreedWithSpecies { + if (isBreedWithSpecies(value)) { + return value; + } else { + throw new Error( + ajv.errorsText(isBreedWithSpecies.errors!.filter((e: any) => e.keyword !== 'if'), {dataVar: 'BreedWithSpecies'}) + + '\n\n' + + inspect(value), + ); + } +}