fix(search): ensure results are deduplicated

This commit is contained in:
Cory Dransfeldt 2025-06-18 11:16:08 -07:00
parent 5684b461fd
commit 55da3dc27b
No known key found for this signature in database
4 changed files with 31 additions and 23 deletions

18
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "coryd.dev", "name": "coryd.dev",
"version": "10.7.3", "version": "10.7.4",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "coryd.dev", "name": "coryd.dev",
"version": "10.7.3", "version": "10.7.4",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"minisearch": "^7.1.2", "minisearch": "^7.1.2",
@ -37,7 +37,7 @@
"postcss-import-ext-glob": "^2.1.1", "postcss-import-ext-glob": "^2.1.1",
"prettier": "3.5.3", "prettier": "3.5.3",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"sql-formatter": "15.6.4", "sql-formatter": "15.6.5",
"terser": "^5.43.0", "terser": "^5.43.0",
"truncate-html": "^1.2.2" "truncate-html": "^1.2.2"
}, },
@ -1681,9 +1681,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.169", "version": "1.5.170",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.169.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.170.tgz",
"integrity": "sha512-q7SQx6mkLy0GTJK9K9OiWeaBMV4XQtBSdf6MJUzDB/H/5tFXfIiX38Lci1Kl6SsgiEhz1SQI1ejEOU5asWEhwQ==", "integrity": "sha512-GP+M7aeluQo9uAyiTCxgIj/j+PrWhMlY7LFVj8prlsPljd0Fdg9AprlfUi+OCSFWy9Y5/2D/Jrj9HS8Z4rpKWA==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -5298,9 +5298,9 @@
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/sql-formatter": { "node_modules/sql-formatter": {
"version": "15.6.4", "version": "15.6.5",
"resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.6.4.tgz", "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.6.5.tgz",
"integrity": "sha512-osSvFAtUu/SqT4ywdPTraCHR/VzMjeG+cXFEGwJJtm2SoA/uewU6Sm2HYyqo6W7VTGSWUWx7WT8KkE3HJq51cA==", "integrity": "sha512-fr4TyM1udCSrOHOmouotwUi8dxIDhSLpYNmPePGFVzxq8/i8jd828IapE49QXG7Gzkswxo5WwdAGnYX4YpKoTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {

View file

@ -1,6 +1,6 @@
{ {
"name": "coryd.dev", "name": "coryd.dev",
"version": "10.7.3", "version": "10.7.4",
"description": "The source for my personal site. Built using 11ty (and other tools).", "description": "The source for my personal site. Built using 11ty (and other tools).",
"type": "module", "type": "module",
"engines": { "engines": {
@ -66,7 +66,7 @@
"postcss-import-ext-glob": "^2.1.1", "postcss-import-ext-glob": "^2.1.1",
"prettier": "3.5.3", "prettier": "3.5.3",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"sql-formatter": "15.6.4", "sql-formatter": "15.6.5",
"terser": "^5.43.0", "terser": "^5.43.0",
"truncate-html": "^1.2.2" "truncate-html": "^1.2.2"
} }

View file

@ -1,7 +1,7 @@
CREATE OR REPLACE VIEW optimized_search_index AS CREATE OR REPLACE VIEW optimized_search_index AS
WITH WITH
search_data AS ( search_data AS (
SELECT SELECT DISTINCT ON (p.url)
p.title, p.title,
p.url::TEXT AS url, p.url::TEXT AS url,
p.description AS description, p.description AS description,
@ -15,7 +15,7 @@ WITH
FROM FROM
optimized_posts p optimized_posts p
UNION ALL UNION ALL
SELECT SELECT DISTINCT ON (l.link)
CONCAT(l.title, ' via ', l.name) AS title, CONCAT(l.title, ' via ', l.name) AS title,
l.link::TEXT AS url, l.link::TEXT AS url,
l.description AS description, l.description AS description,
@ -29,7 +29,7 @@ WITH
FROM FROM
optimized_links l optimized_links l
UNION ALL UNION ALL
SELECT SELECT DISTINCT ON (b.url)
CASE CASE
WHEN b.rating IS NOT NULL THEN CONCAT(b.title, ' (', b.rating, ')') WHEN b.rating IS NOT NULL THEN CONCAT(b.title, ' (', b.rating, ')')
ELSE b.title ELSE b.title
@ -48,11 +48,11 @@ WITH
WHERE WHERE
LOWER(b.status) = 'finished' LOWER(b.status) = 'finished'
UNION ALL UNION ALL
SELECT SELECT DISTINCT ON (ar.url)
ar.name AS title, ar.name AS title,
ar.url::TEXT AS url, ar.url::TEXT AS url,
ar.description AS description, ar.description AS description,
ARRAY[ar.genre_name] AS tags, ARRAY_REMOVE(ARRAY[NULLIF(ar.genre_name, '')], NULL) AS tags,
CONCAT( CONCAT(
COALESCE(ar.emoji, ar.genre_emoji, '🎧'), COALESCE(ar.emoji, ar.genre_emoji, '🎧'),
' ', ' ',
@ -66,7 +66,7 @@ WITH
FROM FROM
optimized_artists ar optimized_artists ar
UNION ALL UNION ALL
SELECT SELECT DISTINCT ON (g.url)
g.name AS title, g.name AS title,
g.url::TEXT AS url, g.url::TEXT AS url,
g.description AS description, g.description AS description,
@ -80,7 +80,7 @@ WITH
FROM FROM
optimized_genres g optimized_genres g
UNION ALL UNION ALL
SELECT SELECT DISTINCT ON (s.url)
CONCAT(s.title, ' (', s.year, ')') AS title, CONCAT(s.title, ' (', s.year, ')') AS title,
s.url::TEXT AS url, s.url::TEXT AS url,
s.description AS description, s.description AS description,
@ -96,7 +96,7 @@ WITH
WHERE WHERE
s.last_watched_at IS NOT NULL s.last_watched_at IS NOT NULL
UNION ALL UNION ALL
SELECT SELECT DISTINCT ON (m.url)
CASE CASE
WHEN m.rating IS NOT NULL THEN CONCAT(m.title, ' (', m.rating, ')') WHEN m.rating IS NOT NULL THEN CONCAT(m.title, ' (', m.rating, ')')
ELSE CONCAT(m.title, ' (', m.year, ')') ELSE CONCAT(m.title, ' (', m.year, ')')

View file

@ -117,6 +117,7 @@ description: Search through posts and other content on my site.
let total = 0; let total = 0;
let debounceTimeout; let debounceTimeout;
let isLoading = false; let isLoading = false;
const resultIds = new Set();
const generateResultHTML = ({ title, url, description, type, tags, genre_name, genre_url, total_plays }) => ` const generateResultHTML = ({ title, url, description, type, tags, genre_name, genre_url, total_plays }) => `
<article class="search__results--result"> <article class="search__results--result">
@ -215,13 +216,14 @@ description: Search through posts and other content on my site.
} }
showLoadingMessage(); showLoadingMessage();
$loadMoreButton.style.display = "none"; $loadMoreButton.style.display = "none";
const results = await loadSearchIndex(query, getSelectedSections(), 1); const results = await loadSearchIndex(query, getSelectedSections(), 1);
currentResults = results;
currentPage = 1; currentPage = 1;
currentResults = results;
resultIds.clear();
results.forEach((r) => resultIds.add(r.id));
updateSearchResults(results); updateSearchResults(results);
}; };
@ -241,9 +243,15 @@ description: Search through posts and other content on my site.
const nextResults = await loadSearchIndex($input.value.trim(), getSelectedSections(), currentPage); const nextResults = await loadSearchIndex($input.value.trim(), getSelectedSections(), currentPage);
currentResults = [...currentResults, ...nextResults]; const filteredResults = nextResults.filter((item) => {
if (resultIds.has(item.id)) return false;
resultIds.add(item.id);
return true;
});
updateSearchResults(nextResults); currentResults = [...currentResults, ...filteredResults];
updateSearchResults(filteredResults);
}); });
})(); })();
}); });