Skip to content

Commit 4bc55e6

Browse files
Merge remote-tracking branch 'origin/develop-postgres' into feat/devcontainer-v2
2 parents 50bf805 + 0fac5c2 commit 4bc55e6

File tree

13 files changed

+1109
-214
lines changed

13 files changed

+1109
-214
lines changed

schema.graphql

+45-22
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ enum AdvertisementType {
140140
pop_up
141141
}
142142

143+
"""Filter criteria for organization advertisements"""
144+
input AdvertisementWhereInput {
145+
"""Filter advertisements by completion status"""
146+
isCompleted: Boolean
147+
}
148+
143149
type AgendaFolder {
144150
"""
145151
GraphQL connection to traverse through the agenda folders that have the agenda folder as a parent folder.
@@ -774,8 +780,11 @@ type GetUrlResponse {
774780
}
775781

776782
type HasUserVoted {
777-
"""Type of the post vote"""
778-
type: PostVoteType!
783+
"""Indicates if the user has voted"""
784+
hasVoted: Boolean!
785+
786+
"""Type of the post vote, null if no vote exists"""
787+
voteType: PostVoteType
779788
}
780789

781790
"""
@@ -2884,7 +2893,15 @@ type Organization {
28842893
"""
28852894
GraphQL connection to traverse through the advertisements belonging to the organization.
28862895
"""
2887-
advertisements(after: String, before: String, first: Int, last: Int): OrganizationAdvertisementsConnection
2896+
advertisements(
2897+
after: String
2898+
before: String
2899+
first: Int
2900+
last: Int
2901+
2902+
"""Filter criteria for advertisements"""
2903+
where: AdvertisementWhereInput
2904+
): OrganizationAdvertisementsConnection
28882905

28892906
"""Mime type of the avatar of the organization."""
28902907
avatarMimeType: String
@@ -3176,25 +3193,6 @@ A field whose value conforms to the standard E.164 format as specified in: https
31763193
"""
31773194
scalar PhoneNumber
31783195

3179-
"""
3180-
Sorting criteria, e.g., 'amount_ASC', 'amount_DESC', 'endDate_ASC', 'endDate_DESC'
3181-
"""
3182-
enum QueryPledgeOrderByInput {
3183-
amount_ASC
3184-
amount_DESC
3185-
endDate_ASC
3186-
endDate_DESC
3187-
}
3188-
3189-
"""Filter criteria for Pledges"""
3190-
input QueryPledgeWhereInput {
3191-
"""Filter pledges by the name of the creator"""
3192-
firstName_contains: String
3193-
3194-
"""Filter pledges by the name of the campaign"""
3195-
name_contains: String
3196-
}
3197-
31983196
type Post {
31993197
"""Array of attachments."""
32003198
attachments: [PostAttachment!]
@@ -3385,6 +3383,12 @@ type Query {
33853383

33863384
"""Query field to get fund campaign pledge associated to a user."""
33873385
getPledgesByUserId(
3386+
"""Maximum number of results to return."""
3387+
limit: Int
3388+
3389+
"""Number of results to skip."""
3390+
offset: Int
3391+
33883392
"""
33893393
Sorting criteria, e.g., 'amount_ASC', 'amount_DESC', 'endDate_ASC', 'endDate_DESC'
33903394
"""
@@ -3541,6 +3545,25 @@ input QueryOrganizationInput {
35413545
id: String!
35423546
}
35433547

3548+
"""
3549+
Sorting criteria, e.g., 'amount_ASC', 'amount_DESC', 'endDate_ASC', 'endDate_DESC'
3550+
"""
3551+
enum QueryPledgeOrderByInput {
3552+
amount_ASC
3553+
amount_DESC
3554+
endDate_ASC
3555+
endDate_DESC
3556+
}
3557+
3558+
"""Filter criteria for Pledges"""
3559+
input QueryPledgeWhereInput {
3560+
"""Filter pledges by the name of the creator"""
3561+
firstName_contains: String
3562+
3563+
"""Filter pledges by the name of the campaign"""
3564+
name_contains: String
3565+
}
3566+
35443567
""""""
35453568
input QueryPostInput {
35463569
"""Global id of the post."""

src/graphql/inputs/QueryOrganizationInput.ts

+14
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,17 @@ export const MembersWhereInput = builder
6060
// Add other filter fields here
6161
}),
6262
});
63+
64+
export const AdvertisementWhereInput = builder
65+
.inputRef("AdvertisementWhereInput")
66+
.implement({
67+
description: "Filter criteria for organization advertisements",
68+
fields: (t) => ({
69+
isCompleted: t.field({
70+
type: "Boolean",
71+
description: "Filter advertisements by completion status",
72+
required: false,
73+
}),
74+
// Add other filter fields here
75+
}),
76+
});

src/graphql/types/Organization/advertisements.ts

+142-33
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,60 @@
11
import { type SQL, and, asc, desc, eq, exists, gt, lt } from "drizzle-orm";
2-
import type { z } from "zod";
2+
import { z } from "zod";
33
import {
44
advertisementsTable,
55
advertisementsTableInsertSchema,
66
} from "~/src/drizzle/tables/advertisements";
77
import { Advertisement } from "~/src/graphql/types/Advertisement/Advertisement";
88
import { TalawaGraphQLError } from "~/src/utilities/TalawaGraphQLError";
99
import {
10-
defaultGraphQLConnectionArgumentsSchema,
11-
transformDefaultGraphQLConnectionArguments,
10+
type ParsedDefaultGraphQLConnectionArgumentsWithWhere,
11+
createGraphQLConnectionWithWhereSchema,
12+
type defaultGraphQLConnectionArgumentsSchema,
13+
transformGraphQLConnectionArgumentsWithWhere,
1214
transformToDefaultGraphQLConnection,
1315
} from "~/src/utilities/defaultGraphQLConnection";
1416
import envConfig from "~/src/utilities/graphqLimits";
17+
import { AdvertisementWhereInput } from "../../inputs/QueryOrganizationInput";
1518
import { Organization } from "./Organization";
16-
const advertisementsArgumentsSchema = defaultGraphQLConnectionArgumentsSchema
17-
.transform(transformDefaultGraphQLConnectionArguments)
18-
.transform((arg, ctx) => {
19-
let cursor: z.infer<typeof cursorSchema> | undefined = undefined;
20-
21-
try {
22-
if (arg.cursor !== undefined) {
23-
cursor = cursorSchema.parse(
24-
JSON.parse(Buffer.from(arg.cursor, "base64url").toString("utf-8")),
25-
);
26-
}
27-
} catch (error) {
28-
ctx.addIssue({
29-
code: "custom",
30-
message: "Not a valid cursor.",
31-
path: [arg.isInversed ? "before" : "after"],
32-
});
33-
}
3419

35-
return {
36-
cursor,
37-
isInversed: arg.isInversed,
38-
limit: arg.limit,
39-
};
40-
});
20+
const advertisementWhereSchema = z
21+
.object({
22+
isCompleted: z.boolean().optional(),
23+
})
24+
.optional();
25+
26+
const advertisementsArgumentsSchema = createGraphQLConnectionWithWhereSchema(
27+
advertisementWhereSchema,
28+
).transform((arg, ctx) => {
29+
const transformedArg = transformGraphQLConnectionArgumentsWithWhere(
30+
{ ...arg, where: arg.where || {} } as z.infer<
31+
typeof defaultGraphQLConnectionArgumentsSchema
32+
> & { where: unknown },
33+
ctx,
34+
);
35+
let cursor: z.infer<typeof cursorSchema> | undefined = undefined;
36+
try {
37+
if (transformedArg.cursor !== undefined) {
38+
cursor = cursorSchema.parse(
39+
JSON.parse(
40+
Buffer.from(transformedArg.cursor, "base64url").toString("utf-8"),
41+
),
42+
);
43+
}
44+
} catch (error) {
45+
ctx.addIssue({
46+
code: "custom",
47+
message: "Not a valid cursor.",
48+
path: [transformedArg.isInversed ? "before" : "after"],
49+
});
50+
}
51+
return {
52+
cursor,
53+
isInversed: transformedArg.isInversed,
54+
limit: transformedArg.limit,
55+
where: transformedArg.where || {}, // Default to empty object if where is undefined
56+
};
57+
});
4158

4259
const cursorSchema = advertisementsTableInsertSchema.pick({
4360
name: true,
@@ -55,6 +72,13 @@ Organization.implement({
5572
multiplier: args.first || args.last || 1,
5673
};
5774
},
75+
args: {
76+
where: t.arg({
77+
type: AdvertisementWhereInput,
78+
description: "Filter criteria for advertisements",
79+
required: false,
80+
}),
81+
},
5882
resolve: async (parent, args, ctx) => {
5983
if (!ctx.currentClient.isAuthenticated) {
6084
throw new TalawaGraphQLError({
@@ -69,7 +93,6 @@ Organization.implement({
6993
error,
7094
success,
7195
} = advertisementsArgumentsSchema.safeParse(args);
72-
7396
if (!success) {
7497
throw new TalawaGraphQLError({
7598
extensions: {
@@ -124,7 +147,15 @@ Organization.implement({
124147
});
125148
}
126149

127-
const { cursor, isInversed, limit } = parsedArgs;
150+
const {
151+
cursor,
152+
isInversed,
153+
limit,
154+
where: extendedArgs,
155+
} = parsedArgs as ParsedDefaultGraphQLConnectionArgumentsWithWhere<
156+
{ name: string },
157+
{ isCompleted?: boolean }
158+
>;
128159

129160
const orderBy = isInversed
130161
? [desc(advertisementsTable.name)]
@@ -134,7 +165,7 @@ Organization.implement({
134165

135166
if (isInversed) {
136167
if (cursor !== undefined) {
137-
where = and(
168+
const baseCondition = and(
138169
exists(
139170
ctx.drizzleClient
140171
.select()
@@ -149,12 +180,51 @@ Organization.implement({
149180
eq(advertisementsTable.organizationId, parent.id),
150181
lt(advertisementsTable.name, cursor.name),
151182
);
183+
184+
if (extendedArgs.isCompleted !== undefined) {
185+
const today = new Date();
186+
187+
if (extendedArgs.isCompleted) {
188+
where = and(
189+
baseCondition,
190+
lt(advertisementsTable.endAt, today),
191+
);
192+
} else {
193+
where = and(
194+
baseCondition,
195+
gt(advertisementsTable.endAt, today),
196+
);
197+
}
198+
} else {
199+
where = baseCondition;
200+
}
152201
} else {
153-
where = eq(advertisementsTable.organizationId, parent.id);
202+
const baseCondition = eq(
203+
advertisementsTable.organizationId,
204+
parent.id,
205+
);
206+
207+
if (extendedArgs.isCompleted !== undefined) {
208+
const today = new Date();
209+
210+
if (extendedArgs.isCompleted) {
211+
where = and(
212+
baseCondition,
213+
lt(advertisementsTable.endAt, today),
214+
);
215+
} else {
216+
where = and(
217+
baseCondition,
218+
gt(advertisementsTable.endAt, today),
219+
);
220+
}
221+
} else {
222+
where = baseCondition;
223+
}
154224
}
155225
} else {
156226
if (cursor !== undefined) {
157-
where = and(
227+
const baseCondition = and(
158228
exists(
159229
ctx.drizzleClient
160230
.select()
@@ -169,8 +239,47 @@ Organization.implement({
169239
eq(advertisementsTable.organizationId, parent.id),
170240
gt(advertisementsTable.name, cursor.name),
171241
);
242+
243+
if (extendedArgs.isCompleted !== undefined) {
244+
const today = new Date();
245+
246+
if (extendedArgs.isCompleted) {
247+
where = and(
248+
baseCondition,
249+
lt(advertisementsTable.endAt, today),
250+
);
251+
} else {
252+
where = and(
253+
baseCondition,
254+
gt(advertisementsTable.endAt, today),
255+
);
256+
}
257+
} else {
258+
where = baseCondition;
259+
}
172260
} else {
173-
where = eq(advertisementsTable.organizationId, parent.id);
261+
const baseCondition = eq(
262+
advertisementsTable.organizationId,
263+
parent.id,
264+
);
265+
266+
if (extendedArgs.isCompleted !== undefined) {
267+
const today = new Date();
268+
269+
if (extendedArgs.isCompleted) {
270+
where = and(
271+
baseCondition,
272+
lt(advertisementsTable.endAt, today),
273+
);
274+
} else {
275+
where = and(
276+
baseCondition,
277+
gt(advertisementsTable.endAt, today),
278+
);
279+
}
280+
} else {
281+
where = baseCondition;
282+
}
174283
}
175284
}
176285

src/graphql/types/Post/hasUserVoted.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,24 @@ import type { z } from "zod";
22
import type { postVoteTypeEnum } from "~/src/drizzle/enums/postVoteType";
33
import { builder } from "~/src/graphql/builder";
44
import { PostVoteType } from "../../enums/PostVoteType";
5+
56
export const HasUserVoted = builder.objectRef<{
6-
type: z.infer<typeof postVoteTypeEnum>;
7+
hasVoted: boolean;
8+
voteType: z.infer<typeof postVoteTypeEnum> | null;
79
}>("HasUserVoted");
810

911
HasUserVoted.implement({
1012
fields: (t) => ({
11-
type: t.expose("type", {
12-
type: PostVoteType,
13+
hasVoted: t.field({
14+
type: "Boolean",
1315
nullable: false,
14-
description: "Type of the post vote",
16+
description: "Indicates if the user has voted",
17+
resolve: (parent) => parent.hasVoted,
18+
}),
19+
voteType: t.expose("voteType", {
20+
type: PostVoteType,
21+
nullable: true,
22+
description: "Type of the post vote, null if no vote exists",
1523
}),
1624
}),
1725
});

0 commit comments

Comments
 (0)