@@ -186,11 +186,32 @@ export async function handleReviews(
186186
187187 switch ( request . method ) {
188188 case "GET" :
189- return getReview ( { db, bucket, festivalId, drinkId, deviceId : deviceResult . deviceId , corsHeaders } ) ;
189+ return getReview ( {
190+ db,
191+ bucket,
192+ festivalId,
193+ drinkId,
194+ deviceId : deviceResult . deviceId ,
195+ corsHeaders,
196+ } ) ;
190197 case "PATCH" :
191- return upsertReview ( request , { db, bucket, festivalId, drinkId, deviceId : deviceResult . deviceId , corsHeaders } ) ;
198+ return upsertReview ( request , {
199+ db,
200+ bucket,
201+ festivalId,
202+ drinkId,
203+ deviceId : deviceResult . deviceId ,
204+ corsHeaders,
205+ } ) ;
192206 case "DELETE" :
193- return deleteReview ( { db, bucket, festivalId, drinkId, deviceId : deviceResult . deviceId , corsHeaders } ) ;
207+ return deleteReview ( {
208+ db,
209+ bucket,
210+ festivalId,
211+ drinkId,
212+ deviceId : deviceResult . deviceId ,
213+ corsHeaders,
214+ } ) ;
194215 default :
195216 return methodNotAllowed ( corsHeaders ) ;
196217 }
@@ -212,7 +233,14 @@ export async function handleReviews(
212233 if ( isReviewList ) {
213234 const deviceResult = getDeviceId ( request , corsHeaders ) ;
214235 if ( "error" in deviceResult ) return deviceResult . error ;
215- return listReviews ( { db, bucket, festivalId, deviceId : deviceResult . deviceId , url, corsHeaders } ) ;
236+ return listReviews ( {
237+ db,
238+ bucket,
239+ festivalId,
240+ deviceId : deviceResult . deviceId ,
241+ url,
242+ corsHeaders,
243+ } ) ;
216244 }
217245
218246 // isSummary
@@ -271,7 +299,8 @@ function summaryFields(row: Partial<SummaryRow>): Omit<ReviewSummary, "name"> {
271299 const recommendCount = row . recommend_count ?? 0 ;
272300 return {
273301 ratingCount,
274- averageRating : ratingCount && row . avg_rating != null ? round1 ( row . avg_rating ) : 0 ,
302+ averageRating :
303+ ratingCount && row . avg_rating != null ? round1 ( row . avg_rating ) : 0 ,
275304 responseCount,
276305 recommendCount,
277306 recommendRate : responseCount ? round2 ( recommendCount / responseCount ) : 0 ,
@@ -298,7 +327,13 @@ async function getReview(ctx: ReviewCtx): Promise<Response> {
298327 const { db, bucket, festivalId, drinkId, deviceId, corsHeaders } = ctx ;
299328 const row = await readRow ( db , bucket , festivalId , drinkId , deviceId ) ;
300329 if ( ! row ) {
301- return errorResponse ( 404 , "NOT_FOUND" , "No review found" , "NOT_FOUND" , corsHeaders ) ;
330+ return errorResponse (
331+ 404 ,
332+ "NOT_FOUND" ,
333+ "No review found" ,
334+ "NOT_FOUND" ,
335+ corsHeaders ,
336+ ) ;
302337 }
303338 return jsonResponse < Review > (
304339 serializeReview ( reviewName ( festivalId , drinkId ) , row ) ,
@@ -307,17 +342,32 @@ async function getReview(ctx: ReviewCtx): Promise<Response> {
307342 ) ;
308343}
309344
310- async function upsertReview ( request : Request , ctx : ReviewCtx ) : Promise < Response > {
345+ async function upsertReview (
346+ request : Request ,
347+ ctx : ReviewCtx ,
348+ ) : Promise < Response > {
311349 const { db, bucket, festivalId, drinkId, deviceId, corsHeaders } = ctx ;
312350
313351 let body : unknown ;
314352 try {
315353 body = await request . json ( ) ;
316354 } catch {
317- return errorResponse ( 400 , "INVALID_ARGUMENT" , "Invalid JSON body" , "INVALID_BODY" , corsHeaders ) ;
355+ return errorResponse (
356+ 400 ,
357+ "INVALID_ARGUMENT" ,
358+ "Invalid JSON body" ,
359+ "INVALID_BODY" ,
360+ corsHeaders ,
361+ ) ;
318362 }
319363 if ( body === null || typeof body !== "object" ) {
320- return errorResponse ( 400 , "INVALID_ARGUMENT" , "Body must be a JSON object" , "INVALID_BODY" , corsHeaders ) ;
364+ return errorResponse (
365+ 400 ,
366+ "INVALID_ARGUMENT" ,
367+ "Body must be a JSON object" ,
368+ "INVALID_BODY" ,
369+ corsHeaders ,
370+ ) ;
321371 }
322372
323373 // Parse updateMask: comma-separated field names. Absent/empty = all provided fields.
@@ -340,8 +390,10 @@ async function upsertReview(request: Request, ctx: ReviewCtx): Promise<Response>
340390 mask = new Set ( fields ) ;
341391 }
342392
343- const updateStar = mask === null ? "starRating" in patch : mask . has ( "starRating" ) ;
344- const updateRec = mask === null ? "wouldRecommend" in patch : mask . has ( "wouldRecommend" ) ;
393+ const updateStar =
394+ mask === null ? "starRating" in patch : mask . has ( "starRating" ) ;
395+ const updateRec =
396+ mask === null ? "wouldRecommend" in patch : mask . has ( "wouldRecommend" ) ;
345397
346398 if ( ! updateStar && ! updateRec ) {
347399 return errorResponse (
@@ -389,24 +441,44 @@ async function upsertReview(request: Request, ctx: ReviewCtx): Promise<Response>
389441 // Compute the final column values upfront so we can build the response
390442 // without a second DB read — avoids a round trip and the race where a
391443 // concurrent DELETE between write and re-read would make row! throw.
392- const finalStarRating = updateStar ? ( starRating ?? null ) : ( existing ?. star_rating ?? null ) ;
393- const finalRecommend = updateRec ? ( recommend ?? null ) : ( existing ?. recommend ?? null ) ;
444+ const finalStarRating = updateStar
445+ ? ( starRating ?? null )
446+ : ( existing ?. star_rating ?? null ) ;
447+ const finalRecommend = updateRec
448+ ? ( recommend ?? null )
449+ : ( existing ?. recommend ?? null ) ;
394450
395451 if ( existing ) {
396452 await db
397453 . prepare (
398454 "UPDATE reviews SET star_rating = ?, recommend = ?, updated_at = ? " +
399455 "WHERE bucket = ? AND festival_id = ? AND drink_id = ? AND device_id = ?" ,
400456 )
401- . bind ( finalStarRating , finalRecommend , now , bucket , festivalId , drinkId , deviceId )
457+ . bind (
458+ finalStarRating ,
459+ finalRecommend ,
460+ now ,
461+ bucket ,
462+ festivalId ,
463+ drinkId ,
464+ deviceId ,
465+ )
402466 . run ( ) ;
403467 } else {
404468 await db
405469 . prepare (
406470 "INSERT INTO reviews (bucket, festival_id, drink_id, device_id, star_rating, recommend, updated_at) " +
407471 "VALUES (?, ?, ?, ?, ?, ?, ?)" ,
408472 )
409- . bind ( bucket , festivalId , drinkId , deviceId , finalStarRating , finalRecommend , now )
473+ . bind (
474+ bucket ,
475+ festivalId ,
476+ drinkId ,
477+ deviceId ,
478+ finalStarRating ,
479+ finalRecommend ,
480+ now ,
481+ )
410482 . run ( ) ;
411483 }
412484
@@ -433,7 +505,13 @@ async function deleteReview(ctx: ReviewCtx): Promise<Response> {
433505
434506 const changes = result . meta ?. changes ?? 0 ;
435507 if ( ! changes ) {
436- return errorResponse ( 404 , "NOT_FOUND" , "No review found" , "NOT_FOUND" , corsHeaders ) ;
508+ return errorResponse (
509+ 404 ,
510+ "NOT_FOUND" ,
511+ "No review found" ,
512+ "NOT_FOUND" ,
513+ corsHeaders ,
514+ ) ;
437515 }
438516 return jsonResponse ( { } , 200 , corsHeaders ) ;
439517}
@@ -443,13 +521,25 @@ async function listReviews(ctx: ListCtx): Promise<Response> {
443521
444522 const sizeResult = resolvePageSize ( url . searchParams . get ( "page_size" ) ) ;
445523 if ( "error" in sizeResult ) {
446- return errorResponse ( 400 , "INVALID_ARGUMENT" , "page_size must be >= 0" , "INVALID_PAGE_SIZE" , corsHeaders ) ;
524+ return errorResponse (
525+ 400 ,
526+ "INVALID_ARGUMENT" ,
527+ "page_size must be >= 0" ,
528+ "INVALID_PAGE_SIZE" ,
529+ corsHeaders ,
530+ ) ;
447531 }
448532 const pageSize = sizeResult . value ;
449533
450534 const cursor = decodePageToken ( url . searchParams . get ( "page_token" ) ) ;
451535 if ( cursor === undefined ) {
452- return errorResponse ( 400 , "INVALID_ARGUMENT" , "Invalid page_token" , "INVALID_PAGE_TOKEN" , corsHeaders ) ;
536+ return errorResponse (
537+ 400 ,
538+ "INVALID_ARGUMENT" ,
539+ "Invalid page_token" ,
540+ "INVALID_PAGE_TOKEN" ,
541+ corsHeaders ,
542+ ) ;
453543 }
454544
455545 const where = [ "bucket = ?" , "festival_id = ?" , "device_id = ?" ] ;
@@ -510,13 +600,25 @@ async function listReviewSummaries(ctx: ListSummaryCtx): Promise<Response> {
510600
511601 const sizeResult = resolvePageSize ( url . searchParams . get ( "page_size" ) ) ;
512602 if ( "error" in sizeResult ) {
513- return errorResponse ( 400 , "INVALID_ARGUMENT" , "page_size must be >= 0" , "INVALID_PAGE_SIZE" , corsHeaders ) ;
603+ return errorResponse (
604+ 400 ,
605+ "INVALID_ARGUMENT" ,
606+ "page_size must be >= 0" ,
607+ "INVALID_PAGE_SIZE" ,
608+ corsHeaders ,
609+ ) ;
514610 }
515611 const pageSize = sizeResult . value ;
516612
517613 const cursor = decodePageToken ( url . searchParams . get ( "page_token" ) ) ;
518614 if ( cursor === undefined ) {
519- return errorResponse ( 400 , "INVALID_ARGUMENT" , "Invalid page_token" , "INVALID_PAGE_TOKEN" , corsHeaders ) ;
615+ return errorResponse (
616+ 400 ,
617+ "INVALID_ARGUMENT" ,
618+ "Invalid page_token" ,
619+ "INVALID_PAGE_TOKEN" ,
620+ corsHeaders ,
621+ ) ;
520622 }
521623
522624 const where = [ "bucket = ?" , "festival_id = ?" ] ;
0 commit comments