|
1 | 1 | import type * as schema from '@tecnova/db'; |
2 | 2 | import { events, participants, sessions } from '@tecnova/db'; |
3 | 3 | import { fetchSheetRows, updateSheetRow } from '@tecnova/shared/google-sheets'; |
4 | | -import type { TodaySessionsResponse } from '@tecnova/shared/schemas'; |
5 | | -import { and, desc, eq, inArray, isNull, like } from 'drizzle-orm'; |
| 4 | +import type { ParticipantSearchItem, TodaySessionsResponse } from '@tecnova/shared/schemas'; |
| 5 | +import { and, asc, desc, eq, inArray, isNull, like } from 'drizzle-orm'; |
6 | 6 | import type { DrizzleD1Database } from 'drizzle-orm/d1'; |
7 | 7 |
|
8 | 8 | type Db = DrizzleD1Database<typeof schema>; |
@@ -424,6 +424,26 @@ export const fetchParticipantProfile = async ( |
424 | 424 | }; |
425 | 425 | }; |
426 | 426 |
|
| 427 | +// マニュアル入力画面のニックネーム検索。QR が読めない場面で使うので |
| 428 | +// 件数は実用上の上限(同名複数 + タイポ救済)として 50 件に制限する。 |
| 429 | +export const searchActiveParticipantsByNickname = async ( |
| 430 | + db: Db, |
| 431 | + query: string, |
| 432 | + limit = 50, |
| 433 | +): Promise<ParticipantSearchItem[]> => { |
| 434 | + const rows = await db |
| 435 | + .select({ |
| 436 | + id: participants.id, |
| 437 | + nickname: participants.nickname, |
| 438 | + grade: participants.grade, |
| 439 | + }) |
| 440 | + .from(participants) |
| 441 | + .where(and(eq(participants.active, true), like(participants.nickname, `%${query}%`))) |
| 442 | + .orderBy(asc(participants.nickname), asc(participants.id)) |
| 443 | + .limit(limit); |
| 444 | + return rows; |
| 445 | +}; |
| 446 | + |
427 | 447 | export const fetchReceptionHistoryToday = async (db: Db): Promise<TodaySessionsResponse> => { |
428 | 448 | const [event] = await db |
429 | 449 | .select({ id: events.id, date: events.date }) |
|
0 commit comments