Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/routes/player/search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,15 @@ describe("player search 200", () => {
expect(data.parsed.results).toHaveLength(0)
}
})

test("membership id", async () => {
const data = await t({
query: "4611686018467831285"
})

if (data.type === "ok") {
expect(data.parsed.results.length).toBeGreaterThan(0)
expect(data.parsed.results[0].membershipId).toBe(BigInt("4611686018467831285"))
}
})

Copilot AI Feb 22, 2026

Copy link

Choose a reason for hiding this comment

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

The test for membership ID queries should include a test case that validates the membershipType filter is respected. Currently, there's no test verifying that when a membershipType filter is provided with a membership ID query, only players from that platform are returned (or the result is filtered out if the platform doesn't match).

Consider adding a test similar to "full bungie name wrong platform" that queries by membership ID with a mismatched membershipType to ensure proper filtering.

Suggested change
})
})
test("membership id wrong platform", async () => {
const data = await t({
query: "4611686018467831285",
membershipType: 2
})
if (data.type === "ok") {
expect(data.parsed.results).toHaveLength(0)
}
})

Copilot uses AI. Check for mistakes.
})
42 changes: 28 additions & 14 deletions src/services/search/player-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { playerSearchQueryTimer } from "@/integrations/prometheus/metrics"
import { withHistogramTimer } from "@/integrations/prometheus/util"
import { PlayerInfo } from "@/schema/components/PlayerInfo"
import { DestinyMembershipType } from "@/schema/enums/DestinyMembershipType"
import { getPlayer } from "@/services/player"

/**
* Case insensitive search
Expand All @@ -18,14 +19,17 @@ export async function searchForPlayer(
searchTerm: string
results: PlayerInfo[]
}> {
const searchTerm = query.trim().toLowerCase()
const trimmedQuery = query.trim()
const searchTerm = trimmedQuery.toLowerCase()
const isMembershipIdQuery = /^\d+$/.test(trimmedQuery)

const results = await withHistogramTimer(
playerSearchQueryTimer,
{ prefixLength: searchTerm.split("#")[0]?.length ?? 0 },
() =>
pgReader.queryRows<PlayerInfo>(
`SELECT
const [nameResults, membershipIdResult] = await Promise.all([
withHistogramTimer(
playerSearchQueryTimer,
{ prefixLength: searchTerm.split("#")[0]?.length ?? 0 },
() =>
pgReader.queryRows<PlayerInfo>(
`SELECT
membership_id AS "membershipId",
membership_type AS "membershipType",
icon_path AS "iconPath",
Expand All @@ -41,13 +45,23 @@ export async function searchForPlayer(
AND last_seen > TIMESTAMP 'epoch'
ORDER BY _search_score DESC
LIMIT $2;`,
{
params: opts.membershipType
? [searchTerm + "%", opts.count, opts.membershipType]
: [searchTerm + "%", opts.count]
}
)
)
{
params: opts.membershipType
? [searchTerm + "%", opts.count, opts.membershipType]
: [searchTerm + "%", opts.count]
}
)
),
isMembershipIdQuery ? getPlayer(trimmedQuery).catch(() => null) : Promise.resolve(null)
])

let results = nameResults
if (membershipIdResult) {
const membershipIdBigInt = BigInt(trimmedQuery)
if (!results.some(r => r.membershipId === membershipIdBigInt)) {

Copilot AI Feb 22, 2026

Copy link

Choose a reason for hiding this comment

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

The membership ID lookup does not respect the opts.membershipType filter. When a user specifies a membershipType filter (e.g., membershipType=2 for PlayStation), the name-based search correctly filters by platform, but the direct membership ID lookup via getPlayer() does not apply this filter. This could result in returning a player from a different platform than requested.

Consider filtering the membershipIdResult by membershipType before prepending it to results, similar to how the test "full bungie name wrong platform" expects zero results when the platform doesn't match.

Suggested change
if (!results.some(r => r.membershipId === membershipIdBigInt)) {
const membershipTypeMatches =
!opts.membershipType || membershipIdResult.membershipType === opts.membershipType
if (membershipTypeMatches && !results.some(r => r.membershipId === membershipIdBigInt)) {

Copilot uses AI. Check for mistakes.
results = [membershipIdResult, ...results]
}
}

Copilot AI Feb 22, 2026

Copy link

Choose a reason for hiding this comment

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

When a membership ID result is prepended to the name-based results, the total results array can exceed the requested opts.count limit. For example, if opts.count is 10 and the name search returns 10 results, prepending the membership ID result would yield 11 results total.

Consider either slicing the results array to maintain the count limit, or documenting that membership ID matches can cause the result count to be count+1.

Suggested change
if (results.length > opts.count) {
results = results.slice(0, opts.count)
}

Copilot uses AI. Check for mistakes.
return {
searchTerm,
Expand Down