phone.ts (4080B)
1 import { PhoneRepository } from "#core/application/phone/phone_repository.ts"; 2 import { 3 EntityLocked, 4 EntityNotFound, 5 } from "#core/application/repository_error.ts"; 6 import { PhoneEKYC } from "#core/domain/phone_ekyc.ts"; 7 import { InvalidUUID, UUID } from "#core/domain/uuid.ts"; 8 import { 9 mapFromPhoneEKYC, 10 mapToPhoneEKYC, 11 PhoneEKYCDto, 12 } from "#infrastructure/memory/mapper/phone.ts"; 13 import { mapError } from "#infrastructure/postgres/error.ts"; 14 import { Pool } from "$postgres"; 15 16 export class PostgresPhoneRepositoryAdapter implements PhoneRepository { 17 constructor(readonly pool: Pool) { 18 } 19 20 async findOrCreate(id: UUID): Promise<PhoneEKYC> { 21 try { 22 const connection = await this.pool.connect(); 23 try { 24 const result = await connection.queryObject<PhoneEKYCDto>` 25 select "uuid", "phoneNumber", "phoneNumberVerified", 26 "phoneNumberCode", "phoneNumberCodeExpire", 27 "phoneNumberChallengeRequest", "phoneNumberChallengeRequestExpire", 28 "phoneNumberChallengeAttempt", "phoneNumberChallengeAttemptExpire", 29 "version" 30 from "phone" 31 where uuid = ${id.toString()} 32 limit 1; 33 `; 34 if (result.rowCount !== 1) { 35 return new PhoneEKYC(id); 36 } 37 return mapToPhoneEKYC(result.rows[0]); 38 } finally { 39 connection.release(); 40 } 41 } catch (error) { 42 if (error instanceof InvalidUUID) { 43 throw new EntityNotFound(id.toString()); 44 } 45 throw mapError(error); 46 } 47 } 48 49 async store(phoneEKYC: PhoneEKYC): Promise<void> { 50 try { 51 const dto = mapFromPhoneEKYC(phoneEKYC); 52 const connection = await this.pool.connect(); 53 const transaction = connection.createTransaction( 54 `txn_${dto.uuid}_${dto.version}`, 55 ); 56 try { 57 await transaction.begin(); 58 dto.version++; 59 if (dto.version === 1) { 60 await transaction.queryArray` 61 insert into "phone" ( 62 "uuid", "phoneNumber", "phoneNumberVerified", 63 "phoneNumberCode", "phoneNumberCodeExpire", 64 "phoneNumberChallengeRequest", "phoneNumberChallengeRequestExpire", 65 "phoneNumberChallengeAttempt", "phoneNumberChallengeAttemptExpire", 66 "version" 67 ) values ( 68 ${dto.uuid}, ${dto.phoneNumber}, ${dto.phoneNumberVerified}, 69 ${dto.phoneNumberCode}, ${dto.phoneNumberCodeExpire}, 70 ${dto.phoneNumberChallengeRequest}, ${dto.phoneNumberChallengeRequestExpire}, 71 ${dto.phoneNumberChallengeAttempt}, ${dto.phoneNumberChallengeAttemptExpire}, 72 ${dto.version} 73 ); 74 `; 75 await transaction.commit(); 76 phoneEKYC.version = dto.version; 77 return; 78 } 79 const result = await transaction.queryObject<{ version: number }>` 80 update "phone" set 81 "phoneNumber" = ${dto.phoneNumber}, "phoneNumberVerified" = ${dto.phoneNumberVerified}, 82 "phoneNumberCode" = ${dto.phoneNumberCode}, "phoneNumberCodeExpire" = ${dto.phoneNumberCodeExpire}, 83 "phoneNumberChallengeRequest" = ${dto.phoneNumberChallengeRequest}, 84 "phoneNumberChallengeRequestExpire" = ${dto.phoneNumberChallengeRequestExpire}, 85 "phoneNumberChallengeAttempt" = ${dto.phoneNumberChallengeAttempt}, 86 "phoneNumberChallengeAttemptExpire" = ${dto.phoneNumberChallengeAttemptExpire}, 87 "version" = "version" + 1 88 where uuid = ${dto.uuid} 89 returning version; 90 `; 91 if (result.rowCount !== 1) { 92 transaction.rollback(); 93 throw new EntityNotFound(dto.uuid); 94 } 95 if (result.rows[0].version === dto.version) { 96 await transaction.commit(); 97 phoneEKYC.version = dto.version; 98 return; 99 } 100 transaction.rollback(); 101 throw new EntityLocked(); 102 } finally { 103 connection.release(); 104 } 105 } catch (error) { 106 throw mapError(error); 107 } 108 } 109 }