drizzle-orm icon indicating copy to clipboard operation
drizzle-orm copied to clipboard

[FEATURE]: Support setting collation of columns

Open tmcw opened this issue 2 years ago • 21 comments
trafficstars

Describe want to want

Another fun Postgres feature! Let's say you're using fractional indexing and want to sort strings in a particular way that has nothing to do with their ordering in English or any other language, but with how they'd compare by codepoints, like ASCII strings. You could use COLLATE "C" to do that.

This would be an addition to the text() type in the schema builder.

tmcw avatar May 26 '23 18:05 tmcw

Collation support would also be good for MySQL

danielsharvey avatar Jun 11 '23 06:06 danielsharvey

+1

zgayjjf avatar Jul 27 '23 15:07 zgayjjf

Collation support would be great for UTF-8 support as well.

cmarker0 avatar Oct 09 '23 07:10 cmarker0

For Postgres:

It would be nice to support the basic scenario: After (manually creating a collation)

   CREATE COLLATION case_insensitive (
      provider = icu,
      locale = 'und-u-ks-level2',
      deterministic = false
    );

Note: you can always lookup your collations by SELECT * FROM pg_collation;

it would be nice to have something that can use that collation maybe in a form something like:

db.select().from(person)
.where(eq(person.name, 'Jack').collate('case_insensitive'));

resulting in the sql:

SELECT * FROM person WHERE name = 'Jack' collate case_insensitive;

Is there maybe another way to achieve this already?

delight avatar Oct 20 '23 17:10 delight

This is actually more important than I thought. I worked around this till now by using case-insensitive ids, e.g. no base64, but this is for ids I can control but what if I get ids from oauth providers I can't control? Would be great if this somehow gets in the backlog soon, thanks 🚀

Edit: Just to illustrate and have all in one thread, enabling case-sensitive queries with MySQL is something like id CHAR(20) PRIMARY KEY COLLATE utf8mb4_bin,

Edit2: related to https://github.com/drizzle-team/drizzle-orm/issues/735 which I'll close in favor of this one

205g0 avatar Dec 12 '23 10:12 205g0

I guess this is related to LIKE which is something I (and a lot of people) also use a lot so upvoting here (although I'm not entirely sure what collations are lol)

statusunknown418 avatar Jan 12 '24 02:01 statusunknown418

+1

VergeDX avatar Feb 11 '24 09:02 VergeDX

this seems like a pretty basic feature... how can we get it on the roadmap?

aaroned avatar Apr 23 '24 13:04 aaroned

the default collation is case insensitive, means if using something like nanoid as id, less characters could be use, higher collision chance with same length

eslym avatar May 08 '24 06:05 eslym

found a work around, kinda working

import type { ColumnBaseConfig } from 'drizzle-orm';
import { mysqlTable, char, varchar, type MySqlColumn } from 'drizzle-orm/mysql-core';
import { nanoid } from 'nanoid';

function collate<
    T extends 'MySqlChar' | 'MySqlVarChar' | 'MySqlText',
    C extends MySqlColumn<ColumnBaseConfig<any, T>>
>(col: C, collation: string) {
    col.getSQLType = function (this: C) {
        return Object.getPrototypeOf(this).getSQLType.call(this) + ' COLLATE ' + collation;
    };
    return col;
}

export const User = mysqlTable('users', {
    id: char('id', { length: 10 })
        .$defaultFn(() => nanoid(10))
        .primaryKey(),
    email: varchar('email', { length: 255 }).unique().notNull()
});

collate(User.id, 'ascii_bin');

which generates follow sql using drizzle-kit generate:mysql

CREATE TABLE `users` (
	`id` char(10) COLLATE ascii_bin NOT NULL,
	`email` varchar(255) NOT NULL,
	CONSTRAINT `users_id` PRIMARY KEY(`id`),
	CONSTRAINT `users_email_unique` UNIQUE(`email`)
);

eslym avatar May 08 '24 07:05 eslym

We just create a custom type of citext for our sqlite databases. It replicates the text type functionality and appends COLLATE NOCASE as a workaround.

import { customType } from "drizzle-orm/sqlite-core";

export const citext = customType<{
  data: string;
  notNull: true;
  default: true;
  config: { length?: number };
}>({
  dataType(config) {
    return `text${config?.length ? `(${config.length})` : ""} COLLATE NOCASE`;
  },
});

CTOJoe avatar May 10 '24 16:05 CTOJoe

+1

ingadi avatar May 30 '24 17:05 ingadi

+1 for MySQL too

selemessaied avatar Jun 15 '24 11:06 selemessaied