Does it support postgres extensions? #123
-
|
I am most interested in CITEXT and POSTGIS. Is there a way to work with those? |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 6 replies
-
|
@capaj But you still have a possibility to use those extension types even now. It won't be fully automated but will still work Example with adding custom CITEXT type
After adding new datatype you can use it in your table schema definition. It will look like this const tableWithCustomType = pgTable('table_with_custom_type', {
id: integer('id').primaryKey(),
ciname: citext('ciname')
})
CREATE TABLE table_with_custom_type (
"id" integer PRIMARY KEY NOT NULL,
"ciname" "citext"
);All you left to do is to add CREATE EXTENSION IF NOT EXISTS citext;
CREATE TABLE table_with_custom_type (
"id" integer PRIMARY KEY NOT NULL,
"ciname" "citext"
);
Same could be done with any other extension or datatype that is missing. But you are free to create an |
Beta Was this translation helpful? Give feedback.
-
|
We actually have prepared even better way to create CITEXT example will look like thisconst citext = customType<{ data: string }>({
dataType() {
return 'citext';
},
}); |
Beta Was this translation helpful? Give feedback.
-
|
The following code seems to work for the postgis geometry type. I haven't tested it extensively, my experience with drizzle is limited to 2 hours (awesome btw!). This code is inspired by what sequelize does : import { sql } from "drizzle-orm";
import { customType } from "drizzle-orm/pg-core";
import type { Geometry, Point } from "geojson";
import wkx from "wkx";
type GeometryOptions = { type?: string; srid?: never } | { type: string; srid: number };
const dataType = (options?: GeometryOptions) => {
let result = "GEOMETRY";
if (options?.type) {
result += `(${options.type.toUpperCase()}`;
if (options?.srid) {
result += `,${options.srid}`;
}
result += ")";
}
return result;
};
const toDriver = (value: Geometry) => {
return sql`ST_GeomFromGeoJSON(${JSON.stringify(value)})`;
};
const fromDriver = (value: string) => {
const b = Buffer.from(value, "hex");
return wkx.Geometry.parse(b).toGeoJSON({ shortCrs: true }) as Geometry;
};
export const geometry = (name: string, options?: GeometryOptions) =>
customType<{
data: Geometry;
config: GeometryOptions;
driverData: string;
}>({
dataType,
toDriver,
fromDriver,
})(name, options);
type PointOptions = Omit<GeometryOptions, "type">;
type LatLng = { lat: number; lng: number };
export const point = (name: string, options?: PointOptions) =>
customType<{
data: LatLng;
config: PointOptions;
driverData: string;
}>({
dataType: (options) => dataType({ type: "POINT", ...options }),
toDriver: ({ lat, lng }: LatLng) =>
toDriver({
type: "Point",
coordinates: [lng, lat],
}),
fromDriver: (value) => {
const [lng, lat] = (fromDriver(value) as Point).coordinates;
return { lat, lng };
},
})(name, options);Usage : export const events = pgTable("events", {
geometry: geometry("geometry"),
location: point("location", { srid: 4326 }),
});
type Event = InferModel<typeof events, "select">;
// type Event = {
// geometry: Geometry | null, // https://www.jsdocs.io/package/@types/geojson#Geometry
// location: { lat: number; lng: number } | null
// }Unfortunatly I don't feel confident enough with postgis and drizzle to create a PR ::( |
Beta Was this translation helpful? Give feedback.
-
|
but it's not working with drizzle kit it has a bug with those types |
Beta Was this translation helpful? Give feedback.
-
|
ALTER TABLE "todos" ALTER COLUMN "task" SET DATA TYPE "undefined"."citext";--> statement-breakpoint Tried to alter a column to citext, and now I'm getting this in my migration.. import { type InferSelectModel, sql } from "drizzle-orm"
import { authenticatedRole, authUid, crudPolicy } from "drizzle-orm/neon"
import {
boolean,
customType,
jsonb,
pgTable,
serial,
text,
timestamp,
uuid
} from "drizzle-orm/pg-core"
// Enable RLS on all auth tables and re-export them
export const users = authSchema.users.enableRLS()
export const sessions = authSchema.sessions.enableRLS()
export const accounts = authSchema.accounts.enableRLS()
export const verifications = authSchema.verifications.enableRLS()
export const jwkss = authSchema.jwkss.enableRLS()
const citext = customType<{ data: string }>({
dataType() {
return "citext"
}
})
export const todos = pgTable(
"todos",
{
id: uuid().primaryKey().defaultRandom(),
userId: text()
.notNull()
.default(sql`(auth.user_id())`)
.references(() => profiles.id, { onDelete: "cascade" }),
projectId: uuid().references(() => projects.id, {
onDelete: "cascade"
}),
task: citext().notNull().default(""),
isComplete: boolean().notNull().default(false),
createdAt: timestamp({ withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp({ withTimezone: true })
.defaultNow()
.$onUpdate(() => new Date())
.notNull(),
_deleted: boolean().notNull().default(false)
},
(table) => [
crudPolicy({
role: authenticatedRole,
read: authUid(table.userId),
modify: authUid(table.userId)
})
]
) |
Beta Was this translation helpful? Give feedback.
-
|
Drizzle supports Postgres extensions well — the approach depends on whether you need the extension at the type level (DDL) or query level. DDL: declaring extension usage in schema: // schema.ts
import { pgSchema, vector, point } from 'drizzle-orm/pg-core';
// pgvector extension
export const embeddings = pgTable('embeddings', {
id: serial('id').primaryKey(),
content: text('content').notNull(),
embedding: vector('embedding', { dimensions: 1536 }), // pgvector type
createdAt: timestamp('created_at').defaultNow(),
});
// PostGIS point type
export const locations = pgTable('locations', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
coords: point('coords', { mode: 'xy' }), // PostGIS
});Query: using extension functions: import { sql } from 'drizzle-orm';
// pgvector similarity search (cosine distance)
const results = await db.select({
id: embeddings.id,
content: embeddings.content,
similarity: sql<number>`1 - (${embeddings.embedding} <=> ${queryVector}::vector)`,
})
.from(embeddings)
.orderBy(sql`${embeddings.embedding} <=> ${queryVector}::vector`)
.limit(10);
// Full text search with ts_vector/ts_rank
const posts = await db.select()
.from(articles)
.where(sql`to_tsvector('english', ${articles.content}) @@ plainto_tsquery('english', ${searchQuery})`)
.orderBy(sql`ts_rank(to_tsvector('english', ${articles.content}), plainto_tsquery('english', ${searchQuery})) DESC`);Migration: enable the extension: -- migrations/0001_add_pgvector.sql
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS postgis;Drizzle's custom type helpers allow you to add any Postgres type not natively supported. The raw |
Beta Was this translation helpful? Give feedback.
@capaj
We actually have prepared even better way to create
custom typesin postgresql and mysql. You can check those docs hereCITEXT example will look like this