export const find = query({
args: {
paginationOpts: paginationOptsValidator,
filter: v.optional(
v.object({
createdById: v.optional(v.id("users")),
search: v.optional(v.string()),
})
),
},
handler: async (ctx, args) => {
let query = ctx.db.query("protests");
if (args.filter?.search) {
return await query
.withSearchIndex("fts", (q) => q.search("fts", args.filter!.search!))
.paginate(args.paginationOpts);
}
if (args.filter?.createdById) {
query = query.filter((q) =>
q.eq(q.field("createdById"), args.filter?.createdById)
);
}
const { page, ...res } = await query.paginate(args.paginationOpts);
const users: (Doc<"users"> & {
profileImageUrl?: string;
})[] = await Promise.all(
page
.reduce(
(ids, protest) =>
ids.indexOf(protest.createdById) !== -1
? ids
: [...ids, protest.createdById],
[] as Id<"users">[]
)
.map(
(id) =>
ctx.runQuery(api.users.findById, { id }) as Promise<
Doc<"users"> & {
profileImageUrl?: string;
}
>
)
);
return {
...res,
page: page.map(
(protest) =>
({
...protest,
createdBy: users.find((u) => u?._id === protest.createdById),
}) as Doc<"protests"> & {
createdBy: Doc<"users"> & {
profileImageUrl?: string;
};
}
),
};
},
returns: v.object({
isDone: v.boolean(),
continueCursor: v.string(),
splitCursor: v.optional(v.union(v.string(), v.null())),
pageStatus: v.optional(
v.union(
v.literal("SplitRecommended"),
v.literal("SplitRequired"),
v.null()
)
),
page: v.array(
v.object({
_id: v.id("protests"),
_creationTime: v.number(),
name: v.string(),
startDate: v.number(),
endDate: v.optional(v.number()),
createdById: v.id("users"),
mainLocationId: v.optional(v.id("locations")),
missionStatement: v.string(),
fts: v.string(),
createdBy: v.object({
name: v.optional(v.string()),
image: v.optional(v.string()),
email: v.optional(v.string()),
emailVerificationTime: v.optional(v.number()),
phone: v.optional(v.string()),
phoneVerificationTime: v.optional(v.number()),
isAnonymous: v.optional(v.boolean()),
profileImageId: v.optional(v.id("_storage")),
profileImageUrl: v.optional(v.string()),
}),
})
),
}),
});
export const find = query({
args: {
paginationOpts: paginationOptsValidator,
filter: v.optional(
v.object({
createdById: v.optional(v.id("users")),
search: v.optional(v.string()),
})
),
},
handler: async (ctx, args) => {
let query = ctx.db.query("protests");
if (args.filter?.search) {
return await query
.withSearchIndex("fts", (q) => q.search("fts", args.filter!.search!))
.paginate(args.paginationOpts);
}
if (args.filter?.createdById) {
query = query.filter((q) =>
q.eq(q.field("createdById"), args.filter?.createdById)
);
}
const { page, ...res } = await query.paginate(args.paginationOpts);
const users: (Doc<"users"> & {
profileImageUrl?: string;
})[] = await Promise.all(
page
.reduce(
(ids, protest) =>
ids.indexOf(protest.createdById) !== -1
? ids
: [...ids, protest.createdById],
[] as Id<"users">[]
)
.map(
(id) =>
ctx.runQuery(api.users.findById, { id }) as Promise<
Doc<"users"> & {
profileImageUrl?: string;
}
>
)
);
return {
...res,
page: page.map(
(protest) =>
({
...protest,
createdBy: users.find((u) => u?._id === protest.createdById),
}) as Doc<"protests"> & {
createdBy: Doc<"users"> & {
profileImageUrl?: string;
};
}
),
};
},
returns: v.object({
isDone: v.boolean(),
continueCursor: v.string(),
splitCursor: v.optional(v.union(v.string(), v.null())),
pageStatus: v.optional(
v.union(
v.literal("SplitRecommended"),
v.literal("SplitRequired"),
v.null()
)
),
page: v.array(
v.object({
_id: v.id("protests"),
_creationTime: v.number(),
name: v.string(),
startDate: v.number(),
endDate: v.optional(v.number()),
createdById: v.id("users"),
mainLocationId: v.optional(v.id("locations")),
missionStatement: v.string(),
fts: v.string(),
createdBy: v.object({
name: v.optional(v.string()),
image: v.optional(v.string()),
email: v.optional(v.string()),
emailVerificationTime: v.optional(v.number()),
phone: v.optional(v.string()),
phoneVerificationTime: v.optional(v.number()),
isAnonymous: v.optional(v.boolean()),
profileImageId: v.optional(v.id("_storage")),
profileImageUrl: v.optional(v.string()),
}),
})
),
}),
});