Mhamdans17 commited on
Commit
4a28cd8
·
1 Parent(s): 97344b4

perf: completely fix N+1 query problem and select * in ListCompanies, ListBranches, and GetCurrentUser middleware

Browse files
controllers/auth_controller.go CHANGED
@@ -493,7 +493,7 @@ func ListKasir(c *gin.Context) {
493
  owner := userVal.(*models.User)
494
 
495
  var kasir []models.User
496
- if err := config.DB.Preload("Branch").Where("company_id = ? AND role = ?", *owner.CompanyID, "kasir").Find(&kasir).Error; err != nil {
497
  c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal mengambil data kasir"})
498
  return
499
  }
 
493
  owner := userVal.(*models.User)
494
 
495
  var kasir []models.User
496
+ if err := config.DB.Select("id, name, email, phone, role, company_id, branch_id, is_active, created_at").Preload("Branch").Where("company_id = ? AND role = ?", *owner.CompanyID, "kasir").Find(&kasir).Error; err != nil {
497
  c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal mengambil data kasir"})
498
  return
499
  }
controllers/company_controller.go CHANGED
@@ -76,7 +76,8 @@ func ListCompanies(c *gin.Context) {
76
  skipStr := c.Query("skip")
77
  searchQuery := c.Query("search")
78
 
79
- query := config.DB.Model(&models.Company{})
 
80
 
81
  if searchQuery != "" {
82
  query = query.Where("name ILIKE ? OR email ILIKE ? OR phone ILIKE ? OR address ILIKE ?",
@@ -103,23 +104,59 @@ func ListCompanies(c *gin.Context) {
103
  return
104
  }
105
 
106
- resp := []CompanyResponse{}
 
 
 
 
 
107
  for _, comp := range companies {
108
- var owner models.User
109
- err := config.DB.Where("company_id = ? AND role = ?", comp.ID, "owner").First(&owner).Error
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
 
 
 
111
  var ownerVerified *bool
112
  var ownerName, ownerEmail, ownerPhone string
113
 
114
- if err == nil {
115
  ownerName = owner.Name
116
  ownerEmail = owner.Email
117
  ownerPhone = owner.Phone
118
 
119
  if owner.Phone != "" {
120
- var otp models.OTP
121
- otpErr := config.DB.Where("phone_number = ? AND is_verified = ?", owner.Phone, true).First(&otp).Error
122
- isVerified := otpErr == nil
123
  ownerVerified = &isVerified
124
  }
125
  }
@@ -454,7 +491,7 @@ func ListBranches(c *gin.Context) {
454
  owner := userVal.(*models.User)
455
 
456
  var branches []models.Branch
457
- if err := config.DB.Where("company_id = ?", *owner.CompanyID).Find(&branches).Error; err != nil {
458
  c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal mengambil data cabang"})
459
  return
460
  }
 
76
  skipStr := c.Query("skip")
77
  searchQuery := c.Query("search")
78
 
79
+ query := config.DB.Model(&models.Company{}).
80
+ Select("id, name, bank_account_number, bank_name, address, email, phone, logo_url, is_active, fee_percentage, approved_at, created_at")
81
 
82
  if searchQuery != "" {
83
  query = query.Where("name ILIKE ? OR email ILIKE ? OR phone ILIKE ? OR address ILIKE ?",
 
104
  return
105
  }
106
 
107
+ if len(companies) == 0 {
108
+ c.JSON(http.StatusOK, []CompanyResponse{})
109
+ return
110
+ }
111
+
112
+ var companyIDs []uint
113
  for _, comp := range companies {
114
+ companyIDs = append(companyIDs, comp.ID)
115
+ }
116
+
117
+ // Ambil semua owner user dalam 1 query (hanya kolom yang diperlukan)
118
+ var owners []models.User
119
+ config.DB.Select("id, name, email, phone, company_id").
120
+ Where("company_id IN ? AND role = ?", companyIDs, "owner").
121
+ Find(&owners)
122
+
123
+ // Map company_id -> owner
124
+ ownerMap := make(map[uint]models.User)
125
+ var ownerPhones []string
126
+ for _, o := range owners {
127
+ if o.CompanyID != nil {
128
+ ownerMap[*o.CompanyID] = o
129
+ if o.Phone != "" {
130
+ ownerPhones = append(ownerPhones, o.Phone)
131
+ }
132
+ }
133
+ }
134
+
135
+ // Ambil status verifikasi OTP semua owner dalam 1 query
136
+ otpMap := make(map[string]bool)
137
+ if len(ownerPhones) > 0 {
138
+ var otps []models.OTP
139
+ config.DB.Select("phone_number").
140
+ Where("phone_number IN ? AND is_verified = ?", ownerPhones, true).
141
+ Find(&otps)
142
+ for _, otp := range otps {
143
+ otpMap[otp.PhoneNumber] = true
144
+ }
145
+ }
146
 
147
+ resp := []CompanyResponse{}
148
+ for _, comp := range companies {
149
+ owner, hasOwner := ownerMap[comp.ID]
150
  var ownerVerified *bool
151
  var ownerName, ownerEmail, ownerPhone string
152
 
153
+ if hasOwner {
154
  ownerName = owner.Name
155
  ownerEmail = owner.Email
156
  ownerPhone = owner.Phone
157
 
158
  if owner.Phone != "" {
159
+ isVerified := otpMap[owner.Phone]
 
 
160
  ownerVerified = &isVerified
161
  }
162
  }
 
491
  owner := userVal.(*models.User)
492
 
493
  var branches []models.Branch
494
+ if err := config.DB.Select("id, company_id, name, address, phone, is_active, created_at").Where("company_id = ?", *owner.CompanyID).Find(&branches).Error; err != nil {
495
  c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal mengambil data cabang"})
496
  return
497
  }
middleware/auth.go CHANGED
@@ -98,7 +98,7 @@ func GetCurrentUser() gin.HandlerFunc {
98
  }
99
 
100
  var user models.User
101
- if err := config.DB.Preload("Company").Preload("Branch").First(&user, claims.Sub).Error; err != nil {
102
  c.JSON(http.StatusUnauthorized, gin.H{"detail": "User tidak ditemukan"})
103
  c.Abort()
104
  return
 
98
  }
99
 
100
  var user models.User
101
+ if err := config.DB.Select("id, name, email, phone, role, company_id, branch_id, is_active, created_at").First(&user, claims.Sub).Error; err != nil {
102
  c.JSON(http.StatusUnauthorized, gin.H{"detail": "User tidak ditemukan"})
103
  c.Abort()
104
  return