Skip to content

Commit 0841355

Browse files
Copilotowens1127
andauthored
Add membership ID support to player search (#116)
* Initial plan * Add search by membership ID support Co-authored-by: owens1127 <98496129+owens1127@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: owens1127 <98496129+owens1127@users.noreply.github.com>
1 parent 3de3225 commit 0841355

2 files changed

Lines changed: 39 additions & 14 deletions

File tree

src/routes/player/search.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,15 @@ describe("player search 200", () => {
7272
expect(data.parsed.results).toHaveLength(0)
7373
}
7474
})
75+
76+
test("membership id", async () => {
77+
const data = await t({
78+
query: "4611686018467831285"
79+
})
80+
81+
if (data.type === "ok") {
82+
expect(data.parsed.results.length).toBeGreaterThan(0)
83+
expect(data.parsed.results[0].membershipId).toBe(BigInt("4611686018467831285"))
84+
}
85+
})
7586
})

src/services/search/player-search.ts

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { playerSearchQueryTimer } from "@/integrations/prometheus/metrics"
33
import { withHistogramTimer } from "@/integrations/prometheus/util"
44
import { PlayerInfo } from "@/schema/components/PlayerInfo"
55
import { DestinyMembershipType } from "@/schema/enums/DestinyMembershipType"
6+
import { getPlayer } from "@/services/player"
67

78
/**
89
* Case insensitive search
@@ -18,14 +19,17 @@ export async function searchForPlayer(
1819
searchTerm: string
1920
results: PlayerInfo[]
2021
}> {
21-
const searchTerm = query.trim().toLowerCase()
22+
const trimmedQuery = query.trim()
23+
const searchTerm = trimmedQuery.toLowerCase()
24+
const isMembershipIdQuery = /^\d+$/.test(trimmedQuery)
2225

23-
const results = await withHistogramTimer(
24-
playerSearchQueryTimer,
25-
{ prefixLength: searchTerm.split("#")[0]?.length ?? 0 },
26-
() =>
27-
pgReader.queryRows<PlayerInfo>(
28-
`SELECT
26+
const [nameResults, membershipIdResult] = await Promise.all([
27+
withHistogramTimer(
28+
playerSearchQueryTimer,
29+
{ prefixLength: searchTerm.split("#")[0]?.length ?? 0 },
30+
() =>
31+
pgReader.queryRows<PlayerInfo>(
32+
`SELECT
2933
membership_id AS "membershipId",
3034
membership_type AS "membershipType",
3135
icon_path AS "iconPath",
@@ -41,13 +45,23 @@ export async function searchForPlayer(
4145
AND last_seen > TIMESTAMP 'epoch'
4246
ORDER BY _search_score DESC
4347
LIMIT $2;`,
44-
{
45-
params: opts.membershipType
46-
? [searchTerm + "%", opts.count, opts.membershipType]
47-
: [searchTerm + "%", opts.count]
48-
}
49-
)
50-
)
48+
{
49+
params: opts.membershipType
50+
? [searchTerm + "%", opts.count, opts.membershipType]
51+
: [searchTerm + "%", opts.count]
52+
}
53+
)
54+
),
55+
isMembershipIdQuery ? getPlayer(trimmedQuery).catch(() => null) : Promise.resolve(null)
56+
])
57+
58+
let results = nameResults
59+
if (membershipIdResult) {
60+
const membershipIdBigInt = BigInt(trimmedQuery)
61+
if (!results.some(r => r.membershipId === membershipIdBigInt)) {
62+
results = [membershipIdResult, ...results]
63+
}
64+
}
5165

5266
return {
5367
searchTerm,

0 commit comments

Comments
 (0)