package main import ( "context" "errors" "github.com/ne-sachirou/dmmf-go/query" ) type EmailAddress string func NewEmailAddress(emailAddress string) (EmailAddress, error) { return EmailAddress(emailAddress), nil } type PhoneNumber string func NewPhoneNumber(phoneNumber string) (PhoneNumber, error) { return PhoneNumber(phoneNumber), nil } type ContactInfo interface{} type Email struct { ContactInfo EmailAddress EmailAddress } type Phone struct { ContactInfo PhoneNumber PhoneNumber } type Contact struct { ContactId int64 Info ContactInfo } type ContactRecord struct { ContactId int64 EmailAddress *string PhoneNumber *string } var InvalidContactRecord = errors.New("invalid contact record") func ContactRecordToDomain(dbRecord ContactRecord) (Contact, error) { var info ContactInfo if dbRecord.EmailAddress != nil { emailAddress, err := NewEmailAddress(*dbRecord.EmailAddress) if err != nil { return Contact{}, errors.Join(InvalidContactRecord, err) } info = Email{EmailAddress: emailAddress} } else if dbRecord.PhoneNumber != nil { phoneNumber, err := NewPhoneNumber(*dbRecord.PhoneNumber) if err != nil { return Contact{}, errors.Join(InvalidContactRecord, err) } info = Phone{PhoneNumber: phoneNumber} } else { return Contact{}, InvalidContactRecord } return Contact{ ContactId: dbRecord.ContactId, Info: info, }, nil } var ContactNotFound = errors.New("contact not found") var MultipleContactsFound = errors.New("multiple contacts found") // Gen/GORM を想定 func ReadOneContact(ctx context.Context, c query.Contact, contactId int64) (Contact, error) { var records []ContactRecord records, err := c.WithContext(ctx).Where(c.ContactId.EQ(contactId)).Find() if err != nil { return Contact{}, err } if len(records) == 0 { return Contact{}, ContactNotFound } if len(records) > 1 { return Contact{}, MultipleContactsFound } return ContactRecordToDomain(records[0]) } // Gen/GORM を想定 func WriteContect(ctx context.Context, c query.Contact, contact Contact) error { record := ContactRecord{ ContactId: contact.ContactId, } switch info := contact.Info.(type) { case Email: record.EmailAddress = (*string)(&info.EmailAddress) case Phone: record.PhoneNumber = (*string)(&info.PhoneNumber) default: return errors.New("invalid contact info") } if err := c.WithContext(ctx).Create(&record); err != nil { return err } if err := c.WithContext(ctx).Where(c.ContactId.EQ(contact.ContactId)).Update(record.EmailAddress, record.PhoneNumber); err != nil { return err } return nil }