[object Object]

← 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)