@@ -15,6 +15,7 @@ import { json, param } from "service/validator/hono.ts";
15
15
import { assignRoles } from "share/logic/min-flow.ts" ;
16
16
import { ProjectSchema } from "share/schema.ts" ;
17
17
import * as v from "valibot" ;
18
+ import { multipleMatch } from "share/logic/multiple.ts" ;
18
19
19
20
import { at } from "share/lib.ts" ;
20
21
import preferenceRoutes from "./preferences.ts" ;
@@ -68,6 +69,7 @@ const route = new Hono<HonoOptions>()
68
69
. select ( {
69
70
id : participants . id ,
70
71
name : participants . name ,
72
+ roles_count : participants . roles_count ,
71
73
} )
72
74
. from ( participants )
73
75
. where (
@@ -115,6 +117,7 @@ const route = new Hono<HonoOptions>()
115
117
id : project_id ,
116
118
name : body . name ,
117
119
description : body . description ,
120
+ multiple_roles : body . multipleRoles ,
118
121
} ,
119
122
] )
120
123
. returning ( )
@@ -194,59 +197,143 @@ const route = new Hono<HonoOptions>()
194
197
return c . json ( { message : "Unauthorized" } , 401 ) ;
195
198
}
196
199
197
- await db ( c )
198
- . update ( projects )
199
- . set ( {
200
- closed_at : new Date ( ) . toISOString ( ) ,
201
- } )
202
- . where ( eq ( projects . id , projectId ) ) ;
200
+ const projectData = (
201
+ await db ( c ) . select ( ) . from ( projects ) . where ( eq ( projects . id , projectId ) )
202
+ ) [ 0 ] ;
203
203
204
- const participantsData = await db ( c )
205
- . select ( )
206
- . from ( ratings )
207
- . where ( eq ( ratings . project_id , projectId ) )
208
- . orderBy ( ratings . participant_id , ratings . role_id ) ;
204
+ if ( ! projectData ) {
205
+ throw new HTTPException ( 404 , { message : "Project not found" } ) ;
206
+ }
209
207
210
- const ratingsByParticipant = Map . groupBy (
211
- participantsData ,
212
- ( item ) => item . participant_id ,
213
- ) ;
208
+ if ( projectData . closed_at ) {
209
+ throw new HTTPException ( 409 , { message : "Project already finalized" } ) ;
210
+ }
214
211
215
- const ratingsArray : number [ ] [ ] = [ ] ; // TODO: 型付けをマシにする
216
- const participantIndexIdMap : string [ ] = [ ] ;
212
+ if ( projectData . multiple_roles ) {
213
+ // multiple mode
214
+ const participantsWithPreferences = await db ( c )
215
+ . select ( {
216
+ id : participants . id ,
217
+ rolesCount : participants . roles_count ,
218
+ score : ratings . score ,
219
+ roleId : ratings . role_id ,
220
+ } )
221
+ . from ( participants )
222
+ . innerJoin (
223
+ ratings ,
224
+ and (
225
+ eq ( participants . id , ratings . participant_id ) ,
226
+ eq ( participants . project_id , ratings . project_id ) ,
227
+ ) ,
228
+ )
229
+ . where ( eq ( participants . project_id , projectId ) ) ;
217
230
218
- ratingsByParticipant . forEach ( ( r ) => {
219
- ratingsArray . push ( r . map ( ( item ) => item . score ) ) ;
220
- participantIndexIdMap . push ( r [ 0 ] ?. participant_id ?? "-" ) ;
221
- } ) ;
231
+ const preferencesByParticipant = Map . groupBy (
232
+ participantsWithPreferences ,
233
+ ( p ) => p . id ,
234
+ ) ;
222
235
223
- const roleConstraints = await db ( c )
224
- . select ( )
225
- . from ( roles )
226
- . where ( eq ( roles . project_id , projectId ) )
227
- . orderBy ( roles . id ) ;
228
- const minMaxConstraints = roleConstraints . map ( ( role ) => ( {
229
- min : role . min ,
230
- max : role . max ,
231
- } ) ) ;
236
+ const participantInput = Array . from (
237
+ preferencesByParticipant . entries ( ) ,
238
+ ) . map ( ( [ participantId , preferences ] ) => ( {
239
+ id : participantId ,
240
+ rolesCount : preferences [ 0 ] ?. rolesCount ?? 0 ,
241
+ preferences : preferences . map ( ( p ) => ( {
242
+ roleId : p . roleId ,
243
+ score : p . score ,
244
+ } ) ) ,
245
+ } ) ) ;
232
246
233
- const result = assignRoles (
234
- ratingsArray ,
235
- at ( ratingsArray , 0 ) . length ,
236
- minMaxConstraints ,
237
- ) ;
247
+ const roleConstraints = await db ( c )
248
+ . select ( )
249
+ . from ( roles )
250
+ . where ( eq ( roles . project_id , projectId ) )
251
+ . orderBy ( roles . id ) ;
238
252
239
- await db ( c )
240
- . insert ( matches )
241
- . values (
242
- result . map ( ( r ) => ( {
243
- id : crypto . randomUUID ( ) ,
244
- project_id : projectId ,
245
- role_id : roleConstraints [ r . role ] ?. id ?? "-" ,
246
- participant_id : participantIndexIdMap [ r . participant ] ?? "-" ,
247
- } ) ) ,
253
+ const roleInput = roleConstraints . map ( ( role ) => ( {
254
+ id : role . id ,
255
+ capacity : role . max , // multiple mode の場合、max と min は同一
256
+ } ) ) ;
257
+
258
+ console . log ( participantInput ) ;
259
+ console . log ( roleInput ) ;
260
+
261
+ const matching = multipleMatch ( participantInput , roleInput ) ;
262
+ console . log ( matching ) ;
263
+
264
+ const result : {
265
+ id : string ;
266
+ project_id : string ;
267
+ role_id : string ;
268
+ participant_id : string ;
269
+ } [ ] = [ ] ;
270
+ matching . forEach ( ( m ) => {
271
+ m . roleIds . forEach ( ( roleId ) => {
272
+ result . push ( {
273
+ id : crypto . randomUUID ( ) ,
274
+ project_id : projectId ,
275
+ role_id : roleId ,
276
+ participant_id : m . participantId ,
277
+ } ) ;
278
+ } ) ;
279
+ } ) ;
280
+
281
+ await db ( c ) . insert ( matches ) . values ( result ) ;
282
+ } else {
283
+ // default mode
284
+ const participantsData = await db ( c )
285
+ . select ( )
286
+ . from ( ratings )
287
+ . where ( eq ( ratings . project_id , projectId ) )
288
+ . orderBy ( ratings . participant_id , ratings . role_id ) ;
289
+
290
+ const ratingsByParticipant = Map . groupBy (
291
+ participantsData ,
292
+ ( item ) => item . participant_id ,
248
293
) ;
249
294
295
+ const ratingsArray : number [ ] [ ] = [ ] ; // TODO: 型付けをマシにする
296
+ const participantIndexIdMap : string [ ] = [ ] ;
297
+
298
+ ratingsByParticipant . forEach ( ( r ) => {
299
+ ratingsArray . push ( r . map ( ( item ) => item . score ) ) ;
300
+ participantIndexIdMap . push ( r [ 0 ] ?. participant_id ?? "-" ) ;
301
+ } ) ;
302
+
303
+ const roleConstraints = await db ( c )
304
+ . select ( )
305
+ . from ( roles )
306
+ . where ( eq ( roles . project_id , projectId ) )
307
+ . orderBy ( roles . id ) ;
308
+ const minMaxConstraints = roleConstraints . map ( ( role ) => ( {
309
+ min : role . min ,
310
+ max : role . max ,
311
+ } ) ) ;
312
+
313
+ const result = assignRoles (
314
+ ratingsArray ,
315
+ at ( ratingsArray , 0 ) . length ,
316
+ minMaxConstraints ,
317
+ ) ;
318
+
319
+ await db ( c )
320
+ . insert ( matches )
321
+ . values (
322
+ result . map ( ( r ) => ( {
323
+ id : crypto . randomUUID ( ) ,
324
+ project_id : projectId ,
325
+ role_id : roleConstraints [ r . role ] ?. id ?? "-" ,
326
+ participant_id : participantIndexIdMap [ r . participant ] ?? "-" ,
327
+ } ) ) ,
328
+ ) ;
329
+ }
330
+ await db ( c )
331
+ . update ( projects )
332
+ . set ( {
333
+ closed_at : new Date ( ) . toISOString ( ) ,
334
+ } )
335
+ . where ( eq ( projects . id , projectId ) ) ;
336
+
250
337
return c . json ( { } , 200 ) ;
251
338
} )
252
339
. get ( "/:projectId/result" , param ( { projectId : v . string ( ) } ) , async ( c ) => {
0 commit comments