Open Jolg42 opened 1 year ago
@binajmen @dvins
Do you have any suggested solution, alternatives or additional context for how to do this? It would help us and other people that need this.
I'm not confident enough in Rust to help on the PR itself, but here are some useful food for thoughts:
Custom alphabet in JS version of nanoid
:
https://github.com/ai/nanoid#custom-alphabet-or-size
Custom alphabet in Rust version of nanoid
:
https://github.com/nikolay-govorov/nanoid#custom-alphabet-or-length
I suppose the alphabet itself should be defined somewhere in the generator client
?
@benjaminbours My first though was to have it in the schema, looks like this in my head:
model Blog {
id String @id @default(nanoid(length: 10, alphabet: "1234567890abcdef"))
}
It makes it extremely configurable (can use a different setting for different fields), this might be useful? The configuration on the generator would make it less configurable and global.
@Jolg42 I had the same idea first, but what if I have many models using nanoid
? Do I want to repeat the same parameters (length and/or alphabet) in each of them?
Maybe an hybrid solution where you could define globally these parameters, while being able to overwrite locally when needed?
Something like:
generator client {
provider = "prisma-client-js"
nanoid = { length: 12, alphabet: "123..abc.." } // <-- if omitted, use default values (*)
}
model Model1 {
id String @id @default(nanoid()) // <-- will use the global settings
}
model Model2 {
id String @id @default(nanoid(length: 10, alphabet: "1234567890abcdef")) // <-- will overwrite for this model
}
(*) official default values are alphabet = A-Za-z0-9_-
and length = 21 (https://github.com/ai/nanoid#api)
Indeed good questions to design the feature!
I think this will not make it at first, so first nanoid() will be supported but without alphabet configuration.
If more people can show up here and let us know what/why it's important for them, it will help prioritize the feature request work here.
@Jolg42 @binajmen Crawl -> Walk -> Run. A shared setting in the generator configuration would be grand, but would happily settle for cut and pasting the alphabet and/or length on the column and table definitions where needed.
In the Javascript ecosystem there's https://github.com/CyberAP/nanoid-dictionary and it offers predefined custom alphabets, such as nolookalikes
which would provide another way as well. I suppose the alphabets and names could be transfered into Rust in some fashion. But ultimately the more stuffed into this feature the longer it will take to move through the process and introduces other risks and probably even more edge cases.
The length and alphabet features of nanoid are IMHO required to be configured. Sure, take steps, but I would like to see it adopted and configured.
What would be great as well, actually for all string-generated IDs, is the possibility to set prefixes, e.g. user_
for users, post_
for posts, etc. In my project, I rely on middleware to achieve all 3: length, alphabet, and prefix.
@smolak Check this feature issue https://github.com/prisma/prisma/issues/6719, it is more generic and mentions the prefix configuration. Does it cover everything you want to do? Feel free to comment there 🙌🏼
@Jolg42: I am active there, but thanks. I have even proposed a solution to prefixing, that is abstract from DB one is using: https://github.com/prisma/prisma/issues/6719#issuecomment-1178211695
I don't like any of those that start with: if you're using PostgreSQL...
. Any solution should be abstracted from the DB that is being used, and be available on the Prisma level - if you asked me.
Indeed good questions to design the feature!
I think this will not make it at first, so first nanoid() will be supported but without alphabet configuration.
If more people can show up here and let us know what/why it's important for them, it will help prioritize the feature request work here.
I believe the default nanoid generator also includes symbols like dash and ubderscore to the id which is not wanted by many devs since it doesn't look good. Also, confusing 'i, I, l, 1, 0, o' is a major argument like others said. Code verification after login/signup is another user journey where safe alphabets come in handy. You would give a limited set of alphanumeric chars to make a random code that is easy to input (eg. only safe uppercase letters and numbers without 0).
Indeed good questions to design the feature! I think this will not make it at first, so first nanoid() will be supported but without alphabet configuration. If more people can show up here and let us know what/why it's important for them, it will help prioritize the feature request work here.
I believe the default nanoid generator also includes symbols like dash and ubderscore to the id which is not wanted by many devs since it doesn't look good. Also, confusing 'i, I, l, 1, 0, o' is a major argument like others said. Code verification after login/signup is another user journey where safe alphabets come in handy. You would give a limited set of alphanumeric chars to make a random code that is easy to input (eg. only safe uppercase letters and numbers without 0).
Exactly that. That counts for readability. The DX (developer's experience) is also important, e.g. take those two strings:
sdfsdf_adfasda sdfsdf-sdfsdff
Double-click on each. Only the first will be selected as a whole. It will work if you click 3x, but if you have an ID in a longer string, 3x will select the entire string, and we want to select the ID alone. Small things like that count at some point. So you want to limit the possible special characters (if you want to achieve that DX).
I think @smolak summarised it pretty well in his previous post:
The length and alphabet features of nanoid are IMHO required to be configured. Sure, take steps, but I would like to see it adopted and configured.
What would be great as well, actually for all string-generated IDs, is the possibility to set prefixes, e.g. user for users, post for posts, etc. In my project, I rely on middleware to achieve all 3: length, alphabet, and prefix.
The perfect solution should offer the capability to define:
With these three characteristics, I'd be an happy developer 😃
+1 for custom alphabet support. would love to have only a-z0-9
as my id alphabet
Hi everyone,
We ended up using creating a custom migration adding nanoid-postgres function .
To do that you can use refer to this doc
Then you can use nanoid with length or alphabet as parameters.
model User {
id String @id @default(dbgenerated("nanoid(12, 'abcdef')"))
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
username String? @unique
}
Hope it helps
for those using MySQL / Planetscale, this is how i'm creating a nanoID with a custom length and alphabet for all models.
# lib/prisma.ts
import { PrismaClient } from '@prisma/client'
import { customAlphabet } from 'nanoid'
const prismaClientSingleton = () => {
const nanoid = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 12)
return new PrismaClient().$extends({
query: {
$allModels: {
async create({ args, query }) {
const id = nanoid()
args.data = {
...args.data,
id,
}
return query(args)
}
}
}
})
}
export const prisma = global.prisma || prismaClientSingleton()
if (process.env.NODE_ENV !== "production") global.prisma = prisma
export * from "@prisma/client"
Hi everyone,
We ended up using creating a custom migration adding nanoid-postgres function .
To do that you can use refer to this doc
Then you can use nanoid with length or alphabet as parameters.
model User { id String @id @default(dbgenerated("nanoid(12, 'abcdef')")) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt username String? @unique } Hope it helps
Step 1: Create a dummy migration
npx prisma migrate dev --create-only --name add_nanoid_postgres_util
Important Read: paste this sql query to your newly generated .sql
migration file
Setp 2: Add nanoid
id String @id @default(dbgenerated("nanoid(7, '0123456789')"))
Step 3: Create Migration and generate migration
npx prisma migrate dev --name add_nonoid
If anyone are using Neon.tech or any other PostgreSQL database, you can generate a unique 6-digit (or any structure (take example from @pavankumar-v answer) that you want to) code by following these steps:
First, create a function (this one is answered by ChatGPT) in the Neon SQL Editor (or any applications that you can run SQL Script in your db) then run it:
CREATE OR REPLACE FUNCTION generate_six_digit_code()
RETURNS TEXT AS $$
DECLARE
code TEXT;
BEGIN
code := substring(to_char(floor(random() * 1000000)::integer, 'FM000000') from 1 for 6);
RETURN code;
END;
$$ LANGUAGE plpgsql;
Then, for example define your Coupon model in your Prisma schema as follows:
model Coupon {
id String @id @default(uuid())
ownerId String?
owner User? @relation(fields: [ownerId], references: [userId])
code String @unique @default(dbgenerated("generate_six_digit_code()"))
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
then run npx prisma generate
, npx prisma db push
close your local dev environment Ctrl + C
then npm run dev
so see if it worked
This solves it, yes, but on a different layer, whereas it should be done through Prisma, regardless of the DB used. Just sayin'.
Note: the feature is not complete yet, see https://github.com/prisma/prisma/issues/17199
Example 1
Originally posted by @dvins in https://github.com/prisma/prisma-engines/issues/3556#issuecomment-1381592441
Example 2
Originally posted by @binajmen in https://github.com/prisma/prisma-engines/issues/3556#issuecomment-1381617208