Skip to content

Releases: drizzle-team/drizzle-orm

v0.31.0-beta

23 May 16:24
7a05232
Compare
Choose a tag to compare
v0.31.0-beta Pre-release
Pre-release

Breaking changes

PostgreSQL indexes API was changed

The previous Drizzle+PostgreSQL indexes API was incorrect and was not aligned with the PostgreSQL documentation. The good thing is that it was not used in queries, and drizzle-kit didn't support all properties for indexes. This means we can now change the API to the correct one and provide full support for it in drizzle-kit

Previous API

  • No way to define SQL expressions inside .on.
  • .using and .on in our case are the same thing, so the API is incorrect here.
  • .asc(), .desc(), .nullsFirst(), and .nullsLast() should be specified for each column or expression on indexes, but not on an index itself.
// Index declaration reference
index('name')
  .on(table.column1, table.column2, ...) or .onOnly(table.column1, table.column2, ...)
  .concurrently()
  .using(sql``) // sql expression
  .asc() or .desc()
  .nullsFirst() or .nullsLast()
  .where(sql``) // sql expression

Current API

// First example, with `.on()`
index('name')
  .on(table.column1.asc(), table.column2.nullsFirst(), ...) or .onOnly(table.column1.desc().nullsLast(), table.column2, ...)
  .concurrently()
  .where(sql``)
  .with({ fillfactor: '70' })

// Second Example, with `.using()`
index('name')
  .using('btree', table.column1.asc(), sql`lower(${table.column2})`, table.column1.op('text_ops'))
  .where(sql``) // sql expression
  .with({ fillfactor: '70' })

New Features

🎉 "pg_vector" extension support

There is no specific code to create an extension inside the Drizzle schema. We assume that if you are using vector types, indexes, and queries, you have a PostgreSQL database with the pg_vector extension installed.

You can now specify indexes for pg_vector and utilize pg_vector functions for querying, ordering, etc.

Let's take a few examples of pg_vector indexes from the pg_vector docs and translate them to Drizzle

L2 distance, Inner product and Cosine distance

// CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
// CREATE INDEX ON items USING hnsw (embedding vector_ip_ops);
// CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);

const table = pgTable('items', {
    embedding: vector('embedding', { dimensions: 3 })
}, (table) => ({
    l2: index('l2_index').using('hnsw', table.embedding.op('vector_l2_ops'))
    ip: index('ip_index').using('hnsw', table.embedding.op('vector_ip_ops'))
    cosine: index('cosine_index').using('hnsw', table.embedding.op('vector_cosine_ops'))
}))

L1 distance, Hamming distance and Jaccard distance - added in pg_vector 0.7.0 version

// CREATE INDEX ON items USING hnsw (embedding vector_l1_ops);
// CREATE INDEX ON items USING hnsw (embedding bit_hamming_ops);
// CREATE INDEX ON items USING hnsw (embedding bit_jaccard_ops);

const table = pgTable('table', {
    embedding: vector('embedding', { dimensions: 3 })
}, (table) => ({
    l1: index('l1_index').using('hnsw', table.embedding.op('vector_l1_ops'))
    hamming: index('hamming_index').using('hnsw', table.embedding.op('bit_hamming_ops'))
    bit: index('bit_jaccard_index').using('hnsw', table.embedding.op('bit_jaccard_ops'))
}))

For queries, you can use predefined functions for vectors or create custom ones using the SQL template operator.

You can also use the following helpers:

import { l2Distance, l1Distance, innerProduct, 
          cosineDistance, hammingDistance, jaccardDistance } from 'drizzle-orm'

l2Distance(table.column, [3, 1, 2]) // table.column <-> '[3, 1, 2]'
l1Distance(table.column, [3, 1, 2]) // table.column <+> '[3, 1, 2]'

innerProduct(table.column, [3, 1, 2]) // table.column <#> '[3, 1, 2]'
cosineDistance(table.column, [3, 1, 2]) // table.column <=> '[3, 1, 2]'

hammingDistance(table.column, '101') // table.column <~> '101'
jaccardDistance(table.column, '101') // table.column <%> '101'

If pg_vector has some other functions to use, you can replicate implimentation from existing one we have. Here is how it can be done

export function l2Distance(
  column: SQLWrapper | AnyColumn,
  value: number[] | string[] | TypedQueryBuilder<any> | string,
): SQL {
  if (is(value, TypedQueryBuilder<any>) || typeof value === 'string') {
    return sql`${column} <-> ${value}`;
  }
  return sql`${column} <-> ${JSON.stringify(value)}`;
}

Name it as you wish and change the operator. This example allows for a numbers array, strings array, string, or even a select query. Feel free to create any other type you want or even contribute and submit a PR

Examples

Let's take a few examples of pg_vector queries from the pg_vector docs and translate them to Drizzle

import { l2Distance } from 'drizzle-orm';

// SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
db.select().from(items).orderBy(l2Distance(items.embedding, [3,1,2]))

// SELECT embedding <-> '[3,1,2]' AS distance FROM items;
db.select({ distance: l2Distance(items.embedding, [3,1,2]) })

// SELECT * FROM items ORDER BY embedding <-> (SELECT embedding FROM items WHERE id = 1) LIMIT 5;
const subquery = db.select({ embedding: items.embedding }).from(items).where(eq(items.id, 1));
db.select().from(items).orderBy(l2Distance(items.embedding, subquery)).limit(5)

// SELECT (embedding <#> '[3,1,2]') * -1 AS inner_product FROM items;
db.select({ innerProduct: sql`(${maxInnerProduct(items.embedding, [3,1,2])}) * -1` }).from(items)

// and more!

0.30.10

01 May 14:10
a78eefe
Compare
Choose a tag to compare

