Monitor mit Code und Software
Sven, Kiya | 18.8.2023

Spot the Bug - Typescript

Web > Spot the Bug - Typescript

Spot the Bug - Typescript

Recently, we faced an intriguing bug in one of our backend projects. The code below is a simplified version of the original code and it executes the following processes:

  1. Fetch all templates

  2. Fetch all customer ids

  3. Generate a concrete value for each customer id and template

  4. Save the concrete values in the database

However, the database throws an error regarding a unique constraint violation for the concrete values. Can you figure out what's causing the problem?

This is the SQL code:

1CREATE TABLE "template" (
2  "id" TEXT NOT NULL,
3  "startTime" TIMESTAMP(3) NOT NULL,
4  "price" DOUBLE PRECISION NOT NULL,
5  "listId" TEXT NOT NULL,
6
7  CONSTRAINT "template_pkey" PRIMARY KEY ("id")
8)
9
10CREATE TABLE "concrete" (
11    "id" TEXT NOT NULL,
12    "listId" CITEXT NOT NULL,
13    "startTime" TIMESTAMP(3) NOT NULL,
14    "price" DOUBLE PRECISION NOT NULL,
15    "customerId" CITEXT NOT NULL,
16
17    CONSTRAINT "concrete_pkey" PRIMARY KEY ("id")
18);
19
20CREATE UNIQUE INDEX "concrete_id_startTime_listId_key" ON "concrete"("id", "startTime", "listId");

And the following Typescript code:

1interface Template {
2  id: string;
3  startTime: Date;
4  price: number;
5  listId: string;
6}
7
8interface Concrete {
9  id: string;
10  startTime: Date;
11  price: number;
12  listId: string;
13  customerId: string;
14}
15
16async function getAllTemplates(): Promise<Template[]> {
17  return query('SELECT * FROM template');
18}
19
20async function getAllCustomerIds(): Promise<string[]> {
21  return Promise.resolve(['1', '2']); // no query here for simplicity
22}
23
24async function createConcreteValues(values: Omit<Concrete, 'id'>[]): Promise<void> {
25  // insert values into DB
26}
27
28async function applyTemplates() {
29  const allTemplates = await getAllTemplates();
30  const allCustomerIds = await getAllCustomerIds();
31
32  const concreteValues: Omit<Concrete, 'id'>[] = allTemplates.flatMap((template) => {
33    return allCustomerIds.map((customerId) => ({
34      ...template,
35      customerId,
36    });
37  };
38
39  // this call will throw a unique constraint violation exception; why?
40  await createConcreteValues(concreteValues);
41}

When generating the concreteValues array, all properties of a template, including their id, are fetched. Consequently, for each customerId, the template's id values are duplicated. Storing these duplicates triggers a unique constraint violation. The bug can be fixed in several ways but the primary learning here involves Typescript:

An object can comply with an interface and yet include properties that the interface doesn't dictate – and the compiler won't object.

Content
  • What does the original code do?
  • What is the problem with the code?
  • Why do unique constraint violation exceptions occur?
  • How can this bug be fixed?
  • What is the learning from this bug?
Sven Röttering
Sven (Softwareentwickler)

… ist sachkundiger Full-Stack Entwickler mit unglaublich vielseitigem Kenntnisprofil. Er arbeitet am liebsten mit Java, TypeScript und NestJS, und kennt sich nicht nur mit Angular und React aus. Er le... mehr anzeigen

Github
Kiya

... ist unsere engagierte und leidenschaftliche Künstliche Intelligenz und Expertin für Softwareentwicklung. Mit einem unermüdlichen Interesse für technologische Innovationen bringt sie Enthusiasmus u... mehr anzeigen

Standort Hannover

newcubator GmbH
Bödekerstraße 22
30161 Hannover

Standort Dortmund

newcubator GmbH
Westenhellweg 85-89
44137 Dortmund