Skip to content

Commit a98a67e

Browse files
authored
Merge pull request #84 from mizdra/implement-build-connection
Implement `buildConnection()`
2 parents eb7f2bc + a7ed125 commit a98a67e

File tree

5 files changed

+112
-2
lines changed

5 files changed

+112
-2
lines changed

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,30 @@ expect(await BookFactory.buildList(3)).toStrictEqual([
233233
]);
234234
```
235235

236+
### Building connection
237+
238+
You can build a [connection](https://relay.dev/graphql/connections.htm) of mock data with the `buildConnection` method.
239+
240+
```ts
241+
const BookFactory = defineBookFactory({
242+
defaultFields: {
243+
id: dynamic(({ seq }) => `Book-${seq}`),
244+
},
245+
});
246+
expect(await BookFactory.buildConnection(3, { first: 2 })).toStrictEqual([
247+
edges: [
248+
{ cursor: "YXJyYXljb25uZWN0aW9uOjA=", node: { id: 'Book-0' } },
249+
{ cursor: "YXJyYXljb25uZWN0aW9uOjE=", node: { id: 'Book-1' } },
250+
],
251+
pageInfo: {
252+
startCursor: "YXJyYXljb25uZWN0aW9uOjA=",
253+
endCursor: "YXJyYXljb25uZWN0aW9uOjE=",
254+
hasPreviousPage: false,
255+
hasNextPage: true,
256+
},
257+
]);
258+
```
259+
236260
### Build mock data of related types (a.k.a. Associations)
237261

238262
You can build mock data of the relevant type in one shot.

e2e/esm/index.e2e.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { oneOf } from './test/util.js';
2222
import { definePrefixTypeFactory } from './__generated__/2-typesPrefix/fabbrica.js';
2323
import { defineTypeSuffixFactory } from './__generated__/3-typesSuffix/fabbrica.js';
2424
import { defineNonOptionalDefaultFields_NonOptionalDefaultFieldsTypeFactory } from './__generated__/4-non-optional-fields/fabbrica.js';
25+
import { offsetToCursor } from 'graphql-relay';
2526

2627
describe('integration test', () => {
2728
it('circular dependent type', async () => {
@@ -1017,6 +1018,37 @@ describe('TypeFactoryInterface', () => {
10171018
>();
10181019
});
10191020
});
1021+
describe('buildConnection', () => {
1022+
it('build connection', async () => {
1023+
const BookFactory = defineBookFactory({
1024+
defaultFields: {
1025+
id: dynamic(({ seq }) => `Book-${seq}`),
1026+
},
1027+
});
1028+
const books1 = await BookFactory.buildConnection(3, { first: 2 });
1029+
expect(books1).toStrictEqual({
1030+
edges: [
1031+
{ cursor: offsetToCursor(0), node: { id: 'Book-0' } },
1032+
{ cursor: offsetToCursor(1), node: { id: 'Book-1' } },
1033+
],
1034+
pageInfo: {
1035+
startCursor: offsetToCursor(0),
1036+
endCursor: offsetToCursor(1),
1037+
hasPreviousPage: false,
1038+
hasNextPage: true,
1039+
},
1040+
});
1041+
expectTypeOf(books1).toEqualTypeOf<{
1042+
edges: { cursor: string; node: { id: string } }[];
1043+
pageInfo: {
1044+
startCursor: string | null;
1045+
endCursor: string | null;
1046+
hasPreviousPage: boolean;
1047+
hasNextPage: boolean;
1048+
};
1049+
}>();
1050+
});
1051+
});
10201052
describe('resetSequence', () => {
10211053
it('resets sequence', async () => {
10221054
const BookFactory = defineBookFactory({

package-lock.json

Lines changed: 26 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
},
9898
"dependencies": {
9999
"@graphql-codegen/plugin-helpers": "^5.0.1",
100-
"@graphql-codegen/visitor-plugin-common": "^4.0.1"
100+
"@graphql-codegen/visitor-plugin-common": "^4.0.1",
101+
"graphql-relay": "^0.10.2"
101102
}
102103
}

src/helper/factory.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// MEMO: The tests for this module are covered by `e2e/*.e2e.ts`.
22

3+
import { Connection, ConnectionArguments, connectionFromArray } from 'graphql-relay';
34
import { ResolvedFields, FieldsResolver, resolveFields, FieldResolver } from './field-resolver.js';
45
import { getSequenceCounter, resetSequence } from './sequence.js';
56
import { Merge } from './util.js';
@@ -40,6 +41,17 @@ export interface TypeFactoryInterface<
4041
count: number,
4142
inputFieldsResolver: T,
4243
): Promise<Omit<Merge<ResolvedFields<_DefaultFieldsResolver>, ResolvedFields<T>>, keyof TransientFields>[]>;
44+
buildConnection(
45+
count: number,
46+
connectionArgs: ConnectionArguments,
47+
): Promise<
48+
Connection<Omit<Merge<ResolvedFields<_DefaultFieldsResolver>, ResolvedFields<{}>>, keyof TransientFields>>
49+
>;
50+
buildConnection<T extends FieldsResolver<Type & TransientFields>>(
51+
count: number,
52+
connectionArgs: ConnectionArguments,
53+
inputFieldsResolver: T,
54+
): Promise<Connection<Omit<Merge<ResolvedFields<_DefaultFieldsResolver>, ResolvedFields<T>>, keyof TransientFields>>>;
4355
use<T extends keyof _Traits>(
4456
traitName: T,
4557
): TypeFactoryInterface<Type, TransientFields, Merge<_DefaultFieldsResolver, _Traits[T]['defaultFields']>, _Traits>;
@@ -119,6 +131,22 @@ export function defineTypeFactoryInternal<
119131
}
120132
return array;
121133
},
134+
async buildConnection<T extends FieldsResolver<Type & TransientFields>>(
135+
count: number,
136+
connectionArgs: ConnectionArguments,
137+
inputFieldsResolver?: T,
138+
): Promise<
139+
Connection<Omit<Merge<ResolvedFields<_DefaultFieldsResolver>, ResolvedFields<T>>, keyof TransientFields>>
140+
> {
141+
const list = inputFieldsResolver ? await this.buildList(count, inputFieldsResolver) : await this.buildList(count);
142+
return connectionFromArray(
143+
list as readonly Omit<
144+
Merge<ResolvedFields<_DefaultFieldsResolver>, ResolvedFields<T>>,
145+
keyof TransientFields
146+
>[],
147+
connectionArgs,
148+
);
149+
},
122150
use<T extends keyof _Traits>(
123151
traitName: T,
124152
): TypeFactoryInterface<

0 commit comments

Comments
 (0)