// 마일스톤 생성
// 문제코드
const milestoneCreateResponse = await supabase
.from("milestone")
.insert(newMilestoneList)
.select()
supabase에서는 insert의 인자로 배열을 넣으면 bulk 처리가 가능합니다.
하지만 순서는 보장되지 않아서 만약에 위에 인자로 넣은 인덱스값이 중요하다면 곤란한 상황이 아닐 수 없습니다.
저장하는 개수가 적으면 상관없는데 많아지면 상당히 골치아파집니다...
순서를 보장받아야하는 이유도 해당 값을 어디선가 복잡하게 재사용해야한다는 건데 썩 좋은 방법처럼 보이지 않습니다.
식별 가능 아이디를 넣어주는 것도 방법일 수도 있습니다.
다만 그저 위의 기능만을 목적으로 한다면 조금 아쉬울 수 있는 방법처럼 보입니다.
또한 위의 배열에서 서로 배열 인덱스처럼 관련이 있는 값이어야 사용이 간편할 텐데 아마 적용이 어려울 수 있습니다.
내 배열에서만 순서가 1,2,3,4 로 시작하지 실제 db에서의 값과는 아무 상관이 없을 확률이 높기 때문입니다.
Promise.all() 메서드는 순회 가능한 객체에 주어진 모든 프로미스가 이행한 후, 혹은 프로미스가 주어지지 않았을 때 이행하는 Promise를 반환합니다. 주어진 프로미스 중 하나가 거부하는 경우, 첫 번째로 거절한 프로미스의 이유를 사용해 자신도 거부합니다.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
위의 이미지에서 완료 순서에 영향을 받지 않고 매개변수에 입력한 순서와 리턴 값이 같다고 합니다.
앞에서 제시한 문제코드를 promise.all 로 해결해보겠습니다.
// 해결코드
// 마일스톤 동시 생성 Promise 셋팅
const insertMileStonePromises = newMilestoneList.map((obj) =>
supabase.from("milestone").insert(obj).select()
)
// try, catch 내부 작업을 외부로 끌어낼 변수
let milestoneCreateResponses: PostgrestResponse<MilestoneType>[]
try {
// 마일스톤 생성
milestoneCreateResponses = await Promise.all(insertMileStonePromises)
} catch {
try {
// 마일스톤 생성 에러 발생시 첼린지 아이디를 에러로 리턴하여 해당 챌린지 삭제처리
// 삭제 로직을 분리하지 말고 여기서 바로 작성, 에러 코드에 메세지를 상세하게 작성해줄 것.
await supabase.from("challenge").delete().eq("id", newChallengeId)
} catch {
console.log(`챌린지 ${newChallengeId} 삭제 오류`)
}
return NextResponse.json(
{
error: {
message: "milestone create error",
},
},
{ status: 405 }
)
}
위의 코드를 간단하게 설명해보겠습니다.
newMilestoneList 이라는 객체 안에는 supabase의 insert 문에 들어갈 객체들이 있습니다.
이는 맨 위의 코드와 동일합니다.
newMilestoneList를 돌면서 배열에 비동기 함수를 담슴니다.
Promise.all 메서드 안에 해당 배열을 인자로 넣어주면 됩니다.
Promise.all의 리턴값의 형식은 인자로 넣어준 배열 요소의 response 값과 일치합니다.
따라서 Promise.all의 리턴값을 배열 안에 각각의 비동기 함수의 리턴 값으로 타입을 지정해주어 사용할 수 있습니다.
let milestoneCreateResponses: PostgrestResponse<MilestoneType>[]
긴글 읽어주셔서 감사합니다!