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

[FEATURE]: ORM Schema for Generated Columns

Open tomery11 opened this issue 2 years ago • 6 comments

Hi! I have a column in a table which is a Generated Column. Is there a solution for drizzle orm pgTable schema columns that are Generated Columns? Do you have a solution for this in the meantime? Thanks! T

tomery11 avatar May 14 '23 16:05 tomery11

This is how I implemented Generated Columns in one of my projects:

const customGeneratedText = (name: string, ...columns: [string, ...string[]]) =>
  customType<{ data: undefined; driverData: undefined }>({
    dataType() {
      return `text as (concat_ws(" ", ${columns.join(", ")})) invisible`;
    }
  })(name);

To be used like this:

export const vehicles = mysqlTable(
  "vehicles",
  {
    id: char("id", { length: 26 }).primaryKey().notNull(),
    make: varchar("make", { length: 191 }).notNull(),
    model: varchar("model", { length: 191 }).notNull(),
    year: int("year").notNull(),
    name: varchar("name", { length: 191 }).notNull(),
    vin: varchar("vin", { length: 191 }).notNull(),
    tag: varchar("tag", { length: 191 }),
    createdAt: datetime("createdAt", { mode: "date", fsp: 3 })
      .default(sql`(CURRENT_TIMESTAMP(3))`)
      .notNull(),
    search: customGeneratedText(
      "search",
      "make",
      "model",
      "year",
      "name",
      "vin",
      "tag"
    )
  },
  (table) => {
    return {
      nameKey: uniqueIndex("vehicle_name_key").on(table.name),
      vinKey: uniqueIndex("vehicle_vin_key").on(table.vin)
    };
  }
);

And the SQL output is:

ALTER TABLE `vehicles` ADD `search` text as (concat_ws(" ", make, model, year, name, vin, tag)) invisible;

The issue to track is #261

Angelelz avatar Aug 14 '23 19:08 Angelelz

I believe this can be closed as duplicate.

Angelelz avatar Aug 14 '23 19:08 Angelelz

For some reason, using the @Angelelz approach does not work on the initial push, since it generates the following SQL:

CREATE TABLE IF NOT EXISTS "contacts" (
	"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
	"first_name" varchar(50),
	"last_name" varchar(50),
	"full_name" "text GENERATED ALWAYS AS (TRIM(concat_ws(" ", first_name, last_name))) STORED",
	"created_at" timestamp DEFAULT now() NOT NULL
);

Custom Type definition:

export const generatedConcatColumns = customType<{
  data: string;
  driverData: string;
  config: {
    columns: string[];
  };
}>({
  dataType(config) {
    return `text GENERATED ALWAYS AS (TRIM(concat_ws(" ", ${config?.columns.join(
      ", ",
    )}))) STORED`;
  },
});

Schema Definition:

export const contacts = pgTable("contacts", {
  id: uuid("id").defaultRandom().primaryKey(),
  first_name: varchar("first_name", { length: 50 }),
  last_name: varchar("last_name", { length: 50 }),
  full_name: generatedConcatColumns("full_name", {
    columns: ["first_name", "last_name"],
  }),
  createdAt: timestamp("created_at")
    .notNull()
    .default(sql`now()`),
});

ocruzv avatar Aug 15 '23 21:08 ocruzv

Interesting, I've never tried it on initial push. It might be a bug, but it might be a Drizzle-kit bug.

Angelelz avatar Aug 15 '23 23:08 Angelelz

The issue above mentioned by @ocruzv is most likely caused by a bug in drizzle-kit: https://github.com/drizzle-team/drizzle-kit-mirror/issues/167.

davepar avatar Jan 31 '24 20:01 davepar

For Postgres users here is a patch-package to fix this with drizzle-kit

diff --git a/node_modules/drizzle-kit/bin.cjs b/node_modules/drizzle-kit/bin.cjs
index 9b92321..d347342 100755
--- a/node_modules/drizzle-kit/bin.cjs
+++ b/node_modules/drizzle-kit/bin.cjs
@@ -15496,6 +15496,7 @@ var init_sqlgenerator = __esm({
       "interval minute to second"
     ]);
     isPgNativeType = (it) => {
+      return true
       if (pgNativeTypes.has(it))
         return true;
       const toCheck = it.replace(/ /g, "");

I've only tested this type, test other custom types as I have no clue if this will break them

import { customType } from "drizzle-orm/pg-core";
export const identity = (name: string) =>
  customType<{
    data: string;
    notNull: true;
    default: true;
  }>({
    dataType() {
      return "BIGINT GENERATED ALWAYS AS IDENTITY";
    },
  })(name);

arjunyel avatar May 03 '24 20:05 arjunyel

any update

ghyath5 avatar Jul 10 '24 09:07 ghyath5

We just released it yesterday!

release notes: https://github.com/drizzle-team/drizzle-orm/releases/tag/0.32.0 docs: https://orm.drizzle.team/docs/generated-columns

AndriiSherman avatar Jul 11 '24 06:07 AndriiSherman