Skip to content

feat: api key profile channel tags compposite, close #1220#1240

Merged
looplj merged 1 commit intorelease/v0.9.xfrom
dev-tmp
Apr 2, 2026
Merged

feat: api key profile channel tags compposite, close #1220#1240
looplj merged 1 commit intorelease/v0.9.xfrom
dev-tmp

Conversation

@looplj
Copy link
Copy Markdown
Owner

@looplj looplj commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a channelTagsMatchMode setting for API key profiles, allowing users to choose between 'any' and 'all' tag matching for channel filtering. The changes include frontend UI components, GraphQL schema updates, and backend logic for tag matching. Feedback suggests optimizing the MatchChannelTags method in internal/objects/apikey.go by using a map for lookups to improve time complexity from O(N*M) to O(N+M).

Comment on lines +44 to 70
func (p *APIKeyProfile) MatchChannelTags(tags []string) bool {
if p == nil || len(p.ChannelTags) == 0 {
return true
}

//nolint:exhaustive // Checked.
switch p.ChannelTagsMatchMode.OrDefault() {
case APIKeyMatchModeAll:
for _, allowedTag := range p.ChannelTags {
matched := slices.Contains(tags, allowedTag)

if !matched {
return false
}
}

return true
default:
for _, tag := range tags {
if slices.Contains(p.ChannelTags, tag) {
return true
}
}

return false
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation of MatchChannelTags uses slices.Contains within loops, which has a time complexity of O(N*M) and can be inefficient if the tag lists are large. This can be optimized to O(N+M) by using a map for lookups.

func (p *APIKeyProfile) MatchChannelTags(tags []string) bool {
	if p == nil || len(p.ChannelTags) == 0 {
		return true
	}

	//nolint:exhaustive // Checked.
	switch p.ChannelTagsMatchMode.OrDefault() {
	case APIKeyMatchModeAll:
		// For 'all' mode, all of p.ChannelTags must be in tags.
		// Create a set of the channel's tags for efficient lookup.
		tagSet := make(map[string]struct{}, len(tags))
		for _, tag := range tags {
			tagSet[tag] = struct{}{}
		}

		for _, allowedTag := range p.ChannelTags {
			if _, ok := tagSet[allowedTag]; !ok {
				return false
			}
		}

		return true
	default: // APIKeyMatchModeAny
		// For 'any' mode, at least one of the channel's tags must be in p.ChannelTags.
		// It's generally more efficient to build a set from the allowed tags.
		allowedTagSet := make(map[string]struct{}, len(p.ChannelTags))
		for _, allowedTag := range p.ChannelTags {
			allowedTagSet[allowedTag] = struct{}{}
		}

		for _, tag := range tags {
			if _, ok := allowedTagSet[tag]; ok {
				return true
			}
		}

		return false
	}
}

@looplj looplj merged commit 22a9702 into release/v0.9.x Apr 2, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant