Skip to content

Commit

Permalink
feat(relay): update connection pattern to conform to relay (#408)
Browse files Browse the repository at this point in the history
* feat(relay): update connection pattern to conform to relay
  • Loading branch information
goldcaddy77 authored Sep 11, 2020
1 parent a914116 commit eeddc26
Show file tree
Hide file tree
Showing 31 changed files with 1,305 additions and 155 deletions.
4 changes: 2 additions & 2 deletions examples/02-complex-example/generated/binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export interface UserCreateInput {
bigIntField?: Float | null
jsonField?: JSONObject | null
jsonFieldNoFilter?: JSONObject | null
stringField: String
stringField?: String | null
noFilterField?: String | null
noSortField?: String | null
noFilterOrSortField?: String | null
Expand Down Expand Up @@ -504,7 +504,7 @@ export interface User extends BaseGraphQLObject {
bigIntField?: Int | null
jsonField?: JSONObject | null
jsonFieldNoFilter?: JSONObject | null
stringField: String
stringField?: String | null
noFilterField?: String | null
noSortField?: String | null
noFilterOrSortField?: String | null
Expand Down
4 changes: 2 additions & 2 deletions examples/02-complex-example/generated/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,8 +784,8 @@ export class UserCreateInput {
@TypeGraphQLField(() => GraphQLJSONObject, { nullable: true })
jsonFieldNoFilter?: JsonObject;

@TypeGraphQLField()
stringField!: string;
@TypeGraphQLField({ nullable: true })
stringField?: string;

@TypeGraphQLField({ nullable: true })
noFilterField?: string;
Expand Down
4 changes: 2 additions & 2 deletions examples/02-complex-example/generated/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ type User implements BaseGraphQLObject {
jsonFieldNoFilter: JSONObject

"""This is a string field"""
stringField: String!
stringField: String
noFilterField: String
noSortField: String
noFilterOrSortField: String
Expand Down Expand Up @@ -172,7 +172,7 @@ input UserCreateInput {
bigIntField: Float
jsonField: JSONObject
jsonFieldNoFilter: JSONObject
stringField: String!
stringField: String
noFilterField: String
noSortField: String
noFilterOrSortField: String
Expand Down
1 change: 1 addition & 0 deletions examples/02-complex-example/src/modules/user/user.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export class User extends BaseModel {
@StringField({ dataType: 'varchar', nullable: true })
varcharField: string;

// DOCUMENTATION TODO
// Spacial fields
// https://github.com/typeorm/typeorm/blob/master/test/functional/spatial/postgres/entity/Post.ts
@CustomField({
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@
"singleQuote": true
},
"jest": {
"setupFiles": [
"./src/test/setupFiles.ts"
],
"setupFilesAfterEnv": [
"./src/test/setupFilesAfterEnv.ts"
],
Expand Down
9 changes: 9 additions & 0 deletions src/core/BaseModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ export abstract class BaseModel implements BaseGraphQLObject {
return this.id || shortid.generate();
}

// V3: DateTime should use getter to return ISO8601 string
getValue(field: any) {
const self = this as any;
if (self[field] instanceof Date) {
return self[field].toISOString();
}
return self[field];
}

@BeforeInsert()
setId() {
this.id = this.getId();
Expand Down
279 changes: 279 additions & 0 deletions src/core/BaseService.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
// TODO:
// - test totalCount
//
// Good test example: https://github.com/typeorm/typeorm/blob/master/test/functional/query-builder/brackets/query-builder-brackets.ts
import 'reflect-metadata';
import { Brackets, Connection } from 'typeorm';
import { Container } from 'typedi';

import { createDBConnection } from '../torm';

import { MyBase, MyBaseService } from './tests/entity/MyBase.model';

describe('BaseService', () => {
let connection: Connection;
let service: MyBaseService;
beforeAll(async () => {
connection = await createDBConnection({
entities: [__dirname + '/tests/entity/*{.js,.ts}']
// logging: 'all'
});

service = Container.get('MyBaseService');
});
beforeEach(async () => {
await connection.synchronize(true);
});
afterAll(() => connection.close());

test('buildFindQuery', async () => {
await service.createMany(
[
{ firstName: 'AA', lastName: '01' },
{ firstName: 'BB', lastName: '02' },
{ firstName: 'CC', lastName: '03' },
{ firstName: 'DD', lastName: '04' },
{ firstName: 'EE', lastName: '05' },
{ firstName: 'FF', lastName: '06' },
{ firstName: 'GG', lastName: '07' },
{ firstName: 'HH', lastName: '08' },
{ firstName: 'II', lastName: '09' },
{ firstName: 'JJ', lastName: '10' },
{ firstName: 'KK', lastName: '11' },
{ firstName: 'LL', lastName: '12' },
{ firstName: 'MM', lastName: '13' },
{ firstName: 'NN', lastName: '14' }
],
'1'
);

const results = await service
.buildFindQuery({
OR: [
{ firstName_contains: 'A' },
{ firstName_contains: 'B' },
{ firstName_contains: 'C' },
{ firstName_contains: 'D' },
{ firstName_contains: 'J' },
{ firstName_contains: 'K' }
],
AND: [{ lastName_contains: '0' }]
} as any)
.getMany();

expect(results.length).toEqual(5);
});

describe('findConnection', () => {
test('returns all objects with no inputs', async () => {
await service.createMany(
[
{ firstName: 'AA', lastName: '01' },
{ firstName: 'BB', lastName: '02' },
{ firstName: 'CC', lastName: '03' }
],
'1'
);

const results = await service.findConnection();

expect(results.edges?.length).toEqual(3);
});

test('returns a limited number of items if asked', async () => {
await service.createMany(
[
{ firstName: 'AA', lastName: '01' },
{ firstName: 'BB', lastName: '02' },
{ firstName: 'CC', lastName: '03' }
],
'1'
);

const results = await service.findConnection(
undefined,
'firstName_ASC',
{ first: 2 },
{ edges: { node: { firstName: true } } }
);

expect(results.edges?.map(edge => edge.node?.firstName)).toEqual(['AA', 'BB']);
});

test('returns a limited number of items (using last)', async () => {
await service.createMany(
[
{ firstName: 'AA', lastName: '01' },
{ firstName: 'BB', lastName: '02' },
{ firstName: 'CC', lastName: '03' }
],
'1'
);

const results = await service.findConnection(
undefined,
'firstName_ASC',
{ last: 2 },
{ edges: { node: { firstName: true } } }
);

expect(results.edges?.map(edge => edge.node?.firstName)).toEqual(['CC', 'BB']);
});

test('query with first, grab cursor and refetch', async () => {
await service.createMany(
[
{ firstName: 'AA', lastName: '01' },
{ firstName: 'BB', lastName: '02' },
{ firstName: 'CC', lastName: '03' },
{ firstName: 'DD', lastName: '04' },
{ firstName: 'EE', lastName: '05' },
{ firstName: 'FF', lastName: '06' },
{ firstName: 'GG', lastName: '07' }
],
'1'
);

let results = await service.findConnection(
undefined,
'firstName_ASC',
{ first: 3 },
{
edges: { node: { firstName: true } },
pageInfo: { endCursor: {}, hasNextPage: {}, hasPreviousPage: {} }
}
);

expect(results.edges?.map(edge => edge.node?.firstName)).toEqual(['AA', 'BB', 'CC']);

const cursor = results.pageInfo?.endCursor;

results = await service.findConnection(
undefined,
'firstName_ASC',
{ first: 3, after: cursor },
{
edges: { node: { firstName: true } },
pageInfo: { endCursor: {}, hasNextPage: {}, hasPreviousPage: {} }
}
);

expect(results.edges?.map(edge => edge.node?.firstName)).toEqual(['DD', 'EE', 'FF']);
});

test('query with last, grab cursor and refetch', async () => {
await service.createMany(
[
{ firstName: 'AA', lastName: '01' },
{ firstName: 'BB', lastName: '02' },
{ firstName: 'CC', lastName: '03' },
{ firstName: 'DD', lastName: '04' },
{ firstName: 'EE', lastName: '05' },
{ firstName: 'FF', lastName: '06' },
{ firstName: 'GG', lastName: '07' }
],
'1'
);

let results = await service.findConnection(
undefined,
'firstName_ASC',
{ last: 3 },
{
edges: { node: { firstName: true } },
pageInfo: { endCursor: {}, hasNextPage: {}, hasPreviousPage: {} }
}
);

expect(results.edges?.map(edge => edge.node?.firstName)).toEqual(['GG', 'FF', 'EE']);

const cursor = results.pageInfo?.endCursor;

results = await service.findConnection(
undefined,
'firstName_ASC',
{ last: 3, before: cursor },
{
edges: { node: { firstName: true } },
pageInfo: { endCursor: {}, hasNextPage: {}, hasPreviousPage: {} }
}
);

expect(results.edges?.map(edge => edge.node?.firstName)).toEqual(['DD', 'CC', 'BB']);
});
});

test('multiple sorts, query with first, grab cursor and refetch', async () => {
await service.createMany(
[
{ registered: true, firstName: 'AA', lastName: '01' },
{ registered: false, firstName: 'BB', lastName: '02' },
{ registered: true, firstName: 'CC', lastName: '03' },
{ registered: false, firstName: 'DD', lastName: '04' },
{ registered: true, firstName: 'EE', lastName: '05' },
{ registered: false, firstName: 'FF', lastName: '06' },
{ registered: true, firstName: 'GG', lastName: '07' }
],
'1'
);

let results = await service.findConnection(
undefined,
['registered_ASC', 'firstName_ASC'],
{ first: 4 },
{
edges: { node: { firstName: true, registered: true } },
pageInfo: { endCursor: {}, hasNextPage: {}, hasPreviousPage: {} }
}
);

expect(results.edges?.map(edge => edge.node?.firstName)).toEqual(['BB', 'DD', 'FF', 'AA']);
expect(results.pageInfo?.hasNextPage).toEqual(true);

const cursor = results.pageInfo?.endCursor;

results = await service.findConnection(
undefined,
['registered_ASC', 'firstName_ASC'],
{ first: 3, after: cursor },
{
edges: { node: { firstName: true } },
pageInfo: { endCursor: {}, hasNextPage: {}, hasPreviousPage: {} }
}
);

expect(results.edges?.map(edge => edge.node?.firstName)).toEqual(['CC', 'EE', 'GG']);
});

test.skip('fun with brackets', async () => {
await service.createMany(
[
{ firstName: 'Timber', lastName: 'Saw' },
{ firstName: 'Pleerock', lastName: 'Pleerock' },
{ firstName: 'Alex', lastName: 'Messer' }
],
'1'
);

const bases = await connection
.createQueryBuilder(MyBase, 'user')
.where('user.lastName = :lastName0', { lastName0: 'Pleerock' })
.orWhere(
new Brackets(qb => {
qb.where('user.firstName = :firstName1', {
firstName1: 'Timber'
}).andWhere('user.lastName = :lastName1', { lastName1: 'Saw' });
})
)
.orWhere(
new Brackets(qb => {
qb.where('user.firstName = :firstName2', {
firstName2: 'Alex'
}).andWhere('user.lastName = :lastName2', { lastName2: 'Messer' });
})
)
.getMany();

expect(bases.length).toEqual(3);
});
});
Loading

0 comments on commit eeddc26

Please sign in to comment.