New Features

🎉 .if() function added to all WHERE expressions

Select all users after cursors if a cursor value was provided

async function someFunction(categories: string[] = [], views = 0) {
  await db
    .select()
    .from(users)
    .where(
       and(
          gt(posts.views, views).if(views > 100),
          inArray(posts.category, categories).if(categories.length > 0),
       ),
    );
}

Bug Fixes

  • Fixed internal mappings for sessions .all, .values, .execute functions in AWS DataAPI

0.30.9

21 Apr 12:56
e0aaeb2
Compare
Choose a tag to compare
  • 🐛 Fixed migrator in AWS Data API
  • Added setWhere and targetWhere fields to .onConflictDoUpdate() config in SQLite instead of single where field
  • 🛠️ Added schema information to Drizzle instances via db._.fullSchema

0.30.8

11 Apr 07:27
4706ad1
Compare
Choose a tag to compare
  • 🎉 Added custom schema support to enums in Postgres (fixes #669 via #2048):

⚠️ Only available in drizzle-orm for now, drizzle-kit support will arrive soon

import { pgSchema } from 'drizzle-orm/pg-core';

const mySchema = pgSchema('mySchema');
const colors = mySchema.enum('colors', ['red', 'green', 'blue']);
  • 🎉 Changed D1 migrate() function to use batch API (#2137)
  • 🐛 Split where clause in Postgres .onConflictDoUpdate method into setWhere and targetWhere clauses, to support both where cases in on conflict ... clause (fixes #1628, #1302 via #2056)
  • 🐛 Fixed query generation for where clause in Postgres .onConflictDoNothing method, as it was placed in a wrong spot (fixes #1628 via #2056)
  • 🐛 Fixed multiple issues with AWS Data API driver (fixes #1931, #1932, #1934, #1936 via #2119)
  • 🐛 Fix inserting and updating array values in AWS Data API (fixes #1912 via #1911)

Thanks @hugo082 and @livingforjesus!

0.30.7

03 Apr 12:02
76eb060
Compare
Choose a tag to compare

Bug fixes

  • Add mappings for @vercel/postgres package
  • Fix interval mapping for neon drivers - #1542

0.30.6

28 Mar 17:08
0ddab65
Compare
Choose a tag to compare

New Features

🎉 PGlite driver Support

PGlite is a WASM Postgres build packaged into a TypeScript client library that enables you to run Postgres in the browser, Node.js and Bun, with no need to install any other dependencies. It is only 2.6mb gzipped.

It can be used as an ephemeral in-memory database, or with persistence either to the file system (Node/Bun) or indexedDB (Browser).

Unlike previous "Postgres in the browser" projects, PGlite does not use a Linux virtual machine - it is simply Postgres in WASM.

Usage Example

import { PGlite } from '@electric-sql/pglite';
import { drizzle } from 'drizzle-orm/pglite';

// In-memory Postgres
const client = new PGlite();
const db = drizzle(client);

await db.select().from(users);

There are currently 2 limitations, that should be fixed on Pglite side:

0.30.5

27 Mar 12:07
f6de0d5
Compare
Choose a tag to compare

New Features

🎉 $onUpdate functionality for PostgreSQL, MySQL and SQLite

Adds a dynamic update value to the column.
The function will be called when the row is updated, and the returned value will be used as the column value if none is provided.
If no default (or $defaultFn) value is provided, the function will be called when the row is inserted as well, and the returned value will be used as the column value.

Note: This value does not affect the drizzle-kit behavior, it is only used at runtime in drizzle-orm.

const usersOnUpdate = pgTable('users_on_update', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  updateCounter: integer('update_counter').default(sql`1`).$onUpdateFn(() => sql`update_counter + 1`),
  updatedAt: timestamp('updated_at', { mode: 'date', precision: 3 }).$onUpdate(() => new Date()),
  alwaysNull: text('always_null').$type<string | null>().$onUpdate(() => null),
});

Fixes

  • [BUG]: insertions on columns with the smallserial datatype are not optional - #1848

Thanks @Angelelz and @gabrielDonnantuoni!

0.30.4

19 Mar 16:43
3216719
Compare
Choose a tag to compare

New Features

🎉 xata-http driver support

According their official website, Xata is a Postgres data platform with a focus on reliability, scalability, and developer experience. The Xata Postgres service is currently in beta, please see the Xata docs on how to enable it in your account.

Drizzle ORM natively supports both the xata driver with drizzle-orm/xata package and the postgres or pg drivers for accessing a Xata Postgres database.

The following example use the Xata generated client, which you obtain by running the xata init CLI command.

pnpm add drizzle-orm @xata.io/client
import { drizzle } from 'drizzle-orm/xata-http';
import { getXataClient } from './xata'; // Generated client

const xata = getXataClient();
const db = drizzle(xata);

const result = await db.select().from(...);

You can also connect to Xata using pg or postgres.js drivers

0.30.3

18 Mar 23:52
f2ec232
Compare
Choose a tag to compare
  • 🎉 Added raw query support (db.execute(...)) to batch API in Neon HTTP driver
  • 🐛 Fixed @neondatabase/serverless HTTP driver types issue (#1945, neondatabase/serverless#66)
  • 🐛 Fixed sqlite-proxy driver .run() result (#2038)

0.30.2

14 Mar 14:26
ab1cfdf
Compare
Choose a tag to compare

Improvements

LibSQL migrations have been updated to utilize batch execution instead of transactions. As stated in the documentation, LibSQL now supports batch operations

A batch consists of multiple SQL statements executed sequentially within an implicit transaction. The backend handles the transaction: success commits all changes, while any failure results in a full rollback with no modifications.

Bug fixed