Skip to content

Commit 1f43906

Browse files
authored
Merge pull request #214 from pheuberger/create-collections-entity-graphql
Create `collections` top level entity in GraphQL
2 parents c6fb689 + cfeb432 commit 1f43906

19 files changed

+453
-430
lines changed

schema.graphql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ input BooleanSearchOptions {
333333
"""Collection of hypercerts for reference and display purposes"""
334334
type Collection {
335335
admins: [User!]!
336+
blueprints: [Blueprint!]
336337

337338
"""Chain ID of the collection"""
338339
chain_ids: [EthBigInt!]
@@ -342,12 +343,29 @@ type Collection {
342343

343344
"""Description of the collection"""
344345
description: String!
346+
hypercerts: [Hypercert!]
345347
id: ID!
346348

347349
"""Name of the collection"""
348350
name: String!
349351
}
350352

353+
input CollectionFetchInput {
354+
by: CollectionSortOptions
355+
}
356+
357+
input CollectionSortOptions {
358+
created_at: SortOrder
359+
description: SortOrder
360+
name: SortOrder
361+
}
362+
363+
input CollectionWhereInput {
364+
description: StringSearchOptions
365+
id: IdSearchOptions
366+
name: StringSearchOptions
367+
}
368+
351369
"""Pointer to a contract deployed on a chain"""
352370
type Contract {
353371
"""The ID of the chain on which the contract is deployed"""
@@ -469,6 +487,11 @@ type GetBlueprintResponse {
469487
data: [Blueprint!]
470488
}
471489

490+
type GetCollectionsResponse {
491+
count: Int
492+
data: [Collection!]
493+
}
494+
472495
"""Pointer to a contract deployed on a chain"""
473496
type GetContractsResponse {
474497
count: Int
@@ -889,6 +912,7 @@ type Query {
889912
attestationSchemas(first: Int, offset: Int): GetAttestationsSchemaResponse!
890913
attestations(first: Int, offset: Int, sort: AttestationFetchInput, where: AttestationWhereInput): GetAttestationsResponse!
891914
blueprints(first: Int, offset: Int, sort: BlueprintFetchInput, where: BlueprintWhereInput): GetBlueprintResponse!
915+
collections(first: Int, offset: Int, sort: CollectionFetchInput, where: CollectionWhereInput): GetCollectionsResponse!
892916
contracts(first: Int, offset: Int, sort: ContractFetchInput, where: ContractWhereInput): GetContractsResponse!
893917
fractions(first: Int, offset: Int, sort: FractionFetchInput, where: FractionWhereInput): GetFractionsResponse!
894918
hyperboards(first: Int, offset: Int, sort: HyperboardFetchInput, where: HyperboardWhereInput): GetHyperboardsResponse!
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { ArgsType, Field, InputType } from "type-graphql";
2+
3+
import { BasicCollectionWhereInput } from "../inputs/collectionInput.js";
4+
import type { OrderOptions } from "../inputs/orderOptions.js";
5+
import { Collection } from "../typeDefs/collectionTypeDefs.js";
6+
import { CollectionSortOptions } from "../inputs/sortOptions.js";
7+
8+
import { withPagination } from "./baseArgs.js";
9+
10+
@InputType()
11+
export class CollectionWhereInput extends BasicCollectionWhereInput {}
12+
13+
@InputType()
14+
export class CollectionFetchInput implements OrderOptions<Collection> {
15+
@Field(() => CollectionSortOptions, { nullable: true })
16+
by?: CollectionSortOptions;
17+
}
18+
19+
@ArgsType()
20+
export class CollectionArgs {
21+
@Field(() => CollectionWhereInput, { nullable: true })
22+
where?: CollectionWhereInput;
23+
@Field(() => CollectionFetchInput, { nullable: true })
24+
sort?: CollectionFetchInput;
25+
}
26+
27+
@ArgsType()
28+
export class GetCollectionsArgs extends withPagination(CollectionArgs) {}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Field, InputType } from "type-graphql";
2+
3+
import { Collection } from "../typeDefs/collectionTypeDefs.js";
4+
5+
import { IdSearchOptions, StringSearchOptions } from "./searchOptions.js";
6+
import type { WhereOptions } from "./whereOptions.js";
7+
8+
@InputType()
9+
export class BasicCollectionWhereInput implements WhereOptions<Collection> {
10+
@Field(() => IdSearchOptions, { nullable: true })
11+
id?: IdSearchOptions | null;
12+
13+
@Field(() => StringSearchOptions, { nullable: true })
14+
name?: StringSearchOptions;
15+
16+
@Field(() => StringSearchOptions, { nullable: true })
17+
description?: StringSearchOptions;
18+
}

src/graphql/schemas/inputs/sortOptions.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Sale } from "../typeDefs/salesTypeDefs.js";
1111
import { Hyperboard } from "../typeDefs/hyperboardTypeDefs.js";
1212
import { Blueprint } from "../typeDefs/blueprintTypeDefs.js";
1313
import { SignatureRequest } from "../typeDefs/signatureRequestTypeDefs.js";
14+
import { Collection } from "../typeDefs/collectionTypeDefs.js";
1415

1516
export type SortOptions<T extends object> = {
1617
[P in keyof T]: SortOrder | null;
@@ -238,3 +239,13 @@ export class SignatureRequestSortOptions
238239
@Field(() => SortOrder, { nullable: true })
239240
purpose?: SortOrder;
240241
}
242+
243+
@InputType()
244+
export class CollectionSortOptions implements SortOptions<Collection> {
245+
@Field(() => SortOrder, { nullable: true })
246+
name?: SortOrder;
247+
@Field(() => SortOrder, { nullable: true })
248+
created_at?: SortOrder;
249+
@Field(() => SortOrder, { nullable: true })
250+
description?: SortOrder;
251+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import {
2+
Args,
3+
FieldResolver,
4+
ObjectType,
5+
Query,
6+
Resolver,
7+
Root,
8+
} from "type-graphql";
9+
10+
import { GetCollectionsArgs } from "../args/collectionArgs.js";
11+
import { Collection } from "../typeDefs/collectionTypeDefs.js";
12+
import { Blueprint } from "../typeDefs/blueprintTypeDefs.js";
13+
import { User } from "../typeDefs/userTypeDefs.js";
14+
15+
import { createBaseResolver, DataResponse } from "./baseTypes.js";
16+
import GetHypercertsResponse from "./hypercertResolver.js";
17+
18+
@ObjectType()
19+
class GetCollectionsResponse extends DataResponse(Collection) {}
20+
21+
const CollectionBaseResolver = createBaseResolver("collection");
22+
23+
@Resolver(() => Collection)
24+
class CollectionResolver extends CollectionBaseResolver {
25+
@Query(() => GetCollectionsResponse)
26+
async collections(@Args() args: GetCollectionsArgs) {
27+
try {
28+
const res = await this.supabaseDataService.getCollections(args);
29+
30+
return {
31+
data: res.data,
32+
count: res.count,
33+
};
34+
} catch (e) {
35+
console.error("[CollectionResolver::collections] Error:", e);
36+
throw new Error(`Error fetching collections: ${(e as Error).message}`);
37+
}
38+
}
39+
40+
@FieldResolver(() => GetHypercertsResponse)
41+
async hypercerts(@Root() collection: Collection) {
42+
if (!collection.id) {
43+
console.error(
44+
"[CollectionResolver::hypercerts] Collection ID is undefined",
45+
);
46+
return [];
47+
}
48+
49+
const hypercerts = await this.supabaseDataService.getCollectionHypercerts(
50+
collection.id,
51+
);
52+
53+
if (!hypercerts?.length) {
54+
return [];
55+
}
56+
57+
const hypercertIds = hypercerts
58+
.map((h) => h.hypercert_id)
59+
.filter((id): id is string => id !== undefined);
60+
61+
if (hypercertIds.length === 0) {
62+
return [];
63+
}
64+
65+
const hypercertsData = await this.getHypercerts({
66+
where: { hypercert_id: { in: hypercertIds } },
67+
});
68+
69+
return hypercertsData.data || [];
70+
}
71+
72+
@FieldResolver(() => [User])
73+
async admins(@Root() collection: Collection) {
74+
if (!collection.id) {
75+
console.error("[CollectionResolver::admins] Collection ID is undefined");
76+
return [];
77+
}
78+
79+
const admins = await this.supabaseDataService.getCollectionAdmins(
80+
collection.id,
81+
);
82+
return admins || [];
83+
}
84+
85+
@FieldResolver(() => [Blueprint])
86+
async blueprints(@Root() collection: Collection) {
87+
if (!collection.id) {
88+
console.error(
89+
"[CollectionResolver::blueprints] Collection ID is undefined",
90+
);
91+
return [];
92+
}
93+
94+
const blueprints = await this.supabaseDataService.getCollectionBlueprints(
95+
collection.id,
96+
);
97+
return blueprints || [];
98+
}
99+
}
100+
101+
export { CollectionResolver };

src/graphql/schemas/resolvers/composed.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { SalesResolver } from "./salesResolver.js";
1111
import { UserResolver } from "./userResolver.js";
1212
import { BlueprintResolver } from "./blueprintResolver.js";
1313
import { SignatureRequestResolver } from "./signatureRequestResolver.js";
14+
import { CollectionResolver } from "./collectionResolver.js";
1415

1516
export const resolvers = [
1617
ContractResolver,
@@ -26,4 +27,5 @@ export const resolvers = [
2627
UserResolver,
2728
BlueprintResolver,
2829
SignatureRequestResolver,
30+
CollectionResolver,
2931
] as const;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Field, ObjectType } from "type-graphql";
2+
3+
import { EthBigInt } from "../../scalars/ethBigInt.js";
4+
5+
import { BasicTypeDef } from "./baseTypes/basicTypeDef.js";
6+
import { User } from "./userTypeDefs.js";
7+
import { Hypercert } from "./hypercertTypeDefs.js";
8+
import { Blueprint } from "./blueprintTypeDefs.js";
9+
10+
@ObjectType({
11+
description: "Collection of hypercerts for reference and display purposes",
12+
})
13+
export class Collection extends BasicTypeDef {
14+
@Field({ description: "Creation timestamp of the collection" })
15+
created_at?: string;
16+
@Field({ description: "Name of the collection" })
17+
name?: string;
18+
@Field({ description: "Description of the collection" })
19+
description?: string;
20+
@Field(() => [EthBigInt], {
21+
nullable: true,
22+
description: "Chain ID of the collection",
23+
})
24+
chain_ids?: (bigint | number | string)[];
25+
26+
@Field(() => [User])
27+
admins?: User[];
28+
29+
@Field(() => [Hypercert], { nullable: true })
30+
hypercerts?: Hypercert[];
31+
32+
@Field(() => [Blueprint], { nullable: true })
33+
blueprints?: Blueprint[];
34+
}

src/graphql/schemas/typeDefs/hyperboardTypeDefs.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { BasicTypeDef } from "./baseTypes/basicTypeDef.js";
33
import { EthBigInt } from "../../scalars/ethBigInt.js";
44
import { User } from "./userTypeDefs.js";
55
import { GraphQLBigInt } from "graphql-scalars";
6+
import { Collection } from "./collectionTypeDefs.js";
67

78
@ObjectType({
89
description: "Hyperboard of hypercerts for reference and display purposes",
@@ -48,26 +49,6 @@ class SectionResponseType {
4849
count?: number;
4950
}
5051

51-
@ObjectType({
52-
description: "Collection of hypercerts for reference and display purposes",
53-
})
54-
class Collection extends BasicTypeDef {
55-
@Field({ description: "Creation timestamp of the collection" })
56-
created_at?: string;
57-
@Field({ description: "Name of the collection" })
58-
name?: string;
59-
@Field({ description: "Description of the collection" })
60-
description?: string;
61-
@Field(() => [EthBigInt], {
62-
nullable: true,
63-
description: "Chain ID of the collection",
64-
})
65-
chain_ids?: (bigint | number | string)[];
66-
67-
@Field(() => [User])
68-
admins?: User[];
69-
}
70-
7152
@ObjectType({
7253
description: "Section representing a collection within a hyperboard",
7354
})

0 commit comments

Comments
 (0)