diff --git a/builder/store/database/organization.go b/builder/store/database/organization.go index 0fbd2f8e..96f6197c 100644 --- a/builder/store/database/organization.go +++ b/builder/store/database/organization.go @@ -180,6 +180,15 @@ func (s *orgStoreImpl) Search(ctx context.Context, search string, per int, page Model(&orgs).Relation("Namespace") if search != "" { query.Where("LOWER(organization.name) like ? OR LOWER(organization.path) like ?", fmt.Sprintf("%%%s%%", search), fmt.Sprintf("%%%s%%", search)) + query.OrderExpr(` + CASE + WHEN LOWER(organization.path) = ? THEN 0 + WHEN LOWER(organization.path) LIKE ? THEN 1 + WHEN LOWER(organization.name) = ? THEN 2 + WHEN LOWER(organization.name) LIKE ? THEN 3 + ELSE 4 + END + `, search, fmt.Sprintf("%s%%", search), search, fmt.Sprintf("%s%%", search)) } if orgType != "" { query.Where("org_type = ?", orgType) diff --git a/builder/store/database/organization_test.go b/builder/store/database/organization_test.go index 80d33e7c..f7004977 100644 --- a/builder/store/database/organization_test.go +++ b/builder/store/database/organization_test.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "errors" + "slices" "testing" "time" @@ -259,3 +260,85 @@ func TestOrganizationStore_FindByUUID(t *testing.T) { require.NotNil(t, err) require.Nil(t, org) } + +func TestOrganizationStore_SearchOrder(t *testing.T) { + db := tests.InitTestDB() + defer db.Close() + ctx := context.TODO() + + store := database.NewOrgStoreWithDB(db) + orgsToCreate := []database.Organization{ + { + Name: "sss", + Nickname: "zzz org", + UUID: uuid.New(), + }, + { + Name: "sss-team", + Nickname: "alpha org", + UUID: uuid.New(), + }, + { + Name: "team-01", + Nickname: "sss", + UUID: uuid.New(), + }, + { + Name: "team-02", + Nickname: "sss group", + UUID: uuid.New(), + }, + { + Name: "team-03", + Nickname: "group sss", + UUID: uuid.New(), + }, + } + + for _, org := range orgsToCreate { + err := store.Create(ctx, &org, &database.Namespace{Path: org.Name}) + require.Nil(t, err) + } + + orgs, total, err := store.Search(ctx, "sss", 10, 1, "", "") + require.Nil(t, err) + require.Equal(t, 5, total) + + gotNames := make([]string, 0, len(orgs)) + for _, org := range orgs { + gotNames = append(gotNames, org.Name) + } + + require.Equal(t, []string{"sss", "sss-team", "team-01", "team-02", "team-03"}, gotNames) +} + +func TestOrganizationStore_SearchOrderCaseInsensitive(t *testing.T) { + db := tests.InitTestDB() + defer db.Close() + ctx := context.TODO() + + store := database.NewOrgStoreWithDB(db) + err := store.Create(ctx, &database.Organization{ + Name: "SSS-Exact", + Nickname: "display", + UUID: uuid.New(), + }, &database.Namespace{Path: "SSS-Exact"}) + require.Nil(t, err) + err = store.Create(ctx, &database.Organization{ + Name: "other", + Nickname: "sss", + UUID: uuid.New(), + }, &database.Namespace{Path: "other"}) + require.Nil(t, err) + + orgs, total, err := store.Search(ctx, "sss-exact", 10, 1, "", "") + require.Nil(t, err) + require.Equal(t, 1, total) + require.Len(t, orgs, 1) + require.Equal(t, "SSS-Exact", orgs[0].Name) + + orgs, total, err = store.Search(ctx, "SSS", 10, 1, "", "") + require.Nil(t, err) + require.Equal(t, 2, total) + require.True(t, slices.Equal([]string{"SSS-Exact", "other"}, []string{orgs[0].Name, orgs[1].Name})) +} diff --git a/user/component/organization.go b/user/component/organization.go index 82e4882f..8af170b4 100644 --- a/user/component/organization.go +++ b/user/component/organization.go @@ -186,7 +186,7 @@ func (c *organizationComponentImpl) Index(ctx context.Context, username, search } if dborg.Namespace != nil { org.Namespace = &types.Namespace{ - Path: dborg.Nickname, + Path: dborg.Namespace.Path, Type: string(dborg.Namespace.NamespaceType), UUID: dborg.Namespace.UUID, } diff --git a/user/component/organization_test.go b/user/component/organization_test.go index d83ea016..b3550da4 100644 --- a/user/component/organization_test.go +++ b/user/component/organization_test.go @@ -76,6 +76,10 @@ func TestOrganizationComponent_Index(t *testing.T) { Logo: "org-logo.png", OrgType: "school", Verified: false, + Namespace: &database.Namespace{ + Path: "org1", + NamespaceType: database.OrgNamespace, + }, }) dbOrgs = append(dbOrgs, database.Organization{ ID: 2, @@ -85,6 +89,10 @@ func TestOrganizationComponent_Index(t *testing.T) { Logo: "org-logo.png", OrgType: "school", Verified: false, + Namespace: &database.Namespace{ + Path: "org2", + NamespaceType: database.OrgNamespace, + }, }) mockOrgStore := mockdb.NewMockOrgStore(t) mockOrgStore.EXPECT().GetUserOwnOrgs(mock.Anything, "user1").Return(dbOrgs, len(dbOrgs), nil).Once() @@ -125,6 +133,12 @@ func TestOrganizationComponent_Index(t *testing.T) { if expectedOrgs[i].Verified != dbOrgs[i].Verified { return false } + if expectedOrgs[i].Namespace == nil { + return false + } + if expectedOrgs[i].Namespace.Path != dbOrgs[i].Namespace.Path { + return false + } } return true })