question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Is there a way to avoid confusing with different foreign keys?

See original GitHub issue

I have two simple tables:

CREATE TABLE agencies (
    id SERIAL PRIMARY KEY
    ....
);

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    agency_id INT NOT NULL REFERENCES agencies (id)
    first_name TEXT NOT NULL,
    last_name TEXT NOT NULL
);

A single agency has many users. This is pretty straightforward. So if I type:

export const getAgencyUsers = sql`
   SELECT * FROM users WHERE agency_id = $agencyId
`;

Then $agencyId would be evaluated as number for typescript, which is perfectly fine. But when the application grows, we can mistakenly pass the wrong entity id (e.g user id instead of agency id) and since typescript evaluates both user id and agency id as numbers, so we can easily get mistaken. At my work, we don’t use pgtyped, we’ve got something else. But the thing is when it comes to column keys, we treat each key as a different class. So user id would be UserId and agency id would be AgencyId. This way, we can never make a mistake. For example

export class UserId {
    private constructor() { }

    "UserId": UserId;

    public static wrap(id: number): UserId {
        return <any>id;
    }

    public static unwrap(userId: UserId): number {
        return <any>userId;
    }
}

so if by mistake I passed the wrong key (let’s say $agencyId instead of $userId, then I would get a type check error like so:

image

I was wondering if this is possible to achieve with pgtyped as well.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:3
  • Comments:13 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
golergkacommented, Dec 25, 2020

You know, as it often happens when you get very self-confident, I just had to debug a nasty issue that originated exactly from this kind of confusion. In the code that I wrote personally, all the way. So, even if you didn’t post this (pretty convincing, by the way) comment, I just had to get back to this discussion and humbly concede that we probably do, indeed, need a more rigid way to prevent this kind of bugs.

2reactions
Newbie012commented, Dec 24, 2020

@golergka Thanks for the tip. And still, I’ll try to draw a scenario where this can get out of hand. Take this code for example:

const updateUserCashQuery= sql<IUpdateUserCashQuery>`UPDATE users SET cash = $cash WHERE id = $userId`

async function updateUserCash(db: PoolClient, userId: number, cash: number) {
    await updateUserCashQuery.run({userId, cash}, db)
}

Looks fine, no chance that updateUserCash will pass the wrong params to the query. But what about the ones that call updateUserCash? This can quickly get out of hand when working with multiple devs on functions that have lots of params. Of course, we can convert the params to a single one that should be an object, but that will require us to write an undesirable boilerplate for each function (a separate or an inline interface).

About backward compatibility, can’t we make a flag that it turned off by default (I hope?).


Another library that adds typescript types from pg schema that I found today is kristiandupont/kanel Which translate keys as “opaque” types:

// Automatically generated. Don't change this file manually.
// Name: actor

export type ActorId = number & { __flavor?: 'actor' };

export default interface Actor {
  /** Primary key. Index: actor_pkey */
  actor_id: ActorId;
  ...
}

taken from https://github.com/kristiandupont/kanel/blob/master/example/models/Actor.ts

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Add Multiple Foreign Keys to Same Table and Not Get ...
Start by creating tables without any foreign keys. If you try to create tables with foreign keys that reference other tables that are...
Read more >
database design - Confusion with Foreign Keys
There's no reason in principle why primary key attributes shouldn't be foreign keys. – nvogel. Mar 21, 2014 at 20:44.
Read more >
Is There a Way to Avoid Spurious Foreign Key Constraint ...
Sometimes, having expertise in a different technology can be confusing to people, when they start to use LightSwitch. Some things just have to ......
Read more >
sql - Foreign Key confusion - Stack Overflow
Does the table contains data? If yes, then the foreign keys in other tables must have the exact datatype and the exact values...
Read more >
10 SQL Foreign Keys Best Practices - CLIMB
A good practice is to prefix the name of the foreign key with the name of the referenced table, such as “customer_id”. This...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found