From cea19083b4eeca351cc790f897bd8a2635f044d1 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 21 May 2026 22:50:38 +0200 Subject: [PATCH] Add ?search= server-side ILIKE filter to words, pictures, categories - words: ILIKE across titel_de, titel_en, titel_sv - pictures: ILIKE on design - categories: ILIKE across name_de, name_en, name_sv Co-Authored-By: Claude Sonnet 4.6 --- src/routes/categories.js | 12 +++++++++--- src/routes/pictures.js | 8 +++++--- src/routes/words.js | 7 ++++++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/routes/categories.js b/src/routes/categories.js index b14455c..e93a409 100644 --- a/src/routes/categories.js +++ b/src/routes/categories.js @@ -12,10 +12,16 @@ const STATUS_TIMESTAMP = { // GET /api/categories router.get('/', async (req, res, next) => { try { - const { status, limit = 50, offset = 0 } = req.query; + const { status, search, limit = 50, offset = 0 } = req.query; const params = [Math.min(parseInt(limit), 500), parseInt(offset)]; - const where = status ? `WHERE c.status = $3` : ''; - if (status) params.push(status); + const conditions = []; + if (status) { conditions.push(`c.status = $${params.length + 1}`); params.push(status); } + if (search) { + const p = `%${search.toLowerCase()}%`; + conditions.push(`(lower(c.name_de) LIKE $${params.length + 1} OR lower(c.name_en) LIKE $${params.length + 1} OR lower(c.name_sv) LIKE $${params.length + 1})`); + params.push(p); + } + const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : ''; const result = await query( `SELECT c.*, COALESCE(json_agg(DISTINCT w.id) FILTER (WHERE w.id IS NOT NULL), '[]') AS word_ids diff --git a/src/routes/pictures.js b/src/routes/pictures.js index 7eb7ea6..d6917d9 100644 --- a/src/routes/pictures.js +++ b/src/routes/pictures.js @@ -12,10 +12,12 @@ const ALLOWED_BLOCKED_REASONS = ['regenerate', 'not_to_use']; // GET /api/pictures router.get('/', async (req, res, next) => { try { - const { status, limit = 50, offset = 0 } = req.query; + const { status, search, limit = 50, offset = 0 } = req.query; const params = [Math.min(parseInt(limit), 500), parseInt(offset)]; - const where = status ? `WHERE status = $3` : ''; - if (status) params.push(status); + const conditions = []; + if (status) { conditions.push(`status = $${params.length + 1}`); params.push(status); } + if (search) { conditions.push(`lower(design) LIKE $${params.length + 1}`); params.push(`%${search.toLowerCase()}%`); } + const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : ''; const result = await query( `SELECT * FROM pictures ${where} ORDER BY created_at DESC LIMIT $1 OFFSET $2`, params diff --git a/src/routes/words.js b/src/routes/words.js index da358b0..0d8c490 100644 --- a/src/routes/words.js +++ b/src/routes/words.js @@ -12,11 +12,16 @@ const STATUS_TIMESTAMP = { // GET /api/words router.get('/', async (req, res, next) => { try { - const { status, titel_de, limit = 50, offset = 0 } = req.query; + const { status, titel_de, search, limit = 50, offset = 0 } = req.query; const params = [Math.min(parseInt(limit), 500), parseInt(offset)]; const conditions = []; if (status) { conditions.push(`w.status = $${params.length + 1}`); params.push(status); } if (titel_de) { conditions.push(`lower(w.titel_de) = lower($${params.length + 1})`); params.push(titel_de); } + if (search) { + const p = `%${search.toLowerCase()}%`; + conditions.push(`(lower(w.titel_de) LIKE $${params.length + 1} OR lower(w.titel_en) LIKE $${params.length + 1} OR lower(w.titel_sv) LIKE $${params.length + 1})`); + params.push(p); + } const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : ''; const result = await query( `SELECT w.*,