Order organization by name

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-09-11 18:30:01 +02:00
parent c73bb08f25
commit d0e3c63a05
10 changed files with 837 additions and 246 deletions

View File

@@ -41,8 +41,12 @@ type (
func (o Organization) CursorKey(orderBy OrganizationOrderField) page.CursorKey {
switch orderBy {
case OrganizationOrderFieldName:
return page.NewCursorKey(o.ID, o.Name)
case OrganizationOrderFieldCreatedAt:
return page.NewCursorKey(o.ID, o.CreatedAt)
case OrganizationOrderFieldUpdatedAt:
return page.NewCursorKey(o.ID, o.UpdatedAt)
}
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
@@ -90,6 +94,57 @@ LIMIT 1;
return nil
}
// Tenant id scope is not applied in this functions because we want to access all user's organizations.
func (o *Organizations) ListForUserID(
ctx context.Context,
conn pg.Conn,
userID gid.GID,
cursor *page.Cursor[OrganizationOrderField],
) error {
q := `
WITH user_org AS (
SELECT
organization_id
FROM
users_organizations
WHERE
user_id = @user_id
)
SELECT
tenant_id,
id,
name,
logo_object_key,
created_at,
updated_at
FROM
organizations
INNER JOIN
user_org ON organizations.id = user_org.organization_id
WHERE
%s
`
q = fmt.Sprintf(q, cursor.SQLFragment())
args := pgx.StrictNamedArgs{"user_id": userID}
maps.Copy(args, cursor.SQLArguments())
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query organizations: %w", err)
}
organizations, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[Organization])
if err != nil {
return fmt.Errorf("cannot collect organizations: %w", err)
}
*o = organizations
return nil
}
func (o *Organization) Insert(
ctx context.Context,
conn pg.Conn,

View File

@@ -4870,25 +4870,26 @@ func (r *vendorServiceResolver) Vendor(ctx context.Context, obj *types.VendorSer
func (r *viewerResolver) Organizations(ctx context.Context, obj *types.Viewer, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrganizationOrder, filter *types.OrganizationFilter) (*types.OrganizationConnection, error) {
user := UserFromContext(ctx)
// For now, we're not using cursor pagination since we're loading all organizations
organizations, err := r.usrmgrSvc.ListOrganizationsForUserID(ctx, user.ID)
pageOrderBy := page.OrderBy[coredata.OrganizationOrderField]{
Field: coredata.OrganizationOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
if orderBy != nil {
pageOrderBy = page.OrderBy[coredata.OrganizationOrderField]{
Field: orderBy.Field,
Direction: orderBy.Direction,
}
}
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
organizations, err := r.usrmgrSvc.ListOrganizationsForUserIDPaginated(ctx, user.ID, cursor)
if err != nil {
panic(fmt.Errorf("failed to list organizations for user: %w", err))
}
var edges []*types.OrganizationEdge
for _, organization := range organizations {
edges = append(edges, types.NewOrganizationEdge(organization, coredata.OrganizationOrderFieldCreatedAt))
}
page := page.NewPage(organizations, cursor)
// The simple implementation doesn't handle pagination yet
return &types.OrganizationConnection{
Edges: edges,
PageInfo: &types.PageInfo{
HasNextPage: false,
HasPreviousPage: false,
},
}, nil
return types.NewOrganizationConnection(page), nil
}
// Asset returns schema.AssetResolver implementation.

View File

@@ -515,6 +515,33 @@ func (s Service) ListOrganizationsForUserID(
return organizations, nil
}
// Tenant id scope is not applied in this functions because we want to access all user's organizations.
func (s Service) ListOrganizationsForUserIDPaginated(
ctx context.Context,
userID gid.GID,
cursor *page.Cursor[coredata.OrganizationOrderField],
) (coredata.Organizations, error) {
organizations := coredata.Organizations{}
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
err := organizations.ListForUserID(ctx, conn, userID, cursor)
if err != nil {
return fmt.Errorf("cannot list user organizations: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return organizations, nil
}
func (s Service) ListTenantsForUserID(
ctx context.Context,
userID gid.GID,