@@ -36,6 +36,7 @@ var orgPATFilterFields = map[string]string{
3636 "created_at" : "p.created_at" ,
3737 "expires_at" : "p.expires_at" ,
3838 "last_used_at" : "p.last_used_at" ,
39+ "regenerated_at" : "p.regenerated_at" ,
3940}
4041
4142// orgPATSearchColumns are searched with ILIKE when RQL search is used.
@@ -54,6 +55,7 @@ var orgPATSortFields = map[string]string{
5455 "created_at" : "p.created_at" ,
5556 "expires_at" : "p.expires_at" ,
5657 "last_used_at" : "p.last_used_at" ,
58+ "regenerated_at" : "p.regenerated_at" ,
5759}
5860
5961// OrgPATRow is the flat SQL result row from the joined query.
@@ -67,6 +69,7 @@ type OrgPATRow struct {
6769 CreatedAt time.Time `db:"pat_created_at"`
6870 ExpiresAt time.Time `db:"pat_expires_at"`
6971 LastUsedAt * time.Time `db:"pat_last_used_at"`
72+ RegeneratedAt * time.Time `db:"pat_regenerated_at"`
7073 RoleID * string `db:"role_id"`
7174 ResourceType * string `db:"resource_type"`
7275 ResourceID * string `db:"resource_id"`
@@ -177,7 +180,7 @@ func (r OrgPATsRepository) buildDataQuery(orgID string, rqlQuery *rql.Query) (st
177180 paginatedInner := inner .
178181 Select (
179182 goqu .I ("p.id" ), goqu .I ("p.title" ), goqu .I ("p.user_id" ),
180- goqu .I ("p.created_at" ), goqu .I ("p.expires_at" ), goqu .I ("p.last_used_at" ),
183+ goqu .I ("p.created_at" ), goqu .I ("p.expires_at" ), goqu .I ("p.last_used_at" ), goqu . I ( "p.regenerated_at" ),
181184 ).
182185 Offset (uint (rqlQuery .Offset )).
183186 Limit (uint (rqlQuery .Limit ))
@@ -192,6 +195,7 @@ func (r OrgPATsRepository) buildDataQuery(orgID string, rqlQuery *rql.Query) (st
192195 goqu .I ("p.created_at" ).As ("pat_created_at" ),
193196 goqu .I ("p.expires_at" ).As ("pat_expires_at" ),
194197 goqu .I ("p.last_used_at" ).As ("pat_last_used_at" ),
198+ goqu .I ("p.regenerated_at" ).As ("pat_regenerated_at" ),
195199 goqu .I ("pol.role_id" ),
196200 goqu .I ("pol.resource_type" ),
197201 goqu .I ("pol.resource_id" ),
@@ -207,13 +211,18 @@ func (r OrgPATsRepository) buildDataQuery(orgID string, rqlQuery *rql.Query) (st
207211 goqu .I ("pol.principal_id" ).Eq (goqu .I ("p.id" )),
208212 goqu .I ("pol.principal_type" ).Eq (schema .PATPrincipal ),
209213 ),
210- ).
211- Order (
212- goqu .I ("p.created_at" ).Desc (),
213- goqu .I ("p.id" ).Asc (),
214- goqu .I ("pol.role_id" ).Asc (),
215214 )
216215
216+ // Apply the same sort to the outer query to preserve the user's requested order.
217+ // The inner query sort controls pagination (which rows), the outer sort controls
218+ // final row order after the policy LEFT JOIN expands rows.
219+ outer , err = r .addSort (outer , rqlQuery .Sort )
220+ if err != nil {
221+ return "" , nil , err
222+ }
223+ // Add deterministic tiebreakers
224+ outer = outer .OrderAppend (goqu .I ("p.id" ).Asc (), goqu .I ("pol.role_id" ).Asc ())
225+
217226 return outer .ToSQL ()
218227}
219228
@@ -297,10 +306,11 @@ func (r OrgPATsRepository) groupRows(rows []OrgPATRow) []svc.AggregatedPAT {
297306 Title : row .CreatedByTitle ,
298307 Email : row .CreatedByEmail ,
299308 },
300- CreatedAt : row .CreatedAt ,
301- ExpiresAt : row .ExpiresAt ,
302- LastUsedAt : row .LastUsedAt ,
303- UserID : row .CreatedByID ,
309+ CreatedAt : row .CreatedAt ,
310+ ExpiresAt : row .ExpiresAt ,
311+ LastUsedAt : row .LastUsedAt ,
312+ RegeneratedAt : row .RegeneratedAt ,
313+ UserID : row .CreatedByID ,
304314 }
305315 patMap [row .PATID ] = pat
306316 patOrder = append (patOrder , row .PATID )
0 commit comments