I am looking for a way that is not too hacky to hash all ids before returning to user, is there a way to do so? I’ve searched all over docs and couldn’t find anything that handles all scenarios.
I am using Postgres + Prisma ORM and have multiple models with relational fields. Ideally I would achieve the desired behavior using Prisma.
I have tried Jordan reply and my code looks like this.
const getPrismaClient = () => {
const client = new PrismaClient();
client.$extends({
result: {
blog: {
// We basically create a virtual `hashedId` field
hashedId: {
needs: { id: true },
compute(client) {
return intToHashedString(client.id);
},
},
},
},
});
client.blog
.findMany({
select: { hashedId: true },
})
.then((r) => {
console.log(r);
});
return client;
};
but it throws this error
error - unhandledRejection: PrismaClientValidationError:
Invalid `prisma.blog.findMany()` invocation:
{
select: {
hashedId: true,
~~~~~~~~
? id?: true,
? title?: true,
? slug?: true,
? image?: true,
? description?: true,
? views?: true,
? authorId?: true,
clientVersion: '4.11.0'
}
2
Answers
There are undocumented, but largely safe-to-use hashing functions for every built-in data type in Postgres. Those are used for hash partitioning and indexing, among other things. For
integer
(int4
) input:The second form requires Postgres 12 or later, additionally takes a seed as 2nd parameter, and produces a larger
bigint
hash to make collisions less likely.Or, to avoid hash collisions almost certainly, go even bigger with the good old
md5()
function to get strings of 32 characters (matching a UUID). Related:But
md5()
takestext
, so you have to cast yourinteger
input.Examples:
Cast numeric results to
text
with::text
if you insist on "strings".Related (consider the chapter "Probability of a hash collision?"):
You might create a (
MATERIALIZED
)VIEW
of your table with hashed values to save some typing and computation (though the functions are very performant).You can use Prisma Client results extension (They’re still under a feature flag, so at your own risk).
First enable the feature
And then, here is how you could use it:
You’ll need to handle performance issues, but it should answer your need.
EDIT: Note that
prisma.$extends
returns a newPrismaClient
which will include your extensions. Otherwise, it won’t compile. Here’s why I kept the doc’s convention of usingxprisma
.