actual zone search support? owo
This commit is contained in:
parent
821d05c141
commit
a11ff1326b
4 changed files with 116 additions and 9 deletions
|
@ -204,6 +204,21 @@ function useSearchResults(query, outfitState) {
|
||||||
setIsEndOfResults(false);
|
setIsEndOfResults(false);
|
||||||
}, [query]);
|
}, [query]);
|
||||||
|
|
||||||
|
// NOTE: This query should always load ~instantly, from the client cache.
|
||||||
|
const { data: zoneData } = useQuery(gql`
|
||||||
|
query SearchPanelZones {
|
||||||
|
allZones {
|
||||||
|
id
|
||||||
|
label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
const allZones = zoneData?.allZones || [];
|
||||||
|
const filterToZones = query.filterToZoneLabel
|
||||||
|
? allZones.filter((z) => z.label === query.filterToZoneLabel)
|
||||||
|
: [];
|
||||||
|
const filterToZoneIds = filterToZones.map((z) => z.id);
|
||||||
|
|
||||||
// Here's the actual GQL query! At the bottom we have more config than usual!
|
// Here's the actual GQL query! At the bottom we have more config than usual!
|
||||||
const {
|
const {
|
||||||
loading: loadingGQL,
|
loading: loadingGQL,
|
||||||
|
@ -215,11 +230,13 @@ function useSearchResults(query, outfitState) {
|
||||||
query SearchPanel(
|
query SearchPanel(
|
||||||
$query: String!
|
$query: String!
|
||||||
$speciesId: ID!
|
$speciesId: ID!
|
||||||
|
$zoneIds: [ID!]!
|
||||||
$colorId: ID!
|
$colorId: ID!
|
||||||
$offset: Int!
|
$offset: Int!
|
||||||
) {
|
) {
|
||||||
itemSearchToFit(
|
itemSearchToFit(
|
||||||
query: $query
|
query: $query
|
||||||
|
zoneIds: $zoneIds
|
||||||
speciesId: $speciesId
|
speciesId: $speciesId
|
||||||
colorId: $colorId
|
colorId: $colorId
|
||||||
offset: $offset
|
offset: $offset
|
||||||
|
@ -257,7 +274,13 @@ function useSearchResults(query, outfitState) {
|
||||||
${itemAppearanceFragment}
|
${itemAppearanceFragment}
|
||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
variables: { query: debouncedQuery.value, speciesId, colorId, offset: 0 },
|
variables: {
|
||||||
|
query: debouncedQuery.value,
|
||||||
|
zoneIds: filterToZoneIds,
|
||||||
|
speciesId,
|
||||||
|
colorId,
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
skip: !debouncedQuery.value && !debouncedQuery.filterToZoneLabel,
|
skip: !debouncedQuery.value && !debouncedQuery.filterToZoneLabel,
|
||||||
notifyOnNetworkStatusChange: true,
|
notifyOnNetworkStatusChange: true,
|
||||||
onCompleted: (d) => {
|
onCompleted: (d) => {
|
||||||
|
|
|
@ -233,6 +233,7 @@ const typeDefs = gql`
|
||||||
query: String!
|
query: String!
|
||||||
speciesId: ID!
|
speciesId: ID!
|
||||||
colorId: ID!
|
colorId: ID!
|
||||||
|
zoneIds: [ID!]
|
||||||
offset: Int
|
offset: Int
|
||||||
limit: Int
|
limit: Int
|
||||||
): ItemSearchResult!
|
): ItemSearchResult!
|
||||||
|
@ -634,7 +635,7 @@ const resolvers = {
|
||||||
},
|
},
|
||||||
itemSearchToFit: async (
|
itemSearchToFit: async (
|
||||||
_,
|
_,
|
||||||
{ query, speciesId, colorId, offset, limit },
|
{ query, speciesId, colorId, zoneIds, offset, limit },
|
||||||
{ petTypeBySpeciesAndColorLoader, itemSearchToFitLoader }
|
{ petTypeBySpeciesAndColorLoader, itemSearchToFitLoader }
|
||||||
) => {
|
) => {
|
||||||
const petType = await petTypeBySpeciesAndColorLoader.load({
|
const petType = await petTypeBySpeciesAndColorLoader.load({
|
||||||
|
@ -645,6 +646,7 @@ const resolvers = {
|
||||||
const items = await itemSearchToFitLoader.load({
|
const items = await itemSearchToFitLoader.load({
|
||||||
query: query.trim(),
|
query: query.trim(),
|
||||||
bodyId,
|
bodyId,
|
||||||
|
zoneIds,
|
||||||
offset,
|
offset,
|
||||||
limit,
|
limit,
|
||||||
});
|
});
|
||||||
|
|
|
@ -189,7 +189,7 @@ const buildItemSearchToFitLoader = (db, loaders) =>
|
||||||
// This isn't actually optimized as a batch query, we're just using a
|
// This isn't actually optimized as a batch query, we're just using a
|
||||||
// DataLoader API consistency with our other loaders!
|
// DataLoader API consistency with our other loaders!
|
||||||
const queryPromises = queryAndBodyIdPairs.map(
|
const queryPromises = queryAndBodyIdPairs.map(
|
||||||
async ({ query, bodyId, offset, limit }) => {
|
async ({ query, bodyId, zoneIds = [], offset, limit }) => {
|
||||||
const actualOffset = offset || 0;
|
const actualOffset = offset || 0;
|
||||||
const actualLimit = Math.min(limit || 30, 30);
|
const actualLimit = Math.min(limit || 30, 30);
|
||||||
|
|
||||||
|
@ -200,6 +200,10 @@ const buildItemSearchToFitLoader = (db, loaders) =>
|
||||||
const matcherPlaceholders = words
|
const matcherPlaceholders = words
|
||||||
.map((_) => "t.name LIKE ?")
|
.map((_) => "t.name LIKE ?")
|
||||||
.join(" AND ");
|
.join(" AND ");
|
||||||
|
const zoneIdsPlaceholder =
|
||||||
|
zoneIds.length > 0
|
||||||
|
? `swf_assets.zone_id IN (${zoneIds.map((_) => "?").join(", ")})`
|
||||||
|
: "1";
|
||||||
const [rows, _] = await db.execute(
|
const [rows, _] = await db.execute(
|
||||||
`SELECT DISTINCT items.*, t.name FROM items
|
`SELECT DISTINCT items.*, t.name FROM items
|
||||||
INNER JOIN item_translations t ON t.item_id = items.id
|
INNER JOIN item_translations t ON t.item_id = items.id
|
||||||
|
@ -207,10 +211,17 @@ const buildItemSearchToFitLoader = (db, loaders) =>
|
||||||
ON rel.parent_type = "Item" AND rel.parent_id = items.id
|
ON rel.parent_type = "Item" AND rel.parent_id = items.id
|
||||||
INNER JOIN swf_assets ON rel.swf_asset_id = swf_assets.id
|
INNER JOIN swf_assets ON rel.swf_asset_id = swf_assets.id
|
||||||
WHERE ${matcherPlaceholders} AND t.locale="en" AND
|
WHERE ${matcherPlaceholders} AND t.locale="en" AND
|
||||||
(swf_assets.body_id = ? OR swf_assets.body_id = 0)
|
(swf_assets.body_id = ? OR swf_assets.body_id = 0) AND
|
||||||
|
${zoneIdsPlaceholder}
|
||||||
ORDER BY t.name
|
ORDER BY t.name
|
||||||
LIMIT ? OFFSET ?`,
|
LIMIT ? OFFSET ?`,
|
||||||
[...wordMatchersForMysql, bodyId, actualLimit, actualOffset]
|
[
|
||||||
|
...wordMatchersForMysql,
|
||||||
|
bodyId,
|
||||||
|
...zoneIds,
|
||||||
|
actualLimit,
|
||||||
|
actualOffset,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const entities = rows.map(normalizeRow);
|
const entities = rows.map(normalizeRow);
|
||||||
|
|
|
@ -119,7 +119,8 @@ describe("ItemSearch", () => {
|
||||||
ON rel.parent_type = \\"Item\\" AND rel.parent_id = items.id
|
ON rel.parent_type = \\"Item\\" AND rel.parent_id = items.id
|
||||||
INNER JOIN swf_assets ON rel.swf_asset_id = swf_assets.id
|
INNER JOIN swf_assets ON rel.swf_asset_id = swf_assets.id
|
||||||
WHERE t.name LIKE ? AND t.name LIKE ? AND t.locale=\\"en\\" AND
|
WHERE t.name LIKE ? AND t.name LIKE ? AND t.locale=\\"en\\" AND
|
||||||
(swf_assets.body_id = ? OR swf_assets.body_id = 0)
|
(swf_assets.body_id = ? OR swf_assets.body_id = 0) AND
|
||||||
|
1
|
||||||
ORDER BY t.name
|
ORDER BY t.name
|
||||||
LIMIT ? OFFSET ?",
|
LIMIT ? OFFSET ?",
|
||||||
Array [
|
Array [
|
||||||
|
@ -134,6 +135,73 @@ describe("ItemSearch", () => {
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("loads Neopian Times items that fit the Starry Zafara as a Background", async () => {
|
||||||
|
const res = await query({
|
||||||
|
query: gql`
|
||||||
|
query {
|
||||||
|
itemSearchToFit(
|
||||||
|
query: "Neopian Times"
|
||||||
|
speciesId: "54"
|
||||||
|
colorId: "75"
|
||||||
|
zoneIds: ["3"]
|
||||||
|
) {
|
||||||
|
query
|
||||||
|
items {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res).toHaveNoErrors();
|
||||||
|
expect(res.data).toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"itemSearchToFit": Object {
|
||||||
|
"items": Array [
|
||||||
|
Object {
|
||||||
|
"id": "40431",
|
||||||
|
"name": "Neopian Times Background",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"query": "Neopian Times",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(getDbCalls()).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
Array [
|
||||||
|
"SELECT * FROM pet_types WHERE (species_id = ? AND color_id = ?)",
|
||||||
|
Array [
|
||||||
|
"54",
|
||||||
|
"75",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
"SELECT DISTINCT items.*, t.name FROM items
|
||||||
|
INNER JOIN item_translations t ON t.item_id = items.id
|
||||||
|
INNER JOIN parents_swf_assets rel
|
||||||
|
ON rel.parent_type = \\"Item\\" AND rel.parent_id = items.id
|
||||||
|
INNER JOIN swf_assets ON rel.swf_asset_id = swf_assets.id
|
||||||
|
WHERE t.name LIKE ? AND t.name LIKE ? AND t.locale=\\"en\\" AND
|
||||||
|
(swf_assets.body_id = ? OR swf_assets.body_id = 0) AND
|
||||||
|
swf_assets.zone_id IN (?)
|
||||||
|
ORDER BY t.name
|
||||||
|
LIMIT ? OFFSET ?",
|
||||||
|
Array [
|
||||||
|
"%Neopian%",
|
||||||
|
"%Times%",
|
||||||
|
"180",
|
||||||
|
"3",
|
||||||
|
30,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
it("searches for each word separately (fit mode)", async () => {
|
it("searches for each word separately (fit mode)", async () => {
|
||||||
const res = await query({
|
const res = await query({
|
||||||
query: gql`
|
query: gql`
|
||||||
|
@ -183,7 +251,8 @@ describe("ItemSearch", () => {
|
||||||
ON rel.parent_type = \\"Item\\" AND rel.parent_id = items.id
|
ON rel.parent_type = \\"Item\\" AND rel.parent_id = items.id
|
||||||
INNER JOIN swf_assets ON rel.swf_asset_id = swf_assets.id
|
INNER JOIN swf_assets ON rel.swf_asset_id = swf_assets.id
|
||||||
WHERE t.name LIKE ? AND t.name LIKE ? AND t.locale=\\"en\\" AND
|
WHERE t.name LIKE ? AND t.name LIKE ? AND t.locale=\\"en\\" AND
|
||||||
(swf_assets.body_id = ? OR swf_assets.body_id = 0)
|
(swf_assets.body_id = ? OR swf_assets.body_id = 0) AND
|
||||||
|
1
|
||||||
ORDER BY t.name
|
ORDER BY t.name
|
||||||
LIMIT ? OFFSET ?",
|
LIMIT ? OFFSET ?",
|
||||||
Array [
|
Array [
|
||||||
|
@ -242,7 +311,8 @@ describe("ItemSearch", () => {
|
||||||
ON rel.parent_type = \\"Item\\" AND rel.parent_id = items.id
|
ON rel.parent_type = \\"Item\\" AND rel.parent_id = items.id
|
||||||
INNER JOIN swf_assets ON rel.swf_asset_id = swf_assets.id
|
INNER JOIN swf_assets ON rel.swf_asset_id = swf_assets.id
|
||||||
WHERE t.name LIKE ? AND t.locale=\\"en\\" AND
|
WHERE t.name LIKE ? AND t.locale=\\"en\\" AND
|
||||||
(swf_assets.body_id = ? OR swf_assets.body_id = 0)
|
(swf_assets.body_id = ? OR swf_assets.body_id = 0) AND
|
||||||
|
1
|
||||||
ORDER BY t.name
|
ORDER BY t.name
|
||||||
LIMIT ? OFFSET ?",
|
LIMIT ? OFFSET ?",
|
||||||
Array [
|
Array [
|
||||||
|
@ -324,7 +394,8 @@ describe("ItemSearch", () => {
|
||||||
ON rel.parent_type = \\"Item\\" AND rel.parent_id = items.id
|
ON rel.parent_type = \\"Item\\" AND rel.parent_id = items.id
|
||||||
INNER JOIN swf_assets ON rel.swf_asset_id = swf_assets.id
|
INNER JOIN swf_assets ON rel.swf_asset_id = swf_assets.id
|
||||||
WHERE t.name LIKE ? AND t.locale=\\"en\\" AND
|
WHERE t.name LIKE ? AND t.locale=\\"en\\" AND
|
||||||
(swf_assets.body_id = ? OR swf_assets.body_id = 0)
|
(swf_assets.body_id = ? OR swf_assets.body_id = 0) AND
|
||||||
|
1
|
||||||
ORDER BY t.name
|
ORDER BY t.name
|
||||||
LIMIT ? OFFSET ?",
|
LIMIT ? OFFSET ?",
|
||||||
Array [
|
Array [
|
||||||
|
|
Loading…
Reference in a new issue