Skip to content

Commit c58f3ce

Browse files
committed
refactor(signatureRequests): restructure signature request handling and enhance related components
- Moved signature request resolver and composed resolver to services dir - Updaed SignatureRequestResolver with docs - Enhanced SignatureRequestsService with detailed documentation and methods for managing signature requests. - Added extensive test coverage for SignatureRequestsService and SignatureRequestResolver, ensuring robust functionality and error handling. - Updated database schema to support signature requests and improved mock data generation utilities.
1 parent b085990 commit c58f3ce

File tree

10 files changed

+630
-88
lines changed

10 files changed

+630
-88
lines changed

src/graphql/schemas/resolvers/composed.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/graphql/schemas/resolvers/signatureRequestResolver.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/services/database/entities/SignatureRequestsEntityService.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@ export type SignatureRequestUpdate = Updateable<
1616
DataDatabase["signature_requests"]
1717
>;
1818

19+
/**
20+
* Service for handling signature request operations in the system.
21+
* Provides methods for retrieving, creating and updating signature requests.
22+
*
23+
* A signature request represents a request for a user to sign a message, with:
24+
* - Safe address (the address that needs to sign)
25+
* - Message hash (hash of the message to be signed)
26+
* - Status (pending, executed, canceled)
27+
* - Purpose (e.g. update_user_data)
28+
*
29+
* This service uses an EntityService for database operations, providing:
30+
* - Consistent error handling
31+
* - Type safety through Kysely
32+
* - Standard query interface
33+
*/
1934
@injectable()
2035
export class SignatureRequestsService {
2136
private entityService: EntityService<
@@ -31,16 +46,67 @@ export class SignatureRequestsService {
3146
>("signature_requests", "SignatureRequestsEntityService", kyselyData);
3247
}
3348

49+
/**
50+
* Retrieves multiple signature requests based on provided arguments.
51+
*
52+
* @param args - Query arguments for filtering signature requests
53+
* @returns A promise resolving to:
54+
* - data: Array of signature requests matching the criteria
55+
* - count: Total number of matching records
56+
*
57+
* @example
58+
* ```typescript
59+
* const result = await signatureRequestsService.getSignatureRequests({
60+
* where: {
61+
* safe_address: { eq: "0x1234...5678" }
62+
* }
63+
* });
64+
* ```
65+
*/
3466
async getSignatureRequests(args: GetSignatureRequestsArgs) {
3567
return this.entityService.getMany(args);
3668
}
3769

70+
/**
71+
* Retrieves a single signature request based on provided arguments.
72+
*
73+
* @param args - Query arguments for filtering signature requests
74+
* @returns A promise resolving to:
75+
* - The matching signature request if found
76+
* - null if no matching record exists
77+
*
78+
* @example
79+
* ```typescript
80+
* const request = await signatureRequestsService.getSignatureRequest({
81+
* where: {
82+
* safe_address: { eq: "0x1234...5678" },
83+
* message_hash: { eq: "0xabcd...ef12" }
84+
* }
85+
* });
86+
* ```
87+
*/
3888
async getSignatureRequest(args: GetSignatureRequestsArgs) {
3989
return this.entityService.getSingle(args);
4090
}
4191

4292
// Mutations
4393

94+
/**
95+
* Creates a new signature request.
96+
*
97+
* @param signatureRequest - The signature request data to insert
98+
* @returns A promise resolving to the created signature request's safe_address and message_hash
99+
*
100+
* @example
101+
* ```typescript
102+
* const result = await signatureRequestsService.addSignatureRequest({
103+
* safe_address: "0x1234...5678",
104+
* message_hash: "0xabcd...ef12",
105+
* status: "pending",
106+
* purpose: "update_user_data"
107+
* });
108+
* ```
109+
*/
44110
async addSignatureRequest(signatureRequest: SignatureRequestInsert) {
45111
return this.dbService
46112
.getConnection()
@@ -50,6 +116,23 @@ export class SignatureRequestsService {
50116
.executeTakeFirst();
51117
}
52118

119+
/**
120+
* Updates the status of an existing signature request.
121+
*
122+
* @param safe_address - The safe address associated with the request
123+
* @param message_hash - The message hash of the request
124+
* @param status - The new status to set
125+
* @returns A promise resolving to the number of affected rows
126+
*
127+
* @example
128+
* ```typescript
129+
* await signatureRequestsService.updateSignatureRequestStatus(
130+
* "0x1234...5678",
131+
* "0xabcd...ef12",
132+
* "executed"
133+
* );
134+
* ```
135+
*/
53136
async updateSignatureRequestStatus(
54137
safe_address: string,
55138
message_hash: string,

src/services/database/strategies/SignatureRequestsQueryStrategy.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,38 @@ import { Kysely } from "kysely";
22
import { DataDatabase } from "../../../types/kyselySupabaseData.js";
33
import { QueryStrategy } from "./QueryStrategy.js";
44

5+
/**
6+
* Query strategy for signature requests.
7+
* Handles building queries for retrieving and counting signature requests.
8+
*
9+
* A signature request represents a request for a user to sign a message, with:
10+
* - Safe address (the address that needs to sign)
11+
* - Message hash (hash of the message to be signed)
12+
* - Status (pending, executed, canceled)
13+
* - Purpose (e.g. update_user_data)
14+
*/
515
export class SignatureRequestsQueryStrategy extends QueryStrategy<
616
DataDatabase,
717
"signature_requests"
818
> {
919
protected readonly tableName = "signature_requests" as const;
1020

21+
/**
22+
* Builds a query to select all signature request data.
23+
*
24+
* @param db - The database connection
25+
* @returns A query builder for selecting signature request data
26+
*/
1127
buildDataQuery(db: Kysely<DataDatabase>) {
1228
return db.selectFrom(this.tableName).selectAll();
1329
}
1430

31+
/**
32+
* Builds a query to count signature requests.
33+
*
34+
* @param db - The database connection
35+
* @returns A query builder for counting signature requests
36+
*/
1537
buildCountQuery(db: Kysely<DataDatabase>) {
1638
return db.selectFrom(this.tableName).select((eb) => {
1739
return eb.fn.countAll().as("count");
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { HypercertResolver } from "./hypercertResolver.js";
2+
import { MetadataResolver } from "./metadataResolver.js";
3+
import { ContractResolver } from "./contractResolver.js";
4+
import { FractionResolver } from "./fractionResolver.js";
5+
import { AttestationResolver } from "./attestationResolver.js";
6+
import { AttestationSchemaResolver } from "./attestationSchemaResolver.js";
7+
import { OrderResolver } from "./orderResolver.js";
8+
import { HyperboardResolver } from "./hyperboardResolver.js";
9+
import { AllowlistRecordResolver } from "./allowlistRecordResolver.js";
10+
import { SalesResolver } from "./salesResolver.js";
11+
import { UserResolver } from "./userResolver.js";
12+
import { BlueprintResolver } from "./blueprintResolver.js";
13+
import { SignatureRequestResolver } from "./signatureRequestResolver.js";
14+
import { CollectionResolver } from "./collectionResolver.js";
15+
16+
export const resolvers = [
17+
ContractResolver,
18+
FractionResolver,
19+
MetadataResolver,
20+
HypercertResolver,
21+
AttestationResolver,
22+
AttestationSchemaResolver,
23+
OrderResolver,
24+
HyperboardResolver,
25+
AllowlistRecordResolver,
26+
SalesResolver,
27+
UserResolver,
28+
BlueprintResolver,
29+
SignatureRequestResolver,
30+
CollectionResolver,
31+
] as const;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Args, FieldResolver, Query, Resolver, Root } from "type-graphql";
2+
3+
import { GetSignatureRequestsArgs } from "../../../graphql/schemas/args/signatureRequestArgs.js";
4+
import {
5+
GetSignatureRequestResponse,
6+
SignatureRequest,
7+
} from "../../../graphql/schemas/typeDefs/signatureRequestTypeDefs.js";
8+
9+
import { inject, injectable } from "tsyringe";
10+
import { SignatureRequestsService } from "../../database/entities/SignatureRequestsEntityService.js";
11+
12+
/**
13+
* GraphQL resolver for signature requests.
14+
* Handles queries for retrieving signature requests and resolves specific fields.
15+
*
16+
* A signature request represents a message that needs to be signed by a Safe wallet,
17+
* typically used for user data updates or other authenticated operations.
18+
*/
19+
@injectable()
20+
@Resolver(() => SignatureRequest)
21+
export class SignatureRequestResolver {
22+
constructor(
23+
@inject(SignatureRequestsService)
24+
private signatureRequestsService: SignatureRequestsService,
25+
) {}
26+
27+
/**
28+
* Query resolver for fetching signature requests.
29+
* Can be filtered by safe address and status.
30+
*
31+
* @param args - Query arguments including optional safe_address and status filters
32+
* @returns A paginated response containing signature requests and total count
33+
*/
34+
@Query(() => GetSignatureRequestResponse)
35+
async signatureRequests(@Args() args: GetSignatureRequestsArgs) {
36+
return await this.signatureRequestsService.getSignatureRequests(args);
37+
}
38+
39+
/**
40+
* Field resolver for the message field.
41+
* Ensures consistent string representation of messages, whether they're
42+
* stored as objects or strings.
43+
*
44+
* @param signatureRequest - The signature request containing the message
45+
* @returns The message as a string, stringified if it's an object
46+
*/
47+
@FieldResolver(() => String)
48+
message(@Root() signatureRequest: SignatureRequest): string {
49+
return typeof signatureRequest.message === "object"
50+
? JSON.stringify(signatureRequest.message)
51+
: signatureRequest.message || "could not parse message";
52+
}
53+
}

0 commit comments

Comments
 (0)