← back to 4square Admin
TK-11046 WS-C: exclude DELETED_FROM_SHOPIFY from counts + default browse
7e2e7772e395ee322c75f1fd90e90dee60a5a826 · 2026-09-03 12:40:30 -0700 · Steve
Total + per-vendor counts and the default shopify browse where-clause now filter
out deletion tombstones (null-safe IS DISTINCT FROM). Explicit shopify:status:X
override still works; the GROUP BY status view stays honest.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BbqKZLbd8emwVkNrxwtG2X
Files touched
Diff
commit 7e2e7772e395ee322c75f1fd90e90dee60a5a826
Author: Steve <steve@designerwallcoverings.com>
Date: Thu Sep 3 12:40:30 2026 -0700
TK-11046 WS-C: exclude DELETED_FROM_SHOPIFY from counts + default browse
Total + per-vendor counts and the default shopify browse where-clause now filter
out deletion tombstones (null-safe IS DISTINCT FROM). Explicit shopify:status:X
override still works; the GROUP BY status view stays honest.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BbqKZLbd8emwVkNrxwtG2X
---
server.js | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/server.js b/server.js
index 7fc1530..0134a41 100644
--- a/server.js
+++ b/server.js
@@ -43,8 +43,11 @@ app.get('/api/sources', async (_req, res) => {
pbTotal, pbCats, vwTotal, vwDecades, fbCells] = await Promise.all([
pool.query(`SELECT category, COUNT(*)::int AS n FROM spoon_all_designs WHERE category IS NOT NULL GROUP BY category ORDER BY 2 DESC`),
pool.query(`SELECT COUNT(*)::int AS n FROM spoon_all_designs`),
- pool.query(`SELECT vendor, COUNT(*)::int AS n FROM shopify_products WHERE vendor IS NOT NULL GROUP BY vendor ORDER BY 2 DESC LIMIT 30`),
- pool.query(`SELECT COUNT(*)::int AS n FROM shopify_products`),
+ // TK-11046: exclude DELETED_FROM_SHOPIFY tombstones from vendor + total counts
+ // (frozen-delete rows must not inflate the browse counts). The GROUP-BY-status
+ // view below is left honest (it legitimately shows the tombstone bucket).
+ pool.query(`SELECT vendor, COUNT(*)::int AS n FROM shopify_products WHERE vendor IS NOT NULL AND status IS DISTINCT FROM 'DELETED_FROM_SHOPIFY' GROUP BY vendor ORDER BY 2 DESC LIMIT 30`),
+ pool.query(`SELECT COUNT(*)::int AS n FROM shopify_products WHERE status IS DISTINCT FROM 'DELETED_FROM_SHOPIFY'`),
pool.query(`SELECT status, COUNT(*)::int AS n FROM shopify_products WHERE status IS NOT NULL GROUP BY status ORDER BY 2 DESC`),
safe(poolPB, `SELECT COUNT(*)::int AS n FROM patterns`),
safe(poolPB, `SELECT category, COUNT(*)::int AS n FROM patterns WHERE category IS NOT NULL GROUP BY category ORDER BY 2 DESC LIMIT 20`),
@@ -187,8 +190,13 @@ app.get('/api/products', async (req, res) => {
const parts = source.split(':');
const params = [];
let where = '1=1';
+ const isExplicitStatus = parts[1] === 'status' && parts[2];
if (parts[1] === 'vendor' && parts[2]) { params.push(parts.slice(2).join(':')); where = `vendor = $${params.length}`; }
- else if (parts[1] === 'status' && parts[2]) { params.push(parts[2]); where = `status = $${params.length}`; }
+ else if (isExplicitStatus) { params.push(parts[2]); where = `status = $${params.length}`; }
+ // TK-11046: hide DELETED_FROM_SHOPIFY tombstones from the default browse + counts.
+ // An explicit `shopify:status:DELETED_FROM_SHOPIFY` request still works (this
+ // exclusion is skipped whenever the user asked for a specific status).
+ if (!isExplicitStatus) where += ` AND status IS DISTINCT FROM 'DELETED_FROM_SHOPIFY'`;
if (q) {
params.push(`%${q}%`);
const i = params.length;
← 707a66c viewer standard: add Grid/List toggle + per-field on/off men
·
back to 4square Admin
·
(newest)