Skip to content

Commit

Permalink
#303 enhancement for breeds query (#304)
Browse files Browse the repository at this point in the history
* Make species parameter optional. If not specified, return all species breeds

* Create type BreedWithSpecies
  • Loading branch information
pergaliuke authored Nov 24, 2021
1 parent af9ed19 commit a6e54b2
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 39 deletions.
18 changes: 16 additions & 2 deletions src/schema/typeDefs/breed.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ extend type Query {
"""
breeds(
"breed species"
species: String!
species: String
"language code"
language: String!
): [Breed]
): [BreedWithSpecies]
}

"Represents a breed."
Expand All @@ -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!
}
38 changes: 21 additions & 17 deletions src/sql-queries/breed.ts
Original file line number Diff line number Diff line change
@@ -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 = (
Expand All @@ -38,6 +42,6 @@ export const getBreedQuery = (

return {
text,
values: [ breed_id, language, defaultLanguage ]
}
values: [breed_id, language, defaultLanguage]
};
};
1 change: 0 additions & 1 deletion test/animal.graphql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import validateAnimalConnection
import requests from './utils/requests';



const animalFields = `
{
id
Expand Down
38 changes: 21 additions & 17 deletions test/breed.graphql.test.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
7 changes: 7 additions & 0 deletions test/interfaces/breedWithSpecies.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default interface BreedWithSpecies {
id: number;
abbreviation: string;
value: string;
speciesId: number;
speciesValue: string;
}
5 changes: 3 additions & 2 deletions test/validators/breed.interface.validator.ts
Original file line number Diff line number Diff line change
@@ -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'));
Expand Down
54 changes: 54 additions & 0 deletions test/validators/breedWithSpecies.interface.validator.ts
Original file line number Diff line number Diff line change
@@ -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<T> = ((data: unknown) => data is T) & Pick<Ajv.ValidateFunction, 'errors'>
export const isBreedWithSpecies = ajv.compile(BreedWithSpeciesSchema) as ValidateFunction<BreedWithSpecies>;
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),
);
}
}

0 comments on commit a6e54b2

Please sign in to comment